@@ -3,8 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
33use rustc_hir as hir;
44use rustc_hir:: def:: DefKind ;
55use rustc_middle:: query:: Providers ;
6- use rustc_middle:: ty:: layout:: LayoutError ;
7- use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
6+ use rustc_middle:: ty:: { self , AdtDef , Instance , Ty , TyCtxt } ;
87use rustc_session:: declare_lint;
98use rustc_span:: { sym, Span , Symbol } ;
109use rustc_target:: abi:: FIRST_VARIANT ;
@@ -212,7 +211,17 @@ fn structurally_same_type<'tcx>(
212211 ckind : types:: CItemKind ,
213212) -> bool {
214213 let mut seen_types = UnordSet :: default ( ) ;
215- structurally_same_type_impl ( & mut seen_types, tcx, param_env, a, b, ckind)
214+ let result = structurally_same_type_impl ( & mut seen_types, tcx, param_env, a, b, ckind) ;
215+ if cfg ! ( debug_assertions) && result {
216+ // Sanity-check: must have same ABI, size and alignment.
217+ // `extern` blocks cannot be generic, so we'll always get a layout here.
218+ let a_layout = tcx. layout_of ( param_env. and ( a) ) . unwrap ( ) ;
219+ let b_layout = tcx. layout_of ( param_env. and ( b) ) . unwrap ( ) ;
220+ assert_eq ! ( a_layout. abi, b_layout. abi) ;
221+ assert_eq ! ( a_layout. size, b_layout. size) ;
222+ assert_eq ! ( a_layout. align, b_layout. align) ;
223+ }
224+ result
216225}
217226
218227fn structurally_same_type_impl < ' tcx > (
@@ -266,30 +275,21 @@ fn structurally_same_type_impl<'tcx>(
266275 // Do a full, depth-first comparison between the two.
267276 use rustc_type_ir:: TyKind :: * ;
268277
269- let compare_layouts = |a, b| -> Result < bool , & ' tcx LayoutError < ' tcx > > {
270- debug ! ( "compare_layouts({:?}, {:?})" , a, b) ;
271- let a_layout = & tcx. layout_of ( param_env. and ( a) ) ?. layout . abi ( ) ;
272- let b_layout = & tcx. layout_of ( param_env. and ( b) ) ?. layout . abi ( ) ;
273- debug ! (
274- "comparing layouts: {:?} == {:?} = {}" ,
275- a_layout,
276- b_layout,
277- a_layout == b_layout
278- ) ;
279- Ok ( a_layout == b_layout)
280- } ;
281-
282278 let is_primitive_or_pointer =
283279 |ty : Ty < ' tcx > | ty. is_primitive ( ) || matches ! ( ty. kind( ) , RawPtr ( ..) | Ref ( ..) ) ;
284280
285281 ensure_sufficient_stack ( || {
286282 match ( a. kind ( ) , b. kind ( ) ) {
287- ( Adt ( a_def, _) , Adt ( b_def, _) ) => {
288- // We can immediately rule out these types as structurally same if
289- // their layouts differ.
290- match compare_layouts ( a, b) {
291- Ok ( false ) => return false ,
292- _ => ( ) , // otherwise, continue onto the full, fields comparison
283+ ( & Adt ( a_def, _) , & Adt ( b_def, _) ) => {
284+ // Only `repr(C)` types can be compared structurally.
285+ if !( a_def. repr ( ) . c ( ) && b_def. repr ( ) . c ( ) ) {
286+ return false ;
287+ }
288+ // If the types differ in their packed-ness, align, or simd-ness they conflict.
289+ let repr_characteristica =
290+ |def : AdtDef < ' tcx > | ( def. repr ( ) . pack , def. repr ( ) . align , def. repr ( ) . simd ( ) ) ;
291+ if repr_characteristica ( a_def) != repr_characteristica ( b_def) {
292+ return false ;
293293 }
294294
295295 // Grab a flattened representation of all fields.
@@ -311,9 +311,9 @@ fn structurally_same_type_impl<'tcx>(
311311 } ,
312312 )
313313 }
314- ( Array ( a_ty, a_const ) , Array ( b_ty, b_const ) ) => {
315- // For arrays, we also check the constness of the type .
316- a_const . kind ( ) == b_const . kind ( )
314+ ( Array ( a_ty, a_len ) , Array ( b_ty, b_len ) ) => {
315+ // For arrays, we also check the length .
316+ a_len == b_len
317317 && structurally_same_type_impl (
318318 seen_types, tcx, param_env, * a_ty, * b_ty, ckind,
319319 )
@@ -357,10 +357,9 @@ fn structurally_same_type_impl<'tcx>(
357357 ckind,
358358 )
359359 }
360- ( Tuple ( a_args) , Tuple ( b_args) ) => {
361- a_args. iter ( ) . eq_by ( b_args. iter ( ) , |a_ty, b_ty| {
362- structurally_same_type_impl ( seen_types, tcx, param_env, a_ty, b_ty, ckind)
363- } )
360+ ( Tuple ( ..) , Tuple ( ..) ) => {
361+ // Tuples are not `repr(C)` so these cannot be compared structurally.
362+ false
364363 }
365364 // For these, it's not quite as easy to define structural-sameness quite so easily.
366365 // For the purposes of this lint, take the conservative approach and mark them as
@@ -380,24 +379,21 @@ fn structurally_same_type_impl<'tcx>(
380379 // An Adt and a primitive or pointer type. This can be FFI-safe if non-null
381380 // enum layout optimisation is being applied.
382381 ( Adt ( ..) , _) if is_primitive_or_pointer ( b) => {
383- if let Some ( ty ) = types:: repr_nullable_ptr ( tcx, param_env, a, ckind) {
384- ty == b
382+ if let Some ( a_inner ) = types:: repr_nullable_ptr ( tcx, param_env, a, ckind) {
383+ a_inner == b
385384 } else {
386- compare_layouts ( a , b ) . unwrap_or ( false )
385+ false
387386 }
388387 }
389388 ( _, Adt ( ..) ) if is_primitive_or_pointer ( a) => {
390- if let Some ( ty ) = types:: repr_nullable_ptr ( tcx, param_env, b, ckind) {
391- ty == a
389+ if let Some ( b_inner ) = types:: repr_nullable_ptr ( tcx, param_env, b, ckind) {
390+ b_inner == a
392391 } else {
393- compare_layouts ( a , b ) . unwrap_or ( false )
392+ false
394393 }
395394 }
396395
397- // Otherwise, just compare the layouts. This may fail to lint for some
398- // incompatible types, but at the very least, will stop reads into
399- // uninitialised memory.
400- _ => compare_layouts ( a, b) . unwrap_or ( false ) ,
396+ _ => false ,
401397 }
402398 } )
403399 }
0 commit comments