mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-19 18:34:08 +00:00
Auto merge of #108138 - compiler-errors:malformed-fn-trait, r=TaKO8Ki
Move `Fn*` traits malformedness protections to typeck I found it strange that we were doing a custom well-formedness check just for the `Fn*` traits' `call_*` fn items. My understanding from the git history is that this is just to avoid ICEs later on in typeck. Well, that well-formedness check isn't even implemented correctly for `FnOnce::call_once`, or `FnMut::call_mut` for that matter. Instead, this PR just makes the typeck checks more robust, and leaves it up to the call-site to report errors when lang items are implemented in funny ways. This coincidentally fixes another ICE where a the `Add` lang item is implemented with a `add` item that's a const instead of a method.
This commit is contained in:
commit
3200982b76
@ -16,7 +16,7 @@ use rustc_middle::mir::ConstraintCategory;
|
|||||||
use rustc_middle::ty::query::Providers;
|
use rustc_middle::ty::query::Providers;
|
||||||
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
use rustc_middle::ty::trait_def::TraitSpecializationKind;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ir::TypeVisitor, AdtKind, DefIdTree, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
|
self, ir::TypeVisitor, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable,
|
||||||
TypeSuperVisitable,
|
TypeSuperVisitable,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
|
use rustc_middle::ty::{GenericArgKind, InternalSubsts};
|
||||||
@ -277,56 +277,6 @@ fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
|
|||||||
};
|
};
|
||||||
check_object_unsafe_self_trait_by_name(tcx, trait_item);
|
check_object_unsafe_self_trait_by_name(tcx, trait_item);
|
||||||
check_associated_item(tcx, def_id, span, method_sig);
|
check_associated_item(tcx, def_id, span, method_sig);
|
||||||
|
|
||||||
let encl_trait_def_id = tcx.local_parent(def_id);
|
|
||||||
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
|
|
||||||
let encl_trait_def_id = encl_trait.owner_id.to_def_id();
|
|
||||||
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
|
|
||||||
Some("fn")
|
|
||||||
} else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
|
|
||||||
Some("fn_mut")
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
if let (Some(fn_lang_item_name), "call") =
|
|
||||||
(fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str())
|
|
||||||
{
|
|
||||||
// We are looking at the `call` function of the `fn` or `fn_mut` lang item.
|
|
||||||
// Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
|
|
||||||
if let Some(hir::FnSig { decl, span, .. }) = method_sig {
|
|
||||||
if let [self_ty, _] = decl.inputs {
|
|
||||||
if !matches!(self_ty.kind, hir::TyKind::Ref(_, _)) {
|
|
||||||
tcx.sess
|
|
||||||
.struct_span_err(
|
|
||||||
self_ty.span,
|
|
||||||
&format!(
|
|
||||||
"first argument of `call` in `{fn_lang_item_name}` lang item must be a reference",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tcx.sess
|
|
||||||
.struct_span_err(
|
|
||||||
*span,
|
|
||||||
&format!(
|
|
||||||
"`call` function in `{fn_lang_item_name}` lang item takes exactly two arguments",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tcx.sess
|
|
||||||
.struct_span_err(
|
|
||||||
trait_item.span,
|
|
||||||
&format!(
|
|
||||||
"`call` trait item in `{fn_lang_item_name}` lang item must be a function",
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Require that the user writes where clauses on GATs for the implicit
|
/// Require that the user writes where clauses on GATs for the implicit
|
||||||
|
@ -247,6 +247,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
adjusted_ty,
|
adjusted_ty,
|
||||||
opt_input_type.as_ref().map(slice::from_ref),
|
opt_input_type.as_ref().map(slice::from_ref),
|
||||||
) {
|
) {
|
||||||
|
// Check for `self` receiver on the method, otherwise we can't use this as a `Fn*` trait.
|
||||||
|
if !self.tcx.associated_item(ok.value.def_id).fn_has_self_parameter {
|
||||||
|
self.tcx.sess.delay_span_bug(
|
||||||
|
call_expr.span,
|
||||||
|
"input to overloaded call fn is not a self receiver",
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let method = self.register_infer_ok_obligations(ok);
|
let method = self.register_infer_ok_obligations(ok);
|
||||||
let mut autoref = None;
|
let mut autoref = None;
|
||||||
if borrow {
|
if borrow {
|
||||||
@ -257,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// caused an error elsewhere.
|
// caused an error elsewhere.
|
||||||
self.tcx
|
self.tcx
|
||||||
.sess
|
.sess
|
||||||
.delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?");
|
.delay_span_bug(call_expr.span, "input to call/call_mut is not a ref");
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -271,6 +280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
target: method.sig.inputs()[0],
|
target: method.sig.inputs()[0],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Some((autoref, method));
|
return Some((autoref, method));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -823,7 +833,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
|
|||||||
);
|
);
|
||||||
err.help(
|
err.help(
|
||||||
"make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \
|
"make sure the `fn`/`fn_mut`/`fn_once` lang items are defined \
|
||||||
and have associated `call`/`call_mut`/`call_once` functions",
|
and have correctly defined `call`/`call_mut`/`call_once` methods",
|
||||||
);
|
);
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
@ -380,6 +380,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if method_item.kind != ty::AssocKind::Fn {
|
||||||
|
self.tcx.sess.delay_span_bug(tcx.def_span(method_item.def_id), "not a method");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let def_id = method_item.def_id;
|
let def_id = method_item.def_id;
|
||||||
let generics = tcx.generics_of(def_id);
|
let generics = tcx.generics_of(def_id);
|
||||||
|
|
||||||
|
18
tests/ui/lang-items/bad-add-impl.rs
Normal file
18
tests/ui/lang-items/bad-add-impl.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#![feature(no_core)]
|
||||||
|
#![feature(lang_items)]
|
||||||
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[lang = "add"]
|
||||||
|
trait Add<T> {
|
||||||
|
const add: u32 = 1u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<u32> for u32 {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
1u32 + 1u32;
|
||||||
|
//~^ ERROR cannot add `u32` to `u32`
|
||||||
|
}
|
11
tests/ui/lang-items/bad-add-impl.stderr
Normal file
11
tests/ui/lang-items/bad-add-impl.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
error[E0369]: cannot add `u32` to `u32`
|
||||||
|
--> $DIR/bad-add-impl.rs:16:10
|
||||||
|
|
|
||||||
|
LL | 1u32 + 1u32;
|
||||||
|
| ---- ^ ---- u32
|
||||||
|
| |
|
||||||
|
| u32
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0369`.
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:39:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:43:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
18
tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_sig.stderr
Normal file
18
tests/ui/lang-items/fn-fn_mut-call-ill-formed.bad_sig.stderr
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:39:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:43:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -0,0 +1,18 @@
|
|||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:42:5
|
||||||
|
|
|
||||||
|
LL | a();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: failed to find an overloaded call trait for closure call
|
||||||
|
--> $DIR/fn-fn_mut-call-ill-formed.rs:47:5
|
||||||
|
|
|
||||||
|
LL | b();
|
||||||
|
| ^^^
|
||||||
|
|
|
||||||
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
@ -1,27 +1,49 @@
|
|||||||
// Make sure that an error is reported if the `call` function of the
|
// revisions: fn_once_bad_item fn_once_bad_sig fn_mut_bad_item fn_mut_bad_sig fn_bad_item fn_bad_sig
|
||||||
// `fn`/`fn_mut` lang item is grossly ill-formed.
|
|
||||||
|
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(no_core)]
|
#![feature(no_core)]
|
||||||
#![no_core]
|
#![no_core]
|
||||||
|
|
||||||
|
#[lang = "sized"]
|
||||||
|
trait Sized {}
|
||||||
|
|
||||||
|
#[cfg(any(fn_bad_item, fn_bad_sig))]
|
||||||
#[lang = "fn"]
|
#[lang = "fn"]
|
||||||
trait MyFn<T> {
|
trait MyFn<T> {
|
||||||
|
#[cfg(fn_bad_sig)]
|
||||||
|
fn call(i: i32) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[cfg(fn_bad_item)]
|
||||||
const call: i32 = 42;
|
const call: i32 = 42;
|
||||||
//~^ ERROR: `call` trait item in `fn` lang item must be a function
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(fn_mut_bad_item, fn_mut_bad_sig))]
|
||||||
#[lang = "fn_mut"]
|
#[lang = "fn_mut"]
|
||||||
trait MyFnMut<T> {
|
trait MyFnMut<T> {
|
||||||
fn call(i: i32, j: i32) -> i32 { i + j }
|
#[cfg(fn_mut_bad_sig)]
|
||||||
//~^ ERROR: first argument of `call` in `fn_mut` lang item must be a reference
|
fn call_mut(i: i32) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[cfg(fn_mut_bad_item)]
|
||||||
|
const call_mut: i32 = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(fn_once_bad_item, fn_once_bad_sig))]
|
||||||
|
#[lang = "fn_once"]
|
||||||
|
trait MyFnOnce<T> {
|
||||||
|
#[cfg(fn_once_bad_sig)]
|
||||||
|
fn call_once(i: i32) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[cfg(fn_once_bad_item)]
|
||||||
|
const call_once: i32 = 42;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = || 42;
|
let a = || 42;
|
||||||
a();
|
a();
|
||||||
|
//~^ ERROR failed to find an overloaded call trait for closure call
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut b = || { i += 1; };
|
let mut b = || { };
|
||||||
b();
|
b();
|
||||||
|
//~^ ERROR failed to find an overloaded call trait for closure call
|
||||||
}
|
}
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
error: `call` trait item in `fn` lang item must be a function
|
|
||||||
--> $DIR/fn-fn_mut-call-ill-formed.rs:10:5
|
|
||||||
|
|
|
||||||
LL | const call: i32 = 42;
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: first argument of `call` in `fn_mut` lang item must be a reference
|
|
||||||
--> $DIR/fn-fn_mut-call-ill-formed.rs:16:16
|
|
||||||
|
|
|
||||||
LL | fn call(i: i32, j: i32) -> i32 { i + j }
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
@ -4,7 +4,7 @@ error: failed to find an overloaded call trait for closure call
|
|||||||
LL | one()
|
LL | one()
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
|
|
||||||
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have associated `call`/`call_mut`/`call_once` functions
|
= help: make sure the `fn`/`fn_mut`/`fn_once` lang items are defined and have correctly defined `call`/`call_mut`/`call_once` methods
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user