Ping
On Tue, 2017-09-26 at 15:27 -0400, David Malcolm wrote: > There are a few places where the C++ FE will complain when attempting > to do things within an extern "C" linkage specifier. > > I've run into problems where it wasn't clear where the pertinent > extern "C" was; for example, when failing to close an extern "C" > linkage > specifier in a header, leading to "template with C linkage" errors in > a different source file. > > 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. > > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. > > OK for trunk? > > gcc/cp/ChangeLog: > * cp-tree.h (struct saved_scope): Add "location" field. > (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_linkage_specification): Store the > location > of the "extern" token within the scope_chain. > (maybe_show_extern_c_location): New function. > (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. > > 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 | 3 ++ > gcc/cp/decl.c | 1 + > gcc/cp/parser.c | 19 ++++++++++- > 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 | 39 > ++++++++++++++++++++++ > 6 files changed, 78 insertions(+), 2 deletions(-) > 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 e508598..762cc7b 100644 > --- a/gcc/cp/cp-tree.h > +++ b/gcc/cp/cp-tree.h > @@ -1568,6 +1568,8 @@ struct GTY(()) saved_scope { > hash_map<tree, tree> *GTY((skip)) x_local_specializations; > > struct saved_scope *prev; > + > + location_t location; > }; > > extern GTY(()) struct saved_scope *scope_chain; > @@ -6352,6 +6354,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 50fa1ba..d08ac9a 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 d831d66..b90f40d 100644 > --- a/gcc/cp/parser.c > +++ b/gcc/cp/parser.c > @@ -13823,7 +13823,8 @@ cp_parser_linkage_specification (cp_parser* > parser) > tree linkage; > > /* Look for the `extern' keyword. */ > - cp_parser_require_keyword (parser, RID_EXTERN, RT_EXTERN); > + cp_token *extern_token > + = cp_parser_require_keyword (parser, RID_EXTERN, RT_EXTERN); > > /* Look for the string-literal. */ > linkage = cp_parser_string_literal (parser, false, false); > @@ -13843,6 +13844,7 @@ cp_parser_linkage_specification (cp_parser* > parser) > > /* We're now using the new linkage. */ > push_lang_context (linkage); > + scope_chain->location = extern_token->location; > > /* If the next token is a `{', then we're using the first > production. */ > @@ -16589,6 +16591,19 @@ cp_parser_explicit_instantiation (cp_parser* > parser) > timevar_pop (TV_TEMPLATE_INST); > } > > +/* 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 (scope_chain->location != UNKNOWN_LOCATION) > + inform (scope_chain->location, "%<extern \"C\"%> linkage started > here"); > +} > + > + > /* Parse an explicit-specialization. > > explicit-specialization: > @@ -16623,6 +16638,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); > @@ -26858,6 +26874,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); > 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..d47a49c > --- /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 "1: '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..44f538e 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 <typename T> // { dg-error "template with C linkage" } > +void bar (void); > +// { dg-message "1: '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..8a3a77a > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/extern-c.C > @@ -0,0 +1,39 @@ > +template <typename T> void specializable (T); > + > +/* Invalid template: within "extern C". */ > + > +extern "C" { // { dg-message "1: 'extern .C.' linkage started here" > } > + > +template <typename T> // { dg-error "template with C linkage" } > +void within_extern_c_braces (void); > + > +} > + > +/* Valid template: not within "extern C". */ > + > +template <typename T> > +void not_within_extern_c (void); > + > + > +/* Invalid specialization: within "extern C". */ > + > +extern "C" { // { dg-message "1: '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 <typename T> // { 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 "1: 'extern .C.' linkage started here" "" { target > *-*-* } open_extern_c_no_braces } > +