Skip to content

Miscompilation caused by incorrectly-deduced readonly on virtual call #137646

Closed
@johnbwang

Description

@johnbwang

I tried the following code. It requires a binary crate and a library crate.

main.rs

fn main() {
    let mut struct_c = lib::StructC::new();
    let struct_a = lib::StructA { a: 1, b: 2, c: 3 };
    lib::run(&mut struct_c, struct_a);
}

main's Cargo.toml

[package]
name = "compilerbug"
version = "0.1.0"
edition = "2024"

[dependencies]
lib = { path = "./lib" }

[profile.dev]
opt-level = 1
incremental = false

lib.rs

#[derive(Clone, Copy)]
pub struct StructA {
    pub a: i32,
    pub b: i32,
    pub c: i32,
}

pub trait TraitA {}

pub struct StructB {}

impl StructB {
    pub fn new() -> Self {
        Self {}
    }
}

impl TraitA for StructB {}

pub trait TraitB {
    fn get_trait_a(&self, struct_a: StructA) -> Option<Box<dyn TraitA>> {
        Some(Box::new(StructB::new()))
    }
}

pub struct StructC {}

impl StructC {
    pub fn new() -> Self {
        Self {}
    }
}

impl TraitB for StructC {
    fn get_trait_a(&self, mut struct_a: StructA) -> Option<Box<dyn TraitA>> {
        struct_a.a = i32::MAX;
        Some(Box::new(StructB::new()))
    }
}

#[inline(never)]
fn print_struct_a(struct_a: StructA) {
    println!("{}", struct_a.a);
}

#[inline(never)]
pub fn run(trait_b: &mut dyn TraitB, struct_a: StructA) {
    print_struct_a(struct_a);
    trait_b.get_trait_a(struct_a);
    print_struct_a(struct_a);

    // Uncommenting the following will fix the code.
    // println!("{}", struct_a.a);
}

lib's Cargo.toml

[package]
name = "lib"
version = "0.1.0"
edition = "2024"

Since struct_a conforms to Copy, passing struct_a to get_trait_a() should make a copy. Instead, when modifying struct_a inside of get_trait_a(), it modifies the original. When printing the struct a second time, the struct has been modified. To repro the bug, it requires opt-level >= 1 and incremental = false.

I expected the output in my command line to be:

1
1

Instead, this happened:

1
2147483647

Meta

rustc --version --verbose:

rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: aarch64-apple-darwin
release: 1.85.0
LLVM version: 19.1.7

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.I-miscompileIssue: Correct Rust code lowers to incorrect machine codeI-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-criticalCritical priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-stablePerformance or correctness regression from one stable version to another.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions