Skip to content

Moves in guard expressions aren't handled properly #22073

@Aatch

Description

@Aatch

This code causes a segfault (without optimisations on):

use std::fmt;
fn main() {
    let a = std::rc::Rc::new(1);

    let x = (1, 2);

    match x {
        (_, y) |
        (y, _) if take(y, a) => (),
        _ => ()
    }

}

fn take<T:fmt::Debug>(x: usize, t: T) -> bool {
    println!("{:?}", t);
    x == 1
}

as does this similar code:

use std::fmt;
fn main() {
    let a = std::rc::Rc::new(1);

    let x = (1, 2);

    match x {
        (_, y) if take(y, a) => (),
        (y, _) if take(y, a) => (),
        _ => ()
    }

}

fn take<T:fmt::Debug>(x: usize, t: T) -> bool {
    println!("{:?}", t);
    x == 1
}

This is because the current control flow graph essentially visits each arm in parallel. With multiple patterns, each pattern within the arm is visited, then the guard is visited after all the patterns have been visited, even though this doesn't reflect the real semantics (we visit the pattern, then the guard, then the next pattern, then the guard again).

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions