[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
This commit is contained in:
Richard Smith 2015-03-17 02:23:11 +00:00
parent cf191adaf5
commit 15e32fd215
7 changed files with 33 additions and 9 deletions

View File

@ -1198,13 +1198,13 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
D->LocStart = ReadSourceLocation(Record, Idx); D->LocStart = ReadSourceLocation(Record, Idx);
D->RBraceLoc = 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) { if (Redecl.getFirstID() == ThisDeclID) {
// Each module has its own anonymous namespace, which is disjoint from AnonNamespace = ReadDeclID(Record, Idx);
// 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);
} else { } else {
// Link this namespace back to the first declaration, which has already // Link this namespace back to the first declaration, which has already
// been deserialized. // been deserialized.
@ -1212,6 +1212,15 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) {
} }
mergeRedeclarable(D, Redecl); 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) { void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
@ -2196,6 +2205,8 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon); D->RedeclLink = Redeclarable<T>::PreviousDeclLink(ExistingCanon);
// When we merge a namespace, update its pointer to the first namespace. // 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)) if (auto *Namespace = dyn_cast<NamespaceDecl>(D))
Namespace->AnonOrFirstNamespaceAndInline.setPointer( Namespace->AnonOrFirstNamespaceAndInline.setPointer(
assert_cast<NamespaceDecl*>(ExistingCanon)); assert_cast<NamespaceDecl*>(ExistingCanon));
@ -2206,9 +2217,7 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *DBase, T *Existing,
DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon), DTemplate, assert_cast<RedeclarableTemplateDecl*>(ExistingCanon),
TemplatePatternID); TemplatePatternID);
// If this declaration was the canonical declaration, make a note of // If this declaration was the canonical declaration, make a note of that.
// that. We accept the linear algorithm here because the number of
// unique canonical declarations of an entity should always be tiny.
if (DCanon == D) { if (DCanon == D) {
Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID()); Reader.MergedDecls[ExistingCanon].push_back(Redecl.getFirstID());
if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second) if (Reader.PendingDeclChainsKnown.insert(ExistingCanon).second)

View File

@ -0,0 +1 @@
namespace N {}

View File

@ -0,0 +1,2 @@
namespace N {}
namespace N { namespace {} }

View File

@ -0,0 +1,2 @@
#include "a.h"
namespace N {}

View File

@ -0,0 +1 @@
namespace N {}

View File

@ -0,0 +1,3 @@
module a { header "a.h" export * }
module b { module b1 { header "b1.h" export * } module b2 { header "b2.h" export * } }
module c { header "c.h" export * }

View File

@ -0,0 +1,6 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I%S/Inputs/anon-namespace -verify %s
// expected-no-diagnostics
#include "b1.h"
#include "c.h"
using namespace N;