Hi, On Mon, May 25, 2020 at 12:26:33PM -0400, Jason Merrill wrote: > On 5/23/20 8:30 PM, Mark Wielaard wrote: > > When reporting an error in cp_parser and we notice a string literal > > followed by an unknown name check whether there is a known standard > > header containing a string macro with the same name, then add a hint > > to the error message to include that header. > > > > gcc/c-family/ChangeLog: > > > > * known-headers.cc (get_cp_stdlib_header_for_string_macro_name): > > New function. > > * known-headers.h (get_c_stdlib_header_for_string_macro_name): > > Missing 'p'. > > > New function definition. > > Declaration, not definition. > > The C++ changes are OK with these ChangeLog corrections.
Thanks. David, are you OK with the diagnostic changes? Who can we trick into reviewing the C frontend changes in the 1/2 patch that this depends on? Cheers, Mark > > gcc/cp/ChangeLog: > > > > * parser.c (cp_lexer_safe_previous_token): New function. > > (cp_parser_error_1): Add name_hint if the previous token is > > a string literal and next token is a CPP_NAME and we have a > > missing header suggestion for the name. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/spellcheck-inttypes.C: Add string-literal testcases. > > --- > > gcc/c-family/known-headers.cc | 8 +++++ > > gcc/c-family/known-headers.h | 1 + > > gcc/cp/parser.c | 36 ++++++++++++++++++++ > > gcc/testsuite/g++.dg/spellcheck-inttypes.C | 39 ++++++++++++++++++++++ > > 4 files changed, 84 insertions(+) > > > > diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc > > index c07cfd1db815..977230a586db 100644 > > --- a/gcc/c-family/known-headers.cc > > +++ b/gcc/c-family/known-headers.cc > > @@ -268,6 +268,14 @@ get_c_stdlib_header_for_string_macro_name (const char > > *name) > > return get_string_macro_hint (name, STDLIB_C); > > } > > +/* Given non-NULL NAME, return the header name defining a string macro > > + within the C++ standard library (with '<' and '>'), or NULL. */ > > +const char * > > +get_cp_stdlib_header_for_string_macro_name (const char *name) > > +{ > > + return get_string_macro_hint (name, STDLIB_CPLUSPLUS); > > +} > > + > > /* Implementation of class suggest_missing_header. */ > > /* suggest_missing_header's ctor. */ > > diff --git a/gcc/c-family/known-headers.h b/gcc/c-family/known-headers.h > > index a69bbbf28e76..f0c89dc9019d 100644 > > --- a/gcc/c-family/known-headers.h > > +++ b/gcc/c-family/known-headers.h > > @@ -24,6 +24,7 @@ extern const char *get_c_stdlib_header_for_name (const > > char *name); > > extern const char *get_cp_stdlib_header_for_name (const char *name); > > extern const char *get_c_stdlib_header_for_string_macro_name (const char > > *n); > > +extern const char *get_cp_stdlib_header_for_string_macro_name (const char > > *n); > > /* Subclass of deferred_diagnostic for suggesting to the user > > that they have missed a #include. */ > > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > > index 54ca875ce54c..95b8c635fc65 100644 > > --- a/gcc/cp/parser.c > > +++ b/gcc/cp/parser.c > > @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see > > #include "tree-iterator.h" > > #include "cp-name-hint.h" > > #include "memmodel.h" > > +#include "c-family/known-headers.h" > > > > /* The lexer. */ > > @@ -776,6 +777,20 @@ cp_lexer_previous_token (cp_lexer *lexer) > > return cp_lexer_token_at (lexer, tp); > > } > > +/* Same as above, but return NULL when the lexer doesn't own the token > > + buffer or if the next_token is at the start of the token > > + vector. */ > > + > > +static cp_token * > > +cp_lexer_safe_previous_token (cp_lexer *lexer) > > +{ > > + if (lexer->buffer) > > + if (lexer->next_token != lexer->buffer->address ()) > > + return cp_lexer_previous_token (lexer); > > + > > + return NULL; > > +} > > + > > /* Overload for make_location, taking the lexer to mean the location of > > the > > previous token. */ > > @@ -2919,6 +2934,7 @@ cp_parser_error_1 (cp_parser* parser, const char* > > gmsgid, > > } > > } > > + auto_diagnostic_group d; > > gcc_rich_location richloc (input_location); > > bool added_matching_location = false; > > @@ -2941,6 +2957,26 @@ cp_parser_error_1 (cp_parser* parser, const char* > > gmsgid, > > = richloc.add_location_if_nearby (matching_location); > > } > > + /* If we were parsing a string-literal and there is an unknown name > > + token right after, then check to see if that could also have been > > + a literal string by checking the name against a list of known > > + standard string literal constants defined in header files. If > > + there is one, then add that as an hint to the error message. */ > > + name_hint h; > > + cp_token *prev_token = cp_lexer_safe_previous_token (parser->lexer); > > + if (prev_token && cp_parser_is_string_literal (prev_token) > > + && token->type == CPP_NAME) > > + { > > + tree name = token->u.value; > > + const char *token_name = IDENTIFIER_POINTER (name); > > + const char *header_hint > > + = get_cp_stdlib_header_for_string_macro_name (token_name); > > + if (header_hint != NULL) > > + h = name_hint (NULL, new suggest_missing_header (token->location, > > + token_name, > > + header_hint)); > > + } > > + > > /* Actually emit the error. */ > > c_parse_error (gmsgid, > > /* Because c_parser_error does not understand > > diff --git a/gcc/testsuite/g++.dg/spellcheck-inttypes.C > > b/gcc/testsuite/g++.dg/spellcheck-inttypes.C > > index c5861127ca6d..84bfc125513c 100644 > > --- a/gcc/testsuite/g++.dg/spellcheck-inttypes.C > > +++ b/gcc/testsuite/g++.dg/spellcheck-inttypes.C > > @@ -23,6 +23,18 @@ const char *hex64_fmt = PRIx64; /* { dg-error "'PRIx64' > > was not declared" "undec > > const char *hexptr_fmt = PRIxPTR; /* { dg-error "'PRIxPTR' was not > > declared" "undeclared identifier" { target *-*-* } } */ > > /* { dg-message "'PRIxPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +/* As a part of a string-literal. */ > > +const char *dec8msg_fmt = "Provide %" PRId8 "\n"; /* { dg-error "expected" > > "expected string-literal" { target *-*-* } } */ > > +/* { dg-message "'PRId8' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +const char *dec16msg_fmt = "Provide %" PRId16 "\n"; /* { dg-error > > "expected" "expected string-literal" { target *-*-* } } */ > > +/* { dg-message "'PRId16' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +const char *dec32msg_fmt = "Provide %" PRId32 "\n"; /* { dg-error > > "expected" "expected string-literal" { target *-*-* } } */ > > +/* { dg-message "'PRId32' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +const char *dec64msg_fmt = "Provide %" PRId64 "\n"; /* { dg-error > > "expected" "expected string-literal" { target *-*-* } } */ > > +/* { dg-message "'PRId64' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +const char *decptrmsg_fmt = "Provide %" PRIdPTR "\n"; /* { dg-error > > "expected" "expected string-literal" { target *-*-* } } */ > > +/* { dg-message "'PRIdPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + > > void test_printf (void) > > { > > printf ("some format strings %s, %s, %s, %s, %s, %s\n", > > @@ -38,4 +50,31 @@ void test_printf (void) > > /* { dg-message "'PRIx32' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > PRIoPTR); /* { dg-error "'PRIoPTR' was not declared" "undeclared > > identifier" { target *-*-* } } */ > > /* { dg-message "'PRIoPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + > > + printf ("%" PRIo8 "\n", i8); /* { dg-error "expected" } */ > > +/* { dg-message "'PRIo8' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + printf ("%" PRIo16 "\n", i16); /* { dg-error "expected" } */ > > +/* { dg-message "'PRIo16' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + printf ("%" PRIo32 "\n", i32); /* { dg-error "expected" } */ > > +/* { dg-message "'PRIo32' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + printf ("%" PRIo64 "\n", i64); /* { dg-error "expected" } */ > > +/* { dg-message "'PRIo64' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + printf ("%" PRIoPTR "\n", ip); /* { dg-error "expected" } */ > > +/* { dg-message "'PRIoPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > +} > > + > > +void test_scanf (void) > > +{ > > + scanf ("%" SCNu8 "\n", &i8); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNu8' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + scanf ("%" SCNu16 "\n", &i16); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNu16' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + scanf ("%" SCNu32 "\n", &i32); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNu32' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + scanf ("%" SCNu64 "\n", &i64); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNu64' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + scanf ("%" SCNuPTR "\n", &ip); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNuPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > + scanf ("%" SCNxPTR "\n", &up); /* { dg-error "expected" } */ > > +/* { dg-message "'SCNxPTR' is defined in header '<cinttypes>'; did you > > forget to '#include <cinttypes>'?" "replacement note" { target *-*-* } .-1 > > } */ > > } > > >