Skip to content

Commit cb9cb4d

Browse files
committed
Auto merge of #96806 - cjgillot:codegen-fulfill-nice, r=oli-obk
Gracefully fail to resolve associated items instead of `delay_span_bug`. `codegen_fulfill_obligation` is used during instance resolution for trait items. In case of insufficient normalization issues during MIR inlining, it caused ICEs. It's better to gracefully refuse to resolve the associated item, and let the caller decide what to do with this. Split from #91743 Closes #69121 Closes #73021 Closes #88599 Closes #93008 Closes #93248 Closes #94680 Closes #96170 r? `@oli-obk`
2 parents 6dd6840 + dacf118 commit cb9cb4d

File tree

12 files changed

+108
-88
lines changed

12 files changed

+108
-88
lines changed

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ rustc_queries! {
11451145

11461146
query codegen_fulfill_obligation(
11471147
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
1148-
) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
1148+
) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
11491149
cache_on_disk_if { true }
11501150
desc { |tcx|
11511151
"checking if `{}` fulfills its obligations",

compiler/rustc_middle/src/traits/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -963,3 +963,21 @@ pub enum MethodViolationCode {
963963
/// the method's receiver (`self` argument) can't be dispatched on
964964
UndispatchableReceiver,
965965
}
966+
967+
/// These are the error cases for `codegen_fulfill_obligation`.
968+
#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)]
969+
pub enum CodegenObligationError {
970+
/// Ambiguity can happen when monomorphizing during trans
971+
/// expands to some humongous type that never occurred
972+
/// statically -- this humongous type can then overflow,
973+
/// leading to an ambiguous result. So report this as an
974+
/// overflow bug, since I believe this is the only case
975+
/// where ambiguity can result.
976+
Ambiguity,
977+
/// This can trigger when we probe for the source of a `'static` lifetime requirement
978+
/// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
979+
/// This can also trigger when we have a global bound that is not actually satisfied,
980+
/// but was included during typeck due to the trivial_bounds feature.
981+
Unimplemented,
982+
FulfillmentError,
983+
}

compiler/rustc_trait_selection/src/traits/codegen.rs

+16-75
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33
// seems likely that they should eventually be merged into more
44
// general routines.
55

6-
use crate::infer::{InferCtxt, TyCtxtInferExt};
6+
use crate::infer::TyCtxtInferExt;
77
use crate::traits::{
88
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
99
Unimplemented,
1010
};
11-
use rustc_errors::ErrorGuaranteed;
12-
use rustc_middle::ty::fold::TypeFoldable;
11+
use rustc_middle::traits::CodegenObligationError;
1312
use rustc_middle::ty::{self, TyCtxt};
1413

1514
/// Attempts to resolve an obligation to an `ImplSource`. The result is
@@ -23,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt};
2322
pub fn codegen_fulfill_obligation<'tcx>(
2423
tcx: TyCtxt<'tcx>,
2524
(param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
26-
) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> {
25+
) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
2726
// Remove any references to regions; this helps improve caching.
2827
let trait_ref = tcx.erase_regions(trait_ref);
2928
// We expect the input to be fully normalized.
@@ -40,37 +39,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
4039

4140
let selection = match selcx.select(&obligation) {
4241
Ok(Some(selection)) => selection,
43-
Ok(None) => {
44-
// Ambiguity can happen when monomorphizing during trans
45-
// expands to some humongous type that never occurred
46-
// statically -- this humongous type can then overflow,
47-
// leading to an ambiguous result. So report this as an
48-
// overflow bug, since I believe this is the only case
49-
// where ambiguity can result.
50-
let reported = infcx.tcx.sess.delay_span_bug(
51-
rustc_span::DUMMY_SP,
52-
&format!(
53-
"encountered ambiguity selecting `{:?}` during codegen, presuming due to \
54-
overflow or prior type error",
55-
trait_ref
56-
),
57-
);
58-
return Err(reported);
59-
}
60-
Err(Unimplemented) => {
61-
// This can trigger when we probe for the source of a `'static` lifetime requirement
62-
// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
63-
// This can also trigger when we have a global bound that is not actually satisfied,
64-
// but was included during typeck due to the trivial_bounds feature.
65-
let guar = infcx.tcx.sess.delay_span_bug(
66-
rustc_span::DUMMY_SP,
67-
&format!(
68-
"Encountered error `Unimplemented` selecting `{:?}` during codegen",
69-
trait_ref
70-
),
71-
);
72-
return Err(guar);
73-
}
42+
Ok(None) => return Err(CodegenObligationError::Ambiguity),
43+
Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented),
7444
Err(e) => {
7545
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
7646
}
@@ -85,7 +55,17 @@ pub fn codegen_fulfill_obligation<'tcx>(
8555
let impl_source = selection.map(|predicate| {
8656
fulfill_cx.register_predicate_obligation(&infcx, predicate);
8757
});
88-
let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
58+
59+
// In principle, we only need to do this so long as `impl_source`
60+
// contains unbound type parameters. It could be a slight
61+
// optimization to stop iterating early.
62+
let errors = fulfill_cx.select_all_or_error(&infcx);
63+
if !errors.is_empty() {
64+
return Err(CodegenObligationError::FulfillmentError);
65+
}
66+
67+
let impl_source = infcx.resolve_vars_if_possible(impl_source);
68+
let impl_source = infcx.tcx.erase_regions(impl_source);
8969

9070
// Opaque types may have gotten their hidden types constrained, but we can ignore them safely
9171
// as they will get constrained elsewhere, too.
@@ -95,42 +75,3 @@ pub fn codegen_fulfill_obligation<'tcx>(
9575
Ok(&*tcx.arena.alloc(impl_source))
9676
})
9777
}
98-
99-
// # Global Cache
100-
101-
/// Finishes processes any obligations that remain in the
102-
/// fulfillment context, and then returns the result with all type
103-
/// variables removed and regions erased. Because this is intended
104-
/// for use outside of type inference, if any errors occur,
105-
/// it will panic. It is used during normalization and other cases
106-
/// where processing the obligations in `fulfill_cx` may cause
107-
/// type inference variables that appear in `result` to be
108-
/// unified, and hence we need to process those obligations to get
109-
/// the complete picture of the type.
110-
fn drain_fulfillment_cx_or_panic<'tcx, T>(
111-
infcx: &InferCtxt<'_, 'tcx>,
112-
fulfill_cx: &mut FulfillmentContext<'tcx>,
113-
result: T,
114-
) -> T
115-
where
116-
T: TypeFoldable<'tcx>,
117-
{
118-
debug!("drain_fulfillment_cx_or_panic()");
119-
120-
// In principle, we only need to do this so long as `result`
121-
// contains unbound type parameters. It could be a slight
122-
// optimization to stop iterating early.
123-
let errors = fulfill_cx.select_all_or_error(infcx);
124-
if !errors.is_empty() {
125-
infcx.tcx.sess.delay_span_bug(
126-
rustc_span::DUMMY_SP,
127-
&format!(
128-
"Encountered errors `{:?}` resolving bounds outside of type inference",
129-
errors
130-
),
131-
);
132-
}
133-
134-
let result = infcx.resolve_vars_if_possible(result);
135-
infcx.tcx.erase_regions(result)
136-
}

compiler/rustc_ty_utils/src/instance.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use rustc_errors::ErrorGuaranteed;
22
use rustc_hir::def_id::{DefId, LocalDefId};
33
use rustc_infer::infer::TyCtxtInferExt;
4+
use rustc_middle::traits::CodegenObligationError;
45
use rustc_middle::ty::subst::SubstsRef;
56
use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor};
67
use rustc_span::{sym, DUMMY_SP};
@@ -212,7 +213,22 @@ fn resolve_associated_item<'tcx>(
212213
let mut bound_vars_collector = BoundVarsCollector::new();
213214
trait_ref.visit_with(&mut bound_vars_collector);
214215
let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx));
215-
let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?;
216+
let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) {
217+
Ok(vtbl) => vtbl,
218+
Err(CodegenObligationError::Ambiguity) => {
219+
let reported = tcx.sess.delay_span_bug(
220+
tcx.def_span(trait_item_id),
221+
&format!(
222+
"encountered ambiguity selecting `{:?}` during codegen, presuming due to \
223+
overflow or prior type error",
224+
trait_binder
225+
),
226+
);
227+
return Err(reported);
228+
}
229+
Err(CodegenObligationError::Unimplemented) => return Ok(None),
230+
Err(CodegenObligationError::FulfillmentError) => return Ok(None),
231+
};
216232

217233
// Now that we know which impl is being used, we can dispatch to
218234
// the actual function:

src/test/ui/const-generics/generic_const_exprs/issue-85848.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ fn writes_to_path<C>(cap: &C) {
2424
writes_to_specific_path(&cap);
2525
//~^ ERROR: the trait bound `(): _Contains<&C>` is not satisfied [E0277]
2626
//~| ERROR: unconstrained generic constant
27+
//~| ERROR: mismatched types [E0308]
2728
}
2829

2930
fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}

src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr

+14-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ note: required because of the requirements on the impl of `Delegates<()>` for `&
1818
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
1919
| ^^^^^^^^^^^^ ^
2020
note: required by a bound in `writes_to_specific_path`
21-
--> $DIR/issue-85848.rs:29:31
21+
--> $DIR/issue-85848.rs:30:31
2222
|
2323
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
2424
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
@@ -43,11 +43,21 @@ note: required because of the requirements on the impl of `Delegates<()>` for `&
4343
LL | impl<T, U> Delegates<U> for T where T: Contains<U, true> {}
4444
| ^^^^^^^^^^^^ ^
4545
note: required by a bound in `writes_to_specific_path`
46-
--> $DIR/issue-85848.rs:29:31
46+
--> $DIR/issue-85848.rs:30:31
4747
|
4848
LL | fn writes_to_specific_path<C: Delegates<()>>(cap: &C) {}
4949
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
5050

51-
error: aborting due to 2 previous errors
51+
error[E0308]: mismatched types
52+
--> $DIR/issue-85848.rs:24:5
53+
|
54+
LL | writes_to_specific_path(&cap);
55+
| ^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::<T, U>() }`
56+
|
57+
= note: expected type `true`
58+
found type `{ contains::<T, U>() }`
59+
60+
error: aborting due to 3 previous errors
5261

53-
For more information about this error, try `rustc --explain E0277`.
62+
Some errors have detailed explanations: E0277, E0308.
63+
For more information about an error, try `rustc --explain E0277`.

src/test/ui/const-generics/issues/issue-86530.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ where
1515
fn unit_literals() {
1616
z(" ");
1717
//~^ ERROR: the trait bound `&str: X` is not satisfied
18+
//~| ERROR: unconstrained generic constant
1819
}
1920

2021
fn main() {}

src/test/ui/const-generics/issues/issue-86530.stderr

+17-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ LL | where
1515
LL | T: X,
1616
| ^ required by this bound in `z`
1717

18-
error: aborting due to previous error
18+
error: unconstrained generic constant
19+
--> $DIR/issue-86530.rs:16:5
20+
|
21+
LL | z(" ");
22+
| ^
23+
|
24+
= help: try adding a `where` bound using this expression: `where [(); T::Y]:`
25+
note: required by a bound in `z`
26+
--> $DIR/issue-86530.rs:11:10
27+
|
28+
LL | fn z<T>(t: T)
29+
| - required by a bound in this
30+
...
31+
LL | [(); T::Y]: ,
32+
| ^^^^ required by this bound in `z`
33+
34+
error: aborting due to 2 previous errors
1935

2036
For more information about this error, try `rustc --explain E0277`.

src/test/ui/issues/issue-77919.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
fn main() {
22
[1; <Multiply<Five, Five>>::VAL];
3+
//~^ ERROR: constant expression depends on a generic parameter
34
}
45
trait TypeVal<T> {
56
const VAL: T;

src/test/ui/issues/issue-77919.stderr

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0412]: cannot find type `PhantomData` in this scope
2-
--> $DIR/issue-77919.rs:9:9
2+
--> $DIR/issue-77919.rs:10:9
33
|
44
LL | _n: PhantomData,
55
| ^^^^^^^^^^^ not found in this scope
@@ -10,23 +10,31 @@ LL | use std::marker::PhantomData;
1010
|
1111

1212
error[E0412]: cannot find type `VAL` in this scope
13-
--> $DIR/issue-77919.rs:11:63
13+
--> $DIR/issue-77919.rs:12:63
1414
|
1515
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
1616
| - ^^^ not found in this scope
1717
| |
1818
| help: you might be missing a type parameter: `, VAL`
1919

2020
error[E0046]: not all trait items implemented, missing: `VAL`
21-
--> $DIR/issue-77919.rs:11:1
21+
--> $DIR/issue-77919.rs:12:1
2222
|
2323
LL | const VAL: T;
2424
| ------------- `VAL` from trait
2525
...
2626
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
2727
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
2828

29-
error: aborting due to 3 previous errors
29+
error: constant expression depends on a generic parameter
30+
--> $DIR/issue-77919.rs:2:9
31+
|
32+
LL | [1; <Multiply<Five, Five>>::VAL];
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
|
35+
= note: this may fail depending on what value the parameter takes
36+
37+
error: aborting due to 4 previous errors
3038

3139
Some errors have detailed explanations: E0046, E0412.
3240
For more information about an error, try `rustc --explain E0046`.

src/test/ui/recursion/issue-83150.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// build-fail
2-
//~^ overflow evaluating
2+
//~^ ERROR overflow evaluating the requirement
33

44
fn main() {
55
let mut iter = 0u8..1;

src/tools/clippy/tests/ui/crashes/ice-6252.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,15 @@ LL | const VAL: T;
3030
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
3232

33-
error: aborting due to 3 previous errors
33+
error: constant expression depends on a generic parameter
34+
--> $DIR/ice-6252.rs:13:9
35+
|
36+
LL | [1; <Multiply<Five, Five>>::VAL];
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
|
39+
= note: this may fail depending on what value the parameter takes
40+
41+
error: aborting due to 4 previous errors
3442

3543
Some errors have detailed explanations: E0046, E0412.
3644
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)