diff --git a/c2rust-refactor/src/ast_builder/builder.rs b/c2rust-refactor/src/ast_builder/builder.rs index 3ebbac1568..501c6c1fdf 100644 --- a/c2rust-refactor/src/ast_builder/builder.rs +++ b/c2rust-refactor/src/ast_builder/builder.rs @@ -352,6 +352,7 @@ pub struct Builder { unsafety: Unsafe, constness: Const, ext: Extern, + inline: Inline, attrs: AttrVec, span: Span, id: NodeId, @@ -371,6 +372,7 @@ impl Builder { unsafety: Unsafe::No, constness: Const::No, ext: Extern::None, + inline: Inline::No, attrs: AttrVec::new(), span: DUMMY_SP, id: DUMMY_NODE_ID, @@ -388,6 +390,13 @@ impl Builder { self.vis("pub") } + pub fn inline(self) -> Self { + Builder { + inline: Inline::Yes, + ..self + } + } + pub fn set_mutbl>(self, mutbl: M) -> Self { let mutbl = mutbl.make(&self); Builder { @@ -1776,7 +1785,7 @@ impl Builder { inner_span: self.span, inject_use_span: DUMMY_SP, }; - ModKind::Loaded(items, Inline::Yes, spans) + ModKind::Loaded(items, self.inline, spans) } pub fn mac_item(self, mac: M) -> P diff --git a/c2rust-refactor/src/ast_manip/load_modules.rs b/c2rust-refactor/src/ast_manip/load_modules.rs new file mode 100644 index 0000000000..df1f9ade69 --- /dev/null +++ b/c2rust-refactor/src/ast_manip/load_modules.rs @@ -0,0 +1,84 @@ +use rustc_ast::mut_visit::{self, MutVisitor}; +use rustc_ast::ptr::P; +use rustc_ast::*; +use rustc_parse::new_parser_from_file; +use rustc_session::parse::ParseSess; +use rustc_span::source_map::SourceMap; +use rustc_span::FileName; +use smallvec::SmallVec; +use std::path::PathBuf; + +struct LoadModules<'a> { + parse_sess: &'a ParseSess, + source_map: &'a SourceMap, + dir_path: PathBuf, +} + +impl<'a> MutVisitor for LoadModules<'a> { + fn flat_map_item(&mut self, mut i: P) -> SmallVec<[P; 1]> { + let Item { + ref mut attrs, + ref span, + ref ident, + kind: ItemKind::Mod(_, ref mut mod_kind), + .. + } = *i else { + return mut_visit::noop_flat_map_item(i, self); + }; + + match mod_kind { + ModKind::Loaded(_items, Inline::Yes, _spans) => { + // TODO: handle #[path="..."] + } + + ModKind::Loaded(_items, Inline::No, _spans) => { + // We shouldn't be seeing any loaded modules at this point + panic!("unexpected loaded module: {i:?}"); + } + + ModKind::Unloaded => { + // Look for dir_path/foo.rs, then try dir_path/foo/mod.rs + let mut mod_file_path = self.dir_path.join(ident.as_str()).with_extension("rs"); + if !self.source_map.file_exists(&mod_file_path) { + mod_file_path = self.dir_path.join(ident.as_str()).with_file_name("mod.rs"); + } + if !self.source_map.file_exists(&mod_file_path) { + panic!("unable to load module file {mod_file_path:?}"); + } + + let mut parser = + new_parser_from_file(&self.parse_sess, &mod_file_path, Some(*span)); + let (mut inner_attrs, items, inner_span) = parser + .parse_mod(&token::Eof) + .expect("failed to parse {mod_file_path:?}"); + + attrs.append(&mut inner_attrs); + *mod_kind = ModKind::Loaded(items, Inline::No, inner_span); + } + } + + self.dir_path.push(ident.as_str()); + let res = mut_visit::noop_flat_map_item(i, self); + self.dir_path.pop(); + + res + } +} + +pub fn load_modules(krate: &mut Crate, parse_sess: &ParseSess, source_map: &SourceMap) { + let file_path = match source_map.span_to_filename(krate.spans.inner_span) { + FileName::Real(name) => name + .into_local_path() + .expect("attempting to resolve a file path in an external file"), + other => panic!("crate is not from a real file: {other:?}"), + }; + let dir_path = file_path.parent().unwrap_or(&file_path).to_owned(); + + let mut lm = LoadModules { + parse_sess, + source_map, + dir_path, + }; + + lm.visit_crate(krate); +} diff --git a/c2rust-refactor/src/ast_manip/mod.rs b/c2rust-refactor/src/ast_manip/mod.rs index 151051a485..3be22eccdf 100644 --- a/c2rust-refactor/src/ast_manip/mod.rs +++ b/c2rust-refactor/src/ast_manip/mod.rs @@ -11,9 +11,11 @@ mod fold; mod get_node_id; mod get_span; mod list_node_ids; +mod load_modules; mod output_exprs; mod remove_paren; mod seq_edit; +mod span_maps; mod visit; mod visit_node; @@ -29,9 +31,11 @@ pub use self::fold::{FlatMapNodes, MutVisit, MutVisitNodes, WalkAst}; pub use self::get_node_id::{GetNodeId, MaybeGetNodeId}; pub use self::get_span::GetSpan; pub use self::list_node_ids::ListNodeIds; +pub use self::load_modules::load_modules; pub use self::output_exprs::fold_output_exprs; pub use self::remove_paren::remove_paren; pub use self::seq_edit::{fold_blocks, fold_modules}; +pub use self::span_maps::{AstSpanMaps, NodeSpan, SpanNodeKind}; pub use self::visit::Visit; pub use self::visit_node::{visit_nodes, visit_nodes_post, VisitNode}; diff --git a/c2rust-refactor/src/ast_manip/span_maps.rs b/c2rust-refactor/src/ast_manip/span_maps.rs new file mode 100644 index 0000000000..a85a13e578 --- /dev/null +++ b/c2rust-refactor/src/ast_manip/span_maps.rs @@ -0,0 +1,170 @@ +use rustc_ast::visit::{self, AssocCtxt, Visitor}; +use rustc_ast::*; +use rustc_span::Span; +use std::collections::HashMap; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum SpanNodeKind { + Crate, + Block, + Pat, + PatField, + Stmt, + Local, + Arm, + ExprField, + Expr, + AssocConstraint, + Ty, + Param, + Variant, + FieldDef, + Item, + ForeignItem, + AssocItem, + // We need a separate kind for ExprKind::Path because + // the rustc macro expander emits `*foo` expressions where + // both the outer and inner expressions have the same span + // We disambiguate by assigning (span, Expr) to the outer one, + // and (span, PathExpr) to the inner expression. + PathExpr, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct NodeSpan { + pub span: Span, + pub kind: SpanNodeKind, +} + +impl NodeSpan { + pub fn new(span: Span, kind: SpanNodeKind) -> Self { + Self { span, kind } + } +} + +#[derive(Default, Clone)] +pub struct AstSpanMaps { + pub node_id_to_span_map: HashMap, + pub span_to_node_id_map: HashMap, +} + +impl AstSpanMaps { + pub fn new(krate: &Crate) -> Self { + let mut mapper = AstSpanMapper::default(); + mapper.visit_crate(krate); + mapper.0 + } +} + +#[derive(Default, Clone)] +struct AstSpanMapper(AstSpanMaps); + +impl AstSpanMapper { + fn insert_mapping(&mut self, id: NodeId, span: Span, kind: SpanNodeKind) { + if id == DUMMY_NODE_ID || span.is_dummy() { + return; + } + + let ns = NodeSpan { span, kind }; + let old_ns = self.0.node_id_to_span_map.insert(id, ns); + let _old_id = self.0.span_to_node_id_map.insert(ns, id); + + assert!( + old_ns.is_none(), + "id {id:?} already has span {old_ns:?} != {ns:?}" + ); + // Some spans can show up in multiple nodes + //assert!(old_id.is_none(), "span {ns:?} already has id {old_id:?} != {id:?}"); + } +} + +impl Visitor<'_> for AstSpanMapper { + fn visit_crate(&mut self, krate: &Crate) { + self.insert_mapping(krate.id, krate.spans.inner_span, SpanNodeKind::Crate); + visit::walk_crate(self, krate); + } + + fn visit_block(&mut self, block: &Block) { + self.insert_mapping(block.id, block.span, SpanNodeKind::Block); + visit::walk_block(self, block); + } + + fn visit_pat(&mut self, pat: &Pat) { + self.insert_mapping(pat.id, pat.span, SpanNodeKind::Pat); + visit::walk_pat(self, pat); + } + + fn visit_pat_field(&mut self, pf: &PatField) { + self.insert_mapping(pf.id, pf.span, SpanNodeKind::PatField); + visit::walk_pat_field(self, pf); + } + + fn visit_stmt(&mut self, stmt: &Stmt) { + self.insert_mapping(stmt.id, stmt.span, SpanNodeKind::Stmt); + visit::walk_stmt(self, stmt); + } + + fn visit_local(&mut self, local: &Local) { + self.insert_mapping(local.id, local.span, SpanNodeKind::Local); + visit::walk_local(self, local); + } + + fn visit_arm(&mut self, arm: &Arm) { + self.insert_mapping(arm.id, arm.span, SpanNodeKind::Arm); + visit::walk_arm(self, arm); + } + + fn visit_expr_field(&mut self, ef: &ExprField) { + self.insert_mapping(ef.id, ef.span, SpanNodeKind::ExprField); + visit::walk_expr_field(self, ef); + } + + fn visit_expr(&mut self, expr: &Expr) { + if matches!(expr.kind, ExprKind::Path(..)) { + self.insert_mapping(expr.id, expr.span, SpanNodeKind::PathExpr); + } else { + self.insert_mapping(expr.id, expr.span, SpanNodeKind::Expr); + } + visit::walk_expr(self, expr); + } + + fn visit_assoc_constraint(&mut self, ac: &AssocConstraint) { + self.insert_mapping(ac.id, ac.span, SpanNodeKind::AssocConstraint); + visit::walk_assoc_constraint(self, ac); + } + + fn visit_ty(&mut self, ty: &Ty) { + self.insert_mapping(ty.id, ty.span, SpanNodeKind::Ty); + visit::walk_ty(self, ty); + } + + fn visit_param(&mut self, param: &Param) { + self.insert_mapping(param.id, param.span, SpanNodeKind::Param); + visit::walk_param(self, param); + } + + fn visit_variant(&mut self, var: &Variant) { + self.insert_mapping(var.id, var.span, SpanNodeKind::Variant); + visit::walk_variant(self, var); + } + + fn visit_field_def(&mut self, fd: &FieldDef) { + self.insert_mapping(fd.id, fd.span, SpanNodeKind::FieldDef); + visit::walk_field_def(self, fd); + } + + fn visit_item(&mut self, i: &Item) { + self.insert_mapping(i.id, i.span, SpanNodeKind::Item); + visit::walk_item(self, i); + } + + fn visit_foreign_item(&mut self, i: &ForeignItem) { + self.insert_mapping(i.id, i.span, SpanNodeKind::ForeignItem); + visit::walk_foreign_item(self, i); + } + + fn visit_assoc_item(&mut self, i: &AssocItem, ctxt: AssocCtxt) { + self.insert_mapping(i.id, i.span, SpanNodeKind::AssocItem); + visit::walk_assoc_item(self, i, ctxt); + } +} diff --git a/c2rust-refactor/src/collapse/mac_table.rs b/c2rust-refactor/src/collapse/mac_table.rs index af9de77452..dddec0d7c9 100644 --- a/c2rust-refactor/src/collapse/mac_table.rs +++ b/c2rust-refactor/src/collapse/mac_table.rs @@ -13,7 +13,7 @@ use rustc_target::spec::abi::Abi; use rustc_ast::ptr::P; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_span::source_map::Spanned; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; use std::fmt::Debug; use std::rc::Rc; @@ -399,7 +399,7 @@ fn is_derived<'a>(invoc: InvocKind<'a>, new: MacNodeRef<'a>) -> bool { _ => None, }; if let Some(attrs) = attrs { - if crate::util::contains_name(attrs, Symbol::intern("automatically_derived")) { + if crate::util::contains_name(attrs, sym::automatically_derived) { return true; } } @@ -520,9 +520,9 @@ impl CollectMacros for NodeId { } fn has_macro_attr(attrs: &[Attribute]) -> bool { - crate::util::contains_name(attrs, Symbol::intern("derive")) - || crate::util::contains_name(attrs, Symbol::intern("cfg")) - || crate::util::contains_name(attrs, Symbol::intern("test")) + crate::util::contains_name(attrs, sym::derive) + || crate::util::contains_name(attrs, sym::cfg) + || crate::util::contains_name(attrs, sym::test) } trait MaybeInvoc { diff --git a/c2rust-refactor/src/command.rs b/c2rust-refactor/src/command.rs index a94ec20d53..acbd80db81 100644 --- a/c2rust-refactor/src/command.rs +++ b/c2rust-refactor/src/command.rs @@ -27,8 +27,9 @@ use crate::ast_manip::map_ast_into; use crate::ast_manip::number_nodes::{ number_nodes, number_nodes_with, reset_node_ids, NodeIdCounter, }; +use crate::ast_manip::AstSpanMaps; use crate::ast_manip::{collect_comments, gather_comments, Comment, CommentMap}; -use crate::ast_manip::{remove_paren, ListNodeIds, MutVisit, Visit}; +use crate::ast_manip::{load_modules, remove_paren, ListNodeIds, MutVisit, Visit}; use crate::collapse::CollapseInfo; use crate::driver::{self, Phase}; use crate::file_io::FileIO; @@ -315,6 +316,9 @@ impl RefactorState { // Initialize initial parsed crate if not previously parsed let disk_state = disk_state.get_or_insert_with(|| { let mut krate = parse.peek().clone(); + // Expand all the Unloaded modules ourselves + // since rustc folded that operation into expansion + load_modules(&mut krate, &session.parse_sess, source_map); remove_paren(&mut krate); number_nodes(&mut krate); @@ -324,16 +328,25 @@ impl RefactorState { // The newly loaded `krate` and reinitialized `node_map` reference // none of the old `parsed_nodes`. That means we can reset the ID // counter without risk of ID collisions. + let mut need_load = true; let mut cs = CommandState::new( - krate - .take() - .unwrap_or_else(|| disk_state.orig_krate.clone()), + krate.take().unwrap_or_else(|| { + // The original crate already has all modules + need_load = false; + disk_state.orig_krate.clone() + }), Phase::Phase1, marks.clone(), ParsedNodes::default(), node_id_counter.clone(), ); + // Expand all the Unloaded modules ourselves + // since rustc folded that operation into expansion + if need_load { + load_modules(&mut *cs.krate.borrow_mut(), &session.parse_sess, source_map); + } + let unexpanded = cs.krate().clone(); if phase != Phase::Phase1 { // We need all the `NodeId`s for rewriting, @@ -404,6 +417,7 @@ impl RefactorState { node_id_to_def_id, def_id_to_node_id, GenerationalTyCtxt(tcx, tcx_gen.clone()), + AstSpanMaps::new(&expanded), ); profile_end!("Lower to HIR"); @@ -432,6 +446,7 @@ impl RefactorState { node_id_to_def_id, def_id_to_node_id, GenerationalTyCtxt(tcx, tcx_gen.clone()), + AstSpanMaps::new(&expanded), ); profile_end!("Compiler Phase 3"); diff --git a/c2rust-refactor/src/context.rs b/c2rust-refactor/src/context.rs index 77cf56cdc1..bc4b6cdc77 100644 --- a/c2rust-refactor/src/context.rs +++ b/c2rust-refactor/src/context.rs @@ -13,7 +13,7 @@ use rustc_hir::def::{DefKind, Namespace, Res}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId}; use rustc_hir::{self as hir, BodyId, HirId, Node}; use rustc_index::vec::IndexVec; -use rustc_middle::hir::map as hir_map; +use rustc_middle::hir::{map as hir_map, nested_filter}; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{FnSig, ParamEnv, PolyFnSig, Ty, TyCtxt, TyKind}; use rustc_session::config::CrateType; @@ -22,7 +22,7 @@ use rustc_span::Span; use crate::ast_builder::mk; use crate::ast_manip::util::{is_export_attr, namespace}; -use crate::ast_manip::AstEquiv; +use crate::ast_manip::{AstEquiv, AstSpanMaps, NodeSpan, SpanNodeKind}; use crate::command::{GenerationalTyCtxt, TyCtxtGeneration}; use crate::reflect; use crate::{expect, match_or}; @@ -48,6 +48,70 @@ impl<'a, 'tcx> RefactorCtxt<'a, 'tcx> { } } +type SpanToHirMap = FxHashMap; + +struct SpanToHirMapper<'hir> { + hir_map: hir_map::Map<'hir>, + span_to_hir_map: SpanToHirMap, +} + +fn hir_id_to_span(id: HirId, hir_map: hir_map::Map) -> Option { + use SpanNodeKind::*; + let ns = match hir_map.find(id) { + Some(Node::Param(param)) => Some(NodeSpan::new(param.span, Param)), + Some(Node::Item(item)) => Some(NodeSpan::new(item.span, Item)), + Some(Node::ForeignItem(foreign_item)) => { + Some(NodeSpan::new(foreign_item.span, ForeignItem)) + } + Some(Node::TraitItem(trait_item)) => Some(NodeSpan::new(trait_item.span, AssocItem)), + Some(Node::ImplItem(impl_item)) => Some(NodeSpan::new(impl_item.span, AssocItem)), + Some(Node::Variant(variant)) => Some(NodeSpan::new(variant.span, Variant)), + Some(Node::Field(field)) => Some(NodeSpan::new(field.span, FieldDef)), + Some(Node::Expr(expr)) => { + if matches!(expr.kind, hir::ExprKind::Path(..)) { + Some(NodeSpan::new(expr.span, PathExpr)) + } else { + Some(NodeSpan::new(expr.span, Expr)) + } + } + Some(Node::Stmt(stmt)) => Some(NodeSpan::new(stmt.span, Stmt)), + // Intentionally skip PathSegment to avoid collisions + Some(Node::Ty(ty)) => Some(NodeSpan::new(ty.span, Ty)), + // We do not have a SpanNodeKind for TyBinding + // We do not have a SpanNodeKind for TraitRef + Some(Node::Pat(pat)) => Some(NodeSpan::new(pat.span, Pat)), + Some(Node::Arm(arm)) => Some(NodeSpan::new(arm.span, Arm)), + Some(Node::Block(block)) => Some(NodeSpan::new(block.span, Block)), + // We do not have a SpanNodeKind for Ctor + // We do not have a SpanNodeKind for Lifetime + // We do not have a SpanNodeKind for GenericParam + // We do not have a SpanNodeKind for Infer + Some(Node::Local(local)) => Some(NodeSpan::new(local.span, Local)), + Some(Node::Crate(item)) => Some(NodeSpan::new(item.spans.inner_span, Crate)), + _ => None, + }; + + // Filter out dummy spans + ns.filter(|ns| !ns.span.is_dummy()) +} + +impl<'hir> hir::intravisit::Visitor<'hir> for SpanToHirMapper<'hir> { + type NestedFilter = nested_filter::OnlyBodies; + + fn nested_visit_map(&mut self) -> Self::Map { + self.hir_map + } + + fn visit_id(&mut self, id: HirId) { + if let Some(ns) = hir_id_to_span(id, self.hir_map) { + let _old_id = self.span_to_hir_map.insert(ns, id); + // Sometimes we get different HirId's with the same span, e.g., Expr + // TODO: we still should assert here + //assert!(old_id.is_none(), "span {ns:?} already has id {old_id:?} != {id:?}"); + } + } +} + #[derive(Clone)] pub struct HirMap<'hir> { map: hir_map::Map<'hir>, @@ -58,6 +122,9 @@ pub struct HirMap<'hir> { node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, + + span_to_hir_map: SpanToHirMap, + ast_span_maps: AstSpanMaps, } impl<'hir> HirMap<'hir> { @@ -66,12 +133,24 @@ impl<'hir> HirMap<'hir> { map: hir_map::Map<'hir>, node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, + ast_span_maps: AstSpanMaps, ) -> Self { + let mut mapper = SpanToHirMapper { + hir_map: map, + span_to_hir_map: Default::default(), + }; + map.visit_all_item_likes_in_crate(&mut mapper); + let SpanToHirMapper { + span_to_hir_map, .. + } = mapper; + Self { map, max_node_id, node_id_to_def_id, def_id_to_node_id, + span_to_hir_map, + ast_span_maps, } } } @@ -608,9 +687,14 @@ impl<'hir> HirMap<'hir> { if id > self.max_node_id { None } else { - self.node_id_to_def_id + if let Some(ldid) = self.node_id_to_def_id.get(&id) { + return Some(self.map.local_def_id_to_hir_id(*ldid)); + } + + self.ast_span_maps + .node_id_to_span_map .get(&id) - .map(|ldid| self.map.local_def_id_to_hir_id(*ldid)) + .and_then(|span| self.span_to_hir_map.get(&span).copied()) } } @@ -640,6 +724,11 @@ impl<'hir> HirMap<'hir> { } pub fn hir_to_node_id(&self, id: HirId) -> NodeId { + let ns = hir_id_to_span(id, self.map); + if let Some(id) = ns.and_then(|ns| self.ast_span_maps.span_to_node_id_map.get(&ns)) { + return *id; + } + self.map .opt_local_def_id(id) .and_then(|id| self.def_id_to_node_id.get(id)) @@ -918,7 +1007,7 @@ impl<'a, 'tcx, 'b> TypeCompare<'a, 'tcx, 'b> { (Some(ty1), Some(ty2)) => return self.structural_eq_tys(ty1, ty2), _ => {} } - match (self.cx.try_resolve_ty(ty1), self.cx.try_resolve_ty(ty1)) { + match (self.cx.try_resolve_ty(ty1), self.cx.try_resolve_ty(ty2)) { (Some(did1), Some(did2)) => self.structural_eq_defs(did1, did2), _ => ty1.unnamed_equiv(ty2), } diff --git a/c2rust-refactor/src/driver.rs b/c2rust-refactor/src/driver.rs index 9ac42f1eea..fc06478b9b 100644 --- a/c2rust-refactor/src/driver.rs +++ b/c2rust-refactor/src/driver.rs @@ -42,7 +42,7 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::sync::Arc; -use crate::ast_manip::remove_paren; +use crate::ast_manip::{remove_paren, AstSpanMaps}; use crate::command::{GenerationalTyCtxt, RefactorState, Registry}; use crate::file_io::{ArcFileIO, FileIO}; // TODO: don't forget to call span_fix after parsing @@ -76,6 +76,7 @@ impl<'a, 'tcx: 'a> RefactorCtxt<'a, 'tcx> { node_id_to_def_id: FxHashMap, def_id_to_node_id: IndexVec, tcx: GenerationalTyCtxt<'tcx>, + span_maps: AstSpanMaps, ) -> RefactorCtxt<'a, 'tcx> { RefactorCtxt::new( sess, @@ -84,6 +85,7 @@ impl<'a, 'tcx: 'a> RefactorCtxt<'a, 'tcx> { map, node_id_to_def_id, def_id_to_node_id, + span_maps, )), Some(tcx), ) @@ -288,7 +290,7 @@ where // Force disable incremental compilation. It causes panics with multiple typechecking. config.opts.incremental = None; config.file_loader = file_loader; - config.opts.edition = Edition::Edition2018; + config.opts.edition = Edition::Edition2021; interface::run_compiler(config, f) } @@ -308,7 +310,7 @@ where // Force disable incremental compilation. It causes panics with multiple typechecking. config.opts.incremental = None; - run_in_thread_pool_with_globals(Edition::Edition2018, 1, move || { + run_in_thread_pool_with_globals(Edition::Edition2021, 1, move || { let state = RefactorState::new(config, cmd_reg, file_io, marks); f(state) }) diff --git a/c2rust-refactor/src/macros.rs b/c2rust-refactor/src/macros.rs index c6979f9d34..a286197d36 100644 --- a/c2rust-refactor/src/macros.rs +++ b/c2rust-refactor/src/macros.rs @@ -8,15 +8,25 @@ macro_rules! match_or { }; } +#[macro_export] +macro_rules! match_or_else { + ([$e:expr] $($arm_pat:pat => $arm_body:expr),*; $or_else:expr) => { + match $e { + $( $arm_pat => $arm_body, )* + ref x @ _ => $or_else(x), + } + }; +} + #[macro_export] macro_rules! expect { ([$e:expr] $arm_pat:pat => $arm_body:expr) => { - $crate::match_or!([$e] $arm_pat => $arm_body; - panic!("expected {}", stringify!($arm_pat))) + $crate::match_or_else!([$e] $arm_pat => $arm_body; + |x| panic!("expected {}, got {:?}", stringify!($arm_pat), x)) }; ([$e:expr] $($arm_pat:pat => $arm_body:expr),*) => { - $crate::match_or!([$e] $($arm_pat => $arm_body),*; - panic!("expected one of: {}", stringify!($($arm_pat),*))) + $crate::match_or_else!([$e] $($arm_pat => $arm_body),*; + |x| panic!("expected one of: {}, got {:?}", stringify!($($arm_pat),*), x)) }; } diff --git a/c2rust-refactor/src/path_edit.rs b/c2rust-refactor/src/path_edit.rs index 13b4c9edb6..9895796f9c 100644 --- a/c2rust-refactor/src/path_edit.rs +++ b/c2rust-refactor/src/path_edit.rs @@ -119,7 +119,7 @@ where match hir.kind { hir::TyKind::Path(ref qpath) => { // Bail out early if it's not really a path type in the original AST. - match t.kind { + match t.peel_refs().kind { TyKind::ImplicitSelf => return, _ => {} } diff --git a/c2rust-refactor/src/transform/reorganize_definitions.rs b/c2rust-refactor/src/transform/reorganize_definitions.rs index 4fce6ece18..361d189587 100644 --- a/c2rust-refactor/src/transform/reorganize_definitions.rs +++ b/c2rust-refactor/src/transform/reorganize_definitions.rs @@ -701,9 +701,18 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> { // FIXME: we should also check if items overlap mod_items.extend(new_items.into_iter()); } else { - let new_mod = mk().mod_(new_items); - // TODO: do this again when we switch back to outline modules - //new_mod.inline = inline; + // TODO: we should outline the modules, but there + // is currently an issue with the pretty-printer + // where it both writes an output file, and the inline + // module in the parent + // + //let modb = if inline { + // mk.inline() + //} else { + // mk() + //}; + let modb = mk().inline(); + let new_mod = modb.mod_(new_items); let new_mod_item = mk() .pub_() .id(mod_info.id)