aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-10-30 22:55:12 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2019-10-30 22:55:12 +0100
commitcf650568d8f0a1bfc5293447e45117e0623fa908 (patch)
tree5ff224ee73b02b90dfdffbaf911a43ff72bd31f4 /gcc
parent97ccc60e0c8590e22488e909464fc591eb8b0534 (diff)
downloadgcc-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/ChangeLog7
-rw-r--r--gcc/cp/constexpr.c63
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-new5.C79
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 ());