diff options
author | Jakub Jelinek <jakub@redhat.com> | 2019-10-05 09:38:21 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-10-05 09:38:21 +0200 |
commit | 8e007055dd1374ca4c44406a4ead172be0dfa3a8 (patch) | |
tree | 6d2808d70c3cd75cdf81b49e2d1d7495f7ae4516 /gcc/cp/init.c | |
parent | 0043b5280e6f571819d8764d76594a7a20467d00 (diff) | |
download | gcc-8e007055dd1374ca4c44406a4ead172be0dfa3a8.zip gcc-8e007055dd1374ca4c44406a4ead172be0dfa3a8.tar.gz gcc-8e007055dd1374ca4c44406a4ead172be0dfa3a8.tar.bz2 |
PR c++/91369 - Implement P0784R7: constexpr new
PR c++/91369 - Implement P0784R7: constexpr new
c-family/
* c-cppbuiltin.c (c_cpp_builtins): Predefine
__cpp_constexpr_dynamic_alloc=201907 for -std=c++2a.
cp/
* cp-tree.h (enum cp_tree_index): Add CPTI_HEAP_UNINIT_IDENTIFIER,
CPTI_HEAP_IDENTIFIER and CPTI_HEAP_DELETED_IDENTIFIER.
(heap_uninit_identifier, heap_identifier, heap_deleted_identifier):
Define.
(type_has_constexpr_destructor, build_new_constexpr_heap_type,
cxx_constant_dtor): Declare.
* class.c (type_maybe_constexpr_default_constructor): Make static.
(type_maybe_constexpr_destructor, type_has_constexpr_destructor): New
functions.
(finalize_literal_type_property): For c++2a, don't clear
CLASSTYPE_LITERAL_P for types without trivial destructors unless they
have non-constexpr destructors.
(explain_non_literal_class): For c++2a, complain about non-constexpr
destructors rather than about non-trivial destructors.
* constexpr.c: Include stor-layout.h.
(struct constexpr_global_ctx): New type.
(struct constexpr_ctx): Add global field, remove values and
constexpr_ops_count.
(cxx_replaceable_global_alloc_fn): New inline function.
(cxx_eval_call_expression): For c++2a allow calls to replaceable
global allocation functions, for new return address of a heap uninit
var, for delete record its deletion. Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
(non_const_var_error): Add auto_diagnostic_group sentinel. Emit
special diagnostics for heap variables.
(cxx_eval_store_expression): Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
(cxx_eval_loop_expr): Initialize jump_target if NULL. Change
new_ctx.values->remove to ctx->global->values.remove.
(cxx_eval_constant_expression): Change *ctx->constexpr_ops_count
to ctx->global->constexpr_ops_count. Change ctx->values->{get,put} to
ctx->global->values.{get,put}.
<case NOP_EXPR>: Formatting fix. On cast of replaceable global
allocation function to some pointer type, adjust the type of
the heap variable and change name from heap_uninit_identifier
to heap_identifier.
(find_heap_var_refs): New function.
(cxx_eval_outermost_constant_expr): Add constexpr_dtor argument,
handle evaluation of constexpr dtors and add tracking of heap
variables. Use tf_no_cleanup for get_target_expr_with_sfinae.
(cxx_constant_value): Adjust cxx_eval_outermost_constant_expr caller.
(cxx_constant_dtor): New function.
(maybe_constant_value, fold_non_dependent_expr_template,
maybe_constant_init_1): Adjust cxx_eval_outermost_constant_expr
callers.
(potential_constant_expression_1): Ignore clobbers. Allow
COND_EXPR_IS_VEC_DELETE for c++2a.
* decl.c (initialize_predefined_identifiers): Add heap identifiers.
(decl_maybe_constant_destruction): New function.
(cp_finish_decl): Don't clear TREE_READONLY for constexpr variables
with non-trivial, but constexpr destructors.
(register_dtor_fn): For constexpr variables with constexpr non-trivial
destructors call cxx_maybe_build_cleanup instead of adding destructor
calls at runtime.
(expand_static_init): For constexpr variables with constexpr
non-trivial destructors call cxx_maybe_build_cleanup.
(grokdeclarator): Allow constexpr destructors for c++2a. Formatting
fix.
(cxx_maybe_build_cleanup): For constexpr variables with constexpr
non-trivial destructors call cxx_constant_dtor instead of adding
destructor calls at runtime.
* init.c: Include stor-layout.h.
(build_new_constexpr_heap_type, maybe_wrap_new_for_constexpr): New
functions.
(build_new_1): For c++2a and new[], add cast around the alloc call
to help constexpr evaluation figure out the type of the heap storage.
(build_vec_delete_1): Set DECL_INITIAL of tbase and emit a DECL_EXPR
for it instead of initializing an uninitialized variable.
* method.c: Include intl.h.
(SFK_CTOR_P, SFK_DTOR_P, SFK_ASSIGN_P, SFK_COPY_P, SFK_MOVE_P): Move
definitions earlier.
(process_subob_fn): Add sfk argument, adjust non-constexpr call
diagnostics based on it.
(walk_field_subobs): Formatting fixes. Adjust process_subob_fn caller.
(synthesized_method_base_walk): Likewise.
(synthesized_method_walk): Set *constexpr_p to true for dtors in c++2a.
Fix up DR number in comment.
(implicitly_declare_fn): Formatting fix.
* typeck2.c (store_init_value): Don't call cp_fully_fold_init on
initializers of automatic non-constexpr variables in constexpr
functions.
testsuite/
* g++.dg/cpp0x/constexpr-delete2.C: Adjust expected diagnostics for
c++2a.
* g++.dg/cpp0x/locations1.C: Only expect constexpr ~S() diagnostics
in c++17_down, adjust expected wording.
* g++.dg/cpp1y/constexpr-new.C: Only expect diagnostics in c++17_down.
* g++.dg/cpp2a/constexpr-dtor1.C: New test.
* g++.dg/cpp2a/constexpr-dtor2.C: New test.
* g++.dg/cpp2a/constexpr-dtor3.C: New test.
* g++.dg/cpp2a/constexpr-new1.C: New test.
* g++.dg/cpp2a/constexpr-new2.C: New test.
* g++.dg/cpp2a/constexpr-new3.C: New test.
* g++.dg/cpp2a/constexpr-new4.C: New test.
* g++.dg/cpp2a/feat-cxx2a.C: Add __cpp_constinit and
__cpp_constexpr_dynamic_alloc tests. Tweak __cpp_* tests for c++2a
features to use style like older features, including #ifdef test.
* g++.dg/ext/is_literal_type3.C: New test.
From-SVN: r276622
Diffstat (limited to 'gcc/cp/init.c')
-rw-r--r-- | gcc/cp/init.c | 97 |
1 files changed, 86 insertions, 11 deletions
diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 857f360..1c51e26 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "asan.h" +#include "stor-layout.h" static bool begin_init_stmts (tree *, tree *); static tree finish_init_stmts (bool, tree, tree); @@ -2860,6 +2861,82 @@ std_placement_new_fn_p (tree alloc_fn) return false; } +/* For element type ELT_TYPE, return the appropriate type of the heap object + containing such element(s). COOKIE_SIZE is NULL or the size of cookie + in bytes. FULL_SIZE is NULL if it is unknown how big the heap allocation + will be, otherwise size of the heap object. If COOKIE_SIZE is NULL, + return array type ELT_TYPE[FULL_SIZE / sizeof(ELT_TYPE)], otherwise return + struct { size_t[COOKIE_SIZE/sizeof(size_t)]; ELT_TYPE[N]; } + where N is nothing (flexible array member) if FULL_SIZE is NULL, otherwise + it is computed such that the size of the struct fits into FULL_SIZE. */ + +tree +build_new_constexpr_heap_type (tree elt_type, tree cookie_size, tree full_size) +{ + gcc_assert (cookie_size == NULL_TREE || tree_fits_uhwi_p (cookie_size)); + gcc_assert (full_size == NULL_TREE || tree_fits_uhwi_p (full_size)); + unsigned HOST_WIDE_INT csz = cookie_size ? tree_to_uhwi (cookie_size) : 0; + tree itype2 = NULL_TREE; + if (full_size) + { + unsigned HOST_WIDE_INT fsz = tree_to_uhwi (full_size); + gcc_assert (fsz >= csz); + fsz -= csz; + fsz /= int_size_in_bytes (elt_type); + itype2 = build_index_type (size_int (fsz - 1)); + if (!cookie_size) + return build_cplus_array_type (elt_type, itype2); + } + else + gcc_assert (cookie_size); + csz /= int_size_in_bytes (sizetype); + tree itype1 = build_index_type (size_int (csz - 1)); + tree atype1 = build_cplus_array_type (sizetype, itype1); + tree atype2 = build_cplus_array_type (elt_type, itype2); + tree rtype = cxx_make_type (RECORD_TYPE); + TYPE_NAME (rtype) = heap_identifier; + tree fld1 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype1); + tree fld2 = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE, atype2); + DECL_FIELD_CONTEXT (fld1) = rtype; + DECL_FIELD_CONTEXT (fld2) = rtype; + DECL_ARTIFICIAL (fld1) = true; + DECL_ARTIFICIAL (fld2) = true; + TYPE_FIELDS (rtype) = fld1; + DECL_CHAIN (fld1) = fld2; + layout_type (rtype); + return rtype; +} + +/* Help the constexpr code to find the right type for the heap variable + by adding a NOP_EXPR around ALLOC_CALL if needed for cookie_size. + Return ALLOC_CALL or ALLOC_CALL cast to a pointer to + struct { size_t[cookie_size/sizeof(size_t)]; elt_type[]; }. */ + +static tree +maybe_wrap_new_for_constexpr (tree alloc_call, tree elt_type, tree cookie_size) +{ + if (cxx_dialect < cxx2a) + return alloc_call; + + if (current_function_decl != NULL_TREE + && !DECL_DECLARED_CONSTEXPR_P (current_function_decl)) + return alloc_call; + + tree call_expr = extract_call_expr (alloc_call); + if (call_expr == error_mark_node) + return alloc_call; + + tree alloc_call_fndecl = cp_get_callee_fndecl_nofold (call_expr); + if (alloc_call_fndecl == NULL_TREE + || !IDENTIFIER_NEW_OP_P (DECL_NAME (alloc_call_fndecl)) + || CP_DECL_CONTEXT (alloc_call_fndecl) != global_namespace) + return alloc_call; + + tree rtype = build_new_constexpr_heap_type (elt_type, cookie_size, + NULL_TREE); + return build_nop (build_pointer_type (rtype), alloc_call); +} + /* Generate code for a new-expression, including calling the "operator new" function, initializing the object, and, if an exception occurs during construction, cleaning up. The arguments are as for @@ -3327,6 +3404,10 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, } } + if (cookie_size) + alloc_call = maybe_wrap_new_for_constexpr (alloc_call, elt_type, + cookie_size); + /* In the simple case, we can stop now. */ pointer_type = build_pointer_type (type); if (!cookie_size && !is_initialized) @@ -3902,17 +3983,11 @@ build_vec_delete_1 (tree base, tree maxindex, tree type, fold_convert (sizetype, maxindex)); tbase = create_temporary_var (ptype); - tbase_init - = cp_build_modify_expr (input_location, tbase, NOP_EXPR, - fold_build_pointer_plus_loc (input_location, - fold_convert (ptype, - base), - virtual_size), - complain); - if (tbase_init == error_mark_node) - return error_mark_node; - controller = build3 (BIND_EXPR, void_type_node, tbase, - NULL_TREE, NULL_TREE); + DECL_INITIAL (tbase) + = fold_build_pointer_plus_loc (input_location, fold_convert (ptype, base), + virtual_size); + tbase_init = build_stmt (input_location, DECL_EXPR, tbase); + controller = build3 (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE); TREE_SIDE_EFFECTS (controller) = 1; body = build1 (EXIT_EXPR, void_type_node, |