Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Struct initialization and reassignment to data dependent location causes possibly unexpected behavior #22170

Open
aidanbabo opened this issue Dec 6, 2024 · 1 comment
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@aidanbabo
Copy link

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

Sorry for the lengthy title. Given a snippet of Zig code like below:

const Point = extern struct {
    r: i32,
    c: i32,
};

export fn foo() Point {
    var p: Point = .{ .r = -1, .c = 0 };
    p = .{ .r = p.c, .c = -p.r };
    return p;
}

pub fn main() void {
    const p: Point = foo();
    @import("std").debug.print("({d}, {d})\n", .{ p.r, p.c });
}

the program prints (0, 0) when run.

The struct and function are marked as export because I was working with them in Godbolt, but the problem manifest with Zig's layout/cc as well.

Expected Behavior

Given a similar snipped of C code:

struct point {
    int r;
    int c;
};

struct point foo(void) {
    struct point p = { .r = -1, .c = 0 };
    p = (struct point){ .r = p.c, .c = -p.r };
    return p;
}

#include <stdio.h>

int main(void) {
    struct point p = foo();
    printf("(%d, %d)\n", p.r, p.c);
}

the program prints (0, 1), which was my intention when I wrote the above Zig code.

I'm fairly new to Zig, but the behavior in C feels much more intuitive. I would expect the struct initializer to be fully evaluated before any data is written into p.

@aidanbabo aidanbabo added the bug Observed behavior contradicts documented or intended behavior label Dec 6, 2024
@rohlem
Copy link
Contributor

rohlem commented Dec 6, 2024

Duplicate of / related to #3696 (or more particularly #12064) and the dozen other issues linked there.

At some point the current behavior was additionally documented in the language reference (langref):

In essence, Zig desugars the assignment foo = .{ .a = x, .b = y } to the two statements foo.a = x; foo.b = y; .

In your example code, p = .{ .r = p.c, .c = -p.r }; becomes p.r = p.c; p.c = -p.r;.
The workaround for now is to specify the type (p = Point{ .r = p.c, .c = -p.r };), or use a temporary const new_p = ...; p = new_p;.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

2 participants