Skip to content

Commit

Permalink
Fix printing of anonymous struct typedefs.
Browse files Browse the repository at this point in the history
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

llvm-svn: 263836
  • Loading branch information
swatanabe committed Mar 18, 2016
1 parent 26628d3 commit 9359b8f
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 38 deletions.
11 changes: 6 additions & 5 deletions clang/include/clang/AST/PrettyPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down
26 changes: 16 additions & 10 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,16 +909,19 @@ class QualType {
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 {
Expand All @@ -936,21 +939,24 @@ class QualType {
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;
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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<Decl*>& Decls) {
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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 << " : ";
Expand Down Expand Up @@ -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<ParenListExpr>(Init))
Out << ")";
Expand Down
37 changes: 23 additions & 14 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 << "::*";
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -1090,14 +1097,16 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,

void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
raw_ostream &OS) {
if (Policy.SuppressTag && isa<TagType>(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);
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions clang/test/Sema/ast-print.c
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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__));
Expand Down

0 comments on commit 9359b8f

Please sign in to comment.