From 7d8134a1ff132cd975eaf1c75cf9e193ef16b788 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 18 Mar 2016 21:35:59 +0000 Subject: [PATCH] Fix printing of anonymous struct typedefs. clang -cc1 -ast-print put the struct definition in the wrong place, like this: struct {} typedef S; The reason that this happens is that the printing code first prints the struct definition, and then tells the next declaration to leave out the type. This behavior is correct for simple variable declarations, but fails for typedefs (or extern, mutable, etc). The patch address this problem by skipping the struct declaration when we first see it, and then telling the first subsequent declaration that it needs to print out the full struct definition. Differential Revision: http://reviews.llvm.org/D17285 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@263836 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/PrettyPrinter.h | 11 ++++----- include/clang/AST/Type.h | 26 +++++++++++++--------- lib/AST/DeclPrinter.cpp | 17 +++++++------- lib/AST/TypePrinter.cpp | 37 +++++++++++++++++++------------ test/Sema/ast-print.c | 2 ++ 5 files changed, 55 insertions(+), 38 deletions(-) diff --git a/include/clang/AST/PrettyPrinter.h b/include/clang/AST/PrettyPrinter.h index 57495efa96..df3e165c51 100644 --- a/include/clang/AST/PrettyPrinter.h +++ b/include/clang/AST/PrettyPrinter.h @@ -36,7 +36,8 @@ struct PrintingPolicy { /// \brief Create a default printing policy for C. PrintingPolicy(const LangOptions &LO) : LangOpts(LO), Indentation(2), SuppressSpecifiers(false), - SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), + SuppressTagKeyword(false), + IncludeTagDefinition(false), SuppressScope(false), SuppressUnwrittenScope(false), SuppressInitializers(false), ConstantArraySizeAsWritten(false), AnonymousTagLocations(true), SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false), @@ -77,15 +78,15 @@ struct PrintingPolicy { /// \endcode bool SuppressTagKeyword : 1; - /// \brief Whether type printing should skip printing the actual tag type. + /// \brief When true, include the body of a tag definition. /// - /// This is used when the caller needs to print a tag definition in front - /// of the type, as in constructs like the following: + /// This is used to place the definition of a struct + /// in the middle of another declaration as with: /// /// \code /// typedef struct { int x, y; } Point; /// \endcode - bool SuppressTag : 1; + bool IncludeTagDefinition : 1; /// \brief Suppresses printing of scope specifiers. bool SuppressScope : 1; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 2e02ad1ea0..aef891c898 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -909,16 +909,19 @@ public: std::string getAsString(const PrintingPolicy &Policy) const; void print(raw_ostream &OS, const PrintingPolicy &Policy, - const Twine &PlaceHolder = Twine()) const { - print(split(), OS, Policy, PlaceHolder); + const Twine &PlaceHolder = Twine(), + unsigned Indentation = 0) const { + print(split(), OS, Policy, PlaceHolder, Indentation); } static void print(SplitQualType split, raw_ostream &OS, - const PrintingPolicy &policy, const Twine &PlaceHolder) { - return print(split.Ty, split.Quals, OS, policy, PlaceHolder); + const PrintingPolicy &policy, const Twine &PlaceHolder, + unsigned Indentation = 0) { + return print(split.Ty, split.Quals, OS, policy, PlaceHolder, Indentation); } static void print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, - const Twine &PlaceHolder); + const Twine &PlaceHolder, + unsigned Indentation = 0); void getAsStringInternal(std::string &Str, const PrintingPolicy &Policy) const { @@ -936,21 +939,24 @@ public: const QualType &T; const PrintingPolicy &Policy; const Twine &PlaceHolder; + unsigned Indentation; public: StreamedQualTypeHelper(const QualType &T, const PrintingPolicy &Policy, - const Twine &PlaceHolder) - : T(T), Policy(Policy), PlaceHolder(PlaceHolder) { } + const Twine &PlaceHolder, unsigned Indentation) + : T(T), Policy(Policy), PlaceHolder(PlaceHolder), + Indentation(Indentation) { } friend raw_ostream &operator<<(raw_ostream &OS, const StreamedQualTypeHelper &SQT) { - SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder); + SQT.T.print(OS, SQT.Policy, SQT.PlaceHolder, SQT.Indentation); return OS; } }; StreamedQualTypeHelper stream(const PrintingPolicy &Policy, - const Twine &PlaceHolder = Twine()) const { - return StreamedQualTypeHelper(*this, Policy, PlaceHolder); + const Twine &PlaceHolder = Twine(), + unsigned Indentation = 0) const { + return StreamedQualTypeHelper(*this, Policy, PlaceHolder, Indentation); } void dump(const char *s) const; diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index dd3f3b4a0d..f7a8eb2729 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -160,19 +160,17 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls, ++Begin; PrintingPolicy SubPolicy(Policy); - if (TD && TD->isCompleteDefinition()) { - TD->print(Out, Policy, Indentation); - Out << " "; - SubPolicy.SuppressTag = true; - } bool isFirst = true; for ( ; Begin != End; ++Begin) { if (isFirst) { + if(TD) + SubPolicy.IncludeTagDefinition = true; SubPolicy.SuppressSpecifiers = false; isFirst = false; } else { if (!isFirst) Out << ", "; + SubPolicy.IncludeTagDefinition = false; SubPolicy.SuppressSpecifiers = true; } @@ -246,7 +244,7 @@ void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) { Pack = true; T = PET->getPattern(); } - T.print(Out, Policy, (Pack ? "..." : "") + DeclName); + T.print(Out, Policy, (Pack ? "..." : "") + DeclName, Indentation); } void DeclPrinter::ProcessDeclGroup(SmallVectorImpl& Decls) { @@ -380,7 +378,8 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { if (D->isModulePrivate()) Out << "__module_private__ "; } - D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName()); + QualType Ty = D->getTypeSourceInfo()->getType(); + Ty.print(Out, Policy, D->getName(), Indentation); prettyPrintAttributes(D); } @@ -685,7 +684,7 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) { Out << "__module_private__ "; Out << D->getASTContext().getUnqualifiedObjCPointerType(D->getType()). - stream(Policy, D->getName()); + stream(Policy, D->getName(), Indentation); if (D->isBitField()) { Out << " : "; @@ -755,7 +754,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } PrintingPolicy SubPolicy(Policy); SubPolicy.SuppressSpecifiers = false; - SubPolicy.SuppressTag = false; + SubPolicy.IncludeTagDefinition = false; Init->printPretty(Out, nullptr, SubPolicy, Indentation); if ((D->getInitStyle() == VarDecl::CallInit) && !isa(Init)) Out << ")"; diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 7c519fc638..263a24f4ae 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -81,12 +81,14 @@ namespace { class TypePrinter { PrintingPolicy Policy; + unsigned Indentation; bool HasEmptyPlaceHolder; bool InsideCCAttribute; public: - explicit TypePrinter(const PrintingPolicy &Policy) - : Policy(Policy), HasEmptyPlaceHolder(false), InsideCCAttribute(false) { } + explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0) + : Policy(Policy), Indentation(Indentation), + HasEmptyPlaceHolder(false), InsideCCAttribute(false) { } void print(const Type *ty, Qualifiers qs, raw_ostream &OS, StringRef PlaceHolder); @@ -411,7 +413,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T, OS << '('; PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressTag = false; + InnerPolicy.IncludeTagDefinition = false; TypePrinter(InnerPolicy).print(QualType(T->getClass(), 0), OS, StringRef()); OS << "::*"; @@ -934,8 +936,13 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { } void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { - if (Policy.SuppressTag) + if (Policy.IncludeTagDefinition) { + PrintingPolicy SubPolicy = Policy; + SubPolicy.IncludeTagDefinition = false; + D->print(OS, SubPolicy, Indentation); + spaceBeforePlaceHolder(OS); return; + } bool HasKindDecoration = false; @@ -1090,14 +1097,16 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, void TypePrinter::printElaboratedBefore(const ElaboratedType *T, raw_ostream &OS) { - if (Policy.SuppressTag && isa(T->getNamedType())) - return; - OS << TypeWithKeyword::getKeywordName(T->getKeyword()); - if (T->getKeyword() != ETK_None) - OS << " "; - NestedNameSpecifier* Qualifier = T->getQualifier(); - if (Qualifier) - Qualifier->print(OS, Policy); + // The tag definition will take care of these. + if (!Policy.IncludeTagDefinition) + { + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + NestedNameSpecifier* Qualifier = T->getQualifier(); + if (Qualifier) + Qualifier->print(OS, Policy); + } ElaboratedTypePolicyRAII PolicyRAII(Policy); printBefore(T->getNamedType(), OS); @@ -1654,11 +1663,11 @@ std::string QualType::getAsString(const Type *ty, Qualifiers qs) { void QualType::print(const Type *ty, Qualifiers qs, raw_ostream &OS, const PrintingPolicy &policy, - const Twine &PlaceHolder) { + const Twine &PlaceHolder, unsigned Indentation) { SmallString<128> PHBuf; StringRef PH = PlaceHolder.toStringRef(PHBuf); - TypePrinter(policy).print(ty, qs, OS, PH); + TypePrinter(policy, Indentation).print(ty, qs, OS, PH); } void QualType::getAsStringInternal(const Type *ty, Qualifiers qs, diff --git a/test/Sema/ast-print.c b/test/Sema/ast-print.c index b0e421410b..4c0aef5b2f 100644 --- a/test/Sema/ast-print.c +++ b/test/Sema/ast-print.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -ast-print | FileCheck %s +// RUN: %clang_cc1 %s -ast-print | %clang_cc1 -fsyntax-only - typedef void func_typedef(); func_typedef xxx; @@ -39,6 +40,7 @@ int rvarr(int n, int a[restrict static n]) { return a[2]; } +// CHECK: typedef struct { typedef struct { int f; } T __attribute__ ((__aligned__)); -- 2.40.0