fix(codegen): reject out-of-range field defaults at declaration
This commit is contained in:
1 parent
002a98f3f4
commit
e63fc34057
1 file changed
+28
@@ -2478,6 +2478,34 @@ novirtual class StructGenMixin:
|
||||
else:
|
||||
fe.Ty = field_ty
|
||||
fe.DefaultVal = default_val
|
||||
# Field defaults are otherwise validated only when a constructor applies them, so an
|
||||
# uninstantiated class/struct would silently keep an out-of-range literal
|
||||
# (`class C: x: int8 = 1000`). Validate the integer-literal form at declaration time.
|
||||
if default_val is not None:
|
||||
dv_kind: int = default_val.kind()
|
||||
dv_iv: int64 = 0
|
||||
dv_is_int: int = 0
|
||||
if dv_kind == ast.ASTKind.Constant:
|
||||
dv_cn: ast.Constant* = ast.Constant*(default_val)
|
||||
if dv_cn is not None and dv_cn.const_kind == ast.CONST_INT:
|
||||
dv_iv = dv_cn.int_val
|
||||
dv_is_int = 1
|
||||
elif dv_kind == ast.ASTKind.UnaryOp:
|
||||
dv_uo: ast.UnaryOp* = ast.UnaryOp*(default_val)
|
||||
if dv_uo is not None and dv_uo.op == ast.OpKind.USub and dv_uo.operand is not None:
|
||||
if dv_uo.operand.kind() == ast.ASTKind.Constant:
|
||||
dv_cn2: ast.Constant* = ast.Constant*(dv_uo.operand)
|
||||
if dv_cn2 is not None and dv_cn2.const_kind == ast.CONST_INT:
|
||||
dv_iv = -dv_cn2.int_val
|
||||
dv_is_int = 1
|
||||
if dv_is_int != 0:
|
||||
dv_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(field_ty)
|
||||
# 64-bit constants are already carried as int64; 1<<63/1<<64 would overflow here.
|
||||
if dv_bits == 8 or dv_bits == 16 or dv_bits == 32:
|
||||
dv_lo: int64 = -(int64(1) << (dv_bits - 1))
|
||||
dv_hi: int64 = (int64(1) << dv_bits) - 1
|
||||
if dv_iv < dv_lo or dv_iv > dv_hi:
|
||||
self.Gen.TypeGenErr.fatal_error(default_val, f"field '{field_name}' default value {dv_iv} does not fit its {dv_bits}-bit type [{dv_lo}, {dv_hi}]; use an explicit cast or widen the field type", "OverflowError")
|
||||
# Instances are always PermPool-allocated (resident or a separate copy), so they naturally survive a 1b reset.
|
||||
arena_f: TSpec.TypeSpecArena* = self.Gen.TypeGenBase.ensure_spec_arena()
|
||||
if arena_f is not None:
|
||||
|
||||
Reference in new issue
Block a user