@@ -12,9 +12,7 @@ use rustc_hir::def::{CtorKind, DefKind};
1212use  rustc_hir:: { LangItem ,  Node ,  attrs,  find_attr,  intravisit} ; 
1313use  rustc_infer:: infer:: { RegionVariableOrigin ,  TyCtxtInferExt } ; 
1414use  rustc_infer:: traits:: { Obligation ,  ObligationCauseCode ,  WellFormedLoc } ; 
15- use  rustc_lint_defs:: builtin:: { 
16-     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS ,  UNSUPPORTED_CALLING_CONVENTIONS , 
17- } ; 
15+ use  rustc_lint_defs:: builtin:: UNSUPPORTED_CALLING_CONVENTIONS ; 
1816use  rustc_middle:: hir:: nested_filter; 
1917use  rustc_middle:: middle:: resolve_bound_vars:: ResolvedArg ; 
2018use  rustc_middle:: middle:: stability:: EvalResult ; 
@@ -1510,58 +1508,15 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15101508        return ; 
15111509    } 
15121510
1513-     // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with 
1514-     // "known" respecting #[non_exhaustive] attributes. 
1511+     // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST). 
15151512    let  field_infos = adt. all_fields ( ) . map ( |field| { 
15161513        let  ty = field. ty ( tcx,  GenericArgs :: identity_for_item ( tcx,  field. did ) ) ; 
15171514        let  typing_env = ty:: TypingEnv :: non_body_analysis ( tcx,  field. did ) ; 
15181515        let  layout = tcx. layout_of ( typing_env. as_query_input ( ty) ) ; 
15191516        // We are currently checking the type this field came from, so it must be local 
15201517        let  span = tcx. hir_span_if_local ( field. did ) . unwrap ( ) ; 
15211518        let  trivial = layout. is_ok_and ( |layout| layout. is_1zst ( ) ) ; 
1522-         if  !trivial { 
1523-             return  ( span,  trivial,  None ) ; 
1524-         } 
1525-         // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive`. 
1526- 
1527-         fn  check_non_exhaustive < ' tcx > ( 
1528-             tcx :  TyCtxt < ' tcx > , 
1529-             t :  Ty < ' tcx > , 
1530-         )  -> ControlFlow < ( & ' static  str ,  DefId ,  GenericArgsRef < ' tcx > ,  bool ) >  { 
1531-             match  t. kind ( )  { 
1532-                 ty:: Tuple ( list)  => list. iter ( ) . try_for_each ( |t| check_non_exhaustive ( tcx,  t) ) , 
1533-                 ty:: Array ( ty,  _)  => check_non_exhaustive ( tcx,  * ty) , 
1534-                 ty:: Adt ( def,  args)  => { 
1535-                     if  !def. did ( ) . is_local ( ) 
1536-                         && !find_attr ! ( 
1537-                             tcx. get_all_attrs( def. did( ) ) , 
1538-                             AttributeKind :: PubTransparent ( _) 
1539-                         ) 
1540-                     { 
1541-                         let  non_exhaustive = def. is_variant_list_non_exhaustive ( ) 
1542-                             || def
1543-                                 . variants ( ) 
1544-                                 . iter ( ) 
1545-                                 . any ( ty:: VariantDef :: is_field_list_non_exhaustive) ; 
1546-                         let  has_priv = def. all_fields ( ) . any ( |f| !f. vis . is_public ( ) ) ; 
1547-                         if  non_exhaustive || has_priv { 
1548-                             return  ControlFlow :: Break ( ( 
1549-                                 def. descr ( ) , 
1550-                                 def. did ( ) , 
1551-                                 args, 
1552-                                 non_exhaustive, 
1553-                             ) ) ; 
1554-                         } 
1555-                     } 
1556-                     def. all_fields ( ) 
1557-                         . map ( |field| field. ty ( tcx,  args) ) 
1558-                         . try_for_each ( |t| check_non_exhaustive ( tcx,  t) ) 
1559-                 } 
1560-                 _ => ControlFlow :: Continue ( ( ) ) , 
1561-             } 
1562-         } 
1563- 
1564-         ( span,  trivial,  check_non_exhaustive ( tcx,  ty) . break_value ( ) ) 
1519+         ( span,  trivial,  ty) 
15651520    } ) ; 
15661521
15671522    let  non_trivial_fields = field_infos
@@ -1578,36 +1533,84 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
15781533        ) ; 
15791534        return ; 
15801535    } 
1581-     let  mut  prev_non_exhaustive_1zst = false ; 
1582-     for  ( span,  _trivial,  non_exhaustive_1zst)  in  field_infos { 
1583-         if  let  Some ( ( descr,  def_id,  args,  non_exhaustive) )  = non_exhaustive_1zst { 
1536+ 
1537+     // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private 
1538+     // fields or `repr(C)`. We call those fields "unsuited". Search for unsuited fields and 
1539+     // error if the repr(transparent) condition relies on them. 
1540+     enum  UnsuitedReason  { 
1541+         NonExhaustive , 
1542+         PrivateField , 
1543+     } 
1544+     struct  UnsuitedInfo < ' tcx >  { 
1545+         descr :  & ' static  str , 
1546+         def_id :  DefId , 
1547+         args :  GenericArgsRef < ' tcx > , 
1548+         reason :  UnsuitedReason , 
1549+     } 
1550+ 
1551+     fn  check_unsuited_1zst < ' tcx > ( 
1552+         tcx :  TyCtxt < ' tcx > , 
1553+         t :  Ty < ' tcx > , 
1554+     )  -> ControlFlow < UnsuitedInfo < ' tcx > >  { 
1555+         match  t. kind ( )  { 
1556+             ty:: Tuple ( list)  => list. iter ( ) . try_for_each ( |t| check_unsuited_1zst ( tcx,  t) ) , 
1557+             ty:: Array ( ty,  _)  => check_unsuited_1zst ( tcx,  * ty) , 
1558+             ty:: Adt ( def,  args)  => { 
1559+                 if  !def. did ( ) . is_local ( ) 
1560+                     && !find_attr ! ( tcx. get_all_attrs( def. did( ) ) ,  AttributeKind :: PubTransparent ( _) ) 
1561+                 { 
1562+                     let  non_exhaustive = def. is_variant_list_non_exhaustive ( ) 
1563+                         || def. variants ( ) . iter ( ) . any ( ty:: VariantDef :: is_field_list_non_exhaustive) ; 
1564+                     let  has_priv = def. all_fields ( ) . any ( |f| !f. vis . is_public ( ) ) ; 
1565+                     if  non_exhaustive || has_priv { 
1566+                         return  ControlFlow :: Break ( UnsuitedInfo  { 
1567+                             descr :  def. descr ( ) , 
1568+                             def_id :  def. did ( ) , 
1569+                             args, 
1570+                             reason :  if  non_exhaustive { 
1571+                                 UnsuitedReason :: NonExhaustive 
1572+                             }  else  { 
1573+                                 UnsuitedReason :: PrivateField 
1574+                             } , 
1575+                         } ) ; 
1576+                     } 
1577+                 } 
1578+                 def. all_fields ( ) 
1579+                     . map ( |field| field. ty ( tcx,  args) ) 
1580+                     . try_for_each ( |t| check_unsuited_1zst ( tcx,  t) ) 
1581+             } 
1582+             _ => ControlFlow :: Continue ( ( ) ) , 
1583+         } 
1584+     } 
1585+ 
1586+     let  mut  prev_unsuited_1zst = false ; 
1587+     for  ( span,  trivial,  ty)  in  field_infos { 
1588+         if  !trivial { 
1589+             continue ; 
1590+         } 
1591+         if  let  Some ( unsuited)  = check_unsuited_1zst ( tcx,  ty) . break_value ( )  { 
15841592            // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. 
15851593            // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. 
1586-             if  non_trivial_count > 0  || prev_non_exhaustive_1zst { 
1587-                 tcx. node_span_lint ( 
1588-                     REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS , 
1589-                     tcx. local_def_id_to_hir_id ( adt. did ( ) . expect_local ( ) ) , 
1594+             if  non_trivial_count > 0  || prev_unsuited_1zst { 
1595+                 let  mut  diag = tcx. dcx ( ) . struct_span_err ( 
15901596                    span, 
1591-                     |lint| { 
1592-                         lint. primary_message ( 
1593-                             "zero-sized fields in `repr(transparent)` cannot \  
1597+                     "zero-sized fields in `repr(transparent)` cannot \  
15941598                              contain external non-exhaustive types", 
1595-                         ) ; 
1596-                         let  note = if  non_exhaustive { 
1597-                             "is marked with `#[non_exhaustive]`" 
1598-                         }  else  { 
1599-                             "contains private fields" 
1600-                         } ; 
1601-                         let  field_ty = tcx. def_path_str_with_args ( def_id,  args) ; 
1602-                         lint. note ( format ! ( 
1603-                             "this {descr} contains `{field_ty}`, which {note}, \  
1599+                 ) ; 
1600+                 let  note = match  unsuited. reason  { 
1601+                     UnsuitedReason :: NonExhaustive  => "is marked with `#[non_exhaustive]`" , 
1602+                     UnsuitedReason :: PrivateField  => "contains private fields" , 
1603+                 } ; 
1604+                 let  field_ty = tcx. def_path_str_with_args ( unsuited. def_id ,  unsuited. args ) ; 
1605+                 diag. note ( format ! ( 
1606+                     "this {descr} contains `{field_ty}`, which {note}, \  
16041607                                 and makes it not a breaking change to become \ 
1605-                                  non-zero-sized in the future."
1606-                          ) ) ; 
1607-                      } , 
1608-                 ) 
1608+                                  non-zero-sized in the future.", 
1609+                     descr = unsuited . descr , 
1610+                 ) ) ; 
1611+                 diag . emit ( ) ; 
16091612            }  else  { 
1610-                 prev_non_exhaustive_1zst  = true ; 
1613+                 prev_unsuited_1zst  = true ; 
16111614            } 
16121615        } 
16131616    } 
0 commit comments