diff --git a/lib/std/io/io_formatter_private.c3 b/lib/std/io/io_formatter_private.c3 index 422210730..caee12b5c 100644 --- a/lib/std/io/io_formatter_private.c3 +++ b/lib/std/io/io_formatter_private.c3 @@ -67,7 +67,7 @@ fn uint128! int_from_variant(variant arg, bool *is_neg) @private fn FloatType! float_from_variant(variant arg) @private { $if (env::F128_SUPPORT): - if (arg.type == float128.typeid) return *((float128*)arg.ptr); + if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr); $endif; $if (env::F16_SUPPORT): if (arg.type == float16.typeid) return *((float16*)arg.ptr); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index fdfcbead8..d1c496cdd 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -550,7 +550,7 @@ static void setup_int_define(const char *id, uint64_t i, Type *type) id = symtab_add(id, (uint32_t) strlen(id), fnv1a(id, (uint32_t) strlen(id)), &token_type); Type *flat = type_flatten(type); assert(type_is_integer(flat)); - Expr *expr = expr_new_const_int(INVALID_SPAN, flat, i, true); + Expr *expr = expr_new_const_int(INVALID_SPAN, flat, i); expr->type = type; if (expr_const_will_overflow(&expr->const_expr, flat->type_kind)) { diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 27229ebfb..07f077f2b 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -185,7 +185,6 @@ typedef struct typedef struct { ConstKind const_kind : 8; - bool narrowable : 1; bool is_character : 1; bool is_hex : 1; union @@ -2136,7 +2135,7 @@ bool decl_is_local(Decl *decl); #define EXPR_NEW_TOKEN(kind_) expr_new(kind_, c->span) Expr *expr_new(ExprKind kind, SourceSpan start); -Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v, bool narrowable); +Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v); Expr *expr_new_const_bool(SourceSpan span, Type *type, bool value); Expr *expr_new_const_typeid(SourceSpan span, Type *type); bool expr_is_simple(Expr *expr); @@ -2174,8 +2173,8 @@ INLINE bool expr_is_const_member(Expr *expr); INLINE void expr_rewrite_const_null(Expr *expr, Type *type); INLINE void expr_rewrite_const_bool(Expr *expr, Type *type, bool b); -INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d, bool is_narrowable); -INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v, bool narrowable); +INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d); +INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v); INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type); INLINE void expr_rewrite_const_initializer(Expr *expr, Type *type, ConstInitializer *initializer); INLINE void expr_rewrite_const_untyped_list(Expr *expr, Expr **elements); @@ -3156,7 +3155,7 @@ INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type) expr->resolve_status = RESOLVE_DONE; } -INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v, bool narrowable) +INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v) { expr->expr_kind = EXPR_CONST; expr->type = type; @@ -3169,10 +3168,9 @@ INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v, bool narr (&expr->const_expr)->ixx.i.low = v; (&expr->const_expr)->ixx.type = kind; (&expr->const_expr)->const_kind = CONST_INTEGER; - expr->const_expr.narrowable = narrowable; } -INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d, bool is_narrowable) +INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d) { expr->expr_kind = EXPR_CONST; expr->type = type; @@ -3194,7 +3192,6 @@ INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d, bool is_nar expr->const_expr = (ExprConst) { .fxx = (Float){ real, kind }, .const_kind = CONST_FLOAT, - .narrowable = is_narrowable, }; expr->resolve_status = RESOLVE_DONE; } diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 437ef4796..51a30fc1d 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -547,7 +547,6 @@ static inline ConstInitializer *initializer_for_index(ConstInitializer *initiali void expr_rewrite_to_const_zero(Expr *expr, Type *type) { expr->expr_kind = EXPR_CONST; - expr->const_expr.narrowable = true; switch (type->canonical->type_kind) { case TYPE_POISONED: @@ -555,10 +554,10 @@ void expr_rewrite_to_const_zero(Expr *expr, Type *type) case TYPE_INFERRED_VECTOR: UNREACHABLE case ALL_INTS: - expr_rewrite_const_int(expr, type, 0, true); + expr_rewrite_const_int(expr, type, 0); return; case ALL_FLOATS: - expr_rewrite_const_float(expr, type, 0, true); + expr_rewrite_const_float(expr, type, 0); break; case TYPE_BOOL: expr_rewrite_const_bool(expr, type, false); @@ -815,7 +814,7 @@ Expr *expr_new(ExprKind kind, SourceSpan start) return expr; } -Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v, bool narrowable) +Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v) { Expr *expr = expr_calloc(); expr->expr_kind = EXPR_CONST; @@ -830,7 +829,6 @@ Expr *expr_new_const_int(SourceSpan span, Type *type, uint64_t v, bool narrowabl expr->const_expr.ixx.i.low = v; expr->const_expr.ixx.type = kind; expr->const_expr.const_kind = CONST_INTEGER; - expr->const_expr.narrowable = narrowable; expr->resolve_status = RESOLVE_DONE; return expr; } diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index 3a6c00b06..c6e247786 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -26,7 +26,7 @@ bool parse_range(ParseContext *c, Range *range) { // ..123 and :123 range->start_from_end = false; - range->start = exprid(expr_new_const_int(c->span, type_uint, 0, true)); + range->start = exprid(expr_new_const_int(c->span, type_uint, 0)); } else { @@ -1247,7 +1247,6 @@ Expr *parse_integer(ParseContext *c, Expr *left) expr_int->const_expr.const_kind = CONST_INTEGER; expr_int->const_expr.is_hex = hex_characters > 0; Type *type_base = NULL; - expr_int->const_expr.narrowable = !type_bits; if (type_bits) { if (type_bits < 0 || !is_power_of_two((uint64_t)type_bits) || type_bits > 128) @@ -1449,7 +1448,6 @@ static Expr *parse_char_lit(ParseContext *c, Expr *left) Expr *expr_int = EXPR_NEW_TOKEN(EXPR_CONST); expr_int->const_expr.is_character = true; expr_int->const_expr.ixx.i = c->data.char_value; - expr_int->const_expr.narrowable = true; expr_int->const_expr.const_kind = CONST_INTEGER; switch (c->data.width) { @@ -1515,7 +1513,6 @@ static Expr *parse_double(ParseContext *c, Expr *left) UNREACHABLE } number->const_expr.const_kind = CONST_FLOAT; - number->const_expr.narrowable = true; advance(c); return number; } diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 9900a1dbc..7eae44058 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -13,8 +13,7 @@ static bool cast_expr_inner(SemaContext *context, Expr *expr, Type *to_type, boo bool may_not_be_optional); static bool bitstruct_cast(Expr *expr, Type *from_type, Type *to, Type *to_type); static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type); -static Expr *recursive_may_narrow_float(Expr *expr, Type *type); -static Expr *recursive_may_narrow_int(Expr *expr, Type *type); +static Expr *recursive_may_narrow(Expr *expr, Type *type); static void recursively_rewrite_untyped_list(Expr *expr, Expr **list); static inline bool cast_may_implicit_ptr(Type *from_pointee, Type *to_pointee); static inline bool cast_may_array(Type *from, Type *to, bool is_explicit); @@ -152,7 +151,7 @@ static bool pointer_to_integer(Expr *expr, Type *type) if (insert_runtime_cast_unless_const(expr, CAST_PTRINT, type)) return true; // Revisit this to support pointers > 64 bits. - expr_rewrite_const_int(expr, type, expr->const_expr.ptr, false); + expr_rewrite_const_int(expr, type, expr->const_expr.ptr); return true; } @@ -191,7 +190,6 @@ static bool pointer_to_pointer(Expr* expr, Type *type) // Insert the cast, this removes the ability to narrow it. expr->type = type; - expr->const_expr.narrowable = false; expr->const_expr.is_hex = false; return true; } @@ -205,7 +203,7 @@ static bool bool_to_int(Expr *expr, Type *canonical, Type *type) { if (insert_runtime_cast_unless_const(expr, CAST_BOOLINT, type)) return true; - expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0, false); + expr_rewrite_const_int(expr, type, expr->const_expr.b ? 1 : 0); return true; } @@ -219,7 +217,7 @@ static bool bool_to_float(Expr *expr, Type *canonical, Type *type) if (insert_runtime_cast_unless_const(expr, CAST_BOOLFP, type)) return true; assert(expr->const_expr.const_kind == CONST_BOOL); - expr_rewrite_const_float(expr, type, expr->const_expr.b ? 1.0 : 0.0, false); + expr_rewrite_const_float(expr, type, expr->const_expr.b ? 1.0 : 0.0); return true; } @@ -275,7 +273,7 @@ static bool float_to_float(Expr* expr, Type *canonical, Type *type) if (insert_runtime_cast_unless_const(expr, CAST_FPFP, type)) return true; // Otherwise rewrite the const, which may cause rounding. - expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f, false); + expr_rewrite_const_float(expr, type, expr->const_expr.fxx.f); return true; } @@ -293,7 +291,6 @@ static bool float_to_integer(Expr *expr, Type *canonical, Type *type) expr->const_expr.ixx = int_from_real(d, canonical->type_kind); expr->const_expr.const_kind = CONST_INTEGER; expr->type = type; - expr->const_expr.narrowable = false; expr->const_expr.is_hex = false; return true; } @@ -361,7 +358,6 @@ static bool integer_to_integer(Expr *expr, Type *canonical, Type *type) expr->const_expr.ixx = int_conv(expr->const_expr.ixx, canonical->type_kind); expr->const_expr.const_kind = CONST_INTEGER; expr->type = type; - expr->const_expr.narrowable = false; expr->const_expr.is_hex = false; return true; } @@ -398,7 +394,7 @@ static bool integer_to_float(Expr *expr, Type *canonical, Type *type) if (insert_runtime_cast_unless_const(expr, CAST_INTFP, type)) return true; Real f = int_to_real(expr->const_expr.ixx); - expr_rewrite_const_float(expr, type, f, false); + expr_rewrite_const_float(expr, type, f); return true; } @@ -441,7 +437,7 @@ static void enum_to_int_lowering(Expr* expr) if (expr->expr_kind == EXPR_CONST) { assert(expr->const_expr.const_kind == CONST_ENUM); - expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal, false); + expr_rewrite_const_int(expr, underlying_type, expr->const_expr.enum_err_val->enum_constant.ordinal); } expr->type = type_add_optional(underlying_type, IS_OPTIONAL(expr)); @@ -860,17 +856,20 @@ bool cast_may_bool_convert(Type *type) return true; } -INLINE Expr *recursive_may_narrow_floatid(ExprId expr, Type *type) -{ - return recursive_may_narrow_float(exprptr(expr), type); -} - -Expr *recursive_may_narrow_float(Expr *expr, Type *type) +/** + * Check whether an expression may narrow. + * 1. If it has an intrinsic type, then compare it against the type. If the bitwidth is smaller or same => ok + * 2. If it is a constant, then if it fits in the type it is ok. + * 3. If it has sub expressions, recursively check those if they affect the type. + * 4. Widening casts are ignored, all other casts are opaque. + */ +Expr *recursive_may_narrow(Expr *expr, Type *type) { +RETRY: switch (expr->expr_kind) { - case EXPR_BINARY: case EXPR_BITASSIGN: + case EXPR_BINARY: switch (expr->binary_expr.operator) { case BINARYOP_ERROR: @@ -880,15 +879,33 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case BINARYOP_ADD: case BINARYOP_DIV: case BINARYOP_MOD: - case BINARYOP_ELSE: - { - Expr *res = recursive_may_narrow_float(exprptr(expr->binary_expr.left), type); - if (res) return res; - return recursive_may_narrow_float(exprptr(expr->binary_expr.right), type); - } case BINARYOP_BIT_OR: case BINARYOP_BIT_XOR: case BINARYOP_BIT_AND: + case BINARYOP_ELSE: + { + // *, -, +, /, %, |, ^, &, ?? -> check both sides. + Expr *res = recursive_may_narrow(exprptr(expr->binary_expr.left), type); + if (res) return res; + expr = exprptr(expr->binary_expr.right); + goto RETRY; + } + case BINARYOP_SHR: + case BINARYOP_SHL: + case BINARYOP_ASSIGN: + case BINARYOP_ADD_ASSIGN: + case BINARYOP_BIT_AND_ASSIGN: + case BINARYOP_BIT_OR_ASSIGN: + case BINARYOP_BIT_XOR_ASSIGN: + case BINARYOP_DIV_ASSIGN: + case BINARYOP_MOD_ASSIGN: + case BINARYOP_MULT_ASSIGN: + case BINARYOP_SHR_ASSIGN: + case BINARYOP_SHL_ASSIGN: + case BINARYOP_SUB_ASSIGN: + // For shifts and assignment, ignore the right hand side. + expr = exprptr(expr->binary_expr.left); + goto RETRY; case BINARYOP_AND: case BINARYOP_OR: case BINARYOP_GT: @@ -897,296 +914,114 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case BINARYOP_LE: case BINARYOP_NE: case BINARYOP_EQ: - case BINARYOP_SHR: - case BINARYOP_SHL: - case BINARYOP_BIT_AND_ASSIGN: - case BINARYOP_BIT_OR_ASSIGN: - case BINARYOP_BIT_XOR_ASSIGN: - case BINARYOP_SHR_ASSIGN: - case BINARYOP_SHL_ASSIGN: + // This type is bool, so check should never happen. UNREACHABLE - case BINARYOP_ASSIGN: - case BINARYOP_ADD_ASSIGN: - case BINARYOP_DIV_ASSIGN: - case BINARYOP_MOD_ASSIGN: - case BINARYOP_MULT_ASSIGN: - case BINARYOP_SUB_ASSIGN: - return recursive_may_narrow_float(exprptr(expr->binary_expr.left), type); } UNREACHABLE - case EXPR_MACRO_BODY_EXPANSION: - case EXPR_CALL: - case EXPR_POISONED: - case EXPR_BITACCESS: - case EXPR_ACCESS: - case EXPR_CATCH_UNWRAP: - case EXPR_COMPOUND_LITERAL: - case EXPR_COND: - case EXPR_DECL: - case EXPR_CT_IDENT: - case EXPR_DESIGNATOR: - case EXPR_EXPR_BLOCK: - case EXPR_MACRO_BLOCK: - case EXPR_IDENTIFIER: - case EXPR_SLICE_ASSIGN: - case EXPR_SLICE_COPY: - case EXPR_SLICE: - case EXPR_SUBSCRIPT: - case EXPR_RETVAL: - case EXPR_TYPEID_INFO: - if (type_size(expr->type) > type_size(type)) return expr; - return NULL; + case EXPR_BUILTIN_ACCESS: + switch (expr->builtin_access_expr.kind) + { + case ACCESS_LEN: + // Special: we may resize this, but not smaller than cint. + if (type_size(type) < type_size(type_cint)) return expr; + return NULL; + case ACCESS_PTR: + case ACCESS_TYPEOFANY: + case ACCESS_ENUMNAME: + case ACCESS_FAULTNAME: + // For the rest, just check size. + goto CHECK_SIZE; + } + UNREACHABLE; case EXPR_EXPRESSION_LIST: - return recursive_may_narrow_float(VECLAST(expr->expression_list), type); - case EXPR_GROUP: - case EXPR_FORCE_UNWRAP: - return recursive_may_narrow_float(expr->inner_expr, type); - case EXPR_RETHROW: - return recursive_may_narrow_float(expr->rethrow_expr.inner, type); + // Only the last expression counts for narrowing. + // It's unclear if this can happen. + expr = VECLAST(expr->expression_list); + goto RETRY; case EXPR_TERNARY: { - Expr *res = recursive_may_narrow_floatid(expr->ternary_expr.then_expr ? expr->ternary_expr.then_expr - : expr->ternary_expr.cond, type); + // In the case a ?: b -> check a and b + // In the case a ? b : c -> check b and c + Expr *res = recursive_may_narrow(exprptr(expr->ternary_expr.then_expr + ? expr->ternary_expr.then_expr + : expr->ternary_expr.cond), type); if (res) return res; - return recursive_may_narrow_floatid(expr->ternary_expr.else_expr, type); + expr = exprptr(expr->ternary_expr.else_expr); + goto RETRY; } case EXPR_CAST: - return recursive_may_narrow_floatid(expr->cast_expr.expr, type); - case EXPR_CONST: - if (!expr->const_expr.narrowable) + switch (expr->cast_expr.kind) { - return type_size(expr->type) > type_size(type) ? expr : NULL; + case CAST_INTINT: + case CAST_FPFP: + // If this is a narrowing cast that makes it smaller that then target type + // we're done. + if (type_size(type) >= type_size(expr->type)) + { + return NULL; + } + // Otherwise just look through it. + expr = exprptr(expr->cast_expr.expr); + goto RETRY; + default: + // For all other casts we regard them as opaque. + goto CHECK_SIZE; } + case EXPR_CONST: + // For constants, just check that they will fit. + if (type_is_integer(type)) + { + assert(expr->const_expr.const_kind == CONST_INTEGER || expr->const_expr.const_kind == CONST_ENUM); + if (expr_const_will_overflow(&expr->const_expr, type_flatten(type)->type_kind)) + { + return expr; + } + return NULL; + } + assert(type_is_float(type)); assert(expr->const_expr.const_kind == CONST_FLOAT); if (!expr_const_float_fits_type(&expr->const_expr, type_flatten(type)->type_kind)) { return expr; } return NULL; - case EXPR_OPTIONAL: - case EXPR_HASH_IDENT: - case EXPR_FLATPATH: - case EXPR_INITIALIZER_LIST: - case EXPR_DESIGNATED_INITIALIZER_LIST: - case EXPR_TYPEID: - case EXPR_TYPEINFO: - case EXPR_CT_CALL: - case EXPR_NOP: - case EXPR_CATCH: - case EXPR_BUILTIN: - case EXPR_TRY_UNWRAP: - case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_SUBSCRIPT_ADDR: - case EXPR_VARIANTSWITCH: - case EXPR_COMPILER_CONST: - case EXPR_STRINGIFY: - case EXPR_CT_EVAL: - case EXPR_VARIANT: - case EXPR_POINTER_OFFSET: - case EXPR_CT_ARG: - case EXPR_ASM: - case EXPR_VASPLAT: - case EXPR_OPERATOR_CHARS: - case EXPR_CT_CHECKS: - case EXPR_SUBSCRIPT_ASSIGN: - case EXPR_SWIZZLE: - case EXPR_LAMBDA: - UNREACHABLE - case EXPR_BUILTIN_ACCESS: - case EXPR_TEST_HOOK: - return false; case EXPR_POST_UNARY: - return recursive_may_narrow_float(expr->unary_expr.expr, type); - case EXPR_TRY: - return recursive_may_narrow_float(expr->inner_expr, type); - case EXPR_UNARY: - { - switch (expr->unary_expr.operator) - { - case UNARYOP_DEREF: - return false; - case UNARYOP_ERROR: - case UNARYOP_ADDR: - case UNARYOP_NOT: - case UNARYOP_TADDR: - UNREACHABLE - case UNARYOP_NEG: - case UNARYOP_BITNEG: - case UNARYOP_INC: - case UNARYOP_DEC: - return recursive_may_narrow_float(expr->unary_expr.expr, type); - } - } - } - UNREACHABLE -} - -INLINE Expr *recursive_may_narrow_intid(ExprId expr, Type *type) -{ - assert(expr); - return recursive_may_narrow_int(exprptr(expr), type); -} - -Expr *recursive_may_narrow_int(Expr *expr, Type *type) -{ - switch (expr->expr_kind) - { - case EXPR_BITASSIGN: - case EXPR_BINARY: - switch (expr->binary_expr.operator) - { - case BINARYOP_ERROR: - UNREACHABLE - case BINARYOP_MULT: - case BINARYOP_SUB: - case BINARYOP_ADD: - case BINARYOP_DIV: - case BINARYOP_MOD: - case BINARYOP_BIT_OR: - case BINARYOP_BIT_XOR: - case BINARYOP_BIT_AND: - case BINARYOP_ELSE: - { - Expr *res = recursive_may_narrow_int(exprptr(expr->binary_expr.left), type); - if (res) return res; - return recursive_may_narrow_int(exprptr(expr->binary_expr.right), type); - } - case BINARYOP_AND: - case BINARYOP_OR: - case BINARYOP_GT: - case BINARYOP_GE: - case BINARYOP_LT: - case BINARYOP_LE: - case BINARYOP_NE: - case BINARYOP_EQ: - return NULL; - case BINARYOP_SHR: - case BINARYOP_SHL: - case BINARYOP_ASSIGN: - case BINARYOP_ADD_ASSIGN: - case BINARYOP_BIT_AND_ASSIGN: - case BINARYOP_BIT_OR_ASSIGN: - case BINARYOP_BIT_XOR_ASSIGN: - case BINARYOP_DIV_ASSIGN: - case BINARYOP_MOD_ASSIGN: - case BINARYOP_MULT_ASSIGN: - case BINARYOP_SHR_ASSIGN: - case BINARYOP_SHL_ASSIGN: - case BINARYOP_SUB_ASSIGN: - return recursive_may_narrow_int(exprptr(expr->binary_expr.left), type); - } - UNREACHABLE - case EXPR_MACRO_BODY_EXPANSION: - case EXPR_CALL: - case EXPR_POISONED: - case EXPR_BITACCESS: - case EXPR_ACCESS: - case EXPR_CATCH_UNWRAP: - case EXPR_COMPOUND_LITERAL: - case EXPR_COND: - case EXPR_DECL: - case EXPR_CT_IDENT: - case EXPR_DESIGNATOR: - case EXPR_EXPR_BLOCK: - case EXPR_MACRO_BLOCK: - case EXPR_IDENTIFIER: - case EXPR_SLICE_ASSIGN: - case EXPR_SLICE_COPY: - case EXPR_SLICE: - case EXPR_SUBSCRIPT: - case EXPR_RETVAL: - case EXPR_SUBSCRIPT_ASSIGN: - case EXPR_TYPEID_INFO: - if (type_size(expr->type) > type_size(type)) return expr; - return NULL; - case EXPR_BUILTIN_ACCESS: - switch (expr->builtin_access_expr.kind) - { - case ACCESS_LEN: - if (type_size(type) < type_size(type_cint)) return expr; - return NULL; - case ACCESS_TYPEOFANY: - case ACCESS_PTR: - case ACCESS_ENUMNAME: - case ACCESS_FAULTNAME: - return NULL; - } - UNREACHABLE; - case EXPR_EXPRESSION_LIST: - return recursive_may_narrow_int(VECLAST(expr->expression_list), type); - case EXPR_RETHROW: - return recursive_may_narrow_int(expr->rethrow_expr.inner, type); - case EXPR_TERNARY: - { - Expr *res = recursive_may_narrow_intid(expr->ternary_expr.then_expr ? expr->ternary_expr.then_expr - : expr->ternary_expr.cond, type); - if (res) return res; - return recursive_may_narrow_intid(expr->ternary_expr.else_expr, type); - } - case EXPR_CAST: - return recursive_may_narrow_intid(expr->cast_expr.expr, type); - case EXPR_CONST: - assert(expr->const_expr.const_kind == CONST_INTEGER || expr->const_expr.const_kind == CONST_ENUM); - if (expr_const_will_overflow(&expr->const_expr, type_flatten(type)->type_kind)) - { - return expr; - } - return NULL; - case EXPR_OPTIONAL: - case EXPR_HASH_IDENT: - case EXPR_FLATPATH: - case EXPR_INITIALIZER_LIST: - case EXPR_DESIGNATED_INITIALIZER_LIST: - case EXPR_TYPEID: - case EXPR_TYPEINFO: - case EXPR_CT_CALL: - case EXPR_NOP: - case EXPR_BUILTIN: - case EXPR_TRY_UNWRAP: - case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_SUBSCRIPT_ADDR: - case EXPR_VARIANTSWITCH: - case EXPR_COMPILER_CONST: - case EXPR_STRINGIFY: - case EXPR_CT_EVAL: - case EXPR_VARIANT: - case EXPR_POINTER_OFFSET: - case EXPR_CT_ARG: - case EXPR_ASM: - case EXPR_VASPLAT: - case EXPR_OPERATOR_CHARS: - case EXPR_CT_CHECKS: - case EXPR_SWIZZLE: - case EXPR_LAMBDA: - UNREACHABLE - case EXPR_TEST_HOOK: - return false; - case EXPR_POST_UNARY: - return recursive_may_narrow_int(expr->unary_expr.expr, type); - case EXPR_TRY: - case EXPR_CATCH: + expr = expr->unary_expr.expr; + goto RETRY; case EXPR_GROUP: case EXPR_FORCE_UNWRAP: - return recursive_may_narrow_int(expr->inner_expr, type); + expr = expr->inner_expr; + goto RETRY; + case EXPR_RETHROW: + expr = expr->rethrow_expr.inner; + goto RETRY; case EXPR_UNARY: { switch (expr->unary_expr.operator) { case UNARYOP_ERROR: - case UNARYOP_DEREF: case UNARYOP_ADDR: case UNARYOP_NOT: case UNARYOP_TADDR: UNREACHABLE + case UNARYOP_DEREF: + // Check sizes. + goto CHECK_SIZE; case UNARYOP_NEG: case UNARYOP_BITNEG: case UNARYOP_INC: case UNARYOP_DEC: - return recursive_may_narrow_int(expr->unary_expr.expr, type); + expr = expr->unary_expr.expr; + goto RETRY; } } + default: + // Check type sizes + goto CHECK_SIZE; } - UNREACHABLE +CHECK_SIZE: + if (type_size(expr->type) > type_size(type)) return expr; + return NULL; } static void sema_error_const_int_out_of_range(Expr *expr, Expr *problem, Type *to_type) @@ -1267,9 +1102,7 @@ bool cast_implicit_silent(SemaContext *context, Expr *expr, Type *to_type) bool cast_explicit(SemaContext *context, Expr *expr, Type *to_type) { - if (!cast_expr_inner(context, expr, to_type, true, false, false)) return false; - if (expr_is_const(expr)) expr->const_expr.narrowable = false; - return true; + return cast_expr_inner(context, expr, to_type, true, false, false); } static inline bool cast_with_optional(Expr *expr, Type *to_type, bool add_optional) @@ -1491,10 +1324,12 @@ RETRY: return false; } if (to_size == from_size) goto CAST; - Expr *problem = recursive_may_narrow_int(expr, to); + assert(to == type_flatten(to)); + Expr *problem = recursive_may_narrow(expr, to); if (problem) { if (no_report) return false; + expr = problem; goto REQUIRE_CAST; } goto CAST; @@ -1573,10 +1408,11 @@ RETRY: return false; } if (to_size == from_size) goto CAST; - Expr *problem = recursive_may_narrow_float(expr, to); + Expr *problem = recursive_may_narrow(expr, to); if (problem) { if (silent) return false; + expr = problem; goto REQUIRE_CAST; } goto CAST; @@ -2133,7 +1969,6 @@ bool cast(Expr *expr, Type *to_type) expr->type = type_add_optional(to_type, from_is_optional); if (expr->expr_kind == EXPR_CONST) { - expr->const_expr.narrowable = false; expr->const_expr.is_hex = false; } return true; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 650a4723c..72d3a4fcd 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2783,7 +2783,6 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) } if (init_expr->expr_kind == EXPR_CONST) { - init_expr->const_expr.narrowable = false; init_expr->const_expr.is_hex = false; } } diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index fbe06f986..7da68a20a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2889,7 +2889,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e if (name == kw_offsetof) { - expr_rewrite_const_int(expr, type_usz, parent->const_expr.member.offset, true); + expr_rewrite_const_int(expr, type_usz, parent->const_expr.member.offset); return true; } TypeProperty type_property = type_property_by_name(name); @@ -2904,8 +2904,8 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e return true; case TYPE_PROPERTY_ALIGNOF: expr_rewrite_const_int(expr, type_usz, - type_min_alignment(parent->const_expr.member.offset, parent->const_expr.member.align), - true); + type_min_alignment(parent->const_expr.member.offset, + parent->const_expr.member.align)); return true; case TYPE_PROPERTY_MEMBERSOF: sema_create_const_membersof(context, expr, decl->type->canonical, parent->const_expr.member.align, parent->const_expr.member.offset); @@ -2977,7 +2977,7 @@ static inline bool sema_create_const_kind(Expr *expr, Type *type) Type *type_for_kind = type_kind ? type_kind->type : type_char; unsigned val = type_get_introspection_kind(type->type_kind); assert(type_for_kind->type_kind == TYPE_ENUM); - expr_rewrite_const_int(expr, type_flatten(type_for_kind), val, false); + expr_rewrite_const_int(expr, type_flatten(type_for_kind), val); return cast(expr, type_for_kind); } @@ -3002,7 +3002,7 @@ static inline bool sema_create_const_len(SemaContext *context, Expr *expr, Type default: return false; } - expr_rewrite_const_int(expr, type_usz, len, true); + expr_rewrite_const_int(expr, type_usz, len); return true; } @@ -3373,7 +3373,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, return sema_analyse_expr(context, expr); case TYPE_PROPERTY_ELEMENTS: if (!type_kind_is_enumlike(flat->type_kind)) return false; - expr_rewrite_const_int(expr, type_isz, vec_size(flat->decl->enums.values), true); + expr_rewrite_const_int(expr, type_isz, vec_size(flat->decl->enums.values)); return true; case TYPE_PROPERTY_VALUES: if (!type_kind_is_enumlike(flat->type_kind)) return false; @@ -3398,7 +3398,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, expr_rewrite_const_typeid(expr, type_infoptr(flat->function.signature->rtype)->type); return true; case TYPE_PROPERTY_SIZEOF: - expr_rewrite_const_int(expr, type_usz, type_size(type), true); + expr_rewrite_const_int(expr, type_usz, type_size(type)); return true; case TYPE_PROPERTY_NAMEOF: sema_expr_rewrite_to_type_nameof(expr, type, TOKEN_CT_NAMEOF); @@ -3410,7 +3410,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, { AlignSize align; if (!sema_set_abi_alignment(context, type, &align)) return false; - expr_rewrite_const_int(expr, type_usz, align, true); + expr_rewrite_const_int(expr, type_usz, align); return true; } case TYPE_PROPERTY_EXTNAMEOF: @@ -3442,7 +3442,7 @@ static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, E { expr->expr_kind = EXPR_SUBSCRIPT_ADDR; expr->subscript_expr = (ExprSubscript) { - .range.start = exprid(expr_new_const_int(expr->span, type_usz, index, true)), + .range.start = exprid(expr_new_const_int(expr->span, type_usz, index)), .expr = exprid(parent) }; expr->resolve_status = RESOLVE_DONE; @@ -3557,12 +3557,12 @@ CHECK_DEEPER: } if (flat_type->type_kind == TYPE_ARRAY || flat_type->type_kind == TYPE_VECTOR) { - expr_rewrite_const_int(expr, type_isz, flat_type->array.len, true); + expr_rewrite_const_int(expr, type_isz, flat_type->array.len); return true; } if (flat_type->type_kind == TYPE_UNTYPED_LIST) { - expr_rewrite_const_int(expr, type_isz, vec_size(current_parent->const_expr.untyped_list), true); + expr_rewrite_const_int(expr, type_isz, vec_size(current_parent->const_expr.untyped_list)); return true; } } @@ -4440,7 +4440,7 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left, if (expr_both_const(left, right) && sema_constant_fold_ops(left)) { expr_rewrite_const_int(expr, type_isz, (left->const_expr.ptr - right->const_expr.ptr) / - type_size(left_type->pointer), false); + type_size(left_type->pointer)); return true; } // 3b. Set the type @@ -6043,15 +6043,15 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * case BUILTIN_DEF_LINE: if (context->original_inline_line) { - expr_rewrite_const_int(expr, type_isz, context->original_inline_line, true); + expr_rewrite_const_int(expr, type_isz, context->original_inline_line); } else { - expr_rewrite_const_int(expr, type_isz, expr->span.row, true); + expr_rewrite_const_int(expr, type_isz, expr->span.row); } return true; case BUILTIN_DEF_LINE_RAW: - expr_rewrite_const_int(expr, type_isz, expr->span.row, true); + expr_rewrite_const_int(expr, type_isz, expr->span.row); return true; case BUILTIN_DEF_FUNCTION: switch (context->call_env.kind) @@ -6357,7 +6357,7 @@ static inline bool sema_expr_analyse_ct_alignof(SemaContext *context, Expr *expr type = result_type; } - expr_rewrite_const_int(expr, type_isz, align, true); + expr_rewrite_const_int(expr, type_isz, align); return true; } @@ -6811,7 +6811,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Expr *expr) switch (type) { case TOKEN_CT_VACOUNT: - expr_rewrite_const_int(expr, type_usz, vec_size(context->macro_varargs), true); + expr_rewrite_const_int(expr, type_usz, vec_size(context->macro_varargs)); return true; case TOKEN_CT_VAARG: { @@ -6965,7 +6965,7 @@ static inline bool sema_expr_analyse_ct_offsetof(SemaContext *context, Expr *exp type = result_type; } - expr_rewrite_const_int(expr, type_isz, offset, true); + expr_rewrite_const_int(expr, type_isz, offset); return true; } diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 1a7b97be4..81a59e99c 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -281,7 +281,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex vec_add(expr_list->expression_list, decl_expr); Expr *sub = expr_new_expr(EXPR_SUBSCRIPT, element); sub->subscript_expr.expr = exprid(expr_variable(decl)); - sub->subscript_expr.range.start = exprid(expr_new_const_int(element->span, type_usz, 0, true)); + sub->subscript_expr.range.start = exprid(expr_new_const_int(element->span, type_usz, 0)); vec_add(expr_list->expression_list, sub); if (!sema_analyse_expr_rhs(context, inner_type, expr_list, true)) return false; elements[i] = expr_list; @@ -289,7 +289,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex { sub = expr_new_expr(EXPR_SUBSCRIPT, element); sub->subscript_expr.expr = exprid(expr_variable(decl)); - sub->subscript_expr.range.start = exprid(expr_new_const_int(element->span, type_usz, 1, true)); + sub->subscript_expr.range.start = exprid(expr_new_const_int(element->span, type_usz, 1)); vec_insert_at(elements, i + j, sub); if (!sema_analyse_expr_rhs(context, inner_type, sub, true)) return false; } diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 76982f3a1..4717b491d 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1432,7 +1432,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen if (!len_call) { // Create const len if missing. - len_call = expr_new_const_int(enumerator->span, type_isz, array_len, true); + len_call = expr_new_const_int(enumerator->span, type_isz, array_len); } if (!cast_implicit(context, len_call, index_type)) return false; // __idx$ = (IndexType)(@__enum$.len()) (or const) @@ -1446,7 +1446,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen if (!cast_implicit(context, len_call, index_type)) return false; vec_add(expressions, expr_generate_decl(len_decl, len_call)); } - Expr *idx_init = expr_new_const_int(idx_decl->span, index_type, 0, true); + Expr *idx_init = expr_new_const_int(idx_decl->span, index_type, 0); vec_add(expressions, expr_generate_decl(idx_decl, idx_init)); } @@ -1462,7 +1462,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen cond = expr_new(EXPR_BINARY, idx_decl->span); cond->binary_expr.operator = BINARYOP_GT; cond->binary_expr.left = exprid(expr_variable(idx_decl)); - Expr *rhs = expr_new_const_int(enumerator->span, index_type, 0, true); + Expr *rhs = expr_new_const_int(enumerator->span, index_type, 0); cond->binary_expr.right = exprid(rhs); // Create --__idx$ @@ -1485,7 +1485,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen } else { - Expr *rhs = expr_new_const_int(enumerator->span, type_isz, array_len, true); + Expr *rhs = expr_new_const_int(enumerator->span, type_isz, array_len); cond->binary_expr.right = exprid(rhs); } @@ -2396,7 +2396,7 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state } if (index) { - index->var.init_expr = expr_new_const_int(index->span, type_int, i, true); + index->var.init_expr = expr_new_const_int(index->span, type_int, i); index->type = type_int; } if (!sema_analyse_compound_stmt(context, compound_stmt)) goto FAILED; diff --git a/src/version.h b/src/version.h index ddd7f0d71..890360606 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.93" \ No newline at end of file +#define COMPILER_VERSION "0.4.94" \ No newline at end of file diff --git a/test/test_suite/expressions/casts/narrowing_through_casts.c3 b/test/test_suite/expressions/casts/narrowing_through_casts.c3 new file mode 100644 index 000000000..9b4e3c6f7 --- /dev/null +++ b/test/test_suite/expressions/casts/narrowing_through_casts.c3 @@ -0,0 +1,9 @@ +fn void main() +{ + long x; + + int i = (char)x; // Ok + char c; + short s1 = (long)c; // Ok + short s2 = (long)i; // #error: 'int' cannot implicitly be converted +} \ No newline at end of file