diff options
author | Joel E. Denny <jdenny.ornl@gmail.com> | 2018-05-14 19:36:45 +0000 |
---|---|---|
committer | Joel E. Denny <jdenny.ornl@gmail.com> | 2018-05-14 19:36:45 +0000 |
commit | 7509a2f5cc0dac9530ccbaf0194e7b17d88c6c99 (patch) | |
tree | f503d834beb726adc6c255667bd479908da2267a /clang/lib | |
parent | 9668e45b61de5ae468f19ed25b49c87504486158 (diff) | |
download | bcm5719-llvm-7509a2f5cc0dac9530ccbaf0194e7b17d88c6c99.tar.gz bcm5719-llvm-7509a2f5cc0dac9530ccbaf0194e7b17d88c6c99.zip |
[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
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 13 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 8 | ||||
-rw-r--r-- | clang/lib/AST/DeclPrinter.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/TypePrinter.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 1 |
7 files changed, 41 insertions, 14 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 5c64b94c40e..b59589791c3 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3979,12 +3979,12 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( 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 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, (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 d2c8427441a..57d4585e07d 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -908,8 +908,14 @@ QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { 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 c6c9d85f16d..84c56e3b960 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -215,6 +215,8 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) { 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 016e70d4728..b424b24574e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1209,6 +1209,17 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T, 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::printElaboratedBefore(const ElaboratedType *T, void TypePrinter::printElaboratedAfter(const ElaboratedType *T, raw_ostream &OS) { + if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) + return; ElaboratedTypePolicyRAII PolicyRAII(Policy); printAfter(T->getNamedType(), OS); } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 38a06c02078..439031065f8 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1429,7 +1429,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_union: case DeclSpec::TST_struct: case DeclSpec::TST_interface: { - TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl()); + TagDecl *D = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl()); if (!D) { // This can happen in C++ with ambiguous lookups. Result = Context.IntTy; @@ -1449,7 +1449,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // In both C and C++, make an ElaboratedType. ElaboratedTypeKeyword Keyword = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); + Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result, + DS.isTypeSpecOwned() ? D : nullptr); break; } case DeclSpec::TST_typename: { @@ -7863,10 +7864,12 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID) { return RequireLiteralType(Loc, T, Diagnoser); } -/// Retrieve a version of the type 'T' that is elaborated by Keyword -/// and qualified by the nested-name-specifier contained in SS. +/// Retrieve a version of the type 'T' that is elaborated by Keyword, qualified +/// by the nested-name-specifier contained in SS, and that is (re)declared by +/// OwnedTagDecl, which is nullptr if this is not a (re)declaration. QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, - const CXXScopeSpec &SS, QualType T) { + const CXXScopeSpec &SS, QualType T, + TagDecl *OwnedTagDecl) { if (T.isNull()) return T; NestedNameSpecifier *NNS; @@ -7877,7 +7880,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return T; NNS = nullptr; } - return Context.getElaboratedType(Keyword, NNS, T); + return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 724702dcde6..8c8b8788910 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6185,7 +6185,8 @@ QualType ASTReader::readTypeRecord(unsigned Index) { ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); QualType NamedType = readType(*Loc.F, Record, Idx); - return Context.getElaboratedType(Keyword, NNS, NamedType); + TagDecl *OwnedTagDecl = ReadDeclAs<TagDecl>(*Loc.F, Record, Idx); + return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedTagDecl); } case TYPE_OBJC_INTERFACE: { diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a143b956fce..040f1837009 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -512,6 +512,7 @@ void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) { Record.push_back(T->getKeyword()); Record.AddNestedNameSpecifier(T->getQualifier()); Record.AddTypeRef(T->getNamedType()); + Record.AddDeclRef(T->getOwnedTagDecl()); Code = TYPE_ELABORATED; } |