diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 3076b30cd377..49e51e09b830 100644 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -59,6 +59,7 @@ public: CXXLiteralOperatorName, CXXUsingDirective }; + static const unsigned NumNameKinds = CXXUsingDirective + 1; private: /// StoredNameKind - The kind of name that is actually stored in the diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 3738c37ae937..69650f658276 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -443,6 +443,11 @@ private: llvm::DenseMap, NamedDecl*> ImportedTypedefNamesForLinkage; + /// \brief Mergeable declaration contexts that have anonymous declarations + /// within them, and those anonymous declarations. + llvm::DenseMap> + AnonymousDeclarationsForMerging; + struct FileDeclsInfo { ModuleFile *Mod; ArrayRef Decls; diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index b9d453abebe6..a328539b5325 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -283,6 +283,10 @@ private: llvm::DenseMap MacroDefinitions; + /// \brief Cache of indices of anonymous declarations within their lexical + /// contexts. + llvm::DenseMap AnonymousDeclarationNumbers; + /// An update to a Decl. class DeclUpdate { /// A DeclUpdateKind. @@ -639,6 +643,7 @@ public: DeclarationName Name, RecordDataImpl &Record); void AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo, RecordDataImpl &Record); + unsigned getAnonymousDeclarationNumber(const NamedDecl *D); void AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index ad046ffa277a..ba20f281ea7c 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "ASTCommon.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Serialization/ASTDeserializationListener.h" @@ -216,3 +217,10 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { llvm_unreachable("Unhandled declaration kind"); } + +bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) { + if (D->getDeclName() || !isa(D->getLexicalDeclContext())) + return false; + return isa(D) || isa(D); +} + diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 53741977a456..b6488a2a1b99 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -80,6 +80,10 @@ const DeclContext *getDefinitiveDeclContext(const DeclContext *DC); /// \brief Determine whether the given declaration kind is redeclarable. bool isRedeclarableDeclKind(unsigned Kind); +/// \brief Determine whether the given declaration needs an anonymous +/// declaration number. +bool needsAnonymousDeclarationNumber(const NamedDecl *D); + } // namespace serialization } // namespace clang diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 5cd57d70d096..aaea0687b264 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8332,7 +8332,10 @@ void ASTReader::diagnoseOdrViolations() { } if (!Found) { - D->setInvalidDecl(); + // The AST doesn't like TagDecls becoming invalid after they've been + // completed. We only really need to mark FieldDecls as invalid here. + if (!isa(D)) + D->setInvalidDecl(); std::string CanonDefModule = getOwningModuleNameForDiagnostic(cast(CanonDef)); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 60cc6bd59718..af2d47dd9719 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -43,6 +43,7 @@ namespace clang { const RecordData &Record; unsigned &Idx; TypeID TypeIDForTypeDecl; + unsigned AnonymousDeclNumber; bool HasPendingBody; @@ -106,6 +107,12 @@ namespace clang { void MergeDefinitionData(CXXRecordDecl *D, struct CXXRecordDecl::DefinitionData &NewDD); + static NamedDecl *getAnonymousDeclForMerging(ASTReader &Reader, + DeclContext *DC, + unsigned Index); + static void setAnonymousDeclForMerging(ASTReader &Reader, DeclContext *DC, + unsigned Index, NamedDecl *D); + /// \brief RAII class used to capture the first ID within a redeclaration /// chain and to introduce it into the list of pending redeclaration chains /// on destruction. @@ -158,37 +165,41 @@ namespace clang { NamedDecl *New; NamedDecl *Existing; mutable bool AddResult; - + unsigned AnonymousDeclNumber; + void operator=(FindExistingResult&) LLVM_DELETED_FUNCTION; - + public: FindExistingResult(ASTReader &Reader) - : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false) {} + : Reader(Reader), New(nullptr), Existing(nullptr), AddResult(false), + AnonymousDeclNumber(0) {} + + FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing, + unsigned AnonymousDeclNumber = 0) + : Reader(Reader), New(New), Existing(Existing), AddResult(true), + AnonymousDeclNumber(AnonymousDeclNumber) {} - FindExistingResult(ASTReader &Reader, NamedDecl *New, NamedDecl *Existing) - : Reader(Reader), New(New), Existing(Existing), AddResult(true) { } - FindExistingResult(const FindExistingResult &Other) - : Reader(Other.Reader), New(Other.New), Existing(Other.Existing), - AddResult(Other.AddResult) - { + : Reader(Other.Reader), New(Other.New), Existing(Other.Existing), + AddResult(Other.AddResult), + AnonymousDeclNumber(Other.AnonymousDeclNumber) { Other.AddResult = false; } - + ~FindExistingResult(); - + /// \brief Suppress the addition of this result into the known set of /// names. void suppress() { AddResult = false; } - + operator NamedDecl*() const { return Existing; } - + template operator T*() const { return dyn_cast_or_null(Existing); } }; - + FindExistingResult findExisting(NamedDecl *D); - + public: ASTDeclReader(ASTReader &Reader, ModuleFile &F, DeclID thisDeclID, @@ -447,6 +458,8 @@ void ASTDeclReader::VisitTranslationUnitDecl(TranslationUnitDecl *TU) { void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) { VisitDecl(ND); ND->setDeclName(Reader.ReadDeclarationName(F, Record, Idx)); + if (needsAnonymousDeclarationNumber(ND)) + AnonymousDeclNumber = Record[Idx++]; } void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { @@ -2457,6 +2470,10 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() { if (IsTypedefNameForLinkage) { Reader.ImportedTypedefNamesForLinkage.insert( std::make_pair(std::make_pair(DC, Name.getAsIdentifierInfo()), New)); + } else if (!Name) { + assert(needsAnonymousDeclarationNumber(New)); + setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(), + AnonymousDeclNumber, New); } else if (DC->isTranslationUnit() && Reader.SemaObj) { Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name); } else if (DeclContext *MergeDC = getPrimaryContextForMerging(DC)) { @@ -2487,12 +2504,58 @@ static NamedDecl *getDeclForMerging(NamedDecl *Found, return 0; } +NamedDecl *ASTDeclReader::getAnonymousDeclForMerging(ASTReader &Reader, + DeclContext *DC, + unsigned Index) { + // If the lexical context has been merged, look into the now-canonical + // definition. + if (auto *Merged = Reader.MergedDeclContexts.lookup(DC)) + DC = Merged; + + // If we've seen this before, return the canonical declaration. + auto &Previous = Reader.AnonymousDeclarationsForMerging[DC]; + if (Index < Previous.size() && Previous[Index]) + return Previous[Index]; + + // If this is the first time, but we have parsed a declaration of the context, + // build the anonymous declaration list from the parsed declaration. + if (!cast(DC)->isFromASTFile()) { + unsigned Index = 0; + for (Decl *LexicalD : DC->decls()) { + auto *ND = dyn_cast(LexicalD); + if (!ND || !needsAnonymousDeclarationNumber(ND)) + continue; + if (Previous.size() == Index) + Previous.push_back(cast(ND->getCanonicalDecl())); + else + Previous[Index] = cast(ND->getCanonicalDecl()); + ++Index; + } + } + + return Index < Previous.size() ? Previous[Index] : nullptr; +} + +void ASTDeclReader::setAnonymousDeclForMerging(ASTReader &Reader, + DeclContext *DC, unsigned Index, + NamedDecl *D) { + if (auto *Merged = Reader.MergedDeclContexts.lookup(DC)) + DC = Merged; + + auto &Previous = Reader.AnonymousDeclarationsForMerging[DC]; + if (Index >= Previous.size()) + Previous.resize(Index + 1); + if (!Previous[Index]) + Previous[Index] = D; +} + ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { bool IsTypedefNameForLinkage = false; DeclarationName Name = getNameForMerging(D, IsTypedefNameForLinkage); - if (!Name) { - // Don't bother trying to find unnamed declarations. + if (!Name && !needsAnonymousDeclarationNumber(D)) { + // Don't bother trying to find unnamed declarations that are in + // unmergeable contexts. FindExistingResult Result(Reader, D, /*Existing=*/nullptr); // FIXME: We may still need to pull in the redeclaration chain; there can // be redeclarations via 'decltype'. @@ -2513,7 +2576,16 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { // Go on to check in other places in case an existing typedef name // was not imported. } - if (DC->isTranslationUnit() && Reader.SemaObj) { + + if (!Name) { + // This is an anonymous declaration that we may need to merge. Look it up + // in its context by number. + assert(needsAnonymousDeclarationNumber(D)); + if (auto *Existing = getAnonymousDeclForMerging( + Reader, D->getLexicalDeclContext(), AnonymousDeclNumber)) + if (isSameEntity(Existing, D)) + return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber); + } else if (DC->isTranslationUnit() && Reader.SemaObj) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; // Temporarily consider the identifier to be up-to-date. We don't want to @@ -2568,7 +2640,8 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) { MergedDCIt->second == D->getDeclContext()) Reader.PendingOdrMergeChecks.push_back(D); - return FindExistingResult(Reader, D, /*Existing=*/nullptr); + return FindExistingResult(Reader, D, /*Existing=*/nullptr, + AnonymousDeclNumber); } template diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index d58243541542..de86700252e1 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5121,6 +5121,30 @@ void ASTWriter::AddDeclarationName(DeclarationName Name, RecordDataImpl &Record) } } +unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) { + assert(needsAnonymousDeclarationNumber(D) && + "expected an anonymous declaration"); + + // Number the anonymous declarations within this context, if we've not + // already done so. + auto It = AnonymousDeclarationNumbers.find(D); + if (It == AnonymousDeclarationNumbers.end()) { + unsigned Index = 0; + for (Decl *LexicalD : D->getLexicalDeclContext()->decls()) { + auto *ND = dyn_cast(LexicalD); + if (!ND || !needsAnonymousDeclarationNumber(ND)) + continue; + AnonymousDeclarationNumbers[ND] = Index++; + } + + It = AnonymousDeclarationNumbers.find(D); + assert(It != AnonymousDeclarationNumbers.end() && + "declaration not found within its lexical context"); + } + + return It->second; +} + void ASTWriter::AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, DeclarationName Name, RecordDataImpl &Record) { switch (Name.getNameKind()) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 336c86b6d57e..95fabc86a14f 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -203,6 +203,8 @@ void ASTDeclWriter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) { VisitDecl(D); Writer.AddDeclarationName(D->getDeclName(), Record); + if (needsAnonymousDeclarationNumber(D)) + Record.push_back(Writer.getAnonymousDeclarationNumber(D)); } void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { @@ -228,6 +230,7 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { !D->isInvalidDecl() && !D->isTopLevelDeclInObjCContainer() && !D->isModulePrivate() && + !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclTypedefAbbrev(); @@ -292,6 +295,7 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { !CXXRecordDecl::classofKind(D->getKind()) && !D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() && + !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclEnumAbbrev(); @@ -316,6 +320,7 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { D->getAccess() == AS_none && !D->isModulePrivate() && !CXXRecordDecl::classofKind(D->getKind()) && + !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier) AbbrevToUse = Writer.getDeclRecordAbbrev(); @@ -751,6 +756,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { !D->isTopLevelDeclInObjCContainer() && D->getAccess() == AS_none && !D->isModulePrivate() && + !needsAnonymousDeclarationNumber(D) && D->getDeclName().getNameKind() == DeclarationName::Identifier && !D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() && diff --git a/clang/test/Modules/Inputs/cxx-templates-a.h b/clang/test/Modules/Inputs/cxx-templates-a.h index 928a544fc4dc..b1ea6a9c2410 100644 --- a/clang/test/Modules/Inputs/cxx-templates-a.h +++ b/clang/test/Modules/Inputs/cxx-templates-a.h @@ -87,3 +87,4 @@ template struct PartiallyInstantiatePartialSpec { typedef PartiallyInstantiatePartialSpec PartiallyInstantiatePartialSpecHelper; void InstantiateWithAliasTemplate(WithAliasTemplate::X); +inline int InstantiateWithAnonymousDeclsA(WithAnonymousDecls x) { return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d); } diff --git a/clang/test/Modules/Inputs/cxx-templates-b.h b/clang/test/Modules/Inputs/cxx-templates-b.h index cfaea282df03..632a55b72e32 100644 --- a/clang/test/Modules/Inputs/cxx-templates-b.h +++ b/clang/test/Modules/Inputs/cxx-templates-b.h @@ -70,6 +70,9 @@ template<> struct MergeSpecializations { template using AliasTemplate = U; void InstantiateWithAliasTemplate(WithAliasTemplate::X); +inline int InstantiateWithAnonymousDeclsB(WithAnonymousDecls x) { + return (x.k ? x.a : x.b) + (x.k ? x.s.c : x.s.d); +} @import cxx_templates_a; template void UseDefinedInBImplIndirectly(T &v) { diff --git a/clang/test/Modules/Inputs/cxx-templates-common.h b/clang/test/Modules/Inputs/cxx-templates-common.h index d729c6edf4c1..f1cf260fb04d 100644 --- a/clang/test/Modules/Inputs/cxx-templates-common.h +++ b/clang/test/Modules/Inputs/cxx-templates-common.h @@ -45,4 +45,11 @@ template struct WithAliasTemplate { template using X = T; }; +template struct WithAnonymousDecls { + struct { bool k; }; + union { int a, b; }; + struct { int c, d; } s; + typedef int X; +}; + #include "cxx-templates-textual.h" diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp index d0a6c0f9e5d8..b3ef3f6497b3 100644 --- a/clang/test/Modules/cxx-templates.cpp +++ b/clang/test/Modules/cxx-templates.cpp @@ -145,6 +145,11 @@ MergeSpecializations::explicitly_specialized_in_c spec_in_c_2; using AliasTemplateMergingTest = WithAliasTemplate::X; +int AnonymousDeclsMergingTest(WithAnonymousDecls WAD) { + return InstantiateWithAnonymousDeclsA(WAD) + + InstantiateWithAnonymousDeclsB(WAD); +} + @import cxx_templates_common; typedef SomeTemplate SomeTemplateIntPtr;