Screenshot: https://dmalcolm.fedorapeople.org/gcc/2015-09-09/c++-token-ranges.html
gcc/cp/ChangeLog: * parser.c (cp_parser_string_literal): Show ranges of both string literals in the "unsupported concatenation" error. (cp_parser_primary_expression): Use token range rather than location for two errors. (cp_parser_namespace_alias_definition): Likewise for one error. (cp_parser_init_declarator): Likewise. (cp_parser_base_specifier): Likewise for two errors. (cp_parser_std_attribute): Likewise for an error and a warning. (cp_parser_function_definition_after_declarator): Likewise for an error. (cp_parser_explicit_template_declaration): Add "tok_range" param and use it for the errors. (cp_parser_template_declaration_after_export): Pass the range of the "template" token to cp_parser_explicit_template_declaration. gcc/testsuite/ChangeLog: * g++.dg/diagnostic/token-ranges.C: New. --- gcc/cp/parser.c | 45 +++++++---- gcc/testsuite/g++.dg/diagnostic/token-ranges.C | 104 +++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/token-ranges.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7c59c58..17b7de0 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -3734,6 +3734,8 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, gcc_obstack_init (&str_ob); count = 0; + source_range range_of_prior_literal = tok->range; + do { cp_lexer_consume_token (parser->lexer); @@ -3767,11 +3769,17 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok, if (type == CPP_STRING) type = curr_type; else if (curr_type != CPP_STRING) - error_at (tok->location, - "unsupported non-standard concatenation " - "of string literals"); + { + rich_location rich_loc (tok->range); + rich_loc.add_range (range_of_prior_literal); + error_at_rich_loc (&rich_loc, + "unsupported non-standard concatenation " + "of string literals"); + } } + range_of_prior_literal.m_finish = tok->range.m_finish; + obstack_grow (&str_ob, &str, sizeof (cpp_string)); tok = cp_lexer_peek_token (parser->lexer); @@ -4549,7 +4557,7 @@ cp_parser_primary_expression (cp_parser *parser, cp_lexer_consume_token (parser->lexer); if (parser->local_variables_forbidden_p) { - error_at (token->location, + error_at (token->range, "%<this%> may not be used in this context"); return error_mark_node; } @@ -4672,7 +4680,7 @@ cp_parser_primary_expression (cp_parser *parser, && (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS)) { - error_at (token->location, + error_at (token->range, "a template declaration cannot appear at block scope"); cp_parser_skip_to_end_of_block_or_statement (parser); return error_mark_node; @@ -16829,7 +16837,7 @@ cp_parser_namespace_alias_definition (cp_parser* parser) if (!cp_parser_uncommitted_to_tentative_parse_p (parser) && cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)) { - error_at (token->location, "%<namespace%> definition is not allowed here"); + error_at (token->range, "%<namespace%> definition is not allowed here"); /* Skip the definition. */ cp_lexer_consume_token (parser->lexer); if (cp_parser_skip_to_closing_brace (parser)) @@ -17602,7 +17610,7 @@ cp_parser_init_declarator (cp_parser* parser, "an asm-specification is not allowed " "on a function-definition"); if (attributes) - error_at (attributes_start_token->location, + error_at (attributes_start_token->range, "attributes are not allowed " "on a function-definition"); /* This is a function-definition. */ @@ -22016,10 +22024,10 @@ cp_parser_base_specifier (cp_parser* parser) { token = cp_lexer_peek_token (parser->lexer); if (!processing_template_decl) - error_at (token->location, + error_at (token->range, "keyword %<typename%> not allowed outside of templates"); else - error_at (token->location, + error_at (token->range, "keyword %<typename%> not allowed in this context " "(the base class is implicitly a type)"); cp_lexer_consume_token (parser->lexer); @@ -22971,10 +22979,12 @@ cp_parser_std_attribute (cp_parser *parser) { tree attribute, attr_ns = NULL_TREE, attr_id = NULL_TREE, arguments; cp_token *token; + source_range name_range; /* First, parse name of the attribute, a.k.a attribute-token. */ token = cp_lexer_peek_token (parser->lexer); + name_range = token->range; if (token->type == CPP_NAME) attr_id = token->u.value; else if (token->type == CPP_KEYWORD) @@ -23002,7 +23012,7 @@ cp_parser_std_attribute (cp_parser *parser) attr_id = ridpointers[(int) token->keyword]; else { - error_at (token->location, + error_at (token->range, "expected an identifier for the attribute name"); return error_mark_node; } @@ -23021,7 +23031,7 @@ cp_parser_std_attribute (cp_parser *parser) else if (cxx_dialect >= cxx11 && is_attribute_p ("deprecated", attr_id)) { if (cxx_dialect == cxx11) - pedwarn (token->location, OPT_Wpedantic, + pedwarn (name_range, OPT_Wpedantic, "%<deprecated%> is a C++14 feature;" " use %<gnu::deprecated%>"); TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu"); @@ -24383,7 +24393,7 @@ cp_parser_function_definition_after_declarator (cp_parser* parser, returned. */ cp_parser_identifier (parser); /* Issue an error message. */ - error_at (token->location, + error_at (token->range, "named return values are no longer supported"); /* Skip tokens until we reach the start of the function body. */ while (true) @@ -24654,11 +24664,11 @@ cp_parser_template_introduction (cp_parser* parser, bool member_p) /* Parse a normal template-declaration following the template keyword. */ static void -cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p) +cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p, + source_range tok_range) { tree parameter_list; bool need_lang_pop; - location_t location = input_location; /* Look for the `<' token. */ if (!cp_parser_require (parser, CPP_LESS, RT_LESS)) @@ -24668,7 +24678,7 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p) /* 14.5.2.2 [temp.mem] A local class shall not have member templates. */ - error_at (location, + error_at (tok_range, "invalid declaration of member template in local class"); cp_parser_skip_to_end_of_block_or_statement (parser); return; @@ -24678,7 +24688,7 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p) A template ... shall not have C linkage. */ if (current_lang_name == lang_name_c) { - error_at (location, "template with C linkage"); + error_at (tok_range, "template with C linkage"); /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); @@ -24737,8 +24747,9 @@ cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) { if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) { + source_range tok_range = cp_lexer_peek_token (parser->lexer)->range; cp_lexer_consume_token (parser->lexer); - cp_parser_explicit_template_declaration (parser, member_p); + cp_parser_explicit_template_declaration (parser, member_p, tok_range); return true; } else if (flag_concepts) diff --git a/gcc/testsuite/g++.dg/diagnostic/token-ranges.C b/gcc/testsuite/g++.dg/diagnostic/token-ranges.C new file mode 100644 index 0000000..bc830ad --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/token-ranges.C @@ -0,0 +1,104 @@ +/* { dg-options "-fdiagnostics-show-caret -std=c++11 -Wpedantic" } */ + +/* Verify that various diagnostics show source code ranges. */ + +/* These ones merely use token ranges; they don't use tree ranges. */ + +void bad_namespace () { + namespace foo { // { dg-error "'namespace' definition is not allowed here" } + } +/* { dg-begin-multiline-output "" } + namespace foo { + ^~~~~~~~~ + { dg-end-multiline-output "" } */ +} + + +void fn_defn_with_attribute () + __attribute__((constructor (0))) // { dg-error "attributes are not allowed on a function-definition" } +{ + /* { dg-begin-multiline-output "" } + __attribute__((constructor (0))) + ^~~~~~~~~~~~~ + { dg-end-multiline-output "" } */ +} + +class foo {}; +class bar : public typename foo // { dg-error "keyword 'typename' not allowed outside of templates" } +{ +}; +/* { dg-begin-multiline-output "" } + class bar : public typename foo + ^~~~~~~~ + { dg-end-multiline-output "" } */ + + +// C++11 attributes + +void bogus_scoped_attribute [[foo::400]] (); // { dg-error "expected an identifier for the attribute name" } +/* { dg-begin-multiline-output "" } + void bogus_scoped_attribute [[foo::400]] (); + ^~~ + { dg-end-multiline-output "" } */ + +void meta_deprecation [[deprecated]] (); // { dg-warning "use 'gnu::deprecated'" } +/* { dg-begin-multiline-output "" } + void meta_deprecation [[deprecated]] (); + ^~~~~~~~~~ + { dg-end-multiline-output "" } */ + + +int foo() return bar {} // { dg-error "named return values are no longer supported" } +/* { dg-begin-multiline-output "" } + int foo() return bar {} + ^~~~~~ + { dg-end-multiline-output "" } */ + +template<typename T> void foo(T) +{ + struct A + { + template<int> struct B {} // { dg-error "local class" } + +/* { dg-begin-multiline-output "" } + template<int> struct B {} + ^~~~~~~~ + { dg-end-multiline-output "" } */ + }; +} + +extern "C" { template<typename T> void foo(T); } // { dg-error "C linkage" } +/* { dg-begin-multiline-output "" } + extern "C" { template<typename T> void foo(T); } + ^~~~~~~~ + { dg-end-multiline-output "" } */ +// TODO: It would be nice to inform the user of the location of the +// relevant extern "C". + +const void *s = u8"a" u"b"; // { dg-error "non-standard concatenation" } +/* { dg-begin-multiline-output "" } + const void *s = u8"a" u"b"; + ~~~~~ ^~~~ + { dg-end-multiline-output "" } */ + +const void *s2 = u"a" u"b" u8"c"; // { dg-error "non-standard concatenation" } +/* { dg-begin-multiline-output "" } + const void *s2 = u"a" u"b" u8"c"; + ~~~~~~~~~~ ^~~~~ + { dg-end-multiline-output "" } */ + + +void default_arg_of_this (void *ptr = this); // { dg-error "'this'" } +/* { dg-begin-multiline-output "" } + void default_arg_of_this (void *ptr = this); + ^~~~ + { dg-end-multiline-output "" } */ + +void template_inside_fn () +{ + int i = template < // { dg-error "cannot appear at block scope" } +/* { dg-begin-multiline-output "" } + int i = template < + ^~~~~~~~ + { dg-end-multiline-output "" } */ +} -- 1.8.5.3