about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-25 15:05:51 +0000
committerbors <bors@rust-lang.org>2024-04-25 15:05:51 +0000
commit9e6c4fddda9d3e5d6cf1b20a0fb82c128efe27ef (patch)
tree0c8f7087e062f6d18ae044a4d37976554aee376a
parent6a9758d4f38d4763bd437c48fa7e5246cecf8d04 (diff)
parent870ed4bfa2be044bafba589b9d53def3f0a8b005 (diff)
downloadrust-9e6c4fddda9d3e5d6cf1b20a0fb82c128efe27ef.tar.gz
rust-9e6c4fddda9d3e5d6cf1b20a0fb82c128efe27ef.zip
Auto merge of #123531 - compiler-errors:closure-wf, r=oli-obk
Enforce closure args + return type are WF

I found this out when investigating https://github.com/rust-lang/rust/issues/123461#issuecomment-2040894359. Turns out we don't register WF obligations for closure args and return types, leading to the ICE.

~~I think this is a useful thing to check for, but I'd like to check what the fallout is.~~ crater is complete.

~~Worst case, I think we should enforce this across an edition boundary (and possibly eventually migrate this for all editions) -- this should be super easy to do, since this is a check in HIR wfcheck, so it can be made edition dependent.~~ I believe the regressions are manageable enough to not necessitate edition-specific behavior.

Fixes #123461
-rw-r--r--compiler/rustc_errors/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs19
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs2
-rw-r--r--tests/crashes/123461.rs5
-rw-r--r--tests/ui/inference/issue-80409.compat.stderr20
-rw-r--r--tests/ui/inference/issue-80409.no-compat.stderr24
-rw-r--r--tests/ui/inference/issue-80409.rs14
-rw-r--r--tests/ui/issues/issue-66706.rs1
-rw-r--r--tests/ui/issues/issue-66706.stderr10
-rw-r--r--tests/ui/traits/mutual-recursion-issue-75860.rs4
-rw-r--r--tests/ui/traits/mutual-recursion-issue-75860.stderr12
-rw-r--r--tests/ui/transmute/ambiguity-in-closure-arg.rs11
-rw-r--r--tests/ui/transmute/ambiguity-in-closure-arg.stderr9
-rw-r--r--tests/ui/type/type-check/unknown_type_for_closure.stderr4
-rw-r--r--tests/ui/wf/closure-wf.rs11
-rw-r--r--tests/ui/wf/closure-wf.stderr20
16 files changed, 126 insertions, 44 deletions
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b3c1c6c8515..adbac80d7cc 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -502,7 +502,7 @@ struct DiagCtxtInner {
 }
 
 /// A key denoting where from a diagnostic was stashed.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub enum StashKey {
     ItemNoType,
     UnderscoreForArrayLengths,
@@ -779,7 +779,7 @@ impl DiagCtxt {
             // We delay a bug here so that `-Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs`
             // can be used to create a backtrace at the stashing site insted of whenever the
             // diagnostic context is dropped and thus delayed bugs are emitted.
-            Error => Some(self.span_delayed_bug(span, "stashing {key:?}")),
+            Error => Some(self.span_delayed_bug(span, format!("stashing {key:?}"))),
             DelayedBug => return self.inner.borrow_mut().emit_diagnostic(diag),
             ForceWarning(_) | Warning | Note | OnceNote | Help | OnceHelp | FailureNote | Allow
             | Expect(_) => None,
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index b0d1b6655db..b106eca59c4 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -10,6 +10,7 @@ use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi};
 use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::RegionVariableOrigin;
+use rustc_infer::traits::WellFormedLoc;
 use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::sym;
@@ -71,6 +72,18 @@ pub(super) fn check_fn<'a, 'tcx>(
     let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs);
     let inputs_fn = fn_sig.inputs().iter().copied();
     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
+        // We checked the root's signature during wfcheck, but not the child.
+        if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
+            fcx.register_wf_obligation(
+                param_ty.into(),
+                param.span,
+                traits::WellFormed(Some(WellFormedLoc::Param {
+                    function: fn_def_id,
+                    param_idx: idx,
+                })),
+            );
+        }
+
         // Check the pattern.
         let ty: Option<&hir::Ty<'_>> = inputs_hir.and_then(|h| h.get(idx));
         let ty_span = ty.map(|ty| ty.span);
@@ -108,7 +121,13 @@ pub(super) fn check_fn<'a, 'tcx>(
         hir::FnRetTy::DefaultReturn(_) => body.value.span,
         hir::FnRetTy::Return(ty) => ty.span,
     };
+
     fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType);
+    // We checked the root's signature during wfcheck, but not the child.
+    if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
+        fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::WellFormed(None));
+    }
+
     fcx.is_whole_body.set(true);
     fcx.check_return_expr(body.value, false);
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index ceee3ea48e3..c4eef8e7728 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -487,7 +487,7 @@ pub enum WellFormedLoc {
         /// The index of the parameter to use.
         /// Parameters are indexed from 0, with the return type
         /// being the last 'parameter'
-        param_idx: u16,
+        param_idx: usize,
     },
 }
 
diff --git a/tests/crashes/123461.rs b/tests/crashes/123461.rs
deleted file mode 100644
index 6dbfb5c8092..00000000000
--- a/tests/crashes/123461.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: #123461
-
-fn main() {
-    let _: [_; unsafe { std::mem::transmute(|o_b: Option<_>| {}) }];
-}
diff --git a/tests/ui/inference/issue-80409.compat.stderr b/tests/ui/inference/issue-80409.compat.stderr
new file mode 100644
index 00000000000..2f3f6cef209
--- /dev/null
+++ b/tests/ui/inference/issue-80409.compat.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `usize: Fsm` is not satisfied
+  --> $DIR/issue-80409.rs:36:31
+   |
+LL |     builder.state().on_entry(|_| {});
+   |                               ^ the trait `Fsm` is not implemented for `usize`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-80409.rs:26:1
+   |
+LL | trait Fsm {
+   | ^^^^^^^^^
+note: required by a bound in `StateContext`
+  --> $DIR/issue-80409.rs:30:31
+   |
+LL | struct StateContext<'a, TFsm: Fsm> {
+   |                               ^^^ required by this bound in `StateContext`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr
index c772225be75..2f3f6cef209 100644
--- a/tests/ui/inference/issue-80409.no-compat.stderr
+++ b/tests/ui/inference/issue-80409.no-compat.stderr
@@ -1,14 +1,20 @@
-error: internal compiler error: error performing operation: fully_perform
-  --> $DIR/issue-80409.rs:49:30
+error[E0277]: the trait bound `usize: Fsm` is not satisfied
+  --> $DIR/issue-80409.rs:36:31
    |
 LL |     builder.state().on_entry(|_| {});
-   |                              ^^^
+   |                               ^ the trait `Fsm` is not implemented for `usize`
    |
-note: 
-  --> $DIR/issue-80409.rs:49:30
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-80409.rs:26:1
    |
-LL |     builder.state().on_entry(|_| {});
-   |                              ^^^
+LL | trait Fsm {
+   | ^^^^^^^^^
+note: required by a bound in `StateContext`
+  --> $DIR/issue-80409.rs:30:31
+   |
+LL | struct StateContext<'a, TFsm: Fsm> {
+   |                               ^^^ required by this bound in `StateContext`
+
+error: aborting due to 1 previous error
 
-query stack during panic:
-end of query stack
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/inference/issue-80409.rs b/tests/ui/inference/issue-80409.rs
index dfb84563e6d..86dac3cda91 100644
--- a/tests/ui/inference/issue-80409.rs
+++ b/tests/ui/inference/issue-80409.rs
@@ -1,18 +1,5 @@
-// This should not pass, because `usize: Fsm` does not hold. However, it currently ICEs.
-
-// ignore-tidy-linelength
-
 //@ revisions: compat no-compat
-//@[compat] check-pass
 //@[no-compat] compile-flags: -Zno-implied-bounds-compat
-//@[no-compat] check-fail
-//@[no-compat] known-bug: #80409
-//@[no-compat] failure-status: 101
-//@[no-compat] normalize-stderr-test "delayed at.*" -> ""
-//@[no-compat] normalize-stderr-test "note: .*\n\n" -> ""
-//@[no-compat] normalize-stderr-test "thread 'rustc' panicked.*\n" -> ""
-//@[no-compat] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: "
-//@[no-compat] rustc-env:RUST_BACKTRACE=0
 
 #![allow(unreachable_code, unused)]
 
@@ -47,4 +34,5 @@ struct StateContext<'a, TFsm: Fsm> {
 fn main() {
     let mut builder: FsmBuilder<usize> = todo!();
     builder.state().on_entry(|_| {});
+    //~^ ERROR the trait bound `usize: Fsm` is not satisfied
 }
diff --git a/tests/ui/issues/issue-66706.rs b/tests/ui/issues/issue-66706.rs
index 835fdfae86c..6d1d9f5e3a9 100644
--- a/tests/ui/issues/issue-66706.rs
+++ b/tests/ui/issues/issue-66706.rs
@@ -12,6 +12,7 @@ fn b() {
 fn c() {
     [0; [|&_: _ &_| {}; 0 ].len()]
     //~^ ERROR expected `,`, found `&`
+    //~| ERROR type annotations needed
 }
 
 fn d() {
diff --git a/tests/ui/issues/issue-66706.stderr b/tests/ui/issues/issue-66706.stderr
index ffdd61e7723..0271db754bd 100644
--- a/tests/ui/issues/issue-66706.stderr
+++ b/tests/ui/issues/issue-66706.stderr
@@ -21,7 +21,7 @@ LL |     [0; [|&_: _ &_| {}; 0 ].len()]
    |                help: missing `,`
 
 error: expected identifier, found reserved identifier `_`
-  --> $DIR/issue-66706.rs:18:26
+  --> $DIR/issue-66706.rs:19:26
    |
 LL |     [0; match [|f @ &ref _| () ] {} ]
    |         -----            ^ expected identifier, found reserved identifier
@@ -34,6 +34,12 @@ error[E0282]: type annotations needed
 LL |     [0; [|_: _ &_| ()].len()]
    |           ^ cannot infer type
 
-error: aborting due to 5 previous errors
+error[E0282]: type annotations needed
+  --> $DIR/issue-66706.rs:13:11
+   |
+LL |     [0; [|&_: _ &_| {}; 0 ].len()]
+   |           ^^^^^ cannot infer type
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/mutual-recursion-issue-75860.rs b/tests/ui/traits/mutual-recursion-issue-75860.rs
index d7d7307b424..65c3dd132c3 100644
--- a/tests/ui/traits/mutual-recursion-issue-75860.rs
+++ b/tests/ui/traits/mutual-recursion-issue-75860.rs
@@ -6,10 +6,10 @@ pub fn iso<A, B, F1, F2>(a: F1, b: F2) -> (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) ->
     (Box::new(a), Box::new(b))
 }
 pub fn iso_un_option<A, B>() -> (Box<dyn Fn(A) -> B>, Box<dyn Fn(B) -> A>) {
-   let left = |o_a: Option<_>| o_a.unwrap();
+    let left = |o_a: Option<_>| o_a.unwrap();
+    //~^ ERROR overflow
     let right = |o_b: Option<_>| o_b.unwrap();
     iso(left, right)
-    //~^ ERROR overflow
 }
 
 fn main() {}
diff --git a/tests/ui/traits/mutual-recursion-issue-75860.stderr b/tests/ui/traits/mutual-recursion-issue-75860.stderr
index 8f83bab003d..272c56301bc 100644
--- a/tests/ui/traits/mutual-recursion-issue-75860.stderr
+++ b/tests/ui/traits/mutual-recursion-issue-75860.stderr
@@ -1,12 +1,8 @@
-error[E0275]: overflow evaluating the requirement `Option<_>: Sized`
-  --> $DIR/mutual-recursion-issue-75860.rs:11:5
+error[E0275]: overflow assigning `_` to `Option<_>`
+  --> $DIR/mutual-recursion-issue-75860.rs:9:33
    |
-LL |     iso(left, right)
-   |     ^^^
-   |
-   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`mutual_recursion_issue_75860`)
-note: required by an implicit `Sized` bound in `Option`
-  --> $SRC_DIR/core/src/option.rs:LL:COL
+LL |     let left = |o_a: Option<_>| o_a.unwrap();
+   |                                 ^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.rs b/tests/ui/transmute/ambiguity-in-closure-arg.rs
new file mode 100644
index 00000000000..4c2d1ce2ad4
--- /dev/null
+++ b/tests/ui/transmute/ambiguity-in-closure-arg.rs
@@ -0,0 +1,11 @@
+// Minimized test for <https://github.com/rust-lang/rust/issues/123461>.
+
+struct Unconstrained<T>(T);
+
+fn main() {
+    unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) };
+    //~^ ERROR type annotations needed
+    // We unfortunately don't check `Wf(Unconstrained<_>)`, so we won't
+    // hit an ambiguity error before checking the transmute. That means
+    // we still may have inference variables in our transmute src.
+}
diff --git a/tests/ui/transmute/ambiguity-in-closure-arg.stderr b/tests/ui/transmute/ambiguity-in-closure-arg.stderr
new file mode 100644
index 00000000000..24a10a6d210
--- /dev/null
+++ b/tests/ui/transmute/ambiguity-in-closure-arg.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/ambiguity-in-closure-arg.rs:6:44
+   |
+LL |     unsafe { std::mem::transmute::<_, ()>(|o_b: Unconstrained<_>| {}) };
+   |                                            ^^^^^^^^^^^^^^^^^^^^^ cannot infer type
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/type/type-check/unknown_type_for_closure.stderr b/tests/ui/type/type-check/unknown_type_for_closure.stderr
index e5e29aabf37..960c0eff8ea 100644
--- a/tests/ui/type/type-check/unknown_type_for_closure.stderr
+++ b/tests/ui/type/type-check/unknown_type_for_closure.stderr
@@ -1,8 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/unknown_type_for_closure.rs:2:13
+  --> $DIR/unknown_type_for_closure.rs:2:14
    |
 LL |     let x = |b: Vec<_>| {};
-   |             ^^^^^^^^^^^^^^ cannot infer type for struct `Vec<_>`
+   |              ^^^^^^^^^ cannot infer type
 
 error[E0282]: type annotations needed
   --> $DIR/unknown_type_for_closure.rs:6:14
diff --git a/tests/ui/wf/closure-wf.rs b/tests/ui/wf/closure-wf.rs
new file mode 100644
index 00000000000..48baeb30ce5
--- /dev/null
+++ b/tests/ui/wf/closure-wf.rs
@@ -0,0 +1,11 @@
+trait Bound {}
+struct NeedsBound<T: Bound>(T);
+
+// Checks that we enforce that closure args are WF.
+
+fn constrain_inner<T, F: for<'a> FnOnce(&'a (), NeedsBound<T>)>(_: T, _: F) {}
+
+fn main() {
+    constrain_inner(1u32, |&(), _| ());
+    //~^ ERROR the trait bound `u32: Bound` is not satisfied
+}
diff --git a/tests/ui/wf/closure-wf.stderr b/tests/ui/wf/closure-wf.stderr
new file mode 100644
index 00000000000..4beef3bb7c5
--- /dev/null
+++ b/tests/ui/wf/closure-wf.stderr
@@ -0,0 +1,20 @@
+error[E0277]: the trait bound `u32: Bound` is not satisfied
+  --> $DIR/closure-wf.rs:9:33
+   |
+LL |     constrain_inner(1u32, |&(), _| ());
+   |                                 ^ the trait `Bound` is not implemented for `u32`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/closure-wf.rs:1:1
+   |
+LL | trait Bound {}
+   | ^^^^^^^^^^^
+note: required by a bound in `NeedsBound`
+  --> $DIR/closure-wf.rs:2:22
+   |
+LL | struct NeedsBound<T: Bound>(T);
+   |                      ^^^^^ required by this bound in `NeedsBound`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.