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

Reply via email to