From patchwork Thu Oct 12 18:45:29 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 825016 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-464056-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="tG3JsgLH"; dkim-atps=neutral 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 3yCfsz2mQqz9s7p for ; Fri, 13 Oct 2017 05:45:01 +1100 (AEDT) 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; q=dns; s= default; b=u1dd9Y7N11kfW8SaAZAD0WJNfDuR6gOj+0frnqbtivaiSlUeMZAnl HmepAPvqrnZqhv8b5iqItvPr6fvvawOqdR4sF3qVC7Tgf7Laql+OAjsgBy1e8QiD BZ0fFx5JE01z2QjymdVov9KQ09xJnDnrMi5UcE0mkjCJUEtF6dNi5s= 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; s= default; bh=3h0pT2soOHFm3nMK9BVv9D94L2U=; b=tG3JsgLHBYK15awVBYbD I1G1oNxUC+eOxPKqDFvBsy9Bf4NNzK/lxQ0n+V4bseii9BCAlo77BkS8lfKweoon vqH8ZJLNINE9l5e2tK4bn8IL5w5MFAO7h2upXaJ5LcdPw8Fxkpex0Dq1LDfQA2Fy hLw2otCrprLDMeYhJhyrccg= Received: (qmail 88263 invoked by alias); 12 Oct 2017 18:44:53 -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 88130 invoked by uid 89); 12 Oct 2017 18:44:52 -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; Thu, 12 Oct 2017 18:44:50 +0000 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 884AB806BD for ; Thu, 12 Oct 2017 18:44:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 884AB806BD Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=dmalcolm@redhat.com Received: from c64.redhat.com (ovpn-112-12.phx2.redhat.com [10.3.112.12]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2C60E5EDE0; Thu, 12 Oct 2017 18:44:45 +0000 (UTC) From: David Malcolm To: Jason Merrill Cc: gcc-patches List , David Malcolm Subject: [PATCH] C++: show location of unclosed extern "C" specifications (v2) Date: Thu, 12 Oct 2017 14:45:29 -0400 Message-Id: <1507833929-25385-1-git-send-email-dmalcolm@redhat.com> In-Reply-To: References: X-IsSubscribed: yes On Wed, 2017-10-11 at 15:51 -0400, Jason Merrill wrote: > On Tue, Sep 26, 2017 at 3:27 PM, David Malcolm > wrote: > > * cp-tree.h (struct saved_scope): Add "location" field. > > saved_scope seems like the wrong place for this; it's only > interesting > at parse time, so having it saved during template instantiation > doesn't seem useful. I'd prefer to put it in cp_parser and have > maybe_show_extern_c_location look in the_parser. > > Jason Here's an updated version that moves it there. Other changes in v2: - handle nested linkage specifications - put the note on the string-literal, rather than the extern: note: 'extern "C"' linkage started here extern "C" { ^~~ Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. OK for trunk? Thanks Dave Blurb from v1: If the user fails to close an extern "C" linkage specifier, and then uses templates, they will run into "template with C linkage" errors. From personal experience, it can be hard to tell where the extern "C" began. As of r251026 there will be a message highlighting the unclosed '{', but this may be hard to spot at the very end of the errors. This patch adds a note to the various diagnostics that complain about C linkage, showing the user where the extern "C" specification began. gcc/cp/ChangeLog: * cp-tree.h (maybe_show_extern_c_location): New decl. * decl.c (grokfndecl): When complaining about literal operators with C linkage, issue a note giving the location of the extern "C". * parser.c (cp_parser_new): Initialize new field "innermost_linkage_specification_location". (cp_parser_linkage_specification): Store the location of the string-literal token within the cp_parser. (cp_parser_explicit_specialization): When complaining about template specializations with C linkage, issue a note giving the location of the extern "C". (cp_parser_explicit_template_declaration): Likewise for templates. (maybe_show_extern_c_location): New function. * parser.h (struct cp_parser): New field "innermost_linkage_specification_location". gcc/testsuite/ChangeLog: * g++.dg/cpp0x/udlit-extern-c.C: New test case. * g++.dg/diagnostic/unclosed-extern-c.C: Add example of a template erroneously covered by an unclosed extern "C". * g++.dg/template/extern-c.C: New test case. --- gcc/cp/cp-tree.h | 1 + gcc/cp/decl.c | 1 + gcc/cp/parser.c | 29 ++++++++++ gcc/cp/parser.h | 4 ++ gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C | 7 +++ .../g++.dg/diagnostic/unclosed-extern-c.C | 11 +++- gcc/testsuite/g++.dg/template/extern-c.C | 66 ++++++++++++++++++++++ 7 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C create mode 100644 gcc/testsuite/g++.dg/template/extern-c.C diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 82ebc28..df3d198 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6362,6 +6362,7 @@ extern bool parsing_nsdmi (void); extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); extern location_t defarg_location (tree); +extern void maybe_show_extern_c_location (void); /* in pt.c */ extern bool check_template_shadow (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 99f0af2..51a5305 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8724,6 +8724,7 @@ grokfndecl (tree ctype, if (DECL_LANGUAGE (decl) == lang_c) { error ("literal operator with C linkage"); + maybe_show_extern_c_location (); return NULL_TREE; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 28bc8e4..a556a21 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3828,6 +3828,9 @@ cp_parser_new (void) /* Allow constrained-type-specifiers. */ parser->prevent_constrained_type_specifiers = 0; + /* We haven't yet seen an 'extern "C"'. */ + parser->innermost_linkage_specification_location = UNKNOWN_LOCATION; + return parser; } @@ -13740,6 +13743,7 @@ cp_parser_linkage_specification (cp_parser* parser) cp_parser_require_keyword (parser, RID_EXTERN, RT_EXTERN); /* Look for the string-literal. */ + cp_token *string_token = cp_lexer_peek_token (parser->lexer); linkage = cp_parser_string_literal (parser, false, false); /* Transform the literal into an identifier. If the literal is a @@ -13758,6 +13762,13 @@ cp_parser_linkage_specification (cp_parser* parser) /* We're now using the new linkage. */ push_lang_context (linkage); + /* Preserve the location of the string-literal for the innermost linkage + specification, tracking the locations of nested specifications + via a local. */ + location_t saved_location + = parser->innermost_linkage_specification_location; + parser->innermost_linkage_specification_location = string_token->location; + /* If the next token is a `{', then we're using the first production. */ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) @@ -13788,6 +13799,9 @@ cp_parser_linkage_specification (cp_parser* parser) /* We're done with the linkage-specification. */ pop_lang_context (); + + /* Restore location of parent linkage specification, if any. */ + parser->innermost_linkage_specification_location = saved_location; } /* Parse a static_assert-declaration. @@ -16537,6 +16551,7 @@ cp_parser_explicit_specialization (cp_parser* parser) if (current_lang_name == lang_name_c) { error_at (token->location, "template specialization with C linkage"); + maybe_show_extern_c_location (); /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); @@ -26861,6 +26876,7 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p) if (current_lang_name == lang_name_c) { error_at (location, "template with C linkage"); + maybe_show_extern_c_location (); /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); @@ -39479,4 +39495,17 @@ finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt) return member_decl_opt; } +/* Helper function for diagnostics that have complained about things + being used with 'extern "C"' linkage. + + Attempt to issue a note showing where the 'extern "C"' linkage began. */ + +void +maybe_show_extern_c_location (void) +{ + if (the_parser->innermost_linkage_specification_location != UNKNOWN_LOCATION) + inform (the_parser->innermost_linkage_specification_location, + "% linkage started here"); +} + #include "gt-cp-parser.h" diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index 0994e1e..f4f4a01 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -412,6 +412,10 @@ struct GTY(()) cp_parser { context e.g., because they could never be deduced. */ int prevent_constrained_type_specifiers; + /* Location of the string-literal token within the current linkage + specification, if any, or UNKNOWN_LOCATION otherwise. */ + location_t innermost_linkage_specification_location; + }; /* In parser.c */ diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C b/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C new file mode 100644 index 0000000..ea54cba --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C @@ -0,0 +1,7 @@ +// { dg-do compile { target c++11 } } + +extern "C" { // { dg-message "8: 'extern .C.' linkage started here" } + +constexpr double operator"" _deg ( double degrees ); // { dg-error "literal operator with C linkage" } + +} diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C index fda3532..d85a049 100644 --- a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C +++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C @@ -1,3 +1,12 @@ -extern "C" { /* { dg-message "12: to match this '.'" } */ +extern "C" { // { dg-line open_extern_c } + + int foo (void); + +/* Missing close-brace for the extern "C" here. */ + +template // { dg-error "template with C linkage" } +void bar (void); +// { dg-message "8: 'extern .C.' linkage started here" "" { target *-*-* } open_extern_c } void test (void); /* { dg-error "17: expected '.' at end of input" } */ +// { message "12: to match this '.'" "" { target *-*-* } open_extern_c } diff --git a/gcc/testsuite/g++.dg/template/extern-c.C b/gcc/testsuite/g++.dg/template/extern-c.C new file mode 100644 index 0000000..6cbf69f --- /dev/null +++ b/gcc/testsuite/g++.dg/template/extern-c.C @@ -0,0 +1,66 @@ +template void specializable (T); + +/* Invalid template: within "extern C". */ + +extern "C" { // { dg-message "8: 'extern .C.' linkage started here" } + +template // { dg-error "template with C linkage" } +void within_extern_c_braces (void); + +} + +/* Valid template: not within "extern C". */ + +template +void not_within_extern_c (void); + + +/* Invalid specialization: within "extern C". */ + +extern "C" { // { dg-message "8: 'extern .C.' linkage started here" } + +template <> // { dg-error "template specialization with C linkage" } +void specializable (int); + +} + + +/* Valid specialization: not within "extern C". */ +template <> +void specializable (char); + + +/* Example of extern C without braces. */ + +extern "C" template // { dg-line open_extern_c_no_braces } +void within_extern_c_no_braces (void); +// { dg-error "12: template with C linkage" "" { target *-*-* } open_extern_c_no_braces } +// { dg-message "8: 'extern .C.' linkage started here" "" { target *-*-* } open_extern_c_no_braces } + + +/* Nested extern "C" specifications. + We should report within the innermost extern "C" that's still open. */ + +extern "C" { + extern "C" { // { dg-line middle_open_extern_c } + extern "C" { + } + + template // { dg-error "template with C linkage" } + void within_nested_extern_c (void); + // { dg-message "10: 'extern .C.' linkage started here" "" { target *-*-* } middle_open_extern_c } + + extern "C++" { + /* Valid template: within extern "C++". */ + template + void within_nested_extern_cpp (void); + + extern "C" { // { dg-line last_open_extern_c } + /* Invalid template: within "extern C". */ + template // { dg-error "template with C linkage" } + void within_extern_c_within_extern_cpp (void); + // { dg-message "14: 'extern .C.' linkage started here" "" { target *-*-* } last_open_extern_c } + } + } + } +}