diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4f281c5c8bde..c95db7e8049d 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -300,10 +300,13 @@ class Spelling { } class GNU : Spelling; -class Declspec : Spelling; +class Declspec : Spelling { + bit PrintOnLeft = 1; +} class Microsoft : Spelling; class CXX11 : Spelling { + bit CanPrintOnLeft = 0; string Namespace = namespace; } class C23 @@ -559,6 +562,12 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; class Attr { + // Specifies that when printed, this attribute is meaningful on the + // 'left side' of the declaration. + bit CanPrintOnLeft = 1; + // Specifies that when printed, this attribute is required to be printed on + // the 'left side' of the declaration. + bit PrintOnLeft = 0; // The various ways in which an attribute can be spelled in source list Spellings; // The things to which an attribute can appertain @@ -892,6 +901,7 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr { } def AsmLabel : InheritableAttr { + let CanPrintOnLeft = 0; let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">]; let Args = [ // Label specifies the mangled name for the decl. @@ -1434,6 +1444,7 @@ def AllocSize : InheritableAttr { } def EnableIf : InheritableAttr { + let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. @@ -2920,6 +2931,7 @@ def Unavailable : InheritableAttr { } def DiagnoseIf : InheritableAttr { + let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index f010e04f62cd..085e316fcc67 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -30,6 +30,16 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list SOURCE Attr.td TARGET ClangAttrList) +clang_tablegen(AttrLeftSideCanPrintList.inc -gen-clang-attr-can-print-left-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrCanPrintLeftList) + +clang_tablegen(AttrLeftSideMustPrintList.inc -gen-clang-attr-must-print-left-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrMustPrintLeftList) + clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE Attr.td diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 034fc874bd88..834449ff1b99 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -49,6 +49,18 @@ namespace { void PrintObjCTypeParams(ObjCTypeParamList *Params); + enum class AttrPrintLoc { + None = 0, + Left = 1, + Right = 2, + Any = Left | Right, + + LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any) + }; + + void prettyPrintAttributes(Decl *D, raw_ostream &out, + AttrPrintLoc loc = AttrPrintLoc::Any); + public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, const ASTContext &Context, unsigned Indentation = 0, @@ -117,7 +129,11 @@ namespace { 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 +250,40 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { return Out; } -void DeclPrinter::prettyPrintAttributes(Decl *D) { +static bool canPrintOnLeftSide(attr::Kind kind) { + switch (kind) { +#include "clang/Basic/AttrLeftSideCanPrintList.inc" + return true; + default: + return false; + } +} + +static bool canPrintOnLeftSide(const Attr *A) { + if (A->isStandardAttributeSyntax()) + return false; + + return canPrintOnLeftSide(A->getKind()); +} + +static bool mustPrintOnLeftSide(attr::Kind kind) { + switch (kind) { +#include "clang/Basic/AttrLeftSideMustPrintList.inc" + return true; + default: + return false; + } +} + +static bool mustPrintOnLeftSide(const Attr *A) { + if (A->isDeclspecAttribute()) + return true; + + return mustPrintOnLeftSide(A->getKind()); +} + +void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out, + AttrPrintLoc Loc) { if (Policy.PolishForDeclaration) return; @@ -243,15 +292,32 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) { 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; + + AttrPrintLoc AttrLoc = AttrPrintLoc::Right; + if (mustPrintOnLeftSide(A)) { + // If we must always print on left side (e.g. declspec), then mark as + // so. + AttrLoc = AttrPrintLoc::Left; + } else if (canPrintOnLeftSide(A)) { + // For functions with body defined we print the attributes on the left + // side so that GCC accept our dumps as well. + if (const FunctionDecl *FD = dyn_cast(D); + FD && FD->isThisDeclarationADefinition()) + // In case Decl is a function with a body, then attrs should be print + // on the left side. + AttrLoc = AttrPrintLoc::Left; + + // In case it is a variable declaration with a ctor, then allow + // printing on the left side for readbility. + else if (const VarDecl *VD = dyn_cast(D); + VD && VD->getInit() && + VD->getInitStyle() == VarDecl::CallInit) + AttrLoc = AttrPrintLoc::Left; } + + // Only print the side matches the user requested. + if ((Loc & AttrLoc) != AttrPrintLoc::None) + A->printPretty(Out, Policy); } } } @@ -613,6 +679,22 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { printTemplateParameters(D->getTemplateParameterList(I)); } + std::string LeftsideAttrs; + llvm::raw_string_ostream LSAS(LeftsideAttrs); + + prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left); + + // prettyPrintAttributes print a space on left side of the attribute. + if (LeftsideAttrs[0] == ' ') { + // Skip the space prettyPrintAttributes generated. + LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' ')); + + // Add a single space between the attribute and the Decl name. + LSAS << ' '; + } + + Out << LeftsideAttrs; + CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); CXXDeductionGuideDecl *GuideDecl = dyn_cast(D); @@ -774,7 +856,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Ty.print(Out, Policy, Proto); } - prettyPrintAttributes(D); + prettyPrintAttributes(D, Out, AttrPrintLoc::Right); if (D->isPure()) Out << " = 0"; @@ -867,6 +949,23 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { prettyPrintPragmas(D); + std::string LeftSide; + llvm::raw_string_ostream LeftSideStream(LeftSide); + + // Print attributes that should be placed on the left, such as __declspec. + prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left); + + // prettyPrintAttributes print a space on left side of the attribute. + if (LeftSide[0] == ' ') { + // Skip the space prettyPrintAttributes generated. + LeftSide.erase(0, LeftSide.find_first_not_of(' ')); + + // Add a single space between the attribute and the Decl name. + LeftSideStream << ' '; + } + + Out << LeftSide; + QualType T = D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); @@ -899,10 +998,19 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - printDeclType(T, (isa(D) && Policy.CleanUglifiedParameters && - D->getIdentifier()) - ? D->getIdentifier()->deuglifiedName() - : D->getName()); + StringRef Name; + + Name = (isa(D) && Policy.CleanUglifiedParameters && + D->getIdentifier()) + ? D->getIdentifier()->deuglifiedName() + : D->getName(); + + printDeclType(T, Name); + + // Print the attributes that should be placed right before the end of the + // decl. + prettyPrintAttributes(D, Out, AttrPrintLoc::Right); + Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; @@ -931,7 +1039,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { Out << ")"; } } - prettyPrintAttributes(D); } 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 index 000000000000..d7a53f958669 --- /dev/null +++ b/clang/test/AST/ast-print-attr-knr.c @@ -0,0 +1,17 @@ +// 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 i __attribute__((unused)); +// CHECK-NEXT: { +// CHECK-NEXT: return 0; +// CHECK-NEXT: } +int knr(i) int i __attribute__((unused)); { return 0; } + +// CHECK: __attribute__((unused)) int knr2(i) +// CHECK-NEXT: int i; +// CHECK-NEXT: { +// CHECK-NEXT: return 0; +// CHECK-NEXT: } +__attribute__((unused)) int knr2(i) int i; { return 0; } diff --git a/clang/test/AST/ast-print-attr.c b/clang/test/AST/ast-print-attr.c index 4140ae6ac11f..8e047f16bb16 100644 --- a/clang/test/AST/ast-print-attr.c +++ b/clang/test/AST/ast-print-attr.c @@ -32,3 +32,9 @@ int *fun_returns() __attribute__((ownership_returns(fun_returns))); // 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 x __attribute__((unused)) = 0; +// CHECK-NEXT: return x; +// CHECK-NEXT: } +int fun_var_unused() { int x __attribute__((unused)) = 0; return x; } diff --git a/clang/test/AST/ast-print-method-decl.cpp b/clang/test/AST/ast-print-method-decl.cpp index 37ddefcb611e..9f5d11260994 100644 --- a/clang/test/AST/ast-print-method-decl.cpp +++ b/clang/test/AST/ast-print-method-decl.cpp @@ -95,7 +95,7 @@ struct DefMethodsWithoutBody { // CHECK-NEXT: DefMethodsWithoutBody() = default; ~DefMethodsWithoutBody() = default; - // CHECK-NEXT: void m1() __attribute__((alias("X"))); + // CHECK-NEXT: __attribute__((alias("X"))) void m1(); void m1() __attribute__((alias("X"))); // CHECK-NEXT: }; diff --git a/clang/test/AST/ast-print-pragmas.cpp b/clang/test/AST/ast-print-pragmas.cpp index 5f27ff71b4ee..5059c5710189 100644 --- a/clang/test/AST/ast-print-pragmas.cpp +++ b/clang/test/AST/ast-print-pragmas.cpp @@ -93,7 +93,7 @@ void test_templates(int *List, int Length) { #ifdef MS_EXT #pragma init_seg(compiler) // MS-EXT: #pragma init_seg (.CRT$XCC){{$}} -// MS-EXT-NEXT: int x = 3 __declspec(thread); -int __declspec(thread) x = 3; +// MS-EXT-NEXT: __declspec(thread) int x = 3; +__declspec(thread) int x = 3; #endif //MS_EXT diff --git a/clang/test/Analysis/blocks.mm b/clang/test/Analysis/blocks.mm index 81db705b6afb..3ac11aa5a620 100644 --- a/clang/test/Analysis/blocks.mm +++ b/clang/test/Analysis/blocks.mm @@ -78,7 +78,7 @@ void testBlockWithCaptureByReference() { // 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: __attribute__((blocks("byref"))) StructWithCopyConstructor s(5); // CHECK-NEXT: 4: ^{ } // CHECK-NEXT: 5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void) // CHECK-NEXT: Preds (1): B2 diff --git a/clang/test/OpenMP/assumes_codegen.cpp b/clang/test/OpenMP/assumes_codegen.cpp index 884c980bf30e..e47b8ff5b7af 100644 --- a/clang/test/OpenMP/assumes_codegen.cpp +++ b/clang/test/OpenMP/assumes_codegen.cpp @@ -67,41 +67,41 @@ int lambda_outer() { } #pragma omp end assumes -// AST: void foo() __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST: __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void foo() { // AST-NEXT: } // AST-NEXT: class BAR { // AST-NEXT: public: -// AST-NEXT: BAR() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAR() { // AST-NEXT: } -// AST-NEXT: void bar1() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar1() { // AST-NEXT: } -// AST-NEXT: static void bar2() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void bar2() { // AST-NEXT: } // AST-NEXT: }; -// AST-NEXT: void bar() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void bar() { // AST-NEXT: BAR b; // AST-NEXT: } // AST-NEXT: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))); // AST-NEXT: template class BAZ { // AST-NEXT: public: -// AST-NEXT: BAZ() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ() { // AST-NEXT: } -// AST-NEXT: void baz1() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz1() { // AST-NEXT: } -// AST-NEXT: static void baz2() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) static void baz2() { // AST-NEXT: } // AST-NEXT: }; // AST-NEXT: template<> class BAZ { // AST-NEXT: public: -// AST-NEXT: BAZ() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) BAZ() { // AST-NEXT: } // AST-NEXT: void baz1() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))); // AST-NEXT: static void baz2() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))); // AST-NEXT: }; -// AST-NEXT: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void baz() { // AST-NEXT: BAZ b; // AST-NEXT: } -// AST-NEXT: int lambda_outer() __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) { +// AST-NEXT: __attribute__((assume("ompx_lambda_assumption"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) int lambda_outer() { // AST-NEXT: auto lambda_inner = []() { // AST-NEXT: return 42; // AST-NEXT: }; diff --git a/clang/test/OpenMP/assumes_print.cpp b/clang/test/OpenMP/assumes_print.cpp index eaaf55ccfd05..a7f04edb3b1a 100644 --- a/clang/test/OpenMP/assumes_print.cpp +++ b/clang/test/OpenMP/assumes_print.cpp @@ -37,8 +37,8 @@ void baz() { } #pragma omp end assumes -// CHECK: void foo() __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) -// CHECK: void bar() __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) -// CHECK: void baz() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) +// CHECK: __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void foo() +// CHECK: __attribute__((assume("ompx_range_bar_only"))) __attribute__((assume("ompx_range_bar_only_2"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void bar() +// CHECK: __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines"))) __attribute__((assume("omp_no_openmp"))) void baz() #endif diff --git a/clang/test/OpenMP/assumes_template_print.cpp b/clang/test/OpenMP/assumes_template_print.cpp index c73095e6f771..bd1100fbefff 100644 --- a/clang/test/OpenMP/assumes_template_print.cpp +++ b/clang/test/OpenMP/assumes_template_print.cpp @@ -17,7 +17,7 @@ template struct S { int a; // CHECK: template struct S { -// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() { void foo() { #pragma omp parallel {} @@ -25,15 +25,15 @@ struct S { }; // CHECK: template<> struct S { -// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() { #pragma omp begin assumes no_openmp -// CHECK: void S_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_no_call() { void S_with_assumes_no_call() { S s; s.a = 0; } -// CHECK: void S_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_call() { void S_with_assumes_call() { S s; s.a = 0; @@ -42,7 +42,7 @@ void S_with_assumes_call() { } #pragma omp end assumes -// CHECK: void S_without_assumes() __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) void S_without_assumes() { void S_without_assumes() { S s; s.foo(); @@ -54,7 +54,7 @@ void S_without_assumes() { template struct P { // CHECK: template struct P { -// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) void foo() { int a; void foo() { #pragma omp parallel @@ -65,21 +65,21 @@ struct P { // TODO: Avoid the duplication here: // CHECK: template<> struct P { -// CHECK: void foo() __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption"))) void foo() { -// CHECK: void P_without_assumes() __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("ompx_global_assumption"))) void P_without_assumes() { void P_without_assumes() { P p; p.foo(); } #pragma omp begin assumes no_openmp -// CHECK: void P_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_no_call() { void P_with_assumes_no_call() { P p; p.a = 0; } -// CHECK: void P_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) { +// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_call() { void P_with_assumes_call() { P p; p.a = 0; diff --git a/clang/test/OpenMP/declare_simd_ast_print.cpp b/clang/test/OpenMP/declare_simd_ast_print.cpp index 565dc2dfc04d..1adf95226c8b 100644 --- a/clang/test/OpenMP/declare_simd_ast_print.cpp +++ b/clang/test/OpenMP/declare_simd_ast_print.cpp @@ -60,11 +60,11 @@ void h(int *hp, int *hp2, int *hq, int *lin) class VV { // CHECK: #pragma omp declare simd uniform(this, a) linear(val(b): a) - // CHECK-NEXT: int add(int a, int b) __attribute__((cold)) { + // CHECK-NEXT: __attribute__((cold)) int add(int a, int b) { // CHECK-NEXT: return a + b; // CHECK-NEXT: } #pragma omp declare simd uniform(this, a) linear(val(b): a) - int add(int a, int b) __attribute__((cold)) { return a + b; } + __attribute__((cold)) int add(int a, int b) { return a + b; } // CHECK: #pragma omp declare simd aligned(b: 4) aligned(a) linear(ref(b): 4) linear(val(this)) linear(val(a)) // CHECK-NEXT: float taddpf(float *a, float *&b) { diff --git a/clang/test/Sema/attr-print.c b/clang/test/Sema/attr-print.c index cf6b2463c7bb..ffa27de4a5d3 100644 --- a/clang/test/Sema/attr-print.c +++ b/clang/test/Sema/attr-print.c @@ -3,8 +3,7 @@ // CHECK: int x __attribute__((aligned(4))); int x __attribute__((aligned(4))); -// FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); +// CHECK: __declspec(align(4)) int y; __declspec(align(4)) int y; // CHECK: short arr[3] __attribute__((aligned)); diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp index fa8059fc8ab3..dff290be696b 100644 --- a/clang/test/SemaCXX/attr-print.cpp +++ b/clang/test/SemaCXX/attr-print.cpp @@ -3,8 +3,7 @@ // CHECK: int x __attribute__((aligned(4))); int x __attribute__((aligned(4))); -// FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); +// CHECK: __declspec(align(4)) int y; __declspec(align(4)) int y; // CHECK: void foo() __attribute__((const)); diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp index 2bf0ea5d8258..7095c462031d 100644 --- a/clang/test/SemaCXX/cxx11-attr-print.cpp +++ b/clang/test/SemaCXX/cxx11-attr-print.cpp @@ -3,8 +3,7 @@ // CHECK: int x __attribute__((aligned(4))); int x __attribute__((aligned(4))); -// FIXME: Print this at a valid location for a __declspec attr. -// CHECK: int y __declspec(align(4)); +// CHECK: __declspec(align(4)) int y; __declspec(align(4)) int y; // CHECK: int z {{\[}}[gnu::aligned(4)]]; @@ -66,7 +65,7 @@ void f8 (void *, const char *, ...) __attribute__ ((format (printf, 2, 3))); // CHECK: int m __attribute__((aligned(4 // CHECK: int n alignas(4 // CHECK: int p alignas(int -// CHECK: static int f() __attribute__((pure)) +// CHECK: __attribute__((pure)) static int f() // CHECK: static int g() {{\[}}[gnu::pure]] template struct S { __attribute__((aligned(4))) int m; @@ -82,7 +81,7 @@ template struct S { // CHECK: int m __attribute__((aligned(4 // CHECK: int n alignas(4 -// CHECK: static int f() __attribute__((pure)) +// CHECK: __attribute__((pure)) static int f() // CHECK: static int g() {{\[}}[gnu::pure]] template struct S; diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index fe9e4cd757d3..ff6ffe16b4cc 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3207,6 +3207,27 @@ void EmitClangAttrList(RecordKeeper &Records, raw_ostream &OS) { OS << "#undef PRAGMA_SPELLING_ATTR\n"; } +// Emits the enumeration list for attributes. +void EmitClangAttrPrintList(const std::string &FieldName, RecordKeeper &Records, + raw_ostream &OS) { + emitSourceFileHeader( + "List of attributes that can be print on the left side of a decl", OS); + + AttrClassHierarchy Hierarchy(Records); + + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); + std::vector PragmaAttrs; + for (auto *Attr : Attrs) { + if (!Attr->getValueAsBit("ASTNode")) + continue; + + if (!Attr->getValueAsBit(FieldName)) + continue; + + OS << "case attr::" << Attr->getName() << ":\n"; + } +} + // Emits the enumeration list for attributes. void EmitClangAttrSubjectMatchRuleList(RecordKeeper &Records, raw_ostream &OS) { emitSourceFileHeader( diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 38215abd9d9b..7efb6c731d3e 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -31,6 +31,8 @@ enum ActionType { GenClangAttrSubjectMatchRulesParserStringSwitches, GenClangAttrImpl, GenClangAttrList, + GenClangAttrCanPrintLeftList, + GenClangAttrMustPrintLeftList, GenClangAttrDocTable, GenClangAttrSubjectMatchRuleList, GenClangAttrPCHRead, @@ -127,6 +129,14 @@ cl::opt Action( "Generate clang attribute implementations"), clEnumValN(GenClangAttrList, "gen-clang-attr-list", "Generate a clang attribute list"), + clEnumValN(GenClangAttrCanPrintLeftList, + "gen-clang-attr-can-print-left-list", + "Generate list of attributes that can be printed on left " + "side of a decl"), + clEnumValN(GenClangAttrMustPrintLeftList, + "gen-clang-attr-must-print-left-list", + "Generate list of attributes that must be printed on left " + "side of a decl"), clEnumValN(GenClangAttrDocTable, "gen-clang-attr-doc-table", "Generate a table of attribute documentation"), clEnumValN(GenClangAttrSubjectMatchRuleList, @@ -315,6 +325,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangAttrList: EmitClangAttrList(Records, OS); break; + case GenClangAttrCanPrintLeftList: + EmitClangAttrPrintList("CanPrintOnLeft", Records, OS); + break; + case GenClangAttrMustPrintLeftList: + EmitClangAttrPrintList("PrintOnLeft", Records, OS); + break; case GenClangAttrDocTable: EmitClangAttrDocTable(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index 8265a531a98f..d8f447069376 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -39,6 +39,8 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches( void EmitClangAttrClass(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrImpl(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitClangAttrPrintList(const std::string &FieldName, + llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrSubjectMatchRuleList(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);