public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Jason Merrill <jason@redhat.com>
To: Michel Morin <mimomorin@gmail.com>
Cc: David Malcolm <dmalcolm@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: fix wrong fixit hints for misspelled typedef [PR77565]
Date: Mon, 20 Sep 2021 16:24:31 -0400	[thread overview]
Message-ID: <5ebab71b-b8a3-0420-df1a-362cce6893ff@redhat.com> (raw)
In-Reply-To: <CAO=jbbqc3SLr1eQKFyxnMPAxLMbHGvRLugiBN2Vrtch8jWJ=0A@mail.gmail.com>

On 9/17/21 13:31, Michel Morin wrote:
> On Fri, Sep 17, 2021 at 3:23 AM Jason Merrill <jason@redhat.com> wrote:
>>
>> On 9/16/21 11:50, Michel Morin wrote:
>>> On Thu, Sep 16, 2021 at 5:44 AM Jason Merrill <jason@redhat.com> wrote:
>>>>
>>>> On 9/14/21 04:29, Michel Morin via Gcc-patches wrote:
>>>>> On Tue, Sep 14, 2021 at 7:14 AM David Malcolm <dmalcolm@redhat.com> wrote:
>>>>>>
>>>>>> On Tue, 2021-09-14 at 03:35 +0900, Michel Morin via Gcc-patches wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> PR77565 reports that, with the code `typdef int Int;`, GCC emits
>>>>>>> "did you mean 'typeof'?" instead of "did you mean 'typedef'?".
>>>>>>>
>>>>>>> This happens because the typo corrector determines that `typeof` is a
>>>>>>> candidate for suggestion (through
>>>>>>> `cp_keyword_starts_decl_specifier_p`),
>>>>>>> but `typedef` is not.
>>>>>>>
>>>>>>> This patch fixes the issue by adding `typedef` as a candidate. The
>>>>>>> patch
>>>>>>> additionally adds the `inline` specifier and cv-specifiers as a
>>>>>>> candidate.
>>>>>>> Here is a patch (tests `make check-gcc` pass on darwin):
>>>>>>
>>>>>> Thanks for this patch (and for reporting the bug in the first place).
>>>>>>
>>>>>> I notice that, as well as being used for fix-it hints by
>>>>>> lookup_name_fuzzy (indirectly via suggest_rid_p),
>>>>>> cp_keyword_starts_decl_specifier_p is also used by
>>>>>> cp_lexer_next_token_is_decl_specifier_keyword, which is used by
>>>>>> cp_parser_lambda_declarator_opt and cp_parser_constructor_declarator_p.
>>>>>
>>>>> Ah, you're right! Thank you for pointing this out.
>>>>> I failed to grep those functions somehow.
>>>>>
>>>>> One thing that confuses me is that cp_keyword_starts_decl_specifier_p
>>>>> misses many keywords that can start decl-specifiers (e.g.
>>>>> typedef/inline/cv-qual and friend/explicit/virtual).
>>>>> So let's wait C++ frontend maintainers ;)
>>>>
>>>> That is strange.  Let's add all the rest of them as well.
>>>
>>> Done. Thanks for your help!
>>>
>>> One more thing — cp_keyword_starts_decl_specifier_p includes RID_ATTRIBUTE
>>> (from the beginning; see https://gcc.gnu.org/PR28261 ), but attributes are
>>> not decl-specifiers. Would it be reasonable to remove this?
>>
>> It looks like the place that PR28261 used
>> cp_lexer_next_token_is_decl_specifier_keyword specifically exempts
>> attributes:
>>
>>>            && (!cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
>>>                /* GNU attributes can actually appear both at the start of
>>>                   a parameter and parenthesized declarator.
>>>                   S (__attribute__((unused)) int);
>>>                   is a constructor, but
>>>                   S (__attribute__((unused)) foo) (int);
>>>                   is a function declaration.  */
>>>                || (cp_parser_allow_gnu_extensions_p (parser)
>>>                    && cp_next_tokens_can_be_gnu_attribute_p (parser)))
>>
>> So yes, let's remove RID_ATTRIBUTE and the || clause there.  I'd keep
>> the comment, but move it to go with the test for C++11 attributes below.
> 
> Done. No regressions introduced.
> 
>>> One more thing — cp_keyword_starts_decl_specifier_p includes RID_ATTRIBUTE
>>> (from the beginning; see https://gcc.gnu.org/PR28261 ), but attributes are
>>> not decl-specifiers.
> 
> Oh, this is wrong. I thought that, since C++11 attributes are not a
> decl-specifier, neither are GNU attributes. But the comment just before
> cp_parser_decl_specifier_seq says that GNU attributes are considered as a
> decl-specifier. So I'm not confident about the removal of RID_ATTRIBUTE in
> cp_keyword_starts_decl_specifier_p...

GNU attributes can appear in lots of places, and the only two callers of 
cp_parser_next_token_is_decl_specifier_keyword don't want to treat 
attributes accordingly.  Let's go with both your patches, and also 
remove the consequently-unnecessary attributes check in 
cp_parser_lambda_declarator_opt:

>   if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
>       && !cp_next_tokens_can_be_gnu_attribute_p (parser))

OK with that change.

> I've split the patch into two. The first one is for adding missing keywords to
> fix PR77565 and the second one is for removing the "attribute" keyword.
> Here is the second patch (if this is not applied, that's no problem ;) )
> 
> ======================================================
> c++: adjust the handling of RID_ATTRIBUTE.
> 
> gcc/cp/ChangeLog:
> 
> * parser.c (cp_keyword_starts_decl_specifier_p): Do not
> handle RID_ATTRIBUTE.
> (cp_parser_constructor_declarator_p): Remove now-redundant
> checks.
> 
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 40308d0d33f..d184a3aca7e 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -1062,7 +1062,6 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
>       case RID_TYPEDEF:
>       case RID_INLINE:
>         /* GNU extensions.  */
> -    case RID_ATTRIBUTE:
>       case RID_TYPEOF:
>         /* C++11 extensions.  */
>       case RID_DECLTYPE:
> @@ -30798,23 +30797,22 @@ cp_parser_constructor_declarator_p
> (cp_parser *parser, cp_parser_flags flags,
>      /* A parameter declaration begins with a decl-specifier,
>         which is either the "attribute" keyword, a storage class
>         specifier, or (usually) a type-specifier.  */
> -   && (!cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
> -       /* GNU attributes can actually appear both at the start of
> - a parameter and parenthesized declarator.
> - S (__attribute__((unused)) int);
> - is a constructor, but
> - S (__attribute__((unused)) foo) (int);
> - is a function declaration.  */
> -       || (cp_parser_allow_gnu_extensions_p (parser)
> -   && cp_next_tokens_can_be_gnu_attribute_p (parser)))
> -   /* A parameter declaration can also begin with [[attribute]].  */
> +   && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
> +   /* GNU attributes can actually appear both at the start of
> +      a parameter and parenthesized declarator.
> +      S (__attribute__((unused)) int);
> +      is a constructor, but
> +      S (__attribute__((unused)) foo) (int);
> +      is a function declaration. [[attribute]] can appear in the
> +      first form too, but not in the second form.  */
>      && !cp_next_tokens_can_be_std_attribute_p (parser))
>    {
>      tree type;
>      tree pushed_scope = NULL_TREE;
>      unsigned saved_num_template_parameter_lists;
> 
> -   if (cp_next_tokens_can_be_gnu_attribute_p (parser))
> +   if (cp_parser_allow_gnu_extensions_p (parser)
> +       && cp_next_tokens_can_be_gnu_attribute_p (parser))
>        {
>          unsigned int n = cp_parser_skip_gnu_attributes_opt (parser, 1);
>          while (--n)
> ======================================================
> 
> Regards,
> Michel
> 
> 
>>> Both patches (with and without removal of RID_ATTRIBUTE) attached.
>>> No regressions on x86_64-apple-darwin.
>>>
>>> Regards,
>>> Michel
>>>
>>>
>>>
>>>>>> So I'm not sure if this fix is exactly correct - hopefully one of the
>>>>>> C++ frontend maintainers can chime in.  If
>>>>>> cp_keyword_starts_decl_specifier_p isn't quite the right place for
>>>>>> this, the fix could probably go in suggest_rid_p instead, which *is*
>>>>>> specific to spelling corrections.
>>>>>>
>>>>>> Hope this is constructive; thanks again for the patch
>>>>>> Dave
>>>>>>
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> ============================================
>>>>>>> c++: add typo corrections for typedef/inline/cv-qual [PR77565]
>>>>>>>
>>>>>>> PR c++/77565
>>>>>>>
>>>>>>> gcc/cp/ChangeLog:
>>>>>>>
>>>>>>> * parser.c (cp_keyword_starts_decl_specifier_p): Handle
>>>>>>> typedef/inline specifiers and cv-qualifiers.
>>>>>>>
>>>>>>> gcc/testsuite/ChangeLog:
>>>>>>>
>>>>>>> * g++.dg/spellcheck-typenames.C: Add tests for decl-specs.
>>>>>>>
>>>>>>> --- a/gcc/cp/parser.c
>>>>>>> +++ b/gcc/cp/parser.c
>>>>>>> @@ -1051,6 +1051,12 @@ cp_keyword_starts_decl_specifier_p (enum rid
>>>>>>> keyword)
>>>>>>>         case RID_FLOAT:
>>>>>>>         case RID_DOUBLE:
>>>>>>>         case RID_VOID:
>>>>>>> +      /* CV qualifiers.  */
>>>>>>> +    case RID_CONST:
>>>>>>> +    case RID_VOLATILE:
>>>>>>> +      /* typedef/inline specifiers.  */
>>>>>>> +    case RID_TYPEDEF:
>>>>>>> +    case RID_INLINE:
>>>>>>>           /* GNU extensions.  */
>>>>>>>         case RID_ATTRIBUTE:
>>>>>>>         case RID_TYPEOF:
>>>>>>> --- a/gcc/testsuite/g++.dg/spellcheck-typenames.C
>>>>>>> +++ b/gcc/testsuite/g++.dg/spellcheck-typenames.C
>>>>>>> @@ -76,3 +76,38 @@ singed char ch; // { dg-error "1: 'singed' does
>>>>>>> not
>>>>>>> name a type; did you mean 's
>>>>>>>      ^~~~~~
>>>>>>>      signed
>>>>>>>        { dg-end-multiline-output "" } */
>>>>>>> +
>>>>>>> +typdef int my_int; // { dg-error "1: 'typdef' does not name a type;
>>>>>>> did you mean 'typedef'?" }
>>>>>>> +/* { dg-begin-multiline-output "" }
>>>>>>> + typdef int my_int;
>>>>>>> + ^~~~~~
>>>>>>> + typedef
>>>>>>> +   { dg-end-multiline-output "" } */
>>>>>>> +
>>>>>>> +inlien int inline_func(); // { dg-error "1: 'inlien' does not name a
>>>>>>> type; did you mean 'inline'?" }
>>>>>>> +/* { dg-begin-multiline-output "" }
>>>>>>> + inlien int inline_func();
>>>>>>> + ^~~~~~
>>>>>>> + inline
>>>>>>> +   { dg-end-multiline-output "" } */
>>>>>>> +
>>>>>>> +coonst int ci = 0; // { dg-error "1: 'coonst' does not name a type;
>>>>>>> did you mean 'const'?" }
>>>>>>> +/* { dg-begin-multiline-output "" }
>>>>>>> + coonst int ci = 0;
>>>>>>> + ^~~~~~
>>>>>>> + const
>>>>>>> +   { dg-end-multiline-output "" } */
>>>>>>> +
>>>>>>> +voltil int vi; // { dg-error "1: 'voltil' does not name a type; did
>>>>>>> you mean 'volatile'?" }
>>>>>>> +/* { dg-begin-multiline-output "" }
>>>>>>> + voltil int vi;
>>>>>>> + ^~~~~~
>>>>>>> + volatile
>>>>>>> +   { dg-end-multiline-output "" } */
>>>>>>> +
>>>>>>> +statik int si; // { dg-error "1: 'statik' does not name a type; did
>>>>>>> you mean 'static'?" }
>>>>>>> +/* { dg-begin-multiline-output "" }
>>>>>>> + statik int si;
>>>>>>> + ^~~~~~
>>>>>>> + static
>>>>>>> +   { dg-end-multiline-output "" } */
>>>>>>> ============================================
>>>>>>>
>>>>>>> --
>>>>>>> Regards,
>>>>>>> Michel
>>>>>>
>>>>>>
>>>>>
>>>>
>>


  reply	other threads:[~2021-09-20 20:24 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-09-13 18:35 Michel Morin
2021-09-13 22:14 ` David Malcolm
2021-09-14  8:29   ` Michel Morin
2021-09-15 20:43     ` Jason Merrill
2021-09-16 15:50       ` Michel Morin
2021-09-16 18:23         ` Jason Merrill
2021-09-17 17:31           ` Michel Morin
2021-09-20 20:24             ` Jason Merrill [this message]
2021-09-22  0:53               ` Michel Morin
2021-09-22 20:08                 ` Jason Merrill
2021-09-22 23:05                   ` Michel Morin
2021-09-23 20:29                     ` Jason Merrill
2021-09-24  0:49                       ` Michel Morin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5ebab71b-b8a3-0420-df1a-362cce6893ff@redhat.com \
    --to=jason@redhat.com \
    --cc=dmalcolm@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=mimomorin@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).