c++: ICE with reference NSDMI [PR114854]
Checks
Context |
Check |
Description |
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_build--master-arm |
success
|
Testing passed
|
linaro-tcwg-bot/tcwg_gcc_check--master-arm |
success
|
Testing passed
|
Commit Message
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:
/* A TARGET_EXPR that expresses direct-initialization should have been
elided by cp_gimplify_init_expr. */
gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
the TARGET_EXPR in question is created for the NSDMI in:
class Vector { int m_size; };
struct S {
const Vector &vec{};
};
where we first need to create a Vector{} temporary, and then bind the
vec reference to it. The temporary is represented by a TARGET_EXPR
and it cannot be elided. When we create an object of type S, we get
D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}
where the TARGET_EXPR is no longer direct-initializing anything.
Perhaps we can clear the TARGET_EXPR_DIRECT_INIT_P flag when taking the
address of an TARGET_EXPR, like below. I'm also clearing _ELIDING_P
even though that's not necessary to fix this ICE.
PR c++/114854
gcc/cp/ChangeLog:
* typeck.cc (cp_build_addr_expr_1) <case TARGET_EXPR>: Clear
TARGET_EXPR_DIRECT_INIT_P and TARGET_EXPR_ELIDING_P.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1y/nsdmi-aggr22.C: New test.
---
gcc/cp/typeck.cc | 7 +++++++
gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C | 12 ++++++++++++
2 files changed, 19 insertions(+)
create mode 100644 gcc/testsuite/g++.dg/cpp1y/nsdmi-aggr22.C
base-commit: 80d1e2ec4d394111ebd50d2e8928f7596b7b5c7e
Comments
On 5/9/24 12:04, Marek Polacek wrote:
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
>
> -- >8 --
> Here we crash on a cp_gimplify_expr/TARGET_EXPR assert:
>
> /* A TARGET_EXPR that expresses direct-initialization should have been
> elided by cp_gimplify_init_expr. */
> gcc_checking_assert (!TARGET_EXPR_DIRECT_INIT_P (*expr_p));
>
> the TARGET_EXPR in question is created for the NSDMI in:
>
> class Vector { int m_size; };
> struct S {
> const Vector &vec{};
> };
>
> where we first need to create a Vector{} temporary, and then bind the
> vec reference to it. The temporary is represented by a TARGET_EXPR
> and it cannot be elided. When we create an object of type S, we get
>
> D.2848 = {.vec=(const struct Vector &) &TARGET_EXPR <D.2840, {.m_size=0}>}
>
> where the TARGET_EXPR is no longer direct-initializing anything.
Seems like the problem is in convert_like_internal:
> bool direct = CONSTRUCTOR_IS_DIRECT_INIT (expr);
> if (abstract_virtuals_error (NULL_TREE, totype, complain))
> return error_mark_node;
> expr = build_value_init (totype, complain);
> expr = get_target_expr (expr, complain);
> if (expr != error_mark_node)
> {
> TARGET_EXPR_LIST_INIT_P (expr) = true;
> => TARGET_EXPR_DIRECT_INIT_P (expr) = direct;
> }
My patch for 50930 assumed that if a CONSTRUCTOR represents syntactic
direct-initialization, a resulting TARGET_EXPR is itself the direct
initializer, but that isn't the case here; the temporary is
copy-initialized.
We could calculate direct-initializanity from cand->flags, but perhaps
we can just stop trying to set TARGET_EXPR_DIRECT_INIT_P here at all?
We don't do that for other list-initialization in ck_user, I don't know
why I thought it was needed for {} specifically. It doesn't seem to be
needed for the 50930 testcase.
Jason
@@ -7303,6 +7303,13 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
return t;
}
+ case TARGET_EXPR:
+ /* We're going to be taking the address of this TARGET_EXPR, so
+ it cannot be expected to be elided. */
+ TARGET_EXPR_DIRECT_INIT_P (arg) = false;
+ TARGET_EXPR_ELIDING_P (arg) = false;
+ break;
+
default:
break;
}
new file mode 100644
@@ -0,0 +1,12 @@
+// PR c++/114854
+// { dg-do compile { target c++14 } }
+
+struct Vector {
+ int m_size;
+};
+struct S {
+ const Vector &vec{};
+};
+
+void spawn(S);
+void test() { spawn({}); }