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: assertion failed: layout.is_sized() #124182

Closed
cushionbadak opened this issue Apr 20, 2024 · 6 comments · Fixed by #129970
Closed

ICE: assertion failed: layout.is_sized() #124182

cushionbadak opened this issue Apr 20, 2024 · 6 comments · Fixed by #129970
Labels
A-const-eval Area: constant evaluation (mir interpretation) C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@cushionbadak
Copy link

Code

struct LazyLock<T> {
    data: (Copy, fn() -> T),
}

impl<T> LazyLock<T> {
    pub const fn new(f: fn() -> T) -> LazyLock<T> {
        LazyLock { data: (None, f) }
    }
}

struct A<T = i32>(Option<T>);

impl<T> Default for A<T> {
    fn default() -> Self {
        A(None)
    }
}

static EMPTY_SET: LazyLock<A<i32>> = LazyLock::new(A::default);

fn main() {}

I couldn't simplify the code without making it harder to understand.

Meta

rustc --version --verbose:

rustc 1.79.0-nightly (e3181b091 2024-04-18)
binary: rustc
commit-hash: e3181b091e88321f5ea149afed6db0edf0a4f37b
commit-date: 2024-04-18
host: aarch64-apple-darwin
release: 1.79.0-nightly
LLVM version: 18.1.4

Command

rustc

Error output

warning: trait objects without an explicit `dyn` are deprecated
 --> r_crushed_473555.rs:2:12
  |
2 |     data: (Copy, fn() -> T),
  |            ^^^^
  |
  = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
  = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
  = note: `#[warn(bare_trait_objects)]` on by default
help: if this is an object-safe trait, use `dyn`
  |
2 |     data: (dyn Copy, fn() -> T),
  |            +++

error[E0038]: the trait `Copy` cannot be made into an object
 --> r_crushed_473555.rs:2:12
  |
2 |     data: (Copy, fn() -> T),
  |            ^^^^ `Copy` cannot be made into an object
  |
  = note: the trait cannot be made into an object because it requires `Self: Sized`
  = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>

error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time
 --> r_crushed_473555.rs:2:11
  |
2 |     data: (Copy, fn() -> T),
  |           ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)`
  = note: only the last element of a tuple may have a dynamically sized type

error[E0277]: `(dyn Copy + 'static)` cannot be shared between threads safely
  --> r_crushed_473555.rs:19:19
   |
19 | static EMPTY_SET: LazyLock<A<i32>> = LazyLock::new(A::default);
   |                   ^^^^^^^^^^^^^^^^ `(dyn Copy + 'static)` cannot be shared between threads safely
   |
   = help: within `LazyLock<A>`, the trait `Sync` is not implemented for `(dyn Copy + 'static)`, which is required by `LazyLock<A>: Sync`
   = note: required because it appears within the type `((dyn Copy + 'static), fn() -> A)`
note: required because it appears within the type `LazyLock<A>`
  --> r_crushed_473555.rs:1:8
   |
1  | struct LazyLock<T> {
   |        ^^^^^^^^
   = note: shared static variables must have a type that implements `Sync`
Backtrace

thread 'rustc' panicked at compiler/rustc_const_eval/src/const_eval/eval_queries.rs:54:5:
assertion failed: layout.is_sized()
stack backtrace:
   0: _rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic
   3: rustc_const_eval::const_eval::eval_queries::eval_static_initializer_provider
      [... omitted 2 frames ...]
   4: <rustc_middle::hir::map::Map>::par_body_owners::<rustc_hir_analysis::check_crate::{closure#3}>::{closure#0}
   5: <rustc_data_structures::sync::parallel::ParallelGuard>::run::<(), rustc_data_structures::sync::parallel::enabled::par_for_each_in<&rustc_span::def_id::LocalDefId, &[rustc_span::def_id::LocalDefId], <rustc_middle::hir::map::Map>::par_body_owners<rustc_hir_analysis::check_crate::{closure#3}>::{closure#0}>::{closure#0}::{closure#0}::{closure#0}>
   6: rustc_hir_analysis::check_crate
   7: rustc_interface::passes::analysis
      [... omitted 2 frames ...]
   8: <rustc_middle::ty::context::GlobalCtxt>::enter::<rustc_driver_impl::run_compiler::{closure#0}::{closure#1}::{closure#3}, core::result::Result<(), rustc_span::ErrorGuaranteed>>
   9: <rustc_interface::interface::Compiler>::enter::<rustc_driver_impl::run_compiler::{closure#0}::{closure#1}, core::result::Result<core::option::Option<rustc_interface::queries::Linker>, rustc_span::ErrorGuaranteed>>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: 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: please make sure that you have updated to the latest nightly

note: please attach the file at `/Users/jisukbyun/workspace/placeholder/240420_rustexec/rustc-ice-2024-04-20T00_36_22-48540.txt` to your bug report

query stack during panic:
#0 [eval_static_initializer] evaluating initializer of static `EMPTY_SET`
#1 [analysis] running analysis passes on this crate
end of query stack
error: aborting due to 3 previous errors; 1 warning emitted

Some errors have detailed explanations: E0038, E0277.
For more information about an error, try `rustc --explain E0038`.

Note

@cushionbadak cushionbadak added C-bug Category: This is a bug. 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. labels Apr 20, 2024
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 20, 2024
@cushionbadak
Copy link
Author

searched nightlies: from nightly-2024-01-01 to nightly-2024-04-19
regressed nightly: nightly-2024-02-21
searched commit range: 3246e79...bb59453
regressed commit: cce6a6e

bisected with cargo-bisect-rustc v0.6.8

Host triple: aarch64-apple-darwin
Reproduce with:

cargo bisect-rustc --start=2024-01-01 --end=2024-04-19 --preserve --regress=ice 

It points to #121087

@lukas-code
Copy link
Member

Smaller: playground

struct LazyLock {
    data: ([u8], ()),
}

static EMPTY_SET: LazyLock = todo!();

fn main() {}

@matthiaskrgr matthiaskrgr added the S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. label Apr 22, 2024
@saethlin saethlin added A-const-eval Area: constant evaluation (mir interpretation) and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 28, 2024
@oli-obk
Copy link
Contributor

oli-obk commented Apr 29, 2024

Preexisting on stable:

struct LazyLock {
    data: ([u8], ()),
}

const EMPTY_SET: LazyLock = todo!();

const _: [(); {
    EMPTY_SET;
    0
}] = [];

fn main() {}

@adwinwhite
Copy link
Contributor

Trying to solve this issue, here is what I got.

The problem is that the trait solver only checks the last element of tuple when processing Tuple: Sized.
And WellFormed obligation for struct doesn't really check anything but its existing predicates. It's not recursive.
Thus the return type of the const body passes typeck.
It also survives layout calculation due to the same reason.
These two methods both assume that definitions are well-formed when they may not be.

Perhaps we can make WellFormed obligation more strict or just don't run const eval when check_mod_type_wf fails?
check_type_defn in check_mod_type_wf does check well-formedness for fields.

@oli-obk
Copy link
Contributor

oli-obk commented Jul 30, 2024

don't run const eval when check_mod_type_wf fails?
check_type_defn in check_mod_type_wf does check well-formedness for fields.

That can't be done, as wfcheck runs various consteval things that quickly result in (undesirable) cycle errors

The problem is that the trait solver only checks the last element of tuple when processing Tuple: Sized.
And WellFormed obligation for struct doesn't really check anything but its existing predicates. It's not recursive.
Thus the return type of the const body passes typeck.
It also survives layout calculation due to the same reason.
These two methods both assume that definitions are well-formed when they may not be.

We just had issues like that a few months ago. Please check which PRs tried to fix that. We may just want to revert them and correctly do WellFormed solving even if it ends up a perf regression.

@adwinwhite
Copy link
Contributor

#122078 added a WellFormed obligation in typeck() which requires all elements except last are Sized for tuple. It works well for tuple: Sized. Though it doesn't help with nested ill-formed types like in this issue.

To fix this issue, WellFormed needs to ensure almost all fields of ADT are Sized. It also needs to be recursive. This turns out to be quite difficult.
Recursive WellFormed solving quickly leads to query cycle. The cycle may be resolved if all trait solving shares a global cache as there are coinductive WellFormed goals in different query frames. It can help with perf too. But this would be a huge change.

@bors bors closed this as completed in e2dc1a1 Sep 17, 2024
github-actions bot pushed a commit to rust-lang/miri that referenced this issue Sep 17, 2024
layout computation: gracefully handle unsized types in unexpected locations

This PR reworks the layout computation to eagerly return an error when encountering an unsized field where a sized field was expected, rather than delaying a bug and attempting to recover a layout. This is required, because with trivially false where clauses like `[T]: Sized`, any field can possible be an unsized type, without causing a compile error.

Since this PR removes the `delayed_bug` method from the `LayoutCalculator` trait, it essentially becomes the same as the `HasDataLayout` trait, so I've also refactored the `LayoutCalculator` to be a simple wrapper struct around a type that implements `HasDataLayout`.

The majority of the diff is whitespace changes, so viewing with whitespace ignored is advised.

implements rust-lang/rust#123169 (comment)

r? `@compiler-errors` or compiler

fixes rust-lang/rust#123134
fixes rust-lang/rust#124182
fixes rust-lang/rust#126939
fixes rust-lang/rust#127737
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 (mir interpretation) C-bug Category: This is a bug. I-ICE Issue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️ S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. 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.

7 participants