[cfe-commits] r127162 - in /cfe/trunk: include/clang/Sema/IdentifierResolver.h include/clang/Sema/Sema.h lib/Sema/IdentifierResolver.cpp lib/Sema/SemaDecl.cpp test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp

Douglas Gregor dgregor at apple.com
Mon Mar 7 08:54:27 PST 2011


Author: dgregor
Date: Mon Mar  7 10:54:27 2011
New Revision: 127162

URL: http://llvm.org/viewvc/llvm-project?rev=127162&view=rev
Log:
Support explicit template specialization and instantiation for members
of a C++0x inline namespace within enclosing namespaces, as noted in
C++0x [namespace.def]p8.

Fixes <rdar://problem/9006349>, a libc++ failure where Clang was
rejected an explicit specialization of std::swap (since libc++ puts it
into an inline, versioned namespace std::__1).


Added:
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Sema/IdentifierResolver.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/IdentifierResolver.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp

Modified: cfe/trunk/include/clang/Sema/IdentifierResolver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/IdentifierResolver.h?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/IdentifierResolver.h (original)
+++ cfe/trunk/include/clang/Sema/IdentifierResolver.h Mon Mar  7 10:54:27 2011
@@ -146,8 +146,13 @@
   /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
   /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
   /// true if 'D' belongs to the given declaration context.
+  ///
+  /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+  /// whether the declaration is in scope for the purposes of explicit template
+  /// instantiation or specialization. The default is false.
   bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context,
-                     Scope *S = 0) const;
+                     Scope *S = 0,
+                     bool ExplicitInstantiationOrSpecialization = false) const;
 
   /// AddDecl - Link the decl to its shadowed decl chain.
   void AddDecl(NamedDecl *D);

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Mar  7 10:54:27 2011
@@ -1058,7 +1058,12 @@
   /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true
   /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
   /// true if 'D' belongs to the given declaration context.
-  bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0);
+  ///
+  /// \param ExplicitInstantiationOrSpecialization When true, we are checking
+  /// whether the declaration is in scope for the purposes of explicit template
+  /// instantiation or specialization. The default is false.
+  bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0,
+                     bool ExplicitInstantiationOrSpecialization = false);
 
   /// Finds the scope corresponding to the given decl context, if it
   /// happens to be an enclosing scope.  Otherwise return NULL.

Modified: cfe/trunk/lib/Sema/IdentifierResolver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/IdentifierResolver.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/IdentifierResolver.cpp (original)
+++ cfe/trunk/lib/Sema/IdentifierResolver.cpp Mon Mar  7 10:54:27 2011
@@ -104,7 +104,8 @@
 /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns
 /// true if 'D' belongs to the given declaration context.
 bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx,
-                                       ASTContext &Context, Scope *S) const {
+                                       ASTContext &Context, Scope *S,
+                             bool ExplicitInstantiationOrSpecialization) const {
   Ctx = Ctx->getRedeclContext();
 
   if (Ctx->isFunctionOrMethod()) {
@@ -135,7 +136,10 @@
     return false;
   }
 
-  return D->getDeclContext()->getRedeclContext()->Equals(Ctx);
+  DeclContext *DCtx = D->getDeclContext()->getRedeclContext();
+  return ExplicitInstantiationOrSpecialization
+           ? Ctx->InEnclosingNamespaceSetOf(DCtx)
+           : Ctx->Equals(DCtx);
 }
 
 /// AddDecl - Link the decl to its shadowed decl chain.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Mar  7 10:54:27 2011
@@ -496,8 +496,10 @@
   IdResolver.AddDecl(D);
 }
 
-bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) {
-  return IdResolver.isDeclInScope(D, Ctx, Context, S);
+bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S,
+                         bool ExplicitInstantiationOrSpecialization) {
+  return IdResolver.isDeclInScope(D, Ctx, Context, S,
+                                  ExplicitInstantiationOrSpecialization);
 }
 
 Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) {
@@ -519,12 +521,13 @@
 /// as determined by isDeclInScope.
 static void FilterLookupForScope(Sema &SemaRef, LookupResult &R,
                                  DeclContext *Ctx, Scope *S,
-                                 bool ConsiderLinkage) {
+                                 bool ConsiderLinkage,
+                                 bool ExplicitInstantiationOrSpecialization) {
   LookupResult::Filter F = R.makeFilter();
   while (F.hasNext()) {
     NamedDecl *D = F.next();
 
-    if (SemaRef.isDeclInScope(D, Ctx, S))
+    if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization))
       continue;
 
     if (ConsiderLinkage &&
@@ -2886,7 +2889,8 @@
 
   // Merge the decl with the existing one if appropriate. If the decl is
   // in an outer scope, it isn't the same thing.
-  FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false);
+  FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false,
+                       /*ExplicitInstantiationOrSpecialization=*/false);
   if (!Previous.empty()) {
     Redeclaration = true;
     MergeTypeDefDecl(NewTD, Previous);
@@ -3167,7 +3171,8 @@
   // Don't consider existing declarations that are in a different
   // scope and are out-of-semantic-context declarations (if the new
   // declaration has linkage).
-  FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage());
+  FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(),
+                       isExplicitSpecialization);
   
   if (!getLangOptions().CPlusPlus)
     CheckVariableDeclaration(NewVD, Previous, Redeclaration);
@@ -3624,7 +3629,8 @@
     // Set the lexical context.
     NewFD->setLexicalDeclContext(CurContext);
     // Filter out previous declarations that don't match the scope.
-    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+                         /*ExplicitInstantiationOrSpecialization=*/false);
   } else {
     isFriend = D.getDeclSpec().isFriendSpecified();
     bool isVirtual = D.getDeclSpec().isVirtualSpecified();
@@ -3884,7 +3890,9 @@
     }
 
     // Filter out previous declarations that don't match the scope.
-    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage());
+    FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(),
+                         isExplicitSpecialization || 
+                         isFunctionTemplateSpecialization);
 
     if (isFriend) {
       // For now, claim that the objects have no previous declaration.
@@ -6268,7 +6276,7 @@
       // in the same scope (so that the definition/declaration completes or
       // rementions the tag), reuse the decl.
       if (TUK == TUK_Reference || TUK == TUK_Friend ||
-          isDeclInScope(PrevDecl, SearchDC, S)) {
+          isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) {
         // Make sure that this wasn't declared as an enum and now used as a
         // struct or something similar.
         if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) {
@@ -6412,7 +6420,8 @@
         Invalid = true;
 
       // Otherwise, only diagnose if the declaration is in scope.
-      } else if (!isDeclInScope(PrevDecl, SearchDC, S)) {
+      } else if (!isDeclInScope(PrevDecl, SearchDC, S, 
+                                isExplicitSpecialization)) {
         // do nothing
 
       // Diagnose implicit declarations introduced by elaborated types.

Modified: cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/basic.namespace/namespace.def/p8.cpp Mon Mar  7 10:54:27 2011
@@ -95,3 +95,24 @@
   };
 
 } }
+
+// Normal redeclarations (not for explicit instantiations or
+// specializations) are distinct in an inline namespace vs. not in an
+// inline namespace.
+namespace redecl2 { 
+  inline namespace n1 {
+    void f(int) { }
+    struct X1 { };
+    template<typename T> void f(T) { }
+    template<typename T> struct X2 { };
+    int i = 71;
+    enum E { e };
+  }
+
+  void f(int) { }
+  struct X1 { };
+  template<typename T> void f(T) { }
+  template<typename T> struct X2 { };
+  int i = 71;
+  enum E { e };
+}

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp?rev=127162&r1=127161&r2=127162&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp Mon Mar  7 10:54:27 2011
@@ -237,3 +237,66 @@
   xvp.ft1(vp, i);
   xvp.ft1(vp, u);
 }
+
+namespace has_inline_namespaces {
+  inline namespace inner {
+    template<class T> void f(T&);
+
+    template<class T> 
+    struct X0 {
+      struct MemberClass;
+
+      void mem_func();
+
+      template<typename U>
+      struct MemberClassTemplate;
+
+      template<typename U>
+      void mem_func_template(U&);
+
+      static int value;
+    };
+  }
+
+  struct X1;
+  struct X2;
+
+  // An explicit specialization whose declarator-id is not qualified
+  // shall be declared in the nearest enclosing namespace of the
+  // template, or, if the namespace is inline (7.3.1), any namespace
+  // from its enclosing namespace set.
+  template<> void f(X1&);
+  template<> void f<X2>(X2&);
+
+  template<> struct X0<X1> { };
+
+  template<> struct X0<X2>::MemberClass { };
+
+  template<> void X0<X2>::mem_func();
+
+  template<> template<typename T> struct X0<X2>::MemberClassTemplate { };
+
+  template<> template<typename T> void X0<X2>::mem_func_template(T&) { }
+
+  template<> int X0<X2>::value = 12;
+}
+
+struct X3;
+struct X4;
+
+template<> void has_inline_namespaces::f(X3&);
+template<> void has_inline_namespaces::f<X4>(X4&);
+
+template<> struct has_inline_namespaces::X0<X3> { };
+
+template<> struct has_inline_namespaces::X0<X4>::MemberClass { };
+
+template<> void has_inline_namespaces::X0<X4>::mem_func();
+
+template<> template<typename T> 
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate { };
+
+template<> template<typename T> 
+void has_inline_namespaces::X0<X4>::mem_func_template(T&) { }
+
+template<> int has_inline_namespaces::X0<X4>::value = 13;

Added: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp?rev=127162&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp Mon Mar  7 10:54:27 2011
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -std=c++0x -verify %s
+
+// If the name declared in the explicit instantiation is an
+// unqualified name, the explicit instantiation shall appear in the
+// namespace where its template is declared or, if that namespace is
+// inline (7.3.1), any namespace from its enclosing namespace set.
+
+namespace has_inline_namespaces {
+  inline namespace inner {
+    template<class T> void f(T&) {}
+
+    template<class T> 
+    struct X0 {
+      struct MemberClass {};
+
+      void mem_func() {}
+
+      template<typename U>
+      struct MemberClassTemplate {};
+
+      template<typename U>
+      void mem_func_template(U&) {}
+
+      static int value;
+    };
+  }
+
+  template<typename T> int X0<T>::value = 17;
+
+  struct X1 {};
+  struct X2 {};
+
+  template void f(X1&);
+  template void f<X2>(X2&);
+
+  template struct X0<X1>;
+
+  template struct X0<X2>::MemberClass;
+
+  template void X0<X2>::mem_func();
+
+  template struct X0<X2>::MemberClassTemplate<X1>;
+
+  template void X0<X2>::mem_func_template(X1&);
+
+  template int X0<X2>::value;
+}
+
+struct X3;
+struct X4;
+
+template void has_inline_namespaces::f(X3&);
+template void has_inline_namespaces::f<X4>(X4&);
+
+template struct has_inline_namespaces::X0<X3>;
+
+template struct has_inline_namespaces::X0<X4>::MemberClass;
+
+template void has_inline_namespaces::X0<X4>::mem_func();
+
+template 
+struct has_inline_namespaces::X0<X4>::MemberClassTemplate<X3>;
+
+template
+void has_inline_namespaces::X0<X4>::mem_func_template(X3&);

Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p3-0x.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list