From 30201e16fa4907d8db81e862f7d821604127a1cc Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Tue, 1 Sep 2015 13:13:06 -0400
Subject: [PATCH 11/42] C frontend: use token ranges in various diagnostics

This patch makes use of token ranges in the C frontend to add underlines
to various diagnostics.

Screenshot:
 https://dmalcolm.fedorapeople.org/gcc/2015-09-09/diagnostic-token-ranges.html

gcc/c/ChangeLog:
	* c-decl.c (undeclared_variable): Convert param "loc" from a
	location_t to a source_range.
	* c-parser.c (c_lex_one_token): Use token's range rather than
	location for "identifier conflicts with C++ keyword" warning.
	(c_parser_declaration_or_fndef): Convert local "here" from a
	location_t to a source_range.
	(c_parser_parms_list_declarator): Use token's range rather than
	location for "ISO C requires a named argument before ..." warning.
	(c_parser_parameter_declaration): Likewise for "unknown type name"
	error.
	(c_parser_asm_string_literal): Likewise for
	"wide string literal in asm" error.
	(c_parser_label): Likewise for label-before-declaration error, and
	show the label's range to the error.
	(c_parser_statement_after_labels): Pass the token's range rather
	than location to c_finish_bc_stmt.
	(c_parser_postfix_expression): Likewise for call to
	build_external_ref.
	(c_parser_omp_variable_list): Likewise for call to
	undeclared_variable.
	* c-tree.h (undeclared_variable): Convert initial param from
	location_t to source_range.
	(build_external_ref): Likewise.
	(c_finish_bc_stmt): Likewise.
	* c-typeck.c (build_external_ref): Likewise.
	(c_finish_bc_stmt): Likewise.

gcc/testsuite/ChangeLog:
	* gcc.dg/diagnostic-token-ranges.c: New file.
---
 gcc/c/c-decl.c                                 |   2 +-
 gcc/c/c-parser.c                               |  31 ++++---
 gcc/c/c-tree.h                                 |   6 +-
 gcc/c/c-typeck.c                               |  22 ++---
 gcc/testsuite/gcc.dg/diagnostic-token-ranges.c | 109 +++++++++++++++++++++++++
 5 files changed, 143 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/diagnostic-token-ranges.c

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index e6b6ba5..9fe8aa4 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -3409,7 +3409,7 @@ implicitly_declare (location_t loc, tree functionid)
    in an appropriate scope, which will suppress further errors for the
    same identifier.  The error message should be given location LOC.  */
 void
-undeclared_variable (location_t loc, tree id)
+undeclared_variable (source_range loc, tree id)
 {
   static bool already = false;
   struct c_scope *scope;
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5d822ee..1c93d39 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -266,7 +266,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
 
 	    if (rid_code == RID_CXX_COMPAT_WARN)
 	      {
-		warning_at (token->location,
+		warning_at (token->range,
 			    OPT_Wc___compat,
 			    "identifier %qE conflicts with C++ keyword",
 			    token->value);
@@ -1526,7 +1526,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
   tree prefix_attrs;
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
-  location_t here = c_parser_peek_token (parser)->location;
+  source_range here = c_parser_peek_token (parser)->range;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -3575,7 +3575,7 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
         {
           /* Suppress -Wold-style-definition for this case.  */
           ret->types = error_mark_node;
-          error_at (c_parser_peek_token (parser)->location,
+          error_at (c_parser_peek_token (parser)->range,
                     "ISO C requires a named argument before %<...%>");
         }
       c_parser_consume_token (parser);
@@ -3670,7 +3670,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
       c_parser_set_source_position_from_token (token);
       if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
 	{
-	  error_at (token->location, "unknown type name %qE", token->value);
+	  error_at (token->range, "unknown type name %qE", token->value);
 	  parser->error = true;
 	}
       /* ??? In some Objective-C cases '...' isn't applicable so there
@@ -3731,7 +3731,7 @@ c_parser_asm_string_literal (c_parser *parser)
     }
   else if (c_parser_next_token_is (parser, CPP_WSTRING))
     {
-      error_at (c_parser_peek_token (parser)->location,
+      error_at (c_parser_peek_token (parser)->range,
 		"wide string literal in %<asm%>");
       str = build_string (1, "");
       c_parser_consume_token (parser);
@@ -4749,6 +4749,7 @@ c_parser_all_labels (c_parser *parser)
 static void
 c_parser_label (c_parser *parser)
 {
+  source_range label_range = c_parser_peek_token (parser)->range;
   location_t loc1 = c_parser_peek_token (parser)->location;
   tree label = NULL_TREE;
   if (c_parser_next_token_is_keyword (parser, RID_CASE))
@@ -4799,9 +4800,11 @@ c_parser_label (c_parser *parser)
     {
       if (c_parser_next_tokens_start_declaration (parser))
 	{
-	  error_at (c_parser_peek_token (parser)->location,
-		    "a label can only be part of a statement and "
-		    "a declaration is not a statement");
+	  rich_location richloc (c_parser_peek_token (parser)->range);
+	  richloc.add_range (label_range);
+	  error_at_rich_loc (&richloc,
+			     "a label can only be part of a statement and "
+			     "a declaration is not a statement");
 	  c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
 					 /*static_assert_ok*/ true,
 					 /*empty_ok*/ true, /*nested*/ true,
@@ -4963,6 +4966,7 @@ static void
 c_parser_statement_after_labels (c_parser *parser)
 {
   location_t loc = c_parser_peek_token (parser)->location;
+  source_range tok_range = c_parser_peek_token (parser)->range;
   tree stmt = NULL_TREE;
   bool in_if_block = parser->in_if_block;
   parser->in_if_block = false;
@@ -5034,11 +5038,11 @@ c_parser_statement_after_labels (c_parser *parser)
 	  goto expect_semicolon;
 	case RID_CONTINUE:
 	  c_parser_consume_token (parser);
-	  stmt = c_finish_bc_stmt (loc, &c_cont_label, false);
+	  stmt = c_finish_bc_stmt (tok_range, &c_cont_label, false);
 	  goto expect_semicolon;
 	case RID_BREAK:
 	  c_parser_consume_token (parser);
-	  stmt = c_finish_bc_stmt (loc, &c_break_label, true);
+	  stmt = c_finish_bc_stmt (tok_range, &c_break_label, true);
 	  goto expect_semicolon;
 	case RID_RETURN:
 	  c_parser_consume_token (parser);
@@ -7128,6 +7132,7 @@ c_parser_postfix_expression (c_parser *parser)
   struct c_expr expr, e1;
   struct c_type_name *t1, *t2;
   location_t loc = c_parser_peek_token (parser)->location;;
+  source_range src_range = c_parser_peek_token (parser)->range;
   expr.original_code = ERROR_MARK;
   expr.original_type = NULL;
   switch (c_parser_peek_token (parser)->type)
@@ -7172,7 +7177,7 @@ c_parser_postfix_expression (c_parser *parser)
 	  {
 	    tree id = c_parser_peek_token (parser)->value;
 	    c_parser_consume_token (parser);
-	    expr.value = build_external_ref (loc, id,
+	    expr.value = build_external_ref (src_range, id,
 					     (c_parser_peek_token (parser)->type
 					      == CPP_OPEN_PAREN),
 					     &expr.original_type);
@@ -10165,7 +10170,7 @@ c_parser_omp_variable_list (c_parser *parser,
 
       if (t == NULL_TREE)
 	{
-	  undeclared_variable (c_parser_peek_token (parser)->location,
+	  undeclared_variable (c_parser_peek_token (parser)->range,
 			       c_parser_peek_token (parser)->value);
 	  t = error_mark_node;
 	}
@@ -14933,7 +14938,7 @@ c_parser_cilk_clause_linear (c_parser *parser, tree clauses)
 
       if (var == NULL)
 	{
-	  undeclared_variable (c_parser_peek_token (parser)->location,
+	  undeclared_variable (c_parser_peek_token (parser)->range,
 			       c_parser_peek_token (parser)->value);
 	c_parser_consume_token (parser);
 	}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index df1ebb6..4b0ec22 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -491,7 +491,7 @@ extern tree build_enumerator (location_t, location_t, struct c_enum_contents *,
 extern tree check_for_loop_decls (location_t, bool);
 extern void mark_forward_parm_decls (void);
 extern void declare_parm_level (void);
-extern void undeclared_variable (location_t, tree);
+extern void undeclared_variable (source_range, tree);
 extern tree lookup_label_for_goto (location_t, tree);
 extern tree declare_label (tree);
 extern tree define_label (location_t, tree);
@@ -595,7 +595,7 @@ extern void mark_exp_read (tree);
 extern tree composite_type (tree, tree);
 extern tree build_component_ref (location_t, tree, tree);
 extern tree build_array_ref (location_t, tree, tree);
-extern tree build_external_ref (location_t, tree, int, tree *);
+extern tree build_external_ref (source_range, tree, int, tree *);
 extern void pop_maybe_used (bool);
 extern struct c_expr c_expr_sizeof_expr (location_t, struct c_expr);
 extern struct c_expr c_expr_sizeof_type (location_t, struct c_type_name *);
@@ -636,7 +636,7 @@ extern tree c_finish_stmt_expr (location_t, tree);
 extern tree c_process_expr_stmt (location_t, tree);
 extern tree c_finish_expr_stmt (location_t, tree);
 extern tree c_finish_return (location_t, tree, tree);
-extern tree c_finish_bc_stmt (location_t, tree *, bool);
+extern tree c_finish_bc_stmt (source_range tok_range, tree *, bool);
 extern tree c_finish_goto_label (location_t, tree);
 extern tree c_finish_goto_ptr (location_t, tree);
 extern tree c_expr_to_decl (tree, bool *, bool *);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index dc22396..a755a7e 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2587,7 +2587,7 @@ build_array_ref (location_t loc, tree array, tree index)
    for CONST_DECLs defined as enum constants.  If the type of the
    identifier is not available, *TYPE is set to NULL.  */
 tree
-build_external_ref (location_t loc, tree id, int fun, tree *type)
+build_external_ref (source_range loc, tree id, int fun, tree *type)
 {
   tree ref;
   tree decl = lookup_name (id);
@@ -2604,7 +2604,7 @@ build_external_ref (location_t loc, tree id, int fun, tree *type)
     }
   else if (fun)
     /* Implicit function declaration.  */
-    ref = implicitly_declare (loc, id);
+    ref = implicitly_declare (loc.m_start, id);
   else if (decl == error_mark_node)
     /* Don't complain about something that's already been
        complained about.  */
@@ -2674,7 +2674,7 @@ build_external_ref (location_t loc, tree id, int fun, tree *type)
 	   && (!VAR_P (ref) || TREE_STATIC (ref))
 	   && ! TREE_PUBLIC (ref)
 	   && DECL_CONTEXT (ref) != current_function_decl)
-    record_inline_static (loc, current_function_decl, ref,
+    record_inline_static (loc.m_start, current_function_decl, ref,
 			  csi_internal);
 
   return ref;
@@ -9873,7 +9873,7 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
 }
 
 tree
-c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
+c_finish_bc_stmt (source_range tok_range, tree *label_p, bool is_break)
 {
   bool skip;
   tree label = *label_p;
@@ -9890,7 +9890,7 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
   if (!label)
     {
       if (!skip)
-	*label_p = label = create_artificial_label (loc);
+	*label_p = label = create_artificial_label (tok_range.m_start);
     }
   else if (TREE_CODE (label) == LABEL_DECL)
     ;
@@ -9898,21 +9898,23 @@ c_finish_bc_stmt (location_t loc, tree *label_p, bool is_break)
     {
     case 0:
       if (is_break)
-	error_at (loc, "break statement not within loop or switch");
+	error_at (tok_range, "break statement not within loop or switch");
       else
-	error_at (loc, "continue statement not within a loop");
+	error_at (tok_range, "continue statement not within a loop");
       return NULL_TREE;
 
     case 1:
       gcc_assert (is_break);
-      error_at (loc, "break statement used with OpenMP for loop");
+      error_at (tok_range, "break statement used with OpenMP for loop");
       return NULL_TREE;
 
     case 2:
       if (is_break) 
-	error ("break statement within %<#pragma simd%> loop body");
+	error_at (tok_range,
+		  "break statement within %<#pragma simd%> loop body");
       else 
-	error ("continue statement within %<#pragma simd%> loop body");
+	error_at (tok_range,
+		  "continue statement within %<#pragma simd%> loop body");
       return NULL_TREE;
 
     default:
diff --git a/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c b/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c
new file mode 100644
index 0000000..6bd9e0b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/diagnostic-token-ranges.c
@@ -0,0 +1,109 @@
+/* { dg-options "-fdiagnostics-show-caret -Wc++-compat" } */
+
+/* Verify that various diagnostics show source code ranges.  */
+
+/* These ones merely use token ranges; they don't use tree ranges.  */
+
+void undeclared_identifier (void)
+{
+  name; /* { dg-error "'name' undeclared" } */
+/*
+{ dg-begin-multiline-output "" }
+   name;
+   ^~~~
+{ dg-end-multiline-output "" }
+*/
+}
+
+void unknown_type_name (void)
+{
+  foo bar; /* { dg-error "unknown type name 'foo'" } */
+/*
+{ dg-begin-multiline-output "" }
+   foo bar;
+   ^~~
+{ dg-end-multiline-output "" }
+*/
+
+  qux *baz; /* { dg-error "unknown type name 'qux'" } */
+/*
+{ dg-begin-multiline-output "" }
+   qux *baz;
+   ^~~
+{ dg-end-multiline-output "" }
+*/
+}
+
+void test_identifier_conflicts_with_cplusplus (void)
+{
+  int new; /* { dg-warning "identifier 'new' conflicts with" } */
+/*
+{ dg-begin-multiline-output "" }
+   int new;
+       ^~~
+{ dg-end-multiline-output "" }
+*/
+}
+
+extern void
+bogus_varargs (...); /* { dg-error "ISO C requires a named argument before '...'" } */
+/*
+{ dg-begin-multiline-output "" }
+ bogus_varargs (...);
+                ^~~
+{ dg-end-multiline-output "" }
+*/
+
+extern void
+foo (unknown_type param); /* { dg-error "unknown type name 'unknown_type'" } */
+/*
+{ dg-begin-multiline-output "" }
+ foo (unknown_type param);
+      ^~~~~~~~~~~~
+{ dg-end-multiline-output "" }
+*/
+
+void wide_string_literal_in_asm (void)
+{
+  asm (L"nop"); /* { dg-error "wide string literal in 'asm'" } */
+/*
+{ dg-begin-multiline-output "" }
+   asm (L"nop");
+        ^~~~~~
+{ dg-end-multiline-output "" }
+*/
+}
+
+void label_in_front_of_decl (void)
+{
+ label:
+  int i; /* { dg-error "a label can only be part of a statement and a declaration is not a statement" } */
+/*
+{ dg-begin-multiline-output "" }
+  label:
+  ~~~~~
+   int i;
+   ^~~
+{ dg-end-multiline-output "" }
+*/
+  return;
+}
+
+void break_and_continue_in_wrong_places (void)
+{
+  if (0)
+    break; /* { dg-error "break statement not within loop or switch" } */
+/* { dg-begin-multiline-output "" }
+     break;
+     ^~~~~
+   { dg-end-multiline-output "" } */
+
+  if (1)
+    ;
+  else
+    continue; /* { dg-error "continue statement not within a loop" } */
+/* { dg-begin-multiline-output "" }
+     continue;
+     ^~~~~~~~
+    { dg-end-multiline-output "" } */
+}
-- 
1.8.5.3

