Skip to content
Draft
20 changes: 20 additions & 0 deletions c2rust-ast-builder/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,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
7 changes: 6 additions & 1 deletion c2rust-ast-exporter/src/AstExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2625,11 +2625,16 @@ class TranslateASTVisitor final

void TypeEncoder::VisitEnumType(const EnumType *T) {
auto ed = T->getDecl()->getDefinition();

if (!ed) {
ed = T->getDecl()->getCanonicalDecl();
}

encodeType(T, TagEnumType, [T, ed](CborEncoder *local) {
cbor_encode_uint(local, uintptr_t(ed));
});

if (ed != nullptr) astEncoder->TraverseDecl(ed);
astEncoder->TraverseDecl(ed);
}

void TypeEncoder::VisitRecordType(const RecordType *T) {
Expand Down
9 changes: 9 additions & 0 deletions c2rust-refactor/src/transform/items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@ impl Transform for RenameUnnamed {
renamer
.new_idents
.insert(cx.hir_map().node_to_hir_id(i.id), new_name);

if let ItemKind::Struct(variant_data, _) | ItemKind::Union(variant_data, _) = &i.kind {
if let Some(ctor_id) = variant_data.ctor_id() {
renamer
.new_idents
.insert(cx.hir_map().node_to_hir_id(ctor_id), new_name);
}
}

renamer.new_to_old.insert(new_name, i.ident);
counter += 1;
smallvec![i.map(|i| Item {
Expand Down
43 changes: 40 additions & 3 deletions c2rust-refactor/src/transform/reorganize_definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_ast::*;
use rustc_ast_pretty::pprust::{self, item_to_string, PrintState};
use rustc_data_structures::map_in_place::MapInPlace;
use rustc_hir::def::{DefKind, Namespace, PerNS, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, Node};
use rustc_middle::metadata::ModChild;
use rustc_middle::ty::{self, ParamEnv};
Expand Down Expand Up @@ -122,6 +122,7 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
self.update_module_info_items(krate);

self.move_items(header_decls, krate);
self.add_ctor_mappings();

self.update_paths(krate)
}
Expand Down Expand Up @@ -765,6 +766,42 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
});
}

fn add_ctor_mappings(&mut self) {
let get_ctor = |def_id: DefId| -> Option<LocalDefId> {
self.cx.hir_map().get_if_local(def_id).and_then(|node| {
let item = match node {
hir::Node::Item(item) => item,
_ => return None,
};
let hir_id = match &item.kind {
hir::ItemKind::Struct(variant_data, _)
| hir::ItemKind::Union(variant_data, _) => variant_data.ctor_hir_id()?,
_ => return None,
};
self.cx.hir_map().opt_local_def_id(hir_id)
})
};

let ctor_mapping: HashMap<DefId, Replacement> = self
.path_mapping
.iter()
.filter_map(|(&def_id, replacement)| {
Some((
get_ctor(def_id)?.to_def_id(),
Replacement {
def: replacement
.def
.and_then(|def| get_ctor(def))
.map(LocalDefId::to_def_id),
..replacement.clone()
},
))
})
.collect();

self.path_mapping.extend(ctor_mapping);
}

/// Update paths to moved items and remove redundant imports.
fn update_paths(&self, krate: &mut Crate) {
let tcx = self.cx.ty_ctxt();
Expand Down Expand Up @@ -1315,8 +1352,8 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
// Keep function definitions, if any
ItemKind::Fn(..) => false,

// Don't keep impl blocks, these are expanded from macros anyway
ItemKind::Impl(..) => true,
// Keep impl blocks
ItemKind::Impl(..) => false,

// We collect all ForeignItems and later filter out any idents
// defined in ident_map after processing the whole list of items.
Expand Down
92 changes: 77 additions & 15 deletions c2rust-transpile/src/c_ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,54 @@ impl TypedAstContext {
}
}

/// Identifies typedefs that name unnamed types.
/// Later, the two declarations can be collapsed into a single name and declaration,
/// eliminating the typedef altogether.
pub fn set_prenamed_decls(&mut self) {
let mut prenamed_decls: IndexMap<CDeclId, CDeclId> = IndexMap::new();

for (&decl_id, decl) in self.iter_decls() {
if let CDeclKind::Typedef { ref name, typ, .. } = decl.kind {
if let Some(subdecl_id) = self.resolve_type(typ.ctype).kind.as_underlying_decl() {
use CDeclKind::*;
let is_unnamed = match self[subdecl_id].kind {
Struct { name: None, .. }
| Union { name: None, .. }
| Enum { name: None, .. } => true,

// Detect case where typedef and struct share the same name.
// In this case the purpose of the typedef was simply to eliminate
// the need for the 'struct' tag when referring to the type name.
Struct {
name: Some(ref target_name),
..
}
| Union {
name: Some(ref target_name),
..
}
| Enum {
name: Some(ref target_name),
..
} => name == target_name,

_ => false,
};

if is_unnamed
&& !prenamed_decls
.values()
.any(|decl_id| *decl_id == subdecl_id)
{
prenamed_decls.insert(decl_id, subdecl_id);
}
}
}
}

self.prenamed_decls = prenamed_decls;
}

pub fn prune_unwanted_decls(&mut self, want_unused_functions: bool) {
// Starting from a set of root declarations, walk each one to find declarations it
// depends on. Then walk each of those, recursively.
Expand Down Expand Up @@ -1105,19 +1153,20 @@ impl TypedAstContext {
}
}

// Unset c_main if we are not retaining its declaration
if let Some(main_id) = self.c_main {
if !wanted.contains(&main_id) {
self.c_main = None;
}
}

// Prune any declaration that isn't considered live
self.c_decls
.retain(|&decl_id, _decl| wanted.contains(&decl_id));

// Prune top declarations that are not considered live
self.c_decls_top.retain(|x| wanted.contains(x));
// Remove references to removed decls that are held elsewhere.
self.c_decls_top.retain(|x| self.c_decls.contains_key(x));
self.prenamed_decls
.retain(|x, _| self.c_decls.contains_key(x));

if let Some(main_id) = self.c_main {
if !self.c_decls.contains_key(&main_id) {
self.c_main = None;
}
}
}

/// Bubble types of unary and binary operators up from their args into the expression type.
Expand Down Expand Up @@ -1803,37 +1852,46 @@ impl CastKind {

(CTypeKind::Function(..), CTypeKind::Pointer(..)) => CastKind::FunctionToPointerDecay,

(_, CTypeKind::Pointer(..)) if source_ty_kind.is_integral_type() => {
(_, CTypeKind::Pointer(..)) if source_ty_kind.is_enum_or_integral_type() => {
CastKind::IntegralToPointer
}

(CTypeKind::Pointer(..), CTypeKind::Bool) => CastKind::PointerToBoolean,

(CTypeKind::Pointer(..), _) if target_ty_kind.is_integral_type() => {
(CTypeKind::Pointer(..), _) if target_ty_kind.is_enum_or_integral_type() => {
CastKind::PointerToIntegral
}

(_, CTypeKind::Bool) if source_ty_kind.is_integral_type() => {
(_, CTypeKind::Bool) if source_ty_kind.is_enum_or_integral_type() => {
CastKind::IntegralToBoolean
}

(CTypeKind::Bool, _) if target_ty_kind.is_signed_integral_type() => {
CastKind::BooleanToSignedIntegral
}

(_, _) if source_ty_kind.is_integral_type() && target_ty_kind.is_integral_type() => {
(_, _)
if source_ty_kind.is_enum_or_integral_type()
&& target_ty_kind.is_enum_or_integral_type() =>
{
CastKind::IntegralCast
}

(_, _) if source_ty_kind.is_integral_type() && target_ty_kind.is_floating_type() => {
(_, _)
if source_ty_kind.is_enum_or_integral_type()
&& target_ty_kind.is_floating_type() =>
{
CastKind::IntegralToFloating
}

(_, CTypeKind::Bool) if source_ty_kind.is_floating_type() => {
CastKind::FloatingToBoolean
}

(_, _) if source_ty_kind.is_floating_type() && target_ty_kind.is_integral_type() => {
(_, _)
if source_ty_kind.is_floating_type()
&& target_ty_kind.is_enum_or_integral_type() =>
{
CastKind::FloatingToIntegral
}

Expand Down Expand Up @@ -2684,6 +2742,10 @@ impl CTypeKind {
matches!(*self, Self::Enum { .. })
}

pub fn is_enum_or_integral_type(&self) -> bool {
self.is_integral_type() || self.is_enum()
}

pub fn is_integral_type(&self) -> bool {
self.is_unsigned_integral_type() || self.is_signed_integral_type()
}
Expand Down
Loading
Loading