Skip to content

Miscellaneous improvements to struct tail normalization #128703

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

Merged
merged 4 commits into from
Aug 9, 2024
Merged
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
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/common.rs
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@ pub(crate) fn has_ptr_meta<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
return false;
}

let tail = tcx.struct_tail_erasing_lifetimes(ty, ParamEnv::reveal_all());
let tail = tcx.struct_tail_for_codegen(ty, ParamEnv::reveal_all());
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/unsize.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ pub(crate) fn unsized_info<'tcx>(
old_info: Option<Value>,
) -> Value {
let (source, target) =
fx.tcx.struct_lockstep_tails_erasing_lifetimes(source, target, ParamEnv::reveal_all());
fx.tcx.struct_lockstep_tails_for_codegen(source, target, ParamEnv::reveal_all());
match (&source.kind(), &target.kind()) {
(&ty::Array(_, len), &ty::Slice(_)) => fx
.bcx
5 changes: 3 additions & 2 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
@@ -12,7 +12,8 @@ use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
TyAndLayout,
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_sanitizers::{cfi, kcfi};
@@ -531,7 +532,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn load_operand(&mut self, place: PlaceRef<'tcx, &'ll Value>) -> OperandRef<'tcx, &'ll Value> {
if place.layout.is_unsized() {
let tail = self.tcx.struct_tail_with_normalize(place.layout.ty, |ty| ty, || {});
let tail = self.tcx.struct_tail_for_codegen(place.layout.ty, self.param_env());
if matches!(tail.kind(), ty::Foreign(..)) {
// Unsized locals and, at least conceptually, even unsized arguments must be copied
// around, which requires dynamically determining their size. Therefore, we cannot
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
pointee_ty: Ty<'tcx>,
) -> Option<FatPtrKind> {
let pointee_tail_ty = cx.tcx.struct_tail_erasing_lifetimes(pointee_ty, cx.param_env());
let pointee_tail_ty = cx.tcx.struct_tail_for_codegen(pointee_ty, cx.param_env());
let layout = cx.layout_of(pointee_tail_ty);
trace!(
"fat_pointer_kind: {:?} has layout {:?} (is_unsized? {})",
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
) -> Bx::Value {
let cx = bx.cx();
let (source, target) =
cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, bx.param_env());
cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.param_env());
match (source.kind(), target.kind()) {
(&ty::Array(_, len), &ty::Slice(_)) => {
cx.const_usize(len.eval_target_usize(cx.tcx(), ty::ParamEnv::reveal_all()))
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/traits/type_.rs
Original file line number Diff line number Diff line change
@@ -91,7 +91,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
return false;
}

let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env);
let tail = self.tcx().struct_tail_for_codegen(ty, param_env);
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
5 changes: 2 additions & 3 deletions compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
@@ -678,9 +678,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
} else {
// Doesn't have to be a `dyn Trait`, but the unsized tail must be `dyn Trait`.
// (For that reason we also cannot use `unpack_dyn_trait`.)
let receiver_tail = self
.tcx
.struct_tail_erasing_lifetimes(receiver_place.layout.ty, self.param_env);
let receiver_tail =
self.tcx.struct_tail_for_codegen(receiver_place.layout.ty, self.param_env);
let ty::Dynamic(receiver_trait, _, ty::Dyn) = receiver_tail.kind() else {
span_bug!(
self.cur_span(),
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
@@ -386,7 +386,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
) -> InterpResult<'tcx> {
// A<Struct> -> A<Trait> conversion
let (src_pointee_ty, dest_pointee_ty) =
self.tcx.struct_lockstep_tails_erasing_lifetimes(source_ty, cast_ty, self.param_env);
self.tcx.struct_lockstep_tails_for_codegen(source_ty, cast_ty, self.param_env);

match (&src_pointee_ty.kind(), &dest_pointee_ty.kind()) {
(&ty::Array(_, length), &ty::Slice(_)) => {
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
@@ -343,7 +343,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
meta: MemPlaceMeta<M::Provenance>,
pointee: TyAndLayout<'tcx>,
) -> InterpResult<'tcx> {
let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env);
let tail = self.ecx.tcx.struct_tail_for_codegen(pointee.ty, self.ecx.param_env);
match tail.kind() {
ty::Dynamic(data, _, ty::Dyn) => {
let vtable = meta.unwrap_meta().to_pointer(self.ecx)?;
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/util/alignment.rs
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ where
};

let ty = place.ty(local_decls, tcx).ty;
let unsized_tail = || tcx.struct_tail_with_normalize(ty, |ty| ty, || {});
let unsized_tail = || tcx.struct_tail_for_codegen(ty, param_env);
match tcx.layout_of(param_env.and(ty)) {
Ok(layout)
if layout.align.abi <= pack
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -1276,7 +1276,7 @@ fn check_item_type(
UnsizedHandling::Forbid => true,
UnsizedHandling::Allow => false,
UnsizedHandling::AllowIfForeignTail => {
let tail = tcx.struct_tail_erasing_lifetimes(item_ty, wfcx.param_env);
let tail = tcx.struct_tail_for_codegen(item_ty, wfcx.param_env);
!matches!(tail.kind(), ty::Foreign(_))
}
};
13 changes: 11 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -404,8 +404,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
code: traits::ObligationCauseCode<'tcx>,
) {
if !ty.references_error() {
let tail =
self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {});
let tail = self.tcx.struct_tail_with_normalize(
ty,
|ty| {
if self.next_trait_solver() {
self.try_structurally_resolve_type(span, ty)
} else {
self.normalize(span, ty)
}
},
|| {},
);
// Sized types have static alignment, and so do slices.
if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) {
// Nothing else is required here.
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
@@ -869,7 +869,7 @@ where
metadata
}
} else {
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
match tcx.struct_tail_for_codegen(pointee, cx.param_env()).kind() {
ty::Slice(_) | ty::Str => tcx.types.usize,
ty::Dynamic(data, _, ty::Dyn) => mk_dyn_vtable(data.principal()),
_ => bug!("TyAndLayout::field({:?}): not applicable", this),
@@ -1348,7 +1348,7 @@ impl<'tcx> TyCtxt<'tcx> {
layout = layout.field(&cx, index);
if !layout.is_sized() {
// If it is not sized, then the tail must still have at least a known static alignment.
let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env);
let tail = self.struct_tail_for_codegen(layout.ty, param_env);
if !matches!(tail.kind(), ty::Slice(..)) {
bug!(
"offset of not-statically-aligned field (type {:?}) cannot be computed statically",
14 changes: 5 additions & 9 deletions compiler/rustc_middle/src/ty/util.rs
Original file line number Diff line number Diff line change
@@ -186,11 +186,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Should only be called if `ty` has no inference variables and does not
/// need its lifetimes preserved (e.g. as part of codegen); otherwise
/// normalization attempt may cause compiler bugs.
pub fn struct_tail_erasing_lifetimes(
self,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Ty<'tcx> {
pub fn struct_tail_for_codegen(self, ty: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let tcx = self;
tcx.struct_tail_with_normalize(ty, |ty| tcx.normalize_erasing_regions(param_env, ty), || {})
}
@@ -203,7 +199,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// handle `<T as Trait>::Assoc` and `impl Trait`); pass the identity
/// function to indicate no normalization should take place.
///
/// See also `struct_tail_erasing_lifetimes`, which is suitable for use
/// See also `struct_tail_for_codegen`, which is suitable for use
/// during codegen.
pub fn struct_tail_with_normalize(
self,
@@ -272,13 +268,13 @@ impl<'tcx> TyCtxt<'tcx> {
/// Same as applying `struct_tail` on `source` and `target`, but only
/// keeps going as long as the two types are instances of the same
/// structure definitions.
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, dyn Trait)`,
/// whereas struct_tail produces `T`, and `Trait`, respectively.
///
/// Should only be called if the types have no inference variables and do
/// not need their lifetimes preserved (e.g., as part of codegen); otherwise,
/// normalization attempt may cause compiler bugs.
pub fn struct_lockstep_tails_erasing_lifetimes(
pub fn struct_lockstep_tails_for_codegen(
self,
source: Ty<'tcx>,
target: Ty<'tcx>,
@@ -296,7 +292,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`,
/// whereas struct_tail produces `T`, and `Trait`, respectively.
///
/// See also `struct_lockstep_tails_erasing_lifetimes`, which is suitable for use
/// See also `struct_lockstep_tails_for_codegen`, which is suitable for use
/// during codegen.
pub fn struct_lockstep_tails_with_normalize(
self,
4 changes: 2 additions & 2 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
@@ -1019,7 +1019,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
if ty.is_sized(tcx.tcx, param_env) {
return false;
}
let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
let tail = tcx.struct_tail_for_codegen(ty, param_env);
match tail.kind() {
ty::Foreign(..) => false,
ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
@@ -1029,7 +1029,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
if type_has_metadata(inner_source) {
(inner_source, inner_target)
} else {
tcx.struct_lockstep_tails_erasing_lifetimes(inner_source, inner_target, param_env)
tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, param_env)
}
};

2 changes: 1 addition & 1 deletion compiler/rustc_ty_utils/src/abi.rs
Original file line number Diff line number Diff line change
@@ -549,7 +549,7 @@ fn fn_abi_sanity_check<'tcx>(
// With metadata. Must be unsized and not on the stack.
assert!(arg.layout.is_unsized() && !on_stack);
// Also, must not be `extern` type.
let tail = cx.tcx.struct_tail_with_normalize(arg.layout.ty, |ty| ty, || {});
let tail = cx.tcx.struct_tail_for_codegen(arg.layout.ty, cx.param_env());
if matches!(tail.kind(), ty::Foreign(..)) {
// These types do not have metadata, so having `meta_attrs` is bogus.
// Conceptually, unsized arguments must be copied around, which requires dynamically
2 changes: 1 addition & 1 deletion compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
@@ -244,7 +244,7 @@ fn layout_of_uncached<'tcx>(

metadata
} else {
let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
let unsized_part = tcx.struct_tail_for_codegen(pointee, param_env);

match unsized_part.kind() {
ty::Foreign(..) => {
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
Original file line number Diff line number Diff line change
@@ -142,7 +142,7 @@ fn check_rvalue<'tcx>(
// We cannot allow this for now.
return Err((span, "unsizing casts are only allowed for references right now".into()));
};
let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, tcx.param_env(def_id));
if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
check_operand(tcx, op, span, body, msrv)?;
// Casting/coercing things to slices is fine.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:28:13
--> $DIR/unaligned_references.rs:32:13
|
LL | &self.x;
| ^^^^^^^
@@ -9,7 +9,7 @@ LL | &self.x;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:40:24
--> $DIR/unaligned_references.rs:44:24
|
LL | println!("{:?}", &*foo.0);
| ^^^^^
@@ -19,7 +19,7 @@ LL | println!("{:?}", &*foo.0);
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:42:24
--> $DIR/unaligned_references.rs:46:24
|
LL | println!("{:?}", &*foo.0);
| ^^^^^
@@ -29,7 +29,7 @@ LL | println!("{:?}", &*foo.0);
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:47:24
--> $DIR/unaligned_references.rs:51:24
|
LL | println!("{:?}", &*foo.0);
| ^^^^^
@@ -39,7 +39,7 @@ LL | println!("{:?}", &*foo.0);
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:57:17
--> $DIR/unaligned_references.rs:81:17
|
LL | let _ = &good.ptr;
| ^^^^^^^^^
@@ -49,7 +49,7 @@ LL | let _ = &good.ptr;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:58:17
--> $DIR/unaligned_references.rs:82:17
|
LL | let _ = &good.data;
| ^^^^^^^^^^
@@ -59,7 +59,7 @@ LL | let _ = &good.data;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:60:17
--> $DIR/unaligned_references.rs:84:17
|
LL | let _ = &good.data as *const _;
| ^^^^^^^^^^
@@ -69,7 +69,7 @@ LL | let _ = &good.data as *const _;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:61:27
--> $DIR/unaligned_references.rs:85:27
|
LL | let _: *const _ = &good.data;
| ^^^^^^^^^^
@@ -79,7 +79,7 @@ LL | let _: *const _ = &good.data;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:63:17
--> $DIR/unaligned_references.rs:87:17
|
LL | let _ = good.data.clone();
| ^^^^^^^^^
@@ -89,7 +89,7 @@ LL | let _ = good.data.clone();
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:65:17
--> $DIR/unaligned_references.rs:89:17
|
LL | let _ = &good.data2[0];
| ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | let _ = &good.data2[0];
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:74:17
--> $DIR/unaligned_references.rs:98:17
|
LL | let _ = &packed2.x;
| ^^^^^^^^^^
@@ -109,7 +109,7 @@ LL | let _ = &packed2.x;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:113:20
--> $DIR/unaligned_references.rs:137:20
|
LL | let _ref = &m1.1.a;
| ^^^^^^^
@@ -119,7 +119,7 @@ LL | let _ref = &m1.1.a;
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error[E0793]: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:116:20
--> $DIR/unaligned_references.rs:140:20
|
LL | let _ref = &m2.1.a;
| ^^^^^^^
Loading