r184503 - Bug Fix: Template explicit instantiations should not have definitions (FixIts yet to be tested.)

Larisse Voufo lvoufo at google.com
Thu Jun 20 17:08:47 PDT 2013


Author: lvoufo
Date: Thu Jun 20 19:08:46 2013
New Revision: 184503

URL: http://llvm.org/viewvc/llvm-project?rev=184503&view=rev
Log:
Bug Fix: Template explicit instantiations should not have definitions (FixIts yet to be tested.)

Added:
    cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=184503&r1=184502&r2=184503&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Jun 20 19:08:46 2013
@@ -592,6 +592,9 @@ def err_explicit_instantiation_with_defi
     "explicit template instantiation cannot have a definition; if this "
     "definition is meant to be an explicit specialization, add '<>' after the "
     "'template' keyword">;
+def err_template_defn_explicit_instantiation : Error<
+  "%select{function|class}0 cannot be defined in an explicit instantiation; if this "
+  "declaration is meant to be a %select{function|class}0 definition, remove the 'template' keyword">;
 def err_explicit_instantiation_enum : Error<
     "enumerations cannot be explicitly instantiated">;
 def err_expected_template_parameter : Error<"expected template parameter">;

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=184503&r1=184502&r2=184503&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Jun 20 19:08:46 2013
@@ -13,6 +13,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "RAIIObjectsForParser.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/Basic/AddressSpaces.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Basic/OpenCL.h"

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=184503&r1=184502&r2=184503&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jun 20 19:08:46 2013
@@ -1539,6 +1539,14 @@ void Parser::ParseClassSpecifier(tok::To
   } else {
     if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
       ProhibitAttributes(attrs);
+    
+    if (TUK == Sema::TUK_Definition &&
+        TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+      // If the declarator-id is not a template-id, issue a diagnostic and
+      // recover by ignoring the 'template' keyword.
+      Diag(Tok, diag::err_template_defn_explicit_instantiation)
+        << 1 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc);
+    }
 
     bool IsDependent = false;
 

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=184503&r1=184502&r2=184503&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Thu Jun 20 19:08:46 2013
@@ -236,8 +236,39 @@ Parser::ParseSingleDeclarationAfterTempl
         << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
       DS.ClearStorageClassSpecs();
     }
+
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+      if (DeclaratorInfo.getName().getKind() != UnqualifiedId::IK_TemplateId) {
+        // If the declarator-id is not a template-id, issue a diagnostic and
+        // recover by ignoring the 'template' keyword.
+        Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0;
+      } else {
+        SourceLocation LAngleLoc
+          = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc);
+        Diag(DeclaratorInfo.getIdentifierLoc(), 
+             diag::err_explicit_instantiation_with_definition)
+          << SourceRange(TemplateInfo.TemplateLoc)
+          << FixItHint::CreateInsertion(LAngleLoc, "<>");
+
+        // Recover as if it were an explicit specialization. 
+        TemplateParameterLists ParamLists;
+        SmallVector<Decl*, 4> TemplateParams;
+        ParamLists.push_back(
+            TemplateParameterList::Create(Actions.getASTContext(), 
+                                          TemplateInfo.TemplateLoc,
+                                          LAngleLoc, 
+                                          (NamedDecl**)TemplateParams.data(),
+                                          TemplateParams.size(), LAngleLoc));
+
+        return ParseFunctionDefinition(DeclaratorInfo, 
+                                       ParsedTemplateInfo(&ParamLists,
+                                           /*isSpecialization=*/true,
+                                           /*LastParamListWasEmpty=*/true),
+                                       &LateParsedAttrs);
+      }
+    }
     return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo,
-                                   &LateParsedAttrs);
+				                           &LateParsedAttrs);
   }
 
   // Parse this declaration.

Added: cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp?rev=184503&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/no-body.cpp Thu Jun 20 19:08:46 2013
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+template<typename T> void f(T) { }
+template<typename T> void g(T) { }
+template<typename T> struct x { };
+template<typename T> struct y { };  // expected-note {{declared here}}
+
+namespace good {
+  template void f<int>(int);
+  template void g(int);
+  template struct x<int>;
+}
+
+namespace unsupported {
+ template struct y;     // expected-error {{elaborated type refers to a template}}
+}
+
+template<typename T> void f0(T) { }
+template<typename T> void g0(T) { }
+template<typename T> struct x0 { }; // expected-note {{explicitly specialized declaration is here}}
+template<typename T> struct y0 { };
+
+// Should recover as if definition
+namespace noargs_body {
+  template void g0(int) { } // expected-error {{function cannot be defined in an explicit instantiation; if this declaration is meant to be a function definition, remove the 'template' keyword}}
+  template struct y0 { };   // expected-error {{class cannot be defined in an explicit instantiation; if this declaration is meant to be a class definition, remove the 'template' keyword}}
+}
+
+// Explicit specializations expected in global scope
+namespace exp_spec {
+  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<typename T> void f1(T) { }
+template<typename T> struct x1 { };  // expected-note {{explicitly specialized declaration is here}}
+
+// Should recover as if specializations, 
+// thus also complain about not being in global scope.
+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}}
+}
+
+template<typename T> void f2(T) { }
+template<typename T> struct x2 { };
+
+// Should recover as if specializations
+template void f2<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}}
+template struct x2<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}}





More information about the cfe-commits mailing list