c++: improve constexpr prvalue folding [PR116416]
This patch improves upon r15-6052-g12de1942a0a673 by performing prvalue folding with mce_false rather than mce_unknown when it's safe to do so (i.e. ff_mce_false is set), so that we can also fold temporary initializers that call is_constant_evaluated etc. In passing I noticed constexpr-prvalue1.C could more precisely verify the optimization happened by inspecting what the front end spits out instead of inspecting the optimized assembly -- that there's no constructor call doesn't necessarily imply the constructor has been completely folded away, only that its body has been inlined. PR c++/116416 gcc/cp/ChangeLog: * constexpr.cc (maybe_constant_init_1): Generalize type of of manifestly_const_eval parameter from bool to mce_value. (maybe_constant_init): Define 3-parameter version taking a manifestly_const_eval instead of bool parameter. (cxx_constant_init): Adjust. * cp-gimplify.cc (cp_fold_r) <case TARGET_EXPR>: Pass mce_false to maybe_constant_init during prvalue folding if ff_mce_false is set. * cp-tree.h (maybe_constant_init): Declare new overload. gcc/testsuite/ChangeLog: * g++.dg/cpp1y/constexpr-prvalue1.C: Adjust to instead inspect the 'original' dump. * g++.dg/cpp1y/constexpr-prvalue1a.C: New test. Reviewed-by: Jason Merrill <jason@redhat.com>
This commit is contained in:
parent
342f1663bf
commit
e7bccec33b
5 changed files with 55 additions and 11 deletions
|
@ -9679,7 +9679,7 @@ fold_non_dependent_init (tree t,
|
|||
|
||||
static tree
|
||||
maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
|
||||
bool manifestly_const_eval)
|
||||
mce_value manifestly_const_eval)
|
||||
{
|
||||
if (!t)
|
||||
return t;
|
||||
|
@ -9709,13 +9709,13 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
|
|||
bool is_static = (decl && DECL_P (decl)
|
||||
&& (TREE_STATIC (decl) || DECL_EXTERNAL (decl)));
|
||||
if (is_static)
|
||||
manifestly_const_eval = true;
|
||||
manifestly_const_eval = mce_true;
|
||||
|
||||
if (cp_unevaluated_operand && !manifestly_const_eval)
|
||||
if (cp_unevaluated_operand && manifestly_const_eval != mce_true)
|
||||
return fold_to_constant (t);
|
||||
|
||||
t = cxx_eval_outermost_constant_expr (t, allow_non_constant, !is_static,
|
||||
mce_value (manifestly_const_eval),
|
||||
manifestly_const_eval,
|
||||
false, decl);
|
||||
}
|
||||
if (TREE_CODE (t) == TARGET_EXPR)
|
||||
|
@ -9731,6 +9731,12 @@ maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant,
|
|||
|
||||
tree
|
||||
maybe_constant_init (tree t, tree decl, bool manifestly_const_eval)
|
||||
{
|
||||
return maybe_constant_init_1 (t, decl, true, mce_value (manifestly_const_eval));
|
||||
}
|
||||
|
||||
tree
|
||||
maybe_constant_init (tree t, tree decl, mce_value manifestly_const_eval)
|
||||
{
|
||||
return maybe_constant_init_1 (t, decl, true, manifestly_const_eval);
|
||||
}
|
||||
|
@ -9740,7 +9746,7 @@ maybe_constant_init (tree t, tree decl, bool manifestly_const_eval)
|
|||
tree
|
||||
cxx_constant_init (tree t, tree decl)
|
||||
{
|
||||
return maybe_constant_init_1 (t, decl, false, true);
|
||||
return maybe_constant_init_1 (t, decl, false, mce_true);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
|
@ -1483,7 +1483,9 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
|
|||
*walk_subtrees = 0;
|
||||
if (!flag_no_inline)
|
||||
{
|
||||
tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt));
|
||||
tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
|
||||
(data->flags & ff_mce_false
|
||||
? mce_false : mce_unknown));
|
||||
if (folded != init && TREE_CONSTANT (folded))
|
||||
init = folded;
|
||||
}
|
||||
|
|
|
@ -8837,6 +8837,7 @@ extern void cxx_constant_dtor (tree, tree);
|
|||
extern tree cxx_constant_init (tree, tree = NULL_TREE);
|
||||
extern tree maybe_constant_value (tree, tree = NULL_TREE, mce_value = mce_unknown);
|
||||
extern tree maybe_constant_init (tree, tree = NULL_TREE, bool = false);
|
||||
extern tree maybe_constant_init (tree, tree, mce_value);
|
||||
extern tree fold_non_dependent_expr (tree,
|
||||
tsubst_flags_t = tf_warning_or_error,
|
||||
bool = false, tree = NULL_TREE);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// PR c++/116416
|
||||
// { dg-do compile { target c++14 } }
|
||||
// { dg-options "-O" }
|
||||
// { dg-options "-O -fdump-tree-original" }
|
||||
|
||||
struct Str {
|
||||
constexpr Str() {}
|
||||
|
@ -17,14 +17,16 @@ extern void callback(Str str);
|
|||
void
|
||||
func1()
|
||||
{
|
||||
callback(Str{"Test"});
|
||||
callback(Str{"Test1"});
|
||||
}
|
||||
void
|
||||
func2()
|
||||
{
|
||||
Str str{"Test"};
|
||||
Str str{"Test2"};
|
||||
callback(str);
|
||||
}
|
||||
|
||||
// Check that we don't call Str::Str(char const*)
|
||||
// { dg-final { scan-assembler-not "_ZN3StrC1EPKc" } }
|
||||
// Check that the front end folds both the temporary initializer and
|
||||
// that of 'str'.
|
||||
// { dg-final { scan-tree-dump "{.str=\\(const char \\*\\) \"Test1\", .length=5}" "original" } }
|
||||
// { dg-final { scan-tree-dump "{.str=\\(const char \\*\\) \"Test2\", .length=5}" "original" } }
|
||||
|
|
33
gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1a.C
Normal file
33
gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1a.C
Normal file
|
@ -0,0 +1,33 @@
|
|||
// PR c++/116416
|
||||
// A version of constexpr-prvalue1.C that calls __builtin_is_constant_evaluated.
|
||||
// { dg-do compile { target c++14 } }
|
||||
// { dg-options "-O -fdump-tree-original" }
|
||||
|
||||
struct Str {
|
||||
constexpr Str() {}
|
||||
constexpr Str(const char *instr) {
|
||||
str = instr; length = 0;
|
||||
for (auto index = 0; instr[index]; ++index) {
|
||||
length += __builtin_is_constant_evaluated() ? 1 : 1;
|
||||
}
|
||||
}
|
||||
const char *str = nullptr;
|
||||
int length = 0;
|
||||
};
|
||||
extern void callback(Str str);
|
||||
void
|
||||
func1()
|
||||
{
|
||||
callback(Str{"Test1"});
|
||||
}
|
||||
void
|
||||
func2()
|
||||
{
|
||||
Str str{"Test2"};
|
||||
callback(str);
|
||||
}
|
||||
|
||||
// Check that the front end folds both the temporary initializer and
|
||||
// that of 'str'.
|
||||
// { dg-final { scan-tree-dump "{.str=\\(const char \\*\\) \"Test1\", .length=5}" "original" } }
|
||||
// { dg-final { scan-tree-dump "{.str=\\(const char \\*\\) \"Test2\", .length=5}" "original" } }
|
Loading…
Add table
Reference in a new issue