This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] C++: better locations for bogus initializations (PR c++/88375)
- From: David Malcolm <dmalcolm at redhat dot com>
- To: jason at redhat dot com, gcc-patches at gcc dot gnu dot org
- Cc: David Malcolm <dmalcolm at redhat dot com>
- Date: Tue, 11 Dec 2018 17:55:33 -0500
- Subject: [PATCH] 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.
This patch relies on:
"[PATCH 1/2] v3: C++: more location wrapper nodes (PR c++/43064, PR c++/43486)"
https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00500.html
and:
"[PATCH 2/2] v2: C++: improvements to binary operator diagnostics (PR
c++/87504)"
https://gcc.gnu.org/ml/gcc-patches/2018-12/msg00236.html
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu, on top of
those patches.
OK for trunk, if those patches are approved?
Thanks
Dave
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.
---
gcc/cp/typeck.c | 43 +++++++++++++++++++++--------------
gcc/cp/typeck2.c | 10 ++++----
gcc/testsuite/g++.dg/init/pr88375-2.C | 41 +++++++++++++++++++++++++++++++++
gcc/testsuite/g++.dg/init/pr88375.C | 26 +++++++++++++++++++++
4 files changed, 99 insertions(+), 21 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/init/pr88375-2.C
create mode 100644 gcc/testsuite/g++.dg/init/pr88375.C
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ded6b24..4191a5d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -8824,6 +8824,9 @@ convert_for_assignment (tree type, tree rhs,
tree rhstype;
enum tree_code coder;
+ location_t loc = cp_expr_loc_or_loc (rhs, input_location);
+ bool has_loc = cp_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
@@ -8864,7 +8867,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 (loc, "void value not ignored as it ought to be");
return error_mark_node;
}
@@ -8936,35 +8939,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 (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))
@@ -9031,8 +9042,6 @@ 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,
"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 c1fa4a9..209832b 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/g++.dg/init/pr88375-2.C b/gcc/testsuite/g++.dg/init/pr88375-2.C
new file mode 100644
index 0000000..97ed72e
--- /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 0000000..21dd6c1
--- /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'" }
+};
--
1.8.5.3