[cfe-commits] r113718 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplate.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 test/SemaTemplate/temp_class_spec_neg.cpp

Douglas Gregor dgregor at apple.com
Sat Sep 11 22:24:55 PDT 2010


Author: dgregor
Date: Sun Sep 12 00:24:55 2010
New Revision: 113718

URL: http://llvm.org/viewvc/llvm-project?rev=113718&view=rev
Log:
When diagnosing C++ [temp.expl.spec]p3 in C++98/03 mode, downgrade the
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.

Added:
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
    cfe/trunk/test/SemaTemplate/class-template-spec.cpp
    cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=113718&r1=113717&r2=113718&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Sep 12 00:24:55 2010
@@ -1459,10 +1459,18 @@
   "%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 "

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=113718&r1=113717&r2=113718&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Sep 12 00:24:55 2010
@@ -3454,13 +3454,19 @@
     //   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;

Added: 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=113718&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2-0x.cpp Sun Sep 12 00:24:55 2010
@@ -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);
+}

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

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

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

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp?rev=113718&r1=113717&r2=113718&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.expl.spec/p2.cpp Sun Sep 12 00:24:55 2010
@@ -36,7 +36,7 @@
   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 @@
 
 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 @@
 };
 
 //     -- 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 @@
   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 @@
 }
 
 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 @@
 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 @@
 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<>

Modified: cfe/trunk/test/SemaTemplate/class-template-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-spec.cpp?rev=113718&r1=113717&r2=113718&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-spec.cpp Sun Sep 12 00:24:55 2010
@@ -86,7 +86,7 @@
 
 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'}}

Modified: cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp?rev=113718&r1=113717&r2=113718&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Sun Sep 12 00:24:55 2010
@@ -9,7 +9,7 @@
 }
 
 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





More information about the cfe-commits mailing list