From 5bae8ca77c3f6a0050a58b1bc96ee3d51d3feb32 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 24 Jan 2025 15:57:13 +0000 Subject: [PATCH] Correctly handle pattern types in FFI redeclaration lints --- compiler/rustc_lint/src/foreign_modules.rs | 9 +- compiler/rustc_lint/src/types.rs | 113 +++++++++++---------- tests/ui/lint/clashing-extern-fn.rs | 2 - tests/ui/lint/clashing-extern-fn.stderr | 32 +----- 4 files changed, 66 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 45b188205d2..636779fe9b4 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>( if let ty::Adt(def, args) = *ty.kind() { let is_transparent = def.repr().transparent(); let is_non_null = types::nonnull_optimization_guaranteed(tcx, def); - debug!( - "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", - ty, is_transparent, is_non_null - ); + debug!(?ty, is_transparent, is_non_null); if is_transparent && !is_non_null { debug_assert_eq!(def.variants().len(), 1); let v = &def.variant(FIRST_VARIANT); @@ -378,14 +375,14 @@ fn structurally_same_type_impl<'tcx>( // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. - (Adt(..), _) if is_primitive_or_pointer(b) => { + (Adt(..) | Pat(..), _) if is_primitive_or_pointer(b) => { if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } - (_, Adt(..)) if is_primitive_or_pointer(a) => { + (_, Adt(..) | Pat(..)) if is_primitive_or_pointer(a) => { if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 0dccb8d336d..47ceb4b7d28 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -907,9 +907,8 @@ fn get_nullable_type<'tcx>( }; return get_nullable_type(tcx, typing_env, inner_field_ty); } - ty::Int(ty) => Ty::new_int(tcx, ty), - ty::Uint(ty) => Ty::new_uint(tcx, ty), - ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), + ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base), + ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty, // As these types are always non-null, the nullable equivalent of // `Option` of these types are their raw pointer counterparts. ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl), @@ -965,63 +964,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty); - if let ty::Adt(ty_def, args) = ty.kind() { - let field_ty = match &ty_def.variants().raw[..] { - [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { - ([], [field]) | ([field], []) => field.ty(tcx, args), - ([field1], [field2]) => { - let ty1 = field1.ty(tcx, args); - let ty2 = field2.ty(tcx, args); + match ty.kind() { + ty::Adt(ty_def, args) => { + let field_ty = match &ty_def.variants().raw[..] { + [var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) { + ([], [field]) | ([field], []) => field.ty(tcx, args), + ([field1], [field2]) => { + let ty1 = field1.ty(tcx, args); + let ty2 = field2.ty(tcx, args); - if is_niche_optimization_candidate(tcx, typing_env, ty1) { - ty2 - } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { - ty1 - } else { - return None; + if is_niche_optimization_candidate(tcx, typing_env, ty1) { + ty2 + } else if is_niche_optimization_candidate(tcx, typing_env, ty2) { + ty1 + } else { + return None; + } } - } + _ => return None, + }, _ => return None, - }, - _ => return None, - }; - - if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { - return None; - } - - // At this point, the field's type is known to be nonnull and the parent enum is Option-like. - // If the computed size for the field and the enum are different, the nonnull optimization isn't - // being applied (and we've got a problem somewhere). - let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); - if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { - bug!("improper_ctypes: Option nonnull optimization not applied?"); - } - - // Return the nullable type this Option-like enum can be safely represented with. - let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); - if field_ty_layout.is_err() && !field_ty.has_non_region_param() { - bug!("should be able to compute the layout of non-polymorphic type"); - } - - let field_ty_abi = &field_ty_layout.ok()?.backend_repr; - if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { - match field_ty_scalar.valid_range(&tcx) { - WrappingRange { start: 0, end } - if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => - { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start: 1, .. } => { - return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); - } - WrappingRange { start, end } => { - unreachable!("Unhandled start and end range: ({}, {})", start, end) - } }; + + if !ty_is_known_nonnull(tcx, typing_env, field_ty, ckind) { + return None; + } + + // At this point, the field's type is known to be nonnull and the parent enum is Option-like. + // If the computed size for the field and the enum are different, the nonnull optimization isn't + // being applied (and we've got a problem somewhere). + let compute_size_skeleton = |t| SizeSkeleton::compute(t, tcx, typing_env).ok(); + if !compute_size_skeleton(ty)?.same_size(compute_size_skeleton(field_ty)?) { + bug!("improper_ctypes: Option nonnull optimization not applied?"); + } + + // Return the nullable type this Option-like enum can be safely represented with. + let field_ty_layout = tcx.layout_of(typing_env.as_query_input(field_ty)); + if field_ty_layout.is_err() && !field_ty.has_non_region_param() { + bug!("should be able to compute the layout of non-polymorphic type"); + } + + let field_ty_abi = &field_ty_layout.ok()?.backend_repr; + if let BackendRepr::Scalar(field_ty_scalar) = field_ty_abi { + match field_ty_scalar.valid_range(&tcx) { + WrappingRange { start: 0, end } + if end == field_ty_scalar.size(&tcx).unsigned_int_max() - 1 => + { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start: 1, .. } => { + return Some(get_nullable_type(tcx, typing_env, field_ty).unwrap()); + } + WrappingRange { start, end } => { + unreachable!("Unhandled start and end range: ({}, {})", start, end) + } + }; + } + None } + ty::Pat(base, pat) => match **pat { + ty::PatternKind::Range { .. } => get_nullable_type(tcx, typing_env, *base), + }, + _ => None, } - None } impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index 012eda761f4..1d1c07b66b2 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -514,13 +514,11 @@ mod pattern_types { // invariant that the value is non-zero, or you're missing out on that invariant. Both // cases are warning for, from both a caller-convenience and optimisation perspective. fn pt_non_zero_usize() -> usize; - //~^ WARN `pt_non_zero_usize` redeclared with a different signature fn pt_non_zero_usize_opt() -> usize; //~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature fn pt_non_null_ptr() -> *const (); //~^ WARN `pt_non_null_ptr` redeclared with a different signature fn pt_non_zero_usize_wrapper() -> usize; - //~^ WARN `pt_non_zero_usize_wrapper` redeclared with a different signature fn pt_non_zero_usize_wrapper_opt() -> usize; //~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature } diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index 16d251c1d7a..a2fc9e77492 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -285,20 +285,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option usize` found `unsafe extern "C" fn() -> Option>>` -warning: `pt_non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:516:13 - | -LL | fn pt_non_zero_usize() -> pattern_type!(usize is 1..); - | ------------------------------------------------------ `pt_non_zero_usize` previously declared here -... -LL | fn pt_non_zero_usize() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:518:13 + --> $DIR/clashing-extern-fn.rs:517:13 | LL | fn pt_non_zero_usize_opt() -> Option; | ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here @@ -310,7 +298,7 @@ LL | fn pt_non_zero_usize_opt() -> usize; found `unsafe extern "C" fn() -> usize` warning: `pt_non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:520:13 + --> $DIR/clashing-extern-fn.rs:519:13 | LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..); | ---------------------------------------------------- `pt_non_null_ptr` previously declared here @@ -321,20 +309,8 @@ LL | fn pt_non_null_ptr() -> *const (); = note: expected `unsafe extern "C" fn() -> (usize) is 1..=` found `unsafe extern "C" fn() -> *const ()` -warning: `pt_non_zero_usize_wrapper` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:522:13 - | -LL | fn pt_non_zero_usize_wrapper() -> NonZeroUsize; - | ----------------------------------------------- `pt_non_zero_usize_wrapper` previously declared here -... -LL | fn pt_non_zero_usize_wrapper() -> usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration - | - = note: expected `unsafe extern "C" fn() -> NonZeroUsize` - found `unsafe extern "C" fn() -> usize` - warning: `pt_non_zero_usize_wrapper_opt` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:524:13 + --> $DIR/clashing-extern-fn.rs:522:13 | LL | fn pt_non_zero_usize_wrapper_opt() -> Option; | ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here @@ -345,5 +321,5 @@ LL | fn pt_non_zero_usize_wrapper_opt() -> usize; = note: expected `unsafe extern "C" fn() -> Option` found `unsafe extern "C" fn() -> usize` -warning: 30 warnings emitted +warning: 28 warnings emitted