From afe4369f6e1100fbacc0eb60a8d838dd0411850a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Jan 2026 15:37:54 +0000 Subject: [PATCH 1/3] Add `#+feature force-type-assert` which overrides `-no-type-assert` on a per-file basis --- src/build_settings.cpp | 8 +++++- src/llvm_backend_expr.cpp | 59 ++++++++++++++++++++++++++------------- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 7d43788cd..e66d46713 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -360,12 +360,15 @@ enum OptInFeatureFlags : u64 { OptInFeatureFlag_IntegerDivisionByZero_Self = 1u<<4, OptInFeatureFlag_IntegerDivisionByZero_AllBits = 1u<<5, - OptInFeatureFlag_IntegerDivisionByZero_ALL = OptInFeatureFlag_IntegerDivisionByZero_Trap| OptInFeatureFlag_IntegerDivisionByZero_Zero| OptInFeatureFlag_IntegerDivisionByZero_Self| OptInFeatureFlag_IntegerDivisionByZero_AllBits, + OptInFeatureFlag_ForceTypeAssert = 1u<<6, + + + }; u64 get_feature_flag_from_name(String const &name) { @@ -384,6 +387,9 @@ u64 get_feature_flag_from_name(String const &name) { if (name == "integer-division-by-zero:all-bits") { return OptInFeatureFlag_IntegerDivisionByZero_AllBits; } + if (name == "force-type-assert") { + return OptInFeatureFlag_ForceTypeAssert; + } if (name == "global-context") { diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index dba61df44..59359942e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -282,8 +282,7 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, return res; } - -gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) { +gb_internal u64 lb_get_file_feature_flags(lbProcedure *p) { AstFile *file = nullptr; if (p->body && p->body->file()) { @@ -295,20 +294,29 @@ gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_beha } if (file != nullptr && file->feature_flags_set) { - u64 flags = file->feature_flags; - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) { - return IntegerDivisionByZero_Trap; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { - return IntegerDivisionByZero_Zero; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { - return IntegerDivisionByZero_Self; - } - if (flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) { - return IntegerDivisionByZero_AllBits; - } + return file->feature_flags; } + return 0; +} + + + +gb_internal IntegerDivisionByZeroKind lb_check_for_integer_division_by_zero_behaviour(lbProcedure *p) { + u64 flags = lb_get_file_feature_flags(p); + + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Trap) { + return IntegerDivisionByZero_Trap; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Zero) { + return IntegerDivisionByZero_Zero; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_Self) { + return IntegerDivisionByZero_Self; + } + if (flags & OptInFeatureFlag_IntegerDivisionByZero_AllBits) { + return IntegerDivisionByZero_AllBits; + } + return build_context.integer_division_by_zero_behaviour; } @@ -3802,6 +3810,17 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *type = type_of_expr(ue_expr); GB_ASSERT(!is_type_tuple(type)); + bool do_type_check = true; + if (build_context.no_type_assert) { + u64 feature_flags = lb_get_file_feature_flags(p); + if ((feature_flags & OptInFeatureFlag_ForceTypeAssert) == 0) { + do_type_check = false; + } + + } else if ((p->state_flags & StateFlag_no_type_assert) != 0) { + do_type_check = false; + } + lbValue e = lb_build_expr(p, ta->expr); Type *t = type_deref(e.type); if (is_type_union(t)) { @@ -3813,7 +3832,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { Type *dst_type = type; - if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + if (do_type_check) { lbValue src_tag = {}; lbValue dst_tag = {}; if (is_type_union_maybe_pointer(src_type)) { @@ -3851,7 +3870,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { v = lb_emit_load(p, v); } lbValue data_ptr = lb_emit_struct_ev(p, v, 0); - if (!build_context.no_type_assert && (p->state_flags & StateFlag_no_type_assert) == 0) { + if (do_type_check) { GB_ASSERT(!build_context.no_rtti); lbValue any_id = lb_emit_struct_ev(p, v, 1); @@ -5313,7 +5332,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); + u64 feature_flags = lb_get_file_feature_flags(p); + GB_ASSERT(feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -5402,7 +5422,8 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); + u64 feature_flags = lb_get_file_feature_flags(p); + GB_ASSERT(feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); From efdb89afcb893d9b405d517d00331082fcc849df Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Jan 2026 15:41:15 +0000 Subject: [PATCH 2/3] Revert dynamic literals feature check --- src/llvm_backend_expr.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 59359942e..c925ba2c9 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -5332,8 +5332,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - u64 feature_flags = lb_get_file_feature_flags(p); - GB_ASSERT(feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos); gb_unused(err); @@ -5422,8 +5421,7 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - u64 feature_flags = lb_get_file_feature_flags(p); - GB_ASSERT(feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); + GB_ASSERT(expr->file()->feature_flags & OptInFeatureFlag_DynamicLiterals || build_context.dynamic_literals); Type *et = bt->DynamicArray.elem; lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); From 0774b7465fe0eb29c54af24e0375f80b776f42f6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 26 Jan 2026 15:51:38 +0000 Subject: [PATCH 3/3] Allow for shortcut to get feature flags from the expression directly assuming it as a file --- src/llvm_backend_expr.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c925ba2c9..3c7092a32 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -282,10 +282,16 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, return res; } -gb_internal u64 lb_get_file_feature_flags(lbProcedure *p) { +gb_internal u64 lb_get_file_feature_flags(lbProcedure *p, Ast *expr = nullptr) { AstFile *file = nullptr; - if (p->body && p->body->file()) { + if (expr != nullptr) { + file = expr->file(); + } + + if (file != nullptr) { + // it is now set + } else if (p->body && p->body->file()) { file = p->body->file(); } else if (p->type_expr && p->type_expr->file()) { file = p->type_expr->file(); @@ -3812,7 +3818,7 @@ gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) { bool do_type_check = true; if (build_context.no_type_assert) { - u64 feature_flags = lb_get_file_feature_flags(p); + u64 feature_flags = lb_get_file_feature_flags(p, ue_expr); if ((feature_flags & OptInFeatureFlag_ForceTypeAssert) == 0) { do_type_check = false; }