From db8ffb402adef529e224cdc4bd73e09a3aa247f2 Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 9 Sep 2016 21:22:15 +0000 Subject: Implement P0035R4, C++17 new of over-aligned types. gcc/cp/ * cp-tree.h (enum cp_tree_index): Add CPTI_ALIGN_TYPE. (align_type_node): New macro. * call.c (build_operator_new_call): Handle C++17 aligned new. (second_parm_is_size_t, build_op_delete_call): Likewise. (non_placement_deallocation_fn_p): Likewise. Rename to usual_deallocation_fn_p. (aligned_allocation_fn_p, aligned_deallocation_fn_p): New. * decl.c (cxx_init_decl_processing): Add aligned new support. * init.c (type_has_new_extended_alignment): New. (build_new_1): Handle aligned new. * tree.c (vec_copy_and_insert): New. gcc/c-family/ * c.opt: Add -faligned-new and -Waligned-new. * c-common.c (max_align_t_align): Split out from... (cxx_fundamental_alignment_p): ...here. * c-common.h: Declare it. * c-cppbuiltin.c (c_cpp_builtins): Handle aligned new. libstdc++-v3/ * libsupc++/new: Declare aligned new/delete operators. * config/abi/pre/gnu.ver: Export them. * configure.ac: Check for aligned_alloc, posix_memalign, memalign, _aligned_malloc. * libsupc++/new_opa.cc: New. * libsupc++/new_opant.cc: New. * libsupc++/new_opva.cc: New. * libsupc++/new_opva.cc: New. * libsupc++/del_opa.cc: New. * libsupc++/del_opant.cc: New. * libsupc++/del_opsa.cc: New. * libsupc++/del_opva.cc: New. * libsupc++/del_opvant.cc: New. * libsupc++/del_opvsa.cc: New. * libsupc++/Makefile.am: Build them. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240056 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/call.c | 174 ++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 128 insertions(+), 46 deletions(-) (limited to 'gcc/cp/call.c') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 024519d3601..167d77810c8 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4211,13 +4211,14 @@ build_new_function_call (tree fn, vec **args, bool koenig_p, tree build_operator_new_call (tree fnname, vec **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 **args, we disregard block-scope declarations of "operator new". */ fns = lookup_function_nonclass (fnname, *args, /*block_p=*/false); + if (align_arg) + { + vec* 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. */ @@ -5945,16 +5957,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 +6031,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 +6142,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 +6184,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 +6277,13 @@ build_op_delete_call (enum tree_code code, tree addr, tree size, tree ret; vec *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; -- cgit v1.2.1 From 7a21b590fb5d96a2a925f2a26ea1f20c89ae070f Mon Sep 17 00:00:00 2001 From: edlinger Date: Mon, 12 Sep 2016 20:18:16 +0000 Subject: gcc/c-family: 2016-09-12 Bernd Edlinger PR c++/77496 * c-common.c (warn_for_omitted_condop): Also warn for boolean data. gcc/c: 2016-09-12 Bernd Edlinger PR c++/77496 * c-parser.c (c_parser_conditional_expression): Pass the rightmost COMPOUND_EXPR to warn_for_omitted_condop. gcc/cp: 2016-09-12 Bernd Edlinger PR c++/77496 * call.c (build_conditional_expr_1): Call warn_for_omitted_condop. * class.c (instantiate_type): Look through the SAVE_EXPR. gcc/testsuite: 2016-09-12 Bernd Edlinger PR c++/77496 * c-c++-common/warn-ommitted-condop.c: Add more test cases. * g++.dg/ext/pr77496.C: New test. * g++.dg/warn/pr77496.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240098 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/call.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/cp/call.c') diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 167d77810c8..393aab91bee 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4665,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); -- cgit v1.2.1