diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-03-17 02:23:11 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2015-03-17 02:23:11 +0000 |
commit | 15e32fd215fa49c18a7b8681d0b500ceef641769 (patch) | |
tree | 845c4718a93973457154d22800133e22ce8b3243 /clang/lib/Serialization/ASTReaderDecl.cpp | |
parent | cf191adaf5647f32d62cee7eda8e1775666ddba2 (diff) | |
download | bcm5719-llvm-15e32fd215fa49c18a7b8681d0b500ceef641769.tar.gz bcm5719-llvm-15e32fd215fa49c18a7b8681d0b500ceef641769.zip |
[modules] Fix bug where an anonymous namespace could cause the containing
namespace to not merge properly.
We have an invariant here: after a declaration reads its canonical declaration,
it can assume the canonical declaration is fully merged. This invariant can be
violated if deserializing some declaration triggers the deserialization of a
later declaration, because that later declaration can in turn deserialize a
redeclaration of that first declaration before it is fully merged.
The anonymous namespace for a namespace gets stored with the first declaration
of that namespace, which may be before its parent namespace, so defer loading
it until after we've finished merging the surrounding namespace.
llvm-svn: 232455
Diffstat (limited to 'clang/lib/Serialization/ASTReaderDecl.cpp')
-rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 27 |
1 files changed, 18 insertions, 9 deletions
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 96c16ea10ee..83882a83693 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1198,13 +1198,13 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { D->LocStart = ReadSourceLocation(Record, Idx); D->RBraceLoc = ReadSourceLocation(Record, Idx); + // Defer loading the anonymous namespace until we've finished merging + // this namespace; loading it might load a later declaration of the + // same namespace, and we have an invariant that older declarations + // get merged before newer ones try to merge. + GlobalDeclID AnonNamespace = 0; if (Redecl.getFirstID() == ThisDeclID) { - // Each module has its own anonymous namespace, which is disjoint from - // any other module's anonymous namespaces, so don't attach the anonymous - // namespace at all. - NamespaceDecl *Anon = ReadDeclAs<NamespaceDecl>(Record, Idx); - if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) - D->setAnonymousNamespace(Anon); + AnonNamespace = ReadDeclID(Record, Idx); } else { // Link this namespace back to the first declaration, which has already // been deserialized. @@ -1212,6 +1212,15 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { } mergeRedeclarable(D, Redecl); + + if (AnonNamespace) { + // Each module has its own anonymous namespace, which is disjoint from + // any other module's anonymous namespaces, so don't attach the anonymous + // namespace at all. + NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(AnonNamespace)); + if (F.Kind != MK_ImplicitModule && F.Kind != MK_ExplicitModule) + D->setAnonymousNamespace(Anon); + } } void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { @@ -2196,6 +2205,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon); // When we merge a namespace, update its pointer to the first namespace. + // We cannot have loaded any redeclarations of this declaration yet, so + // there's nothing else that needs to be updated. if (auto *Namespace = dyn_cast<NamespaceDecl>(D)) Namespace->AnonOrFirstNamespaceAndInline.setPointer( assert_cast<NamespaceDecl*>(ExistingCanon)); @@ -2206,9 +2217,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing, DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon), TemplatePatternID); - // If this declaration was the canonical declaration, make a note of - // that. We accept the linear algorithm here because the number of - // unique canonical declarations of an entity should always be tiny. + // If this declaration was the canonical declaration, make a note of that. if (DCanon == D) { Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID()); if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) |