aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/init.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-10-05 09:38:21 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2019-10-05 09:38:21 +0200
commit8e007055dd1374ca4c44406a4ead172be0dfa3a8 (patch)
tree6d2808d70c3cd75cdf81b49e2d1d7495f7ae4516 /gcc/cp/init.c
parent0043b5280e6f571819d8764d76594a7a20467d00 (diff)
downloadgcc-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.c97
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,