Make inline namespace not be transparent after all. The concept simply doesn't fit...
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 31 Aug 2010 20:53:31 +0000 (20:53 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 31 Aug 2010 20:53:31 +0000 (20:53 +0000)
llvm-svn: 112637

clang/include/clang/AST/DeclBase.h
clang/lib/AST/DeclBase.cpp
clang/lib/Sema/SemaLookup.cpp
clang/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp

index d5b183b6a556d9a6f81c382cb51dc5af858b87ec..1369c2b5955a9663478fd5051b5287a056af1d27 100644 (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();
index ca8837703429655e05c8034a50329a920ef3c877..0b958fe82b093a38ddc819d2b973c43906b4f3f2 100644 (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);
 }
 
index bb267e3733a467750801dea557c006f8ab3a8e0b..1e047106cd45b389e5373a5f80d63f3649a11ed0 100644 (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);
       }
index 540af17423987455a7de1cefe5fce57b06ff453a..b9ad6e1c067f4156fde33de2852a1a7ee3ad70bf 100644 (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);
+  };
+
+} }