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

Richard Smith richard at metafoo.co.uk
Fri Jun 21 13:33:36 PDT 2013


On Thu, Jun 20, 2013 at 5:08 PM, Larisse Voufo <lvoufo at google.com> wrote:
> 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 {

The previous case in the if/else if chain seems to do the wrong thing
in the presence of explicit instantiations too. This code triggers an
assert (with or without your patch):

  template<typename T> struct A {};
  struct B { template friend struct A<int> {}; };

If you're not interested in fixing that, let me know and I'll file a bug.

>      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;

Please add

  TemplateInfo = ParsedTemplateInfo();

so that the downstream code sees a consistent state (this doesn't make
any difference right now but should be more robust against future
changes).

> +      } 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));

You can use "0, 0," instead of TemplateParams.data() and
TemplateParams.size() here, and remove the TemplateParams variable.

Also, please use Actions.ActOnTemplateParameterList, rather than
creating the template parameter list directly. We generally avoid
directly manipulating the AST from the Parser.

> +
> +        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}}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits



More information about the cfe-commits mailing list