[clang] Rework the printing of attributes (PR #87281)

Vassil Vassilev via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 1 13:28:48 PDT 2024


https://github.com/vgvassilev created https://github.com/llvm/llvm-project/pull/87281

Commit https://github.com/llvm/llvm-project/commit/46f3ade introduced a notion of printing the attributes on the left to improve the printing of attributes attached to variable declarations. The intent was to produce more GCC compatible code because clang tends to print the attributes on the right hand side which is not accepted by gcc.

This approach has increased the complexity in tablegen and the attrubutes themselves as now the are supposed to know where they could appear. That lead to mishandling of the `override` keyword which is modelled as an attribute in clang.

This patch takes an inspiration from the existing approach and tries to keep the position of the attributes as they were written. To do so we use simpler heuristic which checks if the source locations of the attribute precedes the declaration. If so, it is considered to be printed before the declaration.

Fixes https://github.com/llvm/llvm-project/issues/87151

>From 94f1c8653903cc3db55abd641c68a9dd11f05df3 Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Mon, 1 Apr 2024 15:01:33 +0000
Subject: [PATCH 1/5] Revert "Remove extra switch from  0323938d"

This reverts commit 6c0b9e35761738726aded3b399db89eb0a86f82b.
---
 clang/lib/AST/DeclPrinter.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index edbcdfe4d55bc9..1ab74c71d0fd49 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -277,6 +277,7 @@ static bool canPrintOnLeftSide(const Attr *A) {
 }
 
 static bool mustPrintOnLeftSide(attr::Kind kind) {
+  switch (kind) {
 #ifdef CLANG_ATTR_LIST_PrintOnLeft
   switch (kind) {
   CLANG_ATTR_LIST_PrintOnLeft

>From 871f5b06e0da167c4cf50d336bdc38f0eb684b6b Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Mon, 1 Apr 2024 15:01:44 +0000
Subject: [PATCH 2/5] Revert "Fix warning in MSVC"

This reverts commit 0323938d3c7a1a48b60a7dea8ec7300e98b4a931.
---
 clang/lib/AST/DeclPrinter.cpp             | 20 +++-----------------
 clang/utils/TableGen/ClangAttrEmitter.cpp | 11 +----------
 2 files changed, 4 insertions(+), 27 deletions(-)

diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 1ab74c71d0fd49..c2e0edd5f1f12c 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -250,23 +250,13 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
   return Out;
 }
 
-// For CLANG_ATTR_LIST_CanPrintOnLeft macro.
-#include "clang/Basic/AttrLeftSideCanPrintList.inc"
-
-// For CLANG_ATTR_LIST_PrintOnLeft macro.
-#include "clang/Basic/AttrLeftSideMustPrintList.inc"
-
 static bool canPrintOnLeftSide(attr::Kind kind) {
-#ifdef CLANG_ATTR_LIST_CanPrintOnLeft
   switch (kind) {
-  CLANG_ATTR_LIST_CanPrintOnLeft
+#include "clang/Basic/AttrLeftSideCanPrintList.inc"
     return true;
   default:
     return false;
   }
-#else
-  return false;
-#endif
 }
 
 static bool canPrintOnLeftSide(const Attr *A) {
@@ -278,16 +268,11 @@ static bool canPrintOnLeftSide(const Attr *A) {
 
 static bool mustPrintOnLeftSide(attr::Kind kind) {
   switch (kind) {
-#ifdef CLANG_ATTR_LIST_PrintOnLeft
-  switch (kind) {
-  CLANG_ATTR_LIST_PrintOnLeft
+#include "clang/Basic/AttrLeftSideMustPrintList.inc"
     return true;
   default:
     return false;
   }
-#else
-  return false;
-#endif
 }
 
 static bool mustPrintOnLeftSide(const Attr *A) {
@@ -329,6 +314,7 @@ void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out,
                    VD->getInitStyle() == VarDecl::CallInit)
           AttrLoc = AttrPrintLoc::Left;
       }
+
       // Only print the side matches the user requested.
       if ((Loc & AttrLoc) != AttrPrintLoc::None)
         A->printPretty(Out, Policy);
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index eb5c34d15693d7..985cc1aee579e9 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3327,8 +3327,6 @@ void EmitClangAttrPrintList(const std::string &FieldName, RecordKeeper &Records,
 
   std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
   std::vector<Record *> PragmaAttrs;
-  bool first = false;
-
   for (auto *Attr : Attrs) {
     if (!Attr->getValueAsBit("ASTNode"))
       continue;
@@ -3336,15 +3334,8 @@ void EmitClangAttrPrintList(const std::string &FieldName, RecordKeeper &Records,
     if (!Attr->getValueAsBit(FieldName))
       continue;
 
-    if (!first) {
-      first = true;
-      OS << "#define CLANG_ATTR_LIST_" << FieldName;
-    }
-
-    OS << " \\\n case attr::" << Attr->getName() << ":";
+    OS << "case attr::" << Attr->getName() << ":\n";
   }
-
-  OS << '\n';
 }
 
 // Emits the enumeration list for attributes.

>From e7e2e90da2a9644b0ca8a4c5c464c75a35f019a5 Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Mon, 1 Apr 2024 15:11:28 +0000
Subject: [PATCH 3/5] Revert "Fix ast print of variables with attributes"

This reverts commit 46f3ade5083b8bfce55c78a21086a487eaac6f99.
---
 clang/include/clang/Basic/Attr.td            |  14 +-
 clang/include/clang/Basic/CMakeLists.txt     |  10 --
 clang/lib/AST/DeclPrinter.cpp                | 137 +++----------------
 clang/test/AST/ast-print-attr-knr.c          |  17 ---
 clang/test/AST/ast-print-attr.c              |   6 -
 clang/test/AST/ast-print-method-decl.cpp     |   2 +-
 clang/test/AST/ast-print-pragmas.cpp         |   4 +-
 clang/test/Analysis/blocks.mm                |   2 +-
 clang/test/OpenMP/assumes_codegen.cpp        |  22 +--
 clang/test/OpenMP/assumes_print.cpp          |   6 +-
 clang/test/OpenMP/assumes_template_print.cpp |  20 +--
 clang/test/OpenMP/declare_simd_ast_print.cpp |   4 +-
 clang/test/Sema/attr-print.c                 |   3 +-
 clang/test/SemaCXX/attr-print.cpp            |   3 +-
 clang/test/SemaCXX/cxx11-attr-print.cpp      |   7 +-
 clang/utils/TableGen/ClangAttrEmitter.cpp    |  22 ---
 clang/utils/TableGen/TableGen.cpp            |  16 ---
 clang/utils/TableGen/TableGenBackends.h      |   2 -
 18 files changed, 55 insertions(+), 242 deletions(-)
 delete mode 100644 clang/test/AST/ast-print-attr-knr.c

diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 3e03e55612645b..bb77f62405fbec 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -324,13 +324,10 @@ class Spelling<string name, string variety, int version = 1> {
 }
 
 class GNU<string name> : Spelling<name, "GNU">;
-class Declspec<string name> : Spelling<name, "Declspec"> {
-  bit PrintOnLeft = 1;
-}
+class Declspec<string name> : Spelling<name, "Declspec">;
 class Microsoft<string name> : Spelling<name, "Microsoft">;
 class CXX11<string namespace, string name, int version = 1>
     : Spelling<name, "CXX11", version> {
-  bit CanPrintOnLeft = 0;
   string Namespace = namespace;
 }
 class C23<string namespace, string name, int version = 1>
@@ -596,12 +593,6 @@ class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
 def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
 
 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<Spelling> Spellings;
   // The things to which an attribute can appertain
@@ -937,7 +928,6 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
 }
 
 def AsmLabel : InheritableAttr {
-  let CanPrintOnLeft = 0;
   let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
   let Args = [
     // Label specifies the mangled name for the decl.
@@ -1534,7 +1524,6 @@ 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.
@@ -3149,7 +3138,6 @@ 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 7d53c751c13ac4..2ef6ddc68f4bf3 100644
--- a/clang/include/clang/Basic/CMakeLists.txt
+++ b/clang/include/clang/Basic/CMakeLists.txt
@@ -31,16 +31,6 @@ 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 c2e0edd5f1f12c..9aba0bec0b0cc2 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -49,18 +49,6 @@ 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,
@@ -129,11 +117,7 @@ namespace {
                                 const TemplateParameterList *Params);
     void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
                                 const TemplateParameterList *Params);
-
-    inline void prettyPrintAttributes(Decl *D) {
-      prettyPrintAttributes(D, Out);
-    }
-
+    void prettyPrintAttributes(Decl *D);
     void prettyPrintPragmas(Decl *D);
     void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
   };
@@ -250,40 +234,7 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
   return Out;
 }
 
-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) {
+void DeclPrinter::prettyPrintAttributes(Decl *D) {
   if (Policy.PolishForDeclaration)
     return;
 
@@ -292,32 +243,15 @@ void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out,
     for (auto *A : Attrs) {
       if (A->isInherited() || A->isImplicit())
         continue;
-
-      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<FunctionDecl>(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<VarDecl>(D);
-                   VD && VD->getInit() &&
-                   VD->getInitStyle() == VarDecl::CallInit)
-          AttrLoc = AttrPrintLoc::Left;
-      }
-
-      // Only print the side matches the user requested.
-      if ((Loc & AttrLoc) != AttrPrintLoc::None)
+      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;
+      }
     }
   }
 }
@@ -689,22 +623,6 @@ 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<CXXConstructorDecl>(D);
   CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
   CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
@@ -870,7 +788,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
     Ty.print(Out, Policy, Proto);
   }
 
-  prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
+  prettyPrintAttributes(D);
 
   if (D->isPureVirtual())
     Out << " = 0";
@@ -967,23 +885,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
       Param && Param->isExplicitObjectParameter())
     Out << "this ";
 
-  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());
@@ -1016,21 +917,14 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
     }
   }
 
-  StringRef Name;
-
-  Name = (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
-          D->getIdentifier())
-             ? D->getIdentifier()->deuglifiedName()
-             : D->getName();
-
   if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
       !Policy.SuppressUnwrittenScope)
     MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out);
-  printDeclType(T, Name);
 
-  // Print the attributes that should be placed right before the end of the
-  // decl.
-  prettyPrintAttributes(D, Out, AttrPrintLoc::Right);
+  printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
+                    D->getIdentifier())
+                       ? D->getIdentifier()->deuglifiedName()
+                       : D->getName());
 
   Expr *Init = D->getInit();
   if (!Policy.SuppressInitializers && Init) {
@@ -1060,6 +954,7 @@ 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
deleted file mode 100644
index d7a53f958669f3..00000000000000
--- a/clang/test/AST/ast-print-attr-knr.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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 8e047f16bb16ca..4140ae6ac11fe3 100644
--- a/clang/test/AST/ast-print-attr.c
+++ b/clang/test/AST/ast-print-attr.c
@@ -32,9 +32,3 @@ 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 75dea0cac16be1..cb5d10096381a9 100644
--- a/clang/test/AST/ast-print-method-decl.cpp
+++ b/clang/test/AST/ast-print-method-decl.cpp
@@ -94,7 +94,7 @@ struct DefMethodsWithoutBody {
   // CHECK-NEXT: DefMethodsWithoutBody() = default;
   ~DefMethodsWithoutBody() = default;
 
-  // CHECK-NEXT: __attribute__((alias("X"))) void m1();
+  // CHECK-NEXT: void m1() __attribute__((alias("X")));
   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 5059c5710189ee..5f27ff71b4ee8b 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: __declspec(thread) int x = 3;
-__declspec(thread) int x = 3;
+// MS-EXT-NEXT: int x = 3 __declspec(thread);
+int __declspec(thread) x = 3;
 #endif //MS_EXT
 
diff --git a/clang/test/Analysis/blocks.mm b/clang/test/Analysis/blocks.mm
index 3ac11aa5a620ed..81db705b6afbc2 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: __attribute__((blocks("byref"))) StructWithCopyConstructor s(5);
+// CHECK-NEXT:   3: StructWithCopyConstructor s(5) __attribute__((blocks("byref")));
 // 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 6a5871c303aade..5d8a2ae909a768 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:      __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) void foo() {
+// AST:      void foo() __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp"))) {
 // AST-NEXT: }
 // AST-NEXT: class BAR {
 // AST-NEXT: public:
-// 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:     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:     }
-// 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:     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:     }
-// 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:     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:     }
 // AST-NEXT: };
-// 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: 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:     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 <typename T> class BAZ {
 // AST-NEXT: public:
-// 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<T>()      {
+// AST-NEXT:     BAZ<T>() __attribute__((assume("ompx_1234"))) __attribute__((assume("omp_no_openmp_routines,ompx_another_warning,ompx_after_invalid_clauses"))) __attribute__((assume("omp_no_openmp")))     {
 // AST-NEXT:     }
-// 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:     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:     }
-// 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:     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:     }
 // AST-NEXT: };
 // AST-NEXT: template<> class BAZ<float> {
 // AST-NEXT: public:
-// 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:     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:     }
 // 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: __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: 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:     BAZ<float> b;
 // AST-NEXT: }
-// 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: 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:     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 a7f04edb3b1af4..eaaf55ccfd05de 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: __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()
+// 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")))
 
 #endif
diff --git a/clang/test/OpenMP/assumes_template_print.cpp b/clang/test/OpenMP/assumes_template_print.cpp
index bd1100fbefffc6..c73095e6f771f3 100644
--- a/clang/test/OpenMP/assumes_template_print.cpp
+++ b/clang/test/OpenMP/assumes_template_print.cpp
@@ -17,7 +17,7 @@ template <typename T>
 struct S {
   int a;
 // CHECK: template <typename T> struct S {
-// CHECK:     __attribute__((assume("ompx_global_assumption"))) void foo()     {
+// CHECK:     void foo() __attribute__((assume("ompx_global_assumption")))     {
   void foo() {
     #pragma omp parallel
     {}
@@ -25,15 +25,15 @@ struct S {
 };
 
 // CHECK: template<> struct S<int> {
-// CHECK:     __attribute__((assume("ompx_global_assumption"))) void foo()     {
+// CHECK:     void foo() __attribute__((assume("ompx_global_assumption")))     {
 
 #pragma omp begin assumes no_openmp
-// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_no_call() {
+// CHECK: void S_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
 void S_with_assumes_no_call() {
   S<int> s;
   s.a = 0;
 }
-// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void S_with_assumes_call() {
+// CHECK: void S_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
 void S_with_assumes_call() {
   S<int> s;
   s.a = 0;
@@ -42,7 +42,7 @@ void S_with_assumes_call() {
 }
 #pragma omp end assumes
 
-// CHECK: __attribute__((assume("ompx_global_assumption"))) void S_without_assumes() {
+// CHECK: void S_without_assumes() __attribute__((assume("ompx_global_assumption"))) {
 void S_without_assumes() {
   S<int> s;
   s.foo();
@@ -54,7 +54,7 @@ void S_without_assumes() {
 template <typename T>
 struct P {
 // CHECK: template <typename T> struct P {
-// CHECK:    __attribute__((assume("ompx_global_assumption"))) void foo()      {
+// CHECK:     void foo() __attribute__((assume("ompx_global_assumption")))     {
   int a;
   void foo() {
     #pragma omp parallel
@@ -65,21 +65,21 @@ struct P {
 // TODO: Avoid the duplication here:
 
 // CHECK: template<> struct P<int> {
-// CHECK:      __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption"))) void foo()   {
+// CHECK:     void foo() __attribute__((assume("ompx_global_assumption"))) __attribute__((assume("ompx_global_assumption")))     {
 
-// CHECK: __attribute__((assume("ompx_global_assumption"))) void P_without_assumes() {
+// CHECK: void P_without_assumes() __attribute__((assume("ompx_global_assumption"))) {
 void P_without_assumes() {
   P<int> p;
   p.foo();
 }
 
 #pragma omp begin assumes no_openmp
-// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_no_call() {
+// CHECK: void P_with_assumes_no_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
 void P_with_assumes_no_call() {
   P<int> p;
   p.a = 0;
 }
-// CHECK: __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) void P_with_assumes_call() {
+// CHECK: void P_with_assumes_call() __attribute__((assume("omp_no_openmp"))) __attribute__((assume("ompx_global_assumption"))) {
 void P_with_assumes_call() {
   P<int> 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 1adf95226c8beb..565dc2dfc04d11 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:  __attribute__((cold)) int add(int a, int b)     {
+  // CHECK-NEXT: int add(int a, int b) __attribute__((cold))    {
   // CHECK-NEXT: return a + b;
   // CHECK-NEXT: }
   #pragma omp declare simd uniform(this, a) linear(val(b): a)
-  __attribute__((cold)) int add(int a, int b) { return a + b; }
+  int add(int a, int b) __attribute__((cold)) { 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 8492356e5d2e57..e12c0109efcd9a 100644
--- a/clang/test/Sema/attr-print.c
+++ b/clang/test/Sema/attr-print.c
@@ -3,7 +3,8 @@
 // CHECK: int x __attribute__((aligned(4)));
 int x __attribute__((aligned(4)));
 
-// CHECK: __declspec(align(4)) int y;
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
 __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 c7c58a25504eed..fc11365d14a214 100644
--- a/clang/test/SemaCXX/attr-print.cpp
+++ b/clang/test/SemaCXX/attr-print.cpp
@@ -3,7 +3,8 @@
 // CHECK: int x __attribute__((aligned(4)));
 int x __attribute__((aligned(4)));
 
-// CHECK: __declspec(align(4)) int y;
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
 __declspec(align(4)) int y;
 
 // CHECK: int foo() __attribute__((const));
diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp
index c988972aeb1a5a..e017c8b08b1ddd 100644
--- a/clang/test/SemaCXX/cxx11-attr-print.cpp
+++ b/clang/test/SemaCXX/cxx11-attr-print.cpp
@@ -3,7 +3,8 @@
 // CHECK: int x __attribute__((aligned(4)));
 int x __attribute__((aligned(4)));
 
-// CHECK: __declspec(align(4)) int y;
+// FIXME: Print this at a valid location for a __declspec attr.
+// CHECK: int y __declspec(align(4));
 __declspec(align(4)) int y;
 
 // CHECK: int z {{\[}}[gnu::aligned(4)]];
@@ -65,7 +66,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: __attribute__((pure)) static int f()
+// CHECK: static int f() __attribute__((pure))
 // CHECK: static int g() {{\[}}[gnu::pure]]
 template <typename T> struct S {
   __attribute__((aligned(4))) int m;
@@ -81,7 +82,7 @@ template <typename T> struct S {
 
 // CHECK: int m __attribute__((aligned(4
 // CHECK: int n alignas(4
-// CHECK: __attribute__((pure)) static int f()
+// CHECK: static int f() __attribute__((pure))
 // CHECK: static int g() {{\[}}[gnu::pure]]
 template struct S<int>;
 
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 985cc1aee579e9..9d2e906573443b 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -3316,28 +3316,6 @@ 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,
-      Records);
-
-  AttrClassHierarchy Hierarchy(Records);
-
-  std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
-  std::vector<Record *> 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 3f22e43b97ecd2..42cc704543f18e 100644
--- a/clang/utils/TableGen/TableGen.cpp
+++ b/clang/utils/TableGen/TableGen.cpp
@@ -31,8 +31,6 @@ enum ActionType {
   GenClangAttrSubjectMatchRulesParserStringSwitches,
   GenClangAttrImpl,
   GenClangAttrList,
-  GenClangAttrCanPrintLeftList,
-  GenClangAttrMustPrintLeftList,
   GenClangAttrDocTable,
   GenClangAttrSubjectMatchRuleList,
   GenClangAttrPCHRead,
@@ -134,14 +132,6 @@ cl::opt<ActionType> 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,
@@ -345,12 +335,6 @@ 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 ecd506b7b6b50a..5f2dd257cb90a9 100644
--- a/clang/utils/TableGen/TableGenBackends.h
+++ b/clang/utils/TableGen/TableGenBackends.h
@@ -47,8 +47,6 @@ 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);

>From 4778e900fb645763442ba315f0785a6e1f3c6ede Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Mon, 1 Apr 2024 19:27:39 +0000
Subject: [PATCH 4/5] Rework the printing of attributes.

Commit llvm/llvm-project at 46f3ade introduced a notion of printing the attributes
on the left to improve the printing of attributes attached to variable
declarations. The intent was to produce more GCC compatible code because clang
tends to print the attributes on the right hand side which is not accepted by
gcc.

This approach has increased the complexity in tablegen and the attrubutes
themselves as now the are supposed to know where they could appear. That lead to
mishandling of the `override` keyword which is modelled as an attribute in clang.

This patch takes an inspiration from the existing approach and tries to keep
the position of the attributes as they were written. To do so we use simpler
heuristic which checks if the source locations of the attribute precedes the
declaration. If so, it is considered to be printed before the declaration.

Fixes llvm/llvm-project#87151
---
 clang/lib/AST/DeclPrinter.cpp             | 45 +++++++++++++++++++----
 clang/test/AST/ast-print-attr.c           |  6 +++
 clang/test/AST/ast-print-no-sanitize.cpp  |  2 +-
 clang/test/AST/ast-print-pragmas.cpp      |  4 +-
 clang/test/Analysis/blocks.mm             |  2 +-
 clang/test/Analysis/scopes-cfg-output.cpp |  2 +-
 clang/test/Sema/attr-print.c              |  3 +-
 clang/test/SemaCXX/attr-no-sanitize.cpp   |  6 +--
 clang/test/SemaCXX/attr-print.cpp         |  3 +-
 clang/test/SemaCXX/cxx11-attr-print.cpp   | 15 ++++----
 10 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 9aba0bec0b0cc2..1e62d397db92f8 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -21,6 +21,7 @@
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
@@ -117,7 +118,13 @@ namespace {
                                 const TemplateParameterList *Params);
     void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args,
                                 const TemplateParameterList *Params);
-    void prettyPrintAttributes(Decl *D);
+    enum class AttrPosAsWritten {
+      Unknown = 0,
+      Left = 1,
+      Right = 2,
+    };
+    void prettyPrintAttributes(const Decl *D,
+                               AttrPosAsWritten P = AttrPosAsWritten::Unknown);
     void prettyPrintPragmas(Decl *D);
     void printDeclType(QualType T, StringRef DeclName, bool Pack = false);
   };
@@ -234,12 +241,27 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
   return Out;
 }
 
-void DeclPrinter::prettyPrintAttributes(Decl *D) {
+static DeclPrinter::AttrPosAsWritten getAttrPosAsWritten(const Attr *A,
+                                                         const Decl *D) {
+  SourceLocation ALoc = A->getLoc();
+  SourceLocation DLoc = D->getLocation();
+  const ASTContext &C = D->getASTContext();
+  if (ALoc.isInvalid() || DLoc.isInvalid())
+    return DeclPrinter::AttrPosAsWritten::Unknown;
+
+  if (C.getSourceManager().isBeforeInTranslationUnit(ALoc, DLoc))
+    return DeclPrinter::AttrPosAsWritten::Left;
+
+  return DeclPrinter::AttrPosAsWritten::Right;
+}
+
+void DeclPrinter::prettyPrintAttributes(const Decl *D,
+                                        AttrPosAsWritten P /*=Unknown*/) {
   if (Policy.PolishForDeclaration)
     return;
 
   if (D->hasAttrs()) {
-    AttrVec &Attrs = D->getAttrs();
+    const AttrVec &Attrs = D->getAttrs();
     for (auto *A : Attrs) {
       if (A->isInherited() || A->isImplicit())
         continue;
@@ -249,7 +271,11 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) {
 #include "clang/Basic/AttrList.inc"
         break;
       default:
-        A->printPretty(Out, Policy);
+        if (P == AttrPosAsWritten::Unknown || P == getAttrPosAsWritten(A, D)) {
+          A->printPretty(Out, Policy);
+          if (P == AttrPosAsWritten::Left)
+            Out << " ";
+        }
         break;
       }
     }
@@ -612,8 +638,10 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy,
 
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   if (!D->getDescribedFunctionTemplate() &&
-      !D->isFunctionTemplateSpecialization())
+      !D->isFunctionTemplateSpecialization()) {
     prettyPrintPragmas(D);
+    prettyPrintAttributes(D, AttrPosAsWritten::Left);
+  }
 
   if (D->isFunctionTemplateSpecialization())
     Out << "template<> ";
@@ -788,7 +816,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
     Ty.print(Out, Policy, Proto);
   }
 
-  prettyPrintAttributes(D);
+  prettyPrintAttributes(D, AttrPosAsWritten::Right);
 
   if (D->isPureVirtual())
     Out << " = 0";
@@ -881,6 +909,8 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
 void DeclPrinter::VisitVarDecl(VarDecl *D) {
   prettyPrintPragmas(D);
 
+  prettyPrintAttributes(D, AttrPosAsWritten::Left);
+
   if (const auto *Param = dyn_cast<ParmVarDecl>(D);
       Param && Param->isExplicitObjectParameter())
     Out << "this ";
@@ -926,6 +956,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
                        ? D->getIdentifier()->deuglifiedName()
                        : D->getName());
 
+  prettyPrintAttributes(D, AttrPosAsWritten::Right);
+
   Expr *Init = D->getInit();
   if (!Policy.SuppressInitializers && Init) {
     bool ImplicitInit = false;
@@ -954,7 +986,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
         Out << ")";
     }
   }
-  prettyPrintAttributes(D);
 }
 
 void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) {
diff --git a/clang/test/AST/ast-print-attr.c b/clang/test/AST/ast-print-attr.c
index 4140ae6ac11fe3..8e047f16bb16ca 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-no-sanitize.cpp b/clang/test/AST/ast-print-no-sanitize.cpp
index 4ff97190955add..a5ada8246f0c0b 100644
--- a/clang/test/AST/ast-print-no-sanitize.cpp
+++ b/clang/test/AST/ast-print-no-sanitize.cpp
@@ -4,4 +4,4 @@ void should_not_crash_1() __attribute__((no_sanitize_memory));
 [[clang::no_sanitize_memory]] void should_not_crash_2();
 
 // CHECK: void should_not_crash_1() __attribute__((no_sanitize("memory")));
-// CHECK: void should_not_crash_2() {{\[\[}}clang::no_sanitize("memory"){{\]\]}};
+// CHECK: {{\[\[}}clang::no_sanitize("memory"){{\]\]}} void should_not_crash_2();
diff --git a/clang/test/AST/ast-print-pragmas.cpp b/clang/test/AST/ast-print-pragmas.cpp
index 5f27ff71b4ee8b..5059c5710189ee 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 81db705b6afbc2..3ac11aa5a620ed 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/Analysis/scopes-cfg-output.cpp b/clang/test/Analysis/scopes-cfg-output.cpp
index 4eb8967e373516..5e6706602d4564 100644
--- a/clang/test/Analysis/scopes-cfg-output.cpp
+++ b/clang/test/Analysis/scopes-cfg-output.cpp
@@ -1469,7 +1469,7 @@ void test_cleanup_functions2(int m) {
 // CHECK:       [B1]
 // CHECK-NEXT:    1: CFGScopeBegin(f)
 // CHECK-NEXT:    2:  (CXXConstructExpr, [B1.3], F)
-// CHECK-NEXT:    3: __attribute__((cleanup(cleanup_F))) F f;
+// CHECK-NEXT:    3: F f __attribute__((cleanup(cleanup_F)));
 // CHECK-NEXT:    4: CleanupFunction (cleanup_F)
 // CHECK-NEXT:    5: [B1.3].~F() (Implicit destructor)
 // CHECK-NEXT:    6: CFGScopeEnd(f)
diff --git a/clang/test/Sema/attr-print.c b/clang/test/Sema/attr-print.c
index e12c0109efcd9a..8492356e5d2e57 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-no-sanitize.cpp b/clang/test/SemaCXX/attr-no-sanitize.cpp
index a464947fe5a346..8951f616ce0f05 100644
--- a/clang/test/SemaCXX/attr-no-sanitize.cpp
+++ b/clang/test/SemaCXX/attr-no-sanitize.cpp
@@ -16,12 +16,12 @@ int f3() __attribute__((no_sanitize("address")));
 
 // DUMP-LABEL: FunctionDecl {{.*}} f4
 // DUMP: NoSanitizeAttr {{.*}} thread
-// PRINT: int f4() {{\[\[}}clang::no_sanitize("thread")]]
+// PRINT: {{\[\[}}clang::no_sanitize("thread")]] int f4()
 [[clang::no_sanitize("thread")]] int f4();
 
 // DUMP-LABEL: FunctionDecl {{.*}} f4
 // DUMP: NoSanitizeAttr {{.*}} hwaddress
-// PRINT: int f4() {{\[\[}}clang::no_sanitize("hwaddress")]]
+// PRINT: {{\[\[}}clang::no_sanitize("hwaddress")]] int f4()
 [[clang::no_sanitize("hwaddress")]] int f4();
 
 // DUMP-LABEL: FunctionDecl {{.*}} f5
@@ -36,5 +36,5 @@ int f6() __attribute__((no_sanitize("unknown"))); // expected-warning{{unknown s
 
 // DUMP-LABEL: FunctionDecl {{.*}} f7
 // DUMP: NoSanitizeAttr {{.*}} memtag
-// PRINT: int f7() {{\[\[}}clang::no_sanitize("memtag")]]
+// PRINT: {{\[\[}}clang::no_sanitize("memtag")]] int f7()
 [[clang::no_sanitize("memtag")]] int f7();
diff --git a/clang/test/SemaCXX/attr-print.cpp b/clang/test/SemaCXX/attr-print.cpp
index fc11365d14a214..c7c58a25504eed 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: int foo() __attribute__((const));
diff --git a/clang/test/SemaCXX/cxx11-attr-print.cpp b/clang/test/SemaCXX/cxx11-attr-print.cpp
index e017c8b08b1ddd..a169d1b4409b4d 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)]];
@@ -25,10 +24,10 @@ int d [[deprecated("warning")]];
 // CHECK: __attribute__((deprecated("warning", "fixit")));
 int e __attribute__((deprecated("warning", "fixit")));
 
-// CHECK: int cxx11_alignas alignas(4);
+// CHECK: alignas(4) int cxx11_alignas;
 alignas(4) int cxx11_alignas;
 
-// CHECK: int c11_alignas _Alignas(int);
+// CHECK: _Alignas(int) int c11_alignas;
 _Alignas(int) int c11_alignas;
 
 // CHECK: int foo() __attribute__((const));
@@ -66,8 +65,8 @@ 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: static int g() {{\[}}[gnu::pure]]
+// CHECK: __attribute__((pure)) static int f()
+// CHECK: {{\[}}[gnu::pure]] static int g()
 template <typename T> struct S {
   __attribute__((aligned(4))) int m;
   alignas(4) int n;
@@ -82,8 +81,8 @@ template <typename T> struct S {
 
 // CHECK: int m __attribute__((aligned(4
 // CHECK: int n alignas(4
-// CHECK: static int f() __attribute__((pure))
-// CHECK: static int g() {{\[}}[gnu::pure]]
+// CHECK: __attribute__((pure)) static int f()
+// CHECK: {{\[}}[gnu::pure]] static int g()
 template struct S<int>;
 
 // CHECK: using Small2 {{\[}}[gnu::mode(byte)]] = int;

>From 4686e8f9402866b969c51fe02d7b06032f01c6e5 Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <v.g.vassilev at gmail.com>
Date: Mon, 1 Apr 2024 20:25:21 +0000
Subject: [PATCH 5/5] OpenMP attributes now respect the pragma location

---
 clang/test/OpenMP/assumes_codegen.cpp        | 26 ++++++++++----------
 clang/test/OpenMP/assumes_print.cpp          |  4 +--
 clang/test/OpenMP/assumes_template_print.cpp | 14 +++++------
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/clang/test/OpenMP/assumes_codegen.cpp b/clang/test/OpenMP/assumes_codegen.cpp
index 5d8a2ae909a768..4db4327e85490c 100644
--- a/clang/test/OpenMP/assumes_codegen.cpp
+++ b/clang/test/OpenMP/assumes_codegen.cpp
@@ -71,37 +71,37 @@ int lambda_outer() {
 // 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: __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: template <typename T> class BAZ {
 // AST-NEXT: public:
-// AST-NEXT:     BAZ<T>() __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<T>()      {
 // 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<float> {
 // 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:     __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"))) void baz1();
+// 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"))) static void baz2();
 // 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<float> 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 eaaf55ccfd05de..da3629f70408dc 100644
--- a/clang/test/OpenMP/assumes_print.cpp
+++ b/clang/test/OpenMP/assumes_print.cpp
@@ -38,7 +38,7 @@ 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("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 c73095e6f771f3..d4558f49f700e2 100644
--- a/clang/test/OpenMP/assumes_template_print.cpp
+++ b/clang/test/OpenMP/assumes_template_print.cpp
@@ -28,12 +28,12 @@ struct S {
 // CHECK:     void foo() __attribute__((assume("ompx_global_assumption")))     {
 
 #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"))) void S_with_assumes_no_call() __attribute__((assume("ompx_global_assumption"))) {
 void S_with_assumes_no_call() {
   S<int> 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"))) void S_with_assumes_call() __attribute__((assume("ompx_global_assumption"))) {
 void S_with_assumes_call() {
   S<int> s;
   s.a = 0;
@@ -54,7 +54,7 @@ void S_without_assumes() {
 template <typename T>
 struct P {
 // CHECK: template <typename T> 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<int> {
-// 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<int> 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<int> 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<int> p;
   p.a = 0;



More information about the cfe-commits mailing list