https://gcc.gnu.org/g:8dce1aa0579ab86a626e24c0af29455f30305595
commit r14-11691-g8dce1aa0579ab86a626e24c0af29455f30305595 Author: Jason Merrill <ja...@redhat.com> Date: Sat Apr 12 11:35:18 2025 -0400 c++: shortcut constexpr vector ctor [PR113835] Since std::vector became usable in constant evaluation in C++20, a vector variable with static storage duration might be manifestly constant-evaluated, so we properly try to constant-evaluate its initializer. But it can never succeed since the result will always refer to the result of operator new, so trying is a waste of time. Potentially a large waste of time for a large vector, as in the testcase in the PR. So, let's recognize this case and skip trying constant-evaluation. I do this only for the case of an integer argument, as that's the case that's easy to write but slow to (fail to) evaluate. In the test, I use dg-timeout-factor to lower the default timeout from 300 seconds to 15; on my laptop, compilation without the patch takes about 20 seconds versus about 2 with the patch. is_std_class comes from r15-4953. PR c++/113835 gcc/cp/ChangeLog: * cp-tree.h (is_std_class): Declare. * constexpr.cc (is_std_class): New function. (is_std_allocator): Use it. (cxx_eval_outermost_constant_expr): Bail out early for std::vector(N). gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-vector1.C: New test. (cherry picked from commit 764f02327f7b2dc6ac5abaf89038e51cf0ee6d13) Diff: --- gcc/cp/cp-tree.h | 1 + gcc/cp/constexpr.cc | 25 +++++++++++++++++++++---- gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C | 8 ++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cfdfc4f9abe7..19e7b2edede3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8683,6 +8683,7 @@ extern bool is_rvalue_constant_expression (tree); extern bool is_nondependent_constant_expression (tree); extern bool is_nondependent_static_init_expression (tree); extern bool is_static_init_expression (tree); +extern bool is_std_class (tree, const char *); extern bool is_std_allocator (tree); extern bool potential_rvalue_constant_expression (tree); extern bool require_potential_constant_expression (tree); diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index e68202a5b5d9..6b8f6af00702 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2356,22 +2356,30 @@ is_std_construct_at (const constexpr_call *call) && is_std_construct_at (call->fundef->decl)); } -/* True if CTX is an instance of std::allocator. */ +/* True if CTX is an instance of std::NAME class. */ bool -is_std_allocator (tree ctx) +is_std_class (tree ctx, const char *name) { if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx)) return false; tree decl = TYPE_MAIN_DECL (ctx); - tree name = DECL_NAME (decl); - if (name == NULL_TREE || !id_equal (name, "allocator")) + tree dname = DECL_NAME (decl); + if (dname == NULL_TREE || !id_equal (dname, name)) return false; return decl_in_std_namespace_p (decl); } +/* True if CTX is an instance of std::allocator. */ + +bool +is_std_allocator (tree ctx) +{ + return is_std_class (ctx, "allocator"); +} + /* Return true if FNDECL is std::allocator<T>::{,de}allocate. */ static inline bool @@ -8851,6 +8859,15 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, tree fndecl = cp_get_callee_fndecl_nofold (x); if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) is_consteval = true; + /* Don't try to evaluate a std::vector constructor taking an integer, it + will fail in the 'if (heap_var)' block below after doing all the work + (c++/113835). This will need adjustment if P3554 is accepted. Note + that evaluation of e.g. the vector default constructor can succeed, so + we don't shortcut all vector constructors. */ + if (fndecl && DECL_CONSTRUCTOR_P (fndecl) && allow_non_constant + && is_std_class (type, "vector") && call_expr_nargs (x) > 1 + && TREE_CODE (TREE_TYPE (get_nth_callarg (x, 1))) == INTEGER_TYPE) + return t; } } if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C new file mode 100644 index 000000000000..196c6ec51fcf --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-vector1.C @@ -0,0 +1,8 @@ +// PR c++/113835 +// { dg-timeout-factor 0.05 } +// { dg-do compile { target c++20_only } } + +#include <vector> +const std::size_t N = 1'000'000; +std::vector<int> x(N); +int main() {}