diff options
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index cd34e8e..e0d3580 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3950,6 +3950,205 @@ cxx_eval_bit_field_ref (const constexpr_ctx *ctx, tree t, return error_mark_node; } +/* Helper for cxx_eval_bit_cast. + Check [bit.cast]/3 rules, bit_cast is constexpr only if the To and From + types and types of all subobjects have is_union_v<T>, is_pointer_v<T>, + is_member_pointer_v<T>, is_volatile_v<T> false and has no non-static + data members of reference type. */ + +static bool +check_bit_cast_type (const constexpr_ctx *ctx, location_t loc, tree type, + tree orig_type) +{ + if (TREE_CODE (type) == UNION_TYPE) + { + if (!ctx->quiet) + { + if (type == orig_type) + error_at (loc, "%qs is not a constant expression because %qT is " + "a union type", "__builtin_bit_cast", type); + else + error_at (loc, "%qs is not a constant expression because %qT " + "contains a union type", "__builtin_bit_cast", + orig_type); + } + return true; + } + if (TREE_CODE (type) == POINTER_TYPE) + { + if (!ctx->quiet) + { + if (type == orig_type) + error_at (loc, "%qs is not a constant expression because %qT is " + "a pointer type", "__builtin_bit_cast", type); + else + error_at (loc, "%qs is not a constant expression because %qT " + "contains a pointer type", "__builtin_bit_cast", + orig_type); + } + return true; + } + if (TREE_CODE (type) == REFERENCE_TYPE) + { + if (!ctx->quiet) + { + if (type == orig_type) + error_at (loc, "%qs is not a constant expression because %qT is " + "a reference type", "__builtin_bit_cast", type); + else + error_at (loc, "%qs is not a constant expression because %qT " + "contains a reference type", "__builtin_bit_cast", + orig_type); + } + return true; + } + if (TYPE_PTRMEM_P (type)) + { + if (!ctx->quiet) + { + if (type == orig_type) + error_at (loc, "%qs is not a constant expression because %qT is " + "a pointer to member type", "__builtin_bit_cast", + type); + else + error_at (loc, "%qs is not a constant expression because %qT " + "contains a pointer to member type", + "__builtin_bit_cast", orig_type); + } + return true; + } + if (TYPE_VOLATILE (type)) + { + if (!ctx->quiet) + { + if (type == orig_type) + error_at (loc, "%qs is not a constant expression because %qT is " + "volatile", "__builtin_bit_cast", type); + else + error_at (loc, "%qs is not a constant expression because %qT " + "contains a volatile subobject", + "__builtin_bit_cast", orig_type); + } + return true; + } + if (TREE_CODE (type) == RECORD_TYPE) + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && check_bit_cast_type (ctx, loc, TREE_TYPE (field), orig_type)) + return true; + return false; +} + +/* Subroutine of cxx_eval_constant_expression. + Attempt to evaluate a BIT_CAST_EXPR. */ + +static tree +cxx_eval_bit_cast (const constexpr_ctx *ctx, tree t, bool *non_constant_p, + bool *overflow_p) +{ + if (check_bit_cast_type (ctx, EXPR_LOCATION (t), TREE_TYPE (t), + TREE_TYPE (t)) + || check_bit_cast_type (ctx, cp_expr_loc_or_loc (TREE_OPERAND (t, 0), + EXPR_LOCATION (t)), + TREE_TYPE (TREE_OPERAND (t, 0)), + TREE_TYPE (TREE_OPERAND (t, 0)))) + { + *non_constant_p = true; + return t; + } + + tree op = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), false, + non_constant_p, overflow_p); + if (*non_constant_p) + return t; + + location_t loc = EXPR_LOCATION (t); + if (BITS_PER_UNIT != 8 || CHAR_BIT != 8) + { + if (!ctx->quiet) + sorry_at (loc, "%qs cannot be constant evaluated on the target", + "__builtin_bit_cast"); + *non_constant_p = true; + return t; + } + + if (!tree_fits_shwi_p (TYPE_SIZE_UNIT (TREE_TYPE (t)))) + { + if (!ctx->quiet) + sorry_at (loc, "%qs cannot be constant evaluated because the " + "type is too large", "__builtin_bit_cast"); + *non_constant_p = true; + return t; + } + + HOST_WIDE_INT len = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (t))); + if (len < 0 || (int) len != len) + { + if (!ctx->quiet) + sorry_at (loc, "%qs cannot be constant evaluated because the " + "type is too large", "__builtin_bit_cast"); + *non_constant_p = true; + return t; + } + + unsigned char buf[64]; + unsigned char *ptr, *mask; + size_t alen = (size_t) len * 2; + if (alen <= sizeof (buf)) + ptr = buf; + else + ptr = XNEWVEC (unsigned char, alen); + mask = ptr + (size_t) len; + /* At the beginning consider everything indeterminate. */ + memset (mask, ~0, (size_t) len); + + if (native_encode_initializer (op, ptr, len, 0, mask) != len) + { + if (!ctx->quiet) + sorry_at (loc, "%qs cannot be constant evaluated because the " + "argument cannot be encoded", "__builtin_bit_cast"); + *non_constant_p = true; + if (ptr != buf) + XDELETE (ptr); + return t; + } + + tree r = NULL_TREE; + if (can_native_interpret_type_p (TREE_TYPE (t))) + r = native_interpret_expr (TREE_TYPE (t), ptr, len); + else if (TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE) + { + r = native_interpret_aggregate (TREE_TYPE (t), ptr, 0, len); + if (r != NULL_TREE) + clear_type_padding_in_mask (TREE_TYPE (t), mask); + } + + if (r != NULL_TREE) + { + for (int i = 0; i < len; i++) + if (mask[i]) + { + if (!ctx->quiet) + error_at (loc, "%qs accessing uninitialized byte at offset %d", + "__builtin_bit_cast", i); + *non_constant_p = true; + r = t; + break; + } + if (ptr != buf) + XDELETE (ptr); + return r; + } + + if (!ctx->quiet) + sorry_at (loc, "%qs cannot be constant evaluated because the " + "argument cannot be interpreted", "__builtin_bit_cast"); + *non_constant_p = true; + if (ptr != buf) + XDELETE (ptr); + return t; +} + /* Subroutine of cxx_eval_constant_expression. Evaluate a short-circuited logical expression T in the context of a given constexpr CALL. BAILOUT_VALUE is the value for @@ -6653,6 +6852,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, *non_constant_p = true; return t; + case BIT_CAST_EXPR: + r = cxx_eval_bit_cast (ctx, t, non_constant_p, overflow_p); + break; + default: if (STATEMENT_CODE_P (TREE_CODE (t))) { @@ -8442,6 +8645,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case ANNOTATE_EXPR: return RECUR (TREE_OPERAND (t, 0), rval); + case BIT_CAST_EXPR: + return RECUR (TREE_OPERAND (t, 0), rval); + /* Coroutine await, yield and return expressions are not. */ case CO_AWAIT_EXPR: case CO_YIELD_EXPR: |