From: David Malcolm Date: Wed, 19 Dec 2018 15:22:27 +0000 (+0000) Subject: C++: better locations for bogus initializations (PR c++/88375) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=15c40a3b7ce64665f8b4552a45c0cdd9564598cc;p=gcc.git C++: better locations for bogus initializations (PR c++/88375) PR c++/88375 reports that errors relating to invalid conversions in initializations are reported at unhelpfully vague locations, as in e.g.: enum struct a : int { one, two }; struct foo { int e1, e2; a e3; } arr[] = { { 1, 2, a::one }, { 3, a::two }, { 4, 5, a::two } }; for which g++ trunk emits the vague: pr88375.cc:12:1: error: cannot convert 'a' to 'int' in initialization 12 | }; | ^ with the error at the final closing brace. This patch uses location information for the initializers, converting the above to: pr88375.cc:10:11: error: cannot convert 'a' to 'int' in initialization 10 | { 3, a::two }, | ~~~^~~ | | | a highlighting which subexpression is problematic, and its type. Ideally we'd also issue a note showing the field decl being initialized, but that turned out to be more invasive. gcc/cp/ChangeLog: PR c++/88375 * typeck.c (convert_for_assignment): Capture location of rhs before stripping, and if available. Use the location when complaining about bad conversions, labelling it with the rhstype if the location was present. * typeck2.c (digest_init_r): Capture location of init before stripping. gcc/testsuite/ChangeLog: PR c++/88375 * g++.dg/init/pr88375-2.C: New test. * g++.dg/init/pr88375.C: New test. From-SVN: r267276 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index beae2659c74..7b794612c8b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,13 @@ +2018-12-19 David Malcolm + + PR c++/88375 + * typeck.c (convert_for_assignment): Capture location of rhs + before stripping, and if available. Use the location when + complaining about bad conversions, labelling it with the + rhstype if the location was present. + * typeck2.c (digest_init_r): Capture location of init before + stripping. + 2018-12-19 David Malcolm PR c++/87504 diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 94a33d41dba..ef317f5cc7d 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -8852,6 +8852,7 @@ convert_for_assignment (tree type, tree rhs, enum tree_code coder; location_t rhs_loc = EXPR_LOC_OR_LOC (rhs, input_location); + bool has_loc = EXPR_LOCATION (rhs) != UNKNOWN_LOCATION; /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue, but preserve location wrappers. */ if (TREE_CODE (rhs) == NON_LVALUE_EXPR @@ -8892,7 +8893,7 @@ convert_for_assignment (tree type, tree rhs, if (coder == VOID_TYPE) { if (complain & tf_error) - error ("void value not ignored as it ought to be"); + error_at (rhs_loc, "void value not ignored as it ought to be"); return error_mark_node; } @@ -8964,35 +8965,43 @@ convert_for_assignment (tree type, tree rhs, rhstype, type, fndecl, parmnum); else - switch (errtype) - { + { + range_label_for_type_mismatch label (rhstype, type); + gcc_rich_location richloc (rhs_loc, has_loc ? &label : NULL); + switch (errtype) + { case ICR_DEFAULT_ARGUMENT: - error ("cannot convert %qH to %qI in default argument", - rhstype, type); + error_at (&richloc, + "cannot convert %qH to %qI in default argument", + rhstype, type); break; case ICR_ARGPASS: - error ("cannot convert %qH to %qI in argument passing", - rhstype, type); + error_at (&richloc, + "cannot convert %qH to %qI in argument passing", + rhstype, type); break; case ICR_CONVERTING: - error ("cannot convert %qH to %qI", - rhstype, type); + error_at (&richloc, "cannot convert %qH to %qI", + rhstype, type); break; case ICR_INIT: - error ("cannot convert %qH to %qI in initialization", - rhstype, type); + error_at (&richloc, + "cannot convert %qH to %qI in initialization", + rhstype, type); break; case ICR_RETURN: - error ("cannot convert %qH to %qI in return", - rhstype, type); + error_at (&richloc, "cannot convert %qH to %qI in return", + rhstype, type); break; case ICR_ASSIGN: - error ("cannot convert %qH to %qI in assignment", - rhstype, type); + error_at (&richloc, + "cannot convert %qH to %qI in assignment", + rhstype, type); break; default: gcc_unreachable(); } + } if (TYPE_PTR_P (rhstype) && TYPE_PTR_P (type) && CLASS_TYPE_P (TREE_TYPE (rhstype)) @@ -9059,9 +9068,7 @@ convert_for_assignment (tree type, tree rhs, && TREE_CODE (TREE_TYPE (rhs)) != BOOLEAN_TYPE && (complain & tf_warning)) { - location_t loc = cp_expr_loc_or_loc (rhs, input_location); - - warning_at (loc, OPT_Wparentheses, + warning_at (rhs_loc, OPT_Wparentheses, "suggest parentheses around assignment used as truth value"); TREE_NO_WARNING (rhs) = 1; } diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index c1fa4a94843..209832b19ea 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1050,14 +1050,16 @@ digest_init_r (tree type, tree init, int nested, int flags, complain)) return error_mark_node; + location_t loc = cp_expr_loc_or_loc (init, input_location); + + tree stripped_init = init; + /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue (g++.old-deja/g++.law/casts2.C). */ if (TREE_CODE (init) == NON_LVALUE_EXPR) - init = TREE_OPERAND (init, 0); - - location_t loc = cp_expr_loc_or_loc (init, input_location); + stripped_init = TREE_OPERAND (init, 0); - tree stripped_init = tree_strip_any_location_wrapper (init); + stripped_init = tree_strip_any_location_wrapper (stripped_init); /* Initialization of an array of chars from a string constant. The initializer can be optionally enclosed in braces, but reshape_init has already removed diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 4a613382a07..b996242f00b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2018-12-19 David Malcolm + + PR c++/88375 + * g++.dg/init/pr88375-2.C: New test. + * g++.dg/init/pr88375.C: New test. + 2018-12-19 David Malcolm * c-c++-common/Wtautological-compare-ranges.c: New test. diff --git a/gcc/testsuite/g++.dg/init/pr88375-2.C b/gcc/testsuite/g++.dg/init/pr88375-2.C new file mode 100644 index 00000000000..97ed72e7a61 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pr88375-2.C @@ -0,0 +1,41 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-fdiagnostics-show-caret" } + +enum struct a : int { + one, two +}; + +constexpr int fn () { return 42; } + +struct foo { + int e1, e2; + a e3; +} arr[] = { + { 3, a::two }, // { dg-error "11: cannot convert 'a' to 'int' in initialization" } + /* { dg-begin-multiline-output "" } + { 3, a::two }, + ~~~^~~ + | + a + { dg-end-multiline-output "" } */ + { 6, 7, fn() }, // { dg-error "13: cannot convert 'int' to 'a' in initialization" } + /* { dg-begin-multiline-output "" } + { 6, 7, fn() }, + ~~^~ + | + int + { dg-end-multiline-output "" } */ +}; + +struct bar { + const char *f1; + int f2; +} arr_2[] = { + { 42 }, // { dg-error "5: invalid conversion from 'int' to 'const char\\*'" } + /* { dg-begin-multiline-output "" } + { 42 }, + ^~ + | + int + { dg-end-multiline-output "" } */ +}; diff --git a/gcc/testsuite/g++.dg/init/pr88375.C b/gcc/testsuite/g++.dg/init/pr88375.C new file mode 100644 index 00000000000..21dd6c1006f --- /dev/null +++ b/gcc/testsuite/g++.dg/init/pr88375.C @@ -0,0 +1,26 @@ +// { dg-do compile { target c++11 } } + +enum struct a : int { + one, two +}; + +constexpr int fn () { return 42; } + +struct foo { + int e1, e2; + a e3; +} arr[] = { + { 1, 2, a::one }, + { 3, a::two }, // { dg-error "11: cannot convert 'a' to 'int' in initialization" } + { 6, 7, 8 }, // { dg-error "11: cannot convert 'int' to 'a' in initialization" } + { 6, 7, fn() }, // { dg-error "13: cannot convert 'int' to 'a' in initialization" } +}; + +struct bar { + const char *f1; + int f2; +} arr_2[] = { + { "hello world", 42 }, + { 42 }, // { dg-error "5: invalid conversion from 'int' to 'const char\\*'" } + { "hello", "world" }, // { dg-error "14: invalid conversion from 'const char\\*' to 'int'" } +};