From 7c64ef05e179d29646030e9d453081844ecc537a Mon Sep 17 00:00:00 2001 From: Larisse Voufo Date: Fri, 21 Jun 2013 00:08:46 +0000 Subject: [PATCH] Bug Fix: Template explicit instantiations should not have definitions (FixIts yet to be tested.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184503 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 3 ++ lib/Parse/ParseDecl.cpp | 1 + lib/Parse/ParseDeclCXX.cpp | 8 ++++ lib/Parse/ParseTemplate.cpp | 33 ++++++++++++- test/CXX/temp/temp.spec/no-body.cpp | 52 +++++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 test/CXX/temp/temp.spec/no-body.cpp diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 4ffb34ba0f..d9370d4b9a 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index b3e8412dcf..451bf95721 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f09aaf5c0b..68d8e6ba4d 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/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/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index f55fcc0740..e8e7efd19d 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/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 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/test/CXX/temp/temp.spec/no-body.cpp b/test/CXX/temp/temp.spec/no-body.cpp new file mode 100644 index 0000000000..c2434a8c94 --- /dev/null +++ b/test/CXX/temp/temp.spec/no-body.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template void f(T) { } +template void g(T) { } +template struct x { }; +template struct y { }; // expected-note {{declared here}} + +namespace good { + template void f(int); + template void g(int); + template struct x; +} + +namespace unsupported { + template struct y; // expected-error {{elaborated type refers to a template}} +} + +template void f0(T) { } +template void g0(T) { } +template struct x0 { }; // expected-note {{explicitly specialized declaration is here}} +template 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) { } // expected-error {{no function template matches function template specialization 'f0'}} + template<> struct x0 { }; // expected-error {{class template specialization of 'x0' must originally be declared in the global scope}} +} + +template void f1(T) { } +template 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) { } // 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 { }; // 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 void f2(T) { } +template struct x2 { }; + +// Should recover as if specializations +template void f2(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 { }; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} -- 2.40.0