From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 47B8D3857402; Mon, 29 Aug 2022 15:35:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 47B8D3857402 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1661787326; bh=PY527y/aGJCVQfyCkg9JvJriLiAr9H3OdGxkgltpOHM=; h=From:To:Subject:Date:From; b=hn2CZdmGcXMi+0f6rpBWHIrlTuqetdIwIIDmiOaqbyo9vA0ruAK60lAVaQ/uxo1Qb qXgr23TkMXHsvKkUBdnUDr7SM91NXhPNT3q9MIeSZ4HJOCXAwBx2AdiMDRUS769OQG 14LaAALHz/1r5kN1XBuE4JEgrgjpk3BFbjEXRGl4= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] rust-constexpr.cc: port over cxx_eval_array_reference and cxx_eval_component_reference. X-Act-Checkin: gcc X-Git-Author: Faisal Abbas <90.abbasfaisal@gmail.com> X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: debe4aedc76a1f52c3072254b6be4da4f4c4696c X-Git-Newrev: 4ca228d2f32e5eb6e9516f487be85383225d5a00 Message-Id: <20220829153526.47B8D3857402@sourceware.org> Date: Mon, 29 Aug 2022 15:35:26 +0000 (GMT) List-Id: https://gcc.gnu.org/g:4ca228d2f32e5eb6e9516f487be85383225d5a00 commit 4ca228d2f32e5eb6e9516f487be85383225d5a00 Author: Faisal Abbas <90.abbasfaisal@gmail.com> Date: Tue Aug 16 12:40:33 2022 +0100 rust-constexpr.cc: port over cxx_eval_array_reference and cxx_eval_component_reference. Some important parts are commented out and marked such. These will need revisiting. Diff: --- gcc/rust/backend/rust-constexpr.cc | 327 ++++++++++++++++++++++++++++++++++--- gcc/rust/backend/rust-tree.cc | 59 +++++++ gcc/rust/backend/rust-tree.h | 28 ++++ 3 files changed, 388 insertions(+), 26 deletions(-) diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc index 5ac12d2ec6a..c0194db6b21 100644 --- a/gcc/rust/backend/rust-constexpr.cc +++ b/gcc/rust/backend/rust-constexpr.cc @@ -1532,6 +1532,273 @@ adjust_temp_type (tree type, tree temp) return fold_convert (cv_unqualified (type), temp); } +// forked from gcc/cp/constexpr.cc free_constructor + +/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs. */ + +static void +free_constructor (tree t) +{ + if (!t || TREE_CODE (t) != CONSTRUCTOR) + return; + releasing_vec ctors; + vec_safe_push (ctors, t); + while (!ctors->is_empty ()) + { + tree c = ctors->pop (); + if (vec *elts = CONSTRUCTOR_ELTS (c)) + { + constructor_elt *ce; + for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) + if (TREE_CODE (ce->value) == CONSTRUCTOR) + vec_safe_push (ctors, ce->value); + ggc_free (elts); + } + ggc_free (c); + } +} + +static tree +eval_and_check_array_index (const constexpr_ctx *ctx, tree t, + bool allow_one_past, bool *non_constant_p, + bool *overflow_p); + +// forked from gcc/cp/constexpr.cc cxx_eval_array_reference + +/* Subroutine of cxx_eval_constant_expression. + Attempt to reduce a reference to an array slot. */ + +static tree +eval_array_reference (const constexpr_ctx *ctx, tree t, bool lval, + bool *non_constant_p, bool *overflow_p) +{ + tree oldary = TREE_OPERAND (t, 0); + tree ary + = eval_constant_expression (ctx, oldary, lval, non_constant_p, overflow_p); + if (*non_constant_p) + return t; + if (!lval && TREE_CODE (ary) == VIEW_CONVERT_EXPR + && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0))) + && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0)))) + ary = TREE_OPERAND (ary, 0); + + tree oldidx = TREE_OPERAND (t, 1); + tree index + = eval_and_check_array_index (ctx, t, lval, non_constant_p, overflow_p); + if (*non_constant_p) + return t; + + if (lval && ary == oldary && index == oldidx) + return t; + else if (lval) + return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); + + unsigned len = 0, elem_nchars = 1; + tree elem_type = TREE_TYPE (TREE_TYPE (ary)); + if (TREE_CODE (ary) == CONSTRUCTOR) + len = CONSTRUCTOR_NELTS (ary); + else if (TREE_CODE (ary) == STRING_CST) + { + elem_nchars + = (TYPE_PRECISION (elem_type) / TYPE_PRECISION (char_type_node)); + len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; + } + else if (TREE_CODE (ary) == VECTOR_CST) + /* We don't create variable-length VECTOR_CSTs. */ + len = VECTOR_CST_NELTS (ary).to_constant (); + else + { + /* We can't do anything with other tree codes, so use + VERIFY_CONSTANT to complain and fail. */ + VERIFY_CONSTANT (ary); + gcc_unreachable (); + } + + bool found; + HOST_WIDE_INT i = 0; + if (TREE_CODE (ary) == CONSTRUCTOR) + { + HOST_WIDE_INT ix = find_array_ctor_elt (ary, index); + found = (ix >= 0); + if (found) + i = ix; + } + else + { + i = tree_to_shwi (index); + found = (i < len); + } + + if (found) + { + tree r; + if (TREE_CODE (ary) == CONSTRUCTOR) + r = (*CONSTRUCTOR_ELTS (ary))[i].value; + else if (TREE_CODE (ary) == VECTOR_CST) + r = VECTOR_CST_ELT (ary, i); + else + r = extract_string_elt (ary, elem_nchars, i); + + if (r) + /* Don't VERIFY_CONSTANT here. */ + return r; + + /* Otherwise the element doesn't have a value yet. */ + } + + /* Not found. */ + + if (TREE_CODE (ary) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (ary)) + { + /* 'ary' is part of the aggregate initializer we're currently + building; if there's no initializer for this element yet, + that's an error. */ + if (!ctx->quiet) + error ("accessing uninitialized array element"); + *non_constant_p = true; + return t; + } + + /* If it's within the array bounds but doesn't have an explicit + initializer, it's initialized from {}. But use build_value_init + directly for non-aggregates to avoid creating a garbage CONSTRUCTOR. */ + tree val; + constexpr_ctx new_ctx; + if (is_really_empty_class (elem_type, /*ignore_vptr*/ false)) + return build_constructor (elem_type, NULL); + // Faisal: commenting this out as not sure if we need this but we need to come + // back to handle this to assign suitable value to val before sending it in + // eval_constant_expression below + // else if (CP_AGGREGATE_TYPE_P (elem_type)) + // { + // tree empty_ctor = build_constructor (init_list_type_node, NULL); + // val = digest_init (elem_type, empty_ctor, tf_warning_or_error); + // } + // else + // val = build_value_init (elem_type, tf_warning_or_error); + + if (!SCALAR_TYPE_P (elem_type)) + { + new_ctx = *ctx; + if (ctx->object) + /* If there was no object, don't add one: it could confuse us + into thinking we're modifying a const object. */ + new_ctx.object = t; + new_ctx.ctor = build_constructor (elem_type, NULL); + ctx = &new_ctx; + } + t = eval_constant_expression (ctx, val, lval, non_constant_p, overflow_p); + if (!SCALAR_TYPE_P (elem_type) && t != ctx->ctor) + free_constructor (ctx->ctor); + return t; +} + +// forked from gcc/cp/constexpr.cc cxx_eval_component_reference + +/* Subroutine of cxx_eval_constant_expression. + Attempt to reduce a field access of a value of class type. */ + +static tree +eval_component_reference (const constexpr_ctx *ctx, tree t, bool lval, + bool *non_constant_p, bool *overflow_p) +{ + unsigned HOST_WIDE_INT i; + tree field; + tree value; + tree part = TREE_OPERAND (t, 1); + tree orig_whole = TREE_OPERAND (t, 0); + tree whole = eval_constant_expression (ctx, orig_whole, lval, non_constant_p, + overflow_p); + if (INDIRECT_REF_P (whole) && integer_zerop (TREE_OPERAND (whole, 0))) + { + if (!ctx->quiet) + error ("dereferencing a null pointer in %qE", orig_whole); + *non_constant_p = true; + return t; + } + + if (whole == orig_whole) + return t; + if (lval) + return fold_build3 (COMPONENT_REF, TREE_TYPE (t), whole, part, NULL_TREE); + /* Don't VERIFY_CONSTANT here; we only want to check that we got a + CONSTRUCTOR. */ + if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR) + { + if (!ctx->quiet) + error ("%qE is not a constant expression", orig_whole); + *non_constant_p = true; + } + if (DECL_MUTABLE_P (part)) + { + if (!ctx->quiet) + error ("mutable %qD is not usable in a constant expression", part); + *non_constant_p = true; + } + if (*non_constant_p) + return t; + bool pmf = TYPE_PTRMEMFUNC_P (TREE_TYPE (whole)); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value) + { + /* Use name match for PMF fields, as a variant will have a + different FIELD_DECL with a different type. */ + if (pmf ? DECL_NAME (field) == DECL_NAME (part) : field == part) + { + if (value) + { + STRIP_ANY_LOCATION_WRAPPER (value); + return value; + } + else + /* We're in the middle of initializing it. */ + break; + } + } + if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE + && CONSTRUCTOR_NELTS (whole) > 0) + { + /* DR 1188 says we don't have to deal with this. */ + if (!ctx->quiet) + { + constructor_elt *cep = CONSTRUCTOR_ELT (whole, 0); + if (cep->value == NULL_TREE) + error ("accessing uninitialized member %qD", part); + else + error ("accessing %qD member instead of initialized %qD member in " + "constant expression", + part, cep->index); + } + *non_constant_p = true; + return t; + } + + /* We only create a CONSTRUCTOR for a subobject when we modify it, so empty + classes never get represented; throw together a value now. */ + if (is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/ false)) + return build_constructor (TREE_TYPE (t), NULL); + + gcc_assert (DECL_CONTEXT (part) == TYPE_MAIN_VARIANT (TREE_TYPE (whole))); + + if (CONSTRUCTOR_NO_CLEARING (whole)) + { + /* 'whole' is part of the aggregate initializer we're currently + building; if there's no initializer for this member yet, that's an + error. */ + if (!ctx->quiet) + error ("accessing uninitialized member %qD", part); + *non_constant_p = true; + return t; + } + + /* If there's no explicit init for this field, it's value-initialized. */ + // Faisal: commenting this out as not sure if we need this but we need to come + // back to handle this to assign suitable value to value before sending it in + // eval_constant_expression below + // value = build_value_init (TREE_TYPE (t), tf_warning_or_error); + return eval_constant_expression (ctx, value, lval, non_constant_p, + overflow_p); +} + static tree eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, bool *non_constant_p, bool *overflow_p, @@ -1964,6 +2231,24 @@ eval_constant_expression (const constexpr_ctx *ctx, tree t, bool lval, eval_switch_expr (ctx, t, non_constant_p, overflow_p, jump_target); break; + case ARRAY_REF: + r = eval_array_reference (ctx, t, lval, non_constant_p, overflow_p); + break; + + case COMPONENT_REF: + if (is_overloaded_fn (t)) + { + /* We can only get here in checking mode via + build_non_dependent_expr, because any expression that + calls or takes the address of the function will have + pulled a FUNCTION_DECL out of the COMPONENT_REF. */ + gcc_checking_assert (ctx->quiet || errorcount); + *non_constant_p = true; + return t; + } + r = eval_component_reference (ctx, t, lval, non_constant_p, overflow_p); + break; + case BIT_FIELD_REF: r = eval_bit_field_ref (ctx, t, lval, non_constant_p, overflow_p); break; @@ -4144,32 +4429,6 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index) return r; } -// forked from gcc/cp/constexpr.cc free_constructor - -/* If T is a CONSTRUCTOR, ggc_free T and any sub-CONSTRUCTORs. */ - -static void -free_constructor (tree t) -{ - if (!t || TREE_CODE (t) != CONSTRUCTOR) - return; - releasing_vec ctors; - vec_safe_push (ctors, t); - while (!ctors->is_empty ()) - { - tree c = ctors->pop (); - if (vec *elts = CONSTRUCTOR_ELTS (c)) - { - constructor_elt *ce; - for (HOST_WIDE_INT i = 0; vec_safe_iterate (elts, i, &ce); ++i) - if (TREE_CODE (ce->value) == CONSTRUCTOR) - vec_safe_push (ctors, ce->value); - ggc_free (elts); - } - ggc_free (c); - } -} - /* Check whether the parameter and return types of FUN are valid for a constexpr function, and complain if COMPLAIN. */ @@ -6129,6 +6388,22 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, &target); } +// forked from gcc/cp/constexpr.cc fold_non_dependent_init + +/* Like maybe_constant_init but first fully instantiate the argument. */ + +tree +fold_non_dependent_init (tree t, + tsubst_flags_t complain /*=tf_warning_or_error*/, + bool manifestly_const_eval /*=false*/, + tree object /* = NULL_TREE */) +{ + if (t == NULL_TREE) + return NULL_TREE; + + return maybe_constant_init (t, object, manifestly_const_eval); +} + // #include "gt-rust-rust-constexpr.h" } // namespace Compile diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc index fc32c7c1c70..ce820f08eaa 100644 --- a/gcc/rust/backend/rust-tree.cc +++ b/gcc/rust/backend/rust-tree.cc @@ -6146,4 +6146,63 @@ explain_non_literal_class (tree t) } } +// forked from gcc/cp/call.cc reference_related_p + +/* Returns nonzero if T1 is reference-related to T2. */ + +bool +reference_related_p (tree t1, tree t2) +{ + if (t1 == error_mark_node || t2 == error_mark_node) + return false; + + t1 = TYPE_MAIN_VARIANT (t1); + t2 = TYPE_MAIN_VARIANT (t2); + + /* [dcl.init.ref] + + Given types "cv1 T1" and "cv2 T2," "cv1 T1" is reference-related + to "cv2 T2" if T1 is similar to T2, or T1 is a base class of T2. */ + return (similar_type_p (t1, t2) + /*|| (CLASS_TYPE_P (t1) && CLASS_TYPE_P (t2) + && DERIVED_FROM_P (t1, t2))*/); +} + +// forked from gcc/cp/typeck2.cc ordinary_char_type_p + +/* True iff TYPE is a C++20 "ordinary" character type. */ + +bool +ordinary_char_type_p (tree type) +{ + type = TYPE_MAIN_VARIANT (type); + return (type == char_type_node || type == signed_char_type_node + || type == unsigned_char_type_node); +} + +// forked from gcc/cp/typeck2.cc array_string_literal_compatible_p + +/* True iff the string literal INIT has a type suitable for initializing array + TYPE. */ + +bool +array_string_literal_compatible_p (tree type, tree init) +{ + tree to_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + tree from_char_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (init))); + + if (to_char_type == from_char_type) + return true; + /* The array element type does not match the initializing string + literal element type; this is only allowed when both types are + ordinary character type. There are no string literals of + signed or unsigned char type in the language, but we can get + them internally from converting braced-init-lists to + STRING_CST. */ + if (ordinary_char_type_p (to_char_type) + && ordinary_char_type_p (from_char_type)) + return true; + return false; +} + } // namespace Rust diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index 2466efc3309..87ed2b6ae56 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -1529,6 +1529,24 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; #define TYPE_HAS_COMPLEX_DFLT(NODE) \ (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt) +/* [dcl.init.aggr] + + An aggregate is an array or a class with no user-provided + constructors, no brace-or-equal-initializers for non-static data + members, no private or protected non-static data members, no + base classes, and no virtual functions. + + As an extension, we also treat vectors as aggregates. Keep these + checks in ascending code order. */ +#define CP_AGGREGATE_TYPE_P(TYPE) \ + (gnu_vector_type_p (TYPE) || TREE_CODE (TYPE) == ARRAY_TYPE \ + || (CLASS_TYPE_P (TYPE) && COMPLETE_TYPE_P (TYPE) \ + && !CLASSTYPE_NON_AGGREGATE (TYPE))) + +/* Nonzero for a FIELD_DECL means that this member object type + is mutable. */ +#define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (FIELD_DECL_CHECK (NODE))) + #if defined ENABLE_TREE_CHECKING #define LANG_DECL_MIN_CHECK(NODE) \ @@ -3116,6 +3134,12 @@ extern tree get_first_fn (tree) ATTRIBUTE_PURE; extern void explain_non_literal_class (tree); +extern bool reference_related_p (tree, tree); + +extern bool ordinary_char_type_p (tree); + +extern bool array_string_literal_compatible_p (tree, tree); + // forked from gcc/cp/cp-tree.h enum @@ -3351,6 +3375,10 @@ literal_type_p (tree t); extern bool maybe_constexpr_fn (tree t); + +extern tree +fold_non_dependent_init (tree, tsubst_flags_t = tf_warning_or_error, + bool = false, tree = NULL_TREE); } } // namespace Rust