Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions c2rust-ast-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1421,6 +1421,26 @@ impl Builder {
}))
}

pub fn const_impl_item<I>(self, name: I, ty: Box<Type>, init: Box<Expr>) -> ImplItem
where
I: Make<Ident>,
{
let name = name.make(&self);
ImplItem::Const(ImplItemConst {
attrs: self.attrs,
vis: self.vis,
defaultness: None,
const_token: Token![const](self.span),
ident: name,
generics: self.generics,
colon_token: Token![:](self.span),
ty: *ty,
eq_token: Token![=](self.span),
expr: *init,
semi_token: Token![;](self.span),
})
}

pub fn fn_item<S>(self, sig: S, mut block: Block) -> Box<Item>
where
S: Make<Signature>,
Expand Down
108 changes: 73 additions & 35 deletions c2rust-transpile/src/translator/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use c2rust_ast_builder::mk;
use proc_macro2::Span;
use syn::Expr;

use crate::c_ast::iterators::SomeId;
use crate::{
diagnostics::TranslationResult,
translator::{signed_int_expr, ConvertedDecl, ExprContext, Translation},
Expand All @@ -15,6 +16,7 @@ impl<'c> Translation<'c> {
enum_id: CEnumId,
span: Span,
integral_type: CQualTypeId,
variants: &[CEnumConstantId],
) -> TranslationResult<ConvertedDecl> {
let enum_name = &self
.type_converter
Expand All @@ -23,44 +25,59 @@ impl<'c> Translation<'c> {
.expect("Enums should already be renamed");
let integral_type_rs = self.convert_type(integral_type.ctype)?;
let field = mk().pub_().enum_field(integral_type_rs);
let item = mk()
let enum_item = mk()
.span(span)
.call_attr("derive", vec!["Clone", "Copy"])
.call_attr("repr", vec!["transparent"])
.pub_()
.struct_item(enum_name, vec![field], true);

Ok(ConvertedDecl::Item(item))
}
if variants.is_empty() {
return Ok(ConvertedDecl::Item(enum_item));
}

pub fn convert_enum_constant(
&self,
enum_constant_id: CEnumConstantId,
span: Span,
value: ConstIntExpr,
) -> TranslationResult<ConvertedDecl> {
let name = self
.renamer
.borrow_mut()
.get(&enum_constant_id)
.expect("Enum constant not named");
let enum_id = self.ast_context.parents[&enum_constant_id];
let enum_name = self
.type_converter
.borrow()
.resolve_decl_name(enum_id)
.expect("Enums should already be renamed");
let enum_type = mk().ident_ty("Self");
let constants = variants
.iter()
.map(|&enum_constant_id| {
let name = match self.ast_context[enum_constant_id].kind {
CDeclKind::EnumConstant { ref name, .. } => name,
_ => panic!("{:?} does not point to an enum variant", enum_constant_id),
};
let name_rs = self.type_converter.borrow_mut().declare_field_name(
enum_id,
enum_constant_id,
name,
);
let (span, init) = self.make_enum_constant_init(enum_constant_id);
mk().span(span)
.pub_()
.const_impl_item(name_rs, enum_type.clone(), init)
})
.collect();

let ty = mk().ident_ty(enum_name);
let val = match value {
let impl_block = mk()
.span(span)
.impl_item(mk().ident_ty(enum_name), constants);
Ok(ConvertedDecl::Items(vec![enum_item, impl_block]))
}

fn make_enum_constant_init(&self, enum_constant_id: CEnumConstantId) -> (Span, Box<Expr>) {
let value = match self.ast_context[enum_constant_id].kind {
CDeclKind::EnumConstant { value, .. } => value,
_ => panic!("{:?} does not point to an enum variant", enum_constant_id),
};
let value_rs = match value {
ConstIntExpr::I(value) => signed_int_expr(value),
ConstIntExpr::U(value) => mk().lit_expr(mk().int_unsuffixed_lit(value as u128)),
};
let init = self.enum_constructor_expr(enum_id, val);
let enum_id = self.ast_context.parents[&enum_constant_id];
let init = self.enum_constructor_expr(enum_id, value_rs, true);
let span = self
.get_span(SomeId::Decl(enum_constant_id))
.unwrap_or_else(Span::call_site);

Ok(ConvertedDecl::Item(
mk().span(span).pub_().const_item(name, ty, init),
))
(span, init)
}

pub fn convert_enum_zero_initializer(&self, enum_id: CEnumId) -> WithStmts<Box<Expr>> {
Expand Down Expand Up @@ -131,7 +148,7 @@ impl<'c> Translation<'c> {
let enum_integral_type = self.enum_integral_type(enum_id);
let mut val = WithStmts::new_val(val);
val = self.make_cast(ctx, source_cty, enum_integral_type, val)?;
val = val.map(|val| self.enum_constructor_expr(enum_id, val));
val = val.map(|val| self.enum_constructor_expr(enum_id, val, false));

Ok(val)
}
Expand All @@ -150,7 +167,7 @@ impl<'c> Translation<'c> {
_ => signed_int_expr(value),
};

self.enum_constructor_expr(enum_id, value)
self.enum_constructor_expr(enum_id, value, false)
}

/// Returns the id of the variant of `enum_id` whose value matches `value`, if any.
Expand All @@ -172,20 +189,41 @@ impl<'c> Translation<'c> {
}

fn enum_constant_expr(&self, enum_constant_id: CEnumConstantId) -> Box<Expr> {
let name = self.renamer.borrow().get(&enum_constant_id).unwrap();
self.add_import(enum_constant_id, &name);
mk().ident_expr(name)
}

fn enum_constructor_expr(&self, enum_id: CEnumId, value: Box<Expr>) -> Box<Expr> {
let enum_id = self.ast_context.parents[&enum_constant_id];
let enum_name = self
.type_converter
.borrow()
.resolve_decl_name(enum_id)
.unwrap();
let enum_constant_name = self
.type_converter
.borrow()
.resolve_field_name(Some(enum_id), enum_constant_id)
.unwrap();

self.add_import(enum_id, &enum_name);
mk().path_expr(vec![enum_name, enum_constant_name])
}

fn enum_constructor_expr(
&self,
enum_id: CEnumId,
value: Box<Expr>,
use_self_type: bool,
) -> Box<Expr> {
let func = if use_self_type {
mk().ident_expr("Self")
} else {
let enum_name = self
.type_converter
.borrow()
.resolve_decl_name(enum_id)
.unwrap();
self.add_import(enum_id, &enum_name);
mk().ident_expr(enum_name)
};

mk().call_expr(mk().ident_expr(enum_name), vec![value])
mk().call_expr(func, vec![value])
}

pub(crate) fn enum_constant_matches_type(
Expand Down
12 changes: 6 additions & 6 deletions c2rust-transpile/src/translator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,9 +899,7 @@ pub fn translate(
// Tuple structs are in both namespaces.
Enum { .. } => Namespaces::types() | Namespaces::values(),
Struct { .. } | Union { .. } | Typedef { .. } => Namespaces::types(),
Function { .. } | EnumConstant { .. } | Variable { .. } | MacroObject { .. } => {
Namespaces::values()
}
Function { .. } | Variable { .. } | MacroObject { .. } => Namespaces::values(),
_ => Namespaces::none(),
}
}
Expand Down Expand Up @@ -997,7 +995,6 @@ pub fn translate(
let needs_export = match decl.kind {
Struct { .. } => true,
Enum { .. } => true,
EnumConstant { .. } => true,
Union { .. } => true,
Typedef { .. } => {
// Only check the key as opposed to `contains`
Expand Down Expand Up @@ -2090,11 +2087,13 @@ impl<'c> Translation<'c> {
)),

Enum {
ref variants,
integral_type: Some(integral_type),
..
} => self.convert_enum(decl_id, span, integral_type),
} => self.convert_enum(decl_id, span, integral_type, variants),

EnumConstant { value, .. } => self.convert_enum_constant(decl_id, span, value),
// EnumConstant is translated as part of Enum.
EnumConstant { .. } => Ok(ConvertedDecl::NoItem),

// We can allow non top level function declarations (i.e. extern
// declarations) without any problem. Clang doesn't support nested
Expand Down Expand Up @@ -3603,6 +3602,7 @@ impl<'c> Translation<'c> {
}

let varname = decl.get_name().expect("expected variable name").to_owned();

let rustname = self
.renamer
.borrow_mut()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,32 @@ expression: cat tests/snapshots/enums.2021.clang15.rs
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Foo(pub ::core::ffi::c_uint);
pub const Foo3: Foo = Foo(3);
pub const Foo2: Foo = Foo(2);
pub const Foo1: Foo = Foo(1);
pub const Foo0: Foo = Foo(0);
impl Foo {
pub const Foo0: Self = Self(0);
pub const Foo1: Self = Self(1);
pub const Foo2: Self = Self(2);
pub const Foo3: Self = Self(3);
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Bar(pub ::core::ffi::c_int);
pub const Bar3: Bar = Bar(3);
pub const Bar2: Bar = Bar(2);
pub const Bar1: Bar = Bar(1);
pub const Bar0: Bar = Bar(0);
pub const BarN1: Bar = Bar(-1);
impl Bar {
pub const BarN1: Self = Self(-1);
pub const Bar0: Self = Self(0);
pub const Bar1: Self = Self(1);
pub const Bar2: Self = Self(2);
pub const Bar3: Self = Self(3);
}
pub const FOO1_MACRO: ::core::ffi::c_uint = 1 as ::core::ffi::c_uint;
pub const BAR1_MACRO: ::core::ffi::c_int = 1;
#[no_mangle]
pub unsafe extern "C" fn test_enums() {
let mut foo: Foo = Foo0;
let mut bar: Bar = Bar0;
foo = Foo1;
bar = BarN1;
foo = Foo(Bar0.0 as ::core::ffi::c_uint);
bar = Bar(Foo0.0 as ::core::ffi::c_int);
let mut foo: Foo = Foo::Foo0;
let mut bar: Bar = Bar::Bar0;
foo = Foo::Foo1;
bar = Bar::BarN1;
foo = Foo(Bar::Bar0.0 as ::core::ffi::c_uint);
bar = Bar(Foo::Foo0.0 as ::core::ffi::c_int);
foo = Foo(1 as ::core::ffi::c_int as ::core::ffi::c_uint);
bar = Bar(1 as ::core::ffi::c_int);
foo = Foo(3 as ::core::ffi::c_int as ::core::ffi::c_uint);
Expand All @@ -50,13 +54,13 @@ pub unsafe extern "C" fn test_enums() {
let c2rust_fresh1 = bar;
bar = Bar(bar.0 + 1);
foo = Foo(c2rust_fresh1.0 as ::core::ffi::c_uint);
let mut e: Foo = Foo1;
let mut e: Foo = Foo::Foo1;
let mut enum_enum: ::core::ffi::c_int = (e.0 == foo.0) as ::core::ffi::c_int;
let mut enum_constant: ::core::ffi::c_int = (e.0 == Foo0.0) as ::core::ffi::c_int;
let mut enum_constant: ::core::ffi::c_int = (e.0 == Foo::Foo0.0) as ::core::ffi::c_int;
let mut wrong_enum_enum: ::core::ffi::c_int =
(e.0 == bar.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
let mut wrong_enum_constant: ::core::ffi::c_int =
(e.0 == Bar0.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
(e.0 == Bar::Bar0.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
match foo.0 {
0 | 1 | 2 | 3 | 42 | 4294967254 | _ => {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,32 @@ expression: cat tests/snapshots/enums.2024.clang15.rs
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Foo(pub ::core::ffi::c_uint);
pub const Foo3: Foo = Foo(3);
pub const Foo2: Foo = Foo(2);
pub const Foo1: Foo = Foo(1);
pub const Foo0: Foo = Foo(0);
impl Foo {
pub const Foo0: Self = Self(0);
pub const Foo1: Self = Self(1);
pub const Foo2: Self = Self(2);
pub const Foo3: Self = Self(3);
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Bar(pub ::core::ffi::c_int);
pub const Bar3: Bar = Bar(3);
pub const Bar2: Bar = Bar(2);
pub const Bar1: Bar = Bar(1);
pub const Bar0: Bar = Bar(0);
pub const BarN1: Bar = Bar(-1);
impl Bar {
pub const BarN1: Self = Self(-1);
pub const Bar0: Self = Self(0);
pub const Bar1: Self = Self(1);
pub const Bar2: Self = Self(2);
pub const Bar3: Self = Self(3);
}
pub const FOO1_MACRO: ::core::ffi::c_uint = 1 as ::core::ffi::c_uint;
pub const BAR1_MACRO: ::core::ffi::c_int = 1;
#[unsafe(no_mangle)]
pub unsafe extern "C" fn test_enums() {
let mut foo: Foo = Foo0;
let mut bar: Bar = Bar0;
foo = Foo1;
bar = BarN1;
foo = Foo(Bar0.0 as ::core::ffi::c_uint);
bar = Bar(Foo0.0 as ::core::ffi::c_int);
let mut foo: Foo = Foo::Foo0;
let mut bar: Bar = Bar::Bar0;
foo = Foo::Foo1;
bar = Bar::BarN1;
foo = Foo(Bar::Bar0.0 as ::core::ffi::c_uint);
bar = Bar(Foo::Foo0.0 as ::core::ffi::c_int);
foo = Foo(1 as ::core::ffi::c_int as ::core::ffi::c_uint);
bar = Bar(1 as ::core::ffi::c_int);
foo = Foo(3 as ::core::ffi::c_int as ::core::ffi::c_uint);
Expand All @@ -51,13 +55,13 @@ pub unsafe extern "C" fn test_enums() {
let c2rust_fresh1 = bar;
bar = Bar(bar.0 + 1);
foo = Foo(c2rust_fresh1.0 as ::core::ffi::c_uint);
let mut e: Foo = Foo1;
let mut e: Foo = Foo::Foo1;
let mut enum_enum: ::core::ffi::c_int = (e.0 == foo.0) as ::core::ffi::c_int;
let mut enum_constant: ::core::ffi::c_int = (e.0 == Foo0.0) as ::core::ffi::c_int;
let mut enum_constant: ::core::ffi::c_int = (e.0 == Foo::Foo0.0) as ::core::ffi::c_int;
let mut wrong_enum_enum: ::core::ffi::c_int =
(e.0 == bar.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
let mut wrong_enum_constant: ::core::ffi::c_int =
(e.0 == Bar0.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
(e.0 == Bar::Bar0.0 as ::core::ffi::c_uint) as ::core::ffi::c_int;
match foo.0 {
0 | 1 | 2 | 3 | 42 | 4294967254 | _ => {}
}
Expand Down
Loading
Loading