On Tue, Sep 21, 2021 at 5:24 AM Jason Merrill <ja...@redhat.com> wrote:
>
> On 9/17/21 13:31, Michel Morin wrote:
> > On Fri, Sep 17, 2021 at 3:23 AM Jason Merrill <ja...@redhat.com> wrote:
> >>
> >> On 9/16/21 11:50, Michel Morin wrote:
> >>> On Thu, Sep 16, 2021 at 5:44 AM Jason Merrill <ja...@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 <dmalc...@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.

Makes sense.

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

Updated and rebased the patch. No regressions on x86_64-apple-darwin.

Thank you for your help!


>
> > 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
> >>>>>>
> >>>>>>
> >>>>>
> >>>>
> >>
>
From 1edc3b6afe58b7ac5f88c586490b79bad793aafa Mon Sep 17 00:00:00 2001
From: morinmorin <mimomo...@gmail.com>
Date: Thu, 16 Sep 2021 23:29:54 +0900
Subject: [PATCH 1/2] c++: add spellcheck suggestions for typedef etc.
 [PR77565]

cp_keyword_starts_decl_specifier_p misses many keywords that can
start decl-specifiers. This patch adds support for those keywords.

        PR c++/77565

gcc/cp/ChangeLog:

        * parser.c (cp_keyword_starts_decl_specifier_p): Handle more
        decl-specifiers (typedef/inline/cv/explicit/virtual/friend).

gcc/testsuite/ChangeLog:

        * g++.dg/spellcheck-pr77565.C: New test.
---
 gcc/cp/parser.c                           | 10 ++++++++++
 gcc/testsuite/g++.dg/spellcheck-pr77565.C | 12 ++++++++++++
 2 files changed, 22 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/spellcheck-pr77565.C

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 62908daa5b7..40569fc410a 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1051,6 +1051,16 @@ 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:
+      /* Function specifiers.  */
+    case RID_EXPLICIT:
+    case RID_VIRTUAL:
+      /* friend/typdef/inline specifiers.  */
+    case RID_FRIEND:
+    case RID_TYPEDEF:
+    case RID_INLINE:
       /* GNU extensions.  */
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
diff --git a/gcc/testsuite/g++.dg/spellcheck-pr77565.C 
b/gcc/testsuite/g++.dg/spellcheck-pr77565.C
new file mode 100644
index 00000000000..2257f7b699d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/spellcheck-pr77565.C
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+
+typdef int my_int; // { dg-error "1: 'typdef' does not name a type; did you 
mean 'typedef'\\?" }
+inlien int i_fn(); // { dg-error "1: 'inlien' does not name a type; did you 
mean 'inline'\\?" }
+coonst int ci = 1; // { dg-error "1: 'coonst' does not name a type; did you 
mean 'const'\\?" }
+voltil int vi = 2; // { dg-error "1: 'voltil' does not name a type; did you 
mean 'volatile'\\?" }
+
+class my_class {
+  explict my_class(int); // { dg-error "3: 'explict' does not name a type; did 
you mean 'explicit'\\?" }
+  friends double f_fn(); // { dg-error "3: 'friends' does not name a type; did 
you mean 'friend'\\?" }
+  virtial double v_fn(); // { dg-error "3: 'virtial' does not name a type; did 
you mean 'virtual'\\?" }
+};
-- 
2.31.1

From ad640e12ab78c582f3e83ae2f38b830308542030 Mon Sep 17 00:00:00 2001
From: morinmorin <mimomo...@gmail.com>
Date: Wed, 22 Sep 2021 08:04:31 +0900
Subject: [PATCH 2/2] 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.
        (cp_parser_lambda_declarator_opt): Likewise.
---
 gcc/cp/parser.c | 25 +++++++++++--------------
 1 file changed, 11 insertions(+), 14 deletions(-)

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 40569fc410a..f5ec7688213 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:
@@ -11466,8 +11465,7 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, 
tree lambda_expr)
   /* In the decl-specifier-seq of the lambda-declarator, each
      decl-specifier shall either be mutable or constexpr.  */
   int declares_class_or_enum;
-  if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer)
-      && !cp_next_tokens_can_be_gnu_attribute_p (parser))
+  if (cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer))
     cp_parser_decl_specifier_seq (parser,
                                  CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
                                  &lambda_specs, &declares_class_or_enum);
@@ -30835,23 +30833,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)
-- 
2.31.1

Reply via email to