Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 4 additions & 4 deletions c2rust-transpile/src/cfg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1508,7 +1508,7 @@ impl CfgBuilder {

// Condition
let (stmts, val) = translator
.convert_condition(ctx, true, scrutinee)?
.convert_condition(ctx.used(), true, scrutinee)?
.discard_unsafe();
wip.extend(stmts);

Expand Down Expand Up @@ -1581,7 +1581,7 @@ impl CfgBuilder {

// Condition
let (stmts, val) = translator
.convert_condition(ctx, true, condition)?
.convert_condition(ctx.used(), true, condition)?
.discard_unsafe();
let cond_val = translator
.ast_context
Expand Down Expand Up @@ -1660,7 +1660,7 @@ impl CfgBuilder {

// Condition
let (stmts, val) = translator
.convert_condition(ctx, true, condition)?
.convert_condition(ctx.used(), true, condition)?
.discard_unsafe();
let cond_val = translator
.ast_context
Expand Down Expand Up @@ -1715,7 +1715,7 @@ impl CfgBuilder {
// Condition
if let Some(cond) = condition {
let (stmts, val) = translator
.convert_condition(ctx, true, cond)?
.convert_condition(ctx.used(), true, cond)?
.discard_unsafe();
let cond_val = translator
.ast_context
Expand Down
6 changes: 3 additions & 3 deletions c2rust-transpile/src/translator/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl<'c> Translation<'c> {
}

"__builtin_va_start" => {
if ctx.is_unused() && args.len() == 2 {
if !ctx.is_used && args.len() == 2 {
if let Some(va_id) = self.match_vastart(args[0]) {
if self.ast_context.get_decl(&va_id).is_some() {
let dst = self.convert_expr(ctx.used(), args[0], None)?;
Expand All @@ -352,7 +352,7 @@ impl<'c> Translation<'c> {
Err(TranslationError::generic("Unsupported va_start"))
}
"__builtin_va_copy" => {
if ctx.is_unused() && args.len() == 2 {
if !ctx.is_used && args.len() == 2 {
if let Some((_dst_va_id, _src_va_id)) = self.match_vacopy(args[0], args[1]) {
let dst = self.convert_expr(ctx.used(), args[0], None)?;
let src = self.convert_expr(ctx.used(), args[1], None)?;
Expand All @@ -370,7 +370,7 @@ impl<'c> Translation<'c> {
Err(TranslationError::generic("Unsupported va_copy"))
}
"__builtin_va_end" => {
if ctx.is_unused() && args.len() == 1 {
if !ctx.is_used && args.len() == 1 {
if let Some(_va_id) = self.match_vaend(args[0]) {
// nothing to do since the translated Rust `va_list` values get `Drop`'ed.
return Ok(WithStmts::new_val(self.panic("va_end stub")));
Expand Down
8 changes: 4 additions & 4 deletions c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl<'c> Translation<'c> {

let to_array_element = |id: CExprId| -> TranslationResult<_> {
let val =
self.convert_expr(ctx.used(), id, Some(CQualTypeId::new(element_type_id)))?;
self.convert_expr(ctx, id, Some(CQualTypeId::new(element_type_id)))?;
val.try_map(|x| {
// Array literals require all of their elements to be
// the correct type; they will not use implicit casts to
Expand Down Expand Up @@ -309,7 +309,7 @@ impl<'c> Translation<'c> {
// * `ptr_extra_braces`
// * `array_of_ptrs`
// * `array_of_arrays`
self.convert_expr(ctx.used(), single, expected_type_id)
self.convert_expr(ctx, single, expected_type_id)
}
&[single] if is_zero_literal(single) && n > 1 => {
// This was likely a C array of the form `int x[16] = { 0 }`.
Expand Down Expand Up @@ -348,9 +348,9 @@ impl<'c> Translation<'c> {
}
ref kind if kind.is_scalar() => {
if let Some(&first) = ids.first() {
self.convert_expr(ctx.used(), first, expected_type_id)
self.convert_expr(ctx, first, expected_type_id)
} else {
self.implicit_default_expr(ctx.used(), result_type_id.ctype)
self.implicit_default_expr(ctx, result_type_id.ctype)
}
}
ref t => Err(format_err!("Init list not implemented for {:?}", t).into()),
Expand Down
2 changes: 1 addition & 1 deletion c2rust-transpile/src/translator/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl<'c> Translation<'c> {
.kind
.get_type()
.ok_or_else(|| format_err!("Invalid expression type"))?;
let expr = self.convert_expr(ctx, id, None)?;
let expr = self.convert_expr(ctx.used(), id, None)?;

// Join ty and cur_ty to the smaller of the two types. If the
// types are not cast-compatible, abort the fold.
Expand Down
58 changes: 36 additions & 22 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,23 @@ pub enum ReplaceMode {
/// Options that impact an expression and all of its subexpressions.
#[derive(Copy, Clone, Debug)]
pub struct ExprContext {
used: bool,
/// Whether the result value of the expression is used in a larger expression.
///
/// When the result value is not used in a particular context, only the side effects of the
/// expression matter. The `stmts` field of `WithStmts` should hold any statements with side
/// effects, and the `val` field is expected to be discarded. It should not appear in the final
/// transpiler output, and may be an expression that panics when evaluated.
///
/// `is_used` should be `false` for the top-level expression of an `ExprStmt`, the increment
/// expression of a `for` loop, the `lhs` of a comma operator expression, and other such cases.
/// It should be `true` if an expression is needed to evaluate the side effects of a parent
/// expression, such as the arguments of a function call, the operands of an assignment
/// expression, the expression of a `return` statement, etc.
///
/// If an expression is pure (has no side effects), then it should inherit its `is_used` value
/// from its parent expression: if the parent expression is going to be discarded, then so are
/// all of its pure child expressions.
is_used: bool,

/// In a Rust const context, for example in a static initializer or constant-like macro
/// translation.
Expand All @@ -149,20 +165,18 @@ pub struct ExprContext {

impl ExprContext {
pub fn used(self) -> Self {
ExprContext { used: true, ..self }
ExprContext {
is_used: true,
..self
}
}
pub fn unused(self) -> Self {
ExprContext {
used: false,
is_used: false,
..self
}
}
pub fn is_used(&self) -> bool {
self.used
}
pub fn is_unused(&self) -> bool {
!self.used
}

pub fn decay_ref(self) -> Self {
ExprContext {
decay_ref: DecayRef::Yes,
Expand Down Expand Up @@ -855,7 +869,7 @@ pub fn translate(
) -> (String, Option<DeclMap>, PragmaVec, CrateSet) {
let mut t = Translation::new(ast_context, tcfg, main_file);
let ctx = ExprContext {
used: true,
is_used: false,
is_static: false,
is_const: false,
decay_ref: DecayRef::Default,
Expand Down Expand Up @@ -2455,7 +2469,7 @@ impl<'c> Translation<'c> {

let null_pointer_case =
|ptr: CExprId, is_null: bool| -> TranslationResult<WithStmts<Box<Expr>>> {
let val = self.convert_expr(ctx.used().decay_ref(), ptr, None)?;
let val = self.convert_expr(ctx.decay_ref(), ptr, None)?;
let ptr_type = self
.ast_context
.index_unwrap_parens(ptr)
Expand Down Expand Up @@ -2510,7 +2524,7 @@ impl<'c> Translation<'c> {
// in https://github.com/rust-lang/rust/issues/53772, you cant compare a reference (lhs) to
// a ptr (rhs) (even though the reverse works!). We could also be smarter here and just
// specify Yes for that particular case, given enough analysis.
let val = self.convert_expr(ctx.used().decay_ref(), cond_id, None)?;
let val = self.convert_expr(ctx.decay_ref(), cond_id, None)?;
val.try_map(|e| self.match_bool(ctx, target, ty_id, e))
}
}
Expand Down Expand Up @@ -3066,7 +3080,7 @@ impl<'c> Translation<'c> {

let elts = self.compute_size_of_type(ctx, expected_type_id, result_type_id, elts)?;
return elts.and_then_try(|lhs| {
let len = self.convert_expr(ctx.used().not_static(), len, expected_type_id)?;
let len = self.convert_expr(ctx.not_static(), len, expected_type_id)?;
Ok(len.map(|len| {
let rhs = cast_int(len, "usize", true);
mk().binary_expr(BinOp::Mul(Default::default()), lhs, rhs)
Expand Down Expand Up @@ -3166,10 +3180,10 @@ impl<'c> Translation<'c> {
/// Translate a C expression into a Rust one, possibly collecting side-effecting statements
/// to run before the expression.
///
/// `ctx.is_used()` informs us how the C expression we are translating is used in the C
/// `ctx.is_used` informs us how the C expression we are translating is used in the C
/// program.
///
/// In the case that `ctx.is_unused()`, all side-effecting components will be in the
/// In the case that `!ctx.is_used`, all side-effecting components will be in the
/// `stmts` field of the output and it is expected that the `val` field of the output will be
/// ignored.
///
Expand Down Expand Up @@ -3391,12 +3405,12 @@ impl<'c> Translation<'c> {
}

Conditional(ty, cond, lhs, rhs) => {
let cond = self.convert_condition(ctx, true, cond)?;
let cond = self.convert_condition(ctx.used(), true, cond)?;

let lhs = self.convert_expr(ctx, lhs, Some(override_ty.unwrap_or(ty)))?;
let rhs = self.convert_expr(ctx, rhs, Some(override_ty.unwrap_or(ty)))?;

if ctx.is_unused() {
if !ctx.is_used {
let is_unsafe = lhs.is_unsafe() || rhs.is_unsafe();
let then = mk().block(lhs.into_stmts());
let else_ = mk().block_expr(mk().block(rhs.into_stmts()));
Expand Down Expand Up @@ -3431,9 +3445,9 @@ impl<'c> Translation<'c> {
BinaryConditional(ty, lhs, rhs) => {
let rhs = self.convert_expr(ctx, rhs, None)?;

if ctx.is_unused() {
if !ctx.is_used {
let lhs = self
.convert_condition(ctx, false, lhs)?
.convert_condition(ctx.used(), false, lhs)?
.merge_unsafe(rhs.is_unsafe());

Ok(lhs.and_then(|val| {
Expand Down Expand Up @@ -3746,7 +3760,7 @@ impl<'c> Translation<'c> {
expr: WithStmts<Box<Expr>>,
panic_msg: &str,
) -> WithStmts<Box<Expr>> {
if ctx.is_unused() {
if !ctx.is_used {
// Recall that if `used` is false, the `stmts` field of the output must contain
// all side-effects (and a function call can always have side-effects)
expr.and_then(|expr| {
Expand Down Expand Up @@ -3816,7 +3830,7 @@ impl<'c> Translation<'c> {
match as_semi_break_stmt(&stmt, &lbl) {
Some(val) => {
let block = mk().block_expr(match val {
Some(val) if ctx.is_used() => WithStmts::new(stmts, val).to_block(),
Some(val) if ctx.is_used => WithStmts::new(stmts, val).to_block(),
_ => mk().block(stmts),
});

Expand Down Expand Up @@ -3845,7 +3859,7 @@ impl<'c> Translation<'c> {
))
}
_ => {
if ctx.is_unused() {
if !ctx.is_used {
let val =
self.panic_or_err("Empty statement expression is not supposed to be used");
Ok(WithStmts::new_val(val))
Expand Down
2 changes: 1 addition & 1 deletion c2rust-transpile/src/translator/named_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl<'c> Translation<'c> {

let is_pure = self.ast_context.is_expr_pure(reference);
let read = |write| self.read(reference_ty, write);
let reference = self.convert_expr(ctx.used(), reference, Some(reference_ty))?;
let reference = self.convert_expr(ctx, reference, Some(reference_ty))?;
reference.and_then_try(|reference| {
if is_lvalue(&reference) && (is_pure || !uses_read) {
let rvalue = uses_read.then(|| read(reference.clone())).transpose()?;
Expand Down
Loading
Loading