Commit cf650568 by Jakub Jelinek Committed by Jakub Jelinek

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
parent 97ccc60e
2019-10-30 Jakub Jelinek <jakub@redhat.com> 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 * typeck.c (decl_in_std_namespace_p): Return true also for decls
in inline namespaces inside of std namespace. in inline namespaces inside of std namespace.
......
...@@ -1601,7 +1601,41 @@ cxx_replaceable_global_alloc_fn (tree fndecl) ...@@ -1601,7 +1601,41 @@ cxx_replaceable_global_alloc_fn (tree fndecl)
{ {
return (cxx_dialect >= cxx2a return (cxx_dialect >= cxx2a
&& IDENTIFIER_NEWDEL_OP_P (DECL_NAME (fndecl)) && 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. /* Subroutine of cxx_eval_constant_expression.
...@@ -1738,6 +1772,27 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, ...@@ -1738,6 +1772,27 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
return 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 (!ctx->quiet)
{ {
if (!lambda_static_thunk_p (fun)) if (!lambda_static_thunk_p (fun))
...@@ -6453,7 +6508,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, ...@@ -6453,7 +6508,11 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
&& !fndecl_built_in_p (fun) && !fndecl_built_in_p (fun)
/* In C++2a, replaceable global allocation functions /* In C++2a, replaceable global allocation functions
are constant expressions. */ 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) if (flags & tf_error)
{ {
......
2019-10-30 Jakub Jelinek <jakub@redhat.com> 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. * g++.dg/cpp0x/Wpessimizing-move6.C: New test.
2019-10-30 Bernd Edlinger <bernd.edlinger@hotmail.de> 2019-10-30 Bernd Edlinger <bernd.edlinger@hotmail.de>
......
// 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 ());
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment