@@ -210,7 +210,7 @@ let whitelisted_tapp e =
210210let no_return_type_lids = ref []
211211
212212let rec unit_to_void env e es extra =
213- let mk_expr env e = mk_expr env false e in
213+ let mk_expr env e = mk_expr env false false e in
214214 match es with
215215 | [ { node = EUnit ; _ } ] ->
216216 CStar. Call (mk_expr env e, [] @ extra)
@@ -313,13 +313,22 @@ and is_arith op w =
313313(* As an optimization, this function returns a boolean indicating whether the
314314 arithmetic expression was "atomic", i.e. something that certainly doesn't
315315 have extra bits beyond the intended width of the type. Globals, results of
316- function calls, anything not an arithmetic operation, really, is atomic. *)
316+ function calls, anything not an arithmetic operation, really, is atomic.
317+
318+ We now also return a boolean indicating whether this expression was widened
319+ (per the compilation strategy above).
320+ - In C, we rely on implicit narrowing conversions, and let the (wider)
321+ arithmetic expression be { assigned, returned, passed } at a narrow type.
322+ - In C++, initializer lists are intended to disallow this beahvior, so if the
323+ boolean is true, if we are in C++, and if we are under an initializer list
324+ (mostly, EBufCreateL and/or ECons a.k.a. initializer lists for arrays and
325+ structs), then we narrow-cast, relying on the third boolean. *)
317326and mk_arith env e =
318327 let mask_if is_atomic w e = if is_atomic then e else mask w e in
319328 match e.node with
320329 | EApp ({ node = EOp (op , w ); _ } , [ e1 ; e2 ]) when is_arith op w ->
321- let e1, a1 = mk_arith env e1 in
322- let e2, a2 = mk_arith env e2 in
330+ let e1, a1, w1 = mk_arith env e1 in
331+ let e2, a2, w2 = mk_arith env e2 in
323332 begin match op with
324333 | Add | AddW | Sub | SubW | Mult | MultW | BOr | BAnd | BXor | BNot | BShiftL ->
325334 CStar. Call (Op op, [ e1; e2 ])
@@ -329,27 +338,27 @@ and mk_arith env e =
329338 CStar. Call (Op op, [ mask_if a1 w e1; e2 ])
330339 | _ ->
331340 assert false
332- end , false
341+ end , false , w1 || w2
333342 | EConstant _ ->
334343 (* Constants are emitted with the U suffix which preserves the invariant
335344 that every subexpression operates over unsigned int until the final
336345 cast, or until a mask is needed to preserve semantics. *)
337- mk_expr env false e, true
346+ mk_expr env false false e, true , false (* C++: a constant that is wider than the intended type, but in an initializer list, is ok *)
338347 | _ ->
339348 (* Something else. Who knows? Maybe a function call, a field reference, a
340349 variable, a global... which will be upcast into `int`, which is *not*
341350 what we want! (See compilation strategy above.). We cast. *)
342351 if e.typ = TInt UInt16 || e.typ = TInt UInt8 then
343- CStar. Cast (mk_expr env false e, Int UInt32 ), true
352+ CStar. Cast (mk_expr env false false e, Int UInt32 ), true , true
344353 else
345- mk_expr env false e, true
354+ mk_expr env false false e, true , false
346355
347356and return_type_not_needed e =
348357 match e.node with
349358 | EQualified lid when List. mem lid ! no_return_type_lids -> true
350359 | _ -> false
351360
352- and mk_expr env in_stmt e =
361+ and mk_expr env in_stmt under_initializer_list e =
353362 (* Wrap in comment node if need be. *)
354363 let meta = match e.node with ELet (b , _ , _ ) -> b.meta @ e.meta | _ -> e.meta in
355364 begin match List. filter_map (function CommentBefore s -> Some s | _ -> None ) meta,
@@ -360,7 +369,7 @@ and mk_expr env in_stmt e =
360369 end @@
361370
362371 (* Actual translation. *)
363- let mk_expr env e = mk_expr env false e in
372+ let mk_expr env u e = mk_expr env false u e in
364373 match e.node with
365374 | EBound var ->
366375 CStar. Var (find env var)
@@ -387,7 +396,11 @@ and mk_expr env in_stmt e =
387396 unit_to_void env e0 (cgs @ cgs') (List. map (fun t -> CStar. Type (mk_type env t)) ts @ [ ret_t ])
388397
389398 | EApp ({ node = EOp (op , w ); _ } , [ _ ; _ ]) when is_arith op w ->
390- fst (mk_arith env e)
399+ let e', _, widened = mk_arith env e in
400+ if ! Options. cxx_compat && under_initializer_list && widened then
401+ Cast (e', mk_type env e.typ)
402+ else
403+ e'
391404
392405 | EApp (e , es ) ->
393406 (* Functions that only take a unit take no argument. *)
@@ -404,15 +417,15 @@ and mk_expr env in_stmt e =
404417 else
405418 call
406419 | EBufCreate (l , e1 , e2 ) ->
407- CStar. BufCreate (l, mk_expr env e1, mk_expr env e2)
420+ CStar. BufCreate (l, mk_expr env false e1, mk_expr env false e2)
408421 | EBufCreateL (l , es ) ->
409- CStar. BufCreateL (l, List. map (mk_expr env) es)
422+ CStar. BufCreateL (l, List. map (mk_expr env true ) es)
410423 | EBufRead (e1 , e2 ) ->
411- CStar. BufRead (mk_expr env e1, mk_expr env e2)
424+ CStar. BufRead (mk_expr env false e1, mk_expr env false e2)
412425 | EBufSub (e1 , e2 ) ->
413- CStar. BufSub (mk_expr env e1, mk_expr env e2)
426+ CStar. BufSub (mk_expr env false e1, mk_expr env false e2)
414427 | EBufDiff (e1 , e2 ) ->
415- CStar. Call (CStar. Op K. Sub , [mk_expr env e1; mk_expr env e2])
428+ CStar. Call (CStar. Op K. Sub , [mk_expr env false e1; mk_expr env false e2])
416429 | EOp (o , _ ) ->
417430 CStar. Op o
418431 | EPolyComp (c , _ ) ->
@@ -421,7 +434,7 @@ and mk_expr env in_stmt e =
421434 scalar type in C that is supported by C's equality comparison. *)
422435 CStar. Op (K. op_of_poly_comp c)
423436 | ECast (e , t ) ->
424- CStar. Cast (mk_expr env e, mk_type env t)
437+ CStar. Cast (mk_expr env false e, mk_type env t)
425438 | EAbort (t , s ) ->
426439 let t = match t with Some t -> t | None -> e.typ in
427440 CStar. EAbort (mk_type env t, Option. value ~default: " " s)
@@ -436,13 +449,13 @@ and mk_expr env in_stmt e =
436449 | EFlat fields ->
437450 let name = match e.typ with TQualified lid -> Some lid | _ -> None in
438451 CStar. Struct (name, List. map (fun (name , expr ) ->
439- name, mk_expr env expr
452+ name, mk_expr env true expr
440453 ) fields)
441454 | EField (expr , field ) ->
442- CStar. Field (mk_expr env expr, field)
455+ CStar. Field (mk_expr env false expr, field)
443456
444457 | EAddrOf e ->
445- CStar. AddrOf (mk_expr env e)
458+ CStar. AddrOf (mk_expr env false e)
446459
447460 | EBufNull ->
448461 CStar. BufNull
@@ -459,9 +472,9 @@ and mk_ignored_stmt env e =
459472 let s =
460473 match e.typ with
461474 | TUnit ->
462- CStar. Ignore (mk_expr env true e)
475+ CStar. Ignore (mk_expr env true false e)
463476 | _ ->
464- CStar. Ignore (CStar. Cast (mk_expr env true e, CStar. Void ))
477+ CStar. Ignore (CStar. Cast (mk_expr env true false e, CStar. Void ))
465478 in
466479 env, [s]
467480
@@ -486,12 +499,12 @@ and mk_stmts env e ret_type =
486499 match e.node with
487500 | ELet (b , e1 , e2 ) ->
488501 let env, binder = mk_and_push_binder env b Local (Some e1) [ e2 ]
489- and e1 = mk_expr env false e1 in
502+ and e1 = mk_expr env false false e1 in
490503 let acc = CStar. Decl (binder, e1) :: comment (e.meta @ b.meta) @ acc in
491504 collect (env, acc) return_pos e2
492505
493506 | EWhile (e1 , e2 ) ->
494- let e' = CStar. While (mk_expr env false e1, mk_block env Not e2) in
507+ let e' = CStar. While (mk_expr env false false e1, mk_block env Not e2) in
495508 env, maybe_return (e' :: comment e.meta @ acc)
496509
497510 | EFor (binder,
@@ -545,7 +558,7 @@ and mk_stmts env e ret_type =
545558 let is_solo_assignment = binder.node.meta = Some MetaSequence in
546559 (* TODO: shouldn't e1 be added here? *)
547560 let env', binder = mk_and_push_binder env binder Local (Some e1) [ e2; e3; e4 ] in
548- let e2 = mk_expr env' false e2 in
561+ let e2 = mk_expr env' false false e2 in
549562 let e3 = KList. last (mk_block env' Not e3) in
550563 let e4 = mk_block env' Not e4 in
551564 let e' =
@@ -557,7 +570,7 @@ and mk_stmts env e ret_type =
557570 in
558571 CStar. For (e1, e2, e3, e4)
559572 else
560- let e1 = mk_expr env false e1 in
573+ let e1 = mk_expr env false false e1 in
561574 CStar. For (`Decl (binder, e1), e2, e3, e4)
562575 in
563576 env', maybe_return (e' :: comment e.meta @ acc)
@@ -586,7 +599,7 @@ and mk_stmts env e ret_type =
586599 if not ! Options. no_return_else || return_pos = Not then
587600 (* No optimization *)
588601 let e' = CStar. IfThenElse (false ,
589- mk_expr env false e1,
602+ mk_expr env false false e1,
590603 mk_block env return_pos e2,
591604 mk_block env return_pos e3
592605 ) in
@@ -595,7 +608,7 @@ and mk_stmts env e ret_type =
595608 (* no_return_else && return_pos <> Not,
596609 * i.e. optimization enabled; we are in return position *)
597610 let e' = CStar. IfThenElse (false ,
598- mk_expr env false e1,
611+ mk_expr env false false e1,
599612 mk_block env Must e2,
600613 []
601614 ) in
@@ -613,39 +626,39 @@ and mk_stmts env e ret_type =
613626 assert false
614627
615628 | EAssign (e1 , e2 ) ->
616- let e' = CStar. Assign (mk_expr env false e1, mk_type env e1.typ, mk_expr env false e2) in
629+ let e' = CStar. Assign (mk_expr env false false e1, mk_type env e1.typ, mk_expr env false false e2) in
617630 env, maybe_return (e' :: comment e.meta @ acc)
618631
619632 | EBufBlit (e1 , e2 , e3 , e4 , e5 ) ->
620633 let e' = CStar. BufBlit (
621634 mk_type env (assert_tbuf_or_tarray e1.typ),
622- mk_expr env false e1,
623- mk_expr env false e2,
624- mk_expr env false e3,
625- mk_expr env false e4,
626- mk_expr env false e5
635+ mk_expr env false false e1,
636+ mk_expr env false false e2,
637+ mk_expr env false false e3,
638+ mk_expr env false false e4,
639+ mk_expr env false false e5
627640 ) in
628641 env, maybe_return (e' :: comment e.meta @ acc)
629642
630643 | EBufWrite (e1 , e2 , e3 ) ->
631644 let e' = CStar. BufWrite (
632- mk_expr env false e1,
633- mk_expr env false e2,
634- mk_expr env false e3
645+ mk_expr env false false e1,
646+ mk_expr env false false e2,
647+ mk_expr env false false e3
635648 ) in
636649 env, maybe_return (e' :: comment e.meta @ acc)
637650
638651 | EBufFill (e1 , e2 , e3 ) ->
639652 let e' = CStar. BufFill (
640653 mk_type env (assert_tbuf e1.typ),
641- mk_expr env false e1,
642- mk_expr env false e2,
643- mk_expr env false e3
654+ mk_expr env false false e1,
655+ mk_expr env false false e2,
656+ mk_expr env false false e3
644657 ) in
645658 env, maybe_return (e' :: comment e.meta @ acc)
646659
647660 | EBufFree e ->
648- let e' = CStar. BufFree (mk_type env (assert_tbuf e.typ), mk_expr env false e) in
661+ let e' = CStar. BufFree (mk_type env (assert_tbuf e.typ), mk_expr env false false e) in
649662 env, maybe_return (e' :: comment e.meta @ acc)
650663
651664 | EMatch _ ->
@@ -663,7 +676,7 @@ and mk_stmts env e ret_type =
663676 | [] -> None
664677 | _ -> failwith " impossible"
665678 in
666- env, CStar. Switch (mk_expr env false e,
679+ env, CStar. Switch (mk_expr env false false e,
667680 List. map (fun (lid , e ) ->
668681 (match lid with
669682 | SConstant k -> `Int k
@@ -699,7 +712,7 @@ and mk_stmts env e ret_type =
699712 if is_readonly_c_expression e then
700713 env, comment e.meta @ acc
701714 else
702- let e' = CStar. Ignore (mk_expr env true e) in
715+ let e' = CStar. Ignore (mk_expr env true false e) in
703716 env, e' :: comment e.meta @ acc
704717
705718 and mk_block env return_pos e =
@@ -716,7 +729,7 @@ and mk_stmts env e ret_type =
716729 let env, s = mk_ignored_stmt env e in
717730 env, maybe_return_nothing (s @ acc)
718731 else
719- env, CStar. Return (Some (mk_expr env false e)) :: acc
732+ env, CStar. Return (Some (mk_expr env false false e)) :: acc
720733
721734 and mk_ifdef env return_pos acc e1 e2 e3 =
722735 try
@@ -924,7 +937,7 @@ and mk_declaration m env d: (CStar.decl * _) option =
924937 macro,
925938 flags,
926939 mk_type env t,
927- mk_expr env false body), [] )
940+ mk_expr env false false body), [] )
928941
929942 | DExternal (cc , flags , _ , n , name , t , pp ) ->
930943 if LidSet. mem name env.ifdefs || n > 0 then
0 commit comments