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 {
|
class TranslationUnitDecl : public Decl, public DeclContext {
|
||||||
ASTContext &Ctx;
|
ASTContext &Ctx;
|
||||||
|
|
||||||
|
/// The (most recently entered) anonymous namespace for this
|
||||||
|
/// translation unit, if one has been created.
|
||||||
|
NamespaceDecl *AnonymousNamespace;
|
||||||
|
|
||||||
explicit TranslationUnitDecl(ASTContext &ctx)
|
explicit TranslationUnitDecl(ASTContext &ctx)
|
||||||
: Decl(TranslationUnit, 0, SourceLocation()),
|
: Decl(TranslationUnit, 0, SourceLocation()),
|
||||||
DeclContext(TranslationUnit),
|
DeclContext(TranslationUnit),
|
||||||
Ctx(ctx) {}
|
Ctx(ctx), AnonymousNamespace(0) {}
|
||||||
public:
|
public:
|
||||||
ASTContext &getASTContext() const { return Ctx; }
|
ASTContext &getASTContext() const { return Ctx; }
|
||||||
|
|
||||||
|
NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
|
||||||
|
void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
|
||||||
|
|
||||||
static TranslationUnitDecl *Create(ASTContext &C);
|
static TranslationUnitDecl *Create(ASTContext &C);
|
||||||
// Implement isa/cast/dyncast/etc.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) { return D->getKind() == TranslationUnit; }
|
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.
|
// OrigNamespace of the first namespace decl points to itself.
|
||||||
NamespaceDecl *OrigNamespace, *NextNamespace;
|
NamespaceDecl *OrigNamespace, *NextNamespace;
|
||||||
|
|
||||||
|
// The (most recently entered) anonymous namespace inside this
|
||||||
|
// namespace.
|
||||||
|
NamespaceDecl *AnonymousNamespace;
|
||||||
|
|
||||||
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id)
|
||||||
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
|
: NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) {
|
||||||
OrigNamespace = this;
|
OrigNamespace = this;
|
||||||
NextNamespace = 0;
|
NextNamespace = 0;
|
||||||
|
AnonymousNamespace = 0;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
static NamespaceDecl *Create(ASTContext &C, DeclContext *DC,
|
||||||
|
@ -278,6 +290,16 @@ public:
|
||||||
}
|
}
|
||||||
void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; }
|
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; }
|
virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; }
|
||||||
const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
|
const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; }
|
||||||
|
|
||||||
|
|
|
@ -2748,6 +2748,28 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
||||||
PushOnScopeChains(Namespc, DeclRegionScope);
|
PushOnScopeChains(Namespc, DeclRegionScope);
|
||||||
} else {
|
} else {
|
||||||
// Anonymous namespaces.
|
// 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
|
// C++ [namespace.unnamed]p1. An unnamed-namespace-definition
|
||||||
// behaves as if it were replaced by
|
// behaves as if it were replaced by
|
||||||
|
@ -2765,9 +2787,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
||||||
// declarations semantically contained within an anonymous
|
// declarations semantically contained within an anonymous
|
||||||
// namespace internal linkage.
|
// namespace internal linkage.
|
||||||
|
|
||||||
assert(Namespc->isAnonymousNamespace());
|
if (!PrevDecl) {
|
||||||
CurContext->addDecl(Namespc);
|
|
||||||
|
|
||||||
UsingDirectiveDecl* UD
|
UsingDirectiveDecl* UD
|
||||||
= UsingDirectiveDecl::Create(Context, CurContext,
|
= UsingDirectiveDecl::Create(Context, CurContext,
|
||||||
/* 'using' */ LBrace,
|
/* 'using' */ LBrace,
|
||||||
|
@ -2780,6 +2800,7 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope,
|
||||||
UD->setImplicit();
|
UD->setImplicit();
|
||||||
CurContext->addDecl(UD);
|
CurContext->addDecl(UD);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Although we could have an invalid decl (i.e. the namespace name is a
|
// 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.
|
// redefinition), push it as current DeclContext and try to continue parsing.
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// RUN: %clang_cc1 -emit-llvm-only -verify %s
|
// RUN: %clang_cc1 -emit-llvm-only -verify %s
|
||||||
|
|
||||||
// This lame little test was ripped straight from the standard.
|
// This lame little test was ripped straight from the standard.
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
int i; // expected-note {{candidate}}
|
int i; // expected-note {{candidate}}
|
||||||
}
|
}
|
||||||
|
@ -22,3 +21,22 @@ void test2() {
|
||||||
A::i++;
|
A::i++;
|
||||||
j++;
|
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