From: Douglas Gregor Date: Wed, 24 Mar 2010 00:46:35 +0000 (+0000) Subject: Make sure to properly track the anonymous namespace that lives inside X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a418147c61a14cd21d4cce8f9c7a8750d2a59803;p=clang Make sure to properly track the anonymous namespace that lives inside each namespace, even when the outer namespace has multiple definitions. As part of this, collapsed two pointers worth of storage (original namespace and inner anonymous namespace) into a single pointer with a distinguishing bit, since the two are mutually exclusive, saving a pointer per NamespaceDecl. Fixes PR6620. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99368 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index e23811d8f9..5e06f05624 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -224,18 +224,26 @@ class NamespaceDecl : public NamedDecl, public DeclContext { // NextNamespace points to the next extended declaration. // OrigNamespace points to the original namespace declaration. // OrigNamespace of the first namespace decl points to itself. - NamespaceDecl *OrigNamespace, *NextNamespace; + NamespaceDecl *NextNamespace; - // The (most recently entered) anonymous namespace inside this - // namespace. - NamespaceDecl *AnonymousNamespace; + /// \brief A pointer to either the original namespace definition for + /// this namespace (if the boolean value is false) or the anonymous + /// namespace that lives just inside this namespace (if the boolean + /// value is true). + /// + /// We can combine these two notions because the anonymous namespace + /// must only be stored in one of the namespace declarations (so all + /// of the namespace declarations can find it). We therefore choose + /// the original namespace declaration, since all of the namespace + /// declarations have a link directly to it; the original namespace + /// declaration itself only needs to know that it is the original + /// namespace declaration (which the boolean indicates). + llvm::PointerIntPair OrigOrAnonNamespace; NamespaceDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id) - : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace) { - OrigNamespace = this; - NextNamespace = 0; - AnonymousNamespace = 0; - } + : NamedDecl(Namespace, DC, L, Id), DeclContext(Namespace), + NextNamespace(0), OrigOrAnonNamespace(0, true) { } + public: static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id); @@ -258,22 +266,33 @@ public: void setNextNamespace(NamespaceDecl *ND) { NextNamespace = ND; } NamespaceDecl *getOriginalNamespace() const { - return OrigNamespace; + if (OrigOrAnonNamespace.getInt()) + return const_cast(this); + + return OrigOrAnonNamespace.getPointer(); + } + + void setOriginalNamespace(NamespaceDecl *ND) { + if (ND != this) { + OrigOrAnonNamespace.setPointer(ND); + OrigOrAnonNamespace.setInt(false); + } } - void setOriginalNamespace(NamespaceDecl *ND) { OrigNamespace = ND; } NamespaceDecl *getAnonymousNamespace() const { - return AnonymousNamespace; + return getOriginalNamespace()->OrigOrAnonNamespace.getPointer(); } void setAnonymousNamespace(NamespaceDecl *D) { assert(!D || D->isAnonymousNamespace()); assert(!D || D->getParent() == this); - AnonymousNamespace = D; + getOriginalNamespace()->OrigOrAnonNamespace.setPointer(D); } - virtual NamespaceDecl *getCanonicalDecl() { return OrigNamespace; } - const NamespaceDecl *getCanonicalDecl() const { return OrigNamespace; } + virtual NamespaceDecl *getCanonicalDecl() { return getOriginalNamespace(); } + const NamespaceDecl *getCanonicalDecl() const { + return getOriginalNamespace(); + } virtual SourceRange getSourceRange() const { return SourceRange(getLocation(), RBracLoc); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 3e97b6bf71..76875c9773 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2955,7 +2955,6 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, } else { // Anonymous namespaces. assert(Namespc->isAnonymousNamespace()); - CurContext->addDecl(Namespc); // Link the anonymous namespace into its parent. NamespaceDecl *PrevDecl; @@ -2977,6 +2976,8 @@ Sema::DeclPtrTy Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PrevDecl->setNextNamespace(Namespc); } + CurContext->addDecl(Namespc); + // C++ [namespace.unnamed]p1. An unnamed-namespace-definition // behaves as if it were replaced by // namespace unique { /* empty body */ } diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp index 2a9d31fa94..d47b7076ce 100644 --- a/test/SemaCXX/namespace.cpp +++ b/test/SemaCXX/namespace.cpp @@ -68,3 +68,25 @@ namespace foo { static foo::x test1; // ok static foo::X test2; // typo: expected-error {{no type named 'X' in}} + +namespace PR6620 { + namespace numeric { + namespace op { + struct greater {}; + } + namespace { + extern op::greater const greater; + } + } + + namespace numeric { + namespace { + op::greater const greater = op::greater(); + } + + template + int f(T& l, U& r) + { numeric::greater(l, r); } + + } +}