Skip to content

fix ICE in layout computation with unnormalizable const #137399

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

Merged
merged 2 commits into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::borrow::Cow;
use std::hash::{Hash, Hasher};
use std::sync::Arc;

use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::HirId;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -996,4 +996,7 @@ pub enum CodegenObligationError {
/// but was included during typeck due to the trivial_bounds feature.
Unimplemented,
FulfillmentError,
/// The selected impl has unconstrained generic parameters. This will emit an error
/// during impl WF checking.
UnconstrainedParam(ErrorGuaranteed),
}
16 changes: 7 additions & 9 deletions compiler/rustc_traits/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,14 @@ pub(crate) fn codegen_select_candidate<'tcx>(
// but never resolved, causing the return value of a query to contain inference
// vars. We do not have a concept for this and will in fact ICE in stable hashing
// of the return value. So bail out instead.
match impl_source {
ImplSource::UserDefined(impl_) => {
tcx.dcx().span_delayed_bug(
tcx.def_span(impl_.impl_def_id),
"this impl has unconstrained generic parameters",
);
}
let guar = match impl_source {
ImplSource::UserDefined(impl_) => tcx.dcx().span_delayed_bug(
tcx.def_span(impl_.impl_def_id),
"this impl has unconstrained generic parameters",
),
_ => unreachable!(),
}
return Err(CodegenObligationError::FulfillmentError);
};
return Err(CodegenObligationError::UnconstrainedParam(guar));
}

Ok(&*tcx.arena.alloc(impl_source))
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ fn resolve_associated_item<'tcx>(
| CodegenObligationError::Unimplemented
| CodegenObligationError::FulfillmentError,
) => return Ok(None),
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
};

// Now that we know which impl is being used, we can dispatch to
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,25 @@ fn extract_const_value<'tcx>(
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
match ct.kind() {
ty::ConstKind::Value(cv) => Ok(cv),
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
if !ct.has_param() {
bug!("failed to normalize const, but it is not generic: {ct:?}");
}
Err(error(cx, LayoutError::TooGeneric(ty)))
}
ty::ConstKind::Unevaluated(_) => {
let err = if ct.has_param() {
LayoutError::TooGeneric(ty)
} else {
// This case is reachable with unsatisfiable predicates and GCE (which will
// cause anon consts to inherit the unsatisfiable predicates). For example
// if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
// error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
// layout.
LayoutError::Unknown(ty)
};
Err(error(cx, err))
}
ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
Expand Down
27 changes: 27 additions & 0 deletions tests/ui/layout/gce-rigid-const-in-array-len.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//! With `feature(generic_const_exprs)`, anon consts (e.g. length in array types) will
//! inherit their parent's predicates. When combined with `feature(trivial_bounds)`, it
//! is possible to have an unevaluated constant that is rigid, but not generic.
//!
//! This is what happens below: `u8: A` does not hold in the global environment, but
//! with trivial bounds + GCE it it possible that `<u8 as A>::B` can appear in an array
//! length without causing a compile error. This constant is *rigid* (i.e. it cannot be
//! normalized further), but it is *not generic* (i.e. it does not depend on any generic
//! parameters).
//!
//! This test ensures that we do not ICE in layout computation when encountering such a
//! constant.

#![feature(rustc_attrs)]
#![feature(generic_const_exprs)] //~ WARNING: the feature `generic_const_exprs` is incomplete
#![feature(trivial_bounds)]

#![crate_type = "lib"]

trait A {
const B: usize;
}

#[rustc_layout(debug)]
struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
where
u8: A;
17 changes: 17 additions & 0 deletions tests/ui/layout/gce-rigid-const-in-array-len.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/gce-rigid-const-in-array-len.rs:15:12
|
LL | #![feature(generic_const_exprs)]
| ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
= note: `#[warn(incomplete_features)]` on by default

error: the type `[u8; <u8 as A>::B]` has an unknown layout
--> $DIR/gce-rigid-const-in-array-len.rs:25:1
|
LL | struct S([u8; <u8 as A>::B])
| ^^^^^^^^

error: aborting due to 1 previous error; 1 warning emitted

18 changes: 18 additions & 0 deletions tests/ui/layout/unconstrained-param-ice-137308.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/137308>.
//!
//! This used to ICE in layout computation, because `<u8 as A>::B` fails to normalize
//! due to the unconstrained param on the impl.

#![feature(rustc_attrs)]
#![crate_type = "lib"]

trait A {
const B: usize;
}

impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
const B: usize = 42;
}

#[rustc_layout(debug)]
struct S([u8; <u8 as A>::B]); //~ ERROR: the type has an unknown layout
15 changes: 15 additions & 0 deletions tests/ui/layout/unconstrained-param-ice-137308.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
--> $DIR/unconstrained-param-ice-137308.rs:13:6
|
LL | impl<C: ?Sized> A for u8 {
| ^ unconstrained type parameter

error: the type has an unknown layout
--> $DIR/unconstrained-param-ice-137308.rs:18:1
|
LL | struct S([u8; <u8 as A>::B]);
| ^^^^^^^^

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0207`.
Loading