Bug 104319 - better error message for parsing error when >= or >> ends a template variable.
Summary: better error message for parsing error when >= or >> ends a template variable.
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 12.0
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2022-02-01 00:47 UTC by qingzhe huang
Modified: 2022-04-29 11:52 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2022-02-01 00:00:00


Attachments
gcc12-pr104319.patch (1.25 KB, patch)
2022-02-03 10:41 UTC, Jakub Jelinek
Details | Diff
gcc12-pr104319.patch (1.39 KB, patch)
2022-02-03 11:13 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description qingzhe huang 2022-02-01 00:47:56 UTC
consider following code (https://www.godbolt.org/z/4drb17Pqn):

template<typename T>
struct A{ 
    constexpr static int value=0;
};

template<typename T>
constexpr int Zero=A<T>::value;
static_assert(Zero<int>==0);

<source>:8:15: error: parse error in template argument list
    8 | static_assert(Zero<int>==0);
      |               ^~~~~~~~~~~~
<source>:8:15: error: template argument 1 is invalid
Compiler returned: 1


clang gives much clear reason: 
error: a space is required between a right angle bracket and an equals sign (use '> =')
static_assert(Zero<int>==0);
                      ^~
                      > =

clearly "Zero<int>" can be considered template id to avoid template argument list error message.
Comment 1 Andrew Pinski 2022-02-01 00:52:45 UTC
Confirmed here is a simplified reduced testcase:
template<typename T> int Zero;
void f(void)
{
  Zero<int>=0;
}

--- CUT ----
GCC currently produces:
<source>: In function 'void f()':
<source>:4:3: error: parse error in template argument list
    4 |   Zero<int>=0;
      |   ^~~~~~~~~~~

Clang gives:
<source>:4:11: error: a space is required between a right angle bracket and an equals sign (use '> =')
  Zero<int>=0;
          ^~
          > =

While MSVC gives:
<source>(4): error C2947: expecting '>' to terminate template-argument-list, found '>='

ICC gives:
<source>(4): error: expected a ">"
    Zero<int>=0;
            ^


All three are better than GCC's really.
Comment 2 qingzhe huang 2022-02-02 21:30:41 UTC
A slightly different case with operator ">=" after template-id causing identical error message is: https://www.godbolt.org/z/7ajvfM4rb

#include <utility>

template<typename T>
constexpr std::size_t zero=0;

template<typename T>
constexpr bool Bool=zero<T>>=0;

<source>:7:21: error: parse error in template argument list
    7 | constexpr bool Bool=zero<T>>=0;
      |                     ^~~~~~~~~~
Compiler returned: 1
Comment 3 Andrew Pinski 2022-02-02 21:36:57 UTC
(In reply to qingzhe huang from comment #2)
> A slightly different case with operator ">=" after template-id causing
> identical error message is: https://www.godbolt.org/z/7ajvfM4rb
> 
> #include <utility>
> 
> template<typename T>
> constexpr std::size_t zero=0;
> 
> template<typename T>
> constexpr bool Bool=zero<T>>=0;

Right in this case >> is the token. these cases just need to be special cased really in the parser itself which is what clang does.
Comment 4 Jakub Jelinek 2022-02-02 21:48:14 UTC
No, whole >>= is one token (CPP_RSHIFT_EQ).
>=, >>= and >> are the only tokens that start with > character, and I think we only handle >> specially (e.g. because in C++11 it is valid to have a<b<c>>
instead of a<b<c> > ).
Comment 5 Andrew Pinski 2022-02-02 21:56:05 UTC
(In reply to Jakub Jelinek from comment #4)
> No, whole >>= is one token (CPP_RSHIFT_EQ).

Oh you are correct, I misread/misremembered the tokens.
Comment 6 qingzhe huang 2022-02-03 01:45:09 UTC
But clang can give similar clear message by pointing out the space.
Just like ">>" instead "> >" after c++98, I think GCC can do better to recognize ">>=" is possible of "> >=". Just considering even though ">>" is one token, still parser now consider the case of ">" and ">" as to two closing brackets for two nested templates. 
My point is that even though ">>=" is one token, it doesn't prevent parser from splitting the token into possible two tokens. Not always the longest match algorithms in tokenization.

My suggestion is that how about we calculate all possible superset of all other operators. For example, ">>=" is equivalent to ">" and ">=". Or ">>" and "=".
there are tokens who is using longest match to return only the longest ones. It is just my naive thought.
Comment 7 Jakub Jelinek 2022-02-03 10:41:04 UTC
Created attachment 52337 [details]
gcc12-pr104319.patch

Untested fix.
That said, now that I think about it, >>= doesn't need to be misspelling of
> >=, but can be also misspelling of >> = e.g. with nested template argument.
Comment 8 Jakub Jelinek 2022-02-03 11:13:40 UTC
Created attachment 52338 [details]
gcc12-pr104319.patch

Improved patch.  The error recovery doesn't work well for some reason though as can be seen on the spurious extra errors, unfortunately no idea why is that because the ugly hack of overwriting token->type clearly works at least for the supported C++11 and later case of z<A<int>> = 0;
But at least the first errors are now clearer.
Comment 9 Jakub Jelinek 2022-02-03 15:40:25 UTC
Though, the cp_parser_next_token_ends_template_argument_p change can't be right.
E.g.
struct <int N> A{};
A<1>=2> a;
is not A<1> =2> a;
I bet we can't treat at least >= as terminating template argument, perhaps we could go back to it if tentative parsing with >= didn't work out.
In any case, not a GCC 12 material as not a regression.
Comment 10 qingzhe huang 2022-02-03 20:01:42 UTC
Here I have another test case. It involves an anonymous template argument which confuses me for a lot at the time which clang is doing a great job to clarify the reason for me.

https://www.godbolt.org/z/YGfMncGeW

template <typename T=int, 
    std::enable_if_t<std::is_integral<T>::value, 
    bool>=true   //there should be a space in ">="
    >  
struct TestStruct{};
Comment 11 Jakub Jelinek 2022-02-08 14:01:22 UTC
Patch has been posted: https://gcc.gnu.org/pipermail/gcc-patches/2022-February/589875.html
and deferred for gcc 13.
Comment 12 GCC Commits 2022-04-29 11:51:47 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:a282da2243103d79262ca04f5e3a3cc7b9b06935

commit r13-40-ga282da2243103d79262ca04f5e3a3cc7b9b06935
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Fri Apr 29 13:50:10 2022 +0200

    c++: Improve diagnostics for template args terminated with >= or >>= [PR104319]
    
    As mentioned in the PR, for C++98 we have diagnostics that expect
    >> terminating template arguments to be a mistake for > > (C++11
    said it has to be treated that way), while if user trying to spare the
    spacebar doesn't separate > from following = or >> from following =,
    the diagnostics is confusing, while clang suggests adding space in between.
    
    The following patch does that for >= and >>= too.
    
    For some strange reason the error recovery emits further errors,
    not really sure what's going on because I overwrite the token->type
    like the code does for the C++11 >> case or for the C++98 >> cases,
    but at least the first error is nicer (well, for the C++98 nested
    template case and >>= I need to overwrite it to > and so the = is lost,
    so perhaps some follow-up errors are needed for that case).
    
    2022-04-29  Jakub Jelinek  <jakub@redhat.com>
    
            PR c++/104319
            * parser.cc (cp_parser_template_argument): Treat >= like C++98 >>
            after a type id by setting maybe_type_id and aborting tentative
            parse.
            (cp_parser_enclosed_template_argument_list): Handle
            CPP_GREATER_EQ like misspelled CPP_GREATER CPP_RQ and
            CPP_RSHIFT_EQ like misspelled CPP_GREATER CPP_GREATER_EQ
            or CPP_RSHIFT CPP_EQ or CPP_GREATER CPP_GREATER CPP_EQ.
            (cp_parser_next_token_ends_template_argument_p): Return true
            also for CPP_GREATER_EQ and CPP_RSHIFT_EQ.
    
            * g++.dg/parse/template28.C: Adjust expected diagnostics.
            * g++.dg/parse/template30.C: New test.
Comment 13 Jakub Jelinek 2022-04-29 11:52:48 UTC
Fixed for GCC 13.