]> granicus.if.org Git - clang/commitdiff
Give a more appropriate diagnostic when a template specialization or
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 7 Dec 2013 05:09:50 +0000 (05:09 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sat, 7 Dec 2013 05:09:50 +0000 (05:09 +0000)
instantiation appears in a non-enclosing namespace (the previous diagnostic
talked about the C++98 rule even in C++11 mode).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196642 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/no-body.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
test/SemaTemplate/class-template-spec.cpp

index 0376d106eae08522e8e4b44490fd0443e3385103..d72c04c012132f2f2d89a22bd013d929f04322d1 100644 (file)
@@ -5596,13 +5596,37 @@ static bool CheckTemplateSpecializationScope(Sema &S,
   //   A class template partial specialization may be declared or redeclared
   //   in any namespace scope in which its definition may be defined (14.5.1
   //   and 14.5.2).
-  bool ComplainedAboutScope = false;
-  DeclContext *SpecializedContext 
+  DeclContext *SpecializedContext
     = Specialized->getDeclContext()->getEnclosingNamespaceContext();
   DeclContext *DC = S.CurContext->getEnclosingNamespaceContext();
-  if ((!PrevDecl ||
-       getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
-       getTemplateSpecializationKind(PrevDecl) == TSK_ImplicitInstantiation)){
+
+  // Make sure that this redeclaration (or definition) occurs in an enclosing
+  // namespace.
+  // Note that HandleDeclarator() performs this check for explicit
+  // specializations of function templates, static data members, and member
+  // functions, so we skip the check here for those kinds of entities.
+  // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
+  // Should we refactor that check, so that it occurs later?
+  if (!DC->Encloses(SpecializedContext) &&
+      !(isa<FunctionTemplateDecl>(Specialized) ||
+        isa<FunctionDecl>(Specialized) ||
+        isa<VarTemplateDecl>(Specialized) ||
+        isa<VarDecl>(Specialized))) {
+    if (isa<TranslationUnitDecl>(SpecializedContext))
+      S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
+        << EntityKind << Specialized;
+    else if (isa<NamespaceDecl>(SpecializedContext))
+      S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
+        << EntityKind << Specialized
+        << cast<NamedDecl>(SpecializedContext);
+    else
+      llvm_unreachable("unexpected namespace context for specialization");
+
+    S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
+  } else if ((!PrevDecl ||
+              getTemplateSpecializationKind(PrevDecl) == TSK_Undeclared ||
+              getTemplateSpecializationKind(PrevDecl) ==
+                  TSK_ImplicitInstantiation)) {
     // C++ [temp.exp.spec]p2:
     //   An explicit specialization shall be declared in the namespace of which
     //   the template is a member, or, for member templates, in the namespace
@@ -5611,9 +5635,12 @@ static bool CheckTemplateSpecializationScope(Sema &S,
     //   static data member of a class template shall be declared in the
     //   namespace of which the class template is a member.
     //
-    // C++0x [temp.expl.spec]p2:
+    // C++11 [temp.expl.spec]p2:
     //   An explicit specialization shall be declared in a namespace enclosing
     //   the specialized template.
+    // C++11 [temp.explicit]p3:
+    //   An explicit instantiation shall appear in an enclosing namespace of its
+    //   template.
     if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) {
       bool IsCPlusPlus11Extension = DC->Encloses(SpecializedContext);
       if (isa<TranslationUnitDecl>(SpecializedContext)) {
@@ -5634,34 +5661,9 @@ static bool CheckTemplateSpecializationScope(Sema &S,
       }
 
       S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
-      ComplainedAboutScope =
-        !(IsCPlusPlus11Extension && S.getLangOpts().CPlusPlus11);
     }
   }
 
-  // Make sure that this redeclaration (or definition) occurs in an enclosing
-  // namespace.
-  // Note that HandleDeclarator() performs this check for explicit
-  // specializations of function templates, static data members, and member
-  // functions, so we skip the check here for those kinds of entities.
-  // FIXME: HandleDeclarator's diagnostics aren't quite as good, though.
-  // Should we refactor that check, so that it occurs later?
-  if (!ComplainedAboutScope && !DC->Encloses(SpecializedContext) &&
-      !(isa<FunctionTemplateDecl>(Specialized) || isa<VarDecl>(Specialized) ||
-        isa<FunctionDecl>(Specialized))) {
-    if (isa<TranslationUnitDecl>(SpecializedContext))
-      S.Diag(Loc, diag::err_template_spec_redecl_global_scope)
-        << EntityKind << Specialized;
-    else if (isa<NamespaceDecl>(SpecializedContext))
-      S.Diag(Loc, diag::err_template_spec_redecl_out_of_scope)
-        << EntityKind << Specialized
-        << cast<NamedDecl>(SpecializedContext);
-
-    S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
-  }
-
-  // FIXME: check for specialization-after-instantiation errors and such.
-
   return false;
 }
 
index a4d7914d9eb6d9bcd507798cb2a72b7cd26bd39c..61d285b27ed28e0010abd8981d8568ae320c8360 100644 (file)
@@ -37,7 +37,7 @@ namespace noargs_body {
 namespace exp_spec {
 #ifndef FIXING
   template<> void f0<int>(int) { }  // expected-error {{no function template matches function template specialization 'f0'}}
-  template<> struct x0<int> { };    // expected-error {{class template specialization of 'x0' must originally be declared in the global scope}}
+  template<> struct x0<int> { };    // expected-error {{class template specialization of 'x0' must occur at global scope}}
 #endif
 }
 
@@ -51,7 +51,7 @@ namespace args_bad {
   template void f1<int>(int) { }    // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
                                        expected-error {{no function template matches function template specialization 'f1'}}
   template struct x1<int> { };      // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \
-                                       expected-error {{class template specialization of 'x1' must originally be declared in the global scope}}
+                                       expected-error {{class template specialization of 'x1' must occur at global scope}}
 #endif
 }
 
index 75b198e47d13c4b5ee5410a4f8eda32ab16b0bf6..1a7065e0022b937567ecf848bccf29774c26b3c8 100644 (file)
@@ -79,7 +79,7 @@ template<> struct N0::X0<void> { };
 N0::X0<void> test_X0;
 
 namespace N1 {
-  template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' must originally be declared in namespace 'N0'}}
+  template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' not in a namespace enclosing 'N0'}}
 }
 
 namespace N0 {
index c972bf7c7d0aafd203cb85c68a7fc91d8584b73d..4fbc45a7d7dd5e1b32799621bb007744756e291d 100644 (file)
@@ -80,7 +80,7 @@ template<> struct N0::X0<void> { }; // expected-warning{{C++11 extension}}
 N0::X0<void> test_X0;
 
 namespace N1 {
-  template<> struct N0::X0<const void> { }; // expected-error{{originally}}
+  template<> struct N0::X0<const void> { }; // expected-error{{not in a namespace enclosing 'N0'}}
 }
 
 namespace N0 {
index f9015b37ea0932d4bba41e8b8755dae6ac46b891..e82537abded2f8746ebc99261f0810423fe26786 100644 (file)
@@ -91,7 +91,7 @@ template<> struct N::B<float> { }; // expected-warning{{C++11 extension}}
 namespace M {
   template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
 
-  template<> struct ::A<long double>; // expected-error{{originally}}
+  template<> struct ::A<long double>; // expected-error{{must occur at global scope}}
 }
 
 template<> struct N::B<char> {