[AST] Print correct tag decl for tag specifier
For example, given:
void fn() {
struct T *p0;
struct T { int i; } *p1;
}
-ast-print produced:
void fn() {
struct T { int i; } *p0;
struct T { int i; } *p1;
}
Compiling that fails with a redefinition error.
Given:
void fn() {
struct T *p0;
struct __attribute__((deprecated)) T *p1;
}
-ast-print dropped the attribute.
Details:
For a tag specifier (that is, struct/union/class/enum used as a type
specifier in a declaration) that was also a tag declaration (that is,
first occurrence of the tag) or tag redeclaration (that is, later
occurrence that specifies attributes or a member list), clang printed
the tag specifier as either (1) the full tag definition if one
existed, or (2) the first tag declaration otherwise. Redefinition
errors were sometimes introduced, as in the first example above. Even
when that was impossible because no member list was ever specified,
attributes were sometimes lost, thus changing semantics and
diagnostics, as in the second example above.
This patch fixes a major culprit for these problems. It does so by
creating an ElaboratedType with a new OwnedDecl member wherever an
occurrence of a tag type is a (re)declaration of that tag type.
PrintingPolicy's IncludeTagDefinition used to trigger printing of the
member list, attributes, etc. for a tag specifier by using a tag
(re)declaration selected as described above. Now, it triggers the
same thing except it uses the tag (re)declaration stored in the
OwnedDecl. Of course, other tooling can now make use of the new
OwnedDecl as well.
Also, to be more faithful to the original source, this patch
suppresses printing of attributes inherited from previous
declarations.
Reviewed by: rsmith, aaron.ballman
Differential Revision: https://reviews.llvm.org/D45463
llvm-svn: 332281
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 5c64b94..b595897 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -3979,12 +3979,12 @@
return QualType(Spec, 0);
}
-QualType
-ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- QualType NamedType) const {
+QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier *NNS,
+ QualType NamedType,
+ TagDecl *OwnedTagDecl) const {
llvm::FoldingSetNodeID ID;
- ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
+ ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl);
void *InsertPos = nullptr;
ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -3999,7 +3999,8 @@
(void)CheckT;
}
- T = new (*this, TypeAlignment) ElaboratedType(Keyword, NNS, NamedType, Canon);
+ T = new (*this, TypeAlignment)
+ ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl);
Types.push_back(T);
ElaboratedTypes.InsertNode(T, InsertPos);
return QualType(T, 0);
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index d2c8427..57d4585 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -908,8 +908,14 @@
if (ToNamedType.isNull())
return {};
+ TagDecl *OwnedTagDecl =
+ cast_or_null<TagDecl>(Importer.Import(T->getOwnedTagDecl()));
+ if (!OwnedTagDecl && T->getOwnedTagDecl())
+ return {};
+
return Importer.getToContext().getElaboratedType(T->getKeyword(),
- ToQualifier, ToNamedType);
+ ToQualifier, ToNamedType,
+ OwnedTagDecl);
}
QualType ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) {
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index c6c9d85..84c56e3 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -215,6 +215,8 @@
if (D->hasAttrs()) {
AttrVec &Attrs = D->getAttrs();
for (auto *A : Attrs) {
+ if (A->isInherited())
+ continue;
switch (A->getKind()) {
#define ATTR(X)
#define PRAGMA_SPELLING_ATTR(X) case attr::X:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 016e70d..b424b24 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1209,6 +1209,17 @@
void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
raw_ostream &OS) {
+ if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) {
+ TagDecl *OwnedTagDecl = T->getOwnedTagDecl();
+ assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() &&
+ "OwnedTagDecl expected to be a declaration for the type");
+ PrintingPolicy SubPolicy = Policy;
+ SubPolicy.IncludeTagDefinition = false;
+ OwnedTagDecl->print(OS, SubPolicy, Indentation);
+ spaceBeforePlaceHolder(OS);
+ return;
+ }
+
// The tag definition will take care of these.
if (!Policy.IncludeTagDefinition)
{
@@ -1226,6 +1237,8 @@
void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
raw_ostream &OS) {
+ if (Policy.IncludeTagDefinition && T->getOwnedTagDecl())
+ return;
ElaboratedTypePolicyRAII PolicyRAII(Policy);
printAfter(T->getNamedType(), OS);
}