about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-11 21:39:02 +0000
committerbors <bors@rust-lang.org>2022-05-11 21:39:02 +0000
commitcb9cb4d4e10366ea2ce13813fff26b90ab3fec1d (patch)
tree00f1c9cb1913239c0490df4422d1dfa4c38f37df
parent6dd68402c5d7da168f87d8551dd9aed1d8a21893 (diff)
parentdacf1185cb9c6aa9bc9770c5202dce6c35d6604e (diff)
downloadrust-cb9cb4d4e10366ea2ce13813fff26b90ab3fec1d.tar.gz
rust-cb9cb4d4e10366ea2ce13813fff26b90ab3fec1d.zip
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 https://github.com/rust-lang/rust/pull/91743
Closes #69121
Closes #73021
Closes #88599
Closes #93008
Closes #93248
Closes #94680
Closes #96170
r? `@oli-obk`
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs18
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs91
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs18
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-85848.rs1
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-85848.stderr18
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.rs1
-rw-r--r--src/test/ui/const-generics/issues/issue-86530.stderr18
-rw-r--r--src/test/ui/issues/issue-77919.rs1
-rw-r--r--src/test/ui/issues/issue-77919.stderr16
-rw-r--r--src/test/ui/recursion/issue-83150.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr10
12 files changed, 108 insertions, 88 deletions
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 629a550b775..0ef694a3c85 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 ffde1294ec6..8c660e38a7f 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 c76a6542ca1..6ca630b74cc 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 802a59abe5f..143081d61fb 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 e86ffbf1075..3a7f4c6184c 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<C>(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<C: Delegates<()>>(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 27f5dce9fb2..d45dfde9a79 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<T, U> Delegates<U> for T where T: Contains<U, true> {}
    |            ^^^^^^^^^^^^     ^
 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<C: Delegates<()>>(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<T, U> Delegates<U> for T where T: Contains<U, true> {}
    |            ^^^^^^^^^^^^     ^
 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<C: Delegates<()>>(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::<T, U>() }`
+   |
+   = note: expected type `true`
+              found type `{ contains::<T, U>() }`
+
+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 b024decd4e1..4a6ffd1f300 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 c63857b2314..c688f838dab 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: 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 966d76d148a..1d5d5930731 100644
--- a/src/test/ui/issues/issue-77919.rs
+++ b/src/test/ui/issues/issue-77919.rs
@@ -1,5 +1,6 @@
 fn main() {
     [1; <Multiply<Five, Five>>::VAL];
+    //~^ ERROR: constant expression depends on a generic parameter
 }
 trait TypeVal<T> {
     const VAL: T;
diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr
index 97bd5ab36b6..c986e47fb55 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<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          -                                                    ^^^ not found in this scope
@@ -18,7 +18,7 @@ LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    |          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<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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; <Multiply<Five, Five>>::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 dc25004f89b..aa3f66b2e28 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;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index c8239897f3a..d930d486fde 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<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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; <Multiply<Five, Five>>::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`.