Successive anonymous namespaces name the same scope. I misinterpreted the
standard the last time. Fixes PR5766. llvm-svn: 91493
This commit is contained in:
parent
85dabae6ad
commit
0db42252f7
|
@ -85,13 +85,20 @@ public:
|
|||
class TranslationUnitDecl : public Decl, public DeclContext {
|
||||
ASTContext &Ctx;
|
||||
|
||||
/// The (most recently entered) anonymous namespace for this
|
||||
/// translation unit, if one has been created.
|
||||
NamespaceDecl *AnonymousNamespace;
|
||||
|
||||
explicit TranslationUnitDecl(ASTContext &ctx)
|
||||
: Decl(TranslationUnit, 0, SourceLocation()),
|
||||
DeclContext(TranslationUnit),
|
||||
Ctx(ctx) {}
|
||||
Ctx(ctx), AnonymousNamespace(0) {}
|
||||
public:
|
||||
ASTContext &getASTContext() const { return Ctx; }
|
||||
|
||||
NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
|
||||
void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
|
||||
|
||||
static TranslationUnitDecl *Create(ASTContext &C);
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
|
||||
|
@ -247,10 +254,15 @@ class NamespaceDecl : public NamedDecl, public DeclContext {
|
|||
// OrigNamespace of the first namespace decl points to itself.
|
||||
NamespaceDecl *OrigNamespace, *NextNamespace;
|
||||
|
||||
// The (most recently entered) anonymous namespace inside this
|
||||
// namespace.
|
||||
NamespaceDecl *AnonymousNamespace;
|
||||
|
||||
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
|
||||
OrigNamespace = this;
|
||||
NextNamespace = 0;
|
||||
AnonymousNamespace = 0;
|
||||
}
|
||||
public:
|
||||
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
|
@ -278,6 +290,16 @@ public:
|
|||
}
|
||||
void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
|
||||
|
||||
NamespaceDecl *getAnonymousNamespace() const {
|
||||
return AnonymousNamespace;
|
||||
}
|
||||
|
||||
void setAnonymousNamespace(NamespaceDecl *D) {
|
||||
assert(D->isAnonymousNamespace());
|
||||
assert(D->getParent() == this);
|
||||
AnonymousNamespace = D;
|
||||
}
|
||||
|
||||
virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
|
||||
const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
|
||||
|
||||
|
|
|
@ -2748,6 +2748,28 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
|||
PushOnScopeChains(Namespc, DeclRegionScope);
|
||||
} else {
|
||||
// Anonymous namespaces.
|
||||
assert(Namespc->isAnonymousNamespace());
|
||||
CurContext->addDecl(Namespc);
|
||||
|
||||
// Link the anonymous namespace into its parent.
|
||||
NamespaceDecl *PrevDecl;
|
||||
DeclContext *Parent = CurContext->getLookupContext();
|
||||
if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(Parent)) {
|
||||
PrevDecl = TU->getAnonymousNamespace();
|
||||
TU->setAnonymousNamespace(Namespc);
|
||||
} else {
|
||||
NamespaceDecl *ND = cast<NamespaceDecl>(Parent);
|
||||
PrevDecl = ND->getAnonymousNamespace();
|
||||
ND->setAnonymousNamespace(Namespc);
|
||||
}
|
||||
|
||||
// Link the anonymous namespace with its previous declaration.
|
||||
if (PrevDecl) {
|
||||
assert(PrevDecl->isAnonymousNamespace());
|
||||
assert(!PrevDecl->getNextNamespace());
|
||||
Namespc->setOriginalNamespace(PrevDecl->getOriginalNamespace());
|
||||
PrevDecl->setNextNamespace(Namespc);
|
||||
}
|
||||
|
||||
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
|
||||
// behaves as if it were replaced by
|
||||
|
@ -2765,20 +2787,19 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
|||
// declarations semantically contained within an anonymous
|
||||
// namespace internal linkage.
|
||||
|
||||
assert(Namespc->isAnonymousNamespace());
|
||||
CurContext->addDecl(Namespc);
|
||||
|
||||
UsingDirectiveDecl* UD
|
||||
= UsingDirectiveDecl::Create(Context, CurContext,
|
||||
/* 'using' */ LBrace,
|
||||
/* 'namespace' */ SourceLocation(),
|
||||
/* qualifier */ SourceRange(),
|
||||
/* NNS */ NULL,
|
||||
/* identifier */ SourceLocation(),
|
||||
Namespc,
|
||||
/* Ancestor */ CurContext);
|
||||
UD->setImplicit();
|
||||
CurContext->addDecl(UD);
|
||||
if (!PrevDecl) {
|
||||
UsingDirectiveDecl* UD
|
||||
= UsingDirectiveDecl::Create(Context, CurContext,
|
||||
/* 'using' */ LBrace,
|
||||
/* 'namespace' */ SourceLocation(),
|
||||
/* qualifier */ SourceRange(),
|
||||
/* NNS */ NULL,
|
||||
/* identifier */ SourceLocation(),
|
||||
Namespc,
|
||||
/* Ancestor */ CurContext);
|
||||
UD->setImplicit();
|
||||
CurContext->addDecl(UD);
|
||||
}
|
||||
}
|
||||
|
||||
// Although we could have an invalid decl (i.e. the namespace name is a
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// RUN: %clang_cc1 -emit-llvm-only -verify %s
|
||||
|
||||
// This lame little test was ripped straight from the standard.
|
||||
|
||||
namespace {
|
||||
int i; // expected-note {{candidate}}
|
||||
}
|
||||
|
@ -22,3 +21,22 @@ void test2() {
|
|||
A::i++;
|
||||
j++;
|
||||
}
|
||||
|
||||
|
||||
// Test that all anonymous namespaces in a translation unit are
|
||||
// considered the same context.
|
||||
namespace {
|
||||
class Test3 {}; // expected-note {{previous definition}}
|
||||
}
|
||||
namespace {
|
||||
class Test3 {}; // expected-error {{redefinition of 'Test3'}}
|
||||
}
|
||||
|
||||
namespace test4 {
|
||||
namespace {
|
||||
class Test4 {}; // expected-note {{previous definition}}
|
||||
}
|
||||
namespace {
|
||||
class Test4 {}; // expected-error {{redefinition of 'Test4'}}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue