2020//! If you define a new `LateLintPass`, you will also need to add it to the
2121//! `late_lint_methods!` invocation in `lib.rs`.
2222
23- use crate :: { EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext } ;
23+ use crate :: {
24+ types:: CItemKind , EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext ,
25+ } ;
2426use rustc_ast:: ast:: { self , Expr } ;
2527use rustc_ast:: attr:: { self , HasAttrs } ;
2628use rustc_ast:: tokenstream:: { TokenStream , TokenTree } ;
@@ -36,14 +38,14 @@ use rustc_hir::def_id::DefId;
3638use rustc_hir:: { ForeignItemKind , GenericParamKind , PatKind } ;
3739use rustc_hir:: { HirId , HirIdSet , Node } ;
3840use rustc_middle:: lint:: LintDiagnosticBuilder ;
39- use rustc_middle:: ty:: subst:: GenericArgKind ;
41+ use rustc_middle:: ty:: subst:: { GenericArgKind , Subst } ;
4042use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
4143use rustc_session:: lint:: FutureIncompatibleInfo ;
4244use rustc_span:: edition:: Edition ;
4345use rustc_span:: source_map:: Spanned ;
4446use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
4547use rustc_span:: { BytePos , Span } ;
46- use rustc_target:: abi:: VariantIdx ;
48+ use rustc_target:: abi:: { LayoutOf , VariantIdx } ;
4749use rustc_trait_selection:: traits:: misc:: can_type_implement_copy;
4850
4951use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
@@ -2144,7 +2146,13 @@ impl ClashingExternDeclarations {
21442146 /// Checks whether two types are structurally the same enough that the declarations shouldn't
21452147 /// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
21462148 /// with the same members (as the declarations shouldn't clash).
2147- fn structurally_same_type < ' tcx > ( cx : & LateContext < ' tcx > , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> bool {
2149+ fn structurally_same_type < ' tcx > (
2150+ cx : & LateContext < ' tcx > ,
2151+ a : Ty < ' tcx > ,
2152+ b : Ty < ' tcx > ,
2153+ ckind : CItemKind ,
2154+ ) -> bool {
2155+ debug ! ( "structurally_same_type(cx, a = {:?}, b = {:?})" , a, b) ;
21482156 let tcx = cx. tcx ;
21492157 if a == b || rustc_middle:: ty:: TyS :: same_type ( a, b) {
21502158 // All nominally-same types are structurally same, too.
@@ -2155,47 +2163,77 @@ impl ClashingExternDeclarations {
21552163 let a_kind = & a. kind ;
21562164 let b_kind = & b. kind ;
21572165
2166+ let compare_layouts = |a, b| -> bool {
2167+ let a_layout = & cx. layout_of ( a) . unwrap ( ) . layout . abi ;
2168+ let b_layout = & cx. layout_of ( b) . unwrap ( ) . layout . abi ;
2169+ debug ! ( "{:?} == {:?} = {}" , a_layout, b_layout, a_layout == b_layout) ;
2170+ a_layout == b_layout
2171+ } ;
2172+
2173+ #[ allow( rustc:: usage_of_ty_tykind) ]
2174+ let is_primitive_or_pointer =
2175+ |kind : & ty:: TyKind < ' _ > | kind. is_primitive ( ) || matches ! ( kind, RawPtr ( ..) ) ;
2176+
21582177 match ( a_kind, b_kind) {
2159- ( Adt ( ..) , Adt ( ..) ) => {
2160- // Adts are pretty straightforward: just compare the layouts.
2161- use rustc_target:: abi:: LayoutOf ;
2162- let a_layout = cx. layout_of ( a) . unwrap ( ) . layout ;
2163- let b_layout = cx. layout_of ( b) . unwrap ( ) . layout ;
2164- a_layout == b_layout
2178+ ( Adt ( _, a_substs) , Adt ( _, b_substs) ) => {
2179+ let a = a. subst ( cx. tcx , a_substs) ;
2180+ let b = b. subst ( cx. tcx , b_substs) ;
2181+ debug ! ( "Comparing {:?} and {:?}" , a, b) ;
2182+
2183+ if let ( Adt ( a_def, ..) , Adt ( b_def, ..) ) = ( & a. kind , & b. kind ) {
2184+ // Grab a flattened representation of all fields.
2185+ let a_fields = a_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2186+ let b_fields = b_def. variants . iter ( ) . flat_map ( |v| v. fields . iter ( ) ) ;
2187+ compare_layouts ( a, b)
2188+ && a_fields. eq_by (
2189+ b_fields,
2190+ |& ty:: FieldDef { did : a_did, .. } ,
2191+ & ty:: FieldDef { did : b_did, .. } | {
2192+ Self :: structurally_same_type (
2193+ cx,
2194+ tcx. type_of ( a_did) ,
2195+ tcx. type_of ( b_did) ,
2196+ ckind,
2197+ )
2198+ } ,
2199+ )
2200+ } else {
2201+ unreachable ! ( )
2202+ }
21652203 }
21662204 ( Array ( a_ty, a_const) , Array ( b_ty, b_const) ) => {
21672205 // For arrays, we also check the constness of the type.
21682206 a_const. val == b_const. val
2169- && Self :: structurally_same_type ( cx, a_const. ty , b_const. ty )
2170- && Self :: structurally_same_type ( cx, a_ty, b_ty)
2207+ && Self :: structurally_same_type ( cx, a_const. ty , b_const. ty , ckind )
2208+ && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
21712209 }
2172- ( Slice ( a_ty) , Slice ( b_ty) ) => Self :: structurally_same_type ( cx, a_ty, b_ty) ,
2210+ ( Slice ( a_ty) , Slice ( b_ty) ) => Self :: structurally_same_type ( cx, a_ty, b_ty, ckind ) ,
21732211 ( RawPtr ( a_tymut) , RawPtr ( b_tymut) ) => {
21742212 a_tymut. mutbl == a_tymut. mutbl
2175- && Self :: structurally_same_type ( cx, & a_tymut. ty , & b_tymut. ty )
2213+ && Self :: structurally_same_type ( cx, & a_tymut. ty , & b_tymut. ty , ckind )
21762214 }
21772215 ( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
21782216 // For structural sameness, we don't need the region to be same.
2179- a_mut == b_mut && Self :: structurally_same_type ( cx, a_ty, b_ty)
2217+ a_mut == b_mut && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
21802218 }
21812219 ( FnDef ( ..) , FnDef ( ..) ) => {
2182- // As we don't compare regions, skip_binder is fine.
21832220 let a_poly_sig = a. fn_sig ( tcx) ;
21842221 let b_poly_sig = b. fn_sig ( tcx) ;
21852222
2223+ // As we don't compare regions, skip_binder is fine.
21862224 let a_sig = a_poly_sig. skip_binder ( ) ;
21872225 let b_sig = b_poly_sig. skip_binder ( ) ;
21882226
21892227 ( a_sig. abi , a_sig. unsafety , a_sig. c_variadic )
21902228 == ( b_sig. abi , b_sig. unsafety , b_sig. c_variadic )
21912229 && a_sig. inputs ( ) . iter ( ) . eq_by ( b_sig. inputs ( ) . iter ( ) , |a, b| {
2192- Self :: structurally_same_type ( cx, a, b)
2230+ Self :: structurally_same_type ( cx, a, b, ckind )
21932231 } )
2194- && Self :: structurally_same_type ( cx, a_sig. output ( ) , b_sig. output ( ) )
2232+ && Self :: structurally_same_type ( cx, a_sig. output ( ) , b_sig. output ( ) , ckind )
21952233 }
21962234 ( Tuple ( a_substs) , Tuple ( b_substs) ) => {
21972235 a_substs. types ( ) . eq_by ( b_substs. types ( ) , |a_ty, b_ty| {
2198- Self :: structurally_same_type ( cx, a_ty, b_ty)
2236+ Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
21992237 } )
22002238 }
22012239 // For these, it's not quite as easy to define structural-sameness quite so easily.
@@ -2208,9 +2246,27 @@ impl ClashingExternDeclarations {
22082246 | ( GeneratorWitness ( ..) , GeneratorWitness ( ..) )
22092247 | ( Projection ( ..) , Projection ( ..) )
22102248 | ( Opaque ( ..) , Opaque ( ..) ) => false ,
2249+
22112250 // These definitely should have been caught above.
22122251 ( Bool , Bool ) | ( Char , Char ) | ( Never , Never ) | ( Str , Str ) => unreachable ! ( ) ,
2213- _ => false ,
2252+
2253+ // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2254+ // non-null field.
2255+ ( Adt ( ..) , other_kind) | ( other_kind, Adt ( ..) )
2256+ if is_primitive_or_pointer ( other_kind) =>
2257+ {
2258+ let ( primitive, adt) =
2259+ if is_primitive_or_pointer ( & a. kind ) { ( a, b) } else { ( b, a) } ;
2260+ if let Some ( ty) = crate :: types:: repr_nullable_ptr ( cx, adt, ckind) {
2261+ ty == primitive
2262+ } else {
2263+ compare_layouts ( a, b)
2264+ }
2265+ }
2266+ // Otherwise, just compare the layouts. This may fail to lint for some
2267+ // incompatible types, but at the very least, will stop reads into
2268+ // uninitialised memory.
2269+ _ => compare_layouts ( a, b) ,
22142270 }
22152271 }
22162272 }
@@ -2231,7 +2287,12 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
22312287 existing_hid, existing_decl_ty, this_fi. hir_id, this_decl_ty
22322288 ) ;
22332289 // Check that the declarations match.
2234- if !Self :: structurally_same_type ( cx, existing_decl_ty, this_decl_ty) {
2290+ if !Self :: structurally_same_type (
2291+ cx,
2292+ existing_decl_ty,
2293+ this_decl_ty,
2294+ CItemKind :: Declaration ,
2295+ ) {
22352296 let orig_fi = tcx. hir ( ) . expect_foreign_item ( existing_hid) ;
22362297 let orig = Self :: name_of_extern_decl ( tcx, orig_fi) ;
22372298
0 commit comments