@@ -107,6 +107,13 @@ let lambda_needs_capture
107107 let rec collect_from_expr (refs , decls ) e =
108108 match e with
109109 | CPPvar id -> (IdSet. add id refs, decls)
110+ | CPPderef e -> collect_from_expr (refs, decls) e
111+ | CPPraw s
112+ when String. length s > 3
113+ && String. sub s 0 2 = " (*"
114+ && s.[String. length s - 1 ] = ')' ->
115+ let name = String. sub s 2 (String. length s - 3 ) in
116+ (try (IdSet. add (Id. of_string name) refs, decls) with _ -> (refs, decls))
110117 | CPPthis | CPPshared_from_this _ ->
111118 uses_this := true ;
112119 (refs, decls)
@@ -802,7 +809,9 @@ and pp_cpp_expr env args t =
802809 | None -> false )
803810 | None -> false ->
804811 let method_name = Id. of_string (Common. pp_global_name Term x) in
805- str " [](const auto &_x) { return _x->"
812+ let accessor = if method_receiver_is_ptr x then " ->" else " ." in
813+ str " [](const auto &_x) { return _x"
814+ ++ str accessor
806815 ++ Id. print method_name
807816 ++ str " (); }"
808817 | CPPglob (x , tys , _ ) ->
@@ -979,8 +988,22 @@ and pp_cpp_expr env args t =
979988 ( str " template " ,
980989 str " <" ++ pp_list (pp_cpp_type false [] ) filtered_tys ++ str " >" )
981990 in
982- obj_s
983- ++ str " ->"
991+ (* Coinductive types are shared_ptr → use arrow.
992+ Value types → use dot. unique_ptr pattern match fields
993+ are auto-dereferenced at binding time, so variables holding
994+ inductives are always value types (T or const T&). *)
995+ let use_arrow = method_receiver_is_ptr n in
996+ let accessor = if use_arrow then " ->" else " ." in
997+ (* Parenthesize deref expressions for correct precedence. *)
998+ let obj_pp =
999+ if not use_arrow then
1000+ match this_arg with
1001+ | CPPderef _ -> str " (" ++ obj_s ++ str " )"
1002+ | _ -> obj_s
1003+ else obj_s
1004+ in
1005+ obj_pp
1006+ ++ str accessor
9841007 ++ template_kw
9851008 ++ Id. print method_name
9861009 ++ ty_args_s
@@ -997,7 +1020,7 @@ and pp_cpp_expr env args t =
9971020 | CPPfun_call (f , ts ) ->
9981021 let args_s = pp_list (pp_cpp_expr env args) (List. rev ts) in
9991022 pp_cpp_expr env args f ++ str " (" ++ args_s ++ str " )"
1000- | CPPderef e -> str " *" ++ pp_cpp_expr env args e
1023+ | CPPderef e -> str " *( " ++ pp_cpp_expr env args e ++ str " ) "
10011024 | CPPmove e ->
10021025 require_header " utility" ;
10031026 str (sn () ).move ++ str " (" ++ pp_cpp_expr env args e ++ str " )"
@@ -1010,6 +1033,49 @@ and pp_cpp_expr env args t =
10101033 ++ str " )"
10111034 | CPPlambda (params , ret_ty , body , capture_by_value ) ->
10121035 let needs_capture, uses_this = lambda_needs_capture params body in
1036+ let body_derefs_var =
1037+ let found = ref false in
1038+ let rec scan_expr = function
1039+ | CPPderef (CPPvar id ) when String. equal (Id. to_string id) " _self" ->
1040+ ()
1041+ | CPPderef _ -> found := true
1042+ | e ->
1043+ iter_expr_children
1044+ ~on_expr: scan_expr
1045+ ~on_stmts: (List. iter scan_stmt)
1046+ e
1047+ and scan_stmt s =
1048+ iter_stmt_children
1049+ ~on_expr: scan_expr
1050+ ~on_stmts: (List. iter scan_stmt)
1051+ s
1052+ in
1053+ List. iter scan_stmt body;
1054+ ! found
1055+ in
1056+ let rec type_contains_unique_ptr = function
1057+ | Tunique_ptr _ -> true
1058+ | Tshared_ptr t | Tref t | Tptr t | Tmod (_ , t ) -> type_contains_unique_ptr t
1059+ | Tglob (_, ts, _) | Tid (_, ts) | Tid_external (_, ts)
1060+ | Tvariant ts | Tnamespace (_ , Tglob (_ , ts , _ )) ->
1061+ List. exists type_contains_unique_ptr ts
1062+ | Tfun (dom , cod ) ->
1063+ List. exists type_contains_unique_ptr dom || type_contains_unique_ptr cod
1064+ | Tnamespace (_ , t ) | Tqualified (t , _ ) -> type_contains_unique_ptr t
1065+ | _ -> false
1066+ in
1067+ let capture_by_value =
1068+ capture_by_value
1069+ && not body_derefs_var
1070+ && not
1071+ ( List. exists
1072+ (fun (ty , _ ) -> type_contains_unique_ptr ty)
1073+ params
1074+ ||
1075+ match ret_ty with
1076+ | Some ty -> type_contains_unique_ptr ty
1077+ | None -> false )
1078+ in
10131079 let capture_str =
10141080 if not needs_capture then
10151081 str " []("
@@ -1114,8 +1180,17 @@ and pp_cpp_expr env args t =
11141180 | _ -> str " <" ++ pp_list (pp_cpp_type false [] ) tys ++ str " >"
11151181 in
11161182 Id. print id ++ templates ++ str " {" ++ es_s ++ str " }"
1117- | CPPget (e , id ) -> pp_cpp_expr env args e ++ str " ." ++ Id. print id
1118- | CPPget ' (e , id ) -> pp_cpp_expr env args e ++ str " ->" ++ pp_global Type id
1183+ | CPPget (e , id ) ->
1184+ ( match e with
1185+ | CPPderef _ | CPPraw _ ->
1186+ str " (" ++ pp_cpp_expr env args e ++ str " )." ++ Id. print id
1187+ | _ -> pp_cpp_expr env args e ++ str " ." ++ Id. print id )
1188+ | CPPget ' (e , id ) ->
1189+ (* Record field access: use "." since records are value types. *)
1190+ ( match e with
1191+ | CPPderef _ | CPPraw _ ->
1192+ str " (" ++ pp_cpp_expr env args e ++ str " )." ++ pp_global Type id
1193+ | _ -> pp_cpp_expr env args e ++ str " ." ++ pp_global Type id )
11191194 | CPPstring s -> str (" \" " ^ Pstring. to_string s ^ " \" " )
11201195 | CPPparray (elems , _ ) ->
11211196 str " {" ++ pp_list (pp_cpp_expr env args) (Array. to_list elems) ++ str " }"
@@ -1205,6 +1280,10 @@ and pp_cpp_expr env args t =
12051280 ( match e with
12061281 | CPPmove inner ->
12071282 str (sn () ).move ++ str " (" ++ pp_cpp_expr env args inner ++ str " ." ++ Id. print id ++ str " )"
1283+ | CPPderef _ ->
1284+ str " (" ++ pp_cpp_expr env args e ++ str " )." ++ Id. print id
1285+ | CPPraw s when String. length s > 0 && s.[0 ] = '*' ->
1286+ str " (" ++ pp_cpp_expr env args e ++ str " )." ++ Id. print id
12081287 | _ ->
12091288 pp_cpp_expr env args e ++ str " ." ++ Id. print id )
12101289 | CPParrow (e , id ) ->
@@ -1240,7 +1319,12 @@ and pp_cpp_expr env args t =
12401319 let full_name = capitalize_enum_qualified (str_global Type ind) ind in
12411320 str full_name ++ str " ::" ++ Id. print ctor
12421321 (* Low-level constructs for reuse optimization *)
1243- | CPPraw code -> str code
1322+ | CPPraw code ->
1323+ str
1324+ (Str. global_replace
1325+ (Str. regexp_string " *(this)." )
1326+ " (*(this))."
1327+ code)
12441328 | CPPbinop (op , lhs , rhs ) ->
12451329 (* Parenthesize && subexpressions inside || to avoid
12461330 -Wlogical-op-parentheses warnings. *)
@@ -1281,11 +1365,18 @@ and pp_cpp_stmt env args = function
12811365 ++ str msg
12821366 ++ str " \" );"
12831367 | Sreturn (Some e ) ->
1284- (* Strip std::move from return statements — C++ applies implicit move
1285- on local variables in return statements. Explicit std::move prevents
1286- NRVO (Named Return Value Optimization) and triggers
1287- -Wpessimizing-move / -Wredundant-move warnings. *)
1288- let e = match e with CPPmove inner -> inner | _ -> e in
1368+ (* Strip std::move from return statements when the inner expression is a
1369+ plain variable — C++ applies implicit move on local variables in return
1370+ statements. Explicit std::move prevents NRVO and triggers
1371+ -Wpessimizing-move / -Wredundant-move.
1372+ Keep std::move for non-variable expressions like *_head (dereference of
1373+ shared_ptr) where explicit move is required. *)
1374+ let e = match e with
1375+ | CPPmove (CPPvar _ as inner ) -> inner
1376+ | CPPmove ((CPPfun_call _ | CPPmethod_call _ | CPPstruct _ | CPPstructmk _
1377+ | CPPstruct_id _ ) as inner ) -> inner
1378+ | _ -> e
1379+ in
12891380 str " return " ++ pp_cpp_expr env args e ++ str " ;"
12901381 | Sdecl (id , ty ) ->
12911382 pp_cpp_type false [] ty ++ str " " ++ Id. print id ++ str " ;"
@@ -1546,38 +1637,52 @@ and pp_cpp_stmt env args = function
15461637 | [] ->
15471638 ( match br.smb_var with
15481639 | Some var_id ->
1549- str " const auto& " ++ Id. print var_id
1550- ++ str " = " ++ str (sn () ).get ++ str " <"
1551- ++ pp_cpp_type false [] br.smb_ctor_type ++ str " >("
1552- ++ scrut_var_pp ++ str " );"
1640+ if br.smb_is_owned then
1641+ str " auto " ++ Id. print var_id
1642+ ++ str " = std::move(" ++ str (sn () ).get ++ str " <"
1643+ ++ pp_cpp_type false [] br.smb_ctor_type ++ str " >("
1644+ ++ scrut_var_pp ++ str " ));"
1645+ else
1646+ str " const auto& " ++ Id. print var_id
1647+ ++ str " = " ++ str (sn () ).get ++ str " <"
1648+ ++ pp_cpp_type false [] br.smb_ctor_type ++ str " >("
1649+ ++ scrut_var_pp ++ str " );"
15531650 | None -> mt () )
15541651 in
1555- (* Extract the scrutinee object expression from [CPPmethod_call(obj, "v", [])].
1556- Bind it with [auto&&] to extend any temporary's lifetime, then
1557- reconstruct the variant accessor as [_svN->v()].
1558- Falls back to the raw scrutinee expression when the pattern doesn't match. *)
1559- let first_scrut =
1652+ (* Extract the scrutinee object expression from the variant accessor.
1653+ Handles both [CPPmethod_call(obj, "v", [])] (pointer: [obj->v()])
1654+ and [CPPfun_call(CPPmember(obj, "v"), [])] (value: [obj.v()]).
1655+ Bind temporaries with [auto&&] to extend lifetime, then reconstruct
1656+ the accessor. *)
1657+ let first_br =
15601658 match branches with
1561- | br :: _ -> br.smb_scrutinee
1659+ | br :: _ -> br
15621660 | [] -> CErrors. anomaly (Pp. str " Smatch with empty branch list" )
15631661 in
1662+ let first_scrut = first_br.smb_scrutinee in
1663+ let is_value_type = first_br.smb_is_value_type in
15641664 let scrut_obj_opt =
15651665 match first_scrut with
15661666 | CPPmethod_call (obj , v_id , [] ) when Id. to_string v_id = " v" ->
15671667 Some obj
1668+ | CPPfun_call (CPPmember (obj , v_id ), [] ) when Id. to_string v_id = " v" ->
1669+ Some obj
15681670 | _ -> None
15691671 in
1672+ let v_access name =
1673+ if is_value_type then name ^ " .v()" else name ^ " ->v()"
1674+ in
15701675 let scrut_binding_pp, scrut_var_pp, scrut_obj_pp =
15711676 match scrut_obj_opt with
15721677 | Some (CPPvar id ) ->
15731678 let name = Id. to_string id in
1574- (mt () , str (name ^ " ->v() " ), str name)
1679+ (mt () , str (v_access name ), str name)
15751680 | Some CPPthis ->
15761681 (mt () , str " this->v()" , str " (*this)" )
15771682 | Some obj_expr ->
15781683 let obj_pp = pp_scrut obj_expr in
15791684 ( str (" auto&& " ^ sv_name ^ " = " ) ++ obj_pp ++ str " ;" ++ fnl () ,
1580- str (sv_name ^ " ->v() " ), str sv_name )
1685+ str (v_access sv_name ), str sv_name )
15811686 | None ->
15821687 ( match first_scrut with
15831688 | CPPvar id ->
@@ -1699,6 +1804,26 @@ and is_constexpr_type = function
16991804 | Tfun _ -> false (* std::function uses type erasure *)
17001805 | Tdecltype _ -> false
17011806 | Tglob (r , _ , _ ) when is_axiom_type_ref r -> false
1807+ | Tglob (GlobRef. IndRef (kn , i ), _ , _ ) ->
1808+ (* Value-type inductives with recursive fields contain shared_ptr
1809+ internally, making them non-literal. Check ip_types of each
1810+ constructor for self-references (same MutInd). *)
1811+ let has_recursive_field =
1812+ let rec check_ctor j =
1813+ let cref = GlobRef. ConstructRef ((kn, i), j) in
1814+ match Table. get_ctor_ip_types_opt cref with
1815+ | None -> false
1816+ | Some tys ->
1817+ List. exists (fun ty ->
1818+ match ty with
1819+ | Miniml. Tglob (GlobRef. IndRef (kn2 , _ ), _ , _ ) ->
1820+ MutInd.CanOrd. equal kn kn2
1821+ | _ -> false ) tys
1822+ || check_ctor (j + 1 )
1823+ in
1824+ (try check_ctor 1 with Not_found -> false )
1825+ in
1826+ not has_recursive_field
17021827 | Tmod (_ , t ) | Tref t | Tptr t -> is_constexpr_type t
17031828 | Tvariant tys -> List. for_all is_constexpr_type tys
17041829 | Tglob (_ , tys , _ ) -> List. for_all is_constexpr_type tys
@@ -2020,7 +2145,10 @@ let rec pp_cpp_field ?(struct_name : Pp.t option) env = function
20202145 let params_s =
20212146 pp_list
20222147 (fun (id , ty ) ->
2023- if not (Id.Set. mem id used_ids) then pp_cpp_type false [] ty
2148+ if
2149+ (not (Id.Set. mem id used_ids))
2150+ && not (String. equal (Id. to_string mf_name) " operator=" )
2151+ then pp_cpp_type false [] ty
20242152 else pp_cpp_type false [] ty ++ str " " ++ Id. print id)
20252153 mf_params
20262154 in
0 commit comments