Hi! The following patch is an attempt to fix PLACEHOLDER_EXPR handling. As e.g. struct Y { static Y bar (Y y) { return y; } int i; int n = bar (Y{2,i}).m + bar {Y{2,i,i}).n; int m = i; }; is rejected - one can't use incomplete ctors which would need NSDMIs until the class is defined, I believe PLACEHOLDER_EXPRs can't be arbitrarily intermixed, rather some CONSTRUCTORs into which we've added the NSDMI expressions can contain PLACEHOLDER_EXPRs and other PLACEHOLDER_EXPRs can be only found inside such CONSTRUCTORs added earlier.
So, this patch adds a new flag on CONSTRUCTORs, which acts as a barrier boundary for replace_placeholders, where we replace just PLACEHOLDER_EXPRs from the outermost expressions and don't dive into CONSTRUCTORs into which we've added other PLACEHOLDER_EXPRs - those will be handled later on separately, by cp_gimplify_init_expr calling replace_placeholders. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2018-03-14 Jakub Jelinek <ja...@redhat.com> 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_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. * 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. --- gcc/cp/cp-tree.h.jj 2018-03-14 16:21:50.745925263 +0100 +++ gcc/cp/cp-tree.h 2018-03-14 15:57:51.171323825 +0100 @@ -425,6 +425,7 @@ extern GTY(()) tree cp_global_trees[CPTI 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_i #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); --- gcc/cp/tree.c.jj 2018-03-14 11:49:58.926816421 +0100 +++ gcc/cp/tree.c 2018-03-14 16:24:29.036987505 +0100 @@ -3096,6 +3096,7 @@ build_ctor_subob_ref (tree index, tree t 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<tree> *pset; /* To avoid walking same trees multiple times. */ }; @@ -3134,7 +3135,12 @@ replace_placeholders_r (tree* t, int* wa { constructor_elt *ce; vec<constructor_elt,va_gc> *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,70 @@ replace_placeholders (tree exp, tree obj return exp; tree *tp = &exp; - hash_set<tree> pset; - replace_placeholders_t data = { obj, false, &pset }; + /* Use exp instead of *(type *)&exp. */ + while (TREE_CODE (exp) == INDIRECT_REF) + { + tree t = TREE_OPERAND (exp, 0); + STRIP_NOPS (t); + if (TREE_CODE (t) == ADDR_EXPR + && (t = TREE_OPERAND (t, 0)) + && same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (exp), + TREE_TYPE (t))) + exp = t; + else + break; + } if (TREE_CODE (exp) == TARGET_EXPR) tp = &TARGET_EXPR_INITIAL (exp); + hash_set<tree> 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 */ --- gcc/cp/typeck2.c.jj 2018-03-14 16:25:49.622019191 +0100 +++ gcc/cp/typeck2.c 2018-03-14 16:02:36.093441530 +0100 @@ -1470,6 +1470,9 @@ process_init_constructor_record (tree ty } /* 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 typ 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; } } --- gcc/testsuite/g++.dg/cpp1y/pr79937-1.C.jj 2018-03-14 14:32:12.230097853 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr79937-1.C 2018-03-14 14:32:12.230097853 +0100 @@ -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}); +} --- gcc/testsuite/g++.dg/cpp1y/pr79937-2.C.jj 2018-03-14 14:32:12.231097853 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr79937-2.C 2018-03-14 14:32:12.231097853 +0100 @@ -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}); +} --- gcc/testsuite/g++.dg/cpp1y/pr79937-3.C.jj 2018-03-14 14:32:12.231097853 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr79937-3.C 2018-03-14 14:32:12.231097853 +0100 @@ -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 (); +} --- gcc/testsuite/g++.dg/cpp1y/pr79937-4.C.jj 2018-03-14 16:14:50.842757308 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr79937-4.C 2018-03-14 16:14:45.761755127 +0100 @@ -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 (); +} --- gcc/testsuite/g++.dg/cpp1y/pr82410.C.jj 2018-03-14 16:20:07.180884544 +0100 +++ gcc/testsuite/g++.dg/cpp1y/pr82410.C 2018-03-14 16:20:01.626882356 +0100 @@ -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}); +} Jakub