From 7872690e5b7e0b889a055210df4671947997982b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 15 Feb 2023 08:45:28 +0000 Subject: [PATCH 1/4] Make trait method lookup reusable --- compiler/rustc_middle/src/ty/mod.rs | 10 ++++++++++ compiler/rustc_mir_build/src/build/matches/test.rs | 12 +++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 09c3d5b736cf1..c99836c6cb5f6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2301,6 +2301,16 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn trait_method(self, trait_def_id: DefId, method_name: Symbol) -> DefId { + // The unhygienic comparison here is acceptable because this is only + // used on known traits. + self.associated_items(trait_def_id) + .filter_by_name_unhygienic(method_name) + .find(|item| item.kind == ty::AssocKind::Fn) + .expect("trait method not found") + .def_id + } + // FIXME(@lcnr): Remove this function. pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] { if let Some(did) = did.as_local() { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index ad7a568a23181..54e494a3676f1 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -837,15 +837,9 @@ fn trait_method<'tcx>( method_name: Symbol, substs: impl IntoIterator>>, ) -> ConstantKind<'tcx> { - // The unhygienic comparison here is acceptable because this is only - // used on known traits. - let item = tcx - .associated_items(trait_def_id) - .filter_by_name_unhygienic(method_name) - .find(|item| item.kind == ty::AssocKind::Fn) - .expect("trait method not found"); - - let method_ty = tcx.mk_fn_def(item.def_id, substs); + let def_id = tcx.trait_method(trait_def_id, method_name); + + let method_ty = tcx.mk_fn_def(def_id, substs); ConstantKind::zero_sized(method_ty) } From a1300b55f93a9cd7fbbbb0d6b1bf7be18e06e004 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 15 Feb 2023 08:45:41 +0000 Subject: [PATCH 2/4] Fix a format string to actually use formatting --- compiler/rustc_const_eval/src/transform/validate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 76b316cdf0c3f..f2500f8d7e063 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -597,7 +597,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { if !(op_ty.is_any_ptr() && target_type.is_unsafe_ptr()) { - self.fail(location, "Can't cast {op_ty} into 'Ptr'"); + self.fail(location, format!("Can't cast {op_ty} into 'Ptr'")); } } CastKind::FloatToFloat | CastKind::FloatToInt => { From ddbf749d8aaedafa31d6fb4f13b5404bdc0ee9e2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 15 Feb 2023 08:47:03 +0000 Subject: [PATCH 3/4] Implement `PartialEq` for all function pointers via a shim --- .../src/interpret/terminator.rs | 1 + compiler/rustc_middle/src/mir/mono.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 1 + compiler/rustc_middle/src/ty/instance.rs | 10 ++ compiler/rustc_middle/src/ty/mod.rs | 1 + compiler/rustc_middle/src/ty/sty.rs | 1 + compiler/rustc_mir_transform/src/inline.rs | 1 + .../rustc_mir_transform/src/inline/cycle.rs | 1 + compiler/rustc_mir_transform/src/shim.rs | 94 +++++++++++++++++++ compiler/rustc_monomorphize/src/collector.rs | 1 + .../src/partitioning/default.rs | 2 + .../src/traits/select/candidate_assembly.rs | 21 ++++- compiler/rustc_ty_utils/src/instance.rs | 16 ++++ 13 files changed, 148 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index da320cd1cd5f0..7ed1b4ab3b923 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -381,6 +381,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::FnPtrEqShim(..) | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) | ty::InstanceDef::Item(_) => { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 7a05ee2ff37fd..3bbb56317b52a 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -378,6 +378,7 @@ impl<'tcx> CodegenUnit<'tcx> { | InstanceDef::ReifyShim(..) | InstanceDef::Intrinsic(..) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::Virtual(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 3ddac5e11fbc5..501373b8ff5a2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -340,6 +340,7 @@ macro_rules! make_mir_visitor { ty::InstanceDef::FnPtrShim(_def_id, ty) | ty::InstanceDef::DropGlue(_def_id, Some(ty)) | + ty::InstanceDef::FnPtrEqShim(_def_id, ty) | ty::InstanceDef::CloneShim(_def_id, ty) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 8b4fccc58bd44..8494a054ebcac 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -96,6 +96,11 @@ pub enum InstanceDef<'tcx> { /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. CloneShim(DefId, Ty<'tcx>), + + /// `::eq` (generated `PartialEq` implementation for `fn()` pointers). + /// + /// `DefId` is `PartialEq::eq`. + FnPtrEqShim(DefId, Ty<'tcx>), } impl<'tcx> Instance<'tcx> { @@ -147,6 +152,7 @@ impl<'tcx> InstanceDef<'tcx> { InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) + | InstanceDef::FnPtrEqShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } @@ -163,6 +169,7 @@ impl<'tcx> InstanceDef<'tcx> { InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } @@ -178,6 +185,7 @@ impl<'tcx> InstanceDef<'tcx> { InstanceDef::VTableShim(def_id) | InstanceDef::ReifyShim(def_id) | InstanceDef::FnPtrShim(def_id, _) + | InstanceDef::FnPtrEqShim(def_id, _) | InstanceDef::Virtual(def_id, _) | InstanceDef::Intrinsic(def_id) | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } @@ -265,6 +273,7 @@ impl<'tcx> InstanceDef<'tcx> { match *self { InstanceDef::CloneShim(..) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::DropGlue(_, Some(_)) => false, InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) @@ -298,6 +307,7 @@ fn fmt_instance( InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty), + InstanceDef::FnPtrEqShim(_, ty) => write!(f, " - shim({ty})"), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c99836c6cb5f6..4dd5323efda7c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2293,6 +2293,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) + | ty::InstanceDef::FnPtrEqShim(..) | ty::InstanceDef::FnPtrShim(..) | ty::InstanceDef::Virtual(..) | ty::InstanceDef::ClosureOnceShim { .. } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 98d6b68356368..bbd297cd8d334 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2088,6 +2088,7 @@ impl<'tcx> Ty<'tcx> { } } + #[track_caller] pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { match self.kind() { FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 84640b703c802..4c6fdc835f93d 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -268,6 +268,7 @@ impl<'tcx> Inliner<'tcx> { InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::DropGlue(..) | InstanceDef::CloneShim(..) => return Ok(()), diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index b027f94925d2f..078b5ce5212a2 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -82,6 +82,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( InstanceDef::VTableShim(_) | InstanceDef::ReifyShim(_) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::ClosureOnceShim { .. } | InstanceDef::CloneShim(..) => {} InstanceDef::DropGlue(..) => { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 551422386f6e0..45312268c1db4 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -44,6 +44,9 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty)) } + ty::InstanceDef::FnPtrEqShim(def_id, ty) => { + build_partial_eq_shim(tcx, instance, def_id, ty) + } // We are generating a call back to our def-id, which the // codegen backend knows to turn to an actual call, be it // a virtual call, or a direct call to a function for which @@ -791,6 +794,97 @@ fn build_call_shim<'tcx>( body } +/// Builds a "call" shim for `PartialEq::eq`. +#[instrument(level = "debug", skip(tcx), ret)] +fn build_partial_eq_shim<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceDef<'tcx>, + partial_eq_eq: DefId, + ty: Ty<'tcx>, +) -> Body<'tcx> { + let span = tcx.def_span(partial_eq_eq); + + let source_info = SourceInfo::outermost(span); + + let mut statements = vec![]; + + let sig = tcx.fn_sig(partial_eq_eq); + let sig = sig.map_bound(|sig| tcx.erase_late_bound_regions(sig)); + let sig = sig.subst(tcx, &[ty.into(), ty.into()]); + let mut local_decls = local_decls_for_sig(&sig, span); + let raw_unit = tcx.mk_imm_ptr(tcx.types.unit); + + let mut cast = |place| { + let tmp = local_decls.push(LocalDecl::new(raw_unit, span).immutable()); + // let tmp = *place as *const (); + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + tmp.into(), + Rvalue::Cast( + CastKind::FnPtrToPtr, + Operand::Move(tcx.mk_place_deref(place)), + raw_unit, + ), + ))), + }); + // let tmp2 = &tmp; + let tmp2 = local_decls.push( + LocalDecl::new(tcx.mk_imm_ref(tcx.lifetimes.re_erased, raw_unit), span).immutable(), + ); + statements.push(Statement { + source_info, + kind: StatementKind::Assign(Box::new(( + tmp2.into(), + Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, tmp.into()), + ))), + }); + Operand::Move(tmp2.into()) + }; + + // Cast both fn ptr arguments to `*const ()` + let a = cast(Local::new(1).into()); + let b = cast(Local::new(2).into()); + + let callee = Operand::Constant(Box::new(Constant { + span, + user_ty: None, + literal: ConstantKind::zero_sized( + tcx.bound_type_of(partial_eq_eq).subst(tcx, &[raw_unit.into(), raw_unit.into()]), + ), + })); + + let mut blocks = IndexVec::with_capacity(2); + let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| { + blocks.push(BasicBlockData { + statements, + terminator: Some(Terminator { source_info, kind }), + is_cleanup, + }) + }; + + // BB #0 + block( + &mut blocks, + statements, + TerminatorKind::Call { + func: callee, + args: vec![a, b], + destination: Place::return_place(), + target: Some(BasicBlock::new(1)), + cleanup: None, + from_hir_call: true, + fn_span: span, + }, + false, + ); + + // BB #1 - return + block(&mut blocks, vec![], TerminatorKind::Return, false); + + new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span) +} + pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { debug_assert!(tcx.is_constructor(ctor_id)); diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 31a3ffbb1d891..9890accd805bc 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -975,6 +975,7 @@ fn visit_instance_use<'tcx>( | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Item(..) | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::FnPtrEqShim(..) | ty::InstanceDef::CloneShim(..) => { output.push(create_fn_mono_item(tcx, instance, source)); } diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs index 29009c48050e1..85845ca426329 100644 --- a/compiler/rustc_monomorphize/src/partitioning/default.rs +++ b/compiler/rustc_monomorphize/src/partitioning/default.rs @@ -274,6 +274,7 @@ fn characteristic_def_id_of_mono_item<'tcx>( ty::InstanceDef::VTableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::FnPtrShim(..) + | ty::InstanceDef::FnPtrEqShim(..) | ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::DropGlue(..) @@ -428,6 +429,7 @@ fn mono_item_visibility<'tcx>( InstanceDef::VTableShim(..) | InstanceDef::ReifyShim(..) | InstanceDef::FnPtrShim(..) + | InstanceDef::FnPtrEqShim(..) | InstanceDef::Virtual(..) | InstanceDef::Intrinsic(..) | InstanceDef::ClosureOnceShim { .. } 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 e9f7c3bc4cca2..4c96863894016 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -103,12 +103,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // types have builtin support for `Clone`. let clone_conditions = self.copy_clone_conditions(obligation); self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); - } - - if lang_items.gen_trait() == Some(def_id) { + } else if lang_items.gen_trait() == Some(def_id) { self.assemble_generator_candidates(obligation, &mut candidates); } else if lang_items.future_trait() == Some(def_id) { self.assemble_future_candidates(obligation, &mut candidates); + } else if lang_items.eq_trait() == Some(def_id) { + self.assemble_eq_candidates(obligation, &mut candidates); } self.assemble_closure_candidates(obligation, &mut candidates); @@ -236,6 +236,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_eq_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let [self_ty, other_ty] = &obligation.predicate.skip_binder().trait_ref.substs[..] else { + span_bug!(obligation.cause.span, "PartialEq has two generic params: `Self` and `Other`, but got {obligation:#?}") + }; + if let ty::FnPtr(..) = self_ty.expect_ty().kind() { + if let ty::FnPtr(..) = other_ty.expect_ty().kind() { + candidates.vec.push(BuiltinCandidate { has_nested: false }); + } + } + } + /// Checks for the artificial impl that the compiler will create for an obligation like `X : /// FnMut<..>` where `X` is a closure type. /// diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 8d46ba320fc03..adf2123edee0c 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -269,6 +269,22 @@ fn resolve_associated_item<'tcx>( let substs = tcx.erase_regions(rcvr_substs); Some(ty::Instance::new(trait_item_id, substs)) } + } else if Some(trait_ref.def_id) == tcx.lang_items().eq_trait() { + // FIXME(eddyb) use lang items for methods instead of names. + let name = tcx.item_name(trait_item_id); + if name == sym::eq { + let self_ty = trait_ref.self_ty(); + Some(Instance { + def: ty::InstanceDef::FnPtrEqShim(trait_item_id, self_ty), + substs: rcvr_substs, + }) + } else { + assert_eq!(name, sym::ne); + + // Use the default `fn ne` from `trait PartialEq`. + let substs = tcx.erase_regions(rcvr_substs); + Some(ty::Instance::new(trait_item_id, substs)) + } } else { None } From ad4a76be518bf136db8689a722bdadc12766aba1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 15 Feb 2023 09:14:30 +0000 Subject: [PATCH 4/4] Add tests showing new and remaining behaviour --- tests/ui/fn/fn-ptr-eq-op.rs | 33 +++++++ tests/ui/fn/fn-ptr-eq-op.stderr | 148 ++++++++++++++++++++++++++++++++ tests/ui/fn/fn-ptr-eq.rs | 19 ++++ 3 files changed, 200 insertions(+) create mode 100644 tests/ui/fn/fn-ptr-eq-op.rs create mode 100644 tests/ui/fn/fn-ptr-eq-op.stderr create mode 100644 tests/ui/fn/fn-ptr-eq.rs diff --git a/tests/ui/fn/fn-ptr-eq-op.rs b/tests/ui/fn/fn-ptr-eq-op.rs new file mode 100644 index 0000000000000..d6ac19a3a029f --- /dev/null +++ b/tests/ui/fn/fn-ptr-eq-op.rs @@ -0,0 +1,33 @@ +fn foo(_: &()) {} + +fn main() { + let x: for<'a> fn(&'a ()) = foo; + let y: for<'a> fn(&'a ()) = foo; + x == y; //~ ERROR: `==` cannot be applied + + let x: for<'a> fn(&'a ()) = foo; + let y: fn(&()) = foo; + x == y; //~ ERROR: `==` cannot be applied + + let x: fn(&()) = foo; + let y: for<'a> fn(&'a ()) = foo; + x == y; //~ ERROR: `==` cannot be applied + + let x: for<'a> fn(&'a ()) = foo; + let y: for<'a> fn(&'a ()) = foo; + x == foo; //~ ERROR: `==` cannot be applied + y == foo; //~ ERROR: `==` cannot be applied + foo == x; //~ ERROR: `==` cannot be applied + //~^ ERROR mismatched types + foo == y; //~ ERROR: `==` cannot be applied + //~^ ERROR mismatched types + + let x: for<'a> fn(&'a ()) = foo; + let y: fn(&'static ()) = foo; + x == y; //~ ERROR: `==` cannot be applied + + let x: fn(&'static ()) = foo; + let y: fn(&'static ()) = foo; + foo == x; //~ ERROR: `==` cannot be applied + //~^ ERROR mismatched types +} diff --git a/tests/ui/fn/fn-ptr-eq-op.stderr b/tests/ui/fn/fn-ptr-eq-op.stderr new file mode 100644 index 0000000000000..c51beed05e63e --- /dev/null +++ b/tests/ui/fn/fn-ptr-eq-op.stderr @@ -0,0 +1,148 @@ +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:6:7 + | +LL | x == y; + | - ^^ - fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | x(/* &() */) == y(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:10:7 + | +LL | x == y; + | - ^^ - fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | x(/* &() */) == y(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:14:7 + | +LL | x == y; + | - ^^ - fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | x(/* &() */) == y(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:18:7 + | +LL | x == foo; + | - ^^ --- fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | x(/* &() */) == foo(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:19:7 + | +LL | y == foo; + | - ^^ --- fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | y(/* &() */) == foo(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ()) {foo}` + --> $DIR/fn-ptr-eq-op.rs:20:9 + | +LL | foo == x; + | --- ^^ - for<'a> fn(&'a ()) + | | + | for<'a> fn(&'a ()) {foo} + | +help: use parentheses to call these + | +LL | foo(/* &() */) == x(/* &() */); + | +++++++++++ +++++++++++ + +error[E0308]: mismatched types + --> $DIR/fn-ptr-eq-op.rs:20:12 + | +LL | foo == x; + | ^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a ()) {foo}` + found fn pointer `for<'a> fn(&'a ())` + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ()) {foo}` + --> $DIR/fn-ptr-eq-op.rs:22:9 + | +LL | foo == y; + | --- ^^ - for<'a> fn(&'a ()) + | | + | for<'a> fn(&'a ()) {foo} + | +help: use parentheses to call these + | +LL | foo(/* &() */) == y(/* &() */); + | +++++++++++ +++++++++++ + +error[E0308]: mismatched types + --> $DIR/fn-ptr-eq-op.rs:22:12 + | +LL | foo == y; + | ^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a ()) {foo}` + found fn pointer `for<'a> fn(&'a ())` + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ())` + --> $DIR/fn-ptr-eq-op.rs:27:7 + | +LL | x == y; + | - ^^ - fn(&()) + | | + | for<'a> fn(&'a ()) + | +help: use parentheses to call these + | +LL | x(/* &() */) == y(/* &() */); + | +++++++++++ +++++++++++ + +error[E0369]: binary operation `==` cannot be applied to type `for<'a> fn(&'a ()) {foo}` + --> $DIR/fn-ptr-eq-op.rs:32:9 + | +LL | foo == x; + | --- ^^ - fn(&()) + | | + | for<'a> fn(&'a ()) {foo} + | +help: use parentheses to call these + | +LL | foo(/* &() */) == x(/* &() */); + | +++++++++++ +++++++++++ + +error[E0308]: mismatched types + --> $DIR/fn-ptr-eq-op.rs:32:12 + | +LL | foo == x; + | ^ expected fn item, found fn pointer + | + = note: expected fn item `for<'a> fn(&'a ()) {foo}` + found fn pointer `fn(&())` + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/fn/fn-ptr-eq.rs b/tests/ui/fn/fn-ptr-eq.rs new file mode 100644 index 0000000000000..3ca98b9048c36 --- /dev/null +++ b/tests/ui/fn/fn-ptr-eq.rs @@ -0,0 +1,19 @@ +// check-pass + +fn foo(_: &()) {} + +fn main() { + let x: for<'a> fn(&'a ()) = foo; + let y: for<'a> fn(&'a ()) = foo; + bar(x, y); + + let x: fn(&'static ()) = foo; + let y: for<'a> fn(&'a ()) = foo; + x == y; + let x: fn(&'static ()) = foo; + let y: fn(&'static ()) = foo; + x == y; + x == foo; +} + +fn bar(_: T, _: T) {}