Skip to content

MIR building generates mistyped assignments for opaques in dead code #129084

Open
@lcnr

Description

enum Never {}
fn foo() -> impl Sized {
    let ret = 'block: {
        break 'block foo();
    };
    let _: Never = ret;
    ret
}

results in the following MIR:

// MIR for `foo` after built

| User Type Annotations
| 0: user_ty: Canonical { value: Ty(Never), max_universe: U0, variables: [], defining_opaque_types: [DefId(0:6 ~ main[7eb4]::foo::{opaque#0})] }, span: src/main.rs:6:12: 6:17, inferred_ty: Never
| 1: user_ty: Canonical { value: Ty(Never), max_universe: U0, variables: [], defining_opaque_types: [DefId(0:6 ~ main[7eb4]::foo::{opaque#0})] }, span: src/main.rs:6:12: 6:17, inferred_ty: Never
|
fn foo() -> impl Sized {
    let mut _0: impl Sized;
    let _1: impl Sized;
    scope 1 {
        debug ret => _1;
        scope 2 {
        }
    }

    bb0: {
        StorageLive(_1);
        _1 = foo() -> [return: bb1, unwind: bb6];
    }

    bb1: {
        goto -> bb3;
    }

    bb2: {
        _1 = const ();
        goto -> bb4;
    }

    bb3: {
        goto -> bb4;
    }

    bb4: {
        FakeRead(ForLet(None), _1);
        PlaceMention(_1);
        AscribeUserType((_1 as Never), +, UserTypeProjection { base: UserType(1), projs: [] });
        _0 = move _1;
        StorageDead(_1);
        return;
    }

    bb5: {
        FakeRead(ForMatchedPlace(None), _1);
        unreachable;
    }

    bb6 (cleanup): {
        resume;
    }
}

notice the _1 = const (); which assigns unit to impl Sized even though its type is Never.

This should result in a type error and therefore an ICE, but apparently we never even get to test that as the block is entirely dead code 🤔 cc @oli-obk

// If a block has no trailing expression, then it is given an implicit return type.
// This return type is usually `()`, unless the block is diverging, in which case the
// return type is `!`. For the unit type, we need to actually return the unit, but in
// the case of `!`, no return value is required, as the block will never return.
// Opaque types of empty bodies also need this unit assignment, in order to infer that their
// type is actually unit. Otherwise there will be no defining use found in the MIR.
if destination_ty.is_unit()
|| matches!(destination_ty.kind(), ty::Alias(ty::Opaque, ..))
{
// We only want to assign an implicit `()` as the return value of the block if the
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions