Commit 1d1364c3cd
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -16945,10 +16945,11 @@ fn coerce(
const arena = sema.arena;
const target = sema.mod.getTarget();
+ const maybe_inst_val = try sema.resolveMaybeUndefVal(block, inst_src, inst);
const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
- if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
+ if (maybe_inst_val) |val| {
// Keep the comptime Value representation; take the new type.
return sema.addConstant(dest_ty, val);
}
@@ -16956,16 +16957,15 @@ fn coerce(
return block.addBitCast(dest_ty, inst);
}
- // undefined to anything
- if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
- if (val.isUndef() or inst_ty.zigTypeTag() == .Undefined) {
- return sema.addConstant(dest_ty, val);
- }
- }
- assert(inst_ty.zigTypeTag() != .Undefined);
+ const is_undef = if (maybe_inst_val) |val| val.isUndef() else false;
switch (dest_ty.zigTypeTag()) {
.Optional => {
+ // undefined sets the optional bit also to undefined.
+ if (is_undef) {
+ return sema.addConstUndef(dest_ty);
+ }
+
// null to ?T
if (inst_ty.zigTypeTag() == .Null) {
return sema.addConstant(dest_ty, Value.@"null");
@@ -17167,8 +17167,8 @@ fn coerce(
}
},
.Many => p: {
+ if (!inst_ty.isSlice()) break :p;
const inst_info = inst_ty.ptrInfo().data;
- if (inst_info.size != .Slice) break :p;
switch (try sema.coerceInMemoryAllowed(
block,
@@ -17191,9 +17191,6 @@ fn coerce(
return sema.coerceCompatiblePtrs(block, dest_ty, slice_ptr, inst_src);
},
}
-
- // This will give an extra hint on top of what the bottom of this func would provide.
- try sema.checkPtrOperand(block, dest_ty_src, inst_ty);
},
.Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
.Float, .ComptimeFloat => float: {
@@ -17230,6 +17227,9 @@ fn coerce(
return block.addTyOp(.intcast, dest_ty, inst);
}
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
@@ -17275,6 +17275,9 @@ fn coerce(
//}
return try sema.addConstant(dest_ty, result_val);
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.Enum => switch (inst_ty.zigTypeTag()) {
@@ -17313,11 +17316,14 @@ fn coerce(
return sema.unionToTag(block, dest_ty, inst, inst_src);
}
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.ErrorUnion => switch (inst_ty.zigTypeTag()) {
.ErrorUnion => {
- if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| {
+ if (maybe_inst_val) |inst_val| {
switch (inst_val.tag()) {
.undef => return sema.addConstUndef(dest_ty),
.eu_payload => {
@@ -17341,7 +17347,15 @@ fn coerce(
// E to E!T
return sema.wrapErrorUnionSet(block, dest_ty, inst, inst_src);
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {
+ // undefined sets the error code also to undefined.
+ if (is_undef) {
+ return sema.addConstUndef(dest_ty);
+ }
+
// T to E!T
return sema.wrapErrorUnionPayload(block, dest_ty, inst, inst_src);
},
@@ -17353,6 +17367,9 @@ fn coerce(
return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
}
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.Array => switch (inst_ty.zigTypeTag()) {
@@ -17365,10 +17382,16 @@ fn coerce(
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
}
},
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.Vector => switch (inst_ty.zigTypeTag()) {
.Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
+ .Undefined => {
+ return sema.addConstUndef(dest_ty);
+ },
else => {},
},
.Struct => {
@@ -17382,6 +17405,13 @@ fn coerce(
else => {},
}
+ // undefined to anything. We do this after the big switch above so that
+ // special logic has a chance to run first, such as `*[N]T` to `[]T` which
+ // should initialize the length field of the slice.
+ if (is_undef) {
+ return sema.addConstUndef(dest_ty);
+ }
+
return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
}
@@ -18452,7 +18482,7 @@ fn coerceArrayPtrToSlice(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
- if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
+ if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
const ptr_array_ty = sema.typeOf(inst);
const array_ty = ptr_array_ty.childType();
const slice_val = try Value.Tag.slice.create(sema.arena, .{
@@ -21336,7 +21366,7 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
}
fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
- return sema.addConstant(ty, Value.initTag(.undef));
+ return sema.addConstant(ty, Value.undef);
}
pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
test/behavior/struct.zig
@@ -1138,11 +1138,9 @@ test "packed struct with undefined initializers" {
}
test "for loop over pointers to struct, getting field from struct pointer" {
- // When enabling this test, be careful. I have observed it to pass when compiling
- // stage2 alone, but when using stage1 with -fno-stage1 -fLLVM it fails.
- // Maybe eyeball the LLVM that it generates and run in valgrind, both the compiler
- // and the generated test at runtime.
- if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
const S = struct {
const Foo = struct {