Open JesseRMeyer opened 4 years ago
They main question that comes up is:
Is the following code undefined behaviour or does Zig guarantee that the expression value of try footgunnery(1)
is alive until "end of sope"
const T = struct { val: i32 };
fn footgunnery(v: i32) !T {
… // here be magic implementation
}
fn callme() !i32 {
const ptr1 = &(try footgunnery(1)).val;
const ptr2 = &(try footgunnery(2)).val;
return ptr1.* + ptr2.*;
}
For function parameters there should be at least the rule that taking a mutable reference of a temporary is forbidden as i cannot imagine when it is not a bug.
Allowing a const reference to a temporary (even a literal) can sometimes come in handy when interfacing generic C apis:
extern fn setValue(type: MyTypeStruct, value: *const c_void) void;
fn foo() void {
setValue(.i32, &as(i32, 42));
}
Good point. The real danger comes from taking the address of temporary mutable references.
Footgun:
var opt: ?u32 = 4;
var ptr = &(opt orelse return);
ptr.* = 2;
std.debug.warn("{}\n", .{ opt }); // prints 4
Whereas var ptr = &opt.?;
works. I'm not sure why.
Linking #7663 since it's at least somewhat related (taking address of struct literals).
Both code examples compile and satisfy the type system but have subtly different semantics.
@ptrCast returns a temporary (unnamed) variable, so its address is likewise transient. I cannot think of a valuable use-case for taking its address, and have felt this as an (educational) footgun about how Zig works.
Is there a high value use-case for taking the address of a temporary variable?
If not, I propose this should be considered an error.