On Thu, Mar 28, 2019 at 02:55:55PM -0400, Jason Merrill wrote: > On 3/27/19 5:45 PM, Marek Polacek wrote: > > Here we have a non-dependent constructor in a template: > > > > { VIEW_CONVERT_EXPR<const A>(j) } > > > > In digest_init we call massage_init_elt, which calls digest_init_r on the > > element. We convert the element, but we're in a template, so > > perform_implicit_conversion added an IMPLICIT_CONV_EXPR around it. And then > > massage_init_elt calls maybe_constant_init on the element and the usual > > sadness > > ensues. > > Only after fold_non_dependent_expr. Perhaps we want a > fold_non_dependent_init?
Yeah, I recall we talked about adding fold_non_dependent_init a year ago. Using it here works -- in a template, we won't call maybe_constant_*, so there's no crash. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-03-29 Marek Polacek <pola...@redhat.com> PR c++/89852 - ICE with C++11 functional cast with { }. * constexpr.c (fold_non_dependent_expr_template): New static function broken out of... (fold_non_dependent_expr): ...here. (fold_non_dependent_init): New function. * cp-tree.h (fold_non_dependent_init): Declare. * typeck2.c (massage_init_elt): Call fold_non_dependent_init instead of fold_non_dependent_expr. Don't call maybe_constant_init. * g++.dg/cpp0x/initlist115.C: New test. diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c index daf34e10784..988b37b8ad8 100644 --- gcc/cp/constexpr.c +++ gcc/cp/constexpr.c @@ -5581,6 +5581,58 @@ clear_cv_and_fold_caches (void) clear_fold_cache (); } +/* Internal function handling expressions in templates for + fold_non_dependent_expr and fold_non_dependent_init. + + If we're in a template, but T isn't value dependent, simplify + it. We're supposed to treat: + + template <typename T> void f(T[1 + 1]); + template <typename T> void f(T[2]); + + as two declarations of the same function, for example. */ + +static tree +fold_non_dependent_expr_template (tree t, tsubst_flags_t complain, + bool manifestly_const_eval) +{ + gcc_assert (processing_template_decl); + + if (is_nondependent_constant_expression (t)) + { + processing_template_decl_sentinel s; + t = instantiate_non_dependent_expr_internal (t, complain); + + if (type_unknown_p (t) || BRACE_ENCLOSED_INITIALIZER_P (t)) + { + if (TREE_OVERFLOW_P (t)) + { + t = build_nop (TREE_TYPE (t), t); + TREE_CONSTANT (t) = false; + } + return t; + } + + tree r = cxx_eval_outermost_constant_expr (t, true, true, + manifestly_const_eval, + NULL_TREE); + /* cp_tree_equal looks through NOPs, so allow them. */ + gcc_checking_assert (r == t + || CONVERT_EXPR_P (t) + || TREE_CODE (t) == VIEW_CONVERT_EXPR + || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) + || !cp_tree_equal (r, t)); + return r; + } + else if (TREE_OVERFLOW_P (t)) + { + t = build_nop (TREE_TYPE (t), t); + TREE_CONSTANT (t) = false; + } + + return t; +} + /* Like maybe_constant_value but first fully instantiate the argument. Note: this is equivalent to instantiate_non_dependent_expr_sfinae @@ -5604,51 +5656,29 @@ fold_non_dependent_expr (tree t, if (t == NULL_TREE) return NULL_TREE; - /* If we're in a template, but T isn't value dependent, simplify - it. We're supposed to treat: + if (processing_template_decl) + return fold_non_dependent_expr_template (t, complain, + manifestly_const_eval); - template <typename T> void f(T[1 + 1]); - template <typename T> void f(T[2]); + return maybe_constant_value (t, NULL_TREE, manifestly_const_eval); +} - as two declarations of the same function, for example. */ - if (processing_template_decl) - { - if (is_nondependent_constant_expression (t)) - { - processing_template_decl_sentinel s; - t = instantiate_non_dependent_expr_internal (t, complain); - if (type_unknown_p (t) - || BRACE_ENCLOSED_INITIALIZER_P (t)) - { - if (TREE_OVERFLOW_P (t)) - { - t = build_nop (TREE_TYPE (t), t); - TREE_CONSTANT (t) = false; - } - return t; - } +/* Like maybe_constant_init but first fully instantiate the argument. */ - tree r = cxx_eval_outermost_constant_expr (t, true, true, - manifestly_const_eval, - NULL_TREE); - /* cp_tree_equal looks through NOPs, so allow them. */ - gcc_checking_assert (r == t - || CONVERT_EXPR_P (t) - || TREE_CODE (t) == VIEW_CONVERT_EXPR - || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) - || !cp_tree_equal (r, t)); - return r; - } - else if (TREE_OVERFLOW_P (t)) - { - t = build_nop (TREE_TYPE (t), t); - TREE_CONSTANT (t) = false; - } - return t; - } +tree +fold_non_dependent_init (tree t, + tsubst_flags_t complain /*=tf_warning_or_error*/, + bool manifestly_const_eval /*=false*/) +{ + if (t == NULL_TREE) + return NULL_TREE; - return maybe_constant_value (t, NULL_TREE, manifestly_const_eval); + if (processing_template_decl) + return fold_non_dependent_expr_template (t, complain, + manifestly_const_eval); + + return maybe_constant_init (t, NULL_TREE, manifestly_const_eval); } /* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather diff --git gcc/cp/cp-tree.h gcc/cp/cp-tree.h index fd612b0dbb1..31218a79be7 100644 --- gcc/cp/cp-tree.h +++ gcc/cp/cp-tree.h @@ -7708,6 +7708,9 @@ extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false); extern tree fold_non_dependent_expr (tree, tsubst_flags_t = tf_warning_or_error, bool = false); +extern tree fold_non_dependent_init (tree, + tsubst_flags_t = tf_warning_or_error, + bool = false); extern tree fold_simple (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c index 7f242ba93da..fa98b1cb8b5 100644 --- gcc/cp/typeck2.c +++ gcc/cp/typeck2.c @@ -1346,8 +1346,7 @@ massage_init_elt (tree type, tree init, int nested, int flags, init = TARGET_EXPR_INITIAL (init); /* When we defer constant folding within a statement, we may want to defer this folding as well. */ - tree t = fold_non_dependent_expr (init, complain); - t = maybe_constant_init (t); + tree t = fold_non_dependent_init (init, complain); if (TREE_CONSTANT (t)) init = t; return init; diff --git gcc/testsuite/g++.dg/cpp0x/initlist115.C gcc/testsuite/g++.dg/cpp0x/initlist115.C new file mode 100644 index 00000000000..ee4b6d4a870 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/initlist115.C @@ -0,0 +1,18 @@ +// PR c++/89852 +// { dg-do compile { target c++11 } } + +struct A { + int b; +}; + +struct B { + A g; +}; + +const auto j = A{}; + +template <typename> +void k() +{ + B{j}; +}