@@ -49,6 +49,18 @@ namespace {
4949
5050 void PrintObjCTypeParams (ObjCTypeParamList *Params);
5151
52+ enum class AttrPrintLoc {
53+ None = 0 ,
54+ Left = 1 ,
55+ Right = 2 ,
56+ Any = Left | Right,
57+
58+ LLVM_MARK_AS_BITMASK_ENUM (/* DefaultValue=*/ Any)
59+ };
60+
61+ void prettyPrintAttributes (Decl *D, raw_ostream &out,
62+ AttrPrintLoc loc = AttrPrintLoc::Any);
63+
5264 public:
5365 DeclPrinter (raw_ostream &Out, const PrintingPolicy &Policy,
5466 const ASTContext &Context, unsigned Indentation = 0 ,
@@ -117,7 +129,11 @@ namespace {
117129 const TemplateParameterList *Params);
118130 void printTemplateArguments (llvm::ArrayRef<TemplateArgumentLoc> Args,
119131 const TemplateParameterList *Params);
120- void prettyPrintAttributes (Decl *D);
132+
133+ inline void prettyPrintAttributes (Decl *D) {
134+ prettyPrintAttributes (D, Out);
135+ }
136+
121137 void prettyPrintPragmas (Decl *D);
122138 void printDeclType (QualType T, StringRef DeclName, bool Pack = false );
123139 };
@@ -234,7 +250,40 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
234250 return Out;
235251}
236252
237- void DeclPrinter::prettyPrintAttributes (Decl *D) {
253+ static bool canPrintOnLeftSide (attr::Kind kind) {
254+ switch (kind) {
255+ #include " clang/Basic/AttrLeftSideCanPrintList.inc"
256+ return true ;
257+ default :
258+ return false ;
259+ }
260+ }
261+
262+ static bool canPrintOnLeftSide (const Attr *A) {
263+ if (A->isStandardAttributeSyntax ())
264+ return false ;
265+
266+ return canPrintOnLeftSide (A->getKind ());
267+ }
268+
269+ static bool mustPrintOnLeftSide (attr::Kind kind) {
270+ switch (kind) {
271+ #include " clang/Basic/AttrLeftSideMustPrintList.inc"
272+ return true ;
273+ default :
274+ return false ;
275+ }
276+ }
277+
278+ static bool mustPrintOnLeftSide (const Attr *A) {
279+ if (A->isDeclspecAttribute ())
280+ return true ;
281+
282+ return mustPrintOnLeftSide (A->getKind ());
283+ }
284+
285+ void DeclPrinter::prettyPrintAttributes (Decl *D, llvm::raw_ostream &Out,
286+ AttrPrintLoc Loc) {
238287 if (Policy.PolishForDeclaration )
239288 return ;
240289
@@ -243,15 +292,32 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) {
243292 for (auto *A : Attrs) {
244293 if (A->isInherited () || A->isImplicit ())
245294 continue ;
246- switch (A->getKind ()) {
247- #define ATTR (X )
248- #define PRAGMA_SPELLING_ATTR (X ) case attr::X:
249- #include " clang/Basic/AttrList.inc"
250- break ;
251- default :
252- A->printPretty (Out, Policy);
253- break ;
295+
296+ AttrPrintLoc AttrLoc = AttrPrintLoc::Right;
297+ if (mustPrintOnLeftSide (A)) {
298+ // If we must always print on left side (e.g. declspec), then mark as
299+ // so.
300+ AttrLoc = AttrPrintLoc::Left;
301+ } else if (canPrintOnLeftSide (A)) {
302+ // For functions with body defined we print the attributes on the left
303+ // side so that GCC accept our dumps as well.
304+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
305+ FD && FD->isThisDeclarationADefinition ())
306+ // In case Decl is a function with a body, then attrs should be print
307+ // on the left side.
308+ AttrLoc = AttrPrintLoc::Left;
309+
310+ // In case it is a variable declaration with a ctor, then allow
311+ // printing on the left side for readbility.
312+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D);
313+ VD && VD->getInit () &&
314+ VD->getInitStyle () == VarDecl::CallInit)
315+ AttrLoc = AttrPrintLoc::Left;
254316 }
317+
318+ // Only print the side matches the user requested.
319+ if ((Loc & AttrLoc) != AttrPrintLoc::None)
320+ A->printPretty (Out, Policy);
255321 }
256322 }
257323}
@@ -613,6 +679,22 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
613679 printTemplateParameters (D->getTemplateParameterList (I));
614680 }
615681
682+ std::string LeftsideAttrs;
683+ llvm::raw_string_ostream LSAS (LeftsideAttrs);
684+
685+ prettyPrintAttributes (D, LSAS, AttrPrintLoc::Left);
686+
687+ // prettyPrintAttributes print a space on left side of the attribute.
688+ if (LeftsideAttrs[0 ] == ' ' ) {
689+ // Skip the space prettyPrintAttributes generated.
690+ LeftsideAttrs.erase (0 , LeftsideAttrs.find_first_not_of (' ' ));
691+
692+ // Add a single space between the attribute and the Decl name.
693+ LSAS << ' ' ;
694+ }
695+
696+ Out << LeftsideAttrs;
697+
616698 CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
617699 CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(D);
618700 CXXDeductionGuideDecl *GuideDecl = dyn_cast<CXXDeductionGuideDecl>(D);
@@ -774,7 +856,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
774856 Ty.print (Out, Policy, Proto);
775857 }
776858
777- prettyPrintAttributes (D);
859+ prettyPrintAttributes (D, Out, AttrPrintLoc::Right );
778860
779861 if (D->isPure ())
780862 Out << " = 0" ;
@@ -867,6 +949,23 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
867949void DeclPrinter::VisitVarDecl (VarDecl *D) {
868950 prettyPrintPragmas (D);
869951
952+ std::string LeftSide;
953+ llvm::raw_string_ostream LeftSideStream (LeftSide);
954+
955+ // Print attributes that should be placed on the left, such as __declspec.
956+ prettyPrintAttributes (D, LeftSideStream, AttrPrintLoc::Left);
957+
958+ // prettyPrintAttributes print a space on left side of the attribute.
959+ if (LeftSide[0 ] == ' ' ) {
960+ // Skip the space prettyPrintAttributes generated.
961+ LeftSide.erase (0 , LeftSide.find_first_not_of (' ' ));
962+
963+ // Add a single space between the attribute and the Decl name.
964+ LeftSideStream << ' ' ;
965+ }
966+
967+ Out << LeftSide;
968+
870969 QualType T = D->getTypeSourceInfo ()
871970 ? D->getTypeSourceInfo ()->getType ()
872971 : D->getASTContext ().getUnqualifiedObjCPointerType (D->getType ());
@@ -899,10 +998,19 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
899998 }
900999 }
9011000
902- printDeclType (T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
903- D->getIdentifier ())
904- ? D->getIdentifier ()->deuglifiedName ()
905- : D->getName ());
1001+ StringRef Name;
1002+
1003+ Name = (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
1004+ D->getIdentifier ())
1005+ ? D->getIdentifier ()->deuglifiedName ()
1006+ : D->getName ();
1007+
1008+ printDeclType (T, Name);
1009+
1010+ // Print the attributes that should be placed right before the end of the
1011+ // decl.
1012+ prettyPrintAttributes (D, Out, AttrPrintLoc::Right);
1013+
9061014 Expr *Init = D->getInit ();
9071015 if (!Policy.SuppressInitializers && Init) {
9081016 bool ImplicitInit = false ;
@@ -931,7 +1039,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
9311039 Out << " )" ;
9321040 }
9331041 }
934- prettyPrintAttributes (D);
9351042}
9361043
9371044void DeclPrinter::VisitParmVarDecl (ParmVarDecl *D) {
0 commit comments