[PATCH] Don't parse non-template name as template name

Richard Smith metafoo at gmail.com
Thu Jan 30 15:22:45 PST 2014


On Thu Jan 30 2014 at 2:38:44 PM, Ismail Pazarbasi <
ismail.pazarbasi at gmail.com> wrote:

> Hi rsmith,
>
> PR18127: misparse of 'new struct S < ...' where S is not a template-name
>
> If clang sees '<' token after an elaborated-type-specifier, it assumes
> elaborated-type-specifier refers to a template name, and then issues
> diagnostics concerning missing '>'.
>
> We try to find corresponding '>' for diagnostics location purpose, and
> perform name lookup. Parser knows that it is not parsing a template. If
> name lookup doesn't find a name, we will keep issuing `explicit
> instantiation/specialization of non-template class` error.
>
> http://llvm-reviews.chandlerc.com/D2662
>
> Files:
>   lib/Parse/ParseDeclCXX.cpp
>   test/Parser/cxx-template-argument.cpp
>
> Index: lib/Parse/ParseDeclCXX.cpp
> ===================================================================
> --- lib/Parse/ParseDeclCXX.cpp
> +++ lib/Parse/ParseDeclCXX.cpp
> @@ -24,6 +24,8 @@
>  #include "clang/Sema/Scope.h"
>  #include "clang/Sema/SemaDiagnostic.h"
>  #include "llvm/ADT/SmallString.h"
> +#include "clang/Sema/Lookup.h"
> +
>  using namespace clang;
>
>  /// ParseNamespace - We know that the current token is a namespace
> keyword. This
> @@ -1230,38 +1232,39 @@
>        // a class (or template thereof).
>        TemplateArgList TemplateArgs;
>        SourceLocation LAngleLoc, RAngleLoc;
> -      if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS,
> -                                           true, LAngleLoc,
> -                                           TemplateArgs, RAngleLoc)) {
> -        // We couldn't parse the template argument list at all, so don't
> -        // try to give any location information for the list.
> -        LAngleLoc = RAngleLoc = SourceLocation();
> -      }
> -
> -      Diag(NameLoc, diag::err_explicit_spec_non_template)
> -          << (TemplateInfo.Kind == ParsedTemplateInfo::
> ExplicitInstantiation)
> -          << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
> +      LAngleLoc = ConsumeToken();
> +      if (SkipUntil(tok::greater, StopBeforeMatch | StopAtSemi))
> +        RAngleLoc = ConsumeToken();
> +      // If a name was not found, this might be an explicit instantiation
> or
> +      // specialization attempt. If a name was found, that name does not
> refer
> +      // to a template name.
> +      LookupResult Result(Actions, Name, NameLoc, Sema::LookupTagName);
> +      Actions.LookupName(Result, getCurScope());
>

This is using too low-level an interface from the Parser into Sema. Also,
I'm not convinced this'll do the right thing if it finds an
injected-class-name for a class template.

Can you use Sema::isTemplateName here?


> +      if (Result.getResultKind() != LookupResult::Found)
> +        Diag(NameLoc, diag::err_explicit_spec_non_template)
>

This is the wrong diagnostic in many cases (including the "new X < blah"
case). This is fine if you have TemplateInfo telling you that we had
template-parameter-lists, but otherwise, you should stop parsing before the
'<'. In particular:

  bool k = new struct IDontExist < 0;

... should only diagnose allocation of an incomplete type, and

  struct A {
    template<typename T> operator T();
  };
  bool b = sizeof &A::operator struct Foo < 8;

... should be accepted without any diagnostics.

+            << (TemplateInfo.Kind == ParsedTemplateInfo::
> ExplicitInstantiation)
> +            << TagTokKind << Name << SourceRange(LAngleLoc, RAngleLoc);
>
>        // Strip off the last template parameter list if it was empty, since
>        // we've removed its template argument list.
>        if (TemplateParams && TemplateInfo.LastParameterListWasEmpty) {
>          if (TemplateParams && TemplateParams->size() > 1) {
>            TemplateParams->pop_back();
>          } else {
>            TemplateParams = 0;
> -          const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
> -            = ParsedTemplateInfo::NonTemplate;
> +          const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
> +              ParsedTemplateInfo::NonTemplate;
>          }
> -      } else if (TemplateInfo.Kind
> -                                == ParsedTemplateInfo::ExplicitInstantiation)
> {
> +      } else if (TemplateInfo.Kind ==
> +                 ParsedTemplateInfo::ExplicitInstantiation) {
>          // Pretend this is just a forward declaration.
>          TemplateParams = 0;
> -        const_cast<ParsedTemplateInfo&>(TemplateInfo).Kind
> -          = ParsedTemplateInfo::NonTemplate;
> -        const_cast<ParsedTemplateInfo&>(TemplateInfo).TemplateLoc
> -          = SourceLocation();
> -        const_cast<ParsedTemplateInfo&>(TemplateInfo).ExternLoc
> -          = SourceLocation();
> +        const_cast<ParsedTemplateInfo &>(TemplateInfo).Kind =
> +            ParsedTemplateInfo::NonTemplate;
> +        const_cast<ParsedTemplateInfo &>(TemplateInfo).TemplateLoc =
> +            SourceLocation();
> +        const_cast<ParsedTemplateInfo &>(TemplateInfo).ExternLoc =
> +            SourceLocation();
>        }
>      }
>    } else if (Tok.is(tok::annot_template_id)) {
> Index: test/Parser/cxx-template-argument.cpp
> ===================================================================
> --- test/Parser/cxx-template-argument.cpp
> +++ test/Parser/cxx-template-argument.cpp
> @@ -106,3 +106,21 @@
>    { };
>
>  }
> +
> +namespace PR18127 {
> +    struct A {} *a;
> +    bool f = new struct A < 0;
> +    bool g = new struct A < a;
> +
> +    template<typename T>
> +    struct B { };
> +
> +    bool h = new struct B < 0;  // expected-error{{expected '>'}}
> +    bool i = new struct B<int> < 0;
> +    bool operator<(const struct O &, const struct O &);
> +    struct O { } *p;
> +    bool j = *(new struct O) < *p;
> +    bool k = new struct IDontExist < 0;  // expected-error{{explicit
> specialization of non-template struct 'IDontExist'}}
> +    // expected-error at -1{{allocation of incomplete type 'struct
> IDontExist'}}
> +    // expected-note at -2{{forward declaration of 'PR18127::IDontExist'}}
> +}
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140130/1042884f/attachment.html>


More information about the cfe-commits mailing list