C++ PATCH for c++/89852 - ICE with C++11 functional cast with { }
Marek Polacek
polacek@redhat.com
Fri Mar 29 21:54:00 GMT 2019
On Fri, Mar 29, 2019 at 05:29:27PM -0400, Jason Merrill wrote:
> On 3/29/19 4:25 PM, Marek Polacek wrote:
> > 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 <polacek@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.
> >
> > @@ -5604,51 +5656,29 @@ fold_non_dependent_expr (tree t,
> > if (t == NULL_TREE)
> > return NULL_TREE;
> > + if (processing_template_decl)
> > + return fold_non_dependent_expr_template (t, complain,
> > + manifestly_const_eval);
> > + return maybe_constant_value (t, NULL_TREE, manifestly_const_eval);
> > +}
> > +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;
> > + if (processing_template_decl)
> > + return fold_non_dependent_expr_template (t, complain,
> > + manifestly_const_eval);
>
> Don't we still need the maybe_constant_init TARGET_EXPR stripping behavior
> in a template?
It would seem that we don't need it, since nothing broke. But this patch
includes the stripping.
Bootstrap/regtest running on x86_64-linux, ok for trunk?
2019-03-29 Marek Polacek <polacek@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..53854a8acd4 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,39 @@ 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))
+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;
+
+ if (processing_template_decl)
+ {
+ t = fold_non_dependent_expr_template (t, complain,
+ manifestly_const_eval);
+ /* maybe_constant_init does this stripping, so do it here too. */
+ if (TREE_CODE (t) == TARGET_EXPR)
{
- t = build_nop (TREE_TYPE (t), t);
- TREE_CONSTANT (t) = false;
+ tree init = TARGET_EXPR_INITIAL (t);
+ if (TREE_CODE (init) == CONSTRUCTOR)
+ t = init;
}
return t;
}
- return maybe_constant_value (t, NULL_TREE, 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};
+}
More information about the Gcc-patches
mailing list