Skip to content
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

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

Closed
Nadrieril opened this issue Nov 17, 2019 · 16 comments · Fixed by #77388
Closed

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

Nadrieril opened this issue Nov 17, 2019 · 16 comments · Fixed by #77388
Assignees
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Nadrieril
Copy link
Member

Nadrieril commented Nov 17, 2019

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

@jonas-schievink jonas-schievink added A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 C-bug Category: This is a bug. F-slice_patterns `#![feature(slice_patterns)]` I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. I-nominated labels Nov 17, 2019
@jonas-schievink
Copy link
Contributor

The feature gate isn't needed to trigger the ICE

@Nadrieril
Copy link
Member Author

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

@Mark-Simulacrum
Copy link
Member

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

@hellow554
Copy link
Contributor

Funny enough: this doesn't ICE

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

but instead shows the correct "unreachable" warning

@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Nov 18, 2019
@Centril
Copy link
Contributor

Centril commented Nov 20, 2019

Reduced:

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

@pnkfelix
Copy link
Member

pnkfelix commented Nov 21, 2019

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

What the heck?!?

@pnkfelix
Copy link
Member

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

@pnkfelix pnkfelix self-assigned this Nov 21, 2019
@pnkfelix pnkfelix added P-high High priority and removed I-nominated labels Nov 21, 2019
@oli-obk
Copy link
Contributor

oli-obk commented Nov 21, 2019

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

@Nadrieril
Copy link
Member Author

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.

@pnkfelix pnkfelix removed the F-slice_patterns `#![feature(slice_patterns)]` label Nov 27, 2019
@pnkfelix
Copy link
Member

pnkfelix commented Dec 21, 2019

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...?

@pnkfelix
Copy link
Member

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.

@pnkfelix
Copy link
Member

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]))

@oli-obk
Copy link
Contributor

oli-obk commented Dec 21, 2019

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.

@oli-obk
Copy link
Contributor

oli-obk commented Dec 21, 2019

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

@Alexendoo
Copy link
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

@Alexendoo
Copy link
Member

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

@Alexendoo Alexendoo added the E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. label Sep 27, 2020
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Oct 3, 2020
Add some regression tests

Closes rust-lang#66501
Closes rust-lang#68951
Closes rust-lang#72565
Closes rust-lang#74244
Closes rust-lang#75299

The first issue is fixed in 1.43.0, other issues are fixed in the recent nightly.
@bors bors closed this as completed in f09c962 Oct 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-slice-patterns Area: Slice patterns, https://github.com/rust-lang/rust/issues/23121 C-bug Category: This is a bug. E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added. glacier ICE tracked in rust-lang/glacier. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ P-high High priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants