From 113459fad35faf22bcc72cee950e8f2ae573eb6f Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Wed, 21 Jun 2017 16:11:36 +0000 Subject: [PATCH] C++: Add fix-it hints for -Wold-style-cast gcc/cp/ChangeLog: * parser.c (get_cast_suggestion): New function. (maybe_add_cast_fixit): New function. (cp_parser_cast_expression): Capture the location of the closing parenthesis. Call maybe_add_cast_fixit when emitting warnings about old-style casts. gcc/testsuite/ChangeLog: * g++.dg/other/old-style-cast-fixits.C: New test case. From-SVN: r249461 --- gcc/cp/ChangeLog | 8 ++ gcc/cp/parser.c | 94 +++++++++++++++++- gcc/testsuite/ChangeLog | 4 + .../g++.dg/other/old-style-cast-fixits.C | 95 +++++++++++++++++++ 4 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/other/old-style-cast-fixits.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 01230c09f02..7d50a0b74f8 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2017-06-21 David Malcolm + + * parser.c (get_cast_suggestion): New function. + (maybe_add_cast_fixit): New function. + (cp_parser_cast_expression): Capture the location of the closing + parenthesis. Call maybe_add_cast_fixit when emitting warnings + about old-style casts. + 2017-06-20 Jason Merrill PR c++/80972 - C++17 ICE with attribute packed. diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 4adf9aac830..37f9154c4ae 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -8636,6 +8636,85 @@ cp_parser_tokens_start_cast_expression (cp_parser *parser) } } +/* Try to find a legal C++-style cast to DST_TYPE for ORIG_EXPR, trying them + in the order: const_cast, static_cast, reinterpret_cast. + + Don't suggest dynamic_cast. + + Return the first legal cast kind found, or NULL otherwise. */ + +static const char * +get_cast_suggestion (tree dst_type, tree orig_expr) +{ + tree trial; + + /* Reuse the parser logic by attempting to build the various kinds of + cast, with "complain" disabled. + Identify the first such cast that is valid. */ + + /* Don't attempt to run such logic within template processing. */ + if (processing_template_decl) + return NULL; + + /* First try const_cast. */ + trial = build_const_cast (dst_type, orig_expr, tf_none); + if (trial != error_mark_node) + return "const_cast"; + + /* If that fails, try static_cast. */ + trial = build_static_cast (dst_type, orig_expr, tf_none); + if (trial != error_mark_node) + return "static_cast"; + + /* Finally, try reinterpret_cast. */ + trial = build_reinterpret_cast (dst_type, orig_expr, tf_none); + if (trial != error_mark_node) + return "reinterpret_cast"; + + /* No such cast possible. */ + return NULL; +} + +/* If -Wold-style-cast is enabled, add fix-its to RICHLOC, + suggesting how to convert a C-style cast of the form: + + (DST_TYPE)ORIG_EXPR + + to a C++-style cast. + + The primary range of RICHLOC is asssumed to be that of the original + expression. OPEN_PAREN_LOC and CLOSE_PAREN_LOC give the locations + of the parens in the C-style cast. */ + +static void +maybe_add_cast_fixit (rich_location *rich_loc, location_t open_paren_loc, + location_t close_paren_loc, tree orig_expr, + tree dst_type) +{ + /* This function is non-trivial, so bail out now if the warning isn't + going to be emitted. */ + if (!warn_old_style_cast) + return; + + /* Try to find a legal C++ cast, trying them in order: + const_cast, static_cast, reinterpret_cast. */ + const char *cast_suggestion = get_cast_suggestion (dst_type, orig_expr); + if (!cast_suggestion) + return; + + /* Replace the open paren with "CAST_SUGGESTION<". */ + pretty_printer pp; + pp_printf (&pp, "%s<", cast_suggestion); + rich_loc->add_fixit_replace (open_paren_loc, pp_formatted_text (&pp)); + + /* Replace the close paren with "> (". */ + rich_loc->add_fixit_replace (close_paren_loc, "> ("); + + /* Add a closing paren after the expr (the primary range of RICH_LOC). */ + rich_loc->add_fixit_insert_after (")"); +} + + /* Parse a cast-expression. cast-expression: @@ -8671,6 +8750,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, /* Consume the `('. */ cp_token *open_paren = cp_lexer_consume_token (parser->lexer); location_t open_paren_loc = open_paren->location; + location_t close_paren_loc = UNKNOWN_LOCATION; /* A very tricky bit is that `(struct S) { 3 }' is a compound-literal (which we permit in C++ as an extension). @@ -8733,7 +8813,10 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, /* Look for the type-id. */ type = cp_parser_type_id (parser); /* Look for the closing `)'. */ - cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + cp_token *close_paren + = cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); + if (close_paren) + close_paren_loc = close_paren->location; parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p; } @@ -8763,8 +8846,13 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p, && !in_system_header_at (input_location) && !VOID_TYPE_P (type) && current_lang_name != lang_name_c) - warning (OPT_Wold_style_cast, - "use of old-style cast to %qT", type); + { + gcc_rich_location rich_loc (input_location); + maybe_add_cast_fixit (&rich_loc, open_paren_loc, close_paren_loc, + expr, type); + warning_at_rich_loc (&rich_loc, OPT_Wold_style_cast, + "use of old-style cast to %qT", type); + } /* Only type conversions to integral or enumeration types can be used in constant-expressions. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a23b04c3af6..446e234a1e2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2017-06-21 David Malcolm + + * g++.dg/other/old-style-cast-fixits.C: New test case. + 2017-06-21 Jakub Jelinek * g++.dg/cpp0x/constexpr-cast.C: Adjust dg-error for ILP32. diff --git a/gcc/testsuite/g++.dg/other/old-style-cast-fixits.C b/gcc/testsuite/g++.dg/other/old-style-cast-fixits.C new file mode 100644 index 00000000000..a10b623f981 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/old-style-cast-fixits.C @@ -0,0 +1,95 @@ +// { dg-options "-Wold-style-cast -fdiagnostics-show-caret" } + +struct foo {}; +struct bar { const foo *field; }; + +void test_1 (void *ptr) +{ + foo *f = (foo *)ptr; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr; + ^~~ + ---------- + static_cast (ptr) + { dg-end-multiline-output "" } */ +} + +void test_2 (const foo *ptr) +{ + foo *f = (foo *)ptr; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr; + ^~~ + ---------- + const_cast (ptr) + { dg-end-multiline-output "" } */ +} + +void test_3 (bar *ptr) +{ + foo *f = (foo *)ptr; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr; + ^~~ + ---------- + reinterpret_cast (ptr) + { dg-end-multiline-output "" } */ +} + +void test_4 (bar *ptr) +{ + foo *f = (foo *)ptr->field; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr->field; + ^~~~~ + ----------------- + const_cast (ptr->field) + { dg-end-multiline-output "" } */ +} + +void test_5 () +{ + bar b_inst; + foo *f = (foo *)&b_inst; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)&b_inst; + ^~~~~~ + -------------- + reinterpret_cast (&b_inst) + { dg-end-multiline-output "" } */ +} + +/* We don't offer suggestions for templates. */ + +template +void test_6 (void *ptr) +{ + foo *f = (foo *)ptr; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr; + ^~~ + { dg-end-multiline-output "" } */ +} + +/* We don't offer suggestions where a single C++-style cast can't be + used. */ + +void test_7 (const void *ptr) +{ + foo *f = (foo *)ptr; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)ptr; + ^~~ + { dg-end-multiline-output "" } */ +} + +/* Likewise, no single C++-style cast is usable here. */ + +void test_8 (const bar &b_inst) +{ + foo *f = (foo *)&b_inst; // { dg-warning "old-style cast" } + /* { dg-begin-multiline-output "" } + foo *f = (foo *)&b_inst; + ^~~~~~ + { dg-end-multiline-output "" } */ +} -- 2.30.2