]> granicus.if.org Git - clang/commitdiff
When diagnosing C++ [temp.expl.spec]p3 in C++98/03 mode, downgrade the
authorDouglas Gregor <dgregor@apple.com>
Sun, 12 Sep 2010 05:24:55 +0000 (05:24 +0000)
committerDouglas Gregor <dgregor@apple.com>
Sun, 12 Sep 2010 05:24:55 +0000 (05:24 +0000)
error to a warning if we're in a case that would be allowed in
C++0x. This "fixes" PR8084 by making Clang accept more code than GCC
and (non-strict) EDG do.

Also, add the missing test case for the C++0x semantics, which should
have been in r113717.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp [new file with mode: 0644]
test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
test/SemaTemplate/class-template-spec.cpp
test/SemaTemplate/temp_class_spec_neg.cpp

index 05a76a71a44ea2aa3c7cba2f56e246c947c053df..9a2102b74316d6aba012432f6dfc08d5aa80dc3d 100644 (file)
@@ -1459,10 +1459,18 @@ def err_template_spec_decl_out_of_scope_global : Error<
   "%select{class template|class template partial|function template|member "
   "function|static data member|member class}0 specialization of %1 must "
   "originally be declared in the global scope">;
+def ext_template_spec_decl_out_of_scope_global : ExtWarn<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 must "
+  "originally be declared in the global scope; accepted as a C++0x extension">;
 def err_template_spec_decl_out_of_scope : Error<
   "%select{class template|class template partial|function template|member "
   "function|static data member|member class}0 specialization of %1 must "
   "originally be declared in namespace %2">;
+def ext_template_spec_decl_out_of_scope : ExtWarn<
+  "%select{class template|class template partial|function template|member "
+  "function|static data member|member class}0 specialization of %1 must "
+  "originally be declared in namespace %2; accepted as a C++0x extension">;
 def err_template_spec_redecl_out_of_scope : Error<
   "%select{class template|class template partial|function template|member "
   "function|static data member|member class}0 specialization of %1 not in a "
index 851f7b96045895cd20b41db0526e7f2afa4775b9..6fe8c75441fc1d9feafe12c05dd75f6feb4999d9 100644 (file)
@@ -3454,13 +3454,19 @@ static bool CheckTemplateSpecializationScope(Sema &S,
     //   the specialized template.
     if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) &&
         !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) {
+      bool IsCPlusPlus0xExtension
+        = !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext);
       if (isa<TranslationUnitDecl>(SpecializedContext))
-        S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
-        << EntityKind << Specialized;
+        S.Diag(Loc, IsCPlusPlus0xExtension
+                      ? diag::ext_template_spec_decl_out_of_scope_global
+                      : diag::err_template_spec_decl_out_of_scope_global)
+          << EntityKind << Specialized;
       else if (isa<NamespaceDecl>(SpecializedContext))
-        S.Diag(Loc, diag::err_template_spec_decl_out_of_scope)
-        << EntityKind << Specialized
-        << cast<NamedDecl>(SpecializedContext);
+        S.Diag(Loc, IsCPlusPlus0xExtension
+                      ? diag::ext_template_spec_decl_out_of_scope
+                      : diag::err_template_spec_decl_out_of_scope)
+          << EntityKind << Specialized
+          << cast<NamedDecl>(SpecializedContext);
       
       S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
       ComplainedAboutScope = true;
diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp
new file mode 100644 (file)
index 0000000..ed600e4
--- /dev/null
@@ -0,0 +1,239 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
+
+// This test creates cases where implicit instantiations of various entities
+// would cause a diagnostic, but provides expliict specializations for those
+// entities that avoid the diagnostic. The specializations are alternately
+// declarations and definitions, and the intent of this test is to verify
+// that we allow specializations only in the appropriate namespaces (and
+// nowhere else).
+struct NonDefaultConstructible {
+  NonDefaultConstructible(int);
+};
+
+
+// C++ [temp.expl.spec]p1:
+//   An explicit specialization of any of the following:
+
+//     -- function template
+namespace N0 {
+  template<typename T> void f0(T) {
+    T t;
+  }
+
+  template<> void f0(NonDefaultConstructible) { }
+
+  void test_f0(NonDefaultConstructible NDC) {
+    f0(NDC);
+  }
+  
+  template<> void f0(int);
+  template<> void f0(long);
+}
+
+template<> void N0::f0(int) { } // okay
+
+namespace N1 {
+  template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
+}
+
+template<> void N0::f0(double) { }
+
+struct X1 {
+  template<typename T> void f(T);
+  
+  template<> void f(int); // expected-error{{in class scope}}
+};
+
+//     -- class template
+namespace N0 {
+  
+template<typename T>
+struct X0 { // expected-note {{here}}
+  static T member;
+  
+  void f1(T t) {
+    t = 17;
+  }
+  
+  struct Inner : public T { }; // expected-note 2{{here}}
+  
+  template<typename U>
+  struct InnerTemplate : public T { }; // expected-note 1{{explicitly specialized}} \
+   // expected-error{{base specifier}}
+  
+  template<typename U>
+  void ft1(T t, U u);
+};
+
+}
+
+template<typename T> 
+template<typename U>
+void N0::X0<T>::ft1(T t, U u) {
+  t = u;
+}
+
+template<typename T> T N0::X0<T>::member;
+
+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'}}
+}
+
+namespace N0 {
+  template<> struct X0<volatile void>;
+}
+
+template<> struct N0::X0<volatile void> { 
+  void f1(void *);
+};
+
+//     -- member function of a class template
+template<> void N0::X0<void*>::f1(void *) { }
+
+void test_spec(N0::X0<void*> xvp, void *vp) {
+  xvp.f1(vp);
+}
+
+namespace N0 {
+  template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
+
+  template<> void X0<const volatile void*>::f1(const volatile void*);
+}
+
+void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) {
+  x0.f1(cvp); // okay: we've explicitly specialized
+}
+
+//     -- static data member of a class template
+namespace N0 {
+  // This actually tests p15; the following is a declaration, not a definition.
+  template<> 
+  NonDefaultConstructible X0<NonDefaultConstructible>::member;
+  
+  template<> long X0<long>::member = 17;
+
+  template<> float X0<float>::member;
+  
+  template<> double X0<double>::member;
+}
+
+NonDefaultConstructible &get_static_member() {
+  return N0::X0<NonDefaultConstructible>::member;
+}
+
+template<> int N0::X0<int>::member;
+
+template<> float N0::X0<float>::member = 3.14f;
+
+namespace N1 {
+  template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
+}
+
+//    -- member class of a class template
+namespace N0 {
+  
+  template<>
+  struct X0<void*>::Inner { };
+
+  template<>
+  struct X0<int>::Inner { };
+
+  template<>
+  struct X0<unsigned>::Inner;
+
+  template<>
+  struct X0<float>::Inner;
+
+  template<>
+  struct X0<double>::Inner; // expected-note{{forward declaration}}
+}
+
+template<>
+struct N0::X0<long>::Inner { };
+
+template<>
+struct N0::X0<float>::Inner { };
+
+namespace N1 {
+  template<>
+  struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
+
+  template<>
+  struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
+};
+
+N0::X0<void*>::Inner inner0;
+N0::X0<int>::Inner inner1;
+N0::X0<long>::Inner inner2;
+N0::X0<float>::Inner inner3;
+N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
+
+//    -- member class template of a class template
+namespace N0 {
+  template<>
+  template<>
+  struct X0<void*>::InnerTemplate<int> { };
+  
+  template<> template<>
+  struct X0<int>::InnerTemplate<int>; // expected-note{{forward declaration}}
+
+  template<> template<>
+  struct X0<int>::InnerTemplate<long>;
+
+  template<> template<>
+  struct X0<int>::InnerTemplate<double>;
+}
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<long> { }; // okay
+
+template<> template<>
+struct N0::X0<int>::InnerTemplate<float> { };
+
+namespace N1 {
+  template<> template<>
+  struct N0::X0<int>::InnerTemplate<double> { }; // expected-error{{enclosing}}
+}
+
+N0::X0<void*>::InnerTemplate<int> inner_template0;
+N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}}
+N0::X0<int>::InnerTemplate<long> inner_template2;
+N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}}
+
+//    -- member function template of a class template
+namespace N0 {
+  template<>
+  template<>
+  void X0<void*>::ft1(void*, const void*) { }
+  
+  template<> template<>
+  void X0<void*>::ft1(void *, int);
+
+  template<> template<>
+  void X0<void*>::ft1(void *, unsigned);
+
+  template<> template<>
+  void X0<void*>::ft1(void *, long);
+}
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, unsigned) { } // okay
+
+template<> template<>
+void N0::X0<void*>::ft1(void *, float) { }
+
+namespace N1 {
+  template<> template<>
+  void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
+}
+
+
+void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
+                        int i, unsigned u) {
+  xvp.ft1(vp, cvp);
+  xvp.ft1(vp, i);
+  xvp.ft1(vp, u);
+}
index 654f5abb8a548b9314267a21a0da4a0d7d2a2ae2..1032a87def133248e6f1b5bf5e2ac2a4be603dfa 100644 (file)
@@ -36,7 +36,7 @@ namespace N1 {
   template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
 }
 
-template<> void N0::f0(double) { } // expected-error{{originally be declared}}
+template<> void N0::f0(double) { } // expected-warning{{originally be declared}}
 
 struct X1 {
   template<typename T> void f(T);
@@ -75,7 +75,7 @@ void N0::X0<T>::ft1(T t, U u) {
 
 template<typename T> T N0::X0<T>::member;
 
-template<> struct N0::X0<void> { }; // expected-error{{originally}}
+template<> struct N0::X0<void> { }; // expected-warning{{originally}}
 N0::X0<void> test_X0;
 
 namespace N1 {
@@ -91,7 +91,7 @@ template<> struct N0::X0<volatile void> {
 };
 
 //     -- member function of a class template
-template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
+template<> void N0::X0<void*>::f1(void *) { } // expected-warning{{member function specialization}}
 
 void test_spec(N0::X0<void*> xvp, void *vp) {
   xvp.f1(vp);
@@ -124,7 +124,7 @@ NonDefaultConstructible &get_static_member() {
   return N0::X0<NonDefaultConstructible>::member;
 }
 
-template<> int N0::X0<int>::member;  // expected-error{{originally}}
+template<> int N0::X0<int>::member;  // expected-warning{{originally}}
 
 template<> float N0::X0<float>::member = 3.14f;
 
@@ -152,7 +152,7 @@ namespace N0 {
 }
 
 template<>
-struct N0::X0<long>::Inner { }; // expected-error{{originally}}
+struct N0::X0<long>::Inner { }; // expected-warning{{originally}}
 
 template<>
 struct N0::X0<float>::Inner { };
@@ -191,7 +191,7 @@ template<> template<>
 struct N0::X0<int>::InnerTemplate<long> { }; // okay
 
 template<> template<>
-struct N0::X0<int>::InnerTemplate<float> { }; // expected-error{{class template specialization}}
+struct N0::X0<int>::InnerTemplate<float> { }; // expected-warning{{class template specialization}}
 
 namespace N1 {
   template<> template<>
@@ -223,7 +223,7 @@ template<> template<>
 void N0::X0<void*>::ft1(void *, unsigned) { } // okay
 
 template<> template<>
-void N0::X0<void*>::ft1(void *, float) { } // expected-error{{function template specialization}}
+void N0::X0<void*>::ft1(void *, float) { } // expected-warning{{function template specialization}}
 
 namespace N1 {
   template<> template<>
index c65802e5c86937786589a435600ca4ade642d3bd..07a5e2982c7f502ea963e98e369c29557525c631 100644 (file)
@@ -86,7 +86,7 @@ namespace N {
 
 template<> struct N::B<int> { }; // okay
 
-template<> struct N::B<float> { }; // expected-error{{originally}}
+template<> struct N::B<float> { }; // expected-warning{{originally}}
 
 namespace M {
   template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
index c8e8a57f278bdfff7926170d2054cfacc2c51adf..6b129a5369fbfcf9f564f38ac557d18071e27de2 100644 (file)
@@ -9,7 +9,7 @@ namespace N {
 }
 
 template<typename T>
-struct N::M::A<T*> { }; // expected-error{{originally}}
+struct N::M::A<T*> { }; // expected-warning{{originally}}
 
 // C++ [temp.class.spec]p9
 //   bullet 1