From patchwork Fri May 5 17:51:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 759110 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wKJYl0lMyz9s5L for ; Sat, 6 May 2017 03:20:08 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="BDkBeudC"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=fr6r2yB22mHTHGd70HCyMJYTV9qQL9caH4dwWOqO5tvF0HmBwdFyH OI9l6hcwrVQBAYhu9IyfbyYy+YvGk0zwJwKu3yMbZ5QrOvk3/tpLbtxExyh/ppHz dM06O3RnPzJvwxRbJTDTAJD7eiQL4tGWrWqUOMalAbniYzcGP+SrQk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=EhrG7WzDAQmDswVItfooHu0R8g4=; b=BDkBeudCFB71X69d4Dbv9TNNvtR0 Ihgzgp/Mn34OXyxi5RHea8fzmBrOzkskVZEPh2SyztTlAuzyp+jOrankJoeKx/xA nDz321oyQ5AJ3AmR4jBvj1Ka6wysmqWv8Iza0dO8bPCovxAlC/Jx4JmjVBK5v/TZ DtxyBpCeQkOY+Xs= Received: (qmail 125074 invoked by alias); 5 May 2017 17:19:55 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 125041 invoked by uid 89); 5 May 2017 17:19:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 05 May 2017 17:19:52 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9540A7D4E2 for ; Fri, 5 May 2017 17:19:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 9540A7D4E2 Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx04.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dmalcolm@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 9540A7D4E2 Received: from c64.redhat.com (ovpn-112-30.phx2.redhat.com [10.3.112.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id C36035DD72; Fri, 5 May 2017 17:19:52 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [PATCH 2/3] C++: provide macro used-before-defined hint (PR c++/72786). Date: Fri, 5 May 2017 13:51:14 -0400 Message-Id: <1494006675-28033-2-git-send-email-dmalcolm@redhat.com> In-Reply-To: <1494006675-28033-1-git-send-email-dmalcolm@redhat.com> References: <1494006675-28033-1-git-send-email-dmalcolm@redhat.com> MIME-Version: 1.0 X-IsSubscribed: yes 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. --- gcc/cp/name-lookup.c | 47 +++++++++++++++++++++- gcc/spellcheck.h | 7 ++++ gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C | 17 ++++++++ gcc/testsuite/g++.dg/spellcheck-macro-ordering.C | 3 +- libcpp/include/cpplib.h | 1 + libcpp/macro.c | 8 ++++ 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/spellcheck-macro-ordering-2.C diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index de8c267..93bea35 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -4952,12 +4952,46 @@ consider_binding_level (tree name, best_match &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); + } + + void emit () OVERRIDE FINAL + { + 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); @@ -4987,6 +5021,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/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..a2c7bba 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/include/cpplib.h b/libcpp/include/cpplib.h index b843992..cf2fdc6 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -876,6 +876,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 de18c22..16fdd2a 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -3472,3 +3472,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; +}