summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarisse Voufo <lvoufo@google.com>2013-06-21 00:08:46 +0000
committerLarisse Voufo <lvoufo@google.com>2013-06-21 00:08:46 +0000
commit725de3e14ff288a92bed36241cdc2c22be55ee0e (patch)
tree75a18311dbe16010eaf81c924f5d03f4f292fe09
parent2c75f11e86ee8bff73a935b7542712f5255f4535 (diff)
downloadbcm5719-llvm-725de3e14ff288a92bed36241cdc2c22be55ee0e.tar.gz
bcm5719-llvm-725de3e14ff288a92bed36241cdc2c22be55ee0e.zip
Bug Fix: Template explicit instantiations should not have definitions (FixIts yet to be tested.)
llvm-svn: 184503
-rw-r--r--clang/include/clang/Basic/DiagnosticParseKinds.td3
-rw-r--r--clang/lib/Parse/ParseDecl.cpp1
-rw-r--r--clang/lib/Parse/ParseDeclCXX.cpp8
-rw-r--r--clang/lib/Parse/ParseTemplate.cpp33
-rw-r--r--clang/test/CXX/temp/temp.spec/no-body.cpp52
5 files changed, 96 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 4ffb34ba0f5..d9370d4b9a3 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -592,6 +592,9 @@ def err_explicit_instantiation_with_definition : Error<
"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">;
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index b3e8412dcf2..451bf957219 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -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"
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index f09aaf5c0bb..68d8e6ba4d0 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1539,6 +1539,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} 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;
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index f55fcc07404..e8e7efd19d6 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -236,8 +236,39 @@ Parser::ParseSingleDeclarationAfterTemplate(
<< 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.
diff --git a/clang/test/CXX/temp/temp.spec/no-body.cpp b/clang/test/CXX/temp/temp.spec/no-body.cpp
new file mode 100644
index 00000000000..c2434a8c948
--- /dev/null
+++ b/clang/test/CXX/temp/temp.spec/no-body.cpp
@@ -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}}
OpenPOWER on IntegriCloud