From 6cfe52c094fcd9897d8c2b4ea713198a58000898 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 1 May 2022 11:03:14 +0200 Subject: [PATCH 1/2] Gracefully fail to resolve associated items instead of `delay_span_bug`. --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 18 ++++ .../src/traits/codegen.rs | 91 ++++--------------- compiler/rustc_ty_utils/src/instance.rs | 18 +++- .../generic_const_exprs/issue-85848.rs | 1 + .../generic_const_exprs/issue-85848.stderr | 18 +++- .../ui/const-generics/issues/issue-86530.rs | 1 + .../const-generics/issues/issue-86530.stderr | 18 +++- src/test/ui/issues/issue-77919.rs | 1 + src/test/ui/issues/issue-77919.stderr | 16 +++- src/test/ui/recursion/issue-83150.rs | 2 +- 11 files changed, 99 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 629a550b77596..0ef694a3c8543 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1145,7 +1145,7 @@ rustc_queries! { query codegen_fulfill_obligation( key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) - ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> { + ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> { cache_on_disk_if { true } desc { |tcx| "checking if `{}` fulfills its obligations", diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ffde1294ec655..8c660e38a7fbe 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -963,3 +963,21 @@ pub enum MethodViolationCode { /// the method's receiver (`self` argument) can't be dispatched on UndispatchableReceiver, } + +/// These are the error cases for `codegen_fulfill_obligation`. +#[derive(Copy, Clone, Debug, Hash, HashStable, Encodable, Decodable)] +pub enum CodegenObligationError { + /// Ambiguity can happen when monomorphizing during trans + /// expands to some humongous type that never occurred + /// statically -- this humongous type can then overflow, + /// leading to an ambiguous result. So report this as an + /// overflow bug, since I believe this is the only case + /// where ambiguity can result. + Ambiguity, + /// This can trigger when we probe for the source of a `'static` lifetime requirement + /// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. + /// This can also trigger when we have a global bound that is not actually satisfied, + /// but was included during typeck due to the trivial_bounds feature. + Unimplemented, + FulfillmentError, +} diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs index c76a6542ca1b1..6ca630b74cc79 100644 --- a/compiler/rustc_trait_selection/src/traits/codegen.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen.rs @@ -3,13 +3,12 @@ // seems likely that they should eventually be merged into more // general routines. -use crate::infer::{InferCtxt, TyCtxtInferExt}; +use crate::infer::TyCtxtInferExt; use crate::traits::{ FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine, Unimplemented, }; -use rustc_errors::ErrorGuaranteed; -use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt}; /// Attempts to resolve an obligation to an `ImplSource`. The result is @@ -23,7 +22,7 @@ use rustc_middle::ty::{self, TyCtxt}; pub fn codegen_fulfill_obligation<'tcx>( tcx: TyCtxt<'tcx>, (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), -) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorGuaranteed> { +) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> { // Remove any references to regions; this helps improve caching. let trait_ref = tcx.erase_regions(trait_ref); // We expect the input to be fully normalized. @@ -40,37 +39,8 @@ pub fn codegen_fulfill_obligation<'tcx>( let selection = match selcx.select(&obligation) { Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongous type that never occurred - // statically -- this humongous type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - let reported = infcx.tcx.sess.delay_span_bug( - rustc_span::DUMMY_SP, - &format!( - "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ - overflow or prior type error", - trait_ref - ), - ); - return Err(reported); - } - Err(Unimplemented) => { - // This can trigger when we probe for the source of a `'static` lifetime requirement - // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. - // This can also trigger when we have a global bound that is not actually satisfied, - // but was included during typeck due to the trivial_bounds feature. - let guar = infcx.tcx.sess.delay_span_bug( - rustc_span::DUMMY_SP, - &format!( - "Encountered error `Unimplemented` selecting `{:?}` during codegen", - trait_ref - ), - ); - return Err(guar); - } + Ok(None) => return Err(CodegenObligationError::Ambiguity), + Err(Unimplemented) => return Err(CodegenObligationError::Unimplemented), Err(e) => { bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) } @@ -85,7 +55,17 @@ pub fn codegen_fulfill_obligation<'tcx>( let impl_source = selection.map(|predicate| { fulfill_cx.register_predicate_obligation(&infcx, predicate); }); - let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source); + + // In principle, we only need to do this so long as `impl_source` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + let errors = fulfill_cx.select_all_or_error(&infcx); + if !errors.is_empty() { + return Err(CodegenObligationError::FulfillmentError); + } + + let impl_source = infcx.resolve_vars_if_possible(impl_source); + let impl_source = infcx.tcx.erase_regions(impl_source); // Opaque types may have gotten their hidden types constrained, but we can ignore them safely // as they will get constrained elsewhere, too. @@ -95,42 +75,3 @@ pub fn codegen_fulfill_obligation<'tcx>( Ok(&*tcx.arena.alloc(impl_source)) }) } - -// # Global Cache - -/// Finishes processes any obligations that remain in the -/// fulfillment context, and then returns the result with all type -/// variables removed and regions erased. Because this is intended -/// for use outside of type inference, if any errors occur, -/// it will panic. It is used during normalization and other cases -/// where processing the obligations in `fulfill_cx` may cause -/// type inference variables that appear in `result` to be -/// unified, and hence we need to process those obligations to get -/// the complete picture of the type. -fn drain_fulfillment_cx_or_panic<'tcx, T>( - infcx: &InferCtxt<'_, 'tcx>, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: T, -) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - let errors = fulfill_cx.select_all_or_error(infcx); - if !errors.is_empty() { - infcx.tcx.sess.delay_span_bug( - rustc_span::DUMMY_SP, - &format!( - "Encountered errors `{:?}` resolving bounds outside of type inference", - errors - ), - ); - } - - let result = infcx.resolve_vars_if_possible(result); - infcx.tcx.erase_regions(result) -} diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 802a59abe5faf..143081d61fb37 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,6 +1,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Binder, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitor}; use rustc_span::{sym, DUMMY_SP}; @@ -212,7 +213,22 @@ fn resolve_associated_item<'tcx>( let mut bound_vars_collector = BoundVarsCollector::new(); trait_ref.visit_with(&mut bound_vars_collector); let trait_binder = ty::Binder::bind_with_vars(trait_ref, bound_vars_collector.into_vars(tcx)); - let vtbl = tcx.codegen_fulfill_obligation((param_env, trait_binder))?; + let vtbl = match tcx.codegen_fulfill_obligation((param_env, trait_binder)) { + Ok(vtbl) => vtbl, + Err(CodegenObligationError::Ambiguity) => { + let reported = tcx.sess.delay_span_bug( + tcx.def_span(trait_item_id), + &format!( + "encountered ambiguity selecting `{:?}` during codegen, presuming due to \ + overflow or prior type error", + trait_binder + ), + ); + return Err(reported); + } + Err(CodegenObligationError::Unimplemented) => return Ok(None), + Err(CodegenObligationError::FulfillmentError) => return Ok(None), + }; // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs b/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs index e86ffbf10757e..3a7f4c6184cf1 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs +++ b/src/test/ui/const-generics/generic_const_exprs/issue-85848.rs @@ -24,6 +24,7 @@ fn writes_to_path(cap: &C) { writes_to_specific_path(&cap); //~^ ERROR: the trait bound `(): _Contains<&C>` is not satisfied [E0277] //~| ERROR: unconstrained generic constant + //~| ERROR: mismatched types [E0308] } fn writes_to_specific_path>(cap: &C) {} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr index 27f5dce9fb266..d45dfde9a791a 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr @@ -18,7 +18,7 @@ note: required because of the requirements on the impl of `Delegates<()>` for `& LL | impl Delegates for T where T: Contains {} | ^^^^^^^^^^^^ ^ note: required by a bound in `writes_to_specific_path` - --> $DIR/issue-85848.rs:29:31 + --> $DIR/issue-85848.rs:30:31 | LL | fn writes_to_specific_path>(cap: &C) {} | ^^^^^^^^^^^^^ 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 `& LL | impl Delegates for T where T: Contains {} | ^^^^^^^^^^^^ ^ note: required by a bound in `writes_to_specific_path` - --> $DIR/issue-85848.rs:29:31 + --> $DIR/issue-85848.rs:30:31 | LL | fn writes_to_specific_path>(cap: &C) {} | ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path` -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/issue-85848.rs:24:5 + | +LL | writes_to_specific_path(&cap); + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `true`, found `{ contains::() }` + | + = note: expected type `true` + found type `{ contains::() }` + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-86530.rs b/src/test/ui/const-generics/issues/issue-86530.rs index b024decd4e11c..4a6ffd1f3008e 100644 --- a/src/test/ui/const-generics/issues/issue-86530.rs +++ b/src/test/ui/const-generics/issues/issue-86530.rs @@ -15,6 +15,7 @@ where fn unit_literals() { z(" "); //~^ ERROR: the trait bound `&str: X` is not satisfied + //~| ERROR: unconstrained generic constant } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-86530.stderr b/src/test/ui/const-generics/issues/issue-86530.stderr index c63857b2314e9..c688f838dab47 100644 --- a/src/test/ui/const-generics/issues/issue-86530.stderr +++ b/src/test/ui/const-generics/issues/issue-86530.stderr @@ -15,6 +15,22 @@ LL | where LL | T: X, | ^ required by this bound in `z` -error: aborting due to previous error +error: unconstrained generic constant + --> $DIR/issue-86530.rs:16:5 + | +LL | z(" "); + | ^ + | + = help: try adding a `where` bound using this expression: `where [(); T::Y]:` +note: required by a bound in `z` + --> $DIR/issue-86530.rs:11:10 + | +LL | fn z(t: T) + | - required by a bound in this +... +LL | [(); T::Y]: , + | ^^^^ required by this bound in `z` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs index 966d76d148af3..1d5d593073117 100644 --- a/src/test/ui/issues/issue-77919.rs +++ b/src/test/ui/issues/issue-77919.rs @@ -1,5 +1,6 @@ fn main() { [1; >::VAL]; + //~^ ERROR: constant expression depends on a generic parameter } trait TypeVal { const VAL: T; diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr index 97bd5ab36b65d..c986e47fb5589 100644 --- a/src/test/ui/issues/issue-77919.stderr +++ b/src/test/ui/issues/issue-77919.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `PhantomData` in this scope - --> $DIR/issue-77919.rs:9:9 + --> $DIR/issue-77919.rs:10:9 | LL | _n: PhantomData, | ^^^^^^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> $DIR/issue-77919.rs:11:63 + --> $DIR/issue-77919.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | - ^^^ not found in this scope @@ -18,7 +18,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | help: you might be missing a type parameter: `, VAL` error[E0046]: not all trait items implemented, missing: `VAL` - --> $DIR/issue-77919.rs:11:1 + --> $DIR/issue-77919.rs:12:1 | LL | const VAL: T; | ------------- `VAL` from trait @@ -26,7 +26,15 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: constant expression depends on a generic parameter + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs index dc25004f89bdb..aa3f66b2e28e1 100644 --- a/src/test/ui/recursion/issue-83150.rs +++ b/src/test/ui/recursion/issue-83150.rs @@ -1,5 +1,5 @@ // build-fail - //~^ overflow evaluating +//~^ ERROR overflow evaluating the requirement fn main() { let mut iter = 0u8..1; From dacf1185cb9c6aa9bc9770c5202dce6c35d6604e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Wed, 11 May 2022 18:51:14 +0200 Subject: [PATCH 2/2] Bless clippy. --- src/tools/clippy/tests/ui/crashes/ice-6252.stderr | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index c8239897f3abb..d930d486fde65 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -30,7 +30,15 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: aborting due to 3 previous errors +error: constant expression depends on a generic parameter + --> $DIR/ice-6252.rs:13:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`.