From 410c4f2eb5e6a8c2318cacb9a6751f1b4fcff166 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Tue, 31 Aug 2010 20:53:31 +0000 Subject: [PATCH] Make inline namespace not be transparent after all. The concept simply doesn't fit. Instead, special-case the few places where transparent contexts have the desired behavior for inline namespaces. Fixes a redeclaration issue in inline namespaces. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112637 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclBase.h | 8 +++---- lib/AST/DeclBase.cpp | 23 +++++++++++-------- lib/Sema/SemaLookup.cpp | 10 +++++--- .../basic.namespace/namespace.def/p8.cpp | 23 +++++++++++++++++++ 4 files changed, 47 insertions(+), 17 deletions(-) diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index d5b183b6a5..1369c2b595 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -784,6 +784,8 @@ public: return DeclKind == Decl::Namespace; } + bool isInlineNamespace() const; + /// \brief Determines whether this context is dependent on a /// template parameter. bool isDependentContext() const; @@ -802,8 +804,7 @@ public: /// Here, E is a transparent context, so its enumerator (Val1) will /// appear (semantically) that it is in the same context of E. /// Examples of transparent contexts include: enumerations (except for - /// C++0x scoped enums), C++ linkage specifications, and C++0x - /// inline namespaces. + /// C++0x scoped enums), and C++ linkage specifications. bool isTransparentContext() const; /// \brief Determine whether this declaration context is equivalent @@ -829,8 +830,7 @@ public: /// getRedeclContext - Retrieve the context in which an entity conflicts with /// other entities of the same name, or where it is a redeclaration if the - /// two entities are compatible. This skips through transparent contexts, - /// except inline namespaces. + /// two entities are compatible. This skips through transparent contexts. DeclContext *getRedeclContext(); const DeclContext *getRedeclContext() const { return const_cast(this)->getRedeclContext(); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index ca88377034..0b958fe82b 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -478,6 +478,11 @@ DeclContext *DeclContext::getLookupParent() { return getParent(); } +bool DeclContext::isInlineNamespace() const { + return isNamespace() && + cast(this)->isInline(); +} + bool DeclContext::isDependentContext() const { if (isFileContext()) return false; @@ -509,8 +514,6 @@ bool DeclContext::isTransparentContext() const { return true; else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord) return cast(this)->isAnonymousStructOrUnion(); - else if (DeclKind == Decl::Namespace) - return cast(this)->isInline(); return false; } @@ -799,10 +802,10 @@ void DeclContext::buildLookup(DeclContext *DCtx) { I != IEnd; ++I) makeDeclVisibleInContextImpl(I->getInterface()); - // If this declaration is itself a transparent declaration context, - // add its members (recursively). + // If this declaration is itself a transparent declaration context or + // inline namespace, add its members (recursively). if (DeclContext *InnerCtx = dyn_cast(*D)) - if (InnerCtx->isTransparentContext()) + if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) buildLookup(InnerCtx->getPrimaryContext()); } } @@ -849,8 +852,8 @@ DeclContext::lookup(DeclarationName Name) const { DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; - // Skip through transparent contexts, except inline namespaces. - while (Ctx->isTransparentContext() && !Ctx->isNamespace()) + // Skip through transparent contexts. + while (Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; } @@ -904,9 +907,9 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { if (LookupPtr || !Recoverable || hasExternalVisibleStorage()) makeDeclVisibleInContextImpl(D); - // If we are a transparent context, insert into our parent context, - // too. This operation is recursive. - if (isTransparentContext()) + // If we are a transparent context or inline namespace, insert into our + // parent context, too. This operation is recursive. + if (isTransparentContext() || isInlineNamespace()) getParent()->makeDeclVisibleInContext(D, Recoverable); } diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index bb267e3733..1e047106cd 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1619,7 +1619,11 @@ static void CollectEnclosingNamespace(Sema::AssociatedNamespaceSet &Namespaces, // We don't use DeclContext::getEnclosingNamespaceContext() as this may // be a locally scoped record. - while (Ctx->isRecord() || Ctx->isTransparentContext()) + // We skip out of inline namespaces. The innermost non-inline namespace + // contains all names of all its nested inline namespaces anyway, so we can + // replace the entire inline namespace tree with its root. + while (Ctx->isRecord() || Ctx->isTransparentContext() || + Ctx->isInlineNamespace()) Ctx = Ctx->getParent(); if (Ctx->isFileContext()) @@ -2423,9 +2427,9 @@ static void LookupVisibleDecls(DeclContext *Ctx, LookupResult &Result, Visited.add(ND); } - // Visit transparent contexts inside this context. + // Visit transparent contexts and inline namespaces inside this context. if (DeclContext *InnerCtx = dyn_cast(*D)) { - if (InnerCtx->isTransparentContext()) + if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass, Consumer, Visited); } diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp index 540af17423..b9ad6e1c06 100644 --- a/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp @@ -72,3 +72,26 @@ void foo3() { Distinct d; ::over(d); } + +// Don't forget to do correct lookup for redeclarations. +namespace redecl { inline namespace n1 { + + template class allocator; + + template <> + class allocator + { + public: + typedef const void* const_pointer; + }; + + template + class allocator + { + public: + typedef Tp& reference; + + void allocate(allocator::const_pointer = 0); + }; + +} } -- 2.40.0