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 resolving non-existent PartialEq::Eq from match of const #65466

Closed
pnkfelix opened this issue Oct 16, 2019 · 5 comments
Closed

ICE resolving non-existent PartialEq::Eq from match of const #65466

pnkfelix opened this issue Oct 16, 2019 · 5 comments
Assignees
Labels
A-mir Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-bug Category: This is a bug. 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

@pnkfelix
Copy link
Member

pnkfelix commented Oct 16, 2019

(Spawned off of #61188 (comment) )

Sometimes the code-generation for pattern-matching a const will generate a invocation of PartialEq::eq (rather than unfolding the structure of that constant inline, which is the usual compilation strategy used in rustc currently...)

The difference between unfolding inline and invoking PartialEq::eq is not meant to be observable, because of RFC 1445 (c.f. #31434): "Restrict constants in patterns"

However, there are cases where rustc's static analysis of the pattern itself was not thorough enough, and it would let patterns through that do end up invoking PartialEq::eq on constants that do not even implement PartialEq in the first place.

We had been relying on the structural-match checking to catch such cases, where we would first run the structural match check, and if we found an ADT that was a non-structural-match, then we would then check if the const in question even implements PartialEq.

But that strategy, of a delayed check for PartialEq, does not suffice in every case. Here is an example, taken from @matthewjasper 's comment linked above:

#![deny(indirect_structural_match)]

#[derive(PartialEq, Eq)]
enum O<T> {
    Some(*const T), // Can also use PhantomData<T>
    None,
}

struct B;

const C: &[O<B>] = &[O::None];

pub fn foo() {
    let x = O::None;
    match &[x][..] {
        C => (),
        _ => (),
    }
}

I had been tagging the above test case as being part of #61188, but at this point I think it is confusing matters, because the code/comments/commit messages say things like "this does not yet fix #61188" and it is ambgious whether that message refers to the original bug described by #61188, or the subsequent issue pointed out by @matthewjasper linked above.

So I am allocating a fresh issue to track the matter here.

@pnkfelix pnkfelix self-assigned this Oct 16, 2019
@pnkfelix pnkfelix added A-mir Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-bug Category: This is a bug. 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. labels Oct 16, 2019
@rust-lang-glacier-bot rust-lang-glacier-bot added the glacier ICE tracked in rust-lang/glacier. label Oct 16, 2019
pnkfelix added a commit to pnkfelix/rust that referenced this issue Oct 25, 2019
(Or more precisely, a pair of such traits: one for `derive(PartialEq)` and one
for `derive(Eq)`.)

((The addition of the second marker trait, `StructuralEq`, is largely a hack to
work-around `fn (&T)` not implementing `PartialEq` and `Eq`; see also issue
rust-lang#46989; otherwise I would just check if `Eq` is implemented.))

Note: this does not use trait fulfillment error-reporting machinery; it just
uses the trait system to determine if the ADT was tagged or not. (Nonetheless, I
have kept an `on_unimplemented` message on the new trait for structural_match
check, even though it is currently not used.)

Note also: this does *not* resolve the ICE from rust-lang#65466, as noted
in a comment added in this commit. Further work is necessary to resolve that and
other problems with the structural match checking, especially to do so without
breaking stable code (adapted from test fn-ptr-is-structurally-matchable.rs):

```rust
fn r_sm_to(_: &SM) {}

fn main() {
    const CFN6: Wrap<fn(&SM)> = Wrap(r_sm_to);
    let input: Wrap<fn(&SM)> = Wrap(r_sm_to);
    match Wrap(input) {
        Wrap(CFN6) => {}
        Wrap(_) => {}
    };
}
```

where we would hit a problem with the strategy of unconditionally checking for
`PartialEq` because the type `for <'a> fn(&'a SM)` does not currently even
*implement* `PartialEq`.

----

added review feedback:
* use an or-pattern
* eschew `return` when tail position will do.
* don't need fresh_expansion; just add `structural_match` to appropriate `allow_internal_unstable` attributes.

also fixed example in doc comment so that it actually compiles.
@pnkfelix
Copy link
Member Author

pnkfelix commented Nov 14, 2019

todo: check how PR #66120 #67088 handles this...

@pnkfelix
Copy link
Member Author

pnkfelix commented Dec 9, 2019

Answer: under PR #67088, this produces:

error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]`
  --> issue-65466.rs:16:9
   |
16 |         C => (),
   |         ^

error: aborting due to previous error

(which is what we want).

@ecstatic-morse
Copy link
Contributor

ecstatic-morse commented Apr 7, 2020

Note to self, matching on &O<B> is enough to trigger the ICE. A slice is not necessary.

bors added a commit to rust-lang-ci/rust that referenced this issue Apr 29, 2020
…h, r=pnkfelix

Const qualification for `StructuralEq`

Furthers rust-lang#62411. Resolves rust-lang#62614.

The goal of this PR is to implement the logic in rust-lang#67088 on the MIR instead of the HIR. It uses the `Qualif` trait to track `StructuralPartialEq`/`StructuralEq` in the final value of a `const`. Then, if we encounter a constant during HAIR lowering whose value may not be structurally matchable, we emit the `indirect_structural_match` lint.

This PR contains all the tests present in rust-lang#67088 and emits the proper warnings for the corner cases. This PR does not handle rust-lang#65466, which would require that we be [more aggressive](https://github.com/rust-lang/rust/blob/42abbd8878d3b67238f3611b0587c704ba94f39c/src/librustc_mir_build/hair/pattern/const_to_pat.rs#L126-L130) when checking matched types for `PartialEq`. I think that should be done separately.

Because this works on MIR and uses dataflow, this PR should accept more cases than rust-lang#67088. Notably, the qualifs in the final value of a const are encoded cross-crate, so matching on a constant whose value is defined in another crate to be `Option::<TyWithCustomEqImpl>::None` should work. Additionally, if a `const` has branching/looping, we will only emit the warning if any possible control flow path could result in a type with a custom `PartialEq` impl ending up as the final value of a `const`. I'm not sure how rust-lang#67088 handled this.

AFAIK, it's not settled that these are the semantics we actually want: it's just how the `Qualif` framework happens to work. If the cross-crate part is undesirable, it would be quite easy to change the result of `mir_const_qualif().custom_eq` to `true` before encoding it in the crate metadata. This way, other crates would have to assume that all publicly exported constants may not be safe for matching.

r? @pnkfelix
cc @eddyb
ecstatic-morse added a commit to ecstatic-morse/rust that referenced this issue May 17, 2020
@matthiaskrgr
Copy link
Member

Still crashing (obviously on nightly, beta and stable by now...).

warning: variant is never constructed: `Some`
 --> src/main.rs:5:5
  |
5 |     Some(*const T), // Can also use PhantomData<T>
  |     ^^^^^^^^^^^^^^
  |
  = note: `#[warn(dead_code)]` on by default

warning: Error finalizing incremental compilation session directory `/tmp/a/target/debug/incremental/a-3ibewktm5f4s7/s-frdnn34p4t-5wozmt-working`: No such file or directory (os error 2)

warning: 2 warnings emitted

error: internal compiler error: broken MIR in DefId(0:6 ~ a[e6bb]::foo[0]) (NoSolution): could not prove TraitPredicate(<[O<B>] as std::cmp::PartialEq>)
  |
  = note: delayed at compiler/rustc_mir/src/borrow_check/type_check/mod.rs:258:27

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', compiler/rustc_errors/src/lib.rs:961:13
stack backtrace:
   0:     0x7fb253922b30 - std::backtrace_rs::backtrace::libunwind::trace::he85dfb3ae4206056
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/../../backtrace/src/backtrace/libunwind.rs:96
   1:     0x7fb253922b30 - std::backtrace_rs::backtrace::trace_unsynchronized::h1ad28094d7b00c21
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/../../backtrace/src/backtrace/mod.rs:66
   2:     0x7fb253922b30 - std::sys_common::backtrace::_print_fmt::h901b54610713cd21
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys_common/backtrace.rs:79
   3:     0x7fb253922b30 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::hb0ad78ee1571f7e0
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys_common/backtrace.rs:58
   4:     0x7fb253990e7c - core::fmt::write::h1857a60b204f1b6a
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/core/src/fmt/mod.rs:1080
   5:     0x7fb253914f07 - std::io::Write::write_fmt::hf7b7d7b243f84a36
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/io/mod.rs:1517
   6:     0x7fb253927880 - std::sys_common::backtrace::_print::hd093978a5287b8ff
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys_common/backtrace.rs:61
   7:     0x7fb253927880 - std::sys_common::backtrace::print::h20f46787581d56d7
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys_common/backtrace.rs:48
   8:     0x7fb253927880 - std::panicking::default_hook::{{closure}}::h486cbb4b82ffc357
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:208
   9:     0x7fb253927538 - std::panicking::default_hook::h4190c9e3edd4d591
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:227
  10:     0x7fb2541bb8d4 - rustc_driver::report_ice::h0baa69c9fa359ad1
  11:     0x7fb2539280b6 - std::panicking::rust_panic_with_hook::h72e78719cdda225c
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:581
  12:     0x7fb253927c39 - std::panicking::begin_panic_handler::{{closure}}::h8bd07dbd34150a96
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:484
  13:     0x7fb253922fbc - std::sys_common::backtrace::__rust_end_short_backtrace::hdb6b3066ad29028a
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys_common/backtrace.rs:153
  14:     0x7fb253927bf9 - rust_begin_unwind
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:483
  15:     0x7fb253927bab - std::panicking::begin_panic_fmt::hc19e75fd2b7bc39b
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/panicking.rs:437
  16:     0x7fb2572fd471 - rustc_errors::HandlerInner::flush_delayed::hc01570dc9a0301e8
  17:     0x7fb2572f9dd1 - <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop::h2fa2449267c97abc
  18:     0x7fb2541df306 - core::ptr::drop_in_place::h3ccf454d686c35e3
  19:     0x7fb2541e9d36 - <alloc::rc::Rc<T> as core::ops::drop::Drop>::drop::h9871ec79020d3d08
  20:     0x7fb2541cdb4d - core::ptr::drop_in_place::h37be4f3688653901
  21:     0x7fb2541bfd31 - rustc_span::with_source_map::he9a81669cd160b82
  22:     0x7fb2541eebd8 - rustc_interface::interface::create_compiler_and_run::h06c2389085f2a79e
  23:     0x7fb2541c02aa - rustc_span::with_session_globals::h3a06e50e1db00721
  24:     0x7fb2541f148d - std::sys_common::backtrace::__rust_begin_short_backtrace::h6f73648415d0d9ce
  25:     0x7fb2541621ce - core::ops::function::FnOnce::call_once{{vtable.shim}}::h213be4bbd07cfb62
  26:     0x7fb25393796a - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::h1080dfe0ef616bdf
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/alloc/src/boxed.rs:1042
  27:     0x7fb25393796a - <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once::hd2747e1f2d5cec32
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/alloc/src/boxed.rs:1042
  28:     0x7fb25393796a - std::sys::unix::thread::Thread::new::thread_start::hd0f336b4ef6808a7
                               at /rustc/f68e08933d8f519a9655934fedebbc509661b219/library/std/src/sys/unix/thread.rs:87
  29:     0x7fb2538343e9 - start_thread
  30:     0x7fb253751293 - __GI___clone
  31:                0x0 - <unknown>

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.48.0-nightly (f68e08933 2020-09-19) running on x86_64-unknown-linux-gnu

note: compiler flags: -C embed-bitcode=no -C debuginfo=2 -C incremental --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack
error: could not compile `a`
```

@Alexendoo
Copy link
Member

Fixed by #70743

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-mir Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html C-bug Category: This is a bug. 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
5 participants