Rollup merge of #75099 - davidtwco:is-zst-abstraction-violation, r=eddyb
lint/ty: move fns to avoid abstraction violation This PR moves `transparent_newtype_field` and `is_zst` to `LateContext` where they are used, rather than being on the `VariantDef` and `TyS` types, hopefully addressing @eddyb's concern [from this comment](https://github.com/rust-lang/rust/pull/74340#discussion_r456534910).
This commit is contained in:
commit
aa25f9ebd8
4 changed files with 27 additions and 25 deletions
|
@ -21,7 +21,8 @@
|
||||||
//! `late_lint_methods!` invocation in `lib.rs`.
|
//! `late_lint_methods!` invocation in `lib.rs`.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
types::{transparent_newtype_field, CItemKind},
|
||||||
|
EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext,
|
||||||
};
|
};
|
||||||
use rustc_ast::attr::{self, HasAttrs};
|
use rustc_ast::attr::{self, HasAttrs};
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||||
|
@ -2688,8 +2689,7 @@ impl ClashingExternDeclarations {
|
||||||
if is_transparent && !is_non_null {
|
if is_transparent && !is_non_null {
|
||||||
debug_assert!(def.variants.len() == 1);
|
debug_assert!(def.variants.len() == 1);
|
||||||
let v = &def.variants[VariantIdx::new(0)];
|
let v = &def.variants[VariantIdx::new(0)];
|
||||||
ty = v
|
ty = transparent_newtype_field(tcx, v)
|
||||||
.transparent_newtype_field(tcx)
|
|
||||||
.expect(
|
.expect(
|
||||||
"single-variant transparent structure with zero-sized field",
|
"single-variant transparent structure with zero-sized field",
|
||||||
)
|
)
|
||||||
|
|
|
@ -639,6 +639,26 @@ crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtD
|
||||||
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
|
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
|
||||||
|
/// field.
|
||||||
|
pub fn transparent_newtype_field<'a, 'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
variant: &'a ty::VariantDef,
|
||||||
|
) -> Option<&'a ty::FieldDef> {
|
||||||
|
let param_env = tcx.param_env(variant.def_id);
|
||||||
|
for field in &variant.fields {
|
||||||
|
let field_ty = tcx.type_of(field.did);
|
||||||
|
let is_zst =
|
||||||
|
tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false);
|
||||||
|
|
||||||
|
if !is_zst {
|
||||||
|
return Some(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// Is type known to be non-null?
|
/// Is type known to be non-null?
|
||||||
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool {
|
||||||
let tcx = cx.tcx;
|
let tcx = cx.tcx;
|
||||||
|
@ -654,7 +674,7 @@ crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: C
|
||||||
}
|
}
|
||||||
|
|
||||||
for variant in &def.variants {
|
for variant in &def.variants {
|
||||||
if let Some(field) = variant.transparent_newtype_field(tcx) {
|
if let Some(field) = transparent_newtype_field(cx.tcx, variant) {
|
||||||
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
|
if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -675,7 +695,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
|
||||||
ty::Adt(field_def, field_substs) => {
|
ty::Adt(field_def, field_substs) => {
|
||||||
let inner_field_ty = {
|
let inner_field_ty = {
|
||||||
let first_non_zst_ty =
|
let first_non_zst_ty =
|
||||||
field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx));
|
field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v));
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
first_non_zst_ty.clone().count(),
|
first_non_zst_ty.clone().count(),
|
||||||
1,
|
1,
|
||||||
|
@ -816,7 +836,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
|
||||||
if def.repr.transparent() {
|
if def.repr.transparent() {
|
||||||
// Can assume that only one field is not a ZST, so only check
|
// Can assume that only one field is not a ZST, so only check
|
||||||
// that field's type for FFI-safety.
|
// that field's type for FFI-safety.
|
||||||
if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) {
|
if let Some(field) = transparent_newtype_field(self.cx.tcx, variant) {
|
||||||
self.check_field_type_for_ffi(cache, field, substs)
|
self.check_field_type_for_ffi(cache, field, substs)
|
||||||
} else {
|
} else {
|
||||||
bug!("malformed transparent type");
|
bug!("malformed transparent type");
|
||||||
|
|
|
@ -1999,7 +1999,7 @@ pub struct VariantDef {
|
||||||
flags: VariantFlags,
|
flags: VariantFlags,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> VariantDef {
|
impl VariantDef {
|
||||||
/// Creates a new `VariantDef`.
|
/// Creates a new `VariantDef`.
|
||||||
///
|
///
|
||||||
/// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
|
/// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef`
|
||||||
|
@ -2065,19 +2065,6 @@ impl<'tcx> VariantDef {
|
||||||
pub fn is_recovered(&self) -> bool {
|
pub fn is_recovered(&self) -> bool {
|
||||||
self.flags.intersects(VariantFlags::IS_RECOVERED)
|
self.flags.intersects(VariantFlags::IS_RECOVERED)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that
|
|
||||||
/// field.
|
|
||||||
pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> {
|
|
||||||
for field in &self.fields {
|
|
||||||
let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id));
|
|
||||||
if !field_ty.is_zst(tcx, self.def_id) {
|
|
||||||
return Some(field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
|
||||||
|
|
|
@ -2322,9 +2322,4 @@ impl<'tcx> TyS<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is this a zero-sized type?
|
|
||||||
pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool {
|
|
||||||
tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue