From c3678041ab92421ae549a9050dd8737f75e624a3 Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 11 Mar 2026 15:10:25 +0100 Subject: [PATCH 1/9] transpile: Move `SomeId` to main `c_ast` module --- c2rust-transpile/src/c_ast/iterators.rs | 31 ------------------- c2rust-transpile/src/c_ast/mod.rs | 33 ++++++++++++++++++++- c2rust-transpile/src/cfg/mod.rs | 4 +-- c2rust-transpile/src/translator/comments.rs | 4 +-- c2rust-transpile/src/translator/mod.rs | 2 +- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/c2rust-transpile/src/c_ast/iterators.rs b/c2rust-transpile/src/c_ast/iterators.rs index 38bcffe6a8..6e0c3ab075 100644 --- a/c2rust-transpile/src/c_ast/iterators.rs +++ b/c2rust-transpile/src/c_ast/iterators.rs @@ -1,36 +1,5 @@ use crate::c_ast::*; -#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] -pub enum SomeId { - Stmt(CStmtId), - Expr(CExprId), - Decl(CDeclId), - Type(CTypeId), -} - -macro_rules! from_some_id { - ( $field_type:ty, $con_name:ident, $proj_name:ident ) => { - impl From<$field_type> for SomeId { - fn from(a: $field_type) -> Self { - SomeId::$con_name(a) - } - } - impl SomeId { - pub fn $proj_name(self) -> Option<$field_type> { - match self { - SomeId::$con_name(x) => Some(x), - _ => None, - } - } - } - }; -} - -from_some_id!(CExprId, Expr, expr); -from_some_id!(CStmtId, Stmt, stmt); -from_some_id!(CDeclId, Decl, decl); -from_some_id!(CTypeId, Type, type_); - /// Like the vec macro except that it calls the into method on all list elements macro_rules! intos { ( $( $x:expr ),* ) => { vec![ $( $x.into(), )* ] }; diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index cf413fce92..908f013307 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -1,5 +1,5 @@ use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor}; -use crate::iterators::{DFNodes, SomeId}; +use crate::iterators::DFNodes; use c2rust_ast_exporter::clang_ast::LRValue; use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; @@ -3096,3 +3096,34 @@ c = {c} locs.sort_unstable_by_key(|&loc| ctx.cmp_loc_include(loc)); } } + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub enum SomeId { + Stmt(CStmtId), + Expr(CExprId), + Decl(CDeclId), + Type(CTypeId), +} + +macro_rules! from_some_id { + ( $field_type:ty, $con_name:ident, $proj_name:ident ) => { + impl From<$field_type> for SomeId { + fn from(a: $field_type) -> Self { + SomeId::$con_name(a) + } + } + impl SomeId { + pub fn $proj_name(self) -> Option<$field_type> { + match self { + SomeId::$con_name(x) => Some(x), + _ => None, + } + } + } + }; +} + +from_some_id!(CExprId, Expr, expr); +from_some_id!(CStmtId, Stmt, stmt); +from_some_id!(CDeclId, Decl, decl); +from_some_id!(CTypeId, Type, type_); diff --git a/c2rust-transpile/src/cfg/mod.rs b/c2rust-transpile/src/cfg/mod.rs index 76549ee735..55e916bde3 100644 --- a/c2rust-transpile/src/cfg/mod.rs +++ b/c2rust-transpile/src/cfg/mod.rs @@ -15,8 +15,8 @@ //! - convert the `Vec>` back into a `Vec` //! -use crate::c_ast::iterators::{DFExpr, SomeId}; -use crate::c_ast::CLabelId; +use crate::c_ast::iterators::DFExpr; +use crate::c_ast::{CLabelId, SomeId}; use crate::diagnostics::TranslationResult; use crate::rust_ast::SpanExt; use c2rust_ast_printer::pprust; diff --git a/c2rust-transpile/src/translator/comments.rs b/c2rust-transpile/src/translator/comments.rs index ed9e8ed4bb..806d18c56a 100644 --- a/c2rust-transpile/src/translator/comments.rs +++ b/c2rust-transpile/src/translator/comments.rs @@ -1,6 +1,6 @@ use super::Translation; -use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor, SomeId}; -use crate::c_ast::{CDeclId, CDeclKind, CommentContext, SrcLoc, TypedAstContext}; +use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor}; +use crate::c_ast::{CDeclId, CDeclKind, CommentContext, SomeId, SrcLoc, TypedAstContext}; use crate::rust_ast::comment_store::CommentStore; use crate::rust_ast::{pos_to_span, SpanExt}; use log::debug; diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index a0c6bf74cc..c89ef43fce 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -36,7 +36,7 @@ use crate::translator::variadic::{mk_va_list_copy, mk_va_list_ty}; use c2rust_ast_builder::{mk, properties::*, Builder}; use c2rust_ast_printer::pprust; -use crate::c_ast::iterators::{DFExpr, SomeId}; +use crate::c_ast::iterators::DFExpr; use crate::c_ast::*; use crate::cfg; use crate::convert_type::TypeConverter; From 84685a9a1f94079a9bd6225b45d6b6f22bf4f7db Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 20 Mar 2026 17:02:34 +0100 Subject: [PATCH 2/9] transpile: Add AST node parent information --- c2rust-transpile/src/c_ast/conversion.rs | 28 +- c2rust-transpile/src/c_ast/mod.rs | 384 +++++++++++++++++- c2rust-transpile/src/translator/enums.rs | 5 +- .../src/translator/structs_unions.rs | 11 +- 4 files changed, 405 insertions(+), 23 deletions(-) diff --git a/c2rust-transpile/src/c_ast/conversion.rs b/c2rust-transpile/src/c_ast/conversion.rs index 59cc7bcfa8..5600f4f333 100644 --- a/c2rust-transpile/src/c_ast/conversion.rs +++ b/c2rust-transpile/src/c_ast/conversion.rs @@ -388,17 +388,23 @@ impl ConversionContext { /// Add a `CStmt` node into the `TypedAstContext` fn add_stmt(&mut self, id: ImporterId, stmt: CStmt) { - self.typed_context.c_stmts.insert(CStmtId(id), stmt); + let id = CStmtId(id); + self.typed_context.add_stmt_parents(id, &stmt.kind); + self.typed_context.c_stmts.insert(id, stmt); } /// Add a `CExpr` node into the `TypedAstContext` fn add_expr(&mut self, id: ImporterId, expr: CExpr) { - self.typed_context.c_exprs.insert(CExprId(id), expr); + let id = CExprId(id); + self.typed_context.add_expr_parents(id, &expr.kind); + self.typed_context.c_exprs.insert(id, expr); } /// Add a `CDecl` node into the `TypedAstContext` fn add_decl(&mut self, id: ImporterId, decl: CDecl) { - self.typed_context.c_decls.insert(CDeclId(id), decl); + let id = CDeclId(id); + self.typed_context.add_decl_parents(id, &decl.kind); + self.typed_context.c_decls.insert(id, decl); } /// Clang has `Expression <: Statement`, but we want to make that explicit via the @@ -561,7 +567,6 @@ impl ConversionContext { &'a mut self, untyped_context: &'a AstContext, node: &'a AstNode, - new_id: ImporterId, ) -> impl Iterator + 'a { use self::node_types::*; @@ -573,7 +578,6 @@ impl ConversionContext { .expect("child node not found"); let id = CDeclId(self.visit_node_type(decl, FIELD_DECL | ENUM_DECL | RECORD_DECL)); - self.typed_context.parents.insert(id, CDeclId(new_id)); if decl_node.tag == ASTEntryTag::TagFieldDecl { Some(id) @@ -2164,9 +2168,7 @@ impl ConversionContext { .iter() .map(|id| { let con = id.expect("Enum constant not found"); - let id = CDeclId(self.visit_node_type(con, ENUM_CON)); - self.typed_context.parents.insert(id, CDeclId(new_id)); - id + CDeclId(self.visit_node_type(con, ENUM_CON)) }) .collect(); @@ -2269,10 +2271,7 @@ impl ConversionContext { from_value(node.extras[6].clone()).expect("Expected struct alignment"); let fields: Option> = if has_def { - Some( - self.visit_record_children(untyped_context, node, new_id) - .collect(), - ) + Some(self.visit_record_children(untyped_context, node).collect()) } else { None }; @@ -2300,10 +2299,7 @@ impl ConversionContext { let attrs = from_value::>(node.extras[2].clone()) .expect("Expected attribute array on record"); let fields: Option> = if has_def { - Some( - self.visit_record_children(untyped_context, node, new_id) - .collect(), - ) + Some(self.visit_record_children(untyped_context, node).collect()) } else { None }; diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index 908f013307..6accc20df1 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -55,12 +55,16 @@ pub struct TypedAstContext { /// iterated over export all defined types during translation. c_decls: IndexMap, + /// The parent nodes of each CExprId, CStmtId or CDeclId node. + /// Most nodes have exactly one parent, or zero if they are a top-level node. + /// + /// Expressions appearing inside an `InitListExpr` can have two parents, + /// as they are shared between the semantic form and the syntactic form. + parents: HashMap>, + pub c_decls_top: Vec, pub c_main: Option, - /// record fields and enum constants - pub parents: HashMap, - /// Mapping from [`FileId`] to [`SrcFile`]. Deduplicated by file path. files: Vec, @@ -240,6 +244,366 @@ impl TypedAstContext { } } + fn add_parent(&mut self, child: impl Into, parent: impl Into) { + self.parents + .entry(child.into()) + .or_default() + .push(parent.into()); + } + + fn add_stmt_parents(&mut self, id: CStmtId, kind: &CStmtKind) { + use CStmtKind::*; + let parent = SomeId::Stmt(id); + + match *kind { + Label(stmt) => { + self.add_parent(stmt, parent); + } + + Case(expr, stmt, _) => { + self.add_parent(expr, parent); + self.add_parent(stmt, parent); + } + + Default(stmt) => { + self.add_parent(stmt, parent); + } + + Compound(ref stmts) => { + for &stmt in stmts { + self.add_parent(stmt, parent); + } + } + + Expr(expr) => { + self.add_parent(expr, parent); + } + + Empty => {} + + If { + scrutinee, + true_variant, + false_variant, + } => { + self.add_parent(scrutinee, parent); + self.add_parent(true_variant, parent); + + if let Some(false_variant) = false_variant { + self.add_parent(false_variant, parent); + } + } + Switch { scrutinee, body } => { + self.add_parent(scrutinee, parent); + self.add_parent(body, parent); + } + + While { condition, body } => { + self.add_parent(condition, parent); + self.add_parent(body, parent); + } + + DoWhile { body, condition } => { + self.add_parent(body, parent); + self.add_parent(condition, parent); + } + + ForLoop { + init, + condition, + increment, + body, + } => { + if let Some(init) = init { + self.add_parent(init, parent); + } + + if let Some(condition) = condition { + self.add_parent(condition, parent); + } + + if let Some(increment) = increment { + self.add_parent(increment, parent); + } + + self.add_parent(body, parent); + } + + Goto(..) => {} + Break => {} + Continue => {} + + Return(expr) => { + if let Some(expr) = expr { + self.add_parent(expr, parent); + } + } + + Decls(ref decls) => { + for &decl in decls { + self.add_parent(decl, parent); + } + } + + Asm { .. } => {} + + Attributed { + attributes: _, + substatement, + } => { + self.add_parent(substatement, parent); + } + } + } + + fn add_expr_parents(&mut self, id: CExprId, kind: &CExprKind) { + use CExprKind::*; + let parent = SomeId::Expr(id); + + match *kind { + Literal(..) => {} + + Unary(_, _, expr, _) => { + self.add_parent(expr, parent); + } + + UnaryType(_, _, expr, _) => { + if let Some(expr) = expr { + self.add_parent(expr, parent); + } + } + + OffsetOf(_, ref kind) => match *kind { + OffsetOfKind::Constant(..) => {} + OffsetOfKind::Variable(_, _, expr) => { + self.add_parent(expr, parent); + } + }, + + Binary(_, _, lhs, rhs, _, _) => { + self.add_parent(lhs, parent); + self.add_parent(rhs, parent); + } + + ImplicitCast(_, expr, _, _, _) => { + self.add_parent(expr, parent); + } + + ExplicitCast(_, expr, _, _, _) => { + self.add_parent(expr, parent); + } + + ConstantExpr(_, expr, _) => { + self.add_parent(expr, parent); + } + + DeclRef(..) => {} + + Call(_, func, ref args) => { + self.add_parent(func, parent); + + for &arg in args { + self.add_parent(arg, parent); + } + } + + Member(_, expr, _, _, _) => { + self.add_parent(expr, parent); + } + + ArraySubscript(_, lhs, rhs, _) => { + self.add_parent(lhs, parent); + self.add_parent(rhs, parent); + } + + Conditional(_, cond, lhs, rhs) => { + self.add_parent(cond, parent); + self.add_parent(lhs, parent); + self.add_parent(rhs, parent); + } + + BinaryConditional(_, cond, rhs) => { + self.add_parent(cond, parent); + self.add_parent(rhs, parent); + } + + InitList(_, ref exprs, _, syntactic_form) => { + for &expr in exprs { + self.add_parent(expr, parent); + } + + if let Some(syntactic_form) = syntactic_form { + self.add_parent(syntactic_form, parent); + } + } + + ImplicitValueInit(..) => {} + + Paren(_, expr) => { + self.add_parent(expr, parent); + } + + CompoundLiteral(_, expr) => { + self.add_parent(expr, parent); + } + + Predefined(_, expr) => { + self.add_parent(expr, parent); + } + + Statements(_, stmt) => { + self.add_parent(stmt, parent); + } + + VAArg(_, expr) => { + self.add_parent(expr, parent); + } + + ShuffleVector(_, ref exprs) => { + for &expr in exprs { + self.add_parent(expr, parent); + } + } + + ConvertVector(_, ref exprs) => { + for &expr in exprs { + self.add_parent(expr, parent); + } + } + + DesignatedInitExpr(_, _, expr) => { + self.add_parent(expr, parent); + } + + Choose(_, cond, lhs, rhs, _) => { + self.add_parent(cond, parent); + self.add_parent(lhs, parent); + self.add_parent(rhs, parent); + } + + Atomic { + ptr, + order, + val1, + order_fail, + val2, + weak, + .. + } => { + self.add_parent(ptr, parent); + self.add_parent(order, parent); + + if let Some(val1) = val1 { + self.add_parent(val1, parent); + } + + if let Some(order_fail) = order_fail { + self.add_parent(order_fail, parent); + } + + if let Some(val2) = val2 { + self.add_parent(val2, parent); + } + + if let Some(weak) = weak { + self.add_parent(weak, parent); + } + } + + BadExpr => {} + } + } + + fn add_decl_parents(&mut self, id: CDeclId, kind: &CDeclKind) { + use CDeclKind::*; + let parent = SomeId::Decl(id); + + match *kind { + Function { + ref parameters, + body, + .. + } => { + for ¶meter in parameters { + self.add_parent(parameter, parent); + } + + if let Some(body) = body { + self.add_parent(body, parent); + } + } + + Variable { initializer, .. } => { + if let Some(initializer) = initializer { + self.add_parent(initializer, parent); + } + } + + Enum { + ref variants, + integral_type, + .. + } => { + if integral_type.is_some() { + for &variant in variants { + self.add_parent(variant, parent); + } + } + } + + EnumConstant { .. } => {} + + Typedef { .. } => {} + + Struct { ref fields, .. } => { + if let Some(fields) = fields { + for &field in fields { + self.add_parent(field, parent); + } + } + } + + Union { ref fields, .. } => { + if let Some(fields) = fields { + for &field in fields { + self.add_parent(field, parent); + } + } + } + + Field { .. } => {} + + MacroObject { .. } => {} + + MacroFunction { .. } => {} + + NonCanonicalDecl { .. } => {} + + StaticAssert { assert_expr, .. } => { + self.add_parent(assert_expr, parent); + } + } + } + + /// Returns the parent nodes of `child`. + pub fn parents(&self, child: impl Into) -> &[SomeId] { + self.parents + .get(&child.into()) + .map(AsRef::as_ref) + .unwrap_or_default() + } + + /// If `child` has a parent node, returns the first one. + pub fn parent(&self, child: impl Into) -> Option { + self.parents(child).get(0).copied() + } + + /// If `child` has a parent node, and the first one is of the given type `T`, returns it. + pub fn parent_with_type>(&self, child: impl Into) -> Option { + self.parent(child) + .and_then(|parent| T::try_from(parent).ok()) + } + pub fn display_loc(&self, loc: &Option) -> Option { loc.as_ref().map(|loc| DisplaySrcSpan { file: self.files[self.file_map[loc.fileid as usize]].path.clone(), @@ -1091,7 +1455,9 @@ impl TypedAstContext { if let CDeclKind::EnumConstant { .. } = self.c_decls[&decl_id].kind { // Special case for enums. The enum constant is used, so the whole // enum is also used. - let parent_id = self.parents[&decl_id]; + let parent_id = self + .parent_with_type(decl_id) + .expect("Enum constant does not have a parent Enum"); if wanted.insert(parent_id) { to_walk.push(parent_id); } @@ -3112,6 +3478,16 @@ macro_rules! from_some_id { SomeId::$con_name(a) } } + impl TryFrom for $field_type { + type Error = (); + + fn try_from(id: SomeId) -> Result { + match id { + SomeId::$con_name(x) => Ok(x), + _ => Err(()), + } + } + } impl SomeId { pub fn $proj_name(self) -> Option<$field_type> { match self { diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 91f1c4ef8e..23dfc119ee 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -40,7 +40,10 @@ impl<'c> Translation<'c> { .borrow_mut() .get(&enum_constant_id) .expect("Enum constant not named"); - let enum_id = self.ast_context.parents[&enum_constant_id]; + let enum_id = self + .ast_context + .parent_with_type(enum_constant_id) + .expect("Enum constant does not have a parent Enum"); let enum_name = self .type_converter .borrow() diff --git a/c2rust-transpile/src/translator/structs_unions.rs b/c2rust-transpile/src/translator/structs_unions.rs index b754159e9b..13b949ad00 100644 --- a/c2rust-transpile/src/translator/structs_unions.rs +++ b/c2rust-transpile/src/translator/structs_unions.rs @@ -1046,7 +1046,11 @@ impl<'a> Translation<'a> { } }; - let record_id = self.ast_context.parents[&decl]; + let record_id = self + .ast_context + .parent_with_type(decl) + .expect("Field does not have a parent Struct or Union"); + if self.ast_context.has_inner_struct_decl(record_id) { // The structure is split into an outer and an inner, // so we need to go through the outer structure to the inner one @@ -1099,7 +1103,10 @@ impl<'a> Translation<'a> { opt_field_id: Option, ) -> TranslationResult>> { let field_id = opt_field_id.expect("Missing field ID in union cast"); - let union_id = self.ast_context.parents[&field_id]; + let union_id = self + .ast_context + .parent_with_type(field_id) + .expect("Union field does not have a parent Union"); let union_name = self .type_converter From f9e82f535ab9f0f08ca257b4fa325f6fbc8dc1a6 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 17 Mar 2026 21:24:46 +0100 Subject: [PATCH 3/9] transpile: Remove no-op override_tys --- c2rust-transpile/src/translator/named_references.rs | 2 +- c2rust-transpile/src/translator/operators.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c2rust-transpile/src/translator/named_references.rs b/c2rust-transpile/src/translator/named_references.rs index a2f16a61c4..1963e035ee 100644 --- a/c2rust-transpile/src/translator/named_references.rs +++ b/c2rust-transpile/src/translator/named_references.rs @@ -107,7 +107,7 @@ impl<'c> Translation<'c> { .get_qual_type() .ok_or_else(|| format_err!("bad reference type"))?; 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.used(), reference, None)?; reference.and_then(|reference| { if !uses_read && is_lvalue(&reference) { Ok(WithStmts::new_val(NamedReference { diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index 17b4892340..cfc3d5b43b 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -300,7 +300,7 @@ impl<'c> Translation<'c> { .ok_or_else(|| format_err!("bad initial lhs type"))?; // First, translate the rhs. Then, if it must match the lhs but doesn't, add a cast. - let mut rhs_translation = self.convert_expr(ctx.used(), rhs, Some(rhs_type_id))?; + let mut rhs_translation = self.convert_expr(ctx.used(), rhs, None)?; let lhs_rhs_types_must_match = { let lhs_resolved_ty = &self.ast_context.resolve_type(lhs_type_id.ctype); let rhs_resolved_ty = &self.ast_context.resolve_type(rhs_type_id.ctype); From 8ebc9c0f585dbb0b3c56e5665701cabddfd7f908 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 20 Mar 2026 17:07:04 +0100 Subject: [PATCH 4/9] transpile: Move `literal_matches_ty` to `TypedAstContext` --- c2rust-transpile/src/c_ast/mod.rs | 16 ++++++++++++++++ c2rust-transpile/src/translator/literals.rs | 16 ---------------- c2rust-transpile/src/translator/mod.rs | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index 6accc20df1..129540d50e 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -1636,6 +1636,22 @@ impl TypedAstContext { } false } + + /// Return whether the literal can be directly translated as this type. + pub fn literal_matches_ty(&self, lit: &CLiteral, ty: CQualTypeId) -> bool { + let ty_kind = &self.resolve_type(ty.ctype).kind; + match *lit { + CLiteral::Integer(value, _) if ty_kind.is_integral_type() && !ty_kind.is_bool() => { + ty_kind.guaranteed_integer_in_range(value) + } + // `convert_literal` always casts these to i32. + CLiteral::Character(_value) => matches!(ty_kind, CTypeKind::Int32), + CLiteral::Floating(value, _) if ty_kind.is_floating_type() => { + ty_kind.guaranteed_float_in_range(value) + } + _ => false, + } + } } impl CommentContext { diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index 256b225de6..67581995d4 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -25,22 +25,6 @@ impl<'c> Translation<'c> { Ok(mk().cast_expr(mk().lit_expr(lit), target_ty)) } - /// Return whether the literal can be directly translated as this type. - pub fn literal_matches_ty(&self, lit: &CLiteral, ty: CQualTypeId) -> bool { - let ty_kind = &self.ast_context.resolve_type(ty.ctype).kind; - match *lit { - CLiteral::Integer(value, _) if ty_kind.is_integral_type() && !ty_kind.is_bool() => { - ty_kind.guaranteed_integer_in_range(value) - } - // `convert_literal` always casts these to i32. - CLiteral::Character(_value) => matches!(ty_kind, CTypeKind::Int32), - CLiteral::Floating(value, _) if ty_kind.is_floating_type() => { - ty_kind.guaranteed_float_in_range(value) - } - _ => false, - } - } - /// Convert a C literal expression to a Rust expression pub fn convert_literal( &self, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index c89ef43fce..8b11812846 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3653,7 +3653,7 @@ impl<'c> Translation<'c> { if let (Some(ty), CExprKind::Literal(_ty, lit)) = (override_ty, &self.ast_context[expr].kind) { - if self.literal_matches_ty(lit, ty) { + if self.ast_context.literal_matches_ty(lit, ty) { return self.convert_expr(ctx, expr, override_ty); } } From e54213ee5587fe1b57e588f2a696536ccae3b949 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 21 Mar 2026 11:14:50 +0100 Subject: [PATCH 5/9] transpile: Do not double-translate expression in `*ToBoolean` casts --- c2rust-transpile/src/translator/mod.rs | 53 +++++++++++++++----------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 8b11812846..d73e980f05 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3612,34 +3612,41 @@ impl<'c> Translation<'c> { _ => {} } - let mut source_ty = self.ast_context[expr] - .kind - .get_qual_type() - .ok_or_else(|| format_err!("bad source type"))?; - - let val = if is_explicit { + let source_ty = if let (true, Some(func_decl)) = + (is_explicit, self.ast_context.fn_declref_decl(expr)) + { // If we're casting a function, look for its declared ty to use as a more // precise source type. The AST node's type will not preserve typedef arg types // but the function's declaration will. - if let Some(func_decl) = self.ast_context.fn_declref_decl(expr) { - let kind_with_declared_args = - self.ast_context.fn_decl_ty_with_declared_args(func_decl); - let func_ty = self - .ast_context - .type_for_kind(&kind_with_declared_args) - .unwrap_or_else(|| { - panic!("no type for kind {kind_with_declared_args:?}") - }); - let func_ptr_ty = self - .ast_context - .type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty))) - .unwrap_or_else(|| { - panic!("no type for kind {kind_with_declared_args:?}") - }); + let kind_with_declared_args = + self.ast_context.fn_decl_ty_with_declared_args(func_decl); + let func_ty = self + .ast_context + .type_for_kind(&kind_with_declared_args) + .unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}")); + let func_ptr_ty = self + .ast_context + .type_for_kind(&CTypeKind::Pointer(CQualTypeId::new(func_ty))) + .unwrap_or_else(|| panic!("no type for kind {kind_with_declared_args:?}")); - source_ty = CQualTypeId::new(func_ptr_ty); - } + CQualTypeId::new(func_ptr_ty) + } else { + self.ast_context[expr] + .kind + .get_qual_type() + .ok_or_else(|| format_err!("bad source type"))? + }; + let val = if matches!( + kind, + CastKind::IntegralToBoolean + | CastKind::FloatingToBoolean + | CastKind::PointerToBoolean + ) { + // `convert_cast` discards the translated expression for these casts, + // so we might as well not bother to translate here. + WithStmts::new_val(self.panic_or_err("val is not supposed to be used")) + } else if is_explicit { let stmts = self.compute_variable_array_sizes(ctx, ty.ctype)?; let mut val = self.convert_expr(ctx, expr, None)?; val.prepend_stmts(stmts); From 6d15fb2d1640f6f301a7d3238c56d52680e253bb Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 22 Mar 2026 20:36:31 +0100 Subject: [PATCH 6/9] transpile: Compute and store `override_ty`s ahead of time --- c2rust-transpile/src/c_ast/mod.rs | 72 +++++ c2rust-transpile/src/translator/mod.rs | 364 ++++++++++++++++++++++++- 2 files changed, 435 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index 129540d50e..9709221dee 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -1,3 +1,4 @@ +use crate::c_ast; use crate::c_ast::iterators::{immediate_children_all_types, NodeVisitor}; use crate::iterators::DFNodes; use c2rust_ast_exporter::clang_ast::LRValue; @@ -604,6 +605,18 @@ impl TypedAstContext { .and_then(|parent| T::try_from(parent).ok()) } + /// If `child` is inside a function, returns its `CDeclId`. + pub fn parent_function(&self, child: impl Into) -> Option { + match self.parent(child)? { + SomeId::Stmt(stmt) => self.parent_function(stmt), + SomeId::Expr(expr) => self.parent_function(expr), + SomeId::Decl(decl) => { + matches!(self[decl].kind, CDeclKind::Function { .. }).then_some(decl) + } + SomeId::Type(ty) => self.parent_function(ty), + } + } + pub fn display_loc(&self, loc: &Option) -> Option { loc.as_ref().map(|loc| DisplaySrcSpan { file: self.files[self.file_map[loc.fileid as usize]].path.clone(), @@ -1652,6 +1665,65 @@ impl TypedAstContext { _ => false, } } + + /// Returns whether `expr` is within a conditional context, meaning that it is in a context + /// where a Rust `bool` will be expected. + pub fn expr_is_condition(&self, expr: CExprId) -> bool { + let parent = match self.parent(expr) { + Some(parent) => parent, + None => return false, + }; + + match parent { + SomeId::Stmt(parent_stmt) => match self.c_stmts[&parent_stmt].kind { + CStmtKind::If { + scrutinee: condition, + .. + } + | CStmtKind::While { condition, .. } + | CStmtKind::DoWhile { condition, .. } + | CStmtKind::ForLoop { + condition: Some(condition), + .. + } => expr == condition, + _ => false, + }, + + SomeId::Expr(parent_expr) => match self.c_exprs[&parent_expr].kind { + CExprKind::Paren(..) => self.expr_is_condition(parent_expr), + CExprKind::Unary(_, c_ast::UnOp::Not, arg, _) => expr == arg, + CExprKind::Binary(_, c_ast::BinOp::And | c_ast::BinOp::Or, lhs, rhs, _, _) => { + expr == lhs || expr == rhs + } + CExprKind::Conditional(_, condition, _, _) + | CExprKind::BinaryConditional(_, condition, _) => expr == condition, + CExprKind::ImplicitCast(_, arg, kind, _, _) + | CExprKind::ExplicitCast(_, arg, kind, _, _) => { + matches!( + kind, + CastKind::IntegralToBoolean + | CastKind::FloatingToBoolean + | CastKind::PointerToBoolean + ) && expr == arg + } + _ => false, + }, + + _ => false, + } + } + + /// Same as the `Index` trait, but doesn't bypass `Paren`. + pub fn index_expr_raw(&self, index: CExprId) -> &CExpr { + static BADEXPR: CExpr = Located { + loc: None, + kind: CExprKind::BadExpr, + }; + match self.c_exprs.get(&index) { + None => &BADEXPR, + Some(e) => e, + } + } } impl CommentContext { diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index d73e980f05..ca6b930ab1 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -36,7 +36,7 @@ use crate::translator::variadic::{mk_va_list_copy, mk_va_list_ty}; use c2rust_ast_builder::{mk, properties::*, Builder}; use c2rust_ast_printer::pprust; -use crate::c_ast::iterators::DFExpr; +use crate::c_ast::iterators::{immediate_children_all_types, DFExpr, NodeVisitor}; use crate::c_ast::*; use crate::cfg; use crate::convert_type::TypeConverter; @@ -273,6 +273,11 @@ pub struct Translation<'c> { pub ast_context: TypedAstContext, pub tcfg: &'c TranspilerConfig, + /// The type expected by the surrounding expression context. + /// This can be different from the type of the AST node itself + /// and in many cases should override it. + pub expr_override_types: HashMap, + // Accumulated outputs pub features: RefCell>, sectioned_static_initializers: RefCell>, @@ -722,6 +727,8 @@ pub fn translate( // in the presence of typedefs. t.ast_context.bubble_expr_types(); + t.set_override_types(); + enum Name<'a> { Var(&'a str), Type(&'a str), @@ -1138,6 +1145,346 @@ pub fn translate( } } +struct SetOverrideTypes<'a> { + ast_context: &'a TypedAstContext, + expr_override_types: &'a mut HashMap, +} + +impl<'a> NodeVisitor for SetOverrideTypes<'a> { + fn children(&mut self, id: SomeId) -> Vec { + immediate_children_all_types(self.ast_context, id) + } + + fn pre(&mut self, id: SomeId) -> bool { + match id { + SomeId::Stmt(stmt) => self.pre_stmt(stmt), + SomeId::Expr(expr) => self.pre_expr(expr), + SomeId::Decl(decl) => self.pre_decl(decl), + SomeId::Type(_) => {} + } + + true + } +} + +impl<'a> SetOverrideTypes<'a> { + fn pre_stmt(&mut self, stmt: CStmtId) { + match self.ast_context[stmt].kind { + CStmtKind::Return(Some(expr)) => { + let func_id = match self.ast_context.parent_function(stmt) { + Some(func_id) => func_id, + None => return, + }; + let func_ty = match self.ast_context[func_id].kind { + CDeclKind::Function { typ, .. } => typ, + _ => return, + }; + let return_ty = match self.ast_context.resolve_type(func_ty).kind { + CTypeKind::Function(return_ty, _, _, false, _) => return_ty, + _ => return, + }; + + self.expr_override_types.insert(expr, return_ty); + } + + _ => {} + } + } + + fn pre_expr(&mut self, expr: CExprId) { + let override_ty = self.expr_override_types.get(&expr).copied(); + + match self.ast_context.index_expr_raw(expr).kind { + CExprKind::Literal(..) => {} + + CExprKind::Unary(ty, op, arg, _) => match op { + c_ast::UnOp::Plus + | c_ast::UnOp::Negate + | c_ast::UnOp::Complement + | c_ast::UnOp::Extension => { + let cqual_type = override_ty.unwrap_or(ty); + self.expr_override_types.insert(arg, cqual_type); + } + c_ast::UnOp::AddressOf + | c_ast::UnOp::Deref + | c_ast::UnOp::PostIncrement + | c_ast::UnOp::PreIncrement + | c_ast::UnOp::PostDecrement + | c_ast::UnOp::PreDecrement + | c_ast::UnOp::Not + | c_ast::UnOp::Real + | c_ast::UnOp::Imag + | c_ast::UnOp::Coawait => {} + }, + + CExprKind::UnaryType(..) => {} + CExprKind::OffsetOf(..) => {} + + CExprKind::Binary(ty, op, lhs, rhs, _, _) => { + match op { + c_ast::BinOp::Comma => { + let expr_type_id = override_ty.unwrap_or(ty); + self.expr_override_types.insert(rhs, expr_type_id); + } + + // Boolean contexts don't care about type overrides. + c_ast::BinOp::And | c_ast::BinOp::Or => {} + + c_ast::BinOp::AssignAdd + | c_ast::BinOp::AssignSubtract + | c_ast::BinOp::AssignMultiply + | c_ast::BinOp::AssignDivide + | c_ast::BinOp::AssignModulus + | c_ast::BinOp::AssignBitXor + | c_ast::BinOp::AssignShiftLeft + | c_ast::BinOp::AssignShiftRight + | c_ast::BinOp::AssignBitOr + | c_ast::BinOp::AssignBitAnd + | c_ast::BinOp::Assign => {} + + // Operands of == and != have no override for null pointer comparisons, + // because only the non-null operand is converted. + c_ast::BinOp::EqualEqual | c_ast::BinOp::NotEqual + if self.ast_context.expr_is_condition(expr) + && (self.ast_context.is_null_expr(lhs) + || self.ast_context.is_null_expr(rhs)) => {} + + _ => { + let expr_type_id = override_ty.unwrap_or(ty); + + let lhs_kind = &self.ast_context[lhs].kind; + let mut lhs_type_id = match lhs_kind.get_qual_type() { + Some(ty) => ty, + None => return, + }; + let rhs_kind = &self.ast_context[rhs].kind; + let mut rhs_type_id = match rhs_kind.get_qual_type() { + Some(ty) => ty, + None => return, + }; + + // If this operation will (in Rust) take args of the same type, then + // propagate our expected type down to the translation of our argument + // expressions. + let lhs_resolved_ty = self.ast_context.resolve_type(lhs_type_id.ctype); + let rhs_resolved_ty = self.ast_context.resolve_type(rhs_type_id.ctype); + let expr_ty_kind = &self.ast_context.index(expr_type_id.ctype).kind; + + // Addition and subtraction can accept one pointer argument for .offset(), + // in which case we don't want to homogenize arg types. + if !lhs_resolved_ty.kind.is_pointer() + && !rhs_resolved_ty.kind.is_pointer() + && !expr_ty_kind.is_pointer() + { + if op.all_types_same() { + // Ops like division and bitxor accept inputs of their expected + // result type. + lhs_type_id = expr_type_id; + rhs_type_id = expr_type_id; + } else if op.input_types_same() + && lhs_resolved_ty.kind != rhs_resolved_ty.kind + { + // Ops like comparisons require argument types to match, but the + // result type doesn't inform us what type to choose. Select a + // synthetic definition of a portable rust type (e.g. u64 or usize) + // if either arg is one. + trace!( + "Binary op arg types differ: {:?} vs {:?}", + lhs_resolved_ty.kind, + rhs_resolved_ty.kind + ); + + if CTypeKind::PULLBACK_KINDS.contains(&lhs_resolved_ty.kind) { + rhs_type_id = lhs_type_id; + } else { + lhs_type_id = rhs_type_id; + } + } else if matches!( + op, + c_ast::BinOp::ShiftLeft | c_ast::BinOp::ShiftRight + ) { + lhs_type_id = expr_type_id; + } + } + + self.expr_override_types.insert(lhs, lhs_type_id); + self.expr_override_types.insert(rhs, rhs_type_id); + } + } + } + + CExprKind::ImplicitCast(_, expr, kind, _, _) => { + if let Some(override_ty) = override_ty { + // In general, if we are casting the result of an expression, then the inner + // expression should be translated to whatever type it normally would. + // But for literals, if we don't absolutely have to cast, we would rather the + // literal is translated according to the type we're expecting, and then we can + // skip the cast entirely. + if let CExprKind::Literal(_ty, lit) = &self.ast_context[expr].kind { + if self.ast_context.literal_matches_ty(lit, override_ty) { + self.expr_override_types.insert(expr, override_ty); + } + } + + // LValueToRValue casts don't actually change the type, so it still makes sense + // to translate their inner expression with the expected type from outside the + // cast. + if kind == CastKind::LValueToRValue { + let source_ty = match self.ast_context[expr].kind.get_qual_type() { + Some(ty) => ty, + None => return, + }; + + if source_ty.ctype != override_ty.ctype { + self.expr_override_types.insert(expr, override_ty); + } + } + } + } + + CExprKind::ExplicitCast(..) => {} + + CExprKind::ConstantExpr(ty, expr, _) => { + self.expr_override_types.insert(expr, ty); + } + + CExprKind::DeclRef(..) => {} + + CExprKind::Call(_, func, ref args) => { + if let CExprKind::ImplicitCast(_, _, CastKind::BuiltinFnToFnPtr, _, _) = + self.ast_context[func].kind + { + return; + } + + // Try to get the Variable decl directly, + // or fall back to querying the function pointer type. + let tys_of_params = if let Some(CDeclKind::Function { parameters, .. }) = + self.ast_context.fn_declref_decl(func) + { + self.ast_context.tys_of_params(parameters) + } else { + self.ast_context[func] + .kind + .get_type() + .and_then(|fn_ptr_qty| self.ast_context.get_pointee_qual_type(fn_ptr_qty)) + .and_then( + |fn_qty| match self.ast_context.resolve_type(fn_qty.ctype).kind { + CTypeKind::Function(_, ref param_tys, ..) => { + Some(param_tys.clone()) + } + _ => None, + }, + ) + }; + + if let Some(tys_of_params) = tys_of_params { + for (&arg, param_ty) in args.iter().zip(tys_of_params) { + if !(self.ast_context[arg].kind.get_qual_type()) + .map_or(false, |qtype| self.ast_context.is_va_list(qtype.ctype)) + { + self.expr_override_types.insert(arg, param_ty); + } + } + } + } + + CExprKind::Member(..) => {} + CExprKind::ArraySubscript(..) => {} + + CExprKind::Conditional(ty, _, lhs, rhs) => { + self.expr_override_types + .insert(lhs, override_ty.unwrap_or(ty)); + self.expr_override_types + .insert(rhs, override_ty.unwrap_or(ty)); + } + + CExprKind::BinaryConditional(..) => {} + + CExprKind::InitList(ty, ref exprs, _, _) => { + match self.ast_context.resolve_type(ty.ctype).kind { + CTypeKind::Struct(struct_id) => { + let field_decl_ids = match self.ast_context[struct_id].kind { + CDeclKind::Struct { + fields: Some(ref fields), + .. + } => fields, + _ => return, + }; + + let field_info_iter = field_decl_ids.iter().filter_map(|&field_id| { + match self.ast_context[field_id].kind { + CDeclKind::Field { + bitfield_width: Some(0), + .. + } => None, + CDeclKind::Field { typ, .. } => Some(typ), + _ => None, + } + }); + + for (&expr, typ) in exprs.iter().zip(field_info_iter) { + self.expr_override_types.insert(expr, typ); + } + } + + _ => {} + } + } + + CExprKind::ImplicitValueInit(..) => {} + + CExprKind::Paren(_, expr) => { + if let Some(override_ty) = override_ty { + self.expr_override_types.insert(expr, override_ty); + } + } + + CExprKind::CompoundLiteral(_, expr) => { + if let Some(override_ty) = override_ty { + self.expr_override_types.insert(expr, override_ty); + } + } + + CExprKind::Predefined(_, expr) => { + if let Some(override_ty) = override_ty { + self.expr_override_types.insert(expr, override_ty); + } + } + + CExprKind::Statements(..) => {} + CExprKind::VAArg(..) => {} + CExprKind::ShuffleVector(..) => {} + CExprKind::ConvertVector(..) => {} + CExprKind::DesignatedInitExpr(..) => {} + + CExprKind::Choose(_, _, lhs, rhs, _) => { + if let Some(override_ty) = override_ty { + self.expr_override_types.insert(lhs, override_ty); + self.expr_override_types.insert(rhs, override_ty); + } + } + + CExprKind::Atomic { .. } => {} + CExprKind::BadExpr => {} + } + } + + fn pre_decl(&mut self, decl: CDeclId) { + match self.ast_context[decl].kind { + CDeclKind::Variable { + typ, + initializer: Some(initializer), + .. + } => { + self.expr_override_types.insert(initializer, typ); + } + + _ => {} + } + } +} + /// Represent the set of names made visible by a `use`: either a set of specific names, or a glob. enum IdentsOrGlob<'a> { Idents(Vec<&'a Ident>), @@ -1546,6 +1893,7 @@ impl<'c> Translation<'c> { type_converter: RefCell::new(type_converter), ast_context, tcfg, + expr_override_types: HashMap::new(), // TODO: Use Renamer::value_namespace() for most renamings. renamer: RefCell::new(Renamer::global_value_namespace()), zero_inits: RefCell::new(IndexMap::new()), @@ -1565,6 +1913,20 @@ impl<'c> Translation<'c> { } } + fn set_override_types(&mut self) { + let mut expr_override_types = HashMap::new(); + + for &decl in &self.ast_context.c_decls_top { + SetOverrideTypes { + ast_context: &self.ast_context, + expr_override_types: &mut expr_override_types, + } + .visit_tree(SomeId::Decl(decl)); + } + + self.expr_override_types = expr_override_types; + } + fn use_crate(&self, extern_crate: ExternCrate) { self.extern_crates.borrow_mut().insert(extern_crate); } From a498f773086b8e96ff2a09e29b6fc1f309b1d5ac Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 22 Mar 2026 20:36:46 +0100 Subject: [PATCH 7/9] transpile: Pass `override_ty` in `recreate_const_macro_from_expansions` --- c2rust-transpile/src/translator/macros.rs | 24 +++---- .../snapshots__transpile@macros.c.2021.snap | 65 +++++++++---------- .../snapshots__transpile@macros.c.2024.snap | 65 +++++++++---------- 3 files changed, 76 insertions(+), 78 deletions(-) diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 67023b247f..975b38e8de 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -74,11 +74,12 @@ impl<'c> Translation<'c> { .try_fold::>, CTypeId)>, _, _>(None, |canonical, &id| { self.can_convert_const_macro_expansion(id)?; - let ty = self.ast_context[id] - .kind - .get_type() - .ok_or_else(|| format_err!("Invalid expression type"))?; - let expr = self.convert_expr(ctx, id, None)?; + let override_ty = self.expr_override_types.get(&id).copied(); + let expr = self.convert_expr(ctx, id, override_ty)?; + let ty = override_ty + .or_else(|| self.ast_context[id].kind.get_qual_type()) + .ok_or_else(|| format_err!("Invalid expression type"))? + .ctype; // Join ty and cur_ty to the smaller of the two types. If the // types are not cast-compatible, abort the fold. @@ -195,13 +196,12 @@ impl<'c> Translation<'c> { let val = WithStmts::new_val(mk().path_expr(vec![rust_name])); - let expr_kind = &self.ast_context[expr_id].kind; - // TODO We'd like to get rid of this cast eventually (see #1321). - // Currently, const macros do not get the correct `override_ty` themselves, - // so they aren't declared with the correct portable type, - // but its uses are expecting the correct portable type, - // so we need to cast it to the `override_ty` here. - let expr_ty = override_ty.or_else(|| expr_kind.get_qual_type()); + // Rust `const` variables have a single consistent type, determined by + // `recreate_const_macro_from_expansions`, while in C each macro expansion has its own type, + // determined by the surrounding context. + // Since the expansion sites are expecting a particular type, we need to cast it here + // if it differs from the `const` type. + let expr_ty = override_ty.or_else(|| self.ast_context[expr_id].kind.get_qual_type()); if let Some(expr_ty) = expr_ty { self.convert_cast( ctx, diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.snap index 64bc423919..b8c349c7ac 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2021.snap @@ -36,10 +36,10 @@ pub struct ntlmdata { pub target_info_len: ::core::ffi::c_uint, } pub const true_0: ::core::ffi::c_int = 1 as ::core::ffi::c_int; -pub const UINTPTR_MAX: ::core::ffi::c_ulong = 18446744073709551615 as ::core::ffi::c_ulong; +pub const UINTPTR_MAX: uintptr_t = 18446744073709551615 as uintptr_t; pub const LITERAL_INT: ::core::ffi::c_int = 0xffff as ::core::ffi::c_int; pub const LITERAL_BOOL: ::core::ffi::c_int = true_0; -pub const LITERAL_FLOAT: ::core::ffi::c_double = 3.14f64; +pub const LITERAL_FLOAT: ::core::ffi::c_float = 3.14f32; pub const LITERAL_CHAR: ::core::ffi::c_int = 'x' as i32; pub const LITERAL_STR: [::core::ffi::c_char; 6] = unsafe { ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0") }; @@ -48,7 +48,7 @@ pub const LITERAL_STRUCT: S = S { }; pub const NESTED_INT: ::core::ffi::c_int = LITERAL_INT; pub const NESTED_BOOL: ::core::ffi::c_int = LITERAL_BOOL; -pub const NESTED_FLOAT: ::core::ffi::c_double = LITERAL_FLOAT; +pub const NESTED_FLOAT: ::core::ffi::c_float = LITERAL_FLOAT; pub const NESTED_CHAR: ::core::ffi::c_int = LITERAL_CHAR; pub const NESTED_STR: [::core::ffi::c_char; 6] = LITERAL_STR; pub const NESTED_STRUCT: S = LITERAL_STRUCT; @@ -66,7 +66,7 @@ pub unsafe extern "C" fn local_muts() { unsafe { let mut literal_int: ::core::ffi::c_int = LITERAL_INT; let mut literal_bool: bool = LITERAL_BOOL != 0; - let mut literal_float: ::core::ffi::c_float = LITERAL_FLOAT as ::core::ffi::c_float; + let mut literal_float: ::core::ffi::c_float = LITERAL_FLOAT; let mut literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; let mut literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); let mut literal_str: [::core::ffi::c_char; 6] = LITERAL_STR; @@ -78,7 +78,7 @@ pub unsafe extern "C" fn local_muts() { let mut literal_struct: S = LITERAL_STRUCT; let mut nested_int: ::core::ffi::c_int = NESTED_INT; let mut nested_bool: bool = NESTED_BOOL != 0; - let mut nested_float: ::core::ffi::c_float = NESTED_FLOAT as ::core::ffi::c_float; + let mut nested_float: ::core::ffi::c_float = NESTED_FLOAT; let mut nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; let mut nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); let mut nested_str: [::core::ffi::c_char; 6] = NESTED_STR; @@ -91,7 +91,7 @@ pub unsafe extern "C" fn local_muts() { let mut int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; let mut mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut parens: ::core::ffi::c_int = PARENS; @@ -100,7 +100,7 @@ pub unsafe extern "C" fn local_muts() { let mut narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; let mut conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; let mut indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut str_concatenation_ptr: *const ::core::ffi::c_char = b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; let mut str_concatenation: [::core::ffi::c_char; 18] = @@ -109,7 +109,7 @@ pub unsafe extern "C" fn local_muts() { (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut ref_indexing: *const ::core::ffi::c_char = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; let mut ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; let mut ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { @@ -122,9 +122,9 @@ pub unsafe extern "C" fn local_muts() { let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; @@ -141,7 +141,7 @@ pub unsafe extern "C" fn local_consts() { unsafe { let literal_int: ::core::ffi::c_int = LITERAL_INT; let literal_bool: bool = LITERAL_BOOL != 0; - let literal_float: ::core::ffi::c_float = LITERAL_FLOAT as ::core::ffi::c_float; + let literal_float: ::core::ffi::c_float = LITERAL_FLOAT; let literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; let literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); let literal_str: [::core::ffi::c_char; 6] = LITERAL_STR; @@ -153,7 +153,7 @@ pub unsafe extern "C" fn local_consts() { let literal_struct: S = LITERAL_STRUCT; let nested_int: ::core::ffi::c_int = NESTED_INT; let nested_bool: bool = NESTED_BOOL != 0; - let nested_float: ::core::ffi::c_float = NESTED_FLOAT as ::core::ffi::c_float; + let nested_float: ::core::ffi::c_float = NESTED_FLOAT; let nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; let nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); let nested_str: [::core::ffi::c_char; 6] = NESTED_STR; @@ -165,7 +165,7 @@ pub unsafe extern "C" fn local_consts() { let nested_struct: S = NESTED_STRUCT; let int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; let mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let parens: ::core::ffi::c_int = PARENS; @@ -174,7 +174,7 @@ pub unsafe extern "C" fn local_consts() { let narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; let conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; let indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let str_concatenation_ptr: *const ::core::ffi::c_char = b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; let str_concatenation: [::core::ffi::c_char; 18] = @@ -183,7 +183,7 @@ pub unsafe extern "C" fn local_consts() { (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let ref_indexing: *const ::core::ffi::c_char = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; let ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; let ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { @@ -196,9 +196,9 @@ pub unsafe extern "C" fn local_consts() { let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; @@ -212,8 +212,7 @@ pub unsafe extern "C" fn local_consts() { } static mut global_static_const_literal_int: ::core::ffi::c_int = LITERAL_INT; static mut global_static_const_literal_bool: bool = LITERAL_BOOL != 0; -static mut global_static_const_literal_float: ::core::ffi::c_float = - LITERAL_FLOAT as ::core::ffi::c_float; +static mut global_static_const_literal_float: ::core::ffi::c_float = LITERAL_FLOAT; static mut global_static_const_literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; static mut global_static_const_literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); @@ -226,8 +225,7 @@ static mut global_static_const_literal_array: [::core::ffi::c_int; 3] = [ static mut global_static_const_literal_struct: S = LITERAL_STRUCT; static mut global_static_const_nested_int: ::core::ffi::c_int = NESTED_INT; static mut global_static_const_nested_bool: bool = NESTED_BOOL != 0; -static mut global_static_const_nested_float: ::core::ffi::c_float = - NESTED_FLOAT as ::core::ffi::c_float; +static mut global_static_const_nested_float: ::core::ffi::c_float = NESTED_FLOAT; static mut global_static_const_nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; static mut global_static_const_nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); @@ -241,7 +239,8 @@ static mut global_static_const_nested_struct: S = NESTED_STRUCT; static mut global_static_const_int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; static mut global_static_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + (LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; static mut global_static_const_parens: ::core::ffi::c_int = PARENS; static mut global_static_const_ptr_arithmetic: *const ::core::ffi::c_char = @@ -270,8 +269,7 @@ pub static mut global_const_literal_int: ::core::ffi::c_int = LITERAL_INT; #[no_mangle] pub static mut global_const_literal_bool: bool = LITERAL_BOOL != 0; #[no_mangle] -pub static mut global_const_literal_float: ::core::ffi::c_float = - LITERAL_FLOAT as ::core::ffi::c_float; +pub static mut global_const_literal_float: ::core::ffi::c_float = LITERAL_FLOAT; #[no_mangle] pub static mut global_const_literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; #[no_mangle] @@ -291,8 +289,7 @@ pub static mut global_const_nested_int: ::core::ffi::c_int = NESTED_INT; #[no_mangle] pub static mut global_const_nested_bool: bool = NESTED_BOOL != 0; #[no_mangle] -pub static mut global_const_nested_float: ::core::ffi::c_float = - NESTED_FLOAT as ::core::ffi::c_float; +pub static mut global_const_nested_float: ::core::ffi::c_float = NESTED_FLOAT; #[no_mangle] pub static mut global_const_nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; #[no_mangle] @@ -312,7 +309,8 @@ pub static mut global_const_int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; #[no_mangle] pub static mut global_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + (LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; #[no_mangle] pub static mut global_const_parens: ::core::ffi::c_int = PARENS; @@ -447,8 +445,7 @@ pub unsafe extern "C" fn use_local_value() -> ::core::ffi::c_int { #[no_mangle] pub unsafe extern "C" fn use_portable_type(mut len: uintptr_t) -> bool { unsafe { - return len - <= (UINTPTR_MAX as uintptr_t).wrapping_div(2 as ::core::ffi::c_int as uintptr_t); + return len <= UINTPTR_MAX.wrapping_div(2 as ::core::ffi::c_int as uintptr_t); } } #[no_mangle] @@ -472,10 +469,11 @@ pub unsafe extern "C" fn late_init_var() -> ::core::ffi::c_int { unsafe extern "C" fn c2rust_run_static_initializers() { unsafe { global_static_const_ptr_arithmetic = PTR_ARITHMETIC; - global_static_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + global_static_const_indexing = + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; global_static_const_ref_indexing = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; global_static_const_ternary = if LITERAL_BOOL != 0 { 1 as ::core::ffi::c_int @@ -484,10 +482,11 @@ unsafe extern "C" fn c2rust_run_static_initializers() { }; global_static_const_member = LITERAL_STRUCT.i; global_const_ptr_arithmetic = PTR_ARITHMETIC; - global_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + global_const_indexing = + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; global_const_ref_indexing = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; global_const_ternary = if LITERAL_BOOL != 0 { 1 as ::core::ffi::c_int diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap index a79d19245f..7d2ac3e4c9 100644 --- a/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile@macros.c.2024.snap @@ -35,10 +35,10 @@ pub struct ntlmdata { pub target_info_len: ::core::ffi::c_uint, } pub const true_0: ::core::ffi::c_int = 1 as ::core::ffi::c_int; -pub const UINTPTR_MAX: ::core::ffi::c_ulong = 18446744073709551615 as ::core::ffi::c_ulong; +pub const UINTPTR_MAX: uintptr_t = 18446744073709551615 as uintptr_t; pub const LITERAL_INT: ::core::ffi::c_int = 0xffff as ::core::ffi::c_int; pub const LITERAL_BOOL: ::core::ffi::c_int = true_0; -pub const LITERAL_FLOAT: ::core::ffi::c_double = 3.14f64; +pub const LITERAL_FLOAT: ::core::ffi::c_float = 3.14f32; pub const LITERAL_CHAR: ::core::ffi::c_int = 'x' as i32; pub const LITERAL_STR: [::core::ffi::c_char; 6] = unsafe { ::core::mem::transmute::<[u8; 6], [::core::ffi::c_char; 6]>(*b"hello\0") }; @@ -47,7 +47,7 @@ pub const LITERAL_STRUCT: S = S { }; pub const NESTED_INT: ::core::ffi::c_int = LITERAL_INT; pub const NESTED_BOOL: ::core::ffi::c_int = LITERAL_BOOL; -pub const NESTED_FLOAT: ::core::ffi::c_double = LITERAL_FLOAT; +pub const NESTED_FLOAT: ::core::ffi::c_float = LITERAL_FLOAT; pub const NESTED_CHAR: ::core::ffi::c_int = LITERAL_CHAR; pub const NESTED_STR: [::core::ffi::c_char; 6] = LITERAL_STR; pub const NESTED_STRUCT: S = LITERAL_STRUCT; @@ -65,7 +65,7 @@ pub unsafe extern "C" fn local_muts() { unsafe { let mut literal_int: ::core::ffi::c_int = LITERAL_INT; let mut literal_bool: bool = LITERAL_BOOL != 0; - let mut literal_float: ::core::ffi::c_float = LITERAL_FLOAT as ::core::ffi::c_float; + let mut literal_float: ::core::ffi::c_float = LITERAL_FLOAT; let mut literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; let mut literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); let mut literal_str: [::core::ffi::c_char; 6] = LITERAL_STR; @@ -77,7 +77,7 @@ pub unsafe extern "C" fn local_muts() { let mut literal_struct: S = LITERAL_STRUCT; let mut nested_int: ::core::ffi::c_int = NESTED_INT; let mut nested_bool: bool = NESTED_BOOL != 0; - let mut nested_float: ::core::ffi::c_float = NESTED_FLOAT as ::core::ffi::c_float; + let mut nested_float: ::core::ffi::c_float = NESTED_FLOAT; let mut nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; let mut nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); let mut nested_str: [::core::ffi::c_char; 6] = NESTED_STR; @@ -90,7 +90,7 @@ pub unsafe extern "C" fn local_muts() { let mut int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; let mut mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut parens: ::core::ffi::c_int = PARENS; @@ -99,7 +99,7 @@ pub unsafe extern "C" fn local_muts() { let mut narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; let mut conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; let mut indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut str_concatenation_ptr: *const ::core::ffi::c_char = b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; let mut str_concatenation: [::core::ffi::c_char; 18] = @@ -108,7 +108,7 @@ pub unsafe extern "C" fn local_muts() { (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut ref_indexing: *const ::core::ffi::c_char = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; let mut ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; let mut ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { @@ -121,9 +121,9 @@ pub unsafe extern "C" fn local_muts() { let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; @@ -140,7 +140,7 @@ pub unsafe extern "C" fn local_consts() { unsafe { let literal_int: ::core::ffi::c_int = LITERAL_INT; let literal_bool: bool = LITERAL_BOOL != 0; - let literal_float: ::core::ffi::c_float = LITERAL_FLOAT as ::core::ffi::c_float; + let literal_float: ::core::ffi::c_float = LITERAL_FLOAT; let literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; let literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); let literal_str: [::core::ffi::c_char; 6] = LITERAL_STR; @@ -152,7 +152,7 @@ pub unsafe extern "C" fn local_consts() { let literal_struct: S = LITERAL_STRUCT; let nested_int: ::core::ffi::c_int = NESTED_INT; let nested_bool: bool = NESTED_BOOL != 0; - let nested_float: ::core::ffi::c_float = NESTED_FLOAT as ::core::ffi::c_float; + let nested_float: ::core::ffi::c_float = NESTED_FLOAT; let nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; let nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); let nested_str: [::core::ffi::c_char; 6] = NESTED_STR; @@ -164,7 +164,7 @@ pub unsafe extern "C" fn local_consts() { let nested_struct: S = NESTED_STRUCT; let int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; let mixed_arithmetic: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let parens: ::core::ffi::c_int = PARENS; @@ -173,7 +173,7 @@ pub unsafe extern "C" fn local_consts() { let narrowing_cast: ::core::ffi::c_char = LITERAL_INT as ::core::ffi::c_char; let conversion_cast: ::core::ffi::c_double = CONVERSION_CAST; let indexing: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let str_concatenation_ptr: *const ::core::ffi::c_char = b"hello hello world\0".as_ptr() as *const ::core::ffi::c_char; let str_concatenation: [::core::ffi::c_char; 18] = @@ -182,7 +182,7 @@ pub unsafe extern "C" fn local_consts() { (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let ref_indexing: *const ::core::ffi::c_char = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; let ref_struct: *const S = &mut LITERAL_STRUCT as *mut S; let ternary: ::core::ffi::c_int = if LITERAL_BOOL != 0 { @@ -195,9 +195,9 @@ pub unsafe extern "C" fn local_consts() { let mut builtin_0: ::core::ffi::c_int = (LITERAL_INT as ::core::ffi::c_uint).leading_zeros() as i32; let mut indexing_0: ::core::ffi::c_char = - NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; let mut mixed: ::core::ffi::c_float = (LITERAL_INT as ::core::ffi::c_double - + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; let mut i: ::core::ffi::c_int = 0 as ::core::ffi::c_int; @@ -211,8 +211,7 @@ pub unsafe extern "C" fn local_consts() { } static mut global_static_const_literal_int: ::core::ffi::c_int = LITERAL_INT; static mut global_static_const_literal_bool: bool = LITERAL_BOOL != 0; -static mut global_static_const_literal_float: ::core::ffi::c_float = - LITERAL_FLOAT as ::core::ffi::c_float; +static mut global_static_const_literal_float: ::core::ffi::c_float = LITERAL_FLOAT; static mut global_static_const_literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; static mut global_static_const_literal_str_ptr: *const ::core::ffi::c_char = LITERAL_STR.as_ptr(); @@ -225,8 +224,7 @@ static mut global_static_const_literal_array: [::core::ffi::c_int; 3] = [ static mut global_static_const_literal_struct: S = LITERAL_STRUCT; static mut global_static_const_nested_int: ::core::ffi::c_int = NESTED_INT; static mut global_static_const_nested_bool: bool = NESTED_BOOL != 0; -static mut global_static_const_nested_float: ::core::ffi::c_float = - NESTED_FLOAT as ::core::ffi::c_float; +static mut global_static_const_nested_float: ::core::ffi::c_float = NESTED_FLOAT; static mut global_static_const_nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; static mut global_static_const_nested_str_ptr: *const ::core::ffi::c_char = NESTED_STR.as_ptr(); @@ -240,7 +238,8 @@ static mut global_static_const_nested_struct: S = NESTED_STRUCT; static mut global_static_const_int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; static mut global_static_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + (LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; static mut global_static_const_parens: ::core::ffi::c_int = PARENS; static mut global_static_const_ptr_arithmetic: *const ::core::ffi::c_char = @@ -269,8 +268,7 @@ pub static mut global_const_literal_int: ::core::ffi::c_int = LITERAL_INT; #[unsafe(no_mangle)] pub static mut global_const_literal_bool: bool = LITERAL_BOOL != 0; #[unsafe(no_mangle)] -pub static mut global_const_literal_float: ::core::ffi::c_float = - LITERAL_FLOAT as ::core::ffi::c_float; +pub static mut global_const_literal_float: ::core::ffi::c_float = LITERAL_FLOAT; #[unsafe(no_mangle)] pub static mut global_const_literal_char: ::core::ffi::c_char = LITERAL_CHAR as ::core::ffi::c_char; #[unsafe(no_mangle)] @@ -290,8 +288,7 @@ pub static mut global_const_nested_int: ::core::ffi::c_int = NESTED_INT; #[unsafe(no_mangle)] pub static mut global_const_nested_bool: bool = NESTED_BOOL != 0; #[unsafe(no_mangle)] -pub static mut global_const_nested_float: ::core::ffi::c_float = - NESTED_FLOAT as ::core::ffi::c_float; +pub static mut global_const_nested_float: ::core::ffi::c_float = NESTED_FLOAT; #[unsafe(no_mangle)] pub static mut global_const_nested_char: ::core::ffi::c_char = NESTED_CHAR as ::core::ffi::c_char; #[unsafe(no_mangle)] @@ -311,7 +308,8 @@ pub static mut global_const_int_arithmetic: ::core::ffi::c_int = NESTED_INT + LITERAL_INT + 1 as ::core::ffi::c_int; #[unsafe(no_mangle)] pub static mut global_const_mixed_arithmetic: ::core::ffi::c_float = - (LITERAL_INT as ::core::ffi::c_double + NESTED_FLOAT * LITERAL_CHAR as ::core::ffi::c_double + (LITERAL_INT as ::core::ffi::c_double + + NESTED_FLOAT as ::core::ffi::c_double * LITERAL_CHAR as ::core::ffi::c_double - true_0 as ::core::ffi::c_double) as ::core::ffi::c_float; #[unsafe(no_mangle)] pub static mut global_const_parens: ::core::ffi::c_int = PARENS; @@ -446,8 +444,7 @@ pub unsafe extern "C" fn use_local_value() -> ::core::ffi::c_int { #[unsafe(no_mangle)] pub unsafe extern "C" fn use_portable_type(mut len: uintptr_t) -> bool { unsafe { - return len - <= (UINTPTR_MAX as uintptr_t).wrapping_div(2 as ::core::ffi::c_int as uintptr_t); + return len <= UINTPTR_MAX.wrapping_div(2 as ::core::ffi::c_int as uintptr_t); } } #[unsafe(no_mangle)] @@ -471,10 +468,11 @@ pub unsafe extern "C" fn late_init_var() -> ::core::ffi::c_int { unsafe extern "C" fn c2rust_run_static_initializers() { unsafe { global_static_const_ptr_arithmetic = PTR_ARITHMETIC; - global_static_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + global_static_const_indexing = + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; global_static_const_ref_indexing = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; global_static_const_ternary = if LITERAL_BOOL != 0 { 1 as ::core::ffi::c_int @@ -483,10 +481,11 @@ unsafe extern "C" fn c2rust_run_static_initializers() { }; global_static_const_member = LITERAL_STRUCT.i; global_const_ptr_arithmetic = PTR_ARITHMETIC; - global_const_indexing = NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_int as usize]; + global_const_indexing = + NESTED_STR[LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as usize]; global_const_ref_indexing = NESTED_STR .as_ptr() - .offset(LITERAL_FLOAT as ::core::ffi::c_int as isize) + .offset(LITERAL_FLOAT as ::core::ffi::c_double as ::core::ffi::c_int as isize) as *const ::core::ffi::c_char; global_const_ternary = if LITERAL_BOOL != 0 { 1 as ::core::ffi::c_int From 314cfc347d91c5144e6046e3d8d743623a0cccc3 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 22 Mar 2026 20:46:09 +0100 Subject: [PATCH 8/9] transpile: Remove `override_ty` param from `convert_expr` --- c2rust-transpile/src/cfg/mod.rs | 21 +-- c2rust-transpile/src/translator/assembly.rs | 4 +- c2rust-transpile/src/translator/atomics.rs | 8 +- c2rust-transpile/src/translator/builtins.rs | 64 ++++----- c2rust-transpile/src/translator/literals.rs | 10 +- c2rust-transpile/src/translator/macros.rs | 2 +- c2rust-transpile/src/translator/mod.rs | 135 +++++++----------- .../src/translator/named_references.rs | 2 +- c2rust-transpile/src/translator/operators.rs | 50 ++++--- c2rust-transpile/src/translator/pointers.rs | 14 +- c2rust-transpile/src/translator/simd.rs | 11 +- .../src/translator/structs_unions.rs | 14 +- c2rust-transpile/src/translator/variadic.rs | 2 +- 13 files changed, 144 insertions(+), 193 deletions(-) diff --git a/c2rust-transpile/src/cfg/mod.rs b/c2rust-transpile/src/cfg/mod.rs index 55e916bde3..2668f96015 100644 --- a/c2rust-transpile/src/cfg/mod.rs +++ b/c2rust-transpile/src/cfg/mod.rs @@ -625,9 +625,7 @@ impl Cfg { wip.body.push(StmtOrDecl::Stmt(mk().semi_stmt(ret_expr))); } ImplicitReturnType::StmtExpr(ctx, expr_id, brk_label) => { - let (stmts, val) = translator - .convert_expr(ctx, expr_id, None)? - .discard_unsafe(); + let (stmts, val) = translator.convert_expr(ctx, expr_id)?.discard_unsafe(); wip.body.extend(stmts.into_iter().map(StmtOrDecl::Stmt)); wip.body.push(StmtOrDecl::Stmt(mk().semi_stmt( @@ -1432,7 +1430,7 @@ impl CfgBuilder { } CStmtKind::Return(expr) => { - let val = match expr.map(|i| translator.convert_expr(ctx.used(), i, ret_ty)) { + let val = match expr.map(|i| translator.convert_expr(ctx.used(), i)) { Some(r) => Some(r?), None => None, }; @@ -1696,9 +1694,8 @@ impl CfgBuilder { match increment { None => slf.add_block(incr_entry, BasicBlock::new_jump(cond_entry)), Some(incr) => { - let incr_stmts = translator - .convert_expr(ctx.unused(), incr, None)? - .into_stmts(); + let incr_stmts = + translator.convert_expr(ctx.unused(), incr)?.into_stmts(); let mut incr_wip = slf.new_wip_block(incr_entry); incr_wip.extend(incr_stmts); slf.add_wip_block(incr_wip, Jump(cond_entry)); @@ -1809,11 +1806,7 @@ impl CfgBuilder { match blk_or_wip { Ok(blk) => Ok(blk), Err(mut wip) => { - wip.extend( - translator - .convert_expr(ctx.unused(), expr, None)? - .into_stmts(), - ); + wip.extend(translator.convert_expr(ctx.unused(), expr)?.into_stmts()); // If we can tell the expression is going to diverge, there is no falling through to // the next block. @@ -1873,7 +1866,7 @@ impl CfgBuilder { let branch = match translator.ast_context.index(resolved).kind { CExprKind::Literal(..) | CExprKind::ConstantExpr(_, _, Some(_)) => { match translator - .convert_expr(ctx.used(), resolved, None)? + .convert_expr(ctx.used(), resolved)? .to_pure_expr() { Some(expr) => match *expr { @@ -1951,7 +1944,7 @@ impl CfgBuilder { // Convert the condition let (stmts, val) = translator - .convert_expr(ctx.used(), scrutinee, None)? + .convert_expr(ctx.used(), scrutinee)? .discard_unsafe(); wip.extend(stmts); diff --git a/c2rust-transpile/src/translator/assembly.rs b/c2rust-transpile/src/translator/assembly.rs index 35270421dc..3fccad1468 100644 --- a/c2rust-transpile/src/translator/assembly.rs +++ b/c2rust-transpile/src/translator/assembly.rs @@ -874,7 +874,7 @@ impl<'c> Translation<'c> { // First, convert output expr if present let out_expr = if let Some((output_idx, out_expr)) = operand.out_expr { - let mut out_expr = self.convert_expr(ctx.used(), out_expr, None)?; + let mut out_expr = self.convert_expr(ctx.used(), out_expr)?; stmts.append(out_expr.stmts_mut()); let mut out_expr = out_expr.into_value(); @@ -919,7 +919,7 @@ impl<'c> Translation<'c> { // Then, handle input expr if present let in_expr = if let Some((input_idx, in_expr)) = operand.in_expr { - let mut in_expr = self.convert_expr(ctx.used(), in_expr, None)?; + let mut in_expr = self.convert_expr(ctx.used(), in_expr)?; stmts.append(in_expr.stmts_mut()); let mut in_expr = in_expr.into_value(); diff --git a/c2rust-transpile/src/translator/atomics.rs b/c2rust-transpile/src/translator/atomics.rs index 1943e3d3b2..59e02af32a 100644 --- a/c2rust-transpile/src/translator/atomics.rs +++ b/c2rust-transpile/src/translator/atomics.rs @@ -144,14 +144,14 @@ impl<'c> Translation<'c> { val2_id: Option, weak_id: Option, ) -> TranslationResult>> { - let ptr = self.convert_expr(ctx.used(), ptr_id, None)?; + let ptr = self.convert_expr(ctx.used(), ptr_id)?; let order = self.convert_memordering(order_id); let val1 = val1_id - .map(|x| self.convert_expr(ctx.used(), x, None)) + .map(|x| self.convert_expr(ctx.used(), x)) .transpose()?; let order_fail = order_fail_id.and_then(|x| self.convert_memordering(x)); let val2 = val2_id - .map(|x| self.convert_expr(ctx.used(), x, None)) + .map(|x| self.convert_expr(ctx.used(), x)) .transpose()?; let weak = weak_id.and_then(|x| self.convert_constant_bool(x)); @@ -244,7 +244,7 @@ impl<'c> Translation<'c> { if name == "__atomic_exchange" { // LLVM stores the ret pointer in the order_fail slot order_fail_id - .map(|x| self.convert_expr(ctx.used(), x, None)) + .map(|x| self.convert_expr(ctx.used(), x)) .transpose()? .expect("__atomic_exchange must have a ret pointer argument") .and_then(|ret| { diff --git a/c2rust-transpile/src/translator/builtins.rs b/c2rust-transpile/src/translator/builtins.rs index fec0c861e4..c6990835f8 100644 --- a/c2rust-transpile/src/translator/builtins.rs +++ b/c2rust-transpile/src/translator/builtins.rs @@ -29,8 +29,8 @@ impl<'c> Translation<'c> { rotate_method_name: &'static str, ) -> TranslationResult>> { // Emit `arg0.{method_name}(arg1)` - let arg0 = self.convert_expr(ctx.used(), args[0], None)?; - let arg1 = self.convert_expr(ctx.used(), args[1], None)?; + let arg0 = self.convert_expr(ctx.used(), args[0])?; + let arg1 = self.convert_expr(ctx.used(), args[1])?; arg0.and_then(|arg0| { arg1.and_then(|arg1| { let arg1 = mk().cast_expr(arg1, mk().path_ty(vec!["u32"])); @@ -105,7 +105,7 @@ impl<'c> Translation<'c> { }); } - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|v| { let val = mk().method_call_expr(v, "is_sign_negative", vec![]); @@ -114,7 +114,7 @@ impl<'c> Translation<'c> { })) } "__builtin_ffs" | "__builtin_ffsl" | "__builtin_ffsll" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| { let add = BinOp::Add(Default::default()); @@ -131,29 +131,29 @@ impl<'c> Translation<'c> { })) } "__builtin_clz" | "__builtin_clzl" | "__builtin_clzll" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| { let zeros = mk().method_call_expr(x, "leading_zeros", vec![]); mk().cast_expr(zeros, mk().path_ty(vec!["i32"])) })) } "__builtin_ctz" | "__builtin_ctzl" | "__builtin_ctzll" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| { let zeros = mk().method_call_expr(x, "trailing_zeros", vec![]); mk().cast_expr(zeros, mk().path_ty(vec!["i32"])) })) } "__builtin_bswap16" | "__builtin_bswap32" | "__builtin_bswap64" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| mk().method_call_expr(x, "swap_bytes", vec![]))) } "__builtin_fabs" | "__builtin_fabsf" | "__builtin_fabsl" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| mk().method_call_expr(x, "abs", vec![]))) } "__builtin_isfinite" | "__builtin_isnan" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; let seg = match builtin_name { "__builtin_isfinite" => "is_finite", @@ -167,7 +167,7 @@ impl<'c> Translation<'c> { } "__builtin_isinf_sign" => { // isinf_sign(x) -> fabs(x) == infinity ? (signbit(x) ? -1 : 1) : 0 - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| { let inner_cond = mk().method_call_expr(x.clone(), "is_sign_positive", vec![]); let one = mk().lit_expr(mk().int_lit(1, "")); @@ -189,18 +189,18 @@ impl<'c> Translation<'c> { // https://github.com/llvm-mirror/llvm/blob/master/lib/CodeGen/IntrinsicLowering.cpp#L470 Ok(WithStmts::new_val(mk().lit_expr(mk().int_lit(1, "i32")))) } - "__builtin_expect" => self.convert_expr(ctx.used(), args[0], None), + "__builtin_expect" => self.convert_expr(ctx.used(), args[0]), "__builtin_popcount" | "__builtin_popcountl" | "__builtin_popcountll" => { - let val = self.convert_expr(ctx.used(), args[0], None)?; + let val = self.convert_expr(ctx.used(), args[0])?; Ok(val.map(|x| { let zeros = mk().method_call_expr(x, "count_ones", vec![]); mk().cast_expr(zeros, mk().path_ty(vec!["i32"])) })) } "__builtin_bzero" => { - let ptr_stmts = self.convert_expr(ctx.used(), args[0], None)?; - let n_stmts = self.convert_expr(ctx.used(), args[1], None)?; + let ptr_stmts = self.convert_expr(ctx.used(), args[0])?; + let n_stmts = self.convert_expr(ctx.used(), args[1])?; let write_bytes = mk().abs_path_expr(vec!["core", "ptr", "write_bytes"]); let zero = mk().lit_expr(mk().int_lit(0, "u8")); ptr_stmts.and_then(|ptr| { @@ -211,7 +211,7 @@ impl<'c> Translation<'c> { // If the target does not support data prefetch, the address expression is evaluated if // it includes side effects but no other code is generated and GCC does not issue a warning. // void __builtin_prefetch (const void *addr, ...); - "__builtin_prefetch" => self.convert_expr(ctx.unused(), args[0], None), + "__builtin_prefetch" => self.convert_expr(ctx.unused(), args[0]), "__builtin_memcpy" | "__builtin_memcmp" | "__builtin_memmove" | "__builtin_strncmp" | "__builtin_strncpy" | "__builtin_strncat" => self.convert_libc_fns( @@ -289,8 +289,8 @@ impl<'c> Translation<'c> { // We can't convert this to Rust, but it should be safe to always return -1/0 // (depending on the value of `type`), so we emit the following: // `(if (type & 2) == 0 { -1isize } else { 0isize }) as libc::size_t` - let ptr_arg = self.convert_expr(ctx.unused(), args[0], None)?; - let type_arg = self.convert_expr(ctx.used(), args[1], None)?; + let ptr_arg = self.convert_expr(ctx.unused(), args[0])?; + let type_arg = self.convert_expr(ctx.used(), args[1])?; ptr_arg.and_then(|_| { Ok(type_arg.map(|type_arg| { let type_and_2 = mk().binary_expr( @@ -323,7 +323,7 @@ impl<'c> Translation<'c> { if ctx.is_unused() && 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)?; + let dst = self.convert_expr(ctx.used(), args[0])?; let fn_ctx = self.function_context.borrow(); let src = fn_ctx.get_va_list_arg_name(); @@ -344,8 +344,8 @@ impl<'c> Translation<'c> { "__builtin_va_copy" => { if ctx.is_unused() && 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)?; + let dst = self.convert_expr(ctx.used(), args[0])?; + let src = self.convert_expr(ctx.used(), args[1])?; let call_expr = mk().method_call_expr(src.to_expr(), "clone", vec![]); let assign_expr = mk().assign_expr(dst.to_expr(), call_expr); @@ -370,7 +370,7 @@ impl<'c> Translation<'c> { } "__builtin_alloca" => { - let count = self.convert_expr(ctx.used(), args[0], None)?; + let count = self.convert_expr(ctx.used(), args[0])?; count.and_then(|count| { // Get `alloca` allocation storage. let mut fn_ctx = self.function_context.borrow_mut(); @@ -536,9 +536,9 @@ impl<'c> Translation<'c> { | "__sync_bool_compare_and_swap_4" | "__sync_bool_compare_and_swap_8" | "__sync_bool_compare_and_swap_16" => { - let arg0 = self.convert_expr(ctx.used(), args[0], None)?; - let arg1 = self.convert_expr(ctx.used(), args[1], None)?; - let arg2 = self.convert_expr(ctx.used(), args[2], None)?; + let arg0 = self.convert_expr(ctx.used(), args[0])?; + let arg1 = self.convert_expr(ctx.used(), args[1])?; + let arg2 = self.convert_expr(ctx.used(), args[2])?; arg0.and_then(|arg0| { arg1.and_then(|arg1| { arg2.and_then(|arg2| { @@ -632,8 +632,8 @@ impl<'c> Translation<'c> { "and" }; - let arg0 = self.convert_expr(ctx.used(), args[0], None)?; - let arg1 = self.convert_expr(ctx.used(), args[1], None)?; + let arg0 = self.convert_expr(ctx.used(), args[0])?; + let arg1 = self.convert_expr(ctx.used(), args[1])?; let fetch_first = builtin_name.starts_with("__sync_fetch"); arg0.and_then(|arg0| { arg1.and_then(|arg1| { @@ -659,8 +659,8 @@ impl<'c> Translation<'c> { | "__sync_lock_test_and_set_16" => { // Emit `atomic_xchg_acquire(arg0, arg1)` let atomic_func = self.atomic_intrinsic_expr("xchg", &[Acquire]); - let arg0 = self.convert_expr(ctx.used(), args[0], None)?; - let arg1 = self.convert_expr(ctx.used(), args[1], None)?; + let arg0 = self.convert_expr(ctx.used(), args[0])?; + let arg1 = self.convert_expr(ctx.used(), args[1])?; arg0.and_then(|arg0| { arg1.and_then(|arg1| { let call_expr = mk().call_expr(atomic_func, vec![arg0, arg1]); @@ -680,7 +680,7 @@ impl<'c> Translation<'c> { | "__sync_lock_release_16" => { // Emit `atomic_store_release(arg0, 0)` let atomic_func = self.atomic_intrinsic_expr("store", &[Release]); - let arg0 = self.convert_expr(ctx.used(), args[0], None)?; + let arg0 = self.convert_expr(ctx.used(), args[0])?; arg0.and_then(|arg0| { let zero = mk().lit_expr(mk().int_lit(0, "")); let call_expr = mk().call_expr(atomic_func, vec![arg0, zero]); @@ -693,7 +693,7 @@ impl<'c> Translation<'c> { } // There's currently no way to replicate this functionality in Rust, so we just // pass the ptr input param in its place. - "__builtin_assume_aligned" => Ok(self.convert_expr(ctx.used(), args[0], None)?), + "__builtin_assume_aligned" => Ok(self.convert_expr(ctx.used(), args[0])?), // Skip over, there's no way to implement it in Rust "__builtin_unwind_init" => Ok(WithStmts::new_val(self.panic_or_err("no value"))), "__builtin_unreachable" => Ok(WithStmts::new( @@ -731,7 +731,7 @@ impl<'c> Translation<'c> { method_name: &str, args: &[CExprId], ) -> TranslationResult>> { - let args = self.convert_exprs(ctx.used(), args, None)?; + let args = self.convert_exprs(ctx.used(), args)?; args.and_then(|args| { let [a, b, c]: [_; 3] = args .try_into() @@ -771,7 +771,7 @@ impl<'c> Translation<'c> { let name = &builtin_name[10..]; self.use_crate(ExternCrate::Libc); let mem = mk().abs_path_expr(vec!["libc", name]); - let args = self.convert_exprs(ctx.used(), args, None)?; + let args = self.convert_exprs(ctx.used(), args)?; args.and_then(|args| { if args.len() != arg_types.len() { // This should not generally happen, as the C frontend checks these first diff --git a/c2rust-transpile/src/translator/literals.rs b/c2rust-transpile/src/translator/literals.rs index 67581995d4..9bb9a90310 100644 --- a/c2rust-transpile/src/translator/literals.rs +++ b/c2rust-transpile/src/translator/literals.rs @@ -137,7 +137,7 @@ impl<'c> Translation<'c> { // Convert all of the provided initializer values let to_array_element = |id: CExprId| -> TranslationResult<_> { - self.convert_expr(ctx.used(), id, None)?.result_map(|x| { + self.convert_expr(ctx.used(), id)?.result_map(|x| { // Array literals require all of their elements to be // the correct type; they will not use implicit casts to // change mut to const. This becomes a problem when an @@ -201,7 +201,7 @@ impl<'c> Translation<'c> { // * `ptr_extra_braces` // * `array_of_ptrs` // * `array_of_arrays` - self.convert_expr(ctx.used(), single, None) + self.convert_expr(ctx.used(), single) } &[single] if is_zero_literal(single) && n > 1 => { // This was likely a C array of the form `int x[16] = { 0 }`. @@ -233,18 +233,18 @@ impl<'c> Translation<'c> { } CTypeKind::Pointer(_) => { let id = ids.first().unwrap(); - self.convert_expr(ctx.used(), *id, None) + self.convert_expr(ctx.used(), *id) } CTypeKind::Enum(_) => { let id = ids.first().unwrap(); - self.convert_expr(ctx.used(), *id, None) + self.convert_expr(ctx.used(), *id) } CTypeKind::Vector(CQualTypeId { ctype, .. }, len) => { self.vector_list_initializer(ctx, ids, ctype, len) } ref kind if kind.is_integral_type() => { let id = ids.first().unwrap(); - self.convert_expr(ctx.used(), *id, None) + self.convert_expr(ctx.used(), *id) } ref t => Err(format_err!("Init list not implemented for {:?}", t).into()), } diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index 975b38e8de..de0566d1f7 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -74,8 +74,8 @@ impl<'c> Translation<'c> { .try_fold::>, CTypeId)>, _, _>(None, |canonical, &id| { self.can_convert_const_macro_expansion(id)?; + let expr = self.convert_expr(ctx, id)?; let override_ty = self.expr_override_types.get(&id).copied(); - let expr = self.convert_expr(ctx, id, override_ty)?; let ty = override_ty .or_else(|| self.ast_context[id].kind.get_qual_type()) .ok_or_else(|| format_err!("Invalid expression type"))? diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index ca6b930ab1..e76683366d 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -2962,7 +2962,7 @@ impl<'c> Translation<'c> { let null_pointer_case = |ptr: CExprId, is_null: bool| -> TranslationResult>> { - let val = self.convert_expr(ctx.used().decay_ref(), ptr, None)?; + let val = self.convert_expr(ctx.used().decay_ref(), ptr)?; let ptr_type = self.ast_context[ptr] .kind .get_type() @@ -3005,7 +3005,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.used().decay_ref(), cond_id)?; val.result_map(|e| self.match_bool(ctx, target, ty_id, e)) } } @@ -3329,7 +3329,7 @@ impl<'c> Translation<'c> { typ: CQualTypeId, ) -> TranslationResult { let init = match initializer { - Some(x) => self.convert_expr(ctx.used(), x, Some(typ)), + Some(x) => self.convert_expr(ctx.used(), x), None => self.implicit_default_expr(ctx, typ.ctype), }; @@ -3510,26 +3510,24 @@ impl<'c> Translation<'c> { type_id = elt; // Convert this expression - let expr = self - .convert_expr(ctx.used(), expr_id, None)? - .and_then(|expr| { - let name = self - .renamer - .borrow_mut() - .insert(CDeclId(expr_id.0), "vla") - .unwrap(); // try using declref name? - // TODO: store the name corresponding to expr_id - - let local = mk().local( - mk().ident_pat(name), - None, - Some(mk().cast_expr(expr, mk().path_ty(vec!["usize"]))), - ); + let expr = self.convert_expr(ctx.used(), expr_id)?.and_then(|expr| { + let name = self + .renamer + .borrow_mut() + .insert(CDeclId(expr_id.0), "vla") + .unwrap(); // try using declref name? + // TODO: store the name corresponding to expr_id - let res: TranslationResult> = - Ok(WithStmts::new(vec![mk().local_stmt(Box::new(local))], ())); - res - })?; + let local = mk().local( + mk().ident_pat(name), + None, + Some(mk().cast_expr(expr, mk().path_ty(vec!["usize"]))), + ); + + let res: TranslationResult> = + Ok(WithStmts::new(vec![mk().local_stmt(Box::new(local))], ())); + res + })?; stmts.extend(expr.into_stmts()); } @@ -3553,7 +3551,7 @@ impl<'c> Translation<'c> { let elts = self.compute_size_of_type(ctx, elts, override_ty)?; return elts.and_then(|lhs| { - let len = self.convert_expr(ctx.used().not_static(), len, override_ty)?; + let len = self.convert_expr(ctx.used().not_static(), len)?; Ok(len.map(|len| { let rhs = cast_int(len, "usize", true); mk().binary_expr(BinOp::Mul(Default::default()), lhs, rhs) @@ -3635,13 +3633,10 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, exprs: &[CExprId], - arg_tys: Option<&[CQualTypeId]>, ) -> TranslationResult>>> { - assert!(arg_tys.map(|tys| tys.len() == exprs.len()).unwrap_or(true)); exprs .iter() - .enumerate() - .map(|(n, arg)| self.convert_expr(ctx, *arg, arg_tys.map(|tys| tys[n]))) + .map(|arg| self.convert_expr(ctx, *arg)) .collect() } @@ -3653,23 +3648,10 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, exprs: &[CExprId], - arg_tys: Option<&[CQualTypeId]>, - is_variadic: bool, ) -> TranslationResult>>> { - let arg_tys = if let Some(arg_tys) = arg_tys { - if !is_variadic { - assert!(arg_tys.len() == exprs.len()); - } - - arg_tys - } else { - &[] - }; - exprs .iter() - .enumerate() - .map(|(n, arg)| self.convert_call_arg(ctx, *arg, arg_tys.get(n).copied())) + .map(|arg| self.convert_call_arg(ctx, *arg)) .collect() } @@ -3690,7 +3672,6 @@ impl<'c> Translation<'c> { &self, mut ctx: ExprContext, expr_id: CExprId, - override_ty: Option, ) -> TranslationResult>> { let Located { loc: src_loc, @@ -3703,6 +3684,8 @@ impl<'c> Translation<'c> { self.ast_context[expr_id] ); + let override_ty = self.expr_override_types.get(&expr_id).copied(); + if let Some(converted) = self.convert_const_macro_expansion(ctx, expr_id, override_ty)? { return Ok(converted); } @@ -3763,11 +3746,11 @@ impl<'c> Translation<'c> { Ok(result) } - ConstantExpr(ty, child, value) => { + ConstantExpr(_ty, child, value) => { if let Some(constant) = value { self.convert_constant(constant).map(WithStmts::new_val) } else { - self.convert_expr(ctx, child, Some(ty)) + self.convert_expr(ctx, child) } } @@ -3921,7 +3904,7 @@ impl<'c> Translation<'c> { // Index Expr let expr = self - .convert_expr(ctx, *expr_id, None)? + .convert_expr(ctx, *expr_id)? .to_pure_expr() .ok_or_else(|| { format_err!("Expected Variable offsetof to be a side-effect free") @@ -4010,7 +3993,7 @@ impl<'c> Translation<'c> { WithStmts::new_val(self.panic_or_err("val is not supposed to be used")) } else if is_explicit { let stmts = self.compute_variable_array_sizes(ctx, ty.ctype)?; - let mut val = self.convert_expr(ctx, expr, None)?; + let mut val = self.convert_expr(ctx, expr)?; val.prepend_stmts(stmts); val } else { @@ -4023,19 +4006,11 @@ impl<'c> Translation<'c> { (override_ty, &self.ast_context[expr].kind) { if self.ast_context.literal_matches_ty(lit, ty) { - return self.convert_expr(ctx, expr, override_ty); + return self.convert_expr(ctx, expr); } } - // LValueToRValue casts don't actually change the type, so it still makes sense - // to translate their inner expression with the expected type from outside the - // cast. - if kind == CastKind::LValueToRValue - && Some(source_ty.ctype) != override_ty.map(|x| x.ctype) - { - self.convert_expr(ctx, expr, override_ty)? - } else { - self.convert_expr(ctx, expr, None)? - } + + self.convert_expr(ctx, expr)? }; // Shuffle Vector "function" builtins will add a cast to the output of the // builtin call which is unnecessary for translation purposes @@ -4060,7 +4035,7 @@ impl<'c> Translation<'c> { self.convert_unary_operator(ctx, op, override_ty.unwrap_or(type_id), arg, lrvalue) } - Conditional(ty, cond, lhs, rhs) => { + Conditional(_ty, cond, lhs, rhs) => { if ctx.is_const { return Err(format_translation_err!( self.ast_context.display_loc(src_loc), @@ -4069,8 +4044,8 @@ impl<'c> Translation<'c> { } let cond = self.convert_condition(ctx, 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)))?; + let lhs = self.convert_expr(ctx, lhs)?; + let rhs = self.convert_expr(ctx, rhs)?; if ctx.is_unused() { let is_unsafe = lhs.is_unsafe() || rhs.is_unsafe(); @@ -4104,7 +4079,7 @@ impl<'c> Translation<'c> { BinaryConditional(ty, lhs, rhs) => { if ctx.is_unused() { let mut lhs = self.convert_condition(ctx, false, lhs)?; - let rhs = self.convert_expr(ctx, rhs, None)?; + let rhs = self.convert_expr(ctx, rhs)?; lhs.merge_unsafe(rhs.is_unsafe()); lhs.and_then(|val| { @@ -4128,7 +4103,7 @@ impl<'c> Translation<'c> { let ite = mk().ifte_expr( cond, mk().block(vec![mk().expr_stmt(lhs_val)]), - Some(self.convert_expr(ctx, rhs, None)?.to_expr()), + Some(self.convert_expr(ctx, rhs)?.to_expr()), ); Ok(ite) }, @@ -4166,14 +4141,6 @@ impl<'c> Translation<'c> { _ => false, }; - let mut arg_tys = if let Some(CDeclKind::Function { parameters, .. }) = - self.ast_context.fn_declref_decl(func) - { - self.ast_context.tys_of_params(parameters) - } else { - None - }; - let func = match self.ast_context[func].kind { // Direct function call CExprKind::ImplicitCast(_, fexp, CastKind::FunctionToPointerDecay, _, _) @@ -4181,7 +4148,7 @@ impl<'c> Translation<'c> { // callee is a declref if matches!(self.ast_context[fexp].kind, CExprKind::DeclRef(..)) => { - self.convert_expr(ctx.used(), fexp, None)? + self.convert_expr(ctx.used(), fexp)? } // Builtin function call @@ -4191,7 +4158,7 @@ impl<'c> Translation<'c> { // Function pointer call _ => { - let mut callee = self.convert_expr(ctx.used(), func, None)?; + let mut callee = self.convert_expr(ctx.used(), func)?; let make_fn_ty = |ret_ty: Box| { let ret_ty = match *ret_ty { Type::Tuple(TypeTuple { elems: ref v, .. }) if v.is_empty() => ReturnType::Default, @@ -4224,8 +4191,7 @@ impl<'c> Translation<'c> { transmute_expr(mk().infer_ty(), target_ty, fn_ptr) }) } - Some(CTypeKind::Function(_, ty_arg_tys, ..)) => { - arg_tys = Some(ty_arg_tys.clone()); + Some(CTypeKind::Function(..)) => { // Normal function pointer callee.map(unwrap_function_pointer) } @@ -4238,8 +4204,7 @@ impl<'c> Translation<'c> { // We want to decay refs only when function is variadic ctx.decay_ref = DecayRef::from(is_variadic); - let args = - self.convert_call_args(ctx.used(), args, arg_tys.as_deref(), is_variadic)?; + let args = self.convert_call_args(ctx.used(), args)?; let mut call_expr = args.map(|args| mk().call_expr(func, args)); if let Some(expected_ty) = override_ty { @@ -4264,12 +4229,12 @@ impl<'c> Translation<'c> { self.convert_member_expr(ctx, qual_ty, expr, decl, kind, override_ty) } - Paren(_, val) => self.convert_expr(ctx, val, override_ty), + Paren(_, val) => self.convert_expr(ctx, val), CompoundLiteral(qty, val) => { if !ctx.needs_address() || ctx.is_const { // consts have their intermediates' lifetimes extended. - return self.convert_expr(ctx, val, override_ty); + return self.convert_expr(ctx, val); } // C compound literals are lvalues, but equivalent Rust expressions generally are not. @@ -4279,7 +4244,7 @@ impl<'c> Translation<'c> { // 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)?; + let val = self.convert_expr(ctx.set_needs_address(false), val)?; val.and_then(|val| { let fresh_stmt = { @@ -4310,7 +4275,7 @@ impl<'c> Translation<'c> { ImplicitValueInit(ty) => self.implicit_default_expr(ctx, ty.ctype), - Predefined(_, val_id) => self.convert_expr(ctx, val_id, override_ty), + Predefined(_, val_id) => self.convert_expr(ctx, val_id), Statements(_, compound_stmt_id) => { self.convert_statement_expression(ctx, compound_stmt_id) @@ -4320,9 +4285,9 @@ impl<'c> Translation<'c> { Choose(_, _cond, lhs, rhs, is_cond_true) => { let chosen_expr = if is_cond_true { - self.convert_expr(ctx, lhs, override_ty)? + self.convert_expr(ctx, lhs)? } else { - self.convert_expr(ctx, rhs, override_ty)? + self.convert_expr(ctx, rhs)? }; // TODO: Support compile-time choice between lhs and rhs based on cond. @@ -4373,18 +4338,16 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, expr_id: CExprId, - override_ty: Option, ) -> TranslationResult>> { let mut val; if (self.ast_context.index(expr_id).kind.get_qual_type()) .map_or(false, |qtype| self.ast_context.is_va_list(qtype.ctype)) { - // No `override_ty` to avoid unwanted casting. - val = self.convert_expr(ctx, expr_id, None)?; + val = self.convert_expr(ctx, expr_id)?; val = val.map(|val| mk_va_list_copy(self.tcfg.edition, val)); } else { - val = self.convert_expr(ctx, expr_id, override_ty)?; + val = self.convert_expr(ctx, expr_id)?; } Ok(val) diff --git a/c2rust-transpile/src/translator/named_references.rs b/c2rust-transpile/src/translator/named_references.rs index 1963e035ee..691ef218a7 100644 --- a/c2rust-transpile/src/translator/named_references.rs +++ b/c2rust-transpile/src/translator/named_references.rs @@ -107,7 +107,7 @@ impl<'c> Translation<'c> { .get_qual_type() .ok_or_else(|| format_err!("bad reference type"))?; let read = |write| self.read(reference_ty, write); - let reference = self.convert_expr(ctx.used(), reference, None)?; + let reference = self.convert_expr(ctx.used(), reference)?; reference.and_then(|reference| { if !uses_read && is_lvalue(&reference) { Ok(WithStmts::new_val(NamedReference { diff --git a/c2rust-transpile/src/translator/operators.rs b/c2rust-transpile/src/translator/operators.rs index cfc3d5b43b..246ef5616e 100644 --- a/c2rust-transpile/src/translator/operators.rs +++ b/c2rust-transpile/src/translator/operators.rs @@ -60,8 +60,8 @@ impl<'c> Translation<'c> { match op { Comma => { // The value of the LHS of a comma expression is always discarded - self.convert_expr(ctx.unused(), lhs, None)? - .and_then(|_| self.convert_expr(ctx, rhs, Some(expr_type_id))) + self.convert_expr(ctx.unused(), lhs)? + .and_then(|_| self.convert_expr(ctx, rhs)) } And | Or => { @@ -158,8 +158,8 @@ impl<'c> Translation<'c> { if ctx.is_unused() { Ok(self - .convert_expr(ctx, lhs, Some(lhs_type_id))? - .and_then(|_| self.convert_expr(ctx, rhs, Some(rhs_type_id)))? + .convert_expr(ctx, lhs)? + .and_then(|_| self.convert_expr(ctx, rhs))? .map(|_| self.panic_or_err("Binary expression is not supposed to be used"))) } else { let rhs_ctx = ctx; @@ -175,24 +175,22 @@ impl<'c> Translation<'c> { } } - self.convert_expr(ctx, lhs, Some(lhs_type_id))? - .and_then(|lhs_val| { - self.convert_expr(rhs_ctx, rhs, Some(rhs_type_id))? - .and_then(|rhs_val| { - let expr_ids = Some((lhs, rhs)); - self.convert_binary_operator( - ctx, - op, - ty, - expr_type_id.ctype, - lhs_type_id, - rhs_type_id, - lhs_val, - rhs_val, - expr_ids, - ) - }) + self.convert_expr(ctx, lhs)?.and_then(|lhs_val| { + self.convert_expr(rhs_ctx, rhs)?.and_then(|rhs_val| { + let expr_ids = Some((lhs, rhs)); + self.convert_binary_operator( + ctx, + op, + ty, + expr_type_id.ctype, + lhs_type_id, + rhs_type_id, + lhs_val, + rhs_val, + expr_ids, + ) }) + }) } } } @@ -300,7 +298,7 @@ impl<'c> Translation<'c> { .ok_or_else(|| format_err!("bad initial lhs type"))?; // First, translate the rhs. Then, if it must match the lhs but doesn't, add a cast. - let mut rhs_translation = self.convert_expr(ctx.used(), rhs, None)?; + let mut rhs_translation = self.convert_expr(ctx.used(), rhs)?; let lhs_rhs_types_must_match = { let lhs_resolved_ty = &self.ast_context.resolve_type(lhs_type_id.ctype); let rhs_resolved_ty = &self.ast_context.resolve_type(rhs_type_id.ctype); @@ -885,10 +883,10 @@ impl<'c> Translation<'c> { c_ast::UnOp::PostIncrement => self.convert_post_increment(ctx, cqual_type, true, arg), c_ast::UnOp::PostDecrement => self.convert_post_increment(ctx, cqual_type, false, arg), c_ast::UnOp::Deref => self.convert_deref(ctx, cqual_type, arg, lrvalue), - c_ast::UnOp::Plus => self.convert_expr(ctx.used(), arg, Some(cqual_type)), // promotion is explicit in the clang AST + c_ast::UnOp::Plus => self.convert_expr(ctx.used(), arg), // promotion is explicit in the clang AST c_ast::UnOp::Negate => { - let val = self.convert_expr(ctx.used(), arg, Some(cqual_type))?; + let val = self.convert_expr(ctx.used(), arg)?; if resolved_ctype.kind.is_unsigned_integral_type() { Ok(val.map(wrapping_neg_expr)) @@ -897,7 +895,7 @@ impl<'c> Translation<'c> { } } c_ast::UnOp::Complement => Ok(self - .convert_expr(ctx.used(), arg, Some(cqual_type))? + .convert_expr(ctx.used(), arg)? .map(|a| mk().unary_expr(UnOp::Not(Default::default()), a))), c_ast::UnOp::Not => { @@ -905,7 +903,7 @@ impl<'c> Translation<'c> { Ok(val.map(|x| mk().cast_expr(x, mk().abs_path_ty(vec!["core", "ffi", "c_int"])))) } c_ast::UnOp::Extension => { - let arg = self.convert_expr(ctx, arg, Some(cqual_type))?; + let arg = self.convert_expr(ctx, arg)?; Ok(arg) } c_ast::UnOp::Real | c_ast::UnOp::Imag | c_ast::UnOp::Coawait => { diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 3a81cd3ef5..26cbf20ae9 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -26,7 +26,7 @@ impl<'c> Translation<'c> { match arg_kind { // C99 6.5.3.2 para 4 CExprKind::Unary(_, c_ast::UnOp::Deref, target, _) => { - return self.convert_expr(ctx, *target, None) + return self.convert_expr(ctx, *target) } // Array subscript functions as a deref too. &CExprKind::ArraySubscript(_, lhs, rhs, _) => { @@ -45,7 +45,7 @@ impl<'c> Translation<'c> { _ => (), } - let val = self.convert_expr(ctx.used().set_needs_address(true), arg, None)?; + let val = self.convert_expr(ctx.used().set_needs_address(true), arg)?; // & becomes a no-op when applied to a function. if self.ast_context.is_function_pointer(cqual_type.ctype) { @@ -206,10 +206,10 @@ impl<'c> Translation<'c> { let arg_expr_kind = &self.ast_context.index(arg).kind; if let &CExprKind::Unary(_, c_ast::UnOp::AddressOf, arg, _) = arg_expr_kind { - return self.convert_expr(ctx.used(), arg, None); + return self.convert_expr(ctx.used(), arg); } - self.convert_expr(ctx.used(), arg, None)? + self.convert_expr(ctx.used(), arg)? .result_map(|val: Box| { if let CTypeKind::Function(..) = self.ast_context.resolve_type(cqual_type.ctype).kind @@ -269,7 +269,7 @@ impl<'c> Translation<'c> { )); } - let rhs = self.convert_expr(ctx.used(), rhs, None)?; + let rhs = self.convert_expr(ctx.used(), rhs)?; rhs.and_then(|rhs| { let simple_index_array = if ctx.needs_address() { // We can't necessarily index into an array if we're using @@ -318,7 +318,7 @@ impl<'c> Translation<'c> { ref other => panic!("Unexpected array type {:?}", other), }; - let lhs = self.convert_expr(ctx.used(), arr, None)?; + let lhs = self.convert_expr(ctx.used(), arr)?; lhs.and_then(|lhs| { // stmts.extend(lhs.stmts_mut()); // is_unsafe = is_unsafe || lhs.is_unsafe(); @@ -334,7 +334,7 @@ impl<'c> Translation<'c> { }) } else { // LHS must be ref decayed for the offset method call's self param - let lhs = self.convert_expr(ctx.used().decay_ref(), lhs, None)?; + let lhs = self.convert_expr(ctx.used().decay_ref(), lhs)?; lhs.and_then(|lhs| { // stmts.extend(lhs.stmts_mut()); // is_unsafe = is_unsafe || lhs.is_unsafe(); diff --git a/c2rust-transpile/src/translator/simd.rs b/c2rust-transpile/src/translator/simd.rs index a9c8a1947f..3d04ae1bfe 100644 --- a/c2rust-transpile/src/translator/simd.rs +++ b/c2rust-transpile/src/translator/simd.rs @@ -222,7 +222,7 @@ impl<'c> Translation<'c> { .map(|arg| self.clean_int_or_vector_param(*arg)), ); - let param_translation = self.convert_exprs(ctx.used(), &processed_args, None)?; + let param_translation = self.convert_exprs(ctx.used(), &processed_args)?; param_translation.and_then(|call_params| { let call = mk().call_expr(mk().ident_expr(fn_name), call_params); @@ -293,7 +293,7 @@ impl<'c> Translation<'c> { ctype: CTypeId, len: usize, ) -> TranslationResult>> { - let param_translation = self.convert_exprs(ctx, ids, None)?; + let param_translation = self.convert_exprs(ctx, ids)?; param_translation.and_then(|mut params| { // When used in a const context, we cannot call the standard functions since they // are not const and so we are forced to transmute @@ -380,11 +380,8 @@ impl<'c> Translation<'c> { } let mask_expr_id = self.get_shuffle_vector_mask(&child_expr_ids[2..])?; - let param_translation = self.convert_exprs( - ctx.used(), - &[first_expr_id, second_expr_id, mask_expr_id], - None, - )?; + let param_translation = + self.convert_exprs(ctx.used(), &[first_expr_id, second_expr_id, mask_expr_id])?; param_translation.and_then(|params| { let [first, second, third]: [_; 3] = params .try_into() diff --git a/c2rust-transpile/src/translator/structs_unions.rs b/c2rust-transpile/src/translator/structs_unions.rs index 13b949ad00..824cd24cba 100644 --- a/c2rust-transpile/src/translator/structs_unions.rs +++ b/c2rust-transpile/src/translator/structs_unions.rs @@ -496,8 +496,8 @@ impl<'a> Translation<'a> { let field = init.map(|init| mk().field(field_name, init)); fields.push(field); } - Both(field_id, (field_name, ty, bitfield_width, use_inner_type)) => { - let mut expr = self.convert_expr(ctx.used(), *field_id, Some(ty))?; + Both(field_id, (field_name, _ty, bitfield_width, use_inner_type)) => { + let mut expr = self.convert_expr(ctx.used(), *field_id)?; if use_inner_type { // See comment above @@ -594,7 +594,7 @@ impl<'a> Translation<'a> { let val = if ids.is_empty() { self.implicit_default_expr(ctx, field_ty.ctype)? } else { - self.convert_expr(ctx.used(), ids[0], None)? + self.convert_expr(ctx.used(), ids[0])? }; Ok(val.map(|v| { @@ -1027,20 +1027,20 @@ impl<'a> Translation<'a> { override_ty: Option, ) -> TranslationResult>> { if ctx.is_unused() { - return self.convert_expr(ctx, expr, None); + return self.convert_expr(ctx, expr); } let mut val = match kind { - MemberKind::Dot => self.convert_expr(ctx, expr, None)?, + MemberKind::Dot => self.convert_expr(ctx, expr)?, MemberKind::Arrow => { if let CExprKind::Unary(_, c_ast::UnOp::AddressOf, subexpr_id, _) = self.ast_context[expr].kind { // Special-case the `(&x)->field` pattern // Convert it directly into `x.field` - self.convert_expr(ctx, subexpr_id, None)? + self.convert_expr(ctx, subexpr_id)? } else { - let val = self.convert_expr(ctx, expr, None)?; + let val = self.convert_expr(ctx, expr)?; val.map(|v| mk().unary_expr(UnOp::Deref(Default::default()), v)) } } diff --git a/c2rust-transpile/src/translator/variadic.rs b/c2rust-transpile/src/translator/variadic.rs index 1ded621021..0dee413305 100644 --- a/c2rust-transpile/src/translator/variadic.rs +++ b/c2rust-transpile/src/translator/variadic.rs @@ -176,7 +176,7 @@ impl<'c> Translation<'c> { val_id: CExprId, ) -> TranslationResult>> { if self.tcfg.translate_valist { - let val = self.convert_expr(ctx.used(), val_id, None)?; + let val = self.convert_expr(ctx.used(), val_id)?; // The current implementation of the C-variadics feature doesn't allow us to // return `Option _>` from `VaList::arg`, so we detect function pointers From 8c209ca972051cd1ba0423cf54371570aaba3860 Mon Sep 17 00:00:00 2001 From: Rua Date: Sun, 22 Mar 2026 20:46:21 +0100 Subject: [PATCH 9/9] transpile: Remove `override_ty` param from `convert_const_macro_expansion` --- c2rust-transpile/src/translator/enums.rs | 2 +- c2rust-transpile/src/translator/macros.rs | 11 +++-------- c2rust-transpile/src/translator/mod.rs | 2 +- c2rust-transpile/src/translator/pointers.rs | 2 +- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 23dfc119ee..5f80244d55 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -100,7 +100,7 @@ impl<'c> Translation<'c> { if self.is_variant_of_enum(enum_id, enum_constant_id) => { // `enum`s shouldn't need portable `override_ty`s. - let expr_is_macro = self.expr_is_expanded_macro(ctx, expr, None); + let expr_is_macro = self.expr_is_expanded_macro(ctx, expr); // If this DeclRef expanded to a const macro, we actually need to insert a cast, // because the translation of a const macro skips implicit casts in its context. diff --git a/c2rust-transpile/src/translator/macros.rs b/c2rust-transpile/src/translator/macros.rs index de0566d1f7..f8c1b12b5f 100644 --- a/c2rust-transpile/src/translator/macros.rs +++ b/c2rust-transpile/src/translator/macros.rs @@ -148,7 +148,6 @@ impl<'c> Translation<'c> { &self, ctx: ExprContext, expr_id: CExprId, - override_ty: Option, ) -> TranslationResult>>> { let macros = match self.ast_context.macro_invocations.get(&expr_id) { Some(macros) => macros.as_slice(), @@ -201,6 +200,7 @@ impl<'c> Translation<'c> { // determined by the surrounding context. // Since the expansion sites are expecting a particular type, we need to cast it here // if it differs from the `const` type. + let override_ty = self.expr_override_types.get(&expr_id).copied(); let expr_ty = override_ty.or_else(|| self.ast_context[expr_id].kind.get_qual_type()); if let Some(expr_ty) = expr_ty { self.convert_cast( @@ -249,14 +249,9 @@ impl<'c> Translation<'c> { )))) } - pub fn expr_is_expanded_macro( - &self, - ctx: ExprContext, - expr_id: CExprId, - override_ty: Option, - ) -> bool { + pub fn expr_is_expanded_macro(&self, ctx: ExprContext, expr_id: CExprId) -> bool { matches!( - self.convert_const_macro_expansion(ctx, expr_id, override_ty), + self.convert_const_macro_expansion(ctx, expr_id), Ok(Some(_)) ) } diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index e76683366d..dbbb9e851e 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3686,7 +3686,7 @@ impl<'c> Translation<'c> { let override_ty = self.expr_override_types.get(&expr_id).copied(); - if let Some(converted) = self.convert_const_macro_expansion(ctx, expr_id, override_ty)? { + if let Some(converted) = self.convert_const_macro_expansion(ctx, expr_id)? { return Ok(converted); } diff --git a/c2rust-transpile/src/translator/pointers.rs b/c2rust-transpile/src/translator/pointers.rs index 26cbf20ae9..3a0706806b 100644 --- a/c2rust-transpile/src/translator/pointers.rs +++ b/c2rust-transpile/src/translator/pointers.rs @@ -103,7 +103,7 @@ impl<'c> Translation<'c> { .ast_context .get_pointee_qual_type(pointer_cty.ctype) .ok_or_else(|| TranslationError::generic("Address-of should return a pointer"))?; - let arg_is_macro = arg.map_or(false, |arg| self.expr_is_expanded_macro(ctx, arg, None)); + let arg_is_macro = arg.map_or(false, |arg| self.expr_is_expanded_macro(ctx, arg)); let mut needs_cast = false; let mut ref_cast_pointee_ty = None;