diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-10-30 22:55:12 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-10-30 22:55:12 +0100 |
commit | cf650568d8f0a1bfc5293447e45117e0623fa908 (patch) | |
tree | 5ff224ee73b02b90dfdffbaf911a43ff72bd31f4 /gcc | |
parent | 97ccc60e0c8590e22488e909464fc591eb8b0534 (diff) | |
download | gcc-cf650568d8f0a1bfc5293447e45117e0623fa908.zip gcc-cf650568d8f0a1bfc5293447e45117e0623fa908.tar.gz gcc-cf650568d8f0a1bfc5293447e45117e0623fa908.tar.bz2 |
PR c++/91369 - Implement P0784R7: constexpr new
PR c++/91369 - Implement P0784R7: constexpr new
* constexpr.c (cxx_replaceable_global_alloc_fn): Don't return true
for placement new.
(cxx_placement_new_fn, is_std_construct_at): New functions.
(cxx_eval_call_expression): Allow placement new in std::construct_at.
(potential_constant_expression_1): Likewise.
* g++.dg/cpp2a/constexpr-new5.C: New test.
From-SVN: r277649
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 63 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 3 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C | 79 |
4 files changed, 150 insertions, 2 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 46b8fe0..efb135e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,12 @@ 2019-10-30 Jakub Jelinek <jakub@redhat.com> + PR c++/91369 - Implement P0784R7: constexpr new + * constexpr.c (cxx_replaceable_global_alloc_fn): Don't return true + for placement new. + (cxx_placement_new_fn, is_std_construct_at): New functions. + (cxx_eval_call_expression): Allow placement new in std::construct_at. + (potential_constant_expression_1): Likewise. + * typeck.c (decl_in_std_namespace_p): Return true also for decls in inline namespaces inside of std namespace. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 6b4e854..75db0b3 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1601,7 +1601,41 @@ cxx_replaceable_global_alloc_fn (tree fndecl) { return (cxx_dialect >= cxx2a && IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fndecl)) - && CP_DECL_CONTEXT (fndecl) == global_namespace); + && CP_DECL_CONTEXT (fndecl) == global_namespace + && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl) + || DECL_IS_OPERATOR_DELETE_P (fndecl))); +} + +/* Return true if FNDECL is a placement new function that should be + useable during constant expression evaluation of std::construct_at. */ + +static inline bool +cxx_placement_new_fn (tree fndecl) +{ + if (cxx_dialect >= cxx2a + && IDENTIFIER_NEW_OP_P (DECL_NAME (fndecl)) + && CP_DECL_CONTEXT (fndecl) == global_namespace + && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl) + && TREE_CODE (TREE_TYPE (fndecl)) == FUNCTION_TYPE) + { + tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (fndecl))); + if (TREE_VALUE (first_arg) == ptr_type_node + && TREE_CHAIN (first_arg) == void_list_node) + return true; + } + return false; +} + +/* Return true if FNDECL is std::construct_at. */ + +static inline bool +is_std_construct_at (tree fndecl) +{ + if (!decl_in_std_namespace_p (fndecl)) + return false; + + tree name = DECL_NAME (fndecl); + return name && id_equal (name, "construct_at"); } /* Subroutine of cxx_eval_constant_expression. @@ -1738,6 +1772,27 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, return t; } } + /* Allow placement new in std::construct_at, just return the second + argument. */ + if (cxx_placement_new_fn (fun) + && ctx->call + && ctx->call->fundef + && is_std_construct_at (ctx->call->fundef->decl)) + { + const int nargs = call_expr_nargs (t); + tree arg1 = NULL_TREE; + for (int i = 0; i < nargs; ++i) + { + tree arg = CALL_EXPR_ARG (t, i); + arg = cxx_eval_constant_expression (ctx, arg, false, + non_constant_p, overflow_p); + VERIFY_CONSTANT (arg); + if (i == 1) + arg1 = arg; + } + gcc_assert (arg1); + return arg1; + } if (!ctx->quiet) { if (!lambda_static_thunk_p (fun)) @@ -6453,7 +6508,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, && !fndecl_built_in_p (fun) /* In C++2a, replaceable global allocation functions are constant expressions. */ - && !cxx_replaceable_global_alloc_fn (fun)) + && !cxx_replaceable_global_alloc_fn (fun) + /* Allow placement new in std::construct_at. */ + && (!cxx_placement_new_fn (fun) + || current_function_decl == NULL_TREE + || !is_std_construct_at (current_function_decl))) { if (flags & tf_error) { diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d64275b..fe2c48a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2019-10-30 Jakub Jelinek <jakub@redhat.com> + PR c++/91369 - Implement P0784R7: constexpr new + * g++.dg/cpp2a/constexpr-new5.C: New test. + * g++.dg/cpp0x/Wpessimizing-move6.C: New test. 2019-10-30 Bernd Edlinger <bernd.edlinger@hotmail.de> diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C new file mode 100644 index 0000000..b2b65f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C @@ -0,0 +1,79 @@ +// P0784R7 +// { dg-do compile { target c++2a } } + +namespace std +{ + typedef __SIZE_TYPE__ size_t; + + template <typename T> + struct allocator + { + constexpr allocator () noexcept {} + + constexpr T *allocate (size_t n) + { return static_cast<T *> (::operator new (n * sizeof(T))); } + + constexpr void + deallocate (T *p, size_t n) + { ::operator delete (p); } + }; + + template <typename T, typename U = T &&> + U __declval (int); + template <typename T> + T __declval (long); + template <typename T> + auto declval () noexcept -> decltype (__declval<T> (0)); + + template <typename T> + struct remove_reference + { typedef T type; }; + template <typename T> + struct remove_reference<T &> + { typedef T type; }; + template <typename T> + struct remove_reference<T &&> + { typedef T type; }; + + template <typename T> + constexpr T && + forward (typename std::remove_reference<T>::type &t) noexcept + { return static_cast<T&&> (t); } + + template<typename T> + constexpr T && + forward (typename std::remove_reference<T>::type &&t) noexcept + { return static_cast<T&&> (t); } + + template <typename T, typename... A> + constexpr auto + construct_at (T *l, A &&... a) + noexcept (noexcept (::new ((void *) 0) T (std::declval<A> ()...))) + -> decltype (::new ((void *) 0) T (std::declval<A> ()...)) + { return ::new ((void *) l) T (std::forward<A> (a)...); } + + template <typename T> + constexpr inline void + destroy_at (T *l) + { l->~T (); } +} + +inline void *operator new (std::size_t, void *p) noexcept +{ return p; } + +constexpr bool +foo () +{ + std::allocator<int> a; + auto p = a.allocate (2); + std::construct_at (p, 1); + std::construct_at (p + 1, 2); + if (p[0] != 1 || p[1] != 2) + throw 1; + std::destroy_at (p); + std::destroy_at (p + 1); + a.deallocate (p, 2); + return true; +} + +static_assert (foo ()); |