@@ -22,7 +22,7 @@ use trans::adt;
2222use trans:: attributes;
2323use trans:: base:: * ;
2424use trans:: build:: * ;
25- use trans:: callee;
25+ use trans:: callee:: { self , Callee } ;
2626use trans:: cleanup;
2727use trans:: cleanup:: CleanupMethods ;
2828use trans:: common:: * ;
@@ -45,6 +45,7 @@ use syntax::ast;
4545use syntax:: ptr:: P ;
4646use syntax:: parse:: token;
4747
48+ use rustc:: lint;
4849use rustc:: session:: Session ;
4950use syntax:: codemap:: Span ;
5051
@@ -125,29 +126,41 @@ pub fn check_intrinsics(ccx: &CrateContext) {
125126 transmute_restriction. substituted_to ) ;
126127 let from_type_size = machine:: llbitsize_of_real ( ccx, llfromtype) ;
127128 let to_type_size = machine:: llbitsize_of_real ( ccx, lltotype) ;
129+
130+ if let ty:: TyFnDef ( ..) = transmute_restriction. substituted_from . sty {
131+ if to_type_size == machine:: llbitsize_of_real ( ccx, ccx. int_type ( ) ) {
132+ // FIXME #19925 Remove this warning after a release cycle.
133+ lint:: raw_emit_lint ( & ccx. tcx ( ) . sess ,
134+ & ccx. tcx ( ) . sess . lint_store . borrow ( ) ,
135+ lint:: builtin:: TRANSMUTE_FROM_FN_ITEM_TYPES ,
136+ ( lint:: Warn , lint:: LintSource :: Default ) ,
137+ Some ( transmute_restriction. span ) ,
138+ & format ! ( "`{}` is now zero-sized and has to be cast \
139+ to a pointer before transmuting to `{}`",
140+ transmute_restriction. substituted_from,
141+ transmute_restriction. substituted_to) ) ;
142+ continue ;
143+ }
144+ }
128145 if from_type_size != to_type_size {
129146 last_failing_id = Some ( transmute_restriction. id ) ;
130147
131148 if transmute_restriction. original_from != transmute_restriction. substituted_from {
132149 span_transmute_size_error ( ccx. sess ( ) , transmute_restriction. span ,
133150 & format ! ( "transmute called with differently sized types: \
134- {} (could be {} bit{} ) to {} (could be {} bit{} )",
151+ {} (could be {} bits ) to {} (could be {} bits )",
135152 transmute_restriction. original_from,
136- from_type_size as usize ,
137- if from_type_size == 1 { "" } else { "s" } ,
153+ from_type_size,
138154 transmute_restriction. original_to,
139- to_type_size as usize ,
140- if to_type_size == 1 { "" } else { "s" } ) ) ;
155+ to_type_size) ) ;
141156 } else {
142157 span_transmute_size_error ( ccx. sess ( ) , transmute_restriction. span ,
143158 & format ! ( "transmute called with differently sized types: \
144- {} ({} bit{} ) to {} ({} bit{} )",
159+ {} ({} bits ) to {} ({} bits )",
145160 transmute_restriction. original_from,
146- from_type_size as usize ,
147- if from_type_size == 1 { "" } else { "s" } ,
161+ from_type_size,
148162 transmute_restriction. original_to,
149- to_type_size as usize ,
150- if to_type_size == 1 { "" } else { "s" } ) ) ;
163+ to_type_size) ) ;
151164 }
152165 }
153166 }
@@ -179,6 +192,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
179192 let foreign_item = tcx. map . expect_foreign_item ( node) ;
180193 let name = foreign_item. name . as_str ( ) ;
181194
195+ let call_debug_location = DebugLoc :: At ( call_info. id , call_info. span ) ;
196+
182197 // For `transmute` we can just trans the input expr directly into dest
183198 if name == "transmute" {
184199 let llret_ty = type_of:: type_of ( ccx, ret_ty. unwrap ( ) ) ;
@@ -194,6 +209,27 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
194209 let in_type_size = machine:: llbitsize_of_real ( ccx, llintype) ;
195210 let out_type_size = machine:: llbitsize_of_real ( ccx, llouttype) ;
196211
212+ if let ty:: TyFnDef ( def_id, substs, _) = in_type. sty {
213+ if out_type_size != 0 {
214+ // FIXME #19925 Remove this hack after a release cycle.
215+ let _ = unpack_datum ! ( bcx, expr:: trans( bcx, & arg_exprs[ 0 ] ) ) ;
216+ let llfn = Callee :: def ( ccx, def_id, substs, in_type) . reify ( ccx) . val ;
217+ let llfnty = val_ty ( llfn) ;
218+ let llresult = match dest {
219+ expr:: SaveIn ( d) => d,
220+ expr:: Ignore => alloc_ty ( bcx, out_type, "ret" )
221+ } ;
222+ Store ( bcx, llfn, PointerCast ( bcx, llresult, llfnty. ptr_to ( ) ) ) ;
223+ if dest == expr:: Ignore {
224+ bcx = glue:: drop_ty ( bcx, llresult, out_type,
225+ call_debug_location) ;
226+ }
227+ fcx. scopes . borrow_mut ( ) . last_mut ( ) . unwrap ( ) . drop_non_lifetime_clean ( ) ;
228+ fcx. pop_and_trans_custom_cleanup_scope ( bcx, cleanup_scope) ;
229+ return Result :: new ( bcx, llresult) ;
230+ }
231+ }
232+
197233 // This should be caught by the intrinsicck pass
198234 assert_eq ! ( in_type_size, out_type_size) ;
199235
@@ -311,8 +347,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
311347 }
312348 }
313349
314- let call_debug_location = DebugLoc :: At ( call_info. id , call_info. span ) ;
315-
316350 // For `try` we need some custom control flow
317351 if & name[ ..] == "try" {
318352 if let callee:: ArgExprs ( ref exprs) = args {
0 commit comments