C++: provide macro used-before-defined hint (PR c++/72786)
This patch uses the name_hint/deferred_diagnostic to provide a message in the C++ frontend if a macro is used before it is defined e.g.: test.c:6:24: error: expected ';' at end of member declaration virtual void clone() const OVERRIDE { } ^~~~~ ; test.c:6:30: error: 'OVERRIDE' does not name a type virtual void clone() const OVERRIDE { } ^~~~~~~~ test.c:6:30: note: the macro 'OVERRIDE' had not yet been defined test.c:15:0: note: it was later defined here #define OVERRIDE override It's possible to do it from the C++ frontend as tokenization happens up-front (and hence the macro already exists when the above is parsed); I attempted to do it from the C frontend, but because the C frontend only tokenizes on-demand during parsing, the macro isn't known about until later. gcc/cp/ChangeLog: PR c++/72786 * name-lookup.c (class macro_use_before_def): New class. (lookup_name_fuzzy): Detect macro that were used before being defined, and report them as such. gcc/ChangeLog: PR c++/72786 * spellcheck.h (best_match::blithely_get_best_candidate): New accessor. gcc/testsuite/ChangeLog: PR c++/72786 * g++.dg/spellcheck-macro-ordering-2.C: New test case. * g++.dg/spellcheck-macro-ordering.C: Add dg-message directives for macro used-before-defined. libcpp/ChangeLog: PR c++/72786 * include/cpplib.h (cpp_macro_definition_location): New decl. * macro.c (cpp_macro_definition): New function. From-SVN: r254978
This commit is contained in:
parent
874b8068f6
commit
01ada12136
|
@ -1,3 +1,9 @@
|
|||
2017-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR c++/72786
|
||||
* spellcheck.h (best_match::blithely_get_best_candidate): New
|
||||
accessor.
|
||||
|
||||
2017-11-20 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* config/i386/i386.c (parse_mtune_ctrl_str): Start diagnostics
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2017-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR c++/72786
|
||||
* name-lookup.c (class macro_use_before_def): New class.
|
||||
(lookup_name_fuzzy): Detect macro that were used before being
|
||||
defined, and report them as such.
|
||||
|
||||
2017-11-20 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* decl2.c (constrain_class_visibility): Don't warn about artificial
|
||||
|
|
|
@ -5636,12 +5636,49 @@ consider_binding_level (tree name, best_match <tree, const char *> &bm,
|
|||
}
|
||||
}
|
||||
|
||||
/* Subclass of deferred_diagnostic. Notify the user that the
|
||||
given macro was used before it was defined.
|
||||
This can be done in the C++ frontend since tokenization happens
|
||||
upfront. */
|
||||
|
||||
class macro_use_before_def : public deferred_diagnostic
|
||||
{
|
||||
public:
|
||||
/* Ctor. LOC is the location of the usage. MACRO is the
|
||||
macro that was used. */
|
||||
macro_use_before_def (location_t loc, cpp_hashnode *macro)
|
||||
: deferred_diagnostic (loc), m_macro (macro)
|
||||
{
|
||||
gcc_assert (macro);
|
||||
}
|
||||
|
||||
~macro_use_before_def ()
|
||||
{
|
||||
if (is_suppressed_p ())
|
||||
return;
|
||||
|
||||
source_location def_loc = cpp_macro_definition_location (m_macro);
|
||||
if (def_loc != UNKNOWN_LOCATION)
|
||||
{
|
||||
inform (get_location (), "the macro %qs had not yet been defined",
|
||||
(const char *)m_macro->ident.str);
|
||||
inform (def_loc, "it was later defined here");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_hashnode *m_macro;
|
||||
};
|
||||
|
||||
|
||||
/* 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.
|
||||
|
||||
Use LOC for any deferred diagnostics. */
|
||||
|
||||
name_hint
|
||||
lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t)
|
||||
lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
|
||||
{
|
||||
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
|
||||
|
||||
|
@ -5671,6 +5708,15 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t)
|
|||
/* If a macro is the closest so far to NAME, consider it. */
|
||||
if (best_macro)
|
||||
bm.consider ((const char *)best_macro->ident.str);
|
||||
else if (bmm.get_best_distance () == 0)
|
||||
{
|
||||
/* If we have an exact match for a macro name, then the
|
||||
macro has been used before it was defined. */
|
||||
cpp_hashnode *macro = bmm.blithely_get_best_candidate ();
|
||||
if (macro)
|
||||
return name_hint (NULL,
|
||||
new macro_use_before_def (loc, macro));
|
||||
}
|
||||
|
||||
/* Try the "starts_decl_specifier_p" keywords to detect
|
||||
"singed" vs "signed" typos. */
|
||||
|
|
|
@ -178,6 +178,13 @@ class best_match
|
|||
return m_best_candidate;
|
||||
}
|
||||
|
||||
/* Get the closest candidate so far, without applying any filtering. */
|
||||
|
||||
candidate_t blithely_get_best_candidate () const
|
||||
{
|
||||
return m_best_candidate;
|
||||
}
|
||||
|
||||
edit_distance_t get_best_distance () const { return m_best_distance; }
|
||||
size_t get_best_candidate_length () const { return m_best_candidate_len; }
|
||||
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2017-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR c++/72786
|
||||
* g++.dg/spellcheck-macro-ordering-2.C: New test case.
|
||||
* g++.dg/spellcheck-macro-ordering.C: Add dg-message directives
|
||||
for macro used-before-defined.
|
||||
|
||||
2017-11-20 Steve Ellcey <sellcey@cavium.com>
|
||||
|
||||
PR target/81356
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
// PR c++/72786
|
||||
|
||||
/* Example of undeffed macro. */
|
||||
|
||||
#define OVERRIDE override
|
||||
|
||||
#undef OVERRIDE
|
||||
|
||||
class DocTargetDriver {
|
||||
virtual void clone() const OVERRIDE { } // { dg-line usage }
|
||||
/* Offering "OVERRIDE" as a spelling suggestion for "OVERRIDE" would be
|
||||
nonsensical. */
|
||||
// { dg-bogus "did you mean" "" { target *-*-* } usage }
|
||||
// { dg-error "expected .;. at end of member declaration" "" { target *-*-* } usage }
|
||||
// { dg-error ".OVERRIDE. does not name a type" "" { target *-*-* } usage }
|
||||
// { dg-bogus "macro" "" { target *-*-* } usage }
|
||||
};
|
|
@ -9,7 +9,8 @@ class DocTargetDriver {
|
|||
// { dg-bogus "did you mean" "" { target *-*-* } .-3 }
|
||||
// { dg-error "expected .;. at end of member declaration" "" { target *-*-* } .-4 }
|
||||
// { dg-error ".OVERRIDE. does not name a type" "" { target *-*-* } .-5 }
|
||||
// { dg-message "the macro 'OVERRIDE' had not yet been defined" "" { target *-*-* } .-6 }
|
||||
};
|
||||
|
||||
#define OVERRIDE override
|
||||
|
||||
// { dg-message "-:it was later defined here" "" { target *-*-* } .-1 }
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2017-11-20 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR c++/72786
|
||||
* include/cpplib.h (cpp_macro_definition_location): New decl.
|
||||
* macro.c (cpp_macro_definition): New function.
|
||||
|
||||
2017-11-13 Tom Tromey <tom@tromey.com>
|
||||
|
||||
* pch.c (cpp_read_state): Set n__VA_OPT__.
|
||||
|
|
|
@ -889,6 +889,7 @@ extern const cpp_token *cpp_get_token_with_location (cpp_reader *,
|
|||
extern bool cpp_fun_like_macro_p (cpp_hashnode *);
|
||||
extern const unsigned char *cpp_macro_definition (cpp_reader *,
|
||||
cpp_hashnode *);
|
||||
extern source_location cpp_macro_definition_location (cpp_hashnode *);
|
||||
extern void _cpp_backup_tokens (cpp_reader *, unsigned int);
|
||||
extern const cpp_token *cpp_peek_token (cpp_reader *, int);
|
||||
|
||||
|
|
|
@ -3646,3 +3646,11 @@ cpp_macro_definition (cpp_reader *pfile, cpp_hashnode *node)
|
|||
*buffer = '\0';
|
||||
return pfile->macro_buffer;
|
||||
}
|
||||
|
||||
/* Get the line at which the macro was defined. */
|
||||
|
||||
source_location
|
||||
cpp_macro_definition_location (cpp_hashnode *node)
|
||||
{
|
||||
return node->value.macro->line;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue