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.

From-SVN: r270048
This commit is contained in:
Marek Polacek 2019-03-31 20:37:22 +00:00 committed by Marek Polacek
parent 93755deb5c
commit a81c8e8c9a
6 changed files with 114 additions and 38 deletions

View File

@ -1,3 +1,14 @@
2019-03-31 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.
2019-03-30 Jason Merrill <jason@redhat.com>
PR c++/89744 - ICE with specialization of member class template.

View File

@ -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);
}
/* Like maybe_constant_init but first fully instantiate the argument. */
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;
as two declarations of the same function, for example. */
if (processing_template_decl)
{
if (is_nondependent_constant_expression (t))
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)
{
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;
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

View File

@ -7716,6 +7716,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);

View File

@ -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;

View File

@ -1,3 +1,8 @@
2019-03-31 Marek Polacek <polacek@redhat.com>
PR c++/89852 - ICE with C++11 functional cast with { }.
* g++.dg/cpp0x/initlist115.C: New test.
2019-03-31 Harald Anlauf <anlauf@gmx.de>
PR fortran/83515

View File

@ -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};
}