@@ -287,6 +287,79 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
287287 keep_items
288288 }
289289
290+ // First, remove and store `impl` items, indexing them by the type they belong to.
291+ let mut impls: HashMap < DefId , MovedDeclImpl > = HashMap :: new ( ) ;
292+ FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
293+ if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
294+ let header_item = item. clone ( ) ;
295+ if let ItemKind :: Mod ( _, ModKind :: Loaded ( ref mut mod_items, _, _) ) = & mut item. kind {
296+ mod_items. retain ( |item| {
297+ if let ItemKind :: Impl ( r#impl) = & item. kind {
298+ // Only keep `impl` items with simple path types, and only if they
299+ // contain nothing but `const` items.
300+ fn impl_parent_decl < ' hir > (
301+ cx : & ' hir RefactorCtxt ,
302+ r#impl : & Impl ,
303+ ) -> Option < ( DefId , & ' hir hir:: Path < ' hir > ) >
304+ {
305+ // Only inherent `impl`s that contain no items other than `const`.
306+ if r#impl. of_trait . is_some ( )
307+ || !r#impl
308+ . items
309+ . iter ( )
310+ . all ( |item| matches ! ( item. kind, AssocItemKind :: Const ( ..) ) )
311+ {
312+ return None ;
313+ } ;
314+ let ty = match cx. hir_map ( ) . find ( r#impl. self_ty . id ) ? {
315+ hir:: Node :: Ty ( ty) => ty,
316+ _ => return None ,
317+ } ;
318+ let ty_path = match & ty. kind {
319+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => path,
320+ _ => return None ,
321+ } ;
322+ match ty_path. res {
323+ Res :: Def ( _, def_id) => Some ( ( def_id, ty_path) ) ,
324+ _ => None ,
325+ }
326+ }
327+
328+ if let Some ( ( decl_def_id, impl_type_path) ) =
329+ impl_parent_decl ( & self . cx , & r#impl)
330+ {
331+ match impls. entry ( decl_def_id) {
332+ Entry :: Occupied ( _) => warn ! (
333+ "decl {decl_def_id:?} ({impl_type_path:?}) \
334+ has more than one `impl` block, dropping the others"
335+ ) ,
336+ Entry :: Vacant ( entry) => {
337+ let parent_header =
338+ HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
339+ entry. insert ( MovedDeclImpl {
340+ item : item. clone ( ) ,
341+ parent_header,
342+ } ) ;
343+ }
344+ }
345+ }
346+
347+ false
348+ } else {
349+ true
350+ }
351+ } ) ;
352+
353+ smallvec ! [ item]
354+ } else {
355+ panic ! ( "Unexpected Item kind with header_src attribute" ) ;
356+ }
357+ } else {
358+ smallvec ! [ item]
359+ }
360+ } ) ;
361+
362+ // Process all the remaining items.
290363 let mut declarations = HeaderDeclarations :: new ( self . cx ) ;
291364 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
292365 if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
@@ -321,8 +394,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
321394 }
322395 }
323396
397+ let new_def_id = self . cx . node_def_id ( item. id ) ;
324398 let header_info = HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
325- let inserted = declarations. insert_item ( item. clone ( ) , header_info) ;
399+ let inserted = declarations. insert_item (
400+ item. clone ( ) ,
401+ header_info,
402+ impls. remove ( & new_def_id) ,
403+ ) ;
326404 // Keep the item if we are not collapsing it
327405 !inserted
328406 } ) ;
@@ -676,7 +754,7 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
676754 } else {
677755 let namespace = self . cx . item_namespace ( & item) ;
678756 if let Some ( namespace) = namespace {
679- match declarations. find_item ( item, namespace) {
757+ match declarations. find_item ( item, namespace, None ) {
680758 ContainsDecl :: NotContained => false ,
681759 ContainsDecl :: Equivalent ( _) => true ,
682760 ContainsDecl :: Definition ( _) => true ,
@@ -750,6 +828,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
750828 // Remove src_loc attributes
751829 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
752830 item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
831+
832+ if let ItemKind :: Impl ( r#impl) = & mut item. kind {
833+ for item in & mut r#impl. items {
834+ item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
835+ }
836+ }
837+
753838 smallvec ! [ item]
754839 } ) ;
755840 FlatMapNodes :: visit ( krate, |mut item : P < ForeignItem > | {
@@ -1085,10 +1170,25 @@ struct MovedDecl {
10851170 namespace : Namespace ,
10861171 loc : Option < SrcLoc > ,
10871172 parent_header : HeaderInfo ,
1173+
1174+ /// The `impl` block that belongs to the definition, if any.
1175+ r#impl : Option < MovedDeclImpl > ,
1176+ }
1177+
1178+ #[ derive( Debug , Clone ) ]
1179+ struct MovedDeclImpl {
1180+ item : P < Item > ,
1181+ parent_header : HeaderInfo ,
10881182}
10891183
10901184impl MovedDecl {
1091- fn new < T > ( decl : T , def_id : DefId , namespace : Namespace , parent_header : HeaderInfo ) -> Self
1185+ fn new < T > (
1186+ decl : T ,
1187+ def_id : DefId ,
1188+ namespace : Namespace ,
1189+ parent_header : HeaderInfo ,
1190+ r#impl : Option < MovedDeclImpl > ,
1191+ ) -> Self
10921192 where
10931193 T : Into < DeclKind > ,
10941194 {
@@ -1105,6 +1205,7 @@ impl MovedDecl {
11051205 namespace,
11061206 loc,
11071207 parent_header,
1208+ r#impl,
11081209 }
11091210 }
11101211
@@ -1291,14 +1392,12 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
12911392
12921393 /// Add an item into the module. If it has a name conflict with an existing
12931394 /// item, choose the definition item over any declarations.
1294- pub fn insert_item ( & mut self , mut item : P < Item > , parent_header : HeaderInfo ) -> bool {
1295- let namespace = self . cx . item_namespace ( & item) ;
1296- let new_def_id = self . cx . node_def_id ( item. id ) ;
1297- let ident = if let ItemKind :: Use ( tree) = & item. kind {
1298- tree. ident ( )
1299- } else {
1300- item. ident
1301- } ;
1395+ pub fn insert_item (
1396+ & mut self ,
1397+ mut item : P < Item > ,
1398+ parent_header : HeaderInfo ,
1399+ r#impl : Option < MovedDeclImpl > ,
1400+ ) -> bool {
13021401 match & item. kind {
13031402 // We have to disambiguate anonymous items by contents,
13041403 // since we don't have a proper Ident.
@@ -1307,7 +1406,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13071406 // ident_map.
13081407 ItemKind :: Use ( tree) if is_nested ( tree) => {
13091408 for u in split_uses ( item) . into_iter ( ) {
1310- self . insert_item ( u, parent_header. clone ( ) ) ;
1409+ self . insert_item ( u, parent_header. clone ( ) , r#impl . clone ( ) ) ;
13111410 }
13121411 true
13131412 }
@@ -1335,11 +1434,24 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13351434 // we don't have any items with the same name but different
13361435 // contents.
13371436 _ => {
1437+ let namespace = self . cx . item_namespace ( & item) ;
1438+ let new_def_id = self . cx . node_def_id ( item. id ) ;
1439+ let ident = if let ItemKind :: Use ( tree) = & item. kind {
1440+ tree. ident ( )
1441+ } else {
1442+ item. ident
1443+ } ;
13381444 let unnamed = ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) ;
1339- let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) ) {
1445+ let impl_item = r#impl. as_ref ( ) . map ( |r#impl| & * r#impl. item ) ;
1446+ let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) , impl_item) {
13401447 ContainsDecl :: NotContained => {
1341- let new_item =
1342- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1448+ let new_item = MovedDecl :: new (
1449+ item,
1450+ new_def_id,
1451+ namespace. unwrap ( ) ,
1452+ parent_header,
1453+ r#impl,
1454+ ) ;
13431455 if unnamed {
13441456 self . unnamed_items [ namespace. unwrap ( ) ] . push ( new_item) ;
13451457 } else {
@@ -1359,17 +1471,27 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13591471 ContainsDecl :: Use ( existing) => {
13601472 let existing_def_id = existing. def_id ;
13611473 existing. join_visibility ( & item. vis . kind ) ;
1362- * existing =
1363- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1474+ * existing = MovedDecl :: new (
1475+ item,
1476+ new_def_id,
1477+ namespace. unwrap ( ) ,
1478+ parent_header,
1479+ r#impl,
1480+ ) ;
13641481 Some ( ( existing_def_id, new_def_id) )
13651482 }
13661483
13671484 ContainsDecl :: Equivalent ( existing) if existing. is_foreign ( ) => {
13681485 let existing_def_id = existing. def_id ;
13691486 item. vis . kind =
13701487 join_visibility ( & existing. visibility ( ) . kind , & item. vis . kind ) ;
1371- * existing =
1372- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1488+ * existing = MovedDecl :: new (
1489+ item,
1490+ new_def_id,
1491+ namespace. unwrap ( ) ,
1492+ parent_header,
1493+ r#impl,
1494+ ) ;
13731495 Some ( ( existing_def_id, new_def_id) )
13741496 }
13751497
@@ -1395,6 +1517,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13951517 new_def_id,
13961518 namespace,
13971519 parent_header. clone ( ) ,
1520+ None ,
13981521 ) ;
13991522 if unnamed {
14001523 self . unnamed_items [ namespace] . push ( new_item) ;
@@ -1414,6 +1537,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14141537 new_def_id,
14151538 namespace,
14161539 parent_header. clone ( ) ,
1540+ None ,
14171541 ) ;
14181542 Some ( ( existing_def_id, new_def_id) )
14191543 }
@@ -1507,6 +1631,17 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15071631 foreign_items. entry ( abi) . or_default ( ) . push ( fi) ;
15081632 }
15091633 }
1634+
1635+ // If there is an impl item, add it now.
1636+ if let Some ( r#impl) = item. r#impl {
1637+ let cur_mod_name = r#impl. parent_header . ident ;
1638+ let i = r#impl. item ;
1639+ if last_item_mod != Some ( cur_mod_name) {
1640+ st. add_comment ( i. id , make_header_comment ( last_item_mod, cur_mod_name) ) ;
1641+ last_item_mod = Some ( cur_mod_name) ;
1642+ }
1643+ items. push ( i) ;
1644+ }
15101645 }
15111646
15121647 let foreign_mods = foreign_items
@@ -1516,14 +1651,30 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15161651 foreign_mods. chain ( items. into_iter ( ) ) . collect ( )
15171652 }
15181653
1519- fn find_item < ' b > ( & ' b mut self , item : & Item , namespace : Namespace ) -> ContainsDecl < ' b > {
1654+ fn find_item < ' b > (
1655+ & ' b mut self ,
1656+ item : & Item ,
1657+ namespace : Namespace ,
1658+ impl_item : Option < & Item > ,
1659+ ) -> ContainsDecl < ' b > {
15201660 let ident = if let ItemKind :: Use ( tree) = & item. kind {
15211661 tree. ident ( )
15221662 } else {
15231663 item. ident
15241664 } ;
15251665 assert ! ( ident. name != kw:: Empty ) ;
15261666
1667+ let impl_is_compatible = |existing_decl : & MovedDecl | -> bool {
1668+ match ( impl_item, & existing_decl. r#impl ) {
1669+ ( None , None ) => true ,
1670+ ( Some ( impl_item) , Some ( existing_impl) ) => {
1671+ self . cx
1672+ . compatible_types ( impl_item, & existing_impl. item , false )
1673+ }
1674+ _ => false ,
1675+ }
1676+ } ;
1677+
15271678 if ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) {
15281679 for existing_decl in self . unnamed_items [ namespace] . iter_mut ( ) {
15291680 match & existing_decl. kind {
@@ -1534,7 +1685,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15341685 | ItemKind :: Enum ( ..) => {
15351686 // Does the new item match the existing item, except
15361687 // for unnamed names?
1537- if item. kind . unnamed_equiv ( & existing_item. kind ) {
1688+ if item. kind . unnamed_equiv ( & existing_item. kind )
1689+ && impl_is_compatible ( existing_decl)
1690+ {
15381691 return ContainsDecl :: Equivalent ( existing_decl) ;
15391692 }
15401693 }
@@ -1579,7 +1732,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15791732 // Otherwise make sure these items are structurally
15801733 // equivalent.
15811734 _ => {
1582- if self . cx . compatible_types ( & item, & existing_item, true ) {
1735+ if self . cx . compatible_types ( & item, & existing_item, true )
1736+ && impl_is_compatible ( existing_decl)
1737+ {
15831738 return ContainsDecl :: Equivalent ( existing_decl) ;
15841739 }
15851740 }
0 commit comments