From 5078afd929259de5d2b3f1803f3695fbb97d4350 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 13 Jun 2016 13:19:51 -0400
Subject: [PATCH 09/22] FIXME: C: WIP on spellchecked labels

---
 gcc/c-family/c-common.c                      |  2 +-
 gcc/c-family/c-common.h                      |  2 +-
 gcc/c/c-decl.c                               | 36 ++++++++++++++++++++--------
 gcc/c/c-parser.c                             |  5 ++--
 gcc/c/c-tree.h                               |  4 ++--
 gcc/c/c-typeck.c                             | 10 ++++----
 gcc/cp/decl.c                                |  4 ++--
 gcc/cp/parser.c                              |  2 +-
 gcc/cp/pt.c                                  |  2 +-
 gcc/cp/semantics.c                           |  2 +-
 gcc/testsuite/gcc.dg/WIP-spellcheck-labels.c |  9 +++++++
 11 files changed, 52 insertions(+), 26 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/WIP-spellcheck-labels.c

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 85f3a03..e265535 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -6393,7 +6393,7 @@ finish_label_address_expr (tree label, location_t loc)
   if (label == error_mark_node)
     return error_mark_node;
 
-  label = lookup_label (label);
+  label = lookup_label (label, loc);
   if (label == NULL_TREE)
     result = null_pointer_node;
   else
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 3ad5400..aceb05c 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -986,7 +986,7 @@ extern tree finish_label_address_expr (tree, location_t);
 
 /* Same function prototype, but the C and C++ front ends have
    different implementations.  Used in c-common.c.  */
-extern tree lookup_label (tree);
+extern tree lookup_label (tree, location_t);
 extern tree lookup_name (tree);
 extern bool lvalue_p (const_tree);
 
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 8b966fe..c872b81 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1194,7 +1194,18 @@ pop_scope (void)
 	  /* Warnings for unused labels, errors for undefined labels.  */
 	  if (TREE_USED (p) && !DECL_INITIAL (p))
 	    {
-	      error ("label %q+D used but not defined", p);
+	      // TODO:
+	      tree hint = NULL_TREE;
+	      //lookup_name_fuzzy (DECL_NAME (p),
+	      //                   FUZZY_LOOKUP_LABEL);
+	      if (hint)
+		error_at (DECL_SOURCE_LOCATION (p),
+			  "label %q+D used but not defined;"
+			  " did you mean %q+D?",
+			  p, hint);
+	      else
+		error_at (DECL_SOURCE_LOCATION (p),
+			  "label %q+D used but not defined", p);
 	      DECL_INITIAL (p) = error_mark_node;
 	    }
 	  else
@@ -3508,14 +3519,14 @@ make_label (location_t location, tree name, bool defining,
    has its address taken.  */
 
 tree
-lookup_label (tree name)
+lookup_label (tree name, location_t loc)
 {
   tree label;
   struct c_label_vars *label_vars;
 
   if (current_function_scope == 0)
     {
-      error ("label %qE referenced outside of any function", name);
+      error_at (loc, "label %qE referenced outside of any function", name);
       return NULL_TREE;
     }
 
@@ -3530,12 +3541,12 @@ lookup_label (tree name)
 	 location to point here, for better diagnostics if it
 	 turns out not to have been defined.  */
       if (DECL_INITIAL (label) == NULL_TREE)
-	DECL_SOURCE_LOCATION (label) = input_location;
+	DECL_SOURCE_LOCATION (label) = loc;
       return label;
     }
 
   /* No label binding for that identifier; make one.  */
-  label = make_label (input_location, name, false, &label_vars);
+  label = make_label (loc, name, false, &label_vars);
 
   /* Ordinary labels go in the current function scope.  */
   bind_label (name, label, current_function_scope, label_vars);
@@ -3563,14 +3574,14 @@ warn_about_goto (location_t goto_loc, tree label, tree decl)
    lookup_label, but also issues any appropriate warnings.  */
 
 tree
-lookup_label_for_goto (location_t loc, tree name)
+lookup_label_for_goto (location_t goto_loc, tree name, location_t label_loc)
 {
   tree label;
   struct c_label_vars *label_vars;
   unsigned int ix;
   tree decl;
 
-  label = lookup_label (name);
+  label = lookup_label (name, label_loc);
   if (label == NULL_TREE)
     return NULL_TREE;
 
@@ -3590,7 +3601,7 @@ lookup_label_for_goto (location_t loc, tree name)
     {
       c_goto_bindings *g = ggc_alloc<c_goto_bindings> ();
 
-      g->loc = loc;
+      g->loc = goto_loc;
       set_spot_bindings (&g->goto_bindings, true);
       vec_safe_push (label_vars->gotos, g);
       return label;
@@ -3605,11 +3616,11 @@ lookup_label_for_goto (location_t loc, tree name)
        goto lab;
      Issue a warning or error.  */
   FOR_EACH_VEC_SAFE_ELT (label_vars->decls_in_scope, ix, decl)
-    warn_about_goto (loc, label, decl);
+    warn_about_goto (goto_loc, label, decl);
 
   if (label_vars->label_bindings.left_stmt_expr)
     {
-      error_at (loc, "jump into statement expression");
+      error_at (goto_loc, "jump into statement expression");
       inform (DECL_SOURCE_LOCATION (label), "label %qD defined here", label);
     }
 
@@ -4032,6 +4043,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind)
 	  if (TREE_CODE (binding->decl) != TYPE_DECL)
 	    continue;
 	bm.consider (binding->id);
+#if 0
+	if (kind == FUZZY_LOOKUP_LABEL)
+	  if (TREE_CODE (binding->decl) != LABEL_DECL)
+	    continue;
+#endif
       }
 
   /* Consider macros: if the user misspelled a macro name e.g. "SOME_MACRO"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index db36a00..cbd2afe 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -5229,7 +5229,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
 	  if (c_parser_next_token_is (parser, CPP_NAME))
 	    {
 	      stmt = c_finish_goto_label (loc,
-					  c_parser_peek_token (parser)->value);
+					  c_parser_peek_token (parser)->value,
+					  c_parser_peek_token (parser)->location);
 	      c_parser_consume_token (parser);
 	    }
 	  else if (c_parser_next_token_is (parser, CPP_MULT))
@@ -6275,7 +6276,7 @@ c_parser_asm_goto_operands (c_parser *parser)
 	{
 	  c_token *tok = c_parser_peek_token (parser);
 	  name = tok->value;
-	  label = lookup_label_for_goto (tok->location, name);
+	  label = lookup_label_for_goto (tok->location, name, tok->location);
 	  c_parser_consume_token (parser);
 	  TREE_USED (label) = 1;
 	}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 46be53e..5e5c6ff 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -514,7 +514,7 @@ 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 tree lookup_label_for_goto (location_t, tree);
+extern tree lookup_label_for_goto (location_t, tree, location_t);
 extern tree declare_label (tree);
 extern tree define_label (location_t, tree);
 extern struct c_spot_bindings *c_get_switch_bindings (void);
@@ -660,7 +660,7 @@ 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_goto_label (location_t, tree);
+extern tree c_finish_goto_label (location_t, tree, location_t);
 extern tree c_finish_goto_ptr (location_t, tree);
 extern tree c_expr_to_decl (tree, bool *, bool *);
 extern tree c_finish_omp_construct (location_t, enum tree_code, tree, tree);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index f03c07b..4d106e3 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -9640,19 +9640,19 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
   return args;
 }
 
-/* Generate a goto statement to LABEL.  LOC is the location of the
-   GOTO.  */
+/* Generate a goto statement to LABEL.  GOTO_LOC is the location of the
+   GOTO; LABEL_LOC is the location of the label.  */
 
 tree
-c_finish_goto_label (location_t loc, tree label)
+c_finish_goto_label (location_t goto_loc, tree label, location_t label_loc)
 {
-  tree decl = lookup_label_for_goto (loc, label);
+  tree decl = lookup_label_for_goto (goto_loc, label, label_loc);
   if (!decl)
     return NULL_TREE;
   TREE_USED (decl) = 1;
   {
     tree t = build1 (GOTO_EXPR, void_type_node, decl);
-    SET_EXPR_LOCATION (t, loc);
+    SET_EXPR_LOCATION (t, goto_loc);
     return add_stmt (t);
   }
 }
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 415689f..a678de8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2949,7 +2949,7 @@ lookup_label_1 (tree id)
 /* Wrapper for lookup_label_1.  */
 
 tree
-lookup_label (tree id)
+lookup_label (tree id, location_t)
 {
   tree ret;
   bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
@@ -3293,7 +3293,7 @@ define_label_1 (location_t location, tree name)
   cp_binding_level *p;
   tree decl;
 
-  decl = lookup_label (name);
+  decl = lookup_label (name, location);
 
   dummy.label_decl = decl;
   ent = named_labels->find (&dummy);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 902006b..fe225ae 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -23564,7 +23564,7 @@ cp_parser_asm_label_list (cp_parser* parser)
       identifier = cp_parser_identifier (parser);
       if (!error_operand_p (identifier))
         {
-	  label = lookup_label (identifier);
+	  label = lookup_label (identifier, input_location);
 	  if (TREE_CODE (label) == LABEL_DECL)
 	    {
 	      TREE_USED (label) = 1;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 3a3d9b8..870fea5 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -14809,7 +14809,7 @@ tsubst_copy_asm_operands (tree t, tree args, tsubst_flags_t complain,
 	value = RECUR (value);
       else
 	{
-	  value = lookup_label (DECL_NAME (value));
+	  value = lookup_label (DECL_NAME (value), input_location);
 	  gcc_assert (TREE_CODE (value) == LABEL_DECL);
 	  TREE_USED (value) = 1;
 	}
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 5365091..14556af 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -601,7 +601,7 @@ tree
 finish_goto_stmt (tree destination)
 {
   if (identifier_p (destination))
-    destination = lookup_label (destination);
+    destination = lookup_label (destination, input_location);
 
   /* We warn about unused labels with -Wunused.  That means we have to
      mark the used labels as used.  */
diff --git a/gcc/testsuite/gcc.dg/WIP-spellcheck-labels.c b/gcc/testsuite/gcc.dg/WIP-spellcheck-labels.c
new file mode 100644
index 0000000..c544b40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/WIP-spellcheck-labels.c
@@ -0,0 +1,9 @@
+int
+test_1 (int i)
+{
+  if (i > 10)
+    goto error; /* { dg-error "10: label .error. used but not defined" } */
+  return 1;
+ err:
+  return 0;
+}
-- 
1.8.5.3

