diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-08-09 00:03:36 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-09 00:03:36 +0200 |
| commit | bcf6f9fa76e9ffa637f9a8efe6081ee431a1d22e (patch) | |
| tree | 970cdf5f0525952e35320249b2b4da7c771fdfa5 /compiler | |
| parent | 95b40727bdaa83fbb3bf687ce70640126d017557 (diff) | |
| parent | ec1c424293c04258da127ed4dfc8d4289834efe6 (diff) | |
| download | rust-bcf6f9fa76e9ffa637f9a8efe6081ee431a1d22e.tar.gz rust-bcf6f9fa76e9ffa637f9a8efe6081ee431a1d22e.zip | |
Rollup merge of #128791 - compiler-errors:async-fn-unsafe, r=lcnr
Don't implement `AsyncFn` for `FnDef`/`FnPtr` that wouldnt implement `Fn` Due to unsafety, ABI, or the presence of target features, some `FnDef`/`FnPtr` types don't implement `Fn*`. Do the same for `AsyncFn*`. Noticed this due to #128764, but this isn't really related to that ICE, which is fixed in #128792.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs | 60 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs | 16 |
2 files changed, 53 insertions, 23 deletions
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index e69d8d84d7d..00837f7cdd8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -458,28 +458,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: )) } - ty::FnDef(..) | ty::FnPtr(..) => { - let bound_sig = self_ty.fn_sig(cx); - let sig = bound_sig.skip_binder(); - let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future); - // `FnDef` and `FnPtr` only implement `AsyncFn*` when their - // return type implements `Future`. - let nested = vec![ - bound_sig - .rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])) - .upcast(cx), - ]; - let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput); - let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]); - Ok(( - bound_sig.rebind(AsyncCallableRelevantTypes { - tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()), - output_coroutine_ty: sig.output(), - coroutine_return_ty: future_output_ty, - }), - nested, - )) + ty::FnDef(def_id, _) => { + let sig = self_ty.fn_sig(cx); + if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) { + fn_item_to_async_callable(cx, sig) + } else { + Err(NoSolution) + } + } + ty::FnPtr(..) => { + let sig = self_ty.fn_sig(cx); + if sig.skip_binder().is_fn_trait_compatible() { + fn_item_to_async_callable(cx, sig) + } else { + Err(NoSolution) + } } + ty::Closure(_, args) => { let args = args.as_closure(); let bound_sig = args.sig(); @@ -563,6 +558,29 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<I: } } +fn fn_item_to_async_callable<I: Interner>( + cx: I, + bound_sig: ty::Binder<I, ty::FnSig<I>>, +) -> Result<(ty::Binder<I, AsyncCallableRelevantTypes<I>>, Vec<I::Predicate>), NoSolution> { + let sig = bound_sig.skip_binder(); + let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future); + // `FnDef` and `FnPtr` only implement `AsyncFn*` when their + // return type implements `Future`. + let nested = vec![ + bound_sig.rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])).upcast(cx), + ]; + let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput); + let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]); + Ok(( + bound_sig.rebind(AsyncCallableRelevantTypes { + tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()), + output_coroutine_ty: sig.output(), + coroutine_return_ty: future_output_ty, + }), + nested, + )) +} + /// Given a coroutine-closure, project to its returned coroutine when we are *certain* /// that the closure's kind is compatible with the goal. fn coroutine_closure_to_certain_coroutine<I: Interner>( diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 2085d3da443..9de62031311 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -467,8 +467,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } candidates.vec.push(AsyncClosureCandidate); } - ty::FnDef(..) | ty::FnPtr(..) => { - candidates.vec.push(AsyncClosureCandidate); + // Provide an impl, but only for suitable `fn` pointers. + ty::FnPtr(sig) => { + if sig.is_fn_trait_compatible() { + candidates.vec.push(AsyncClosureCandidate); + } + } + // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). + ty::FnDef(def_id, _) => { + let tcx = self.tcx(); + if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && tcx.codegen_fn_attrs(def_id).target_features.is_empty() + { + candidates.vec.push(AsyncClosureCandidate); + } } _ => {} } |
