diff --git a/c2rust-ast-exporter/src/AstExporter.cpp b/c2rust-ast-exporter/src/AstExporter.cpp index abc92f7ae7..53fd9c74a7 100644 --- a/c2rust-ast-exporter/src/AstExporter.cpp +++ b/c2rust-ast-exporter/src/AstExporter.cpp @@ -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) { diff --git a/c2rust-transpile/src/c_ast/mod.rs b/c2rust-transpile/src/c_ast/mod.rs index b83171902c..31d1024970 100644 --- a/c2rust-transpile/src/c_ast/mod.rs +++ b/c2rust-transpile/src/c_ast/mod.rs @@ -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 = 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. @@ -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. diff --git a/c2rust-transpile/src/translator/mod.rs b/c2rust-transpile/src/translator/mod.rs index e986c89aeb..6e93fda923 100644 --- a/c2rust-transpile/src/translator/mod.rs +++ b/c2rust-transpile/src/translator/mod.rs @@ -708,6 +708,10 @@ pub fn translate( None }; + // Identify typedefs that name unnamed types and collapse the two declarations + // into a single name and declaration, eliminating the typedef altogether. + t.ast_context.set_prenamed_decls(); + // Headers often pull in declarations that are unused; // we simplify the translator output by omitting those. t.ast_context @@ -737,62 +741,17 @@ pub fn translate( prefix_names(&mut t, prefix); } - // Identify typedefs that name unnamed types and collapse the two declarations - // into a single name and declaration, eliminating the typedef altogether. - let mut prenamed_decls: IndexMap = IndexMap::new(); - for (&decl_id, decl) in t.ast_context.iter_decls() { - if let CDeclKind::Typedef { ref name, typ, .. } = decl.kind { - if let Some(subdecl_id) = t - .ast_context - .resolve_type(typ.ctype) - .kind - .as_underlying_decl() - { - use CDeclKind::*; - let is_unnamed = match t.ast_context[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); - - t.type_converter - .borrow_mut() - .declare_decl_name(decl_id, name); - t.type_converter - .borrow_mut() - .alias_decl_name(subdecl_id, decl_id); - } - } + for (&decl_id, &subdecl_id) in &t.ast_context.prenamed_decls { + if let CDeclKind::Typedef { ref name, .. } = t.ast_context[decl_id].kind { + t.type_converter + .borrow_mut() + .declare_decl_name(decl_id, name); + t.type_converter + .borrow_mut() + .alias_decl_name(subdecl_id, decl_id); } } - t.ast_context.prenamed_decls = prenamed_decls; - // Helper function that returns true if there is either a matching typedef or its // corresponding struct/union/enum fn contains(prenamed_decls: &IndexMap, decl_id: &CDeclId) -> bool { diff --git a/tests/unit/enums/src/enum_fwd_decl.c b/tests/unit/enums/src/enum_fwd_decl.c index e23e446a2b..4a90052755 100644 --- a/tests/unit/enums/src/enum_fwd_decl.c +++ b/tests/unit/enums/src/enum_fwd_decl.c @@ -10,4 +10,4 @@ struct _Evas_Func }; // dummy item imported by `test_enums.rs` -int foo(int i) { return i;} \ No newline at end of file +struct _Evas_Func foo(struct _Evas_Func i) { return i;}