Skip to content

Commit 9edc1ed

Browse files
authored
transpile: separate top-level decl converting and emitting (#1371)
Right now, we sort the top-level decls once by their source order (although we do this largely backwards, a separate issue) before we convert them and then emit them (insert in the code). This means that changing the conversion order also changes the order that they're emitted in, which we don't want to do, so this separates the two steps.
2 parents 25105f9 + b85ef7b commit 9edc1ed

File tree

2 files changed

+64
-40
lines changed

2 files changed

+64
-40
lines changed

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -986,8 +986,10 @@ impl TypedAstContext {
986986
}
987987
}
988988

989-
pub fn sort_top_decls(&mut self) {
990-
// Group and sort declarations by file and by position
989+
/// Sort the top-level declarations by file and source location
990+
/// so that we preserve the ordering of all declarations in each file.
991+
/// This preserves the order when we emit the converted declarations.
992+
pub fn sort_top_decls_for_emitting(&mut self) {
991993
let mut decls_top = mem::take(&mut self.c_decls_top);
992994
decls_top.sort_unstable_by(|a, b| {
993995
let a = self.index(*a);

c2rust-transpile/src/translator/mod.rs

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -495,10 +495,6 @@ pub fn translate(
495495
};
496496

497497
{
498-
// Sort the top-level declarations by file and source location so that we
499-
// preserve the ordering of all declarations in each file.
500-
t.ast_context.sort_top_decls();
501-
502498
t.locate_comments();
503499

504500
// Headers often pull in declarations that are unused;
@@ -688,26 +684,37 @@ pub fn translate(
688684
}
689685
}
690686

691-
// Export top-level value declarations
692-
for top_id in &t.ast_context.c_decls_top {
693-
use CDeclKind::*;
694-
let needs_export = match t.ast_context[*top_id].kind {
695-
Function { is_implicit, .. } => !is_implicit,
696-
Variable { .. } => true,
697-
MacroObject { .. } => true, // Depends on `tcfg.translate_const_macros`, but handled in `fn convert_const_macro_expansion`.
698-
MacroFunction { .. } => true, // Depends on `tcfg.translate_fn_macros`, but handled in `fn convert_fn_macro_invocation`.
699-
_ => false,
700-
};
701-
if needs_export {
702-
let decl = t.ast_context.get_decl(top_id).unwrap();
687+
// Export top-level value declarations.
688+
// We do this in a conversion pass and then an insertion pass
689+
// so that the conversion order can differ from the order they're emitted in.
690+
let mut converted_decls = t
691+
.ast_context
692+
.c_decls_top
693+
.iter()
694+
.filter_map(|&top_id| {
695+
use CDeclKind::*;
696+
let needs_export = match t.ast_context[top_id].kind {
697+
Function { is_implicit, .. } => !is_implicit,
698+
Variable { .. } => true,
699+
MacroObject { .. } => true, // Depends on `tcfg.translate_const_macros`, but handled in `fn convert_const_macro_expansion`.
700+
MacroFunction { .. } => true, // Depends on `tcfg.translate_fn_macros`, but handled in `fn convert_fn_macro_invocation`.
701+
_ => false,
702+
};
703+
if !needs_export {
704+
return None;
705+
}
706+
707+
let decl = t.ast_context.get_decl(&top_id).unwrap();
703708
let decl_file_id = t.ast_context.file_id(decl);
704709

705710
if t.tcfg.reorganize_definitions
706711
&& decl_file_id.map_or(false, |id| id != t.main_file)
707712
{
708713
t.cur_file.set(decl_file_id);
709714
}
710-
match t.convert_decl(ctx, *top_id) {
715+
716+
// TODO use `.inspect_err` once stabilized in Rust 1.76.
717+
let converted = match t.convert_decl(ctx, top_id) {
711718
Err(e) => {
712719
let decl_identifier = decl.kind.get_name().map_or_else(
713720
|| {
@@ -719,32 +726,47 @@ pub fn translate(
719726
);
720727
let msg = format!("Failed to translate {}: {}", decl_identifier, e);
721728
translate_failure(t.tcfg, &msg);
729+
Err(e)
722730
}
723-
Ok(converted_decl) => {
724-
use ConvertedDecl::*;
725-
match converted_decl {
726-
Item(item) => {
727-
t.insert_item(item, decl);
728-
}
729-
ForeignItem(item) => {
730-
t.insert_foreign_item(*item, decl);
731-
}
732-
Items(items) => {
733-
for item in items {
734-
t.insert_item(item, decl);
735-
}
736-
}
737-
NoItem => {}
738-
}
739-
}
731+
Ok(converted) => Ok(converted),
740732
}
733+
.ok()?;
734+
741735
t.cur_file.take();
742736

743-
if t.tcfg.reorganize_definitions
744-
&& decl_file_id.map_or(false, |id| id != t.main_file)
745-
{
746-
t.generate_submodule_imports(*top_id, decl_file_id);
737+
Some((top_id, converted))
738+
})
739+
.collect::<HashMap<_, _>>();
740+
741+
t.ast_context.sort_top_decls_for_emitting();
742+
743+
for top_id in &t.ast_context.c_decls_top {
744+
let decl = t.ast_context.get_decl(top_id).unwrap();
745+
let decl_file_id = t.ast_context.file_id(decl);
746+
// TODO use `let else` when it stabilizes.
747+
let converted_decl = match converted_decls.remove(top_id) {
748+
Some(converted) => converted,
749+
None => continue,
750+
};
751+
752+
use ConvertedDecl::*;
753+
match converted_decl {
754+
Item(item) => {
755+
t.insert_item(item, decl);
747756
}
757+
ForeignItem(item) => {
758+
t.insert_foreign_item(*item, decl);
759+
}
760+
Items(items) => {
761+
for item in items {
762+
t.insert_item(item, decl);
763+
}
764+
}
765+
NoItem => {}
766+
};
767+
768+
if t.tcfg.reorganize_definitions && decl_file_id.map_or(false, |id| id != t.main_file) {
769+
t.generate_submodule_imports(*top_id, decl_file_id);
748770
}
749771
}
750772

0 commit comments

Comments
 (0)