diff options
| author | Larisse Voufo <lvoufo@google.com> | 2013-06-21 00:08:46 +0000 |
|---|---|---|
| committer | Larisse Voufo <lvoufo@google.com> | 2013-06-21 00:08:46 +0000 |
| commit | 725de3e14ff288a92bed36241cdc2c22be55ee0e (patch) | |
| tree | 75a18311dbe16010eaf81c924f5d03f4f292fe09 | |
| parent | 2c75f11e86ee8bff73a935b7542712f5255f4535 (diff) | |
| download | bcm5719-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.td | 3 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 33 | ||||
| -rw-r--r-- | clang/test/CXX/temp/temp.spec/no-body.cpp | 52 |
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}} |

