Skip to content

wasm32-unknown-unknown: Incorrect codegen #57152

@BonsaiDen

Description

@BonsaiDen

I've tested this with current nightly, beta and stable as well as nightlies all the way back to october (haven't tried anything before that).

Expected Output: a: false / t.a: false / both check for: (2 & 1) == 1 (Correct)
Actual Output: a: false / t.a: true / both check for: (2 & 1) == 1 (Incorrect)

Note: You can plug the code below into the https://github.com/rustwasm/rust-webpack-template for running it.

extern crate wasm_bindgen;
use wasm_bindgen::prelude::*;

#[derive(Debug)]
struct Test {
    a: bool,
    b: bool
}

impl Test {
    fn foo(byte: u8) -> String {

        // 1. This must be infront of the struct initializer - It will evaluate correctly to "false"
        let a = (byte & 1) == 1;

        let t = Test {
            a: (byte & 1) == 1, // 2. This must come before "b" - It will incorrectly evaluate to "true"
            b: (byte & 2) == 2, // 3. This must be evaluated inside the initializer
        };

        // 4. This must be called inside the function
        format!("a: {} / t.a: {} / both check for: (2 & 1) == 1", a, t.a)

    }

}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

#[wasm_bindgen]
pub fn run() {
    log(&Test::foo(2));
}

For some reason the two different (byte & 1) == 1 expression generate different results.

Note: Inlining everything by replacing byte with 2 produces the correct output.
Also Note: In my real program there are more strange things that happen after this like (for i in vector not actually iterating over the contents of the vector) but I was unable to reduce those to a test case :(

For comparison, here's the same code (just without the WASM stuff) that produces the expected output a: false / t.a: false / both check for: (2 & 1) == 1 when invoked via a simple cargo run:

#[derive(Debug)]
struct Test {
    a: bool,
    b: bool
}

impl Test {

    fn foo(byte: u8) -> String {

        // 1. This must be infront of the struct initializer - It will evaluate correctly to "false"
        let a = (byte & 1) == 1;

        let t = Test {
            a: (byte & 1) == 1, // 2. This must come before "b" - It will incorrectly evaluate to "true"
            b: (byte & 2) == 2, // 3. This must be evaluated inside the initializer
        };

        // 4. This must be called inside the function
        format!("a: {} / t.a: {} / both check for: (2 & 1) == 1", a, t.a)

    }

}

pub fn main() {
    println!("{}", Test::foo(2));
}

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessO-wasmTarget: WASM (WebAssembly), http://webassembly.org/

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions