summaryrefslogtreecommitdiff
path: root/gcc/cp/call.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/call.c')
-rw-r--r--gcc/cp/call.c179
1 files changed, 132 insertions, 47 deletions
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 024519d3601..393aab91bee 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4211,13 +4211,14 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
tree
build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
- tree *size, tree *cookie_size, tree size_check,
+ tree *size, tree *cookie_size,
+ tree align_arg, tree size_check,
tree *fn, tsubst_flags_t complain)
{
tree original_size = *size;
tree fns;
struct z_candidate *candidates;
- struct z_candidate *cand;
+ struct z_candidate *cand = NULL;
bool any_viable_p;
if (fn)
@@ -4247,9 +4248,20 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
we disregard block-scope declarations of "operator new". */
fns = lookup_function_nonclass (fnname, *args, /*block_p=*/false);
+ if (align_arg)
+ {
+ vec<tree, va_gc>* align_args
+ = vec_copy_and_insert (*args, align_arg, 1);
+ cand = perform_overload_resolution (fns, align_args, &candidates,
+ &any_viable_p, tf_none);
+ /* If no aligned allocation function matches, try again without the
+ alignment. */
+ }
+
/* Figure out what function is being called. */
- cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
- complain);
+ if (!cand)
+ cand = perform_overload_resolution (fns, *args, &candidates, &any_viable_p,
+ complain);
/* If no suitable function could be found, issue an error message
and give up. */
@@ -4653,9 +4665,12 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
if (!arg2)
{
if (complain & tf_error)
- pedwarn (loc, OPT_Wpedantic,
+ pedwarn (loc, OPT_Wpedantic,
"ISO C++ forbids omitting the middle term of a ?: expression");
+ if ((complain & tf_warning) && !truth_value_p (TREE_CODE (arg1)))
+ warn_for_omitted_condop (loc, arg1);
+
/* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */
if (lvalue_p (arg1))
arg2 = arg1 = cp_stabilize_reference (arg1);
@@ -5945,16 +5960,65 @@ static bool
second_parm_is_size_t (tree fn)
{
tree t = FUNCTION_ARG_CHAIN (fn);
- return (t
- && same_type_p (TREE_VALUE (t), size_type_node)
- && TREE_CHAIN (t) == void_list_node);
+ if (!t || !same_type_p (TREE_VALUE (t), size_type_node))
+ return false;
+ t = TREE_CHAIN (t);
+ if (t == void_list_node)
+ return true;
+ if (aligned_new_threshhold && t
+ && same_type_p (TREE_VALUE (t), align_type_node)
+ && TREE_CHAIN (t) == void_list_node)
+ return true;
+ return false;
+}
+
+/* True if T, an allocation function, has std::align_val_t as its second
+ argument. */
+
+bool
+aligned_allocation_fn_p (tree t)
+{
+ if (!aligned_new_threshhold)
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ return (a && same_type_p (TREE_VALUE (a), align_type_node));
+}
+
+/* Returns true iff T, an element of an OVERLOAD chain, is a usual deallocation
+ function (3.7.4.2 [basic.stc.dynamic.deallocation]) with a parameter of
+ std::align_val_t. */
+
+static bool
+aligned_deallocation_fn_p (tree t)
+{
+ if (!aligned_new_threshhold)
+ return false;
+
+ /* A template instance is never a usual deallocation function,
+ regardless of its signature. */
+ if (TREE_CODE (t) == TEMPLATE_DECL
+ || primary_template_instantiation_p (t))
+ return false;
+
+ tree a = FUNCTION_ARG_CHAIN (t);
+ if (same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ if (!same_type_p (TREE_VALUE (a), size_type_node))
+ return false;
+ a = TREE_CHAIN (a);
+ if (a && same_type_p (TREE_VALUE (a), align_type_node)
+ && TREE_CHAIN (a) == void_list_node)
+ return true;
+ return false;
}
/* Returns true iff T, an element of an OVERLOAD chain, is a usual
deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]). */
bool
-non_placement_deallocation_fn_p (tree t)
+usual_deallocation_fn_p (tree t)
{
/* A template instance is never a usual deallocation function,
regardless of its signature. */
@@ -5970,10 +6034,15 @@ non_placement_deallocation_fn_p (tree t)
of which has type std::size_t (18.2), then this function is a usual
deallocation function. */
bool global = DECL_NAMESPACE_SCOPE_P (t);
- if (FUNCTION_ARG_CHAIN (t) == void_list_node
+ tree chain = FUNCTION_ARG_CHAIN (t);
+ if (!chain)
+ return false;
+ if (chain == void_list_node
|| ((!global || flag_sized_deallocation)
&& second_parm_is_size_t (t)))
return true;
+ if (aligned_deallocation_fn_p (t))
+ return true;
return false;
}
@@ -6076,7 +6145,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt)
+ if (usual_deallocation_fn_p (elt)
&& FUNCTION_ARG_CHAIN (elt) == void_list_node)
goto ok;
}
@@ -6118,51 +6187,62 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
t; t = OVL_NEXT (t))
{
tree elt = OVL_CURRENT (t);
- if (non_placement_deallocation_fn_p (elt))
+ if (usual_deallocation_fn_p (elt))
{
- fn = elt;
- /* "If a class T has a member deallocation function named
- operator delete with exactly one parameter, then that
- function is a usual (non-placement) deallocation
- function. If class T does not declare such an operator
- delete but does declare a member deallocation function named
- operator delete with exactly two parameters, the second of
- which has type std::size_t (18.2), then this function is a
- usual deallocation function."
-
- So in a class (void*) beats (void*, size_t). */
- if (DECL_CLASS_SCOPE_P (fn))
+ if (!fn)
{
- if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
- break;
+ fn = elt;
+ continue;
}
- /* At global scope (in C++14 and above) the rules are different:
-
- If deallocation function lookup finds both a usual
- deallocation function with only a pointer parameter and a
- usual deallocation function with both a pointer parameter
- and a size parameter, the function to be called is selected
- as follows:
-
- * If the type is complete and if, for the second alternative
- (delete array) only, the operand is a pointer to a class
- type with a non-trivial destructor or a (possibly
- multi-dimensional) array thereof, the function with two
- parameters is selected.
-
- * Otherwise, it is unspecified which of the two deallocation
- functions is selected. */
+
+ /* -- If the type has new-extended alignment, a function with a
+ parameter of type std::align_val_t is preferred; otherwise a
+ function without such a parameter is preferred. If exactly one
+ preferred function is found, that function is selected and the
+ selection process terminates. If more than one preferred
+ function is found, all non-preferred functions are eliminated
+ from further consideration. */
+ if (aligned_new_threshhold)
+ {
+ bool want_align = type_has_new_extended_alignment (type);
+ bool fn_align = aligned_deallocation_fn_p (fn);
+ bool elt_align = aligned_deallocation_fn_p (elt);
+
+ if (elt_align != fn_align)
+ {
+ if (want_align == elt_align)
+ fn = elt;
+ continue;
+ }
+ }
+
+ /* -- If the deallocation functions have class scope, the one
+ without a parameter of type std::size_t is selected. */
+ bool want_size;
+ if (DECL_CLASS_SCOPE_P (fn))
+ want_size = false;
+
+ /* -- If the type is complete and if, for the second alternative
+ (delete array) only, the operand is a pointer to a class type
+ with a non-trivial destructor or a (possibly multi-dimensional)
+ array thereof, the function with a parameter of type std::size_t
+ is selected.
+
+ -- Otherwise, it is unspecified whether a deallocation function
+ with a parameter of type std::size_t is selected. */
else
{
- bool want_size = COMPLETE_TYPE_P (type);
+ want_size = COMPLETE_TYPE_P (type);
if (code == VEC_DELETE_EXPR
&& !TYPE_VEC_NEW_USES_COOKIE (type))
/* We need a cookie to determine the array size. */
want_size = false;
- bool have_size = (FUNCTION_ARG_CHAIN (fn) != void_list_node);
- if (want_size == have_size)
- break;
}
+ bool fn_size = second_parm_is_size_t (fn);
+ bool elt_size = second_parm_is_size_t (elt);
+ gcc_assert (fn_size != elt_size);
+ if (want_size == elt_size)
+ fn = elt;
}
}
@@ -6200,8 +6280,13 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
tree ret;
vec<tree, va_gc> *args = make_tree_vector ();
args->quick_push (addr);
- if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
+ if (second_parm_is_size_t (fn))
args->quick_push (size);
+ if (aligned_deallocation_fn_p (fn))
+ {
+ tree al = build_int_cst (align_type_node, TYPE_ALIGN_UNIT (type));
+ args->quick_push (al);
+ }
ret = cp_build_function_call_vec (fn, &args, complain);
release_tree_vector (args);
return ret;