From 5da2bf197d301f83716a209cb28ea2b403c8a20c Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Wed, 4 Nov 2020 03:07:40 -0500 Subject: [PATCH 1/2] Remove extra call to upvar_tys Fixes #78720 --- .../rustc_trait_selection/src/opaque_types.rs | 10 ---- src/test/ui/issues/issue-78720.rs | 19 +++++++ src/test/ui/issues/issue-78720.stderr | 55 +++++++++++++++++++ 3 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/issues/issue-78720.rs create mode 100644 src/test/ui/issues/issue-78720.stderr diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index ca547bf88b588..f5bc90e6f9621 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -722,11 +722,6 @@ where // Skip lifetime parameters of the enclosing item(s) substs.as_closure().tupled_upvars_ty().visit_with(self); - - for upvar_ty in substs.as_closure().upvar_tys() { - upvar_ty.visit_with(self); - } - substs.as_closure().sig_as_fn_ptr_ty().visit_with(self); } @@ -735,11 +730,6 @@ where // Also skip the witness type, because that has no free regions. substs.as_generator().tupled_upvars_ty().visit_with(self); - - for upvar_ty in substs.as_generator().upvar_tys() { - upvar_ty.visit_with(self); - } - substs.as_generator().return_ty().visit_with(self); substs.as_generator().yield_ty().visit_with(self); substs.as_generator().resume_ty().visit_with(self); diff --git a/src/test/ui/issues/issue-78720.rs b/src/test/ui/issues/issue-78720.rs new file mode 100644 index 0000000000000..57615d1a207fd --- /dev/null +++ b/src/test/ui/issues/issue-78720.rs @@ -0,0 +1,19 @@ +fn server() -> impl { +//~^ ERROR at least one trait must be specified + ().map2(|| "") +} + +trait FilterBase2 { + fn map2(self, F) -> Map2 {} + //~^ ERROR mismatched types + //~^^ ERROR the size for values of type `Self` cannot be known at compilation time +} + +struct Map2 { + _func: F, + //~^ ERROR cannot find type `F` in this scope +} + +impl FilterBase2 for F {} + +fn main() {} diff --git a/src/test/ui/issues/issue-78720.stderr b/src/test/ui/issues/issue-78720.stderr new file mode 100644 index 0000000000000..a3a14e34acbc1 --- /dev/null +++ b/src/test/ui/issues/issue-78720.stderr @@ -0,0 +1,55 @@ +error: at least one trait must be specified + --> $DIR/issue-78720.rs:1:16 + | +LL | fn server() -> impl { + | ^^^^ + +error[E0412]: cannot find type `F` in this scope + --> $DIR/issue-78720.rs:13:12 + | +LL | _func: F, + | ^ + | + ::: $SRC_DIR/core/src/ops/function.rs:LL:COL + | +LL | pub trait Fn: FnMut { + | ------------------------------- similarly named trait `Fn` defined here + | +help: a trait with a similar name exists + | +LL | _func: Fn, + | ^^ +help: you might be missing a type parameter + | +LL | struct Map2 { + | ^^^ + +error[E0308]: mismatched types + --> $DIR/issue-78720.rs:7:36 + | +LL | fn map2(self, F) -> Map2 {} + | ^^ expected struct `Map2`, found `()` + | + = note: expected struct `Map2` + found unit type `()` + +error[E0277]: the size for values of type `Self` cannot be known at compilation time + --> $DIR/issue-78720.rs:7:16 + | +LL | fn map2(self, F) -> Map2 {} + | ^^^^ doesn't have a size known at compile-time + | + = help: unsized fn params are gated as an unstable feature +help: consider further restricting `Self` + | +LL | fn map2(self, F) -> Map2 where Self: Sized {} + | ^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn map2(&self, F) -> Map2 {} + | ^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308, E0412. +For more information about an error, try `rustc --explain E0277`. From e35e46c1139d292ca0b352416d01b38bcf96fd69 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 7 Nov 2020 01:04:27 -0500 Subject: [PATCH 2/2] Be cautious of calling upvar_tys before mir --- compiler/rustc_middle/src/ty/layout.rs | 228 ++++++++++++---------- compiler/rustc_ty_utils/src/needs_drop.rs | 8 +- 2 files changed, 131 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8bdc7efa0bb61..00fea91fdfcb8 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2105,118 +2105,148 @@ where } fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { - let tcx = cx.tcx(); - let tag_layout = |tag: &Scalar| -> C::TyAndLayout { - let layout = Layout::scalar(cx, tag.clone()); - MaybeResult::from(Ok(TyAndLayout { - layout: tcx.intern_layout(layout), - ty: tag.value.to_ty(tcx), - })) - }; + enum TyMaybeWithLayout { + Ty(C::Ty), + TyAndLayout(C::TyAndLayout), + } - cx.layout_of(match *this.ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::FnPtr(_) - | ty::Never - | ty::FnDef(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this), - - // Potentially-fat pointers. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < this.fields.count()); - - // Reuse the fat `*T` type as its own thin pointer data field. - // This provides information about, e.g., DST struct pointees - // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldsShape` is checked by users. - if i == 0 { - let nil = tcx.mk_unit(); - let ptr_ty = if this.ty.is_unsafe_ptr() { - tcx.mk_mut_ptr(nil) - } else { - tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) - }; - return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map( - |mut ptr_layout| { - ptr_layout.ty = this.ty; - ptr_layout - }, - )); - } + fn ty_and_layout_kind< + C: LayoutOf, TyAndLayout: MaybeResult>> + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + >( + this: TyAndLayout<'tcx>, + cx: &C, + i: usize, + ty: C::Ty, + ) -> TyMaybeWithLayout { + let tcx = cx.tcx(); + let tag_layout = |tag: &Scalar| -> C::TyAndLayout { + let layout = Layout::scalar(cx, tag.clone()); + MaybeResult::from(Ok(TyAndLayout { + layout: tcx.intern_layout(layout), + ty: tag.value.to_ty(tcx), + })) + }; - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { - ty::Slice(_) | ty::Str => tcx.types.usize, - ty::Dynamic(_, _) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) - /* FIXME: use actual fn pointers - Warning: naively computing the number of entries in the - vtable by counting the methods on the trait + methods on - all parent traits does not work, because some methods can - be not object safe and thus excluded from the vtable. - Increase this counter if you tried to implement this but - failed to do it without duplicating a lot of code from - other places in the compiler: 2 - tcx.mk_tup(&[ - tcx.mk_array(tcx.types.usize, 3), - tcx.mk_array(Option), - ]) - */ + match *ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::FnPtr(_) + | ty::Never + | ty::FnDef(..) + | ty::GeneratorWitness(..) + | ty::Foreign(..) + | ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this), + + // Potentially-fat pointers. + ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < this.fields.count()); + + // Reuse the fat `*T` type as its own thin pointer data field. + // This provides information about, e.g., DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldsShape` is checked by users. + if i == 0 { + let nil = tcx.mk_unit(); + let ptr_ty = if ty.is_unsafe_ptr() { + tcx.mk_mut_ptr(nil) + } else { + tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) + }; + return TyMaybeWithLayout::TyAndLayout(MaybeResult::from( + cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| { + ptr_layout.ty = ty; + ptr_layout + }), + )); } - _ => bug!("TyAndLayout::field_type({:?}): not applicable", this), - } - } - // Arrays and slices. - ty::Array(element, _) | ty::Slice(element) => element, - ty::Str => tcx.types.u8, - - // Tuples, generators and closures. - ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(), - - ty::Generator(def_id, ref substs, _) => match this.variants { - Variants::Single { index } => substs - .as_generator() - .state_tys(def_id, tcx) - .nth(index.as_usize()) - .unwrap() - .nth(i) - .unwrap(), - Variants::Multiple { ref tag, tag_field, .. } => { - if i == tag_field { - return tag_layout(tag); + match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { + ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize), + ty::Dynamic(_, _) => { + TyMaybeWithLayout::Ty(tcx.mk_imm_ref( + tcx.lifetimes.re_static, + tcx.mk_array(tcx.types.usize, 3), + )) + /* FIXME: use actual fn pointers + Warning: naively computing the number of entries in the + vtable by counting the methods on the trait + methods on + all parent traits does not work, because some methods can + be not object safe and thus excluded from the vtable. + Increase this counter if you tried to implement this but + failed to do it without duplicating a lot of code from + other places in the compiler: 2 + tcx.mk_tup(&[ + tcx.mk_array(tcx.types.usize, 3), + tcx.mk_array(Option), + ]) + */ + } + _ => bug!("TyAndLayout::field_type({:?}): not applicable", this), } - substs.as_generator().prefix_tys().nth(i).unwrap() } - }, - ty::Tuple(tys) => tys[i].expect_ty(), + // Arrays and slices. + ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element), + ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8), - // ADTs. - ty::Adt(def, substs) => { - match this.variants { - Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs), + // Tuples, generators and closures. + ty::Closure(_, ref substs) => { + ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty()) + } + + ty::Generator(def_id, ref substs, _) => match this.variants { + Variants::Single { index } => TyMaybeWithLayout::Ty( + substs + .as_generator() + .state_tys(def_id, tcx) + .nth(index.as_usize()) + .unwrap() + .nth(i) + .unwrap(), + ), + Variants::Multiple { ref tag, tag_field, .. } => { + if i == tag_field { + return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); + } + TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap()) + } + }, + + ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i].expect_ty()), + + // ADTs. + ty::Adt(def, substs) => { + match this.variants { + Variants::Single { index } => { + TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs)) + } - // Discriminant field for enums (where applicable). - Variants::Multiple { ref tag, .. } => { - assert_eq!(i, 0); - return tag_layout(tag); + // Discriminant field for enums (where applicable). + Variants::Multiple { ref tag, .. } => { + assert_eq!(i, 0); + return TyMaybeWithLayout::TyAndLayout(tag_layout(tag)); + } } } + + ty::Projection(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Opaque(..) + | ty::Param(_) + | ty::Infer(_) + | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), } + } - ty::Projection(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Opaque(..) - | ty::Param(_) - | ty::Infer(_) - | ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty), + cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) { + TyMaybeWithLayout::Ty(result) => result, + TyMaybeWithLayout::TyAndLayout(result) => return result, }) } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d62fc764c76d7..64f82817d3944 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -94,16 +94,12 @@ where _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.as_closure().tupled_upvars_ty()); } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); - for upvar_ty in substs.upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.tupled_upvars_ty()); let witness = substs.witness(); let interior_tys = match witness.kind() {