From 5fdd7643ae81af4ace04f8be888f225b9fcc64b7 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 16 Dec 2009 02:06:49 +0000 Subject: [PATCH] Successive anonymous namespaces name the same scope. I misinterpreted the standard the last time. Fixes PR5766. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@91493 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 24 ++++++++- lib/Sema/SemaDeclCXX.cpp | 49 +++++++++++++------ .../namespace.def/namespace.unnamed/p1.cpp | 20 +++++++- 3 files changed, 77 insertions(+), 16 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index d226f64b3e..40603516ff 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -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; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a70841f536..08edb117e8 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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(Parent)) { + PrevDecl = TU->getAnonymousNamespace(); + TU->setAnonymousNamespace(Namespc); + } else { + NamespaceDecl *ND = cast(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 diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.unnamed/p1.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.unnamed/p1.cpp index 09f291c4dd..b4ec585e48 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.unnamed/p1.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/namespace.unnamed/p1.cpp @@ -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'}} + } +} -- 2.40.0