diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index e0754d21df1f0..564a2fcfc7f1a 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -252,7 +252,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Make sure lifetimes are erased, to avoid generating distinct LLVM // types for Rust types that only differ in the choice of lifetimes. - let normal_ty = cx.tcx.erase_regions(&self.ty); + // Note that we erase *all* regions, include late-bound regions. + let normal_ty = cx.tcx.erase_early_and_late_regions(&self.ty); let mut defer = None; let llty = if self.ty != normal_ty { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9c047cbfaefdd..7ab96f451e839 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -347,6 +347,11 @@ rustc_queries! { anon desc { "erasing regions from `{:?}`", ty } } + + query erase_early_and_late_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { + anon + desc { "erasing early and late regions for `{:?}`", ty } + } } Linking { diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 48d0fc1839e2f..dfdf0c97ebf4c 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -2,7 +2,8 @@ use crate::ty::fold::{TypeFoldable, TypeFolder}; use crate::ty::{self, Ty, TyCtxt, TypeFlags}; pub(super) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { erase_regions_ty, ..*providers }; + *providers = + ty::query::Providers { erase_regions_ty, erase_early_and_late_regions_ty, ..*providers }; } fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -11,6 +12,12 @@ fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { ty.super_fold_with(&mut RegionEraserVisitor { tcx }) } +fn erase_early_and_late_regions_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { + // N.B., use `super_fold_with` here. If we used `fold_with`, it + // could invoke the `erase_regions_ty` query recursively. + ty.super_fold_with(&mut AllRegionEraserVisitor { tcx }) +} + impl<'tcx> TyCtxt<'tcx> { /// Returns an equivalent value with all free regions removed (note /// that late-bound regions remain, because they are important for @@ -28,6 +35,36 @@ impl<'tcx> TyCtxt<'tcx> { debug!("erase_regions({:?}) = {:?}", value, value1); value1 } + + /// Like `erase_regions`, but erases all regions, including late-bound regions. + /// This is only useful during certain parts of codegen, where regions truly + /// don't matter. Normally, `erase_regions` should be used instead. + pub fn erase_early_and_late_regions(self, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + // If there's nothing to erase avoid performing the query at all + if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { + return value.clone(); + } + value.fold_with(&mut AllRegionEraserVisitor { tcx: self }) + } +} + +struct AllRegionEraserVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl TypeFolder<'tcx> for AllRegionEraserVisitor<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + self.tcx.erase_early_and_late_regions_ty(ty) + } + fn fold_region(&mut self, _: ty::Region<'tcx>) -> ty::Region<'tcx> { + self.tcx.lifetimes.re_erased + } } struct RegionEraserVisitor<'tcx> { diff --git a/src/test/ui/higher-rank-trait-bounds/issue-55976-invalid-ir.rs b/src/test/ui/higher-rank-trait-bounds/issue-55976-invalid-ir.rs new file mode 100644 index 0000000000000..4877ce86db0cb --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-55976-invalid-ir.rs @@ -0,0 +1,13 @@ +// Regression test for issue #55976 +// Tests that we don't generate invalid LLVM IR when certain +// higher-ranked trait bounds are involved. + +// run-pass + +pub struct Foo(T, [u8; 64]); + +pub fn abc<'a>(x: &Foo Fn(&'b u8)>>) -> &Foo> { x } + +fn main() { + abc(&Foo(Box::new(|_x| ()), [0; 64])); +}