Skip to content

Commit aacf886

Browse files
authored
Rollup merge of rust-lang#73306 - calebzulawski:target-feature-11-fn-trait-soundness, r=nikomatsakis
Don't implement Fn* traits for #[target_feature] functions Closes rust-lang#72012.
2 parents 13faeea + 51858da commit aacf886

File tree

4 files changed

+148
-1
lines changed

4 files changed

+148
-1
lines changed

Diff for: src/librustc_trait_selection/traits/error_reporting/mod.rs

+18
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,24 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
429429
);
430430
}
431431

432+
let is_fn_trait = [
433+
self.tcx.lang_items().fn_trait(),
434+
self.tcx.lang_items().fn_mut_trait(),
435+
self.tcx.lang_items().fn_once_trait(),
436+
]
437+
.contains(&Some(trait_ref.def_id()));
438+
let is_target_feature_fn =
439+
if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind {
440+
!self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
441+
} else {
442+
false
443+
};
444+
if is_fn_trait && is_target_feature_fn {
445+
err.note(
446+
"`#[target_feature]` functions do not implement the `Fn` traits",
447+
);
448+
}
449+
432450
// Try to report a help message
433451
if !trait_ref.has_infer_types_or_consts()
434452
&& self.predicate_can_apply(obligation.param_env, trait_ref)

Diff for: src/librustc_trait_selection/traits/select/candidate_assembly.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
306306
candidates.ambiguous = true; // Could wind up being a fn() type.
307307
}
308308
// Provide an impl, but only for suitable `fn` pointers.
309-
ty::FnDef(..) | ty::FnPtr(_) => {
309+
ty::FnPtr(_) => {
310310
if let ty::FnSig {
311311
unsafety: hir::Unsafety::Normal,
312312
abi: Abi::Rust,
@@ -317,6 +317,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
317317
candidates.vec.push(FnPointerCandidate);
318318
}
319319
}
320+
// Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
321+
ty::FnDef(def_id, _) => {
322+
if let ty::FnSig {
323+
unsafety: hir::Unsafety::Normal,
324+
abi: Abi::Rust,
325+
c_variadic: false,
326+
..
327+
} = self_ty.fn_sig(self.tcx()).skip_binder()
328+
{
329+
if self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() {
330+
candidates.vec.push(FnPointerCandidate);
331+
}
332+
}
333+
}
320334
_ => {}
321335
}
322336

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// only-x86_64
2+
3+
#![feature(target_feature_11)]
4+
5+
#[target_feature(enable = "avx")]
6+
fn foo() {}
7+
8+
#[target_feature(enable = "avx")]
9+
unsafe fn foo_unsafe() {}
10+
11+
fn call(f: impl Fn()) {
12+
f()
13+
}
14+
15+
fn call_mut(f: impl FnMut()) {
16+
f()
17+
}
18+
19+
fn call_once(f: impl FnOnce()) {
20+
f()
21+
}
22+
23+
fn main() {
24+
call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
25+
call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
26+
call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
27+
28+
call(foo_unsafe);
29+
//~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
30+
call_mut(foo_unsafe);
31+
//~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
32+
call_once(foo_unsafe);
33+
//~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
2+
--> $DIR/fn-traits.rs:24:10
3+
|
4+
LL | fn call(f: impl Fn()) {
5+
| ---- required by this bound in `call`
6+
...
7+
LL | call(foo);
8+
| ^^^ expected an `Fn<()>` closure, found `fn() {foo}`
9+
|
10+
= help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}`
11+
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
12+
= note: `#[target_feature]` functions do not implement the `Fn` traits
13+
14+
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
15+
--> $DIR/fn-traits.rs:25:14
16+
|
17+
LL | fn call_mut(f: impl FnMut()) {
18+
| ------- required by this bound in `call_mut`
19+
...
20+
LL | call_mut(foo);
21+
| ^^^ expected an `FnMut<()>` closure, found `fn() {foo}`
22+
|
23+
= help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}`
24+
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
25+
= note: `#[target_feature]` functions do not implement the `Fn` traits
26+
27+
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
28+
--> $DIR/fn-traits.rs:26:15
29+
|
30+
LL | fn call_once(f: impl FnOnce()) {
31+
| -------- required by this bound in `call_once`
32+
...
33+
LL | call_once(foo);
34+
| ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}`
35+
|
36+
= help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}`
37+
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
38+
= note: `#[target_feature]` functions do not implement the `Fn` traits
39+
40+
error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
41+
--> $DIR/fn-traits.rs:28:10
42+
|
43+
LL | fn call(f: impl Fn()) {
44+
| ---- required by this bound in `call`
45+
...
46+
LL | call(foo_unsafe);
47+
| ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
48+
|
49+
= help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
50+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
51+
= note: `#[target_feature]` functions do not implement the `Fn` traits
52+
53+
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
54+
--> $DIR/fn-traits.rs:30:14
55+
|
56+
LL | fn call_mut(f: impl FnMut()) {
57+
| ------- required by this bound in `call_mut`
58+
...
59+
LL | call_mut(foo_unsafe);
60+
| ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
61+
|
62+
= help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
63+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
64+
= note: `#[target_feature]` functions do not implement the `Fn` traits
65+
66+
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
67+
--> $DIR/fn-traits.rs:32:15
68+
|
69+
LL | fn call_once(f: impl FnOnce()) {
70+
| -------- required by this bound in `call_once`
71+
...
72+
LL | call_once(foo_unsafe);
73+
| ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
74+
|
75+
= help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
76+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
77+
= note: `#[target_feature]` functions do not implement the `Fn` traits
78+
79+
error: aborting due to 6 previous errors
80+
81+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)