20
20
//! If you define a new `LateLintPass`, you will also need to add it to the
21
21
//! `late_lint_methods!` invocation in `lib.rs`.
22
22
23
- use crate :: { EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext } ;
23
+ use crate :: {
24
+ types:: CItemKind , EarlyContext , EarlyLintPass , LateContext , LateLintPass , LintContext ,
25
+ } ;
24
26
use rustc_ast:: ast:: { self , Expr } ;
25
27
use rustc_ast:: attr:: { self , HasAttrs } ;
26
28
use rustc_ast:: tokenstream:: { TokenStream , TokenTree } ;
@@ -36,14 +38,14 @@ use rustc_hir::def_id::DefId;
36
38
use rustc_hir:: { ForeignItemKind , GenericParamKind , PatKind } ;
37
39
use rustc_hir:: { HirId , HirIdSet , Node } ;
38
40
use rustc_middle:: lint:: LintDiagnosticBuilder ;
39
- use rustc_middle:: ty:: subst:: GenericArgKind ;
41
+ use rustc_middle:: ty:: subst:: { GenericArgKind , Subst } ;
40
42
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
41
43
use rustc_session:: lint:: FutureIncompatibleInfo ;
42
44
use rustc_span:: edition:: Edition ;
43
45
use rustc_span:: source_map:: Spanned ;
44
46
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
45
47
use rustc_span:: { BytePos , Span } ;
46
- use rustc_target:: abi:: VariantIdx ;
48
+ use rustc_target:: abi:: { LayoutOf , VariantIdx } ;
47
49
use rustc_trait_selection:: traits:: misc:: can_type_implement_copy;
48
50
49
51
use crate :: nonstandard_style:: { method_context, MethodLateContext } ;
@@ -2144,7 +2146,13 @@ impl ClashingExternDeclarations {
2144
2146
/// Checks whether two types are structurally the same enough that the declarations shouldn't
2145
2147
/// clash. We need this so we don't emit a lint when two modules both declare an extern struct,
2146
2148
/// 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) ;
2148
2156
let tcx = cx. tcx ;
2149
2157
if a == b || rustc_middle:: ty:: TyS :: same_type ( a, b) {
2150
2158
// All nominally-same types are structurally same, too.
@@ -2155,47 +2163,77 @@ impl ClashingExternDeclarations {
2155
2163
let a_kind = & a. kind ;
2156
2164
let b_kind = & b. kind ;
2157
2165
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
+
2158
2177
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
+ }
2165
2203
}
2166
2204
( Array ( a_ty, a_const) , Array ( b_ty, b_const) ) => {
2167
2205
// For arrays, we also check the constness of the type.
2168
2206
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 )
2171
2209
}
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 ) ,
2173
2211
( RawPtr ( a_tymut) , RawPtr ( b_tymut) ) => {
2174
2212
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 )
2176
2214
}
2177
2215
( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
2178
2216
// 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 )
2180
2218
}
2181
2219
( FnDef ( ..) , FnDef ( ..) ) => {
2182
- // As we don't compare regions, skip_binder is fine.
2183
2220
let a_poly_sig = a. fn_sig ( tcx) ;
2184
2221
let b_poly_sig = b. fn_sig ( tcx) ;
2185
2222
2223
+ // As we don't compare regions, skip_binder is fine.
2186
2224
let a_sig = a_poly_sig. skip_binder ( ) ;
2187
2225
let b_sig = b_poly_sig. skip_binder ( ) ;
2188
2226
2189
2227
( a_sig. abi , a_sig. unsafety , a_sig. c_variadic )
2190
2228
== ( b_sig. abi , b_sig. unsafety , b_sig. c_variadic )
2191
2229
&& 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 )
2193
2231
} )
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 )
2195
2233
}
2196
2234
( Tuple ( a_substs) , Tuple ( b_substs) ) => {
2197
2235
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 )
2199
2237
} )
2200
2238
}
2201
2239
// For these, it's not quite as easy to define structural-sameness quite so easily.
@@ -2208,9 +2246,27 @@ impl ClashingExternDeclarations {
2208
2246
| ( GeneratorWitness ( ..) , GeneratorWitness ( ..) )
2209
2247
| ( Projection ( ..) , Projection ( ..) )
2210
2248
| ( Opaque ( ..) , Opaque ( ..) ) => false ,
2249
+
2211
2250
// These definitely should have been caught above.
2212
2251
( 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) ,
2214
2270
}
2215
2271
}
2216
2272
}
@@ -2231,7 +2287,12 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
2231
2287
existing_hid, existing_decl_ty, this_fi. hir_id, this_decl_ty
2232
2288
) ;
2233
2289
// 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
+ ) {
2235
2296
let orig_fi = tcx. hir ( ) . expect_foreign_item ( existing_hid) ;
2236
2297
let orig = Self :: name_of_extern_decl ( tcx, orig_fi) ;
2237
2298
0 commit comments