aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-01-20 13:34:47 +0000
committerMatthew Lugg <mlugg@mlugg.co.uk>2025-01-21 00:33:32 +0000
commit8bcb578507908e17e2081bb03f8c51eb508d51db (patch)
tree1e9caba23ae65432f8aa5abaa55f070e2b5220eb /src
parentb9198b708f8accb41fdb3f11bf635d63fbff461d (diff)
downloadzig-8bcb578507908e17e2081bb03f8c51eb508d51db.tar.gz
zig-8bcb578507908e17e2081bb03f8c51eb508d51db.zip
Sema: fix `is_non_null_ptr` handling for runtime-known pointers
We can still often determine a comptime result based on the type, even if the pointer is runtime-known. Also, we previously used load -> is non null instead of AIR `is_non_null_ptr` if the pointer is comptime-known, but that's a bad heuristic. Instead, we should check for the pointer to be comptime-known, *and* for the load to be comptime-known, and only in that case should we call `Sema.analyzeIsNonNull`. Resolves: #22556
Diffstat (limited to 'src')
-rw-r--r--src/Sema.zig35
-rw-r--r--src/Type.zig10
2 files changed, 27 insertions, 18 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 2b9fa82ce8..e19110bbfb 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -17477,10 +17477,10 @@ fn zirCmpEq(
// comparing null with optionals
if (lhs_ty_tag == .null and (rhs_ty_tag == .optional or rhs_ty.isCPtr(zcu))) {
- return sema.analyzeIsNull(block, src, rhs, op == .neq);
+ return sema.analyzeIsNull(block, rhs, op == .neq);
}
if (rhs_ty_tag == .null and (lhs_ty_tag == .optional or lhs_ty.isCPtr(zcu))) {
- return sema.analyzeIsNull(block, src, lhs, op == .neq);
+ return sema.analyzeIsNull(block, lhs, op == .neq);
}
if (lhs_ty_tag == .null or rhs_ty_tag == .null) {
@@ -19326,7 +19326,7 @@ fn zirIsNonNull(
const src = block.nodeOffset(inst_data.src_node);
const operand = try sema.resolveInst(inst_data.operand);
try sema.checkNullableType(block, src, sema.typeOf(operand));
- return sema.analyzeIsNull(block, src, operand, true);
+ return sema.analyzeIsNull(block, operand, true);
}
fn zirIsNonNullPtr(
@@ -19342,12 +19342,17 @@ fn zirIsNonNullPtr(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const ptr = try sema.resolveInst(inst_data.operand);
+ const ptr_ty = sema.typeOf(ptr);
try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(zcu));
- if ((try sema.resolveValue(ptr)) == null) {
- return block.addUnOp(.is_non_null_ptr, ptr);
+ if (try sema.resolveValue(ptr)) |ptr_val| {
+ if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |loaded_val| {
+ return sema.analyzeIsNull(block, Air.internedToRef(loaded_val.toIntern()), true);
+ }
}
- const loaded = try sema.analyzeLoad(block, src, ptr, src);
- return sema.analyzeIsNull(block, src, loaded, true);
+ if (ptr_ty.childType(zcu).isNullFromType(zcu)) |is_null| {
+ return if (is_null) .bool_false else .bool_true;
+ }
+ return block.addUnOp(.is_non_null_ptr, ptr);
}
fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
@@ -32405,7 +32410,6 @@ fn analyzeSliceLen(
fn analyzeIsNull(
sema: *Sema,
block: *Block,
- src: LazySrcLoc,
operand: Air.Inst.Ref,
invert_logic: bool,
) CompileError!Air.Inst.Ref {
@@ -32421,15 +32425,10 @@ fn analyzeIsNull(
return if (bool_value) .bool_true else .bool_false;
}
- const inverted_non_null_res: Air.Inst.Ref = if (invert_logic) .bool_true else .bool_false;
- const operand_ty = sema.typeOf(operand);
- if (operand_ty.zigTypeTag(zcu) == .optional and operand_ty.optionalChild(zcu).zigTypeTag(zcu) == .noreturn) {
- return inverted_non_null_res;
+ if (sema.typeOf(operand).isNullFromType(zcu)) |is_null| {
+ const result = is_null != invert_logic;
+ return if (result) .bool_true else .bool_false;
}
- if (operand_ty.zigTypeTag(zcu) != .optional and !operand_ty.isPtrLikeOptional(zcu)) {
- return inverted_non_null_res;
- }
- try sema.requireRuntimeBlock(block, src, null);
const air_tag: Air.Inst.Tag = if (invert_logic) .is_non_null else .is_null;
return block.addUnOp(air_tag, operand);
}
@@ -33007,7 +33006,7 @@ fn analyzeSlice(
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(zcu)) {
- const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
+ const is_non_null = try sema.analyzeIsNull(block, ptr, true);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
@@ -33065,7 +33064,7 @@ fn analyzeSlice(
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
if (ptr_ptr_child_ty.isCPtr(zcu)) {
- const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
+ const is_non_null = try sema.analyzeIsNull(block, ptr, true);
try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
}
diff --git a/src/Type.zig b/src/Type.zig
index c6c4334270..b628e0c60e 100644
--- a/src/Type.zig
+++ b/src/Type.zig
@@ -4114,6 +4114,16 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina
};
}
+/// Returns `true` if a value of this type is always `null`.
+/// Returns `false` if a value of this type is neve `null`.
+/// Returns `null` otherwise.
+pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
+ if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;
+ const child = ty.optionalChild(zcu);
+ if (child.zigTypeTag(zcu) == .noreturn) return true; // `?noreturn` is always null
+ return null;
+}
+
pub const @"u1": Type = .{ .ip_index = .u1_type };
pub const @"u8": Type = .{ .ip_index = .u8_type };
pub const @"u16": Type = .{ .ip_index = .u16_type };