Skip to content

Commit ad48749

Browse files
committed
transpile: Convert final return statement into tail expression
1 parent 52f4bd8 commit ad48749

20 files changed

+125
-61
lines changed

c2rust-transpile/src/translator/mod.rs

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ use log::{error, info, trace, warn};
1414
use proc_macro2::{Punct, Spacing::*, Span, TokenStream, TokenTree};
1515
use syn::spanned::Spanned as _;
1616
use syn::{
17-
AttrStyle, BareVariadic, Block, Expr, ExprBinary, ExprBlock, ExprBreak, ExprCast, ExprField,
18-
ExprIndex, ExprParen, ExprReturn, ExprUnary, FnArg, ForeignItem, ForeignItemFn,
19-
ForeignItemMacro, ForeignItemStatic, ForeignItemType, Ident, Item, ItemConst, ItemEnum,
20-
ItemExternCrate, ItemFn, ItemForeignMod, ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct,
21-
ItemTrait, ItemTraitAlias, ItemType, ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment,
22-
ReturnType, Stmt, Type, TypeTuple, UseTree, Visibility,
17+
Arm, AttrStyle, BareVariadic, Block, Expr, ExprBinary, ExprBlock, ExprBreak, ExprCast,
18+
ExprField, ExprIf, ExprIndex, ExprMatch, ExprParen, ExprReturn, ExprTuple, ExprUnary,
19+
ExprUnsafe, FnArg, ForeignItem, ForeignItemFn, ForeignItemMacro, ForeignItemStatic,
20+
ForeignItemType, Ident, Item, ItemConst, ItemEnum, ItemExternCrate, ItemFn, ItemForeignMod,
21+
ItemImpl, ItemMacro, ItemMod, ItemStatic, ItemStruct, ItemTrait, ItemTraitAlias, ItemType,
22+
ItemUnion, ItemUse, Lit, MacroDelimiter, PathSegment, ReturnType, Stmt, Type, TypeTuple,
23+
UseTree, Visibility,
2324
};
2425
use syn::{BinOp, UnOp}; // To override `c_ast::{BinOp,UnOp}` from glob import.
2526

@@ -341,12 +342,7 @@ pub fn stmts_block(mut stmts: Vec<Stmt>) -> Block {
341342
}),
342343
None,
343344
)) if stmts.is_empty() => return block,
344-
Some(mut s) => {
345-
if let Stmt::Expr(e, None) = s {
346-
s = Stmt::Expr(e, Some(Default::default()));
347-
}
348-
stmts.push(s);
349-
}
345+
Some(s) => stmts.push(s),
350346
}
351347
mk().block(stmts)
352348
}
@@ -5388,7 +5384,77 @@ impl<'c> Translation<'c> {
53885384
// If the very last statement in the vector is a `return`, either cut it out or replace it with
53895385
// the returned value.
53905386
fn strip_tail_return(stmts: &mut Vec<Stmt>) {
5391-
if let Some(Stmt::Expr(Expr::Return(ExprReturn { expr: None, .. }), _)) = stmts.last() {
5392-
stmts.pop();
5387+
if let Some(Stmt::Expr(expr, semi)) = stmts.last_mut() {
5388+
*semi = None;
5389+
strip_tail_return_expr(expr);
5390+
5391+
// If the expression was replaced with an empty tuple (), then just delete it altogether.
5392+
if matches!(expr, Expr::Tuple(ExprTuple { elems, .. }) if elems.is_empty()) {
5393+
stmts.pop();
5394+
}
5395+
}
5396+
}
5397+
5398+
// If a return is found, replace it with the returned expression.
5399+
// If an expression of another kind is found, and it contains a subexpression that becomes the
5400+
// final value of the whole, then recurse down into it.
5401+
fn strip_tail_return_expr(expr: &mut Expr) {
5402+
match expr {
5403+
old_expr @ Expr::Return(ExprReturn { .. }) => {
5404+
// placeholder value to allow swapping
5405+
let temp = mem::replace(old_expr, Expr::Verbatim(Default::default()));
5406+
// TODO: Rust 1.65: use let-else
5407+
let expr = match temp {
5408+
Expr::Return(ExprReturn { expr, .. }) => expr,
5409+
_ => unreachable!(),
5410+
};
5411+
5412+
if let Some(expr) = expr {
5413+
// Replace return + expression with the expression.
5414+
*old_expr = *expr;
5415+
} else {
5416+
// Replace standalone return with ()
5417+
*old_expr = *mk().tuple_expr(vec![]);
5418+
}
5419+
}
5420+
5421+
// Simple blocks, recurse down
5422+
// TODO: add when syn is updated
5423+
// | Expr::Const(ExprConst { block, .. })
5424+
Expr::Block(ExprBlock { block, .. }) | Expr::Unsafe(ExprUnsafe { block, .. }) => {
5425+
strip_tail_return(&mut block.stmts);
5426+
}
5427+
5428+
// Recurse down both branches of the `if`
5429+
Expr::If(ExprIf {
5430+
then_branch,
5431+
else_branch,
5432+
..
5433+
}) => {
5434+
strip_tail_return(&mut then_branch.stmts);
5435+
5436+
// If the function returns a value, then there must be an else_branch,
5437+
// but if it returns void then there doesn't have to be. For example
5438+
//
5439+
// if condition {
5440+
// // stuff
5441+
// return;
5442+
// }
5443+
// } // end of function
5444+
if let Some((_, else_branch)) = else_branch {
5445+
strip_tail_return_expr(else_branch);
5446+
}
5447+
}
5448+
5449+
// Recurse down all arms of the `match`
5450+
Expr::Match(ExprMatch { arms, .. }) => {
5451+
for Arm { body, .. } in arms {
5452+
strip_tail_return_expr(body);
5453+
}
5454+
}
5455+
5456+
// Other expression types do not have blocks with tail expressions, whose value becomes
5457+
// that of the whole expression.
5458+
_ => (),
53935459
}
53945460
}

c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64@vm_x86.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,5 @@ pub unsafe extern "C" fn VM_CallCompiled(
6868
return 0 as ::core::ffi::c_int;
6969
}
7070
(*vm).programStack = stackOnEntry;
71-
return *opStack.offset(opStackOfs as isize);
71+
*opStack.offset(opStackOfs as isize)
7272
}

c2rust-transpile/tests/snapshots/snapshots__transpile-linux@macros.c.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ extern "C" {
2222
pub type size_t = usize;
2323
#[no_mangle]
2424
pub unsafe extern "C" fn errno_is_error() -> bool {
25-
return *__errno_location() != 0 as ::core::ffi::c_int;
25+
*__errno_location() != 0 as ::core::ffi::c_int
2626
}
2727
#[no_mangle]
2828
pub unsafe extern "C" fn size_of_const() -> ::core::ffi::c_int {
2929
let mut a: [::core::ffi::c_int; 10] = [0; 10];
30-
return SIZE as ::core::ffi::c_int;
30+
SIZE as ::core::ffi::c_int
3131
}
3232
pub const SIZE: usize = ::core::mem::size_of::<[::core::ffi::c_int; 10]>();
3333
pub const POS: [::core::ffi::c_char; 3] =

c2rust-transpile/tests/snapshots/snapshots__transpile-linux@rnd.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ pub unsafe extern "C" fn get_rand_seed() -> uint32_t {
3232
.wrapping_mul(cur_rand_seed)
3333
.wrapping_add(INCREMENT);
3434
let mut ret: uint32_t = abs(cur_rand_seed as ::core::ffi::c_int) as uint32_t;
35-
return ret;
35+
ret
3636
}

c2rust-transpile/tests/snapshots/snapshots__transpile-linux@rotate.c.snap

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ input_file: c2rust-transpile/tests/snapshots/os-specific/rotate.c
1515
pub unsafe extern "C" fn rotate_left_64(
1616
mut x: ::core::ffi::c_ulonglong,
1717
) -> ::core::ffi::c_ulonglong {
18-
return (x as ::core::ffi::c_ulong)
19-
.rotate_left(4 as ::core::ffi::c_int as ::core::ffi::c_ulong as u32)
20-
as ::core::ffi::c_ulonglong;
18+
(x as ::core::ffi::c_ulong).rotate_left(4 as ::core::ffi::c_int as ::core::ffi::c_ulong as u32)
19+
as ::core::ffi::c_ulonglong
2120
}
2221
#[no_mangle]
2322
pub unsafe extern "C" fn rotate_right_64(
2423
mut x: ::core::ffi::c_ulonglong,
2524
) -> ::core::ffi::c_ulonglong {
26-
return (x as ::core::ffi::c_ulong)
27-
.rotate_right(4 as ::core::ffi::c_int as ::core::ffi::c_ulong as u32)
28-
as ::core::ffi::c_ulonglong;
25+
(x as ::core::ffi::c_ulong).rotate_right(4 as ::core::ffi::c_int as ::core::ffi::c_ulong as u32)
26+
as ::core::ffi::c_ulonglong
2927
}

c2rust-transpile/tests/snapshots/snapshots__transpile-macos@macros.c.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ pub type __darwin_size_t = usize;
2323
pub type size_t = __darwin_size_t;
2424
#[no_mangle]
2525
pub unsafe extern "C" fn errno_is_error() -> bool {
26-
return *__error() != 0 as ::core::ffi::c_int;
26+
*__error() != 0 as ::core::ffi::c_int
2727
}
2828
#[no_mangle]
2929
pub unsafe extern "C" fn size_of_const() -> ::core::ffi::c_int {
3030
let mut a: [::core::ffi::c_int; 10] = [0; 10];
31-
return SIZE as ::core::ffi::c_int;
31+
SIZE as ::core::ffi::c_int
3232
}
3333
pub const SIZE: usize = ::core::mem::size_of::<[::core::ffi::c_int; 10]>();
3434
pub const POS: [::core::ffi::c_char; 3] =

c2rust-transpile/tests/snapshots/snapshots__transpile-macos@rnd.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ pub unsafe extern "C" fn get_rand_seed() -> uint32_t {
3030
.wrapping_mul(cur_rand_seed)
3131
.wrapping_add(INCREMENT);
3232
let mut ret: uint32_t = abs(cur_rand_seed as ::core::ffi::c_int) as uint32_t;
33-
return ret;
33+
ret
3434
}

c2rust-transpile/tests/snapshots/snapshots__transpile-macos@rotate.c.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ input_file: c2rust-transpile/tests/snapshots/os-specific/rotate.c
1515
pub unsafe extern "C" fn rotate_left_64(
1616
mut x: ::core::ffi::c_ulonglong,
1717
) -> ::core::ffi::c_ulonglong {
18-
return x.rotate_left(4 as ::core::ffi::c_int as ::core::ffi::c_ulonglong as u32);
18+
x.rotate_left(4 as ::core::ffi::c_int as ::core::ffi::c_ulonglong as u32)
1919
}
2020
#[no_mangle]
2121
pub unsafe extern "C" fn rotate_right_64(
2222
mut x: ::core::ffi::c_ulonglong,
2323
) -> ::core::ffi::c_ulonglong {
24-
return x.rotate_right(4 as ::core::ffi::c_int as ::core::ffi::c_ulonglong as u32);
24+
x.rotate_right(4 as ::core::ffi::c_int as ::core::ffi::c_ulonglong as u32)
2525
}

c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64@vm_x86.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,5 +78,5 @@ pub unsafe extern "C" fn VM_CallCompiled(
7878
return 0 as ::core::ffi::c_int;
7979
}
8080
(*vm).programStack = stackOnEntry;
81-
return *opStack.offset(opStackOfs as isize);
81+
*opStack.offset(opStackOfs as isize)
8282
}

c2rust-transpile/tests/snapshots/snapshots__transpile@alloca.c.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,5 @@ pub unsafe extern "C" fn alloca_sum(
3737
alloca2 = alloca_allocations.last_mut().unwrap().as_mut_ptr() as *mut ::core::ffi::c_int;
3838
*alloca2 = val2;
3939
}
40-
return *alloca1 + *alloca2;
40+
*alloca1 + *alloca2
4141
}

0 commit comments

Comments
 (0)