Successive anonymous namespaces name the same scope. I misinterpreted the

standard the last time.  Fixes PR5766.

llvm-svn: 91493
This commit is contained in:
John McCall 2009-12-16 02:06:49 +00:00
parent 85dabae6ad
commit 0db42252f7
3 changed files with 77 additions and 16 deletions

View File

@ -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; }

View File

@ -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,9 +2787,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
// declarations semantically contained within an anonymous
// namespace internal linkage.
assert(Namespc->isAnonymousNamespace());
CurContext->addDecl(Namespc);
if (!PrevDecl) {
UsingDirectiveDecl* UD
= UsingDirectiveDecl::Create(Context, CurContext,
/* 'using' */ LBrace,
@ -2780,6 +2800,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
UD->setImplicit();
CurContext->addDecl(UD);
}
}
// Although we could have an invalid decl (i.e. the namespace name is a
// redefinition), push it as current DeclContext and try to continue parsing.

View File

@ -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'}}
}
}