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.

llvm-svn: 112637
This commit is contained in:
Sebastian Redl 2010-08-31 20:53:31 +00:00
parent a23e8f7a0f
commit bd59576541
4 changed files with 47 additions and 17 deletions

View File

@ -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<DeclContext *>(this)->getRedeclContext();

View File

@ -478,6 +478,11 @@ DeclContext *DeclContext::getLookupParent() {
return getParent();
}
bool DeclContext::isInlineNamespace() const {
return isNamespace() &&
cast<NamespaceDecl>(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<RecordDecl>(this)->isAnonymousStructOrUnion();
else if (DeclKind == Decl::Namespace)
return cast<NamespaceDecl>(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<DeclContext>(*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);
}

View File

@ -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<DeclContext>(*D)) {
if (InnerCtx->isTransparentContext())
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
LookupVisibleDecls(InnerCtx, Result, QualifiedNameLookup, InBaseClass,
Consumer, Visited);
}

View File

@ -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 Tp> class allocator;
template <>
class allocator<void>
{
public:
typedef const void* const_pointer;
};
template <class Tp>
class allocator
{
public:
typedef Tp& reference;
void allocate(allocator<void>::const_pointer = 0);
};
} }