From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 966243856DD6; Mon, 29 Aug 2022 15:34:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 966243856DD6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1661787280; bh=d5RTzD/reQo12BnQT45Pf6rZqJlzMUlWxaKgBDwgEVQ=; h=From:To:Subject:Date:From; b=Fp1Ah8uoFtCPGLXtrVNasIlup82HV8aBfeC6uVEbcGtVcDQ03ZULEvaSKZJ7wsMgi XInL0OQoBxOju8L31hMEDH+LZ+6Fh5fsVRWjs2dTCj0MXqvImntfjzfVifBIrpMwh0 gMluEABsI+VfJCd+7CZb381PSXezSn/HeG/9rMeY= 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_outermost_constant_expr X-Act-Checkin: gcc X-Git-Author: Faisal Abbas <90.abbasfaisal@gmail.com> X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 6b440d46f16e3f93dd979852a1aab55f88add75f X-Git-Newrev: d780f02a54ff9cb0b5fd181eb21ae9afe2fd7d1c Message-Id: <20220829153440.966243856DD6@sourceware.org> Date: Mon, 29 Aug 2022 15:34:40 +0000 (GMT) List-Id: https://gcc.gnu.org/g:d780f02a54ff9cb0b5fd181eb21ae9afe2fd7d1c commit d780f02a54ff9cb0b5fd181eb21ae9afe2fd7d1c Author: Faisal Abbas <90.abbasfaisal@gmail.com> Date: Sat Aug 6 19:12:47 2022 +0100 rust-constexpr.cc: port over cxx_eval_outermost_constant_expr Diff: --- gcc/rust/backend/rust-constexpr.cc | 318 +++++++++++++++++++++++++++++++++++++ gcc/rust/backend/rust-tree.cc | 43 +++++ gcc/rust/backend/rust-tree.h | 72 ++++++++- 3 files changed, 429 insertions(+), 4 deletions(-) diff --git a/gcc/rust/backend/rust-constexpr.cc b/gcc/rust/backend/rust-constexpr.cc index 6f645beba45..276bfe94e6f 100644 --- a/gcc/rust/backend/rust-constexpr.cc +++ b/gcc/rust/backend/rust-constexpr.cc @@ -31,6 +31,7 @@ #include "tree-inline.h" #include "vec.h" #include "rust-target.h" +#include "function.h" #define VERIFY_CONSTANT(X) \ do \ @@ -4030,6 +4031,323 @@ eval_unary_expression (const constexpr_ctx *ctx, tree t, bool /*lval*/, return r; } +// forked from gcc/cp/constexpr.cc cxx_eval_outermost_constant_expr + +/* ALLOW_NON_CONSTANT is false if T is required to be a constant expression. + STRICT has the same sense as for constant_value_1: true if we only allow + conforming C++ constant expressions, or false if we want a constant value + even if it doesn't conform. + MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as + per P0595 even when ALLOW_NON_CONSTANT is true. + CONSTEXPR_DTOR is true when evaluating the dtor of a constexpr variable. + OBJECT must be non-NULL in that case. */ + +static tree +cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant, + bool strict = true, + bool manifestly_const_eval = false, + bool constexpr_dtor = false, + tree object = NULL_TREE) +{ + auto_timevar time (TV_CONSTEXPR); + + bool non_constant_p = false; + bool overflow_p = false; + + if (BRACE_ENCLOSED_INITIALIZER_P (t)) + { + gcc_checking_assert (allow_non_constant); + return t; + } + + constexpr_global_ctx global_ctx; + constexpr_ctx ctx + = {&global_ctx, NULL, + NULL, NULL, + NULL, NULL, + NULL, allow_non_constant, + strict, manifestly_const_eval || !allow_non_constant}; + + /* Turn off -frounding-math for manifestly constant evaluation. */ + warning_sentinel rm (flag_rounding_math, ctx.manifestly_const_eval); + tree type = initialized_type (t); + tree r = t; + bool is_consteval = false; + if (VOID_TYPE_P (type)) + { + if (constexpr_dtor) + /* Used for destructors of array elements. */ + type = TREE_TYPE (object); + else + { + if (TREE_CODE (t) != CALL_EXPR) + return t; + /* Calls to immediate functions returning void need to be + evaluated. */ + tree fndecl = rs_get_callee_fndecl_nofold (t); + if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl)) + return t; + else + is_consteval = true; + } + } + else if ((TREE_CODE (t) == CALL_EXPR || TREE_CODE (t) == TARGET_EXPR)) + { + /* For non-concept checks, determine if it is consteval. */ + tree x = t; + if (TREE_CODE (x) == TARGET_EXPR) + x = TARGET_EXPR_INITIAL (x); + tree fndecl = rs_get_callee_fndecl_nofold (x); + if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl)) + is_consteval = true; + } + if (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)) + { + /* In C++14 an NSDMI can participate in aggregate initialization, + and can refer to the address of the object being initialized, so + we need to pass in the relevant VAR_DECL if we want to do the + evaluation in a single pass. The evaluation will dynamically + update ctx.values for the VAR_DECL. We use the same strategy + for C++11 constexpr constructors that refer to the object being + initialized. */ + if (constexpr_dtor) + { + gcc_assert (object && VAR_P (object)); + gcc_assert (DECL_DECLARED_CONSTEXPR_P (object)); + gcc_assert (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object)); + if (error_operand_p (DECL_INITIAL (object))) + return t; + ctx.ctor = unshare_expr (DECL_INITIAL (object)); + TREE_READONLY (ctx.ctor) = false; + /* Temporarily force decl_really_constant_value to return false + for it, we want to use ctx.ctor for the current value instead. */ + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = false; + } + else + { + ctx.ctor = build_constructor (type, NULL); + CONSTRUCTOR_NO_CLEARING (ctx.ctor) = true; + } + if (!object) + { + if (TREE_CODE (t) == TARGET_EXPR) + object = TARGET_EXPR_SLOT (t); + } + ctx.object = object; + if (object) + gcc_assert ( + same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE (object))); + if (object && DECL_P (object)) + global_ctx.values.put (object, ctx.ctor); + if (TREE_CODE (r) == TARGET_EXPR) + /* Avoid creating another CONSTRUCTOR when we expand the + TARGET_EXPR. */ + r = TARGET_EXPR_INITIAL (r); + } + + auto_vec cleanups; + global_ctx.cleanups = &cleanups; + + if (manifestly_const_eval) + instantiate_constexpr_fns (r); + r = eval_constant_expression (&ctx, r, false, &non_constant_p, &overflow_p); + + if (!constexpr_dtor) + verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); + else + DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true; + + unsigned int i; + tree cleanup; + /* Evaluate the cleanups. */ + FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) + eval_constant_expression (&ctx, cleanup, false, &non_constant_p, + &overflow_p); + + /* Mutable logic is a bit tricky: we want to allow initialization of + constexpr variables with mutable members, but we can't copy those + members to another constexpr variable. */ + if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_MUTABLE_POISON (r)) + { + if (!allow_non_constant) + error ("%qE is not a constant expression because it refers to " + "mutable subobjects of %qT", + t, type); + non_constant_p = true; + } + + if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r)) + { + if (!allow_non_constant) + error ("%qE is not a constant expression because it refers to " + "an incompletely initialized variable", + t); + TREE_CONSTANT (r) = false; + non_constant_p = true; + } + + if (!global_ctx.heap_vars.is_empty ()) + { + tree heap_var + = rs_walk_tree_without_duplicates (&r, find_heap_var_refs, NULL); + unsigned int i; + if (heap_var) + { + if (!allow_non_constant && !non_constant_p) + error_at (DECL_SOURCE_LOCATION (heap_var), + "%qE is not a constant expression because it refers to " + "a result of %", + t); + r = t; + non_constant_p = true; + } + FOR_EACH_VEC_ELT (global_ctx.heap_vars, i, heap_var) + { + if (DECL_NAME (heap_var) != heap_deleted_identifier) + { + if (!allow_non_constant && !non_constant_p) + error_at (DECL_SOURCE_LOCATION (heap_var), + "%qE is not a constant expression because allocated " + "storage has not been deallocated", + t); + r = t; + non_constant_p = true; + } + varpool_node::get (heap_var)->remove (); + } + } + + /* Check that immediate invocation does not return an expression referencing + any immediate function decls. */ + if (is_consteval || in_immediate_context ()) + if (tree immediate_fndecl + = rs_walk_tree_without_duplicates (&r, find_immediate_fndecl, NULL)) + { + if (!allow_non_constant && !non_constant_p) + error_at (rs_expr_loc_or_input_loc (t), + "immediate evaluation returns address of immediate " + "function %qD", + immediate_fndecl); + r = t; + non_constant_p = true; + } + + if (non_constant_p) + /* If we saw something bad, go back to our argument. The wrapping below is + only for the cases of TREE_CONSTANT argument or overflow. */ + r = t; + + if (!non_constant_p && overflow_p) + non_constant_p = true; + + /* Unshare the result. */ + bool should_unshare = true; + if (r == t || (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_INITIAL (t) == r)) + should_unshare = false; + + if (non_constant_p && !allow_non_constant) + return error_mark_node; + else if (constexpr_dtor) + return r; + else if (non_constant_p && TREE_CONSTANT (r)) + { + /* This isn't actually constant, so unset TREE_CONSTANT. + Don't clear TREE_CONSTANT on ADDR_EXPR, as the middle-end requires + it to be set if it is invariant address, even when it is not + a valid C++ constant expression. Wrap it with a NOP_EXPR + instead. */ + if (EXPR_P (r) && TREE_CODE (r) != ADDR_EXPR) + r = copy_node (r); + else if (TREE_CODE (r) == CONSTRUCTOR) + r = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (r), r); + else + r = build_nop (TREE_TYPE (r), r); + TREE_CONSTANT (r) = false; + } + else if (non_constant_p) + return t; + + if (should_unshare) + r = unshare_expr (r); + + if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r))) + { + r = adjust_temp_type (type, r); + if (TREE_CODE (t) == TARGET_EXPR && TARGET_EXPR_INITIAL (t) == r) + return t; + } + + /* Remember the original location if that wouldn't need a wrapper. */ + if (location_t loc = EXPR_LOCATION (t)) + protected_set_expr_location (r, loc); + + return r; +} + +/* Like is_constant_expression, but allow const variables that are not allowed + under constexpr rules. */ + +bool +is_static_init_expression (tree t) +{ + // return potential_constant_expression_1 (t, false, false, true, tf_none); + // faisal: just return false for now to make it compile +} + +/* Returns true if T is a potential static initializer expression that is not + instantiation-dependent. */ + +bool +is_nondependent_static_init_expression (tree t) +{ + return (!type_unknown_p (t) && is_static_init_expression (t)); +} + +/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather + than wrapped in a TARGET_EXPR. + ALLOW_NON_CONSTANT is false if T is required to be a constant expression. + MANIFESTLY_CONST_EVAL is true if T is manifestly const-evaluated as + per P0595 even when ALLOW_NON_CONSTANT is true. */ + +static tree +maybe_constant_init_1 (tree t, tree decl, bool allow_non_constant, + bool manifestly_const_eval) +{ + if (!t) + return t; + if (TREE_CODE (t) == EXPR_STMT) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == CONVERT_EXPR && VOID_TYPE_P (TREE_TYPE (t))) + t = TREE_OPERAND (t, 0); + if (TREE_CODE (t) == INIT_EXPR) + t = TREE_OPERAND (t, 1); + if (TREE_CODE (t) == TARGET_EXPR) + t = TARGET_EXPR_INITIAL (t); + if (!is_nondependent_static_init_expression (t)) + /* Don't try to evaluate it. */; + else if (CONSTANT_CLASS_P (t) && allow_non_constant) + /* No evaluation needed. */; + else + t = cxx_eval_outermost_constant_expr (t, allow_non_constant, + /*strict*/ false, + manifestly_const_eval, false, decl); + if (TREE_CODE (t) == TARGET_EXPR) + { + tree init = TARGET_EXPR_INITIAL (t); + if (TREE_CODE (init) == CONSTRUCTOR) + t = init; + } + return t; +} + +/* Wrapper for maybe_constant_init_1 which permits non constants. */ + +tree +maybe_constant_init (tree t, tree decl, bool manifestly_const_eval) +{ + return maybe_constant_init_1 (t, decl, true, 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 289b4b95801..ad457a2e4ce 100644 --- a/gcc/rust/backend/rust-tree.cc +++ b/gcc/rust/backend/rust-tree.cc @@ -4108,4 +4108,47 @@ is_empty_field (tree decl) return r; } +// forked from gcc/cp/call.cc in_immediate_context + +/* Return true if in an immediate function context, or an unevaluated operand, + or a subexpression of an immediate invocation. */ + +bool +in_immediate_context () +{ + return false; +} + +// forked from gcc/cp/cvt.cc cp_get_fndecl_from_callee + +/* FN is the callee of a CALL_EXPR or AGGR_INIT_EXPR; return the FUNCTION_DECL + if we can. */ + +tree +rs_get_fndecl_from_callee (tree fn, bool fold /* = true */) +{ + if (fn == NULL_TREE) + return fn; + if (TREE_CODE (fn) == FUNCTION_DECL) + return fn; + tree type = TREE_TYPE (fn); + if (type == NULL_TREE || !INDIRECT_TYPE_P (type)) + return NULL_TREE; + if (fold) + fn = Compile::maybe_constant_init (fn); + STRIP_NOPS (fn); + if (TREE_CODE (fn) == ADDR_EXPR || TREE_CODE (fn) == FDESC_EXPR) + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) == FUNCTION_DECL) + return fn; + return NULL_TREE; +} + +// forked from gcc/cp/cvt.cc cp_get_callee_fndecl_nofold +tree +rs_get_callee_fndecl_nofold (tree call) +{ + return rs_get_fndecl_from_callee (cp_get_callee (call), false); +} + } // namespace Rust diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index f466a81962e..bd11b20e77f 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -1221,6 +1221,9 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; #define current_class_type scope_chain->class_type +#define in_discarded_stmt scope_chain->discarded_stmt +#define in_consteval_if_p scope_chain->consteval_if_p + /* Nonzero means that this type is being defined. I.e., the left brace starting the definition of this type has been seen. */ #define TYPE_BEING_DEFINED(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->being_defined) @@ -1418,8 +1421,62 @@ extern GTY (()) tree cp_global_trees[CPTI_MAX]; #define STAT_TYPE_HIDDEN_P(N) OVL_HIDDEN_P (N) #define STAT_DECL_HIDDEN_P(N) OVL_DEDUP_P (N) +/* The binding level currently in effect. */ + +#define current_binding_level \ + (*(cfun && cp_function_chain && cp_function_chain->bindings \ + ? &cp_function_chain->bindings \ + : &scope_chain->bindings)) + // Above macros are copied from gcc/cp/name-lookup.cc +// forked from gcc/cp/name_lookup.h scope_kind + +/* The kinds of scopes we recognize. */ +enum scope_kind +{ + sk_block = 0, /* An ordinary block scope. This enumerator must + have the value zero because "cp_binding_level" + is initialized by using "memset" to set the + contents to zero, and the default scope kind + is "sk_block". */ + sk_cleanup, /* A scope for (pseudo-)scope for cleanup. It is + pseudo in that it is transparent to name lookup + activities. */ + sk_try, /* A try-block. */ + sk_catch, /* A catch-block. */ + sk_for, /* The scope of the variable declared in a + init-statement. */ + sk_cond, /* The scope of the variable declared in the condition + of an if or switch statement. */ + sk_function_parms, /* The scope containing function parameters. */ + sk_class, /* The scope containing the members of a class. */ + sk_scoped_enum, /* The scope containing the enumerators of a C++11 + scoped enumeration. */ + sk_namespace, /* The scope containing the members of a + namespace, including the global scope. */ + sk_template_parms, /* A scope for template parameters. */ + sk_template_spec, /* Like sk_template_parms, but for an explicit + specialization. Since, by definition, an + explicit specialization is introduced by + "template <>", this scope is always empty. */ + sk_transaction, /* A synchronized or atomic statement. */ + sk_omp /* An OpenMP structured block. */ +}; + +// forked from gcc/cp/cp-tree.h cp_built_in_function + +/* BUILT_IN_FRONTEND function codes. */ +enum cp_built_in_function +{ + CP_BUILT_IN_IS_CONSTANT_EVALUATED, + CP_BUILT_IN_INTEGER_PACK, + CP_BUILT_IN_IS_CORRESPONDING_MEMBER, + CP_BUILT_IN_IS_POINTER_INTERCONVERTIBLE_WITH_CLASS, + CP_BUILT_IN_SOURCE_LOCATION, + CP_BUILT_IN_LAST +}; + // forked from gcc/cp/cp-tree.h warning_sentinel /* RAII sentinel to disable certain warnings during template substitution @@ -2539,13 +2596,10 @@ extern bool reduced_constant_expression_p (tree); extern tree cv_unqualified (tree); extern tree cp_get_callee (tree); -extern tree cp_get_callee_fndecl_nofold (tree); +extern tree rs_get_callee_fndecl_nofold (tree); extern bool is_nondependent_static_init_expression (tree); -extern tree -maybe_constant_init (tree, tree = NULL_TREE, bool = false); - extern tree build_nop (tree, tree); extern bool scalarish_type_p (const_tree); @@ -2609,6 +2663,11 @@ extern tree build_new_constexpr_heap_type (tree, tree, tree); extern bool is_empty_field (tree); +extern bool +in_immediate_context (); + +extern tree cp_get_callee_fndecl_nofold (tree); + // forked from gcc/cp/cp-tree.h enum @@ -2811,6 +2870,11 @@ cxx_incomplete_type_error (const_tree value, const_tree type) extern location_t location_of (tree t); +namespace Compile { +extern tree +maybe_constant_init (tree, tree = NULL_TREE, bool = false); +} + } // namespace Rust #endif // RUST_TREE