]> granicus.if.org Git - clang/commitdiff
Warn when a 'typename' or a 'template' keyword refers to a
authorDouglas Gregor <dgregor@apple.com>
Mon, 14 Jun 2010 22:07:54 +0000 (22:07 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 14 Jun 2010 22:07:54 +0000 (22:07 +0000)
non-dependent type or template name, respectively, in C++98/03. Fixes
PR7111 and <rdar://problem/8002682>.

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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaTemplate.cpp
test/SemaObjCXX/message.mm
test/SemaTemplate/nested-name-spec-template.cpp
test/SemaTemplate/template-id-expr.cpp
test/SemaTemplate/typename-specifier-4.cpp
test/SemaTemplate/typename-specifier.cpp

index 337bd10fbf2baf86b685d42cffff0c79bee4ae31..4ad76e4678a3c49f84efc0ba725f8e2c798f69ec 100644 (file)
@@ -1611,6 +1611,9 @@ def note_typename_refers_here : Note<
     "referenced member %0 is declared here">;
 def err_typename_missing : Error<
   "missing 'typename' prior to dependent type name '%0%1'">;
+def ext_typename_nondependent : ExtWarn<
+  "'typename' refers to a non-dependent type name; accepted as a C++0x "
+  "extension">;
 
 def err_template_kw_refers_to_non_template : Error<
     "%0 following the 'template' keyword does not refer to a template">;
@@ -1622,6 +1625,9 @@ def note_referenced_class_template : Error<
     "class template declared here">;
 def err_template_kw_missing : Error<
   "missing 'template' keyword prior to dependent template name '%0%1'">;
+def ext_template_nondependent : ExtWarn<
+  "'template' refers to a non-dependent template name; accepted as a C++0x "
+  "extension">;
 
 // C++0x Variadic Templates
 def err_template_param_pack_default_arg : Error<
index 0c75cda57e651870b6a785bd903c9ed5853e8890..21d5702ea2531f1112927ff9b2c20062d1115895 100644 (file)
@@ -1714,7 +1714,7 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
     // the "template" keyword prior to a template-name that was not a
     // dependent name. C++ DR468 relaxed this requirement (the
     // "template" keyword is now permitted). We follow the C++0x
-    // rules, even in C++03 mode, retroactively applying the DR.
+    // rules, even in C++03 mode with a warning, retroactively applying the DR.
     TemplateTy Template;
     bool MemberOfUnknownSpecialization;
     TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
@@ -1733,6 +1733,15 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
       return TemplateTy();
     } else {
       // We found something; return it.
+      if (ActiveTemplateInstantiations.empty() &&
+          !getLangOptions().CPlusPlus0x &&
+          !SS.isEmpty() && !isDependentScopeSpecifier(SS))
+        Diag(TemplateKWLoc.isValid()? TemplateKWLoc 
+                                    : Name.getSourceRange().getBegin(), 
+             diag::ext_template_nondependent)
+        << SourceRange(Name.getSourceRange().getBegin())
+        << FixItHint::CreateRemoval(TemplateKWLoc);
+      
       return Template;
     }
   }
@@ -5368,7 +5377,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
   // the "typename" keyword itself is superfluous. In C++03, the
   // program is actually ill-formed. However, DR 382 (in C++0x CD1)
   // allows such extraneous "typename" keywords, and we retroactively
-  // apply this DR to C++03 code In any case we continue.
+  // apply this DR to C++03 code with only a warning. In any case we continue.
 
   if (RequireCompleteDeclContext(SS, Ctx))
     return QualType();
@@ -5389,6 +5398,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword,
 
   case LookupResult::Found:
     if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) {
+      if (ActiveTemplateInstantiations.empty() &&
+          !getLangOptions().CPlusPlus0x && !SS.isEmpty() &&
+          !isDependentScopeSpecifier(SS))
+        Diag(KeywordLoc.isValid()? KeywordLoc : IILoc, 
+             diag::ext_typename_nondependent)
+          << SourceRange(IILoc)
+          << FixItHint::CreateRemoval(KeywordLoc);
+      
       // We found a type. Build an ElaboratedType, since the
       // typename-specifier was just sugar.
       return Context.getElaboratedType(ETK_Typename, NNS,
index b75608e2327afbe869030b1ecb1afb257daf108e..10b886b203f4cdaeb71048f0ed00dab18fadf715 100644 (file)
@@ -62,15 +62,15 @@ struct identity {
   // or typename-specifiers.
   if (false) {
     if (true)
-      return [typename identity<I3>::type method];
+      return [typename identity<I3>::type method]; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}}
 
     return [::I3 method];
   }
 
   int* ip1 = {[super method]};
   int* ip2 = {[::I3 method]};
-  int* ip3 = {[typename identity<I3>::type method]};
-  int* ip4 = {[typename identity<I2_holder>::type().get() method]};
+  int* ip3 = {[typename identity<I3>::type method]}; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}}
+  int* ip4 = {[typename identity<I2_holder>::type().get() method]}; // expected-warning{{'typename' refers to a non-dependent type name; accepted as a C++0x extension}}
   int array[5] = {[3] = 2};
   return [super method];
 }
index 54e615b4ab69268c6f5b0610ac5db9e58bd541a3..e542507a2f7767a9251a1ed23fdaa11e142570fd 100644 (file)
@@ -21,7 +21,7 @@ namespace N {
   }
 
   M::Promote<int>::type *ret_intptr3(int* ip) { return ip; }
-  M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; }
+  M::template Promote<int>::type *ret_intptr4(int* ip) { return ip; } // expected-warning{{'template' refers to a non-dependent template name; accepted as a C++0x extension}}
 }
 
 N::M::Promote<int>::type *ret_intptr5(int* ip) { return ip; }
index de8d7f6c91a4aa52e735b8ab9a1c6f44c403e262..e8974211b60bb713304a3ac83842b38d131c5232 100644 (file)
@@ -62,12 +62,12 @@ struct Y0 {
 
   template<typename U>
   void f() {
-    Y0::template f1<U>(0);
-    Y0::template f1(0);
+    Y0::template f1<U>(0); // expected-warning{{'template' refers to a non-dependent template name}}
+    Y0::template f1(0); // expected-warning{{'template' refers to a non-dependent template name}}
     this->template f1(0);
 
-    Y0::template f2<U>(0);
-    Y0::template f2(0);
+    Y0::template f2<U>(0); // expected-warning{{'template' refers to a non-dependent template name}}
+    Y0::template f2(0);// expected-warning{{'template' refers to a non-dependent template name}}
 
     Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
     Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
@@ -75,7 +75,8 @@ struct Y0 {
     int x;
     x = Y0::f4(0);
     x = Y0::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
-    x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+    x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}} \
+    // expected-warning{{'template' refers to a non-dependent template name}}
 
     x = this->f4(0);
     x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
index 8dfb60d707189c75376158d3220a3249395730fa..da11119e5b276a93ad639466d3ad22316f432108 100644 (file)
@@ -27,7 +27,7 @@ struct make_pair {
 int a0[is_same<metafun_apply2<make_pair, int, float>::type, 
                pair<int, float> >::value? 1 : -1];
 int a1[is_same<
-         typename make_pair::template apply<int, float>,
+         typename make_pair::template apply<int, float>, // expected-warning{{'template' refers to a non-dependent template name}}
          make_pair::apply<int, float>
        >::value? 1 : -1];
 
index 3f6fe343f5079f920b6aef1a512cf4bbc80e4a5f..e066475be99e9635669439bda34461634039e2f0 100644 (file)
@@ -15,19 +15,20 @@ namespace N {
 
 int i;
 
-typename N::A::type *ip1 = &i;
+typename N::A::type *ip1 = &i; // expected-warning{{'typename' refers to a non-dependent type name}}
 typename N::B::type *ip2 = &i; // expected-error{{no type named 'type' in 'N::B'}}
 typename N::C::type *ip3 = &i; // expected-error{{typename specifier refers to non-type member 'type'}}
 
 void test(double d) {
-  typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}}
+  typename N::A::type f(typename N::A::type(a)); // expected-warning{{parentheses were disambiguated as a function declarator}} \
+  // expected-warning 2{{'typename' refers to a non-dependent type name}}
   int five = f(5);
   
   using namespace N;
-  for (typename A::type i = 0; i < 10; ++i)
+  for (typename A::type i = 0; i < 10; ++i) // expected-warning{{'typename' refers to a non-dependent type name}}
     five += 1;
 
-  const typename N::A::type f2(d);
+  const typename N::A::type f2(d); // expected-warning{{'typename' refers to a non-dependent type name}}
 }
 
 namespace N {