@@ -23,12 +23,15 @@ use trans::type_of;
2323use middle:: subst:: Substs ;
2424use middle:: ty:: { self , Ty } ;
2525use util:: ppaux:: { Repr , ty_to_string} ;
26+ use util:: nodemap:: NodeMap ;
2627
2728use std:: iter:: repeat;
2829use libc:: c_uint;
2930use syntax:: { ast, ast_util} ;
3031use syntax:: ptr:: P ;
3132
33+ type FnArgMap < ' a > = Option < & ' a NodeMap < ValueRef > > ;
34+
3235pub fn const_lit ( cx : & CrateContext , e : & ast:: Expr , lit : & ast:: Lit )
3336 -> ValueRef {
3437 let _icx = push_ctxt ( "trans_lit" ) ;
@@ -157,6 +160,29 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
157160 }
158161}
159162
163+ fn const_fn_call < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
164+ node : ExprOrMethodCall ,
165+ def_id : ast:: DefId ,
166+ arg_vals : & [ ValueRef ] ,
167+ param_substs : & ' tcx Substs < ' tcx > ) -> ValueRef {
168+ let fn_like = const_eval:: lookup_const_fn_by_id ( ccx. tcx ( ) , def_id) ;
169+ let fn_like = fn_like. expect ( "lookup_const_fn_by_id failed in const_fn_call" ) ;
170+
171+ let args = & fn_like. decl ( ) . inputs ;
172+ assert_eq ! ( args. len( ) , arg_vals. len( ) ) ;
173+
174+ let arg_ids = args. iter ( ) . map ( |arg| arg. pat . id ) ;
175+ let fn_args = arg_ids. zip ( arg_vals. iter ( ) . cloned ( ) ) . collect ( ) ;
176+
177+ let substs = ccx. tcx ( ) . mk_substs ( node_id_substs ( ccx, node, param_substs) ) ;
178+ match fn_like. body ( ) . expr {
179+ Some ( ref expr) => {
180+ const_expr ( ccx, & * * expr, substs, Some ( & fn_args) ) . 0
181+ }
182+ None => C_nil ( ccx)
183+ }
184+ }
185+
160186pub fn get_const_expr < ' a , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > ,
161187 def_id : ast:: DefId ,
162188 ref_expr : & ast:: Expr )
@@ -217,9 +243,9 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
217243 // references, even when only the latter are correct.
218244 let ty = monomorphize:: apply_param_substs ( ccx. tcx ( ) , param_substs,
219245 & ty:: expr_ty ( ccx. tcx ( ) , expr) ) ;
220- const_expr_unadjusted ( ccx, expr, ty, param_substs)
246+ const_expr_unadjusted ( ccx, expr, ty, param_substs, None )
221247 } else {
222- const_expr ( ccx, expr, param_substs) . 0
248+ const_expr ( ccx, expr, param_substs, None ) . 0
223249 } ;
224250
225251 // boolean SSA values are i1, but they have to be stored in i8 slots,
@@ -239,11 +265,12 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
239265
240266pub fn const_expr < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
241267 e : & ast:: Expr ,
242- param_substs : & ' tcx Substs < ' tcx > )
268+ param_substs : & ' tcx Substs < ' tcx > ,
269+ fn_args : FnArgMap )
243270 -> ( ValueRef , Ty < ' tcx > ) {
244271 let ety = monomorphize:: apply_param_substs ( cx. tcx ( ) , param_substs,
245272 & ty:: expr_ty ( cx. tcx ( ) , e) ) ;
246- let llconst = const_expr_unadjusted ( cx, e, ety, param_substs) ;
273+ let llconst = const_expr_unadjusted ( cx, e, ety, param_substs, fn_args ) ;
247274 let mut llconst = llconst;
248275 let mut ety_adjusted = monomorphize:: apply_param_substs ( cx. tcx ( ) , param_substs,
249276 & ty:: expr_ty_adjusted ( cx. tcx ( ) , e) ) ;
@@ -352,10 +379,12 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
352379fn const_expr_unadjusted < ' a , ' tcx > ( cx : & CrateContext < ' a , ' tcx > ,
353380 e : & ast:: Expr ,
354381 ety : Ty < ' tcx > ,
355- param_substs : & ' tcx Substs < ' tcx > ) -> ValueRef {
356- let map_list = |exprs : & [ P < ast:: Expr > ] | {
357- exprs. iter ( ) . map ( |e| const_expr ( cx, & * * e, param_substs) . 0 )
358- . fold ( Vec :: new ( ) , |mut l, val| { l. push ( val) ; l } )
382+ param_substs : & ' tcx Substs < ' tcx > ,
383+ fn_args : FnArgMap )
384+ -> ValueRef {
385+ let map_list = |exprs : & [ P < ast:: Expr > ] | -> Vec < ValueRef > {
386+ exprs. iter ( ) . map ( |e| const_expr ( cx, & * * e, param_substs, fn_args) . 0 )
387+ . collect ( )
359388 } ;
360389 unsafe {
361390 let _icx = push_ctxt ( "const_expr" ) ;
@@ -366,7 +395,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
366395 ast:: ExprBinary ( b, ref e1, ref e2) => {
367396 /* Neither type is bottom, and we expect them to be unified
368397 * already, so the following is safe. */
369- let ( te1, ty) = const_expr ( cx, & * * e1, param_substs) ;
398+ let ( te1, ty) = const_expr ( cx, & * * e1, param_substs, fn_args ) ;
370399 let is_simd = ty:: type_is_simd ( cx. tcx ( ) , ty) ;
371400 let intype = if is_simd {
372401 ty:: simd_type ( cx. tcx ( ) , ty)
@@ -376,7 +405,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
376405 let is_float = ty:: type_is_fp ( intype) ;
377406 let signed = ty:: type_is_signed ( intype) ;
378407
379- let ( te2, _) = const_expr ( cx, & * * e2, param_substs) ;
408+ let ( te2, _) = const_expr ( cx, & * * e2, param_substs, fn_args ) ;
380409 let te2 = base:: cast_shift_const_rhs ( b, te1, te2) ;
381410
382411 match b. node {
@@ -431,7 +460,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
431460 }
432461 } ,
433462 ast:: ExprUnary ( u, ref e) => {
434- let ( te, ty) = const_expr ( cx, & * * e, param_substs) ;
463+ let ( te, ty) = const_expr ( cx, & * * e, param_substs, fn_args ) ;
435464 let is_float = ty:: type_is_fp ( ty) ;
436465 match u {
437466 ast:: UnUniq | ast:: UnDeref => {
@@ -445,23 +474,23 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
445474 }
446475 }
447476 ast:: ExprField ( ref base, field) => {
448- let ( bv, bt) = const_expr ( cx, & * * base, param_substs) ;
477+ let ( bv, bt) = const_expr ( cx, & * * base, param_substs, fn_args ) ;
449478 let brepr = adt:: represent_type ( cx, bt) ;
450479 expr:: with_field_tys ( cx. tcx ( ) , bt, None , |discr, field_tys| {
451480 let ix = ty:: field_idx_strict ( cx. tcx ( ) , field. node . name , field_tys) ;
452481 adt:: const_get_field ( cx, & * brepr, bv, discr, ix)
453482 } )
454483 }
455484 ast:: ExprTupField ( ref base, idx) => {
456- let ( bv, bt) = const_expr ( cx, & * * base, param_substs) ;
485+ let ( bv, bt) = const_expr ( cx, & * * base, param_substs, fn_args ) ;
457486 let brepr = adt:: represent_type ( cx, bt) ;
458487 expr:: with_field_tys ( cx. tcx ( ) , bt, None , |discr, _| {
459488 adt:: const_get_field ( cx, & * brepr, bv, discr, idx. node )
460489 } )
461490 }
462491
463492 ast:: ExprIndex ( ref base, ref index) => {
464- let ( bv, bt) = const_expr ( cx, & * * base, param_substs) ;
493+ let ( bv, bt) = const_expr ( cx, & * * base, param_substs, fn_args ) ;
465494 let iv = match const_eval:: eval_const_expr_partial ( cx. tcx ( ) , & * * index, None ) {
466495 Ok ( const_eval:: const_int( i) ) => i as u64 ,
467496 Ok ( const_eval:: const_uint( u) ) => u,
@@ -512,7 +541,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
512541 }
513542 ast:: ExprCast ( ref base, _) => {
514543 let llty = type_of:: type_of ( cx, ety) ;
515- let ( v, basety) = const_expr ( cx, & * * base, param_substs) ;
544+ let ( v, basety) = const_expr ( cx, & * * base, param_substs, fn_args ) ;
516545 if expr:: cast_is_noop ( basety, ety) {
517546 return v;
518547 }
@@ -590,12 +619,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
590619 } else {
591620 // If this isn't the address of a static, then keep going through
592621 // normal constant evaluation.
593- let ( v, _) = const_expr ( cx, & * * sub, param_substs) ;
622+ let ( v, _) = const_expr ( cx, & * * sub, param_substs, fn_args ) ;
594623 addr_of ( cx, v, "ref" , e. id )
595624 }
596625 }
597626 ast:: ExprAddrOf ( ast:: MutMutable , ref sub) => {
598- let ( v, _) = const_expr ( cx, & * * sub, param_substs) ;
627+ let ( v, _) = const_expr ( cx, & * * sub, param_substs, fn_args ) ;
599628 addr_of_mut ( cx, v, "ref_mut_slice" , e. id )
600629 }
601630 ast:: ExprTup ( ref es) => {
@@ -607,15 +636,15 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
607636 let repr = adt:: represent_type ( cx, ety) ;
608637
609638 let base_val = match * base_opt {
610- Some ( ref base) => Some ( const_expr ( cx, & * * base, param_substs) ) ,
639+ Some ( ref base) => Some ( const_expr ( cx, & * * base, param_substs, fn_args ) ) ,
611640 None => None
612641 } ;
613642
614643 expr:: with_field_tys ( cx. tcx ( ) , ety, Some ( e. id ) , |discr, field_tys| {
615644 let cs = field_tys. iter ( ) . enumerate ( )
616645 . map ( |( ix, & field_ty) | {
617646 match fs. iter ( ) . find ( |f| field_ty. name == f. ident . node . name ) {
618- Some ( ref f) => const_expr ( cx, & * f. expr , param_substs) . 0 ,
647+ Some ( ref f) => const_expr ( cx, & * f. expr , param_substs, fn_args ) . 0 ,
619648 None => {
620649 match base_val {
621650 Some ( ( bv, _) ) => {
@@ -640,7 +669,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
640669 ast:: ExprVec ( ref es) => {
641670 let unit_ty = ty:: sequence_element_type ( cx. tcx ( ) , ety) ;
642671 let llunitty = type_of:: type_of ( cx, unit_ty) ;
643- let vs = es. iter ( ) . map ( |e| const_expr ( cx, & * * e, param_substs) . 0 )
672+ let vs = es. iter ( ) . map ( |e| const_expr ( cx, & * * e, param_substs, fn_args ) . 0 )
644673 . collect :: < Vec < _ > > ( ) ;
645674 // If the vector contains enums, an LLVM array won't work.
646675 if vs. iter ( ) . any ( |vi| val_ty ( * vi) != llunitty) {
@@ -657,7 +686,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
657686 Ok ( const_eval:: const_uint( i) ) => i as uint ,
658687 _ => cx. sess ( ) . span_bug ( count. span , "count must be integral const expression." )
659688 } ;
660- let unit_val = const_expr ( cx, & * * elem, param_substs) . 0 ;
689+ let unit_val = const_expr ( cx, & * * elem, param_substs, fn_args ) . 0 ;
661690 let vs: Vec < _ > = repeat ( unit_val) . take ( n) . collect ( ) ;
662691 if val_ty ( unit_val) != llunitty {
663692 C_struct ( cx, & vs[ ..] , false )
@@ -668,6 +697,13 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
668697 ast:: ExprPath ( ..) => {
669698 let def = cx. tcx ( ) . def_map . borrow ( ) [ e. id ] . full_def ( ) ;
670699 match def {
700+ def:: DefLocal ( id) => {
701+ if let Some ( val) = fn_args. and_then ( |args| args. get ( & id) . cloned ( ) ) {
702+ val
703+ } else {
704+ cx. sess ( ) . span_bug ( e. span , "const fn argument not found" )
705+ }
706+ }
671707 def:: DefFn ( ..) | def:: DefMethod ( ..) => {
672708 expr:: trans_def_fn_unadjusted ( cx, e, def, param_substs) . val
673709 }
@@ -703,18 +739,32 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
703739 }
704740 }
705741 ast:: ExprCall ( ref callee, ref args) => {
706- let opt_def = cx. tcx ( ) . def_map . borrow ( ) . get ( & callee. id ) . map ( |d| d. full_def ( ) ) ;
707- let arg_vals = map_list ( & args[ ..] ) ;
708- match opt_def {
709- Some ( def:: DefStruct ( _) ) => {
742+ let mut callee = & * * callee;
743+ loop {
744+ callee = match callee. node {
745+ ast:: ExprParen ( ref inner) => & * * inner,
746+ ast:: ExprBlock ( ref block) => match block. expr {
747+ Some ( ref tail) => & * * tail,
748+ None => break
749+ } ,
750+ _ => break
751+ } ;
752+ }
753+ let def = cx. tcx ( ) . def_map . borrow ( ) [ callee. id ] . full_def ( ) ;
754+ let arg_vals = map_list ( args) ;
755+ match def {
756+ def:: DefFn ( did, _) | def:: DefMethod ( did, _) => {
757+ const_fn_call ( cx, ExprId ( callee. id ) , did, & arg_vals, param_substs)
758+ }
759+ def:: DefStruct ( _) => {
710760 if ty:: type_is_simd ( cx. tcx ( ) , ety) {
711761 C_vector ( & arg_vals[ ..] )
712762 } else {
713763 let repr = adt:: represent_type ( cx, ety) ;
714764 adt:: trans_const ( cx, & * repr, 0 , & arg_vals[ ..] )
715765 }
716766 }
717- Some ( def:: DefVariant ( enum_did, variant_did, _) ) => {
767+ def:: DefVariant ( enum_did, variant_did, _) => {
718768 let repr = adt:: represent_type ( cx, ety) ;
719769 let vinfo = ty:: enum_variant_with_id ( cx. tcx ( ) ,
720770 enum_did,
@@ -724,13 +774,23 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
724774 vinfo. disr_val ,
725775 & arg_vals[ ..] )
726776 }
727- _ => cx. sess ( ) . span_bug ( e. span , "expected a struct or variant def" )
777+ _ => cx. sess ( ) . span_bug ( e. span , "expected a struct, variant, or const fn def" )
728778 }
729779 }
730- ast:: ExprParen ( ref e) => const_expr ( cx, & * * e, param_substs) . 0 ,
780+ ast:: ExprMethodCall ( _, _, ref args) => {
781+ let arg_vals = map_list ( args) ;
782+ let method_call = ty:: MethodCall :: expr ( e. id ) ;
783+ let method_did = match cx. tcx ( ) . method_map . borrow ( ) [ method_call] . origin {
784+ ty:: MethodStatic ( did) => did,
785+ _ => cx. sess ( ) . span_bug ( e. span , "expected a const method def" )
786+ } ;
787+ const_fn_call ( cx, MethodCallKey ( method_call) ,
788+ method_did, & arg_vals, param_substs)
789+ }
790+ ast:: ExprParen ( ref e) => const_expr ( cx, & * * e, param_substs, fn_args) . 0 ,
731791 ast:: ExprBlock ( ref block) => {
732792 match block. expr {
733- Some ( ref expr) => const_expr ( cx, & * * expr, param_substs) . 0 ,
793+ Some ( ref expr) => const_expr ( cx, & * * expr, param_substs, fn_args ) . 0 ,
734794 None => C_nil ( cx)
735795 }
736796 }
0 commit comments