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 } ;
@@ -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.
@@ -2156,29 +2164,30 @@ impl ClashingExternDeclarations {
2156
2164
let b_kind = & b. kind ;
2157
2165
2158
2166
use rustc_target:: abi:: LayoutOf ;
2159
- let compare_layouts = |a, b| {
2160
- let a_layout = & cx. layout_of ( a) . unwrap ( ) . layout . abi ;
2161
- let b_layout = & cx. layout_of ( b) . unwrap ( ) . layout . abi ;
2162
- let result = a_layout == b_layout;
2163
- result
2167
+ let compare_layouts = |a, b| -> bool {
2168
+ & cx. layout_of ( a) . unwrap ( ) . layout . abi == & cx. layout_of ( b) . unwrap ( ) . layout . abi
2164
2169
} ;
2165
2170
2171
+ #[ allow( rustc:: usage_of_ty_tykind) ]
2172
+ let is_primitive_or_pointer =
2173
+ |kind : & ty:: TyKind < ' _ > | kind. is_primitive ( ) || matches ! ( kind, RawPtr ( ..) ) ;
2174
+
2166
2175
match ( a_kind, b_kind) {
2167
2176
( Adt ( ..) , Adt ( ..) ) => compare_layouts ( a, b) ,
2168
2177
( Array ( a_ty, a_const) , Array ( b_ty, b_const) ) => {
2169
2178
// For arrays, we also check the constness of the type.
2170
2179
a_const. val == b_const. val
2171
- && Self :: structurally_same_type ( cx, a_const. ty , b_const. ty )
2172
- && Self :: structurally_same_type ( cx, a_ty, b_ty)
2180
+ && Self :: structurally_same_type ( cx, a_const. ty , b_const. ty , ckind )
2181
+ && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
2173
2182
}
2174
- ( Slice ( a_ty) , Slice ( b_ty) ) => Self :: structurally_same_type ( cx, a_ty, b_ty) ,
2183
+ ( Slice ( a_ty) , Slice ( b_ty) ) => Self :: structurally_same_type ( cx, a_ty, b_ty, ckind ) ,
2175
2184
( RawPtr ( a_tymut) , RawPtr ( b_tymut) ) => {
2176
2185
a_tymut. mutbl == a_tymut. mutbl
2177
- && Self :: structurally_same_type ( cx, & a_tymut. ty , & b_tymut. ty )
2186
+ && Self :: structurally_same_type ( cx, & a_tymut. ty , & b_tymut. ty , ckind )
2178
2187
}
2179
2188
( Ref ( _a_region, a_ty, a_mut) , Ref ( _b_region, b_ty, b_mut) ) => {
2180
2189
// For structural sameness, we don't need the region to be same.
2181
- a_mut == b_mut && Self :: structurally_same_type ( cx, a_ty, b_ty)
2190
+ a_mut == b_mut && Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
2182
2191
}
2183
2192
( FnDef ( ..) , FnDef ( ..) ) => {
2184
2193
let a_poly_sig = a. fn_sig ( tcx) ;
@@ -2191,13 +2200,13 @@ impl ClashingExternDeclarations {
2191
2200
( a_sig. abi , a_sig. unsafety , a_sig. c_variadic )
2192
2201
== ( b_sig. abi , b_sig. unsafety , b_sig. c_variadic )
2193
2202
&& a_sig. inputs ( ) . iter ( ) . eq_by ( b_sig. inputs ( ) . iter ( ) , |a, b| {
2194
- Self :: structurally_same_type ( cx, a, b)
2203
+ Self :: structurally_same_type ( cx, a, b, ckind )
2195
2204
} )
2196
- && Self :: structurally_same_type ( cx, a_sig. output ( ) , b_sig. output ( ) )
2205
+ && Self :: structurally_same_type ( cx, a_sig. output ( ) , b_sig. output ( ) , ckind )
2197
2206
}
2198
2207
( Tuple ( a_substs) , Tuple ( b_substs) ) => {
2199
2208
a_substs. types ( ) . eq_by ( b_substs. types ( ) , |a_ty, b_ty| {
2200
- Self :: structurally_same_type ( cx, a_ty, b_ty)
2209
+ Self :: structurally_same_type ( cx, a_ty, b_ty, ckind )
2201
2210
} )
2202
2211
}
2203
2212
// For these, it's not quite as easy to define structural-sameness quite so easily.
@@ -2210,58 +2219,27 @@ impl ClashingExternDeclarations {
2210
2219
| ( GeneratorWitness ( ..) , GeneratorWitness ( ..) )
2211
2220
| ( Projection ( ..) , Projection ( ..) )
2212
2221
| ( Opaque ( ..) , Opaque ( ..) ) => false ,
2222
+
2213
2223
// These definitely should have been caught above.
2214
2224
( Bool , Bool ) | ( Char , Char ) | ( Never , Never ) | ( Str , Str ) => unreachable ! ( ) ,
2215
2225
2216
- // Disjoint kinds.
2217
- ( _, _) => {
2218
- // First, check if the conversion is FFI-safe. This can happen if the type is an
2219
- // enum with a non-null field (see improper_ctypes).
2220
- let is_primitive_or_pointer =
2221
- |ty : Ty < ' tcx > | ty. is_primitive ( ) || matches ! ( ty. kind, RawPtr ( ..) ) ;
2222
- if ( is_primitive_or_pointer ( a) || is_primitive_or_pointer ( b) )
2223
- && !( is_primitive_or_pointer ( a) && is_primitive_or_pointer ( b) )
2224
- && ( matches ! ( a_kind, Adt ( ..) ) || matches ! ( b_kind, Adt ( ..) ) )
2225
- /* ie, 1 adt and 1 primitive */
2226
- {
2227
- let ( primitive_ty, adt_ty) =
2228
- if is_primitive_or_pointer ( a) { ( a, b) } else { ( b, a) } ;
2229
- // First, check that the Adt is FFI-safe to use.
2230
- use crate :: types:: { ImproperCTypesMode , ImproperCTypesVisitor } ;
2231
- let vis =
2232
- ImproperCTypesVisitor { cx, mode : ImproperCTypesMode :: Declarations } ;
2233
-
2234
- if let Adt ( def, substs) = adt_ty. kind {
2235
- let repr_nullable = vis. is_repr_nullable_ptr ( adt_ty, def, substs) ;
2236
- if let Some ( safe_ty) = repr_nullable {
2237
- let safe_ty_layout = & cx. layout_of ( safe_ty) . unwrap ( ) ;
2238
- let primitive_ty_layout = & cx. layout_of ( primitive_ty) . unwrap ( ) ;
2239
-
2240
- use rustc_target:: abi:: Abi :: * ;
2241
- match ( & safe_ty_layout. abi , & primitive_ty_layout. abi ) {
2242
- ( Scalar ( safe) , Scalar ( primitive) ) => {
2243
- // The two types are safe to convert between if `safe` is
2244
- // the non-zero version of `primitive`.
2245
- use std:: ops:: RangeInclusive ;
2246
-
2247
- let safe_range: & RangeInclusive < _ > = & safe. valid_range ;
2248
- let primitive_range: & RangeInclusive < _ > =
2249
- & primitive. valid_range ;
2250
-
2251
- return primitive_range. end ( ) == safe_range. end ( )
2252
- // This check works for both signed and unsigned types due to wraparound.
2253
- && * safe_range. start ( ) == 1
2254
- && * primitive_range. start ( ) == 0 ;
2255
- }
2256
- _ => { }
2257
- }
2258
- }
2259
- }
2226
+ // An Adt and a primitive type. This can be FFI-safe is the ADT is an enum with a
2227
+ // non-null field.
2228
+ ( Adt ( ..) , other_kind) | ( other_kind, Adt ( ..) )
2229
+ if is_primitive_or_pointer ( other_kind) =>
2230
+ {
2231
+ let ( primitive, adt) =
2232
+ if is_primitive_or_pointer ( & a. kind ) { ( a, b) } else { ( b, a) } ;
2233
+ if let Some ( ty) = crate :: types:: repr_nullable_ptr ( cx, adt, ckind) {
2234
+ ty == primitive
2235
+ } else {
2236
+ compare_layouts ( a, b)
2260
2237
}
2261
- // Otherwise, just compare the layouts. This may be underapproximate, but at
2262
- // the very least, will stop reads into uninitialised memory.
2263
- compare_layouts ( a, b)
2264
2238
}
2239
+ // Otherwise, just compare the layouts. This may fail to lint for some
2240
+ // incompatible types, but at the very least, will stop reads into
2241
+ // uninitialised memory.
2242
+ _ => compare_layouts ( a, b) ,
2265
2243
}
2266
2244
}
2267
2245
}
@@ -2282,7 +2260,12 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
2282
2260
existing_hid, existing_decl_ty, this_fi. hir_id, this_decl_ty
2283
2261
) ;
2284
2262
// Check that the declarations match.
2285
- if !Self :: structurally_same_type ( cx, existing_decl_ty, this_decl_ty) {
2263
+ if !Self :: structurally_same_type (
2264
+ cx,
2265
+ existing_decl_ty,
2266
+ this_decl_ty,
2267
+ CItemKind :: Declaration ,
2268
+ ) {
2286
2269
let orig_fi = tcx. hir ( ) . expect_foreign_item ( existing_hid) ;
2287
2270
let orig = Self :: name_of_extern_decl ( tcx, orig_fi) ;
2288
2271
0 commit comments