Commit 8412b939 by Jakub Jelinek Committed by Jakub Jelinek

PR c++/91369 - Implement P0784R7: constexpr new

	PR c++/91369 - Implement P0784R7: constexpr new
	* cp-tree.h (CALL_FROM_NEW_OR_DELETE_P): Define.
	* init.c (build_new_1, build_vec_delete_1, build_delete): Set
	CALL_FROM_NEW_OR_DELETE_P on the CALL_EXPR to allocator functions.
	* constexpr.c (is_std_allocator_allocate): Only allow
	global replaceable allocator functions if CALL_FROM_NEW_OR_DELETE_P
	or in std::allocate<T>::{,de}allocate.
	(potential_constant_expression_1): Likewise.

	* g++.dg/cpp2a/constexpr-new6.C: New test.
	* g++.dg/cpp2a/constexpr-new7.C: New test.

From-SVN: r277732
parent 8a8ce49e
2019-11-02 Jakub Jelinek <jakub@redhat.com>
PR c++/91369 - Implement P0784R7: constexpr new
* cp-tree.h (CALL_FROM_NEW_OR_DELETE_P): Define.
* init.c (build_new_1, build_vec_delete_1, build_delete): Set
CALL_FROM_NEW_OR_DELETE_P on the CALL_EXPR to allocator functions.
* constexpr.c (is_std_allocator_allocate): Only allow
global replaceable allocator functions if CALL_FROM_NEW_OR_DELETE_P
or in std::allocate<T>::{,de}allocate.
(potential_constant_expression_1): Likewise.
2019-11-01 Nathan Sidwell <nathan@acm.org>
* class.c (check_field_decls): Refactor.
......
......@@ -1638,6 +1638,28 @@ is_std_construct_at (tree fndecl)
return name && id_equal (name, "construct_at");
}
/* Return true if FNDECL is std::allocator<T>::{,de}allocate. */
static inline bool
is_std_allocator_allocate (tree fndecl)
{
tree name = DECL_NAME (fndecl);
if (name == NULL_TREE
|| !(id_equal (name, "allocate") || id_equal (name, "deallocate")))
return false;
tree ctx = DECL_CONTEXT (fndecl);
if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx))
return false;
tree decl = TYPE_MAIN_DECL (ctx);
name = DECL_NAME (decl);
if (name == NULL_TREE || !id_equal (name, "allocator"))
return false;
return decl_in_std_namespace_p (decl);
}
/* Subroutine of cxx_eval_constant_expression.
Evaluate the call expression tree T in the context of OLD_CALL expression
evaluation. */
......@@ -1716,7 +1738,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
lval, non_constant_p, overflow_p);
if (!DECL_DECLARED_CONSTEXPR_P (fun))
{
if (cxx_replaceable_global_alloc_fn (fun))
if (TREE_CODE (t) == CALL_EXPR
&& cxx_replaceable_global_alloc_fn (fun)
&& (CALL_FROM_NEW_OR_DELETE_P (t)
|| (ctx->call
&& ctx->call->fundef
&& is_std_allocator_allocate (ctx->call->fundef->decl))))
{
const int nargs = call_expr_nargs (t);
tree arg0 = NULL_TREE;
......@@ -1774,7 +1801,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
}
/* Allow placement new in std::construct_at, just return the second
argument. */
if (cxx_placement_new_fn (fun)
if (TREE_CODE (t) == CALL_EXPR
&& cxx_placement_new_fn (fun)
&& ctx->call
&& ctx->call->fundef
&& is_std_construct_at (ctx->call->fundef->decl))
......@@ -6508,9 +6536,15 @@ 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)
|| TREE_CODE (t) != CALL_EXPR
|| (!CALL_FROM_NEW_OR_DELETE_P (t)
&& (current_function_decl == NULL_TREE
|| !is_std_allocator_allocate
(current_function_decl))))
/* Allow placement new in std::construct_at. */
&& (!cxx_placement_new_fn (fun)
|| TREE_CODE (t) != CALL_EXPR
|| current_function_decl == NULL_TREE
|| !is_std_construct_at (current_function_decl)))
{
......
......@@ -448,6 +448,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
LAMBDA_EXPR_CAPTURE_OPTIMIZED (in LAMBDA_EXPR)
IMPLICIT_CONV_EXPR_BRACED_INIT (in IMPLICIT_CONV_EXPR)
TINFO_VAR_DECLARED_CONSTINIT (in TEMPLATE_INFO)
CALL_FROM_NEW_OR_DELETE_P (in CALL_EXPR)
3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
......@@ -3791,6 +3792,11 @@ struct GTY(()) lang_decl {
should be performed at instantiation time. */
#define KOENIG_LOOKUP_P(NODE) TREE_LANG_FLAG_0 (CALL_EXPR_CHECK (NODE))
/* In a CALL_EXPR, true for allocator calls from new or delete
expressions. */
#define CALL_FROM_NEW_OR_DELETE_P(NODE) \
TREE_LANG_FLAG_2 (CALL_EXPR_CHECK (NODE))
/* True if the arguments to NODE should be evaluated in left-to-right
order regardless of PUSH_ARGS_REVERSED. */
#define CALL_EXPR_ORDERED_ARGS(NODE) \
......
......@@ -3404,6 +3404,10 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
}
tree alloc_call_expr = extract_call_expr (alloc_call);
if (TREE_CODE (alloc_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (alloc_call_expr) = 1;
if (cookie_size)
alloc_call = maybe_wrap_new_for_constexpr (alloc_call, elt_type,
cookie_size);
......@@ -4046,6 +4050,10 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
/*placement=*/NULL_TREE,
/*alloc_fn=*/NULL_TREE,
complain);
tree deallocate_call_expr = extract_call_expr (deallocate_expr);
if (TREE_CODE (deallocate_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (deallocate_call_expr) = 1;
}
body = loop;
......@@ -4955,6 +4963,13 @@ build_delete (tree otype, tree addr, special_function_kind auto_delete,
if (!deleting)
return expr;
if (do_delete)
{
tree do_delete_call_expr = extract_call_expr (do_delete);
if (TREE_CODE (do_delete_call_expr) == CALL_EXPR)
CALL_FROM_NEW_OR_DELETE_P (do_delete_call_expr) = 1;
}
if (do_delete && !TREE_SIDE_EFFECTS (expr))
expr = do_delete;
else if (do_delete)
......
2019-11-02 Jakub Jelinek <jakub@redhat.com>
PR c++/91369 - Implement P0784R7: constexpr new
* g++.dg/cpp2a/constexpr-new6.C: New test.
* g++.dg/cpp2a/constexpr-new7.C: New test.
* gcc.dg/pr36902.c: Terminate dg-warning regexp string.
2019-11-01 Martin Sebor <msebor@redhat.com>
......
// P0784R7
// { dg-do compile { target c++2a } }
namespace std
{
inline namespace _8 { }
namespace _8 {
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 ());
// P0784R7
// { dg-do compile { target c++2a } }
namespace std
{
typedef __SIZE_TYPE__ size_t;
}
inline void *operator new (std::size_t, void *p) noexcept
{ return p; }
void *operator new (std::size_t) noexcept;
constexpr bool
foo ()
{
auto p = static_cast<int *> (::operator new (sizeof (int))); // { dg-error "call to non-'constexpr' function" }
*p = 1;
::operator delete (p);
return false;
}
struct S { constexpr S () : s (0) {} int s; };
constexpr bool
bar ()
{
auto p = static_cast<S *> (::operator new (sizeof (S))); // { dg-error "call to non-'constexpr' function" }
auto q = new (p) S ();
q->s++;
q->~S ();
::operator delete (p);
return false;
}
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