Provide diagnostic hints for missing C++ cinttypes string constants.
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_cp_stdlib_header_for_string_macro_name): New function declaration. 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.
This commit is contained in:
parent
9eea5d2ddf
commit
1dc83b4606
|
@ -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. */
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 } */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue