[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:
parent
cf191adaf5
commit
15e32fd215
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
namespace N {}
|
|
@ -0,0 +1,2 @@
|
|||
namespace N {}
|
||||
namespace N { namespace {} }
|
|
@ -0,0 +1,2 @@
|
|||
#include "a.h"
|
||||
namespace N {}
|
|
@ -0,0 +1 @@
|
|||
namespace N {}
|
|
@ -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 * }
|
|
@ -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;
|
Loading…
Reference in New Issue