From 0f2bd56b29857453835e47abbe96a80b175632d1 Mon Sep 17 00:00:00 2001 From: David Wood Date: Mon, 3 Aug 2020 11:08:03 +0100 Subject: [PATCH] lint/ty: move fns to avoid abstraction violation This commit moves `transparent_newtype_field` and `is_zst` to `LateContext` where they are used, rather than being on the `VariantDef` and `TyS` types. Signed-off-by: David Wood --- compiler/rustc_lint/src/builtin.rs | 6 +++--- compiler/rustc_lint/src/types.rs | 26 +++++++++++++++++++++++--- compiler/rustc_middle/src/ty/mod.rs | 15 +-------------- compiler/rustc_middle/src/ty/sty.rs | 5 ----- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ea624b9ed30..694455171e9 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,7 +21,8 @@ //! `late_lint_methods!` invocation in `lib.rs`. 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::tokenstream::{TokenStream, TokenTree}; @@ -2180,8 +2181,7 @@ impl ClashingExternDeclarations { if is_transparent && !is_non_null { debug_assert!(def.variants.len() == 1); let v = &def.variants[VariantIdx::new(0)]; - ty = v - .transparent_newtype_field(tcx) + ty = transparent_newtype_field(tcx, v) .expect( "single-variant transparent structure with zero-sized field", ) diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 35c462c24c8..132e9286f6b 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -533,6 +533,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)) } +/// `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? crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { let tcx = cx.tcx; @@ -548,7 +568,7 @@ crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: C } 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) { return true; } @@ -569,7 +589,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { let inner_field_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!( first_non_zst_ty.clone().count(), 1, @@ -710,7 +730,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.repr.transparent() { // Can assume that only one field is not a ZST, so only check // 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) } else { bug!("malformed transparent type"); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index b6300a40b0d..8027bed2c8c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2005,7 +2005,7 @@ pub struct VariantDef { flags: VariantFlags, } -impl<'tcx> VariantDef { +impl VariantDef { /// Creates a new `VariantDef`. /// /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` @@ -2071,19 +2071,6 @@ impl<'tcx> VariantDef { pub fn is_recovered(&self) -> bool { 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)] diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index c1f354c7a15..2af3fb7f863 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -2280,9 +2280,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) - } }