]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: improve constexpr prvalue folding [PR116416]
authorPatrick Palka <ppalka@redhat.com>
Sat, 12 Apr 2025 18:06:56 +0000 (14:06 -0400)
committerPatrick Palka <ppalka@redhat.com>
Sat, 12 Apr 2025 18:06:56 +0000 (14:06 -0400)
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>
gcc/cp/constexpr.cc
gcc/cp/cp-gimplify.cc
gcc/cp/cp-tree.h
gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1.C
gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1a.C [new file with mode: 0644]

index 497f64f3ceaa697ae20e413592c492f6c3a83111..0242425370f43d50e7b2205d6af98e8259cd3b13 100644 (file)
@@ -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
index f5625ab0daad3151611e5c111b77e9c7253ac8ec..d2423fd1848a69bbb9204db7fac04acf35b7151a 100644 (file)
@@ -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;
            }
index 927f51b116b3573c0fefd1a1e4abe49ed65c88f2..55f986e25c14da1e9a315da72505e4716d18d48f 100644 (file)
@@ -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);
index ad31e30011675f71adc59d980d92b49a24bcb36c..6ad2ec89d9e6e88b0d901156d6d0a8f444ac8d67 100644 (file)
@@ -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" } }
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1a.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-prvalue1a.C
new file mode 100644 (file)
index 0000000..54176bf
--- /dev/null
@@ -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" } }