Skip to content

Copy elision causes side effects when modifying a struct in place. #4021

@momumi

Description

@momumi

This code attempts to square a complex number i² -> -1. When computing z = z.mul(z), the compiler decides to pass both values z1 and z2 by reference, however copy elision seems to modify z in place causing the incorrect value to be computed.

const std = @import("std");
const print = std.debug.warn;

const Complex = struct {
    x: f32 = 0,
    y: f32 = 0,

    pub fn mul(z1: Complex, z2: Complex) Complex {
        return Complex {
            .x = z1.x*z2.x - z1.y*z2.y,
            .y = z1.x*z2.y + z1.y*z2.x, // new value of .x gets used here
        };
    }
};

pub fn main() void {
    var c = Complex{ .x=0.0, .y=1.0 };
    var i: usize = 0;
    var z: Complex = undefined;

    print("incorrect:\n", .{});
    z = c;
    z = z.mul(z);
    print("z: {d:.2} {d:.2}\n", .{ z.x, z.y });

    z = c;
    z = z.mul(c);
    print("z: {d:.2} {d:.2}\n", .{ z.x, z.y });

    z = c;
    z = c.mul(z);
    print("z: {d:.2} {d:.2}\n", .{ z.x, z.y });

    // These examples produce the correct output
    print("correct:\n", .{});
    z = c.mul(c);
    print("z: {d:.2} {d:.2}\n", .{ z.x, z.y });

    z = c;
    var res = z.mul(z);
    print("z: {d:.2} {d:.2}\n", .{ res.x, res.y });
}

Output:

incorrect:
z: -1.00 -2.00
z: -1.00 -1.00
z: -1.00 -1.00
correct:
z: -1.00 0.00
z: -1.00 0.00

Related issues: #287, #2765, #3804

Metadata

Metadata

Assignees

No one assigned

    Labels

    use caseDescribes a real use case that is difficult or impossible, but does not propose a solution.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions