Rollup merge of #73758 - davidtwco:issue-60855-remaining-reveal-all, r=matthewjasper
improper_ctypes: fix remaining `Reveal:All` Fixes #60855. This PR replaces the remaining uses of `ParamEnv::reveal_all` with `LateContext`'s `param_env` (normally `Reveal::UserFacing`) in the improper ctypes lint.
This commit is contained in:
commit
d5205f23d3
1 changed files with 77 additions and 73 deletions
|
@ -11,7 +11,7 @@ use rustc_index::vec::Idx;
|
||||||
use rustc_middle::mir::interpret::{sign_extend, truncate};
|
use rustc_middle::mir::interpret::{sign_extend, truncate};
|
||||||
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
|
use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton};
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable};
|
||||||
use rustc_span::source_map;
|
use rustc_span::source_map;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, DUMMY_SP};
|
use rustc_span::{Span, DUMMY_SP};
|
||||||
|
@ -525,78 +525,82 @@ enum FfiResult<'tcx> {
|
||||||
FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
|
FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option<String> },
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_is_known_nonnull<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
|
||||||
match ty.kind {
|
|
||||||
ty::FnPtr(_) => true,
|
|
||||||
ty::Ref(..) => true,
|
|
||||||
ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
|
|
||||||
for field in field_def.all_fields() {
|
|
||||||
let field_ty =
|
|
||||||
tcx.normalize_erasing_regions(ParamEnv::reveal_all(), field.ty(tcx, substs));
|
|
||||||
if field_ty.is_zst(tcx, field.did) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let attrs = tcx.get_attrs(field_def.did);
|
|
||||||
if attrs.iter().any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
|
|
||||||
|| ty_is_known_nonnull(tcx, field_ty)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if this enum can be safely exported based on the
|
|
||||||
/// "nullable pointer optimization". Currently restricted
|
|
||||||
/// to function pointers, references, core::num::NonZero*,
|
|
||||||
/// core::ptr::NonNull, and #[repr(transparent)] newtypes.
|
|
||||||
/// FIXME: This duplicates code in codegen.
|
|
||||||
fn is_repr_nullable_ptr<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
ty_def: &'tcx ty::AdtDef,
|
|
||||||
substs: SubstsRef<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
if ty_def.variants.len() != 2 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
|
|
||||||
let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
|
|
||||||
let fields = if variant_fields[0].is_empty() {
|
|
||||||
&variant_fields[1]
|
|
||||||
} else if variant_fields[1].is_empty() {
|
|
||||||
&variant_fields[0]
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
if fields.len() != 1 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let field_ty = fields[0].ty(tcx, substs);
|
|
||||||
if !ty_is_known_nonnull(tcx, field_ty) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, ParamEnv::reveal_all()).unwrap();
|
|
||||||
if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
|
|
||||||
bug!("improper_ctypes: Option nonnull optimization not applied?");
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
|
/// Is type known to be non-null?
|
||||||
|
fn ty_is_known_nonnull(&self, ty: Ty<'tcx>) -> bool {
|
||||||
|
match ty.kind {
|
||||||
|
ty::FnPtr(_) => true,
|
||||||
|
ty::Ref(..) => true,
|
||||||
|
ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
|
||||||
|
for field in field_def.all_fields() {
|
||||||
|
let field_ty = self.cx.tcx.normalize_erasing_regions(
|
||||||
|
self.cx.param_env,
|
||||||
|
field.ty(self.cx.tcx, substs),
|
||||||
|
);
|
||||||
|
if field_ty.is_zst(self.cx.tcx, field.did) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attrs = self.cx.tcx.get_attrs(field_def.did);
|
||||||
|
if attrs
|
||||||
|
.iter()
|
||||||
|
.any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed))
|
||||||
|
|| self.ty_is_known_nonnull(field_ty)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this enum can be safely exported based on the "nullable pointer optimization".
|
||||||
|
/// Currently restricted to function pointers, references, `core::num::NonZero*`,
|
||||||
|
/// `core::ptr::NonNull`, and `#[repr(transparent)]` newtypes.
|
||||||
|
fn is_repr_nullable_ptr(
|
||||||
|
&self,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
ty_def: &'tcx ty::AdtDef,
|
||||||
|
substs: SubstsRef<'tcx>,
|
||||||
|
) -> bool {
|
||||||
|
if ty_def.variants.len() != 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields;
|
||||||
|
let variant_fields = [get_variant_fields(0), get_variant_fields(1)];
|
||||||
|
let fields = if variant_fields[0].is_empty() {
|
||||||
|
&variant_fields[1]
|
||||||
|
} else if variant_fields[1].is_empty() {
|
||||||
|
&variant_fields[0]
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if fields.len() != 1 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let field_ty = fields[0].ty(self.cx.tcx, substs);
|
||||||
|
if !self.ty_is_known_nonnull(field_ty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 non-null
|
||||||
|
// optimization isn't being applied (and we've got a problem somewhere).
|
||||||
|
let compute_size_skeleton =
|
||||||
|
|t| SizeSkeleton::compute(t, self.cx.tcx, self.cx.param_env).unwrap();
|
||||||
|
if !compute_size_skeleton(ty).same_size(compute_size_skeleton(field_ty)) {
|
||||||
|
bug!("improper_ctypes: Option nonnull optimization not applied?");
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the type is array and emit an unsafe type lint.
|
/// Check if the type is array and emit an unsafe type lint.
|
||||||
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
|
fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
|
||||||
if let ty::Array(..) = ty.kind {
|
if let ty::Array(..) = ty.kind {
|
||||||
|
@ -738,7 +742,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
// discriminant.
|
// discriminant.
|
||||||
if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
|
if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
|
||||||
// Special-case types like `Option<extern fn()>`.
|
// Special-case types like `Option<extern fn()>`.
|
||||||
if !is_repr_nullable_ptr(cx, ty, def, substs) {
|
if !self.is_repr_nullable_ptr(ty, def, substs) {
|
||||||
return FfiUnsafe {
|
return FfiUnsafe {
|
||||||
ty,
|
ty,
|
||||||
reason: "enum has no representation hint".into(),
|
reason: "enum has no representation hint".into(),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue