Skip to content

Commit 29b6d29

Browse files
authored
Unrolled build for rust-lang#137399
Rollup merge of rust-lang#137399 - lukas-code:oopsie-woopsie, r=compiler-errors fix ICE in layout computation with unnormalizable const The first commit reverts half of 7a667d2, where I removed a case from `layout_of` for handling non-generic unevaluated consts in array length, that I incorrectly assumed to be unreachable. This can actually happen with the combination of `feature(generic_const_exprs)` and `feature(trivial_bounds)`, because GCE makes anon consts inherit their parent's predicates and with an impossible predicate like `u8: A` it's possible to have an array whose length is an associated const like `<u8 as A>::B` that is not generic, but also can't be normalized: ```rust #![feature(generic_const_exprs)] #![feature(trivial_bounds)] trait A { const B: usize; } // With GCE + trivial bounds this definition is not a compile error. // Computing the layout of this type shouldn't ICE. struct S([u8; <u8 as A>::B]) where u8: A; ``` --- The first commit also incidentally fixes rust-lang#137308, which also managed to get an unnormalizable assoc const into an array length: ```rust trait A { const B: usize; } impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained const B: usize = 42; } // Computing the layout of this type shouldn't ICE, even with the compile error above. struct S([u8; <u8 as A>::B]); ``` This happens, because we bail out from `codegen_select_candidate` with an error if the selected impl has unconstrained params to avoid leaking infer vars out of a query. `Instance::try_resolve` will then return `Ok(None)`, which for assoc consts roughly means "this const can't be evaluated in a generic context" and is treated as such: https://github.com/rust-lang/rust/blob/71e06b9c59d6af50fdc55aed75620493d29baf98/compiler/rustc_middle/src/mir/interpret/queries.rs#L84 (and this can ICE if the const isn't generic: rust-lang#135617). However, here `<u8 as A>::B` is definitely not "too generic" and also not unresolvable due to an unsatisfiable `u8: A` bound, so I've included the second commit to change the result of `Instance::try_resolve` from `Ok(None)` to `Err(ErrorGuaranteed)` when resolving an assoc item to an impl with unconstrained generic params. This has the effect that `<u8 as A>::B` will now be normalized to `ConstKind::Error` in the example above. This properly fixes rust-lang#137308, by no longer treating `<u8 as A>::B` as unresolvable even though it clearly has a unique impl that it resolves to. It also has the effect of changing the layout error from `Unknown` ("the type may be valid but has no sensible layout") to `ReferencesError` ("a non-layout error is reported elsewhere") which seems more appropriate. r? ```@compiler-errors```
2 parents dc37ff8 + 7fea935 commit 29b6d29

File tree

8 files changed

+103
-11
lines changed

8 files changed

+103
-11
lines changed

compiler/rustc_middle/src/traits/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::borrow::Cow;
1212
use std::hash::{Hash, Hasher};
1313
use std::sync::Arc;
1414

15-
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
15+
use rustc_errors::{Applicability, Diag, EmissionGuarantee, ErrorGuaranteed};
1616
use rustc_hir as hir;
1717
use rustc_hir::HirId;
1818
use rustc_hir::def_id::DefId;
@@ -996,4 +996,7 @@ pub enum CodegenObligationError {
996996
/// but was included during typeck due to the trivial_bounds feature.
997997
Unimplemented,
998998
FulfillmentError,
999+
/// The selected impl has unconstrained generic parameters. This will emit an error
1000+
/// during impl WF checking.
1001+
UnconstrainedParam(ErrorGuaranteed),
9991002
}

compiler/rustc_traits/src/codegen.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,14 @@ pub(crate) fn codegen_select_candidate<'tcx>(
8080
// but never resolved, causing the return value of a query to contain inference
8181
// vars. We do not have a concept for this and will in fact ICE in stable hashing
8282
// of the return value. So bail out instead.
83-
match impl_source {
84-
ImplSource::UserDefined(impl_) => {
85-
tcx.dcx().span_delayed_bug(
86-
tcx.def_span(impl_.impl_def_id),
87-
"this impl has unconstrained generic parameters",
88-
);
89-
}
83+
let guar = match impl_source {
84+
ImplSource::UserDefined(impl_) => tcx.dcx().span_delayed_bug(
85+
tcx.def_span(impl_.impl_def_id),
86+
"this impl has unconstrained generic parameters",
87+
),
9088
_ => unreachable!(),
91-
}
92-
return Err(CodegenObligationError::FulfillmentError);
89+
};
90+
return Err(CodegenObligationError::UnconstrainedParam(guar));
9391
}
9492

9593
Ok(&*tcx.arena.alloc(impl_source))

compiler/rustc_ty_utils/src/instance.rs

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ fn resolve_associated_item<'tcx>(
112112
| CodegenObligationError::Unimplemented
113113
| CodegenObligationError::FulfillmentError,
114114
) => return Ok(None),
115+
Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar),
115116
};
116117

117118
// Now that we know which impl is being used, we can dispatch to

compiler/rustc_ty_utils/src/layout.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,25 @@ fn extract_const_value<'tcx>(
147147
) -> Result<ty::Value<'tcx>, &'tcx LayoutError<'tcx>> {
148148
match ct.kind() {
149149
ty::ConstKind::Value(cv) => Ok(cv),
150-
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) => {
150+
ty::ConstKind::Param(_) | ty::ConstKind::Expr(_) => {
151151
if !ct.has_param() {
152152
bug!("failed to normalize const, but it is not generic: {ct:?}");
153153
}
154154
Err(error(cx, LayoutError::TooGeneric(ty)))
155155
}
156+
ty::ConstKind::Unevaluated(_) => {
157+
let err = if ct.has_param() {
158+
LayoutError::TooGeneric(ty)
159+
} else {
160+
// This case is reachable with unsatisfiable predicates and GCE (which will
161+
// cause anon consts to inherit the unsatisfiable predicates). For example
162+
// if we have an unsatisfiable `u8: Trait` bound, then it's not a compile
163+
// error to mention `[u8; <u8 as Trait>::CONST]`, but we can't compute its
164+
// layout.
165+
LayoutError::Unknown(ty)
166+
};
167+
Err(error(cx, err))
168+
}
156169
ty::ConstKind::Infer(_)
157170
| ty::ConstKind::Bound(..)
158171
| ty::ConstKind::Placeholder(_)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//! With `feature(generic_const_exprs)`, anon consts (e.g. length in array types) will
2+
//! inherit their parent's predicates. When combined with `feature(trivial_bounds)`, it
3+
//! is possible to have an unevaluated constant that is rigid, but not generic.
4+
//!
5+
//! This is what happens below: `u8: A` does not hold in the global environment, but
6+
//! with trivial bounds + GCE it it possible that `<u8 as A>::B` can appear in an array
7+
//! length without causing a compile error. This constant is *rigid* (i.e. it cannot be
8+
//! normalized further), but it is *not generic* (i.e. it does not depend on any generic
9+
//! parameters).
10+
//!
11+
//! This test ensures that we do not ICE in layout computation when encountering such a
12+
//! constant.
13+
14+
#![feature(rustc_attrs)]
15+
#![feature(generic_const_exprs)] //~ WARNING: the feature `generic_const_exprs` is incomplete
16+
#![feature(trivial_bounds)]
17+
18+
#![crate_type = "lib"]
19+
20+
trait A {
21+
const B: usize;
22+
}
23+
24+
#[rustc_layout(debug)]
25+
struct S([u8; <u8 as A>::B]) //~ ERROR: the type `[u8; <u8 as A>::B]` has an unknown layout
26+
where
27+
u8: A;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/gce-rigid-const-in-array-len.rs:15:12
3+
|
4+
LL | #![feature(generic_const_exprs)]
5+
| ^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error: the type `[u8; <u8 as A>::B]` has an unknown layout
11+
--> $DIR/gce-rigid-const-in-array-len.rs:25:1
12+
|
13+
LL | struct S([u8; <u8 as A>::B])
14+
| ^^^^^^^^
15+
16+
error: aborting due to 1 previous error; 1 warning emitted
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//! Regression test for <https://github.com/rust-lang/rust/issues/137308>.
2+
//!
3+
//! This used to ICE in layout computation, because `<u8 as A>::B` fails to normalize
4+
//! due to the unconstrained param on the impl.
5+
6+
#![feature(rustc_attrs)]
7+
#![crate_type = "lib"]
8+
9+
trait A {
10+
const B: usize;
11+
}
12+
13+
impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
14+
const B: usize = 42;
15+
}
16+
17+
#[rustc_layout(debug)]
18+
struct S([u8; <u8 as A>::B]); //~ ERROR: the type has an unknown layout
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0207]: the type parameter `C` is not constrained by the impl trait, self type, or predicates
2+
--> $DIR/unconstrained-param-ice-137308.rs:13:6
3+
|
4+
LL | impl<C: ?Sized> A for u8 {
5+
| ^ unconstrained type parameter
6+
7+
error: the type has an unknown layout
8+
--> $DIR/unconstrained-param-ice-137308.rs:18:1
9+
|
10+
LL | struct S([u8; <u8 as A>::B]);
11+
| ^^^^^^^^
12+
13+
error: aborting due to 2 previous errors
14+
15+
For more information about this error, try `rustc --explain E0207`.

0 commit comments

Comments
 (0)