Change:
I tried this code: I expected to see this happen: The compilation succeed or guide me to (1) cast the to with . (2) borrow the : . But in this case the addresses printed are the same (what?). Instead, this happened*: Cryptic error message: There is : . It took me minutes before I found the workaround. But it still surprised me. : <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
This creates a reference-to-function-pointer (type ), a double indirection. So it is not what you want. The error could possibly be improved, and the entire situation documented better, but I think getting an error is expected here. is not a function pointer, it is an anonymous ) (of size 0) indicating exactly the function it was created from. This type coerces to a function pointer, but cannot know what type to coerce it to. Printing function pointers is easy (well, if they are not polymorphic via ), but printing these function singleton ZSTs is hard.
It might also be worth linting against .
helps with the docs. But to close this issue, it would probably make sense to write a lint against where is the name of a function. That should be a matter of adding a new in which checks all expressions for being . That path we can pass to to get a . Now we just need to check if that refers to a function: pass the to . At least I hope that makes sense, someone stop me if this is all wrong. ;)
I'd like to help write this lint. The default level for the lint should be right? claim
Yeah, feels like a reasonable start.
Nominated for lang team discussion. It seems we usually ask for lints to be approved before shipping them, so let's get that process started. sorry for this, I wasn't aware of this part of the process. You can still go ahead and implement this if you want, but depending on what the lang team decides, we should submit this lint to clippy instead of the compiler itself. That might require minor adjustments, but the main work you are putting in and the testcases will be useful either way. :)
As a point of interest, this would have been extremely useful in helping debug a segfault in The original code used , not .
Without the cast, this should not compile as transmute checks that the sizes match. I assume what you describe happens when using , i.e., not just remove the but also add a .
Unfortunately I never committed the broken code so I'm not sure what I had originally ... the closest thing is which doesn't compile. Sorry for the noise.
no worries. I already have the lint implemented, but in that case I'll wait until they discuss to write the tests
I think should compile. That's no noise, it seems very relevant. :)
poll T-lang Should we add a lint for taking a reference to a fn?
Team member has asked teams: T-lang, for consensus on: [x] [x] [x] [ ] [x] [ ]
I think I agree here, but to confirm: this isn't actually about linting the taking of a reference to a place of type, but just about using on the voldemort-typed function name constants, right?
Yes.
Discussed in a (rather small) meeting today: Those present felt a lint would make sense. If somebody wanted to go ahead and try to author one, please feel free and nominate the resulting PR for discussion.
all right, so if you want to open a PR, everything is settled for that. :)

Discussion:
<ins> use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::ty::{ self, subst::{GenericArgKind, Subst, SubstsRef}, PredicateAtom, Ty, TyCtxt, TyS, }; use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; use crate::transform::MirPass; pub struct FunctionItemReferences; impl<'tcx> MirPass<'tcx> for FunctionItemReferences { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let mut checker = FunctionItemRefChecker { tcx, body }; checker.visit_body(&body); } } struct FunctionItemRefChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, } impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> { /// Emits a lint for function reference arguments bound by `fmt::Pointer` or passed to /// `transmute`. This only handles arguments in calls outside macro expansions to avoid double /// counting function references formatted as pointers by macros. fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { if let TerminatorKind::Call { func, args, destination: _, cleanup: _, from_hir_call: _, fn_span: _, } = &terminator.kind { let source_info = *self.body.source_info(location); // Only handle function calls outside macros if !source_info.span.from_expansion() { let func_ty = func.ty(self.body, self.tcx); if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() { // Handle calls to `transmute` if self.tcx.is_diagnostic_item(sym::transmute, def_id) { let arg_ty = args[0].ty(self.body, self.tcx); for generic_inner_ty in arg_ty.walk() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(inner_ty) { let ident = self.tcx.item_name(fn_id).to_ident_string(); let span = self.nth_arg_span(&args, 0); self.emit_lint(ident, fn_id, source_info, span); } } } } else { self.check_bound_args(def_id, substs_ref, &args, source_info); } } } } self.super_terminator(terminator, location); } /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These /// cases are handled as operands instead of call terminators to avoid any dependence on /// unstable, internal formatting details like whether `fmt` is called directly or not. fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { let source_info = *self.body.source_info(location); if source_info.span.from_expansion() { let op_ty = operand.ty(self.body, self.tcx); if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() { if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) { let param_ty = substs_ref.type_at(0); if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(param_ty) { // The operand's ctxt wouldn't display the lint since it's inside a macro so // we have to use the callsite's ctxt. let callsite_ctxt = source_info.span.source_callsite().ctxt(); let span = source_info.span.with_ctxt(callsite_ctxt); let ident = self.tcx.item_name(fn_id).to_ident_string(); self.emit_lint(ident, fn_id, source_info, span); } } } } self.super_operand(operand, location); } } impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> { /// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the /// function defined by `def_id` with the substitutions `substs_ref`. fn check_bound_args( &self, def_id: DefId, substs_ref: SubstsRef<'tcx>, args: &Vec<Operand<'tcx>>, source_info: SourceInfo, ) { let param_env = self.tcx.param_env(def_id); let bounds = param_env.caller_bounds(); for bound in bounds { if let Some(bound_ty) = self.is_pointer_trait(&bound.skip_binders()) { // Get the argument types as they appear in the function signature. let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); for (arg_num, arg_def) in arg_defs.iter().enumerate() { // For all types reachable from the argument type in the fn sig for generic_inner_ty in arg_def.walk() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { // If the inner type matches the type bound by `Pointer` if TyS::same_type(inner_ty, bound_ty) { // Do a substitution using the parameters from the callsite let subst_ty = inner_ty.subst(self.tcx, substs_ref); if let Some(fn_id) = FunctionItemRefChecker::is_fn_ref(subst_ty) { let ident = self.tcx.item_name(fn_id).to_ident_string(); let span = self.nth_arg_span(args, arg_num); self.emit_lint(ident, fn_id, source_info, span); } } } } } } } } /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type. fn is_pointer_trait(&self, bound: &PredicateAtom<'tcx>) -> Option<Ty<'tcx>> { if let ty::PredicateAtom::Trait(predicate, _) = bound { if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) { Some(predicate.trait_ref.self_ty()) } else { None } } else { None } } /// If a type is a reference or raw pointer to the anonymous type of a function definition, /// returns that function's `DefId`. fn is_fn_ref(ty: Ty<'tcx>) -> Option<DefId> { let referent_ty = match ty.kind() { ty::Ref(_, referent_ty, _) => Some(referent_ty), ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty), _ => None, }; referent_ty .map( |ref_ty| { if let ty::FnDef(def_id, _) = *ref_ty.kind() { Some(def_id) } else { None } }, ) .unwrap_or(None) } fn nth_arg_span(&self, args: &Vec<Operand<'tcx>>, n: usize) -> Span { match &args[n] { Operand::Copy(place) | Operand::Move(place) => { self.body.local_decls[place.local].source_info.span } Operand::Constant(constant) => constant.span, } } fn emit_lint(&self, ident: String, fn_id: DefId, source_info: SourceInfo, span: Span) { let lint_root = self.body.source_scopes[source_info.scope] .local_data .as_ref() .assert_crate_local() .lint_root; let fn_sig = self.tcx.fn_sig(fn_id); let unsafety = fn_sig.unsafety().prefix_str(); let abi = match fn_sig.abi() { Abi::Rust => String::from(""), other_abi => { let mut s = String::from("extern ""); s.push_str(other_abi.name()); s.push_str("" "); s } }; let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder(); let variadic = if fn_sig.c_variadic() { ", ..." } else { "" }; let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" }; self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| { lint.build("taking a reference to a function item does not give a function pointer") .span_suggestion( span, &format!("cast `{}` to obtain a function pointer", ident), format!( "{} as {}{}fn({}{}){}", ident, unsafety, abi, vec!["_"; num_args].join(", "), variadic, ret, ), Applicability::Unspecified, ) .emit(); }); } } </ins>

pub mod dump_mir; pub mod early_otherwise_branch; pub mod elaborate_drops; <ins> pub mod function_item_references; </ins> pub mod generator; pub mod inline; pub mod instcombine;

// MIR-level lints. &check_packed_ref::CheckPackedRef, &check_const_item_mutation::CheckConstItemMutation, <ins> &function_item_references::FunctionItemReferences, </ins> // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck,

} declare_lint! { <ins> /// The `function_item_references` lint detects function references that are /// formatted with [`fmt::Pointer`] or transmuted. /// /// [`fmt::Pointer`]: https://doc.rust-lang.org/std/fmt/trait.Pointer.html /// /// ### Example /// /// ```rust /// fn foo() { } /// /// fn main() { ///     println!("{:p}", &foo); /// } /// ``` /// /// {{produces}} /// /// ### Explanation /// /// Taking a reference to a function may be mistaken as a way to obtain a /// pointer to that function. This can give unexpected results when /// formatting the reference as a pointer or transmuting it. This lint is /// issued when function references are formatted as pointers, passed as /// arguments bound by [`fmt::Pointer`] or transmuted. pub FUNCTION_ITEM_REFERENCES, Warn, "suggest casting to a function pointer when attempting to take references to function items", } declare_lint! { </ins> /// The `uninhabited_static` lint detects uninhabited statics. /// /// ### Example

CONST_EVALUATABLE_UNCHECKED, INEFFECTIVE_UNSTABLE_TRAIT_IMPL, UNINHABITED_STATIC, <ins> FUNCTION_ITEM_REFERENCES, </ins> ] }

plugin_registrar, plugins, pointer, <ins> pointer_trait, pointer_trait_fmt, </ins> poll, position, post_dash_lto: "post-lto",

/// assert_eq!(&l_ptr[..2], "0x"); /// ``` #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait"] </ins> pub trait Pointer { /// Formats the value using the given formatter. #[stable(feature = "rust1", since = "1.0.0")] <ins> #[rustc_diagnostic_item = "pointer_trait_fmt"] </ins> fn fmt(&self, f: &mut Formatter<'_>) -> Result; }

<ins> // check-pass #![feature(c_variadic)] #![warn(function_item_references)] use std::fmt::Pointer; use std::fmt::Formatter; fn nop() { } fn foo() -> u32 { 42 } fn bar(x: u32) -> u32 { x } fn baz(x: u32, y: u32) -> u32 { x + y } unsafe fn unsafe_fn() { } extern "C" fn c_fn() { } unsafe extern "C" fn unsafe_c_fn() { } unsafe extern fn variadic(_x: u32, _args: ...) { } //function references passed to these functions should never lint fn call_fn(f: &dyn Fn(u32) -> u32, x: u32) { f(x); } fn parameterized_call_fn<F: Fn(u32) -> u32>(f: &F, x: u32) { f(x); } //function references passed to these functions should lint fn print_ptr<F: Pointer>(f: F) { println!("{:p}", f); } fn bound_by_ptr_trait<F: Pointer>(_f: F) { } fn bound_by_ptr_trait_tuple<F: Pointer, G: Pointer>(_t: (F, G)) { } fn implicit_ptr_trait<F>(f: &F) { println!("{:p}", f); } //case found in tinyvec that triggered a compiler error in an earlier version of the lint checker trait HasItem { type Item; fn assoc_item(&self) -> Self::Item; } fn _format_assoc_item<T: HasItem>(data: T, f: &mut Formatter) -> std::fmt::Result where T::Item: Pointer { //when the arg type bound by `Pointer` is an associated type, we shouldn't attempt to normalize Pointer::fmt(&data.assoc_item(), f) } //simple test to make sure that calls to `Pointer::fmt` aren't double counted fn _call_pointer_fmt(f: &mut Formatter) -> std::fmt::Result { let zst_ref = &foo; Pointer::fmt(&zst_ref, f) //~^ WARNING taking a reference to a function item does not give a function pointer } fn main() { //`let` bindings with function references shouldn't lint let _ = &foo; let _ = &mut foo; let zst_ref = &foo; let fn_item = foo; let indirect_ref = &fn_item; let _mut_zst_ref = &mut foo; let mut mut_fn_item = foo; let _mut_indirect_ref = &mut mut_fn_item; let cast_zst_ptr = &foo as *const _; let coerced_zst_ptr: *const _ = &foo; let _mut_cast_zst_ptr = &mut foo as *mut _; let _mut_coerced_zst_ptr: *mut _ = &mut foo; let _cast_zst_ref = &foo as &dyn Fn() -> u32; let _coerced_zst_ref: &dyn Fn() -> u32 = &foo; let _mut_cast_zst_ref = &mut foo as &mut dyn Fn() -> u32; let _mut_coerced_zst_ref: &mut dyn Fn() -> u32 = &mut foo; //the suggested way to cast to a function pointer let fn_ptr = foo as fn() -> u32; //correct ways to print function pointers println!("{:p}", foo as fn() -> u32); println!("{:p}", fn_ptr); //potential ways to incorrectly try printing function pointers println!("{:p}", &foo); //~^ WARNING taking a reference to a function item does not give a function pointer print!("{:p}", &foo); //~^ WARNING taking a reference to a function item does not give a function pointer format!("{:p}", &foo); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &foo as *const _); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", zst_ref); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", cast_zst_ptr); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", coerced_zst_ptr); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &fn_item); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", indirect_ref); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &nop); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &bar); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &baz); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &unsafe_fn); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &c_fn); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &unsafe_c_fn); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &variadic); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p}", &std::env::var::<String>); //~^ WARNING taking a reference to a function item does not give a function pointer println!("{:p} {:p} {:p}", &nop, &foo, &bar); //~^ WARNING taking a reference to a function item does not give a function pointer //~^^ WARNING taking a reference to a function item does not give a function pointer //~^^^ WARNING taking a reference to a function item does not give a function pointer //using a function reference to call a function shouldn't lint (&bar)(1); //passing a function reference to an arbitrary function shouldn't lint call_fn(&bar, 1); parameterized_call_fn(&bar, 1); std::mem::size_of_val(&foo); unsafe { //potential ways to incorrectly try transmuting function pointers std::mem::transmute::<_, usize>(&foo); //~^ WARNING taking a reference to a function item does not give a function pointer std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); //~^ WARNING taking a reference to a function item does not give a function pointer //~^^ WARNING taking a reference to a function item does not give a function pointer //the correct way to transmute function pointers std::mem::transmute::<_, usize>(foo as fn() -> u32); std::mem::transmute::<_, (usize, usize)>((foo as fn() -> u32, bar as fn(u32) -> u32)); } //function references as arguments required to be bound by std::fmt::Pointer should lint print_ptr(&bar); //~^ WARNING taking a reference to a function item does not give a function pointer bound_by_ptr_trait(&bar); //~^ WARNING taking a reference to a function item does not give a function pointer bound_by_ptr_trait_tuple((&foo, &bar)); //~^ WARNING taking a reference to a function item does not give a function pointer //~^^ WARNING taking a reference to a function item does not give a function pointer implicit_ptr_trait(&bar); // ignore //correct ways to pass function pointers as arguments bound by std::fmt::Pointer print_ptr(bar as fn(u32) -> u32); bound_by_ptr_trait(bar as fn(u32) -> u32); bound_by_ptr_trait_tuple((foo as fn() -> u32, bar as fn(u32) -> u32)); } </ins>

<ins> warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:40:18 | LL |     Pointer::fmt(&zst_ref, f) |                  ^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` | note: the lint level is defined here --> $DIR/function-item-references.rs:3:9 | LL | #![warn(function_item_references)] |         ^^^^^^^^^^^^^^^^^^^^^^^^ warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:77:22 | LL |     println!("{:p}", &foo); |                      ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:79:20 | LL |     print!("{:p}", &foo); |                    ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:81:21 | LL |     format!("{:p}", &foo); |                     ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:84:22 | LL |     println!("{:p}", &foo as *const _); |                      ^^^^^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:86:22 | LL |     println!("{:p}", zst_ref); |                      ^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:88:22 | LL |     println!("{:p}", cast_zst_ptr); |                      ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:90:22 | LL |     println!("{:p}", coerced_zst_ptr); |                      ^^^^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:93:22 | LL |     println!("{:p}", &fn_item); |                      ^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:95:22 | LL |     println!("{:p}", indirect_ref); |                      ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:98:22 | LL |     println!("{:p}", &nop); |                      ^^^^ help: cast `nop` to obtain a function pointer: `nop as fn()` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:100:22 | LL |     println!("{:p}", &bar); |                      ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:102:22 | LL |     println!("{:p}", &baz); |                      ^^^^ help: cast `baz` to obtain a function pointer: `baz as fn(_, _) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:104:22 | LL |     println!("{:p}", &unsafe_fn); |                      ^^^^^^^^^^ help: cast `unsafe_fn` to obtain a function pointer: `unsafe_fn as unsafe fn()` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:106:22 | LL |     println!("{:p}", &c_fn); |                      ^^^^^ help: cast `c_fn` to obtain a function pointer: `c_fn as extern "C" fn()` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:108:22 | LL |     println!("{:p}", &unsafe_c_fn); |                      ^^^^^^^^^^^^ help: cast `unsafe_c_fn` to obtain a function pointer: `unsafe_c_fn as unsafe extern "C" fn()` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:110:22 | LL |     println!("{:p}", &variadic); |                      ^^^^^^^^^ help: cast `variadic` to obtain a function pointer: `variadic as unsafe extern "C" fn(_, ...)` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:112:22 | LL |     println!("{:p}", &std::env::var::<String>); |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: cast `var` to obtain a function pointer: `var as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:115:32 | LL |     println!("{:p} {:p} {:p}", &nop, &foo, &bar); |                                ^^^^ help: cast `nop` to obtain a function pointer: `nop as fn()` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:115:38 | LL |     println!("{:p} {:p} {:p}", &nop, &foo, &bar); |                                      ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:115:44 | LL |     println!("{:p} {:p} {:p}", &nop, &foo, &bar); |                                            ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:130:41 | LL |         std::mem::transmute::<_, usize>(&foo); |                                         ^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:132:50 | LL |         std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); |                                                  ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:132:50 | LL |         std::mem::transmute::<_, (usize, usize)>((&foo, &bar)); |                                                  ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:142:15 | LL |     print_ptr(&bar); |               ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:144:24 | LL |     bound_by_ptr_trait(&bar); |                        ^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:146:30 | LL |     bound_by_ptr_trait_tuple((&foo, &bar)); |                              ^^^^^^^^^^^^ help: cast `bar` to obtain a function pointer: `bar as fn(_) -> _` warning: taking a reference to a function item does not give a function pointer --> $DIR/function-item-references.rs:146:30 | LL |     bound_by_ptr_trait_tuple((&foo, &bar)); |                              ^^^^^^^^^^^^ help: cast `foo` to obtain a function pointer: `foo as fn() -> _` warning: 28 warnings emitted </ins>