Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
02f2e1d
transpile: Split off `convert_decl_ref`
Rua Apr 26, 2026
695125d
transpile: Modify enum/pointer cast methods to take `CQualTypeId` and…
Rua Apr 25, 2026
f873624
transpile: Add `convert_enum_constant_decl_ref`
Rua May 5, 2026
7b407fe
transpile: Add `enum_constructor_expr`, replace params accordingly
Rua May 5, 2026
9161caa
transpile: Cast enums only if actually needed
Rua May 5, 2026
9f76c0e
transpile: Use correct types for enums in `convert_pre_increment`
Rua May 5, 2026
05af591
transpile: Add `EnumMode` to select enum output type
Rua May 5, 2026
2413faf
transpile: Add `EnumMode::NewType` and make it the default
Rua May 5, 2026
385304d
transpile: Factor out `can_propagate_cast`
Rua May 3, 2026
d52348c
transpile: Move ctx modifications down in cast handling code
Rua May 4, 2026
799cced
transpile: Add `enums.c` snapshot test
Rua May 3, 2026
ec32c82
transpile: let `can_propagate_cast` handle casting `EnumConstant` to …
Rua May 3, 2026
b564188
transpile: let `convert_literal` handle casting literal to enum
Rua May 4, 2026
7e3c4e3
transpile: Propagate cast of `EnumConstant` to its own integral type
Rua May 3, 2026
a53243b
transpile: In `Case` translation, do not propagate translation errors
Rua May 5, 2026
a7811e5
transpile: Add `ExprContext::is_pattern`, error on unsupported exprs
Rua May 5, 2026
5869679
transpile: Do not emit casts for literals in patterns
Rua May 5, 2026
fc99b68
transpile: Use `convert_expr` for patterns in `ConstantExpr`
Rua May 5, 2026
8ab3dc1
transpile: Add `expr_to_pat` function for more thorough conversion
Rua May 5, 2026
e832178
transpile: Treat cast failure in macro expansion as expansion failure
Rua May 5, 2026
9beca5d
transpile: Allow limited cast translation in patterns
Rua May 5, 2026
698955d
transpile: In `Case` translation, do not skip over initial cast
Rua May 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,14 @@ impl TypedAstContext {
TypeOf(ty) => ty,
Paren(ty) => ty,
Auto(ty) => ty,

// As an exception, resolve typedefs in `prenamed_decls`, because they do not
// get translated as type aliases in the final code.
Typedef(decl) if self.prenamed_decls.contains_key(&decl) => match self[decl].kind {
CDeclKind::Typedef { typ: ty, .. } => ty.ctype,
_ => panic!("Typedef decl did not point to a typedef"),
},

_ => return typ,
};
self.resolve_type_id_no_typedef(ty)
Expand Down
203 changes: 179 additions & 24 deletions c2rust-transpile/src/cfg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use std::ops::Index;
use std::rc::Rc;
use std::{fmt, io};
use syn::Lit;
use syn::{spanned::Spanned, Arm, Expr, Pat, Stmt};
use syn::{punctuated::Punctuated, spanned::Spanned, Arm, Expr, Pat, Stmt};

use failure::format_err;
use indexmap::indexset;
Expand Down Expand Up @@ -1857,31 +1857,16 @@ impl CfgBuilder {
self.add_wip_block(wip, Jump(this_label.clone()));

// Case
let resolved = translator.ast_context.unwrap_cast_expr(case_expr);
let branch = match translator.ast_context.index(resolved).kind {
CExprKind::Literal(..) | CExprKind::ConstantExpr(_, _, Some(_)) => {
match translator
.convert_expr(ctx.used(), resolved, None)?
.to_pure_expr()
{
Some(expr) => match *expr {
Expr::Lit(lit) => Some(mk().lit_pat(lit.lit)),
Expr::Path(path) => Some(mk().path_pat(path.path, path.qself)),
_ => None,
},
_ => None,
}
}
_ => None,
};

let pat = match branch {
Some(pat) => pat,
None => match cie {
let expr = translator
.convert_expr(ctx.const_().pattern().used(), case_expr, None)
.ok()
.and_then(WithStmts::to_pure_expr);
let pat = expr
.and_then(|expr| expr_to_pat(*expr))
.unwrap_or_else(|| match cie {
ConstIntExpr::U(n) => mk().lit_pat(mk().int_unsuffixed_lit(n)),
ConstIntExpr::I(n) => mk().lit_pat(mk().int_unsuffixed_lit(n)),
},
};
});

self.switch_expr_cases
.last_mut()
Expand Down Expand Up @@ -2317,3 +2302,173 @@ impl Cfg<Label, StmtOrDecl> {
Ok(())
}
}

fn expr_to_pat(expr: Expr) -> Option<Pat> {
use syn::{
ExprArray, ExprCall, ExprLit, ExprParen, ExprPath, ExprReference, ExprStruct, ExprTuple,
ExprUnary, FieldPat, FieldValue, LitInt, PatLit, PatParen, PatPath, PatReference, PatSlice,
PatStruct, PatTuple, PatTupleStruct, UnOp,
};

match expr {
Expr::Array(ExprArray {
attrs,
bracket_token,
elems,
}) => {
let elems = punctuated_expr_to_pat(elems)?;

Some(Pat::Slice(PatSlice {
attrs,
bracket_token,
elems,
}))
}

Expr::Call(ExprCall {
attrs,
func,
paren_token,
args,
}) => {
let (qself, path) = match *func {
Expr::Path(ExprPath { qself, path, .. }) => (qself, path),
_ => return None,
};
let elems = punctuated_expr_to_pat(args)?;

Some(Pat::TupleStruct(PatTupleStruct {
attrs,
qself,
path,
paren_token,
elems,
}))
}

Expr::Lit(ExprLit { attrs, lit }) => Some(Pat::Lit(PatLit { attrs, lit })),

Expr::Paren(ExprParen {
attrs,
paren_token,
expr,
}) => {
let pat = Box::new(expr_to_pat(*expr)?);
Some(Pat::Paren(PatParen {
attrs,
paren_token,
pat,
}))
}

Expr::Path(ExprPath { attrs, qself, path }) => {
Some(Pat::Path(PatPath { attrs, qself, path }))
}

Expr::Range(range) => Some(Pat::Range(range)),

Expr::Reference(ExprReference {
attrs,
and_token,
mutability,
expr,
}) => {
let pat = Box::new(expr_to_pat(*expr)?);

Some(Pat::Reference(PatReference {
attrs,
and_token,
mutability,
pat,
}))
}

Expr::Struct(ExprStruct {
attrs,
qself,
path,
brace_token,
fields,
dot2_token: None,
rest: None,
}) => {
let fields = fields
.into_iter()
.map(|field| {
let FieldValue {
attrs,
member,
colon_token,
expr,
} = field;
let pat = Box::new(expr_to_pat(expr)?);

Some(FieldPat {
attrs,
member,
colon_token,
pat,
})
})
.collect::<Option<_>>()?;

Some(Pat::Struct(PatStruct {
attrs,
qself,
path,
brace_token,
fields,
rest: None,
}))
}

Expr::Tuple(ExprTuple {
attrs,
paren_token,
elems,
}) => {
let elems = punctuated_expr_to_pat(elems)?;

Some(Pat::Tuple(PatTuple {
attrs,
paren_token,
elems,
}))
}

// There is no equivalent `PatUnary`, but the negative sign can be folded into the literal.
Expr::Unary(ExprUnary {
attrs,
op: UnOp::Neg(_),
expr,
}) => {
let Expr::Lit(ExprLit {
attrs: _,
lit: Lit::Int(lit_int),
}) = *expr else {
return None
};

let repr = format!("-{}{}", lit_int.base10_digits(), lit_int.suffix());
let lit = Lit::Int(LitInt::new(&repr, lit_int.span()));
Some(Pat::Lit(PatLit { attrs, lit }))
}

_ => None,
}
}

fn punctuated_expr_to_pat(
elems: Punctuated<Expr, syn::Token![,]>,
) -> Option<Punctuated<Pat, syn::Token![,]>> {
use syn::punctuated::Pair;

elems
.into_pairs()
.map(|pair| {
let (expr, token) = pair.into_tuple();
let pat = expr_to_pat(expr)?;
Some(Pair::new(pat, token))
})
.collect()
}
3 changes: 2 additions & 1 deletion c2rust-transpile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use c2rust_ast_exporter as ast_exporter;

use crate::build_files::{emit_build_files, get_build_dir, CrateConfig};
use crate::compile_cmds::get_compile_commands;
pub use crate::translator::ReplaceMode;
pub use crate::translator::{EnumMode, ReplaceMode};
use std::prelude::v1::Vec;

type PragmaVec = Vec<(&'static str, Vec<&'static str>)>;
Expand Down Expand Up @@ -108,6 +108,7 @@ pub struct TranspilerConfig {
pub log_level: log::LevelFilter,
pub edition: RustEdition,
pub deny_unsafe_op_in_unsafe_fn: bool,
pub enum_mode: EnumMode,

/// Run `c2rust-postprocess` after transpiling and potentially refactoring.
pub postprocess: bool,
Expand Down
Loading
Loading