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