Skip to content

Erase all regions before constructing an LLVM type #77196

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
39 changes: 38 additions & 1 deletion compiler/rustc_middle/src/ty/erase_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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
Expand All @@ -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<T>(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> {
Expand Down
13 changes: 13 additions & 0 deletions src/test/ui/higher-rank-trait-bounds/issue-55976-invalid-ir.rs
Original file line number Diff line number Diff line change
@@ -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>(T, [u8; 64]);

pub fn abc<'a>(x: &Foo<Box<dyn for<'b> Fn(&'b u8)>>) -> &Foo<Box<dyn Fn(&'a u8)>> { x }

fn main() {
abc(&Foo(Box::new(|_x| ()), [0; 64]));
}