Skip to content

ICE matching on a non-[u8] const array #66501

Closed

Description

@Nadrieril

This produces an ICE (playground link):

fn main() {
    const CONST: &[(); 1] = &[()];
    match &[()] {
        &[()] => {}
        CONST => {}
    }
}

It points to this assert firing:

let data: &[u8] = match (const_val_val, &const_val.ty.kind) {
(ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
assert_eq!(*t, tcx.types.u8);
let n = n.eval_usize(tcx, param_env);
let ptr = Pointer::new(AllocId(0), offset);
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
}

This assert assumes that if we match on a &[T; n] with a const, then T must be u8. I'm not sure where this assumption comes from (I'd guess byte-array patterns), but it's clearly wrong. Note that this also fails with any other non-u8 type here instead of ().
Note that this does not fail when the arrays are not behind references, or if we use slices instead of arrays.

EDIT: removed unnecessary slice_patterns feature gate

Activity

  1. added
    A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)
    A-slice-patternsArea: Slice patterns, https://github.com/rust-lang/rust/issues/23121
    C-bugCategory: This is a bug.
    I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Nov 17, 2019
  2. jonas-schievink commented on Nov 17, 2019

    @jonas-schievink
    Contributor

    The feature gate isn't needed to trigger the ICE

  3. Nadrieril commented on Nov 17, 2019

    @Nadrieril
    MemberAuthor

    Oh, well spotted. And it appears that fails on stable too then

  4. Mark-Simulacrum commented on Nov 17, 2019

    @Mark-Simulacrum
    Member

    cc @pnkfelix as it's possible this is related to your structural match work I guess?

  5. hellow554 commented on Nov 18, 2019

    @hellow554
    Contributor

    Funny enough: this doesn't ICE

    const CONST: [(); 1] = [()];
    match &[()] {
        &[()] => {}
        &CONST => {}
    }

    but instead shows the correct "unreachable" warning

  6. Centril commented on Nov 20, 2019

    @Centril
    Contributor

    Reduced:

    fn main() {
        const CONST: &[(); 0] = &[];
        match &[] {
            &[] => {}
            CONST => {}
        }
    }
  7. pnkfelix commented on Nov 21, 2019

    @pnkfelix
    Contributor

    This assert assumes that if we match on a &[T; n] with a const, then T must be u8

    What the heck?!?

  8. pnkfelix commented on Nov 21, 2019

    @pnkfelix
    Contributor

    triage: P-high. Removing nomination. Self-assigning.

  9. 3 remaining items

  10. oli-obk commented on Nov 21, 2019

    @oli-obk
    Contributor

    That's a leftover from matching on byte strings, which used to be one of the few constants one could actually match on.

  11. Nadrieril commented on Nov 21, 2019

    @Nadrieril
    MemberAuthor

    I think it's one more of theses cases where we don't know how to handle ConstValue::ByRef properly. slice_pat_covered_by_const shouldn't even exist: specialization should be able to specialize consts by unpacking a pattern into its subpatterns, like we specialize everything else.

  12. pnkfelix commented on Dec 21, 2019

    @pnkfelix
    Contributor

    I've figured out a way to eliminate the ICE, but I do not think my code has the desired semantics. That is, I would imagine we would want this to be accepted:

    const CONST: &[(); 1] = &[()];
    fn main() {
        match &[()] {
            ::CONST => {}
        }
    }

    but my current draft code rejects the above as non-exhaustive.

    On the other hand, that does match the current behavior of the compiler, for better or for worse.

    Update: Or maybe I've forgotten the desirata for how match usefulness and consts are supposed to interact...?

  13. pnkfelix commented on Dec 21, 2019

    @pnkfelix
    Contributor

    Reduced:

    fn main() {
        const CONST: &[(); 0] = &[];
        match &[] {
            &[] => {}
            CONST => {}
        }
    }

    This was not a stable reduction; on the current nightly, the above length-zero ZST array is accepted with no ICE, while the original length-one ZST array still causes an ICE.

  14. pnkfelix commented on Dec 21, 2019

    @pnkfelix
    Contributor

    Yet another fun variation on the test:

    fn main() {
        const CONST: &[Option<()>; 1] = &[Some(())];
        match &[Some(())] {
            &[None] => {}
            CONST => {}
            &[Some(())] => {}
        }
    }

    yields:

    error: internal compiler error: src/librustc_mir/hair/pattern/_match.rs:2271: `constructor_covered_by_range` called with Variant(DefId(2:29423 ~ core[f952]::option[0]::Option[0]::Some[0]))
    
  15. oli-obk commented on Dec 21, 2019

    @oli-obk
    Contributor

    slice_pat_covered_by_const shouldn't even exist: specialization should be able to specialize consts by unpacking a pattern into its subpatterns, like we specialize everything else.

    The reason it exists is that we don't want to unpack a multi megabyte byte string you may have gotten from include_bytes!. That would be super inefficient and likely just cause an out of memory abort.

    The reason why I believe we should also do this optimization for other types is that you can easily transmute a multi megabyte byte string to another array type in a constant, and then you have the same problem all over again. (Or you init with a repeat expression).

    I agree that it would be nicer and less fragilr if we just unpacked everything.

  16. oli-obk commented on Dec 21, 2019

    @oli-obk
    Contributor

    Btw, #67192 addresses a few of the ICEs around this

  17. Alexendoo commented on Sep 7, 2020

    @Alexendoo
    Member

    Since #76376 the original and reduced versions no longer ICE, but

    fn main() {
        const CONST: &[Option<()>; 1] = &[Some(())];
        match &[Some(())] {
            &[None] => {}
            CONST => {}
            &[Some(())] => {}
        }
    }

    still does

  18. Alexendoo commented on Sep 27, 2020

    @Alexendoo
    Member

    The above no longer ICEs after #70743, could do with a test

  19. added
    E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.
    on Sep 27, 2020
  20. added a commit that references this issue on Oct 3, 2020
    a341710
  21. added a commit that references this issue on Oct 4, 2020
    f09c962
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

A-const-evalArea: Constant evaluation, covers all const contexts (static, const fn, ...)A-slice-patternsArea: Slice patterns, https://github.com/rust-lang/rust/issues/23121C-bugCategory: This is a bug.E-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️P-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.glacierICE tracked in rust-lang/glacier.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions