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