Skip to content
Draft
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
9 changes: 9 additions & 0 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,15 @@ impl TypedAstContext {
}
}

/// Unwraps a constant expression, if there is one.
pub fn unwrap_constant_expr(&self, expr_id: CExprId) -> CExprId {
if let CExprKind::ConstantExpr(_, subexpr, _) = self[expr_id].kind {
subexpr
} else {
expr_id
}
}

/// Unwraps the underlying expression beneath any casts.
pub fn unwrap_cast_expr(&self, mut expr_id: CExprId) -> CExprId {
while let CExprKind::Paren(_, subexpr)
Expand Down
62 changes: 62 additions & 0 deletions c2rust-transpile/src/translator/literals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,66 @@ impl<'c> Translation<'c> {
bytes_padded
}

/// Convert a C compound literal expression to a Rust expression.
pub fn convert_compound_literal(
&self,
ctx: ExprContext,
qty: CQualTypeId,
val: CExprId,
override_ty: Option<CQualTypeId>,
) -> TranslationResult<WithStmts<Box<Expr>>> {
// C compound literals are lvalues, but equivalent Rust expressions generally are not.
// So if an address is needed, store it in an intermediate variable first.
if !ctx.needs_address() || ctx.expanding_macro.is_some() {
return self.convert_expr(ctx, val, override_ty);
}

let fresh_name = self.renamer.borrow_mut().fresh();
let fresh_ty = self.convert_type(override_ty.unwrap_or(qty).ctype)?;

// Translate the expression to be assigned to the fresh variable.
// It will be assigned by value, so we don't need its address anymore.
let val = self.convert_expr(ctx.set_needs_address(false), val, override_ty)?;

// If we are translating a static variable,
// then the fresh variable should also be static.
if ctx.is_static {
val.wrap_unsafe().and_then(|val| {
let item = mk().mutbl().static_item(&fresh_name, fresh_ty, val);
let fresh_stmt = mk().item_stmt(item);
let mut val = WithStmts::new(vec![fresh_stmt], mk().ident_expr(fresh_name));

// Accessing a static variable is unsafe.
// In the current nightly, this applies also to taking a raw pointer,
// but this requirement was removed in later versions of the
// `raw_ref_op` feature.
if self.tcfg.edition < Edition2024 {
val.set_unsafe();
}

Ok(val)
})
} else {
val.and_then(|val| {
let mutbl = if qty.qualifiers.is_const {
Mutability::Immutable
} else {
Mutability::Mutable
};
let local = mk().local(
mk().set_mutbl(mutbl).ident_pat(&fresh_name),
Some(fresh_ty),
Some(val),
);
let fresh_stmt = mk().local_stmt(Box::new(local));
Ok(WithStmts::new(
vec![fresh_stmt],
mk().ident_expr(fresh_name),
))
})
}
}

/// Convert an initialization list into an expression. These initialization lists can be
/// used as array literals, struct literals, and union literals in code.
pub fn convert_init_list(
Expand Down Expand Up @@ -208,6 +268,7 @@ impl<'c> Translation<'c> {
// * the expr kind being a string literal (`CExprKind::Literal` of a `CLiteral::String`).
let is_string_literal = |id: CExprId| {
let ty_kind = &self.ast_context.resolve_type(ty).kind;
let id = self.ast_context.unwrap_constant_expr(id);
let expr_kind = &self.ast_context.index(id).kind;
let is_char_array = matches!(*ty_kind, CTypeKind::Char);
let is_str_literal =
Expand All @@ -216,6 +277,7 @@ impl<'c> Translation<'c> {
};

let is_zero_literal = |id: CExprId| {
let id = self.ast_context.unwrap_constant_expr(id);
matches!(
self.ast_context.index(id).kind,
CExprKind::Literal(_, CLiteral::Integer(0, _base))
Expand Down
3 changes: 2 additions & 1 deletion c2rust-transpile/src/translator/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ impl<'c> Translation<'c> {
})?
.ok_or_else(|| format_err!("Could not find a valid type for macro"))?;

val.to_unsafe_pure_expr()
val.wrap_unsafe()
.to_pure_expr()
.map(|val| (val, ty))
.ok_or_else(|| TranslationError::generic("Macro expansion is not a pure expression"))

Expand Down
Loading
Loading