C++ PATCH for c++/89217 - ICE with list-initialization in range-based for loop
Marek Polacek
polacek@redhat.com
Thu Feb 7 23:03:00 GMT 2019
Since r268321 we can call digest_init even in a template, when the compound
literal isn't instantiation-dependent. Consequently, when we get to
case RANGE_FOR_STMT in tsubst_expr, RANGE_FOR_EXPR might already have been
digested, as in this case, where before digesting it was
{*((struct S *) this)->r}
and now it's
TARGET_EXPR <D.2334, {.r=(struct R &) (struct R *) ((struct S *) this)->r}>
(that's correct). Now, in tsubst_expr, we recurse on the latter:
17095 expr = RECUR (RANGE_FOR_EXPR (t));
and since the expression contains a COMPONENT_REF, we end up calling
finish_non_static_data_member which calls build_class_member_access_expr
with preserve_reference=false. Thus, after we've tsubst'd the RANGE_FOR_EXPR,
we have
TARGET_EXPR <D.2344, {.r=(struct R &) (struct R *) (struct R &) (struct R *) *((struct S *) this)->r}>
Nevermind those casts, but "(struct R *) *((struct S *) this)->r" causes
problems later in cp_fold -> cp_convert_to_pointer because we're trying to
convert "*((struct S *) this)->r" of type R to R *. That errors and the
error_mark_node causes grief.
My first attempt was to handle this in tsubst_copy_and_build's case
COMPONENT_REF, after the call to finish_non_static_data_member, but that
breaks -- we can't have a LHS of a MODIFY_EXPR of a reference type. So it
seems this needs to be handled closer to where it actually fails, for instance
in ocp_convert.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2019-02-07 Marek Polacek <polacek@redhat.com>
PR c++/89217 - ICE with list-initialization in range-based for loop.
* cvt.c (ocp_convert): Unwrap REFERENCE_REF_P in a COMPONENT_REF.
* g++.dg/cpp0x/range-for37.C: New test.
diff --git gcc/cp/cvt.c gcc/cp/cvt.c
index 82a44f353c7..92677cff0c5 100644
--- gcc/cp/cvt.c
+++ gcc/cp/cvt.c
@@ -857,7 +857,15 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
return ignore_overflows (converted, e);
}
if (INDIRECT_TYPE_P (type) || TYPE_PTRMEM_P (type))
- return cp_convert_to_pointer (type, e, dofold, complain);
+ {
+ /* Undo what finish_non_static_data_member might have done, i.e.
+ turning e.g. (R *)((S *)this)->r into (R *)*((S *)this)->r,
+ rendering the conversion invalid. */
+ if (REFERENCE_REF_P (e)
+ && TREE_CODE (TREE_OPERAND (e, 0)) == COMPONENT_REF)
+ e = TREE_OPERAND (e, 0);
+ return cp_convert_to_pointer (type, e, dofold, complain);
+ }
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
diff --git gcc/testsuite/g++.dg/cpp0x/range-for37.C gcc/testsuite/g++.dg/cpp0x/range-for37.C
new file mode 100644
index 00000000000..d5c7c091d96
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp0x/range-for37.C
@@ -0,0 +1,24 @@
+// PR c++/89217
+// { dg-do compile { target c++11 } }
+
+struct R {};
+
+struct C
+{
+ R* begin() const { return &r; }
+ R* end() const { return &r; }
+
+ R& r;
+};
+
+struct S
+{
+ void f1() { f2<true>(); }
+ R& r;
+
+ template<bool>
+ void f2()
+ {
+ for (auto i : C{r}) {}
+ }
+};
More information about the Gcc-patches
mailing list