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 
> > } */
> >   }
> > 
> 

Reply via email to