From 655235617a00e127b71d8904d27b3d6791404735 Mon Sep 17 00:00:00 2001 From: Rua Date: Tue, 7 Jul 2026 16:08:41 +0200 Subject: [PATCH 1/3] transpile: Split off `convert_decl_ref` --- c2rust-transpile/src/translator/mod.rs | 272 +++++++++++++------------ 1 file changed, 144 insertions(+), 128 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index a0b3a4036d..284743cf06 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3276,134 +3276,9 @@ impl<'c> Translation<'c> { } } - DeclRef(qual_ty, decl_id, lrvalue) => { - let decl = &self - .ast_context - .get_decl(&decl_id) - .ok_or_else(|| format_err!("Missing declref {:?}", decl_id))? - .kind; - if ctx.expanding_macro.is_some() { - // TODO Determining which declarations have been declared within the scope of the const macro expr - // vs. which are out-of-scope of the const macro is non-trivial, - // so for now, we don't allow const macros referencing any declarations. - return Err(format_translation_err!( - self.ast_context.display_loc(src_loc), - "Cannot yet refer to declarations in a const expr", - )); - - #[allow(unreachable_code)] // TODO temporary (see above). - if let CDeclKind::Variable { - has_static_duration: true, - .. - } = decl - { - return Err(format_translation_err!( - self.ast_context.display_loc(src_loc), - "Cannot refer to static duration variable in a const expression", - )); - } - } - - let varname = decl.get_name().expect("expected variable name").to_owned(); - let rustname = self - .renamer - .borrow_mut() - .get(&decl_id) - .ok_or_else(|| format_err!("name not declared: '{}'", varname))?; - - // Import the referenced global decl into our submodule - if self.tcfg.reorganize_definitions { - self.add_import(decl_id, &rustname); - // match decl { - // CDeclKind::Variable { is_defn: false, .. } => {} - // _ => self.add_import(decl_id, &rustname), - // } - } - - let mut val = mk().path_expr(vec![rustname]); - let mut set_unsafe = false; - - match decl { - CDeclKind::EnumConstant { .. } => { - // If the variable is actually an `EnumConstant`, we need to add a cast to - // the expected integral type. - return self.convert_cast_from_enum(qual_ty, val); - } - - CDeclKind::Function { parameters, .. } => { - // If we are referring to a function and need its address, we - // need to cast it to fn() to ensure that it has a real address. - if ctx.needs_address() { - let ty = self.convert_type(qual_ty.ctype)?; - let actual_ty = self - .type_converter - .borrow_mut() - .knr_function_type_with_parameters( - &self.ast_context, - qual_ty.ctype, - parameters, - )?; - if let Some(actual_ty) = actual_ty { - if actual_ty != ty { - // If we're casting a concrete function to - // a K&R function pointer type, use transmute - self.import_type(qual_ty.ctype); - - val = transmute_expr(actual_ty, ty, val); - set_unsafe = true; - } - } else { - let decl_kind = &self.ast_context[decl_id].kind; - let kind_with_declared_args = - self.ast_context.fn_decl_ty_with_declared_args(decl_kind); - - if let Some(ty) = self - .ast_context - .try_type_for_kind(&kind_with_declared_args) - .map(CQualTypeId::new) - { - let ty = self.convert_type(ty.ctype)?; - val = mk().cast_expr(val, ty); - } else { - val = mk().cast_expr(val, ty); - } - } - } - } - - CDeclKind::Variable { - has_static_duration, - has_thread_duration, - .. - } => { - // Accessing a static variable is unsafe. - // In the current nightly, this applies also to taking a raw pointer, - // but this requirement was removed in later versions of the - // `raw_ref_op` feature. - if (*has_static_duration || *has_thread_duration) - && (self.tcfg.edition < Edition2024 || !ctx.needs_address()) - { - set_unsafe = true; - } - } - - _ => {} - } - - if let CTypeKind::VariableArray(..) = - self.ast_context.resolve_type(qual_ty.ctype).kind - { - val = mk().method_call_expr(val, "as_mut_ptr", vec![]); - } - - let mut val = WithStmts::new_val(val).merge_unsafe(set_unsafe); - - if lrvalue.is_rvalue() { - val = self.make_cast(ctx, qual_ty, override_ty.unwrap_or(qual_ty), val)?; - } - - Ok(val) - } + DeclRef(result_type_id, decl_id, lrvalue) => self + .convert_decl_ref(ctx, override_ty, result_type_id, decl_id, lrvalue) + .map_err(|e| e.add_loc(self.ast_context.display_loc(src_loc))), OffsetOf(ty, ref kind) => match kind { OffsetOfKind::Constant(val) => Ok(WithStmts::new_val(self.mk_int_lit( @@ -3682,6 +3557,147 @@ impl<'c> Translation<'c> { self.convert_cast(ctx, None, target_type_id, expr_id, kind, None, false) } + fn convert_decl_ref( + &self, + ctx: ExprContext, + expected_type_id: Option, + result_type_id: CQualTypeId, + decl_id: CDeclId, + lrvalue: LRValue, + ) -> TranslationResult>> { + let decl = &self + .ast_context + .get_decl(&decl_id) + .ok_or_else(|| format_err!("Missing declref {:?}", decl_id))? + .kind; + if ctx.expanding_macro.is_some() { + // TODO Determining which declarations have been declared within the scope of the const macro expr + // vs. which are out-of-scope of the const macro is non-trivial, + // so for now, we don't allow const macros referencing any declarations. + return Err(format_translation_err!( + None, + "Cannot yet refer to declarations in a const expr", + )); + + #[allow(unreachable_code)] // TODO temporary (see above). + if let CDeclKind::Variable { + has_static_duration: true, + .. + } = decl + { + return Err(format_translation_err!( + None, + "Cannot refer to static duration variable in a const expression", + )); + } + } + + let varname = decl.get_name().expect("expected variable name").to_owned(); + let rustname = self + .renamer + .borrow_mut() + .get(&decl_id) + .ok_or_else(|| format_err!("name not declared: '{}'", varname))?; + + // Import the referenced global decl into our submodule + if self.tcfg.reorganize_definitions { + self.add_import(decl_id, &rustname); + // match decl { + // CDeclKind::Variable { is_defn: false, .. } => {} + // _ => self.add_import(decl_id, &rustname), + // } + } + + let mut val = mk().path_expr(vec![rustname]); + let mut set_unsafe = false; + + match decl { + CDeclKind::EnumConstant { .. } => { + // If the variable is actually an `EnumConstant`, we need to add a cast to + // the expected integral type. + return self.convert_cast_from_enum(result_type_id, val); + } + + CDeclKind::Function { parameters, .. } => { + // If we are referring to a function and need its address, we + // need to cast it to fn() to ensure that it has a real address. + if ctx.needs_address() { + let ty = self.convert_type(result_type_id.ctype)?; + let actual_ty = self + .type_converter + .borrow_mut() + .knr_function_type_with_parameters( + &self.ast_context, + result_type_id.ctype, + parameters, + )?; + if let Some(actual_ty) = actual_ty { + if actual_ty != ty { + // If we're casting a concrete function to + // a K&R function pointer type, use transmute + self.import_type(result_type_id.ctype); + + val = transmute_expr(actual_ty, ty, val); + set_unsafe = true; + } + } else { + let decl_kind = &self.ast_context[decl_id].kind; + let kind_with_declared_args = + self.ast_context.fn_decl_ty_with_declared_args(decl_kind); + + if let Some(ty) = self + .ast_context + .try_type_for_kind(&kind_with_declared_args) + .map(CQualTypeId::new) + { + let ty = self.convert_type(ty.ctype)?; + val = mk().cast_expr(val, ty); + } else { + val = mk().cast_expr(val, ty); + } + } + } + } + + CDeclKind::Variable { + has_static_duration, + has_thread_duration, + .. + } => { + // Accessing a static variable is unsafe. + // In the current nightly, this applies also to taking a raw pointer, + // but this requirement was removed in later versions of the + // `raw_ref_op` feature. + if (*has_static_duration || *has_thread_duration) + && (self.tcfg.edition < Edition2024 || !ctx.needs_address()) + { + set_unsafe = true; + } + } + + _ => {} + } + + if let CTypeKind::VariableArray(..) = + self.ast_context.resolve_type(result_type_id.ctype).kind + { + val = mk().method_call_expr(val, "as_mut_ptr", vec![]); + } + + let mut val = WithStmts::new_val(val).merge_unsafe(set_unsafe); + + if lrvalue.is_rvalue() { + val = self.make_cast( + ctx, + result_type_id, + expected_type_id.unwrap_or(result_type_id), + val, + )?; + } + + Ok(val) + } + pub fn convert_constant(&self, constant: ConstIntExpr) -> TranslationResult> { let expr = match constant { ConstIntExpr::U(n) => mk().lit_expr(mk().int_unsuffixed_lit(n as u128)), From ff45604ccb55eedf5afd34066093d78dfcb8dddc Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 30 Jul 2026 09:56:26 +0200 Subject: [PATCH 2/3] transpile: Remove unnecessary `reorganize_definitions` check in `convert_decl_ref` --- c2rust-transpile/src/translator/mod.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 284743cf06..75475e3b30 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3600,13 +3600,11 @@ impl<'c> Translation<'c> { .ok_or_else(|| format_err!("name not declared: '{}'", varname))?; // Import the referenced global decl into our submodule - if self.tcfg.reorganize_definitions { - self.add_import(decl_id, &rustname); - // match decl { - // CDeclKind::Variable { is_defn: false, .. } => {} - // _ => self.add_import(decl_id, &rustname), - // } - } + self.add_import(decl_id, &rustname); + // match decl { + // CDeclKind::Variable { is_defn: false, .. } => {} + // _ => self.add_import(decl_id, &rustname), + // } let mut val = mk().path_expr(vec![rustname]); let mut set_unsafe = false; From 79eceb65732d91bd4ea716aad2e971fda696363f Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 29 Jul 2026 19:28:48 +0200 Subject: [PATCH 3/3] transpile: Add `convert_enum_constant_decl_ref` --- c2rust-transpile/src/translator/enums.rs | 12 ++++++++++++ c2rust-transpile/src/translator/mod.rs | 13 +++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/c2rust-transpile/src/translator/enums.rs b/c2rust-transpile/src/translator/enums.rs index 9408a43d3b..68d1a1ae3b 100644 --- a/c2rust-transpile/src/translator/enums.rs +++ b/c2rust-transpile/src/translator/enums.rs @@ -63,6 +63,18 @@ impl<'c> Translation<'c> { WithStmts::new_val(self.enum_for_i64(type_id, 0)) } + /// Translates a `DeclRef` for an `EnumConstant`. + pub fn convert_enum_constant_decl_ref( + &self, + expr_type_id: CQualTypeId, + enum_constant_id: CEnumConstantId, + ) -> TranslationResult>> { + let val = self.enum_constant_expr(enum_constant_id); + + // Add a cast to the expected integral type. + self.convert_cast_from_enum(expr_type_id, val) + } + /// Translate a cast where the source type, but not the target type, is an `enum` type. pub fn convert_cast_from_enum( &self, diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index 75475e3b30..de55baa604 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -3592,6 +3592,13 @@ impl<'c> Translation<'c> { } } + if let CDeclKind::EnumConstant { .. } = decl { + return self.convert_enum_constant_decl_ref( + expected_type_id.unwrap_or(result_type_id), + decl_id, + ); + } + let varname = decl.get_name().expect("expected variable name").to_owned(); let rustname = self .renamer @@ -3610,12 +3617,6 @@ impl<'c> Translation<'c> { let mut set_unsafe = false; match decl { - CDeclKind::EnumConstant { .. } => { - // If the variable is actually an `EnumConstant`, we need to add a cast to - // the expected integral type. - return self.convert_cast_from_enum(result_type_id, val); - } - CDeclKind::Function { parameters, .. } => { // If we are referring to a function and need its address, we // need to cast it to fn() to ensure that it has a real address.