diff options
author | David Malcolm <dmalcolm@redhat.com> | 2017-11-21 00:40:53 +0000 |
---|---|---|
committer | David Malcolm <dmalcolm@gcc.gnu.org> | 2017-11-21 00:40:53 +0000 |
commit | 01ada12136c64ad9ff305f456637d43b9f6d4356 (patch) | |
tree | 2fd6c86557307e928d7444794521945cbde6d559 | |
parent | 874b8068f6c4cab53b14b7d2db117abd71f7da95 (diff) | |
download | gcc-01ada12136c64ad9ff305f456637d43b9f6d4356.zip gcc-01ada12136c64ad9ff305f456637d43b9f6d4356.tar.gz gcc-01ada12136c64ad9ff305f456637d43b9f6d4356.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/name-lookup.c | 50 | ||||
-rw-r--r-- | gcc/spellcheck.h | 7 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C | 17 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/spellcheck-macro-ordering.C | 3 | ||||
-rw-r--r-- | libcpp/ChangeLog | 6 | ||||
-rw-r--r-- | libcpp/include/cpplib.h | 1 | ||||
-rw-r--r-- | libcpp/macro.c | 8 |
10 files changed, 109 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4589f5b..0255d8a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5de732f..908b48e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -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 diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 9d97da3..fc317b1 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -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. */ diff --git a/gcc/spellcheck.h b/gcc/spellcheck.h index 2edc695..bad3c1e 100644 --- a/gcc/spellcheck.h +++ b/gcc/spellcheck.h @@ -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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 05dd8e0..4c9569f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C b/gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C new file mode 100644 index 0000000..73c0f21 --- /dev/null +++ b/gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C @@ -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 } +}; diff --git a/gcc/testsuite/g++.dg/spellcheck-macro-ordering.C b/gcc/testsuite/g++.dg/spellcheck-macro-ordering.C index 3b888c6..bbd41f4 100644 --- a/gcc/testsuite/g++.dg/spellcheck-macro-ordering.C +++ b/gcc/testsuite/g++.dg/spellcheck-macro-ordering.C @@ -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 } diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog index 70c834c..cc5d4d3 100644 --- a/libcpp/ChangeLog +++ b/libcpp/ChangeLog @@ -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__. diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 101b33a..4d04a48 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -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); diff --git a/libcpp/macro.c b/libcpp/macro.c index bf473ea..43f2baa 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -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; +} |