diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -49,6 +49,17 @@ void PrintObjCTypeParams(ObjCTypeParamList *Params); + enum AttrPrintLoc { + SIDE_NONE = 0, + SIDE_LEFT = 1, + SIDE_MIDDLE = 2, + SIDE_RIGHT = 4, + SIDE_ANY = SIDE_LEFT | SIDE_MIDDLE | SIDE_RIGHT, + }; + + void prettyPrintAttributes(Decl *D, raw_ostream &out, + AttrPrintLoc loc = SIDE_ANY); + public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, const ASTContext &Context, unsigned Indentation = 0, @@ -117,7 +128,11 @@ const TemplateParameterList *Params); void printTemplateArguments(llvm::ArrayRef Args, const TemplateParameterList *Params); - void prettyPrintAttributes(Decl *D); + + inline void prettyPrintAttributes(Decl *D) { + prettyPrintAttributes(D, Out); + } + void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); }; @@ -234,7 +249,8 @@ return Out; } -void DeclPrinter::prettyPrintAttributes(Decl *D) { +void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &out, + AttrPrintLoc loc) { if (Policy.PolishForDeclaration) return; @@ -243,14 +259,28 @@ for (auto *A : Attrs) { if (A->isInherited() || A->isImplicit()) continue; - switch (A->getKind()) { -#define ATTR(X) -#define PRAGMA_SPELLING_ATTR(X) case attr::X: -#include "clang/Basic/AttrList.inc" - break; - default: - A->printPretty(Out, Policy); - break; + + // We will try to classify the attr::Kind into three disjoint sets: + // 1- should be print on the left side of a decl. + // 2- should be print on the middle of a decl right after the type. + // 3- should be print on the right side of a decl. + AttrPrintLoc attrloc = SIDE_MIDDLE; // We default to middle. + attr::Kind kind = A->getKind(); + + // FIXME: Find a way to use the AttrList.inc. We use if-else statements + // to classify each of them. + if (A->isCXX11Attribute()) { + // C++11 onwards attributes can not be placed on middle. Output on + // right to mimic old clang behaviour. + attrloc = SIDE_RIGHT; + } else if (kind == attr::AsmLabel) { + // AsmLabels can not be placed on the middle nor left. + attrloc = SIDE_RIGHT; + } + + // Only print the side matches the user requested. + if ((loc & attrloc) != SIDE_NONE) { + A->printPretty(out, Policy); } } } @@ -887,10 +917,29 @@ } } - printDeclType(T, (isa(D) && Policy.CleanUglifiedParameters && - D->getIdentifier()) - ? D->getIdentifier()->deuglifiedName() - : D->getName()); + std::string Name; + llvm::raw_string_ostream NameStream(Name); + + // Print the middle attributes into a string so we can concatenate with the + // name. + prettyPrintAttributes(D, NameStream, SIDE_MIDDLE); + + // prettyPrintAttributes print a space on left side of the attribute. + if (Name[0] == ' ') { + // Skip the space prettyPrintAttributes generated. + Name.erase(0, Name.find_first_not_of(' ')); + + // Add a single space between the attribute and the Decl name. + NameStream << ' '; + } + + Name += (isa(D) && Policy.CleanUglifiedParameters && + D->getIdentifier()) + ? D->getIdentifier()->deuglifiedName().str() + : D->getName().str(); + + printDeclType(T, StringRef(Name)); + Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; @@ -919,7 +968,10 @@ Out << ")"; } } - prettyPrintAttributes(D); + + // Print the attributes that should be placed right before the end of the + // decl. + prettyPrintAttributes(D, Out, SIDE_RIGHT); } void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { diff --git a/clang/test/AST/ast-print-attr-knr.c b/clang/test/AST/ast-print-attr-knr.c new file mode 100644 --- /dev/null +++ b/clang/test/AST/ast-print-attr-knr.c @@ -0,0 +1,10 @@ +// This file contain tests for attribute arguments on K&R functions. + +// RUN: %clang_cc1 -ast-print -x c -std=c89 -fms-extensions %s -o - | FileCheck %s + +// CHECK: int knr(i) +// CHECK-NEXT: int __attribute__((unused)) i; +// CHECK-NEXT: { +// CHECK-NEXT: return 0; +// CHECK-NEXT: } +int knr(i) int __attribute__((unused)) i; { return 0; } diff --git a/clang/test/AST/ast-print-attr.c b/clang/test/AST/ast-print-attr.c --- a/clang/test/AST/ast-print-attr.c +++ b/clang/test/AST/ast-print-attr.c @@ -32,3 +32,9 @@ // CHECK: void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1))); void fun_holds(int *a) __attribute__((ownership_holds(fun_holds, 1))); + +// CHECK: int fun_var_unused() { +// CHECK-NEXT: int __attribute__((unused)) x = 0; +// CHECK-NEXT: return x; +// CHECK-NEXT: } +int fun_var_unused() { int __attribute__((unused)) x = 0; return x; } diff --git a/clang/test/AST/ast-print-pragmas.cpp b/clang/test/AST/ast-print-pragmas.cpp --- a/clang/test/AST/ast-print-pragmas.cpp +++ b/clang/test/AST/ast-print-pragmas.cpp @@ -93,7 +93,7 @@ #ifdef MS_EXT #pragma init_seg(compiler) // MS-EXT: #pragma init_seg (.CRT$XCC){{$}} -// MS-EXT-NEXT: int x = 3 __declspec(thread); +// MS-EXT-NEXT: int __declspec(thread) x = 3; int __declspec(thread) x = 3; #endif //MS_EXT diff --git a/clang/test/Analysis/blocks.mm b/clang/test/Analysis/blocks.mm --- a/clang/test/Analysis/blocks.mm +++ b/clang/test/Analysis/blocks.mm @@ -70,6 +70,8 @@ }); } +// FIXME: C++ issues a ignore warning on this __attribute__ output. + // CHECK-LABEL:void testBlockWithCaptureByReference() // CHECK-NEXT: [B2 (ENTRY)] // CHECK-NEXT: Succs (1): B1 @@ -78,7 +80,7 @@ // CHECK-NEXT: 1: 5 // WARNINGS-NEXT: 2: [B1.1] (CXXConstructExpr, StructWithCopyConstructor) // ANALYZER-NEXT: 2: [B1.1] (CXXConstructExpr, [B1.3], StructWithCopyConstructor) -// CHECK-NEXT: 3: StructWithCopyConstructor s(5) __attribute__((blocks("byref"))); +// CHECK-NEXT: 3: StructWithCopyConstructor __attribute__((blocks("byref"))) s(5); // CHECK-NEXT: 4: ^{ } // CHECK-NEXT: 5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void) // CHECK-NEXT: Preds (1): B2 diff --git a/clang/test/Sema/attr-print.c b/clang/test/Sema/attr-print.c --- a/clang/test/Sema/attr-print.c +++ b/clang/test/Sema/attr-print.c @@ -1,14 +1,14 @@ // RUN: %clang_cc1 %s -ast-print -fms-extensions | FileCheck %s -// CHECK: int x __attribute__((aligned(4))); -int x __attribute__((aligned(4))); +// CHECK: int __attribute__((aligned(4))) x; +int __attribute__((aligned(4))) x; // FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); -__declspec(align(4)) int y; +// CHECK: int __declspec(align(4)) y; +int __declspec(align(4)) y; -// CHECK: short arr[3] __attribute__((aligned)); -short arr[3] __attribute__((aligned)); +// CHECK: short __attribute__((aligned)) arr[3]; +short __attribute__((aligned)) arr[3]; // CHECK: void foo(void) __attribute__((const)); void foo(void) __attribute__((const)); diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp --- a/clang/test/SemaCXX/attr-print.cpp +++ b/clang/test/SemaCXX/attr-print.cpp @@ -1,11 +1,11 @@ // RUN: %clang_cc1 %s -ast-print -fms-extensions | FileCheck %s -// CHECK: int x __attribute__((aligned(4))); -int x __attribute__((aligned(4))); +// CHECK: int __attribute__((aligned(4))) x; +int __attribute__((aligned(4))) x; // FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); -__declspec(align(4)) int y; +// CHECK: int __declspec(align(4)) y; +int __declspec(align(4)) y; // CHECK: void foo() __attribute__((const)); void foo() __attribute__((const)); @@ -20,11 +20,11 @@ // CHECK: typedef int Small1 __attribute__((mode(byte))); typedef int Small1 __attribute__((mode(byte))); -// CHECK: int small __attribute__((mode(byte))); -int small __attribute__((mode(byte))); +// CHECK: int __attribute__((mode(byte))) small; +int __attribute__((mode(byte))) small; -// CHECK: int v __attribute__((visibility("hidden"))); -int v __attribute__((visibility("hidden"))); +// CHECK: int __attribute__((visibility("hidden"))) v; +int __attribute__((visibility("hidden"))) v; // CHECK: char *PR24565() __attribute__((malloc)) char *PR24565() __attribute__((__malloc__)); diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp --- a/clang/test/SemaCXX/cxx11-attr-print.cpp +++ b/clang/test/SemaCXX/cxx11-attr-print.cpp @@ -1,29 +1,28 @@ // RUN: %clang_cc1 -std=c++11 -ast-print -fms-extensions %s | FileCheck %s // -// CHECK: int x __attribute__((aligned(4))); -int x __attribute__((aligned(4))); +// CHECK: int __attribute__((aligned(4))) x; +int __attribute__((aligned(4))) x; -// FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); -__declspec(align(4)) int y; +// CHECK: int __declspec(align(4)) y; +int __declspec(align(4)) y; // CHECK: int z {{\[}}[gnu::aligned(4)]]; int z [[gnu::aligned(4)]]; -// CHECK: __attribute__((deprecated("warning"))); -int a __attribute__((deprecated("warning"))); +// CHECK: int __attribute__((deprecated("warning"))) a; +int __attribute__((deprecated("warning"))) a; // CHECK: int b {{\[}}[gnu::deprecated("warning")]]; int b [[gnu::deprecated("warning")]]; -// CHECK: __declspec(deprecated("warning")) -__declspec(deprecated("warning")) int c; +// CHECK: int __declspec(deprecated("warning")) c; +int __declspec(deprecated("warning")) c; // CHECK: int d {{\[}}[deprecated("warning")]]; int d [[deprecated("warning")]]; -// CHECK: __attribute__((deprecated("warning", "fixit"))); -int e __attribute__((deprecated("warning", "fixit"))); +// CHECK: int __attribute__((deprecated("warning", "fixit"))) e; +int __attribute__((deprecated("warning", "fixit"))) e; // CHECK: int cxx11_alignas alignas(4); alignas(4) int cxx11_alignas; @@ -63,12 +62,12 @@ // CHECK: __attribute__((format(printf, 2, 3))); void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3))); -// CHECK: int m __attribute__((aligned(4 +// CHECK: int m __attribute__((aligned(4))) // CHECK: int n alignas(4 // CHECK: static int f() __attribute__((pure)) // CHECK: static int g() {{\[}}[gnu::pure]] template struct S { - __attribute__((aligned(4))) int m; + int __attribute__((aligned(4))) m; alignas(4) int n; __attribute__((pure)) static int f() { return 0; @@ -78,7 +77,7 @@ } }; -// CHECK: int m __attribute__((aligned(4 +// CHECK: int m __attribute__((aligned(4))) // CHECK: int n alignas(4 // CHECK: static int f() __attribute__((pure)) // CHECK: static int g() {{\[}}[gnu::pure]]