Correctly handle pattern types in FFI redeclaration lints
This commit is contained in:
parent
473352da31
commit
5bae8ca77c
4 changed files with 66 additions and 90 deletions
|
@ -241,10 +241,7 @@ fn structurally_same_type_impl<'tcx>(
|
||||||
if let ty::Adt(def, args) = *ty.kind() {
|
if let ty::Adt(def, args) = *ty.kind() {
|
||||||
let is_transparent = def.repr().transparent();
|
let is_transparent = def.repr().transparent();
|
||||||
let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
|
let is_non_null = types::nonnull_optimization_guaranteed(tcx, def);
|
||||||
debug!(
|
debug!(?ty, is_transparent, is_non_null);
|
||||||
"non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}",
|
|
||||||
ty, is_transparent, is_non_null
|
|
||||||
);
|
|
||||||
if is_transparent && !is_non_null {
|
if is_transparent && !is_non_null {
|
||||||
debug_assert_eq!(def.variants().len(), 1);
|
debug_assert_eq!(def.variants().len(), 1);
|
||||||
let v = &def.variant(FIRST_VARIANT);
|
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
|
// An Adt and a primitive or pointer type. This can be FFI-safe if non-null
|
||||||
// enum layout optimisation is being applied.
|
// 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) {
|
if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) {
|
||||||
a_inner == b
|
a_inner == b
|
||||||
} else {
|
} else {
|
||||||
false
|
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) {
|
if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) {
|
||||||
b_inner == a
|
b_inner == a
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -907,9 +907,8 @@ fn get_nullable_type<'tcx>(
|
||||||
};
|
};
|
||||||
return get_nullable_type(tcx, typing_env, inner_field_ty);
|
return get_nullable_type(tcx, typing_env, inner_field_ty);
|
||||||
}
|
}
|
||||||
ty::Int(ty) => Ty::new_int(tcx, ty),
|
ty::Pat(base, ..) => return get_nullable_type(tcx, typing_env, base),
|
||||||
ty::Uint(ty) => Ty::new_uint(tcx, ty),
|
ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => ty,
|
||||||
ty::RawPtr(ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
|
|
||||||
// As these types are always non-null, the nullable equivalent of
|
// As these types are always non-null, the nullable equivalent of
|
||||||
// `Option<T>` of these types are their raw pointer counterparts.
|
// `Option<T>` of these types are their raw pointer counterparts.
|
||||||
ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
|
ty::Ref(_region, ty, mutbl) => Ty::new_ptr(tcx, ty, mutbl),
|
||||||
|
@ -965,63 +964,69 @@ pub(crate) fn repr_nullable_ptr<'tcx>(
|
||||||
ckind: CItemKind,
|
ckind: CItemKind,
|
||||||
) -> Option<Ty<'tcx>> {
|
) -> Option<Ty<'tcx>> {
|
||||||
debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
|
debug!("is_repr_nullable_ptr(tcx, ty = {:?})", ty);
|
||||||
if let ty::Adt(ty_def, args) = ty.kind() {
|
match ty.kind() {
|
||||||
let field_ty = match &ty_def.variants().raw[..] {
|
ty::Adt(ty_def, args) => {
|
||||||
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
|
let field_ty = match &ty_def.variants().raw[..] {
|
||||||
([], [field]) | ([field], []) => field.ty(tcx, args),
|
[var_one, var_two] => match (&var_one.fields.raw[..], &var_two.fields.raw[..]) {
|
||||||
([field1], [field2]) => {
|
([], [field]) | ([field], []) => field.ty(tcx, args),
|
||||||
let ty1 = field1.ty(tcx, args);
|
([field1], [field2]) => {
|
||||||
let ty2 = field2.ty(tcx, args);
|
let ty1 = field1.ty(tcx, args);
|
||||||
|
let ty2 = field2.ty(tcx, args);
|
||||||
|
|
||||||
if is_niche_optimization_candidate(tcx, typing_env, ty1) {
|
if is_niche_optimization_candidate(tcx, typing_env, ty1) {
|
||||||
ty2
|
ty2
|
||||||
} else if is_niche_optimization_candidate(tcx, typing_env, ty2) {
|
} else if is_niche_optimization_candidate(tcx, typing_env, ty2) {
|
||||||
ty1
|
ty1
|
||||||
} else {
|
} else {
|
||||||
return None;
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
_ => 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> {
|
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
|
|
@ -514,13 +514,11 @@ mod pattern_types {
|
||||||
// invariant that the value is non-zero, or you're missing out on that invariant. Both
|
// 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.
|
// cases are warning for, from both a caller-convenience and optimisation perspective.
|
||||||
fn pt_non_zero_usize() -> usize;
|
fn pt_non_zero_usize() -> usize;
|
||||||
//~^ WARN `pt_non_zero_usize` redeclared with a different signature
|
|
||||||
fn pt_non_zero_usize_opt() -> usize;
|
fn pt_non_zero_usize_opt() -> usize;
|
||||||
//~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature
|
//~^ WARN `pt_non_zero_usize_opt` redeclared with a different signature
|
||||||
fn pt_non_null_ptr() -> *const ();
|
fn pt_non_null_ptr() -> *const ();
|
||||||
//~^ WARN `pt_non_null_ptr` redeclared with a different signature
|
//~^ WARN `pt_non_null_ptr` redeclared with a different signature
|
||||||
fn pt_non_zero_usize_wrapper() -> usize;
|
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;
|
fn pt_non_zero_usize_wrapper_opt() -> usize;
|
||||||
//~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature
|
//~^ WARN `pt_non_zero_usize_wrapper_opt` redeclared with a different signature
|
||||||
}
|
}
|
||||||
|
|
|
@ -285,20 +285,8 @@ LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usiz
|
||||||
= note: expected `unsafe extern "C" fn() -> usize`
|
= note: expected `unsafe extern "C" fn() -> usize`
|
||||||
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZero<usize>>>`
|
found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZero<usize>>>`
|
||||||
|
|
||||||
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
|
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<pattern_type!(usize is 1..)>;
|
LL | fn pt_non_zero_usize_opt() -> Option<pattern_type!(usize is 1..)>;
|
||||||
| ------------------------------------------------------------------ `pt_non_zero_usize_opt` previously declared here
|
| ------------------------------------------------------------------ `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`
|
found `unsafe extern "C" fn() -> usize`
|
||||||
|
|
||||||
warning: `pt_non_null_ptr` redeclared with a different signature
|
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..);
|
LL | fn pt_non_null_ptr() -> pattern_type!(usize is 1..);
|
||||||
| ---------------------------------------------------- `pt_non_null_ptr` previously declared here
|
| ---------------------------------------------------- `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..=`
|
= note: expected `unsafe extern "C" fn() -> (usize) is 1..=`
|
||||||
found `unsafe extern "C" fn() -> *const ()`
|
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
|
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<NonZeroUsize>;
|
LL | fn pt_non_zero_usize_wrapper_opt() -> Option<NonZeroUsize>;
|
||||||
| ----------------------------------------------------------- `pt_non_zero_usize_wrapper_opt` previously declared here
|
| ----------------------------------------------------------- `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<NonZeroUsize>`
|
= note: expected `unsafe extern "C" fn() -> Option<NonZeroUsize>`
|
||||||
found `unsafe extern "C" fn() -> usize`
|
found `unsafe extern "C" fn() -> usize`
|
||||||
|
|
||||||
warning: 30 warnings emitted
|
warning: 28 warnings emitted
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue