Skip to content

trans tries to clean up values created in a match arm, outside the match. #18845

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

Closed
eddyb opened this issue Nov 10, 2014 · 8 comments · Fixed by #25645
Closed

trans tries to clean up values created in a match arm, outside the match. #18845

eddyb opened this issue Nov 10, 2014 · 8 comments · Fixed by #25645
Assignees
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️

Comments

@eddyb
Copy link
Member

eddyb commented Nov 10, 2014

Original testcase by @hoeppnertill (reduced from his nock repo):

#![crate_type="lib"]

pub fn test(foo: bool) -> int {
    match foo {
        true => *box 0,
        false => 0
    }
}
Instruction does not dominate all uses!
  %6 = bitcast i8* %5 to i64*
  %8 = bitcast i64* %6 to i8*
LLVM ERROR: Broken function found, compilation aborted!

The debug log reveals that a (shallow free) cleanup of the Box<int> rvalue is scheduled in the scope of AST node 11, while the dereference expression itself has id 16:

DEBUG:rustc::middle::trans::expr: deref_once(expr=expr(16: *box() 0), datum=Datum((i64*:  %7 = bitcast i8* %6 to i64*), Box<int>, RvalueExpr(Rvalue { mode: ByValue })), method_call=MethodCall { expr_id: 16, adjustment: NoAdjustment })
DEBUG:rustc::middle::trans::cleanup: temporary_scope(16) = AstScope(11)
DEBUG:rustc::middle::trans::cleanup: schedule_free_value(AstScope(11), val=(i64*:  %7 = bitcast i8* %6 to i64*), heap=HeapExchange)
DEBUG:rustc::middle::trans::cleanup: schedule_clean_in_ast_scope(cleanup_scope=11)
DEBUG:rustc::middle::trans::expr: deref_once(expr=16, method_call=MethodCall { expr_id: 16, adjustment: NoAdjustment }, result=Datum((i64*:  %7 = bitcast i8* %6 to i64*), int, RvalueExpr(Rvalue { mode: ByRef })))

--pretty expanded,identified reveals that id 11 refers to the entire function's block:

pub fn test(foo /* pat 5 */: bool) -> int {
    (match (foo /* 13 */) {
         (true /* 15 */) /* pat 14 */ =>
         (*(box() (0 /* 18 */) /* 17 */) /* 16 */),
         (false /* 20 */) /* pat 19 */ => (0 /* 21 */),
     } /* 12 */)
} /* block 11 */ /* 3 */

This means the cleanup of a value valid only within a match arm is scheduled outside the arm.
cc @nikomatsakis @pnkfelix

@eddyb eddyb changed the title trans generates invalid IR when cleaning up values created in a branch. trans tries to clean up values created in a match arm, outside the match. Nov 10, 2014
@ghost
Copy link

ghost commented Nov 10, 2014

Dupe of #15892. Leaving open for now but we can close either.

@eddyb
Copy link
Member Author

eddyb commented Nov 10, 2014

This is caused by a micro-optimization specific to dereferences of Box<T> rvalues. Is this used oftenly enough to justify its existence in the first place? Even if it is, I guess we can disable it in problematic cases like this, where the temporary scope of the match arm's RHS is outside the arm.

@nikomatsakis
Copy link
Contributor

@eddyb I think we can probably remove it, in general removing special treatment of Box<T> seems like a Good Thing

@huonw huonw added the I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ label Nov 12, 2014
@steveklabnik
Copy link
Member

Triage: this still ICEs.

@pnkfelix
Copy link
Member

@eddyb can you point me/us at the micro-optimization that you mentioned above, so that I (we) can try removing it ourselves and measure the impact?

@eddyb
Copy link
Member Author

eddyb commented Feb 12, 2015

@pnkfelix I only vaguely recall this issue, but I'm pretty sure I was talking about trans::expr::deref_owned_pointer.

@pnkfelix pnkfelix self-assigned this Feb 12, 2015
@tamird
Copy link
Contributor

tamird commented Apr 22, 2015

triage: still ICEs.

#![feature(box_syntax)]

#![crate_type="lib"]

pub fn test(foo: bool) -> u8 {
    match foo {
        true => *box 0,
        false => 0
    }
}

@pnkfelix
Copy link
Member

Indeed, it doesn't even need box_syntax:

pub fn test(foo: bool) -> u8 {
    match foo {
        true => *Box::new(0),
        false => 0
    }
}

fn main() {
    test(true);
}

Does this at least continue to ICE even if LLVM is compiled without assertions? If not, we may want to up the priority on this ticket.

bors added a commit that referenced this issue May 20, 2015
This micro-optimization actually led to generating broken IR in certain cases.

Fixes #18845.
Fixes #25497.
lnicola pushed a commit to lnicola/rust that referenced this issue Jan 7, 2025
fix: Fix flycheck getting confused which package to check
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants