From 1e2471e18372d73e1d622350ec259dc420551201 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 31 Aug 2015 14:29:53 -0400
Subject: [PATCH 23/43] C++ FE: Use token ranges for various diagnostics

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 68b4b8f..0d7ff90 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -3754,6 +3754,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);
@@ -3787,11 +3789,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);
@@ -4777,7 +4785,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;
 	    }
@@ -4900,7 +4908,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;
@@ -17200,7 +17208,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))
@@ -17973,7 +17981,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.  */
@@ -22429,10 +22437,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);
@@ -23384,10 +23392,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)
@@ -23415,7 +23425,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;
 	}
@@ -23434,7 +23444,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");
@@ -24804,7 +24814,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)
@@ -25075,11 +25085,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))
@@ -25089,7 +25099,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;
@@ -25099,7 +25109,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);
@@ -25158,8 +25168,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

