I'd like to ping the following patches: [PATCH 1/3] c-family: add name_hint/deferred_diagnostic https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00439.html
[PATCH 2/3] C++: provide macro used-before-defined hint (PR c++/72786). https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00437.html [PATCH 3/3] C: hints for missing stdlib includes for macros and types https://gcc.gnu.org/ml/gcc-patches/2017-05/msg00438.html On Fri, 2017-05-05 at 13:51 -0400, David Malcolm wrote: > In various places we use lookup_name_fuzzy to provide a hint, > and can report messages of the form: > error: unknown foo named 'bar' > or: > error: unknown foo named 'bar'; did you mean 'SUGGESTION? > > This patch provides a way for lookup_name_fuzzy to provide > both the suggestion above, and (optionally) additional hints > that can be printed e.g. > > note: did you forget to include <SOME_HEADER.h>? > > This patch provides the mechanism and ports existing users > of lookup_name_fuzzy to the new return type. > There are no uses of such hints in this patch, but followup > patches provide various front-end specific uses of this. > > gcc/c-family/ChangeLog: > * c-common.h (class deferred_diagnostic): New class. > (class name_hint): New class. > (lookup_name_fuzzy): Convert return type from const char * > to name_hint. Add location_t param. > > gcc/c/ChangeLog: > * c-decl.c (implicit_decl_warning): Convert "hint" from > const char * to name_hint. Pass location to > lookup_name_fuzzy. Suppress any deferred diagnostic if the > warning was not printed. > (undeclared_variable): Likewise for "guessed_id". > (lookup_name_fuzzy): Convert return type from const char * > to name_hint. Add location_t param. > * c-parser.c (c_parser_declaration_or_fndef): Convert "hint" > from > const char * to name_hint. Pass location to lookup_name_fuzzy. > (c_parser_parameter_declaration): Pass location to > lookup_name_fuzzy. > > gcc/cp/ChangeLog: > * name-lookup.c (suggest_alternatives_for): Convert > "fuzzy_name" from > const char * to name_hint, and rename to "hint". Pass location > to > lookup_name_fuzzy. > (lookup_name_fuzzy): Convert return type from const char * > to name_hint. Add location_t param. > * parser.c (cp_parser_diagnose_invalid_type_name): Convert > "suggestion" from const char * to name_hint, and rename to > "hint". > Pass location to lookup_name_fuzzy. > --- > gcc/c-family/c-common.h | 121 > +++++++++++++++++++++++++++++++++++++++++++++++- > gcc/c/c-decl.c | 35 +++++++------- > gcc/c/c-parser.c | 16 ++++--- > gcc/cp/name-lookup.c | 17 +++---- > gcc/cp/parser.c | 12 ++--- > 5 files changed, 163 insertions(+), 38 deletions(-) > > diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h > index 138a0a6..83c1a68 100644 > --- a/gcc/c-family/c-common.h > +++ b/gcc/c-family/c-common.h > @@ -1009,7 +1009,126 @@ enum lookup_name_fuzzy_kind { > /* Any name. */ > FUZZY_LOOKUP_NAME > }; > -extern const char *lookup_name_fuzzy (tree, enum > lookup_name_fuzzy_kind); > + > +/* A deferred_diagnostic is a wrapper around optional extra > diagnostics > + that we may want to bundle into a name_hint. > + > + The emit method is called when no name_hint instances reference > + the deferred_diagnostic. In the simple case this is when the > name_hint > + goes out of scope, but a reference-counting scheme is used to > allow > + name_hint instances to be copied. */ > + > +class deferred_diagnostic > +{ > + public: > + virtual ~deferred_diagnostic () {} > + virtual void emit () = 0; > + > + void incref () { m_refcnt++; } > + void decref () > + { > + if (--m_refcnt == 0) > + { > + if (!m_suppress) > + emit (); > + delete this; > + } > + } > + > + location_t get_location () const { return m_loc; } > + > + /* Call this if the corresponding warning was not emitted, > + in which case we should also not emit the deferred_diagnostic. > */ > + void suppress () > + { > + m_suppress = true; > + } > + > + protected: > + deferred_diagnostic (location_t loc) > + : m_refcnt (0), m_loc (loc), m_suppress (false) {} > + > + private: > + int m_refcnt; > + location_t m_loc; > + bool m_suppress; > +}; > + > +/* A name_hint is an optional string suggestion, along with an > + optional deferred_diagnostic. > + For example: > + > + error: unknown foo named 'bar' > + > + if the SUGGESTION is "baz", then one might print: > + > + error: unknown foo named 'bar'; did you mean 'baz'? > + > + and the deferred_diagnostic allows for additional (optional) > + diagnostics e.g.: > + > + note: did you check behind the couch? > + > + The deferred_diagnostic is emitted when no name_hint instances > reference > + the deferred_diagnostic. In the simple case this is when the > name_hint > + goes out of scope, but a reference-counting scheme is used to > allow > + name_hint instances to be copied. */ > + > +class name_hint > +{ > +public: > + name_hint () : m_suggestion (NULL), m_deferred (NULL) {} > + > + name_hint (const char *suggestion, deferred_diagnostic *deferred) > + : m_suggestion (suggestion), m_deferred (deferred) > + { > + if (m_deferred) > + m_deferred->incref (); > + } > + > + name_hint (const name_hint &other) > + : m_suggestion (other.m_suggestion), m_deferred (other.m_deferred) > + { > + if (m_deferred) > + m_deferred->incref (); > + } > + > + name_hint& operator= (const name_hint &other) > + { > + m_suggestion = other.m_suggestion; > + if (other.m_deferred) > + other.m_deferred->incref (); > + if (m_deferred) > + m_deferred->decref (); > + m_deferred = other.m_deferred; > + return *this; > + } > + > + ~name_hint () > + { > + if (m_deferred) > + m_deferred->decref (); > + } > + > + const char *suggestion () const { return m_suggestion; } > + operator bool () const { return m_suggestion != NULL; } > + > + /* Call this on a name_hint if the corresponding warning was not > emitted, > + in which case we should also not emit the deferred_diagnostic. > */ > + > + void suppress () > + { > + if (m_deferred) > + m_deferred->suppress (); > + } > + > +private: > + const char *m_suggestion; > + deferred_diagnostic *m_deferred; > +}; > + > +extern name_hint lookup_name_fuzzy (tree, enum > lookup_name_fuzzy_kind, > + location_t); > > extern bool vector_targets_convertible_p (const_tree t1, const_tree > t2); > extern bool vector_types_convertible_p (const_tree t1, const_tree > t2, bool emit_lax_note); > diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c > index 64a1107..64075f9 100644 > --- a/gcc/c/c-decl.c > +++ b/gcc/c/c-decl.c > @@ -3129,20 +3129,20 @@ implicit_decl_warning (location_t loc, tree > id, tree olddecl) > return; > > bool warned; > - const char *hint = NULL; > + name_hint hint; > if (!olddecl) > - hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME); > + hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_FUNCTION_NAME, loc); > > if (flag_isoc99) > { > if (hint) > { > gcc_rich_location richloc (loc); > - richloc.add_fixit_replace (hint); > + richloc.add_fixit_replace (hint.suggestion ()); > warned = pedwarn_at_rich_loc > (&richloc, OPT_Wimplicit_function_declaration, > "implicit declaration of function %qE; did you mean > %qs?", > - id, hint); > + id, hint.suggestion ()); > } > else > warned = pedwarn (loc, OPT_Wimplicit_function_declaration, > @@ -3151,11 +3151,11 @@ implicit_decl_warning (location_t loc, tree > id, tree olddecl) > else if (hint) > { > gcc_rich_location richloc (loc); > - richloc.add_fixit_replace (hint); > + richloc.add_fixit_replace (hint.suggestion ()); > warned = warning_at_rich_loc > (&richloc, OPT_Wimplicit_function_declaration, > G_("implicit declaration of function %qE; did you mean > %qs?"), > - id, hint); > + id, hint.suggestion ()); > } > else > warned = warning_at (loc, OPT_Wimplicit_function_declaration, > @@ -3163,6 +3163,9 @@ implicit_decl_warning (location_t loc, tree id, > tree olddecl) > > if (olddecl && warned) > locate_old_decl (olddecl); > + > + if (!warned) > + hint.suppress (); > } > > /* This function represents mapping of a function code FCODE > @@ -3475,15 +3478,15 @@ undeclared_variable (location_t loc, tree id) > > if (current_function_decl == 0) > { > - const char *guessed_id = lookup_name_fuzzy (id, > FUZZY_LOOKUP_NAME); > + name_hint guessed_id = lookup_name_fuzzy (id, > FUZZY_LOOKUP_NAME, loc); > if (guessed_id) > { > gcc_rich_location richloc (loc); > - richloc.add_fixit_replace (guessed_id); > + richloc.add_fixit_replace (guessed_id.suggestion ()); > error_at_rich_loc (&richloc, > "%qE undeclared here (not in a > function);" > " did you mean %qs?", > - id, guessed_id); > + id, guessed_id.suggestion ()); > } > else > error_at (loc, "%qE undeclared here (not in a function)", > id); > @@ -3493,16 +3496,16 @@ undeclared_variable (location_t loc, tree id) > { > if (!objc_diagnose_private_ivar (id)) > { > - const char *guessed_id = lookup_name_fuzzy (id, > FUZZY_LOOKUP_NAME); > + name_hint guessed_id = lookup_name_fuzzy (id, > FUZZY_LOOKUP_NAME, loc); > if (guessed_id) > { > gcc_rich_location richloc (loc); > - richloc.add_fixit_replace (guessed_id); > + richloc.add_fixit_replace (guessed_id.suggestion ()); > error_at_rich_loc > (&richloc, > "%qE undeclared (first use in this function);" > " did you mean %qs?", > - id, guessed_id); > + id, guessed_id.suggestion ()); > } > else > error_at (loc, "%qE undeclared (first use in this > function)", id); > @@ -4013,8 +4016,8 @@ lookup_name_in_scope (tree name, struct c_scope > *scope) > It also looks for start_typename keywords, to detect "singed" vs > "signed" > typos. */ > > -const char * > -lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind) > +name_hint > +lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, > location_t) > { > gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); > > @@ -4104,9 +4107,9 @@ lookup_name_fuzzy (tree name, enum > lookup_name_fuzzy_kind kind) > > tree best = bm.get_best_meaningful_candidate (); > if (best) > - return IDENTIFIER_POINTER (best); > + return name_hint (IDENTIFIER_POINTER (best), NULL); > else > - return NULL; > + return name_hint (NULL, NULL); > } > > > diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c > index 9398652..550b573 100644 > --- a/gcc/c/c-parser.c > +++ b/gcc/c/c-parser.c > @@ -1623,13 +1623,14 @@ c_parser_declaration_or_fndef (c_parser > *parser, bool fndef_ok, > } > else > { > - const char *hint = lookup_name_fuzzy (name, > FUZZY_LOOKUP_TYPENAME); > + name_hint hint = lookup_name_fuzzy (name, > FUZZY_LOOKUP_TYPENAME, > + here); > if (hint) > { > - richloc.add_fixit_replace (hint); > + richloc.add_fixit_replace (hint.suggestion ()); > error_at_rich_loc (&richloc, > "unknown type name %qE; did you > mean %qs?", > - name, hint); > + name, hint.suggestion ()); > } > else > error_at (here, "unknown type name %qE", name); > @@ -3848,15 +3849,16 @@ c_parser_parameter_declaration (c_parser > *parser, tree attrs) > c_parser_set_source_position_from_token (token); > if (c_parser_next_tokens_start_typename (parser, > cla_prefer_type)) > { > - const char *hint = lookup_name_fuzzy (token->value, > - FUZZY_LOOKUP_TYPENAM > E); > + name_hint hint = lookup_name_fuzzy (token->value, > + FUZZY_LOOKUP_TYPENAME, > + token->location); > if (hint) > { > gcc_rich_location richloc (token->location); > - richloc.add_fixit_replace (hint); > + richloc.add_fixit_replace (hint.suggestion ()); > error_at_rich_loc (&richloc, > "unknown type name %qE; did you > mean %qs?", > - token->value, hint); > + token->value, hint.suggestion ()); > } > else > error_at (token->location, "unknown type name %qE", > token->value); > diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c > index 0c5df93..de8c267 100644 > --- a/gcc/cp/name-lookup.c > +++ b/gcc/cp/name-lookup.c > @@ -4515,13 +4515,14 @@ suggest_alternatives_for (location_t > location, tree name, > { > if (suggest_misspellings) > { > - const char *fuzzy_name = lookup_name_fuzzy (name, > FUZZY_LOOKUP_NAME); > - if (fuzzy_name) > + name_hint hint = lookup_name_fuzzy (name, > FUZZY_LOOKUP_NAME, > + location); > + if (hint) > { > gcc_rich_location richloc (location); > - richloc.add_fixit_replace (fuzzy_name); > + richloc.add_fixit_replace (hint.suggestion ()); > inform_at_rich_loc (&richloc, "suggested alternative: > %qs", > - fuzzy_name); > + hint.suggestion ()); > } > } > return; > @@ -4953,10 +4954,10 @@ consider_binding_level (tree name, best_match > <tree, const char *> &bm, > > /* Search for near-matches for NAME within the current bindings, and > within > macro names, returning the best match as a const char *, or NULL > if > - no reasonable match is found. */ > + no reasonable match is found. */ > > -const char * > -lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind) > +name_hint > +lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, > location_t) > { > gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); > > @@ -5010,7 +5011,7 @@ lookup_name_fuzzy (tree name, enum > lookup_name_fuzzy_kind kind) > bm.consider (IDENTIFIER_POINTER (resword_identifier)); > } > > - return bm.get_best_meaningful_candidate (); > + return name_hint (bm.get_best_meaningful_candidate (), NULL); > } > > /* Subroutine of outer_binding. > diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c > index 7197c19..6e9f05c 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -3173,16 +3173,16 @@ cp_parser_diagnose_invalid_type_name > (cp_parser *parser, tree id, > else if (!parser->scope) > { > /* Issue an error message. */ > - const char *suggestion = NULL; > + name_hint hint; > if (TREE_CODE (id) == IDENTIFIER_NODE) > - suggestion = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME); > - if (suggestion) > + hint = lookup_name_fuzzy (id, FUZZY_LOOKUP_TYPENAME, > location); > + if (hint) > { > gcc_rich_location richloc (location); > - richloc.add_fixit_replace (suggestion); > + richloc.add_fixit_replace (hint.suggestion ()); > error_at_rich_loc (&richloc, > - "%qE does not name a type; did you mean > %qs?", > - id, suggestion); > + "%qE does not name a type; did you mean > %qs?", > + id, hint.suggestion ()); > } > else > error_at (location, "%qE does not name a type", id);