From 570f86f94eca76fbfab919dcbfe639a5ba69f20e Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Fri, 16 Mar 2018 13:46:12 +0100 Subject: [PATCH] re PR c++/79937 (ICE in replace_placeholders_r) PR c++/79937 PR c++/82410 * tree.h (TARGET_EXPR_NO_ELIDE): Define. * gimplify.c (gimplify_modify_expr_rhs): Don't elide TARGET_EXPRs with TARGET_EXPR_NO_ELIDE flag set unless *expr_p is INIT_EXPR. * cp-tree.h (CONSTRUCTOR_PLACEHOLDER_BOUNDARY): Define. (find_placeholder): Declare. * tree.c (struct replace_placeholders_t): Add exp member. (replace_placeholders_r): Don't walk into ctors with CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set, unless they are equal to d->exp. Replace PLACEHOLDER_EXPR with unshare_expr (x) rather than x. (replace_placeholders): Initialize data.exp. (find_placeholders_r, find_placeholders): New functions. * typeck2.c (process_init_constructor_record, process_init_constructor_union): Set CONSTRUCTOR_PLACEHOLDER_BOUNDARY if adding NSDMI on which find_placeholder returns true. * call.c (build_over_call): Don't call replace_placeholders here. * cp-gimplify.c (cp_genericize_r): Set TARGET_EXPR_NO_ELIDE on TARGET_EXPRs with CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on TARGET_EXPR_INITIAL. (cp_fold): Copy over CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit to new ctor. * g++.dg/cpp1y/pr79937-1.C: New test. * g++.dg/cpp1y/pr79937-2.C: New test. * g++.dg/cpp1y/pr79937-3.C: New test. * g++.dg/cpp1y/pr79937-4.C: New test. * g++.dg/cpp1y/pr82410.C: New test. From-SVN: r258593 --- gcc/ChangeLog | 8 +++++ gcc/cp/ChangeLog | 22 ++++++++++++++ gcc/cp/call.c | 2 -- gcc/cp/cp-gimplify.c | 13 +++++++- gcc/cp/cp-tree.h | 8 +++++ gcc/cp/tree.c | 55 +++++++++++++++++++++++++++++++--- gcc/cp/typeck2.c | 12 +++++--- gcc/gimplify.c | 2 ++ gcc/testsuite/ChangeLog | 10 +++++++ gcc/testsuite/g++.dg/cpp1y/pr79937-1.C | 23 ++++++++++++++ gcc/testsuite/g++.dg/cpp1y/pr79937-2.C | 24 +++++++++++++++ gcc/testsuite/g++.dg/cpp1y/pr79937-3.C | 24 +++++++++++++++ gcc/testsuite/g++.dg/cpp1y/pr79937-4.C | 32 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp1y/pr82410.C | 16 ++++++++++ gcc/tree.h | 3 ++ 15 files changed, 243 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr79937-1.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr79937-2.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr79937-3.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr79937-4.C create mode 100644 gcc/testsuite/g++.dg/cpp1y/pr82410.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9ed1172..627700a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2018-03-16 Jakub Jelinek + + PR c++/79937 + PR c++/82410 + * tree.h (TARGET_EXPR_NO_ELIDE): Define. + * gimplify.c (gimplify_modify_expr_rhs): Don't elide TARGET_EXPRs with + TARGET_EXPR_NO_ELIDE flag set unless *expr_p is INIT_EXPR. + 2018-03-16 Julia Koval * doc/invoke.texi (Skylake Server): Add CLWB. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a580860..0ea8371 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2018-03-16 Jakub Jelinek + + PR c++/79937 + PR c++/82410 + * cp-tree.h (CONSTRUCTOR_PLACEHOLDER_BOUNDARY): Define. + (find_placeholder): Declare. + * tree.c (struct replace_placeholders_t): Add exp member. + (replace_placeholders_r): Don't walk into ctors with + CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set, unless they are equal to + d->exp. Replace PLACEHOLDER_EXPR with unshare_expr (x) rather than x. + (replace_placeholders): Initialize data.exp. + (find_placeholders_r, find_placeholders): New functions. + * typeck2.c (process_init_constructor_record, + process_init_constructor_union): Set CONSTRUCTOR_PLACEHOLDER_BOUNDARY + if adding NSDMI on which find_placeholder returns true. + * call.c (build_over_call): Don't call replace_placeholders here. + * cp-gimplify.c (cp_genericize_r): Set TARGET_EXPR_NO_ELIDE on + TARGET_EXPRs with CONSTRUCTOR_PLACEHOLDER_BOUNDARY set on + TARGET_EXPR_INITIAL. + (cp_fold): Copy over CONSTRUCTOR_PLACEHOLDER_BOUNDARY bit to new + ctor. + 2018-03-16 Jason Merrill PR c++/83911 - ICE with multiversioned constructor. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 67438ff..5cee63f 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8164,8 +8164,6 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain) { arg = cp_build_fold_indirect_ref (arg); val = build2 (MODIFY_EXPR, TREE_TYPE (to), to, arg); - /* Handle NSDMI that refer to the object being initialized. */ - replace_placeholders (arg, to); } else { diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index 653d1dce..332ff2b 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -1538,6 +1538,13 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) } break; + case TARGET_EXPR: + if (TARGET_EXPR_INITIAL (stmt) + && TREE_CODE (TARGET_EXPR_INITIAL (stmt)) == CONSTRUCTOR + && CONSTRUCTOR_PLACEHOLDER_BOUNDARY (TARGET_EXPR_INITIAL (stmt))) + TARGET_EXPR_NO_ELIDE (stmt) = 1; + break; + default: if (IS_TYPE_OR_DECL_P (stmt)) *walk_subtrees = 0; @@ -2492,7 +2499,11 @@ cp_fold (tree x) } } if (nelts) - x = build_constructor (TREE_TYPE (x), nelts); + { + x = build_constructor (TREE_TYPE (x), nelts); + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (x) + = CONSTRUCTOR_PLACEHOLDER_BOUNDARY (org_x); + } break; } case TREE_VEC: diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 99c51a8..727822e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -425,6 +425,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; DECL_VTABLE_OR_VTT_P (in VAR_DECL) FUNCTION_RVALUE_QUALIFIED (in FUNCTION_TYPE, METHOD_TYPE) CALL_EXPR_REVERSE_ARGS (in CALL_EXPR, AGGR_INIT_EXPR) + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (in CONSTRUCTOR) 6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE) DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL) TYPE_MARKED_P (in _TYPE) @@ -4144,6 +4145,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define CONSTRUCTOR_C99_COMPOUND_LITERAL(NODE) \ (TREE_LANG_FLAG_3 (CONSTRUCTOR_CHECK (NODE))) +/* True if this CONSTRUCTOR contains PLACEHOLDER_EXPRs referencing the + CONSTRUCTOR's type not nested inside another CONSTRUCTOR marked with + CONSTRUCTOR_PLACEHOLDER_BOUNDARY. */ +#define CONSTRUCTOR_PLACEHOLDER_BOUNDARY(NODE) \ + (TREE_LANG_FLAG_5 (CONSTRUCTOR_CHECK (NODE))) + #define DIRECT_LIST_INIT_P(NODE) \ (BRACE_ENCLOSED_INITIALIZER_P (NODE) && CONSTRUCTOR_IS_DIRECT_INIT (NODE)) @@ -7021,6 +7028,7 @@ extern tree array_type_nelts_top (tree); extern tree break_out_target_exprs (tree); extern tree build_ctor_subob_ref (tree, tree, tree); extern tree replace_placeholders (tree, tree, bool * = NULL); +extern bool find_placeholders (tree); extern tree get_type_decl (tree); extern tree decl_namespace_context (tree); extern bool decl_anon_ns_mem_p (const_tree); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index c2299ba..90fbe18 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -3096,6 +3096,7 @@ build_ctor_subob_ref (tree index, tree type, tree obj) struct replace_placeholders_t { tree obj; /* The object to be substituted for a PLACEHOLDER_EXPR. */ + tree exp; /* The outermost exp. */ bool seen; /* Whether we've encountered a PLACEHOLDER_EXPR. */ hash_set *pset; /* To avoid walking same trees multiple times. */ }; @@ -3124,7 +3125,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_) TREE_TYPE (x)); x = TREE_OPERAND (x, 0)) gcc_assert (TREE_CODE (x) == COMPONENT_REF); - *t = x; + *t = unshare_expr (x); *walk_subtrees = false; d->seen = true; } @@ -3134,7 +3135,12 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_) { constructor_elt *ce; vec *v = CONSTRUCTOR_ELTS (*t); - if (d->pset->add (*t)) + /* Don't walk into CONSTRUCTOR_PLACEHOLDER_BOUNDARY ctors + other than the d->exp one, those have PLACEHOLDER_EXPRs + related to another object. */ + if ((CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t) + && *t != d->exp) + || d->pset->add (*t)) { *walk_subtrees = false; return NULL_TREE; @@ -3192,16 +3198,57 @@ replace_placeholders (tree exp, tree obj, bool *seen_p) return exp; tree *tp = &exp; - hash_set pset; - replace_placeholders_t data = { obj, false, &pset }; if (TREE_CODE (exp) == TARGET_EXPR) tp = &TARGET_EXPR_INITIAL (exp); + hash_set pset; + replace_placeholders_t data = { obj, *tp, false, &pset }; cp_walk_tree (tp, replace_placeholders_r, &data, NULL); if (seen_p) *seen_p = data.seen; return exp; } +/* Callback function for find_placeholders. */ + +static tree +find_placeholders_r (tree *t, int *walk_subtrees, void *) +{ + if (TYPE_P (*t) || TREE_CONSTANT (*t)) + { + *walk_subtrees = false; + return NULL_TREE; + } + + switch (TREE_CODE (*t)) + { + case PLACEHOLDER_EXPR: + return *t; + + case CONSTRUCTOR: + if (CONSTRUCTOR_PLACEHOLDER_BOUNDARY (*t)) + *walk_subtrees = false; + break; + + default: + break; + } + + return NULL_TREE; +} + +/* Return true if EXP contains a PLACEHOLDER_EXPR. Don't walk into + ctors with CONSTRUCTOR_PLACEHOLDER_BOUNDARY flag set. */ + +bool +find_placeholders (tree exp) +{ + /* This is only relevant for C++14. */ + if (cxx_dialect < cxx14) + return false; + + return cp_walk_tree_without_duplicates (&exp, find_placeholders_r, NULL); +} + /* Similar to `build_nt', but for template definitions of dependent expressions */ diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 2df51a5..464e8a7 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -1470,6 +1470,9 @@ process_init_constructor_record (tree type, tree init, int nested, } /* C++14 aggregate NSDMI. */ next = get_nsdmi (field, /*ctor*/false, complain); + if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) + && find_placeholders (next)) + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; } else if (type_build_ctor_call (TREE_TYPE (field))) { @@ -1608,10 +1611,11 @@ process_init_constructor_union (tree type, tree init, int nested, if (TREE_CODE (field) == FIELD_DECL && DECL_INITIAL (field) != NULL_TREE) { - CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), - field, - get_nsdmi (field, /*in_ctor=*/false, - complain)); + tree val = get_nsdmi (field, /*in_ctor=*/false, complain); + if (!CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) + && find_placeholders (val)) + CONSTRUCTOR_PLACEHOLDER_BOUNDARY (init) = 1; + CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (init), field, val); break; } } diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 7fedd97..115f80b 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5211,6 +5211,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree init = TARGET_EXPR_INITIAL (*from_p); if (init + && (TREE_CODE (*expr_p) != MODIFY_EXPR + || !TARGET_EXPR_NO_ELIDE (*from_p)) && !VOID_TYPE_P (TREE_TYPE (init))) { *from_p = init; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 491c403..ff2ac8b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2018-03-16 Jakub Jelinek + + PR c++/79937 + PR c++/82410 + * g++.dg/cpp1y/pr79937-1.C: New test. + * g++.dg/cpp1y/pr79937-2.C: New test. + * g++.dg/cpp1y/pr79937-3.C: New test. + * g++.dg/cpp1y/pr79937-4.C: New test. + * g++.dg/cpp1y/pr82410.C: New test. + 2018-03-16 Tom de Vries * gcc.dg/tree-ssa/pr84512.c: Require effective target vect_int_mult. diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-1.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-1.C new file mode 100644 index 0000000..f547782 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr79937-1.C @@ -0,0 +1,23 @@ +// PR c++/79937 +// { dg-do run { target c++14 } } + +struct C {}; + +struct X { + unsigned i; + unsigned n = i; +}; + +C +bar (X x) +{ + if (x.i != 1 || x.n != 1) + __builtin_abort (); + return {}; +} + +int +main () +{ + C c = bar (X {1}); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-2.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-2.C new file mode 100644 index 0000000..551b8b6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr79937-2.C @@ -0,0 +1,24 @@ +// PR c++/79937 +// { dg-do run { target c++14 } } + +struct C {}; + +struct X { + unsigned i; + unsigned n = i; + unsigned m = i; +}; + +C +bar (X x) +{ + if (x.i != 1 || x.n != 2 || x.m != 1) + __builtin_abort (); + return {}; +} + +int +main () +{ + C c = bar (X {1, X {2}.n}); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-3.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-3.C new file mode 100644 index 0000000..6f0c22d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr79937-3.C @@ -0,0 +1,24 @@ +// PR c++/79937 +// { dg-do run { target c++14 } } + +struct X { + unsigned i; + unsigned n = i; + unsigned m = i; +}; + +X +bar (X x) +{ + if (x.i != 1 || x.n != 2 || x.m != 1) + __builtin_abort (); + return x; +} + +int +main () +{ + X x = bar (X {1, X {2}.n}); + if (x.i != 1 || x.n != 2 || x.m != 1) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr79937-4.C b/gcc/testsuite/g++.dg/cpp1y/pr79937-4.C new file mode 100644 index 0000000..1a49630 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr79937-4.C @@ -0,0 +1,32 @@ +// PR c++/79937 +// { dg-do run { target c++14 } } + +struct X { + unsigned i; + unsigned n = i; +}; + +X +bar (X x) +{ + return x; +} + +struct Y +{ + static Y bar (Y y) { return y; } + unsigned i; + unsigned n = bar (Y{2,i}).n; +}; + +int +main () +{ + X x { 1, bar (X{2}).n }; + if (x.n != 2) + __builtin_abort (); + + Y y { 1 }; + if (y.n != 1) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp1y/pr82410.C b/gcc/testsuite/g++.dg/cpp1y/pr82410.C new file mode 100644 index 0000000..185f644 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr82410.C @@ -0,0 +1,16 @@ +// PR c++/82410 +// { dg-do compile { target c++14 } } + +int +main () +{ + struct A {}; + struct S + { + int & p; + int x = p; + operator A () { return {}; } + }; + int l; + [] (A) {} (S{l}); +} diff --git a/gcc/tree.h b/gcc/tree.h index af8a6fb..1e14d9f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1197,6 +1197,9 @@ extern tree maybe_wrap_with_location (tree, location_t); #define TARGET_EXPR_SLOT(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 0) #define TARGET_EXPR_INITIAL(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 1) #define TARGET_EXPR_CLEANUP(NODE) TREE_OPERAND_CHECK_CODE (NODE, TARGET_EXPR, 2) +/* Don't elide the initialization of TARGET_EXPR_SLOT for this TARGET_EXPR + on rhs of MODIFY_EXPR. */ +#define TARGET_EXPR_NO_ELIDE(NODE) (TARGET_EXPR_CHECK (NODE)->base.private_flag) /* DECL_EXPR accessor. This gives access to the DECL associated with the given declaration statement. */ -- 2.7.4