C++: show location of unclosed extern "C" specifications
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 linkage specification 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. From-SVN: r253726
This commit is contained in:
parent
3b0dd4fea2
commit
15f7a46926
9 changed files with 152 additions and 2 deletions
|
@ -1,3 +1,21 @@
|
|||
2017-10-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* 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 linkage specification 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".
|
||||
|
||||
2017-10-12 Nathan Sidwell <nathan@acm.org>
|
||||
|
||||
* cp-tree.h (cp_expr): Add const operator * and operator->
|
||||
|
|
|
@ -6356,6 +6356,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);
|
||||
|
|
|
@ -8729,6 +8729,7 @@ grokfndecl (tree ctype,
|
|||
if (DECL_LANGUAGE (decl) == lang_c)
|
||||
{
|
||||
error ("literal operator with C linkage");
|
||||
maybe_show_extern_c_location ();
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
|
|
|
@ -3937,6 +3937,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;
|
||||
}
|
||||
|
||||
|
@ -13848,9 +13851,11 @@ 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. */
|
||||
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
|
||||
|
@ -13869,6 +13874,20 @@ cp_parser_linkage_specification (cp_parser* parser)
|
|||
/* We're now using the new linkage. */
|
||||
push_lang_context (linkage);
|
||||
|
||||
/* Preserve the location of the the innermost linkage specification,
|
||||
tracking the locations of nested specifications via a local. */
|
||||
location_t saved_location
|
||||
= parser->innermost_linkage_specification_location;
|
||||
/* Construct a location ranging from the start of the "extern" to
|
||||
the end of the string-literal, with the caret at the start, e.g.:
|
||||
extern "C" {
|
||||
^~~~~~~~~~
|
||||
*/
|
||||
parser->innermost_linkage_specification_location
|
||||
= make_location (extern_token->location,
|
||||
extern_token->location,
|
||||
get_finish (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))
|
||||
|
@ -13899,6 +13918,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.
|
||||
|
@ -16643,6 +16665,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);
|
||||
|
@ -26979,6 +27002,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);
|
||||
|
@ -39552,4 +39576,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,
|
||||
"%<extern \"C\"%> linkage started here");
|
||||
}
|
||||
|
||||
#include "gt-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 */
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2017-10-13 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2017-10-13 Richard Biener <rguenther@suse.de>
|
||||
|
||||
* gcc.dg/graphite/pr35356-3.c: XFAIL again.
|
||||
|
|
7
gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C
Normal file
7
gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C
Normal file
|
@ -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" }
|
||||
|
||||
}
|
|
@ -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 }
|
||||
|
|
66
gcc/testsuite/g++.dg/template/extern-c.C
Normal file
66
gcc/testsuite/g++.dg/template/extern-c.C
Normal file
|
@ -0,0 +1,66 @@
|
|||
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 }
|
||||
|
||||
|
||||
/* 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 <typename T> // { dg-error "template with C linkage" }
|
||||
void within_nested_extern_c (void);
|
||||
// { dg-message "3: 'extern .C.' linkage started here" "" { target *-*-* } middle_open_extern_c }
|
||||
|
||||
extern "C++" {
|
||||
/* Valid template: within extern "C++". */
|
||||
template <typename T>
|
||||
void within_nested_extern_cpp (void);
|
||||
|
||||
extern "C" { // { dg-line last_open_extern_c }
|
||||
/* Invalid template: within "extern C". */
|
||||
template <typename T> // { dg-error "template with C linkage" }
|
||||
void within_extern_c_within_extern_cpp (void);
|
||||
// { dg-message "7: 'extern .C.' linkage started here" "" { target *-*-* } last_open_extern_c }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue