@@ -288,6 +288,67 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
288288 keep_items
289289 }
290290
291+ // First, remove and store `impl` items, indexing them by the type they belong to.
292+ let mut impls: HashMap < DefId , MovedDeclImpl > = HashMap :: new ( ) ;
293+ FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
294+ if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
295+ let header_item = item. clone ( ) ;
296+ if let ItemKind :: Mod ( _, ModKind :: Loaded ( ref mut mod_items, _, _) ) = & mut item. kind {
297+ mod_items. retain ( |item| {
298+ if let ItemKind :: Impl ( impl_) = & item. kind {
299+ // Only keep `impl` items with simple path types, and only if they
300+ // contain nothing but `const` items.
301+ fn impl_type_def_id ( cx : & RefactorCtxt , impl_ : & Impl ) -> Option < DefId > {
302+ // Only inherent `impl`s that contain no items other than `const`.
303+ if impl_. of_trait . is_some ( )
304+ || !impl_
305+ . items
306+ . iter ( )
307+ . all ( |item| matches ! ( item. kind, AssocItemKind :: Const ( ..) ) )
308+ {
309+ return None ;
310+ } ;
311+ let ty = match cx. hir_map ( ) . find ( impl_. self_ty . id ) ? {
312+ hir:: Node :: Ty ( ty) => ty,
313+ _ => return None ,
314+ } ;
315+ let ty_path = match & ty. kind {
316+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) => path,
317+ _ => return None ,
318+ } ;
319+ match ty_path. res {
320+ Res :: Def ( _, def_id) => Some ( def_id) ,
321+ _ => None ,
322+ }
323+ }
324+
325+ if let Some ( impl_type_def_id) = impl_type_def_id ( & self . cx , & impl_) {
326+ impls. entry ( impl_type_def_id) . or_insert_with ( || {
327+ let parent_header =
328+ HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
329+ MovedDeclImpl {
330+ item : item. clone ( ) ,
331+ parent_header,
332+ }
333+ } ) ;
334+ }
335+
336+ false
337+ } else {
338+ true
339+ }
340+ } ) ;
341+
342+ smallvec ! [ item]
343+ } else {
344+ panic ! ( "Unexpected Item kind with header_src attribute" ) ;
345+ }
346+ } else {
347+ smallvec ! [ item]
348+ }
349+ } ) ;
350+
351+ // Process all the remaining items.
291352 let mut declarations = HeaderDeclarations :: new ( self . cx ) ;
292353 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
293354 if let Some ( ( path, _) ) = parse_source_header ( & item. attrs ) {
@@ -322,8 +383,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
322383 }
323384 }
324385
386+ let new_def_id = self . cx . node_def_id ( item. id ) ;
325387 let header_info = HeaderInfo :: new ( header_item. ident , path. clone ( ) ) ;
326- let inserted = declarations. insert_item ( item. clone ( ) , header_info) ;
388+ let inserted = declarations. insert_item (
389+ item. clone ( ) ,
390+ header_info,
391+ impls. remove ( & new_def_id) ,
392+ ) ;
327393 // Keep the item if we are not collapsing it
328394 !inserted
329395 } ) ;
@@ -677,7 +743,7 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
677743 } else {
678744 let namespace = self . cx . item_namespace ( & item) ;
679745 if let Some ( namespace) = namespace {
680- match declarations. find_item ( item, namespace) {
746+ match declarations. find_item ( item, namespace, None ) {
681747 ContainsDecl :: NotContained => false ,
682748 ContainsDecl :: Equivalent ( _) => true ,
683749 ContainsDecl :: Definition ( _) => true ,
@@ -751,6 +817,13 @@ impl<'a, 'tcx> Reorganizer<'a, 'tcx> {
751817 // Remove src_loc attributes
752818 FlatMapNodes :: visit ( krate, |mut item : P < Item > | {
753819 item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
820+
821+ if let ItemKind :: Impl ( impl_) = & mut item. kind {
822+ for item in & mut impl_. items {
823+ item. attrs . retain ( |attr| !is_c2rust_attr ( attr, "src_loc" ) ) ;
824+ }
825+ }
826+
754827 smallvec ! [ item]
755828 } ) ;
756829 FlatMapNodes :: visit ( krate, |mut item : P < ForeignItem > | {
@@ -1122,10 +1195,23 @@ struct MovedDecl {
11221195 namespace : Namespace ,
11231196 loc : Option < SrcLoc > ,
11241197 parent_header : HeaderInfo ,
1198+ impl_ : Option < MovedDeclImpl > ,
1199+ }
1200+
1201+ #[ derive( Debug , Clone ) ]
1202+ struct MovedDeclImpl {
1203+ item : P < Item > ,
1204+ parent_header : HeaderInfo ,
11251205}
11261206
11271207impl MovedDecl {
1128- fn new < T > ( decl : T , def_id : DefId , namespace : Namespace , parent_header : HeaderInfo ) -> Self
1208+ fn new < T > (
1209+ decl : T ,
1210+ def_id : DefId ,
1211+ namespace : Namespace ,
1212+ parent_header : HeaderInfo ,
1213+ impl_ : Option < MovedDeclImpl > ,
1214+ ) -> Self
11291215 where
11301216 T : Into < DeclKind > ,
11311217 {
@@ -1142,6 +1228,7 @@ impl MovedDecl {
11421228 namespace,
11431229 loc,
11441230 parent_header,
1231+ impl_,
11451232 }
11461233 }
11471234
@@ -1328,14 +1415,12 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13281415
13291416 /// Add an item into the module. If it has a name conflict with an existing
13301417 /// item, choose the definition item over any declarations.
1331- pub fn insert_item ( & mut self , mut item : P < Item > , parent_header : HeaderInfo ) -> bool {
1332- let namespace = self . cx . item_namespace ( & item) ;
1333- let new_def_id = self . cx . node_def_id ( item. id ) ;
1334- let ident = if let ItemKind :: Use ( tree) = & item. kind {
1335- tree. ident ( )
1336- } else {
1337- item. ident
1338- } ;
1418+ pub fn insert_item (
1419+ & mut self ,
1420+ mut item : P < Item > ,
1421+ parent_header : HeaderInfo ,
1422+ impl_ : Option < MovedDeclImpl > ,
1423+ ) -> bool {
13391424 match & item. kind {
13401425 // We have to disambiguate anonymous items by contents,
13411426 // since we don't have a proper Ident.
@@ -1344,15 +1429,15 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13441429 // ident_map.
13451430 ItemKind :: Use ( tree) if is_nested ( tree) => {
13461431 for u in split_uses ( item) . into_iter ( ) {
1347- self . insert_item ( u, parent_header. clone ( ) ) ;
1432+ self . insert_item ( u, parent_header. clone ( ) , impl_ . clone ( ) ) ;
13481433 }
13491434 true
13501435 }
13511436
13521437 // Keep function definitions, if any
13531438 ItemKind :: Fn ( ..) => false ,
13541439
1355- // Don't keep impl blocks, these are expanded from macros anyway
1440+ // These should have already been removed before.
13561441 ItemKind :: Impl ( ..) => true ,
13571442
13581443 // We collect all ForeignItems and later filter out any idents
@@ -1372,11 +1457,24 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13721457 // we don't have any items with the same name but different
13731458 // contents.
13741459 _ => {
1460+ let namespace = self . cx . item_namespace ( & item) ;
1461+ let new_def_id = self . cx . node_def_id ( item. id ) ;
1462+ let ident = if let ItemKind :: Use ( tree) = & item. kind {
1463+ tree. ident ( )
1464+ } else {
1465+ item. ident
1466+ } ;
13751467 let unnamed = ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) ;
1376- let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) ) {
1468+ let impl_item = impl_. as_ref ( ) . map ( |impl_| & * impl_. item ) ;
1469+ let def_id_mapping = match self . find_item ( & item, namespace. unwrap ( ) , impl_item) {
13771470 ContainsDecl :: NotContained => {
1378- let new_item =
1379- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1471+ let new_item = MovedDecl :: new (
1472+ item,
1473+ new_def_id,
1474+ namespace. unwrap ( ) ,
1475+ parent_header,
1476+ impl_,
1477+ ) ;
13801478 if unnamed {
13811479 self . unnamed_items [ namespace. unwrap ( ) ] . push ( new_item) ;
13821480 } else {
@@ -1396,17 +1494,27 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
13961494 ContainsDecl :: Use ( existing) => {
13971495 let existing_def_id = existing. def_id ;
13981496 existing. join_visibility ( & item. vis . kind ) ;
1399- * existing =
1400- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1497+ * existing = MovedDecl :: new (
1498+ item,
1499+ new_def_id,
1500+ namespace. unwrap ( ) ,
1501+ parent_header,
1502+ impl_,
1503+ ) ;
14011504 Some ( ( existing_def_id, new_def_id) )
14021505 }
14031506
14041507 ContainsDecl :: Equivalent ( existing) if existing. is_foreign ( ) => {
14051508 let existing_def_id = existing. def_id ;
14061509 item. vis . kind =
14071510 join_visibility ( & existing. visibility ( ) . kind , & item. vis . kind ) ;
1408- * existing =
1409- MovedDecl :: new ( item, new_def_id, namespace. unwrap ( ) , parent_header) ;
1511+ * existing = MovedDecl :: new (
1512+ item,
1513+ new_def_id,
1514+ namespace. unwrap ( ) ,
1515+ parent_header,
1516+ impl_,
1517+ ) ;
14101518 Some ( ( existing_def_id, new_def_id) )
14111519 }
14121520
@@ -1432,6 +1540,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14321540 new_def_id,
14331541 namespace,
14341542 parent_header. clone ( ) ,
1543+ None ,
14351544 ) ;
14361545 if unnamed {
14371546 self . unnamed_items [ namespace] . push ( new_item) ;
@@ -1451,6 +1560,7 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
14511560 new_def_id,
14521561 namespace,
14531562 parent_header. clone ( ) ,
1563+ None ,
14541564 ) ;
14551565 Some ( ( existing_def_id, new_def_id) )
14561566 }
@@ -1544,6 +1654,17 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15441654 foreign_items. entry ( abi) . or_default ( ) . push ( fi) ;
15451655 }
15461656 }
1657+
1658+ // If there is an impl item, add it now.
1659+ if let Some ( impl_) = item. impl_ {
1660+ let cur_mod_name = impl_. parent_header . ident ;
1661+ let i = impl_. item ;
1662+ if last_item_mod != Some ( cur_mod_name) {
1663+ st. add_comment ( i. id , make_header_comment ( last_item_mod, cur_mod_name) ) ;
1664+ last_item_mod = Some ( cur_mod_name) ;
1665+ }
1666+ items. push ( i) ;
1667+ }
15471668 }
15481669
15491670 let foreign_mods = foreign_items
@@ -1553,14 +1674,30 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15531674 foreign_mods. chain ( items. into_iter ( ) ) . collect ( )
15541675 }
15551676
1556- fn find_item < ' b > ( & ' b mut self , item : & Item , namespace : Namespace ) -> ContainsDecl < ' b > {
1677+ fn find_item < ' b > (
1678+ & ' b mut self ,
1679+ item : & Item ,
1680+ namespace : Namespace ,
1681+ impl_item : Option < & Item > ,
1682+ ) -> ContainsDecl < ' b > {
15571683 let ident = if let ItemKind :: Use ( tree) = & item. kind {
15581684 tree. ident ( )
15591685 } else {
15601686 item. ident
15611687 } ;
15621688 assert ! ( ident. name != kw:: Empty ) ;
15631689
1690+ let impl_is_compatible = |existing_decl : & MovedDecl | -> bool {
1691+ match ( impl_item, & existing_decl. impl_ ) {
1692+ ( None , None ) => true ,
1693+ ( Some ( impl_item) , Some ( existing_impl) ) => {
1694+ self . cx
1695+ . compatible_types ( impl_item, & existing_impl. item , false )
1696+ }
1697+ _ => false ,
1698+ }
1699+ } ;
1700+
15641701 if ident. as_str ( ) . contains ( "C2Rust_Unnamed" ) {
15651702 for existing_decl in self . unnamed_items [ namespace] . iter_mut ( ) {
15661703 match & existing_decl. kind {
@@ -1571,7 +1708,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
15711708 | ItemKind :: Enum ( ..) => {
15721709 // Does the new item match the existing item, except
15731710 // for unnamed names?
1574- if item. kind . unnamed_equiv ( & existing_item. kind ) {
1711+ if item. kind . unnamed_equiv ( & existing_item. kind )
1712+ && impl_is_compatible ( existing_decl)
1713+ {
15751714 return ContainsDecl :: Equivalent ( existing_decl) ;
15761715 }
15771716 }
@@ -1616,7 +1755,9 @@ impl<'a, 'tcx> HeaderDeclarations<'a, 'tcx> {
16161755 // Otherwise make sure these items are structurally
16171756 // equivalent.
16181757 _ => {
1619- if self . cx . compatible_types ( & item, & existing_item, true ) {
1758+ if self . cx . compatible_types ( & item, & existing_item, true )
1759+ && impl_is_compatible ( existing_decl)
1760+ {
16201761 return ContainsDecl :: Equivalent ( existing_decl) ;
16211762 }
16221763 }
0 commit comments