Skip to content
Open
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
60 changes: 55 additions & 5 deletions compiler/rustc_codegen_cranelift/example/mini_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,38 @@
rustc_attrs,
rustc_private,
transparent_unions,
pattern_types,
auto_traits,
freeze_impls,
thread_local
)]
#![no_core]
#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]

#[lang = "pointee_trait"]
pub trait Pointee: PointeeSized {
#[lang = "metadata_type"]
// needed so that layout_of will return `TooGeneric` instead of `Unknown`
// when asked for the layout of `*const T`. Which is important for making
// transmutes between raw pointers (and especially pattern types of raw pointers)
// work.
type Metadata: Copy + Sync + Unpin + Freeze;
}

#[lang = "dyn_metadata"]
pub struct DynMetadata<Dyn: PointeeSized> {
_vtable_ptr: NonNull<VTable>,
_phantom: PhantomData<Dyn>,
}

unsafe extern "C" {
/// Opaque type for accessing vtables.
///
/// Private implementation detail of `DynMetadata::size_of` etc.
/// There is conceptually not actually any Abstract Machine memory behind this pointer.
type VTable;
}

#[lang = "pointee_sized"]
pub trait PointeeSized {}

Expand Down Expand Up @@ -105,7 +130,7 @@ unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
unsafe impl<T: Sync, const N: usize> Sync for [T; N] {}

#[lang = "freeze"]
unsafe auto trait Freeze {}
pub unsafe auto trait Freeze {}

unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
unsafe impl<T: PointeeSized> Freeze for *const T {}
Expand Down Expand Up @@ -568,10 +593,24 @@ pub trait Deref {
fn deref(&self) -> &Self::Target;
}

#[rustc_builtin_macro(pattern_type)]
#[macro_export]
macro_rules! pattern_type {
($($arg:tt)*) => {
/* compiler built-in */
};
}

impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<pattern_type!(*const U is !null)> for pattern_type!(*const T is !null) where
T: Unsize<U>
{
}

impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<pattern_type!(U is !null)> for pattern_type!(T is !null) {}

#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
pub struct NonNull<T: PointeeSized>(pub *const T);
pub struct NonNull<T: PointeeSized>(pub pattern_type!(*const T is !null));

impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
Expand All @@ -598,7 +637,16 @@ impl<T> Box<T> {
let size = size_of::<T>();
let ptr = libc::malloc(size);
intrinsics::copy(&val as *const T as *const u8, ptr, size);
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
Box(
Unique {
pointer: NonNull(intrinsics::transmute::<
*mut u8,
pattern_type!(*const T is !null),
>(ptr)),
_marker: PhantomData,
},
Global,
)
}
}
}
Expand All @@ -607,7 +655,9 @@ impl<T: ?Sized, A> Drop for Box<T, A> {
fn drop(&mut self) {
// inner value is dropped by compiler
unsafe {
libc::free(self.0.pointer.0 as *mut u8);
libc::free(intrinsics::transmute::<pattern_type!(*const T is !null), *const T>(
self.0.pointer.0,
) as *mut u8);
}
}
}
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
extern_types,
thread_local,
repr_simd,
pattern_types,
rustc_private
)]
#![no_core]
Expand Down Expand Up @@ -159,7 +160,10 @@ extern "C" fn bool_struct_in_11(_arg0: bool_11) {}

#[allow(unreachable_code)] // FIXME false positive
fn main() {
take_unique(Unique { pointer: unsafe { NonNull(1 as *mut ()) }, _marker: PhantomData });
take_unique(Unique {
pointer: unsafe { NonNull(intrinsics::transmute(1 as *mut ())) },
_marker: PhantomData,
});
take_f32(0.1);

call_return_u128_pair();
Expand Down Expand Up @@ -225,7 +229,12 @@ fn main() {
let noisy_unsized_drop = const { intrinsics::needs_drop::<NoisyDropUnsized>() };
assert!(noisy_unsized_drop);

Unique { pointer: NonNull(1 as *mut &str), _marker: PhantomData } as Unique<dyn SomeTrait>;
Unique {
pointer: NonNull(intrinsics::transmute::<_, pattern_type!(*const &str is !null)>(
1 as *mut &str,
)),
_marker: PhantomData,
} as Unique<dyn SomeTrait>;

struct MyDst<T: ?Sized>(T);

Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,18 @@ pub(crate) fn spanned_type_di_node<'ll, 'tcx>(
AdtKind::Enum => enums::build_enum_type_di_node(cx, unique_type_id, span),
},
ty::Tuple(_) => build_tuple_type_di_node(cx, unique_type_id),
_ => bug!("debuginfo: unexpected type in type_di_node(): {:?}", t),
ty::Pat(base, _) => return type_di_node(cx, base),
// FIXME(unsafe_binders): impl debug info
ty::UnsafeBinder(_) => unimplemented!(),
ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Infer(_)
| ty::Placeholder(_)
| ty::CoroutineWitness(..)
| ty::Error(_) => {
bug!("debuginfo: unexpected type in type_di_node(): {:?}", t)
}
};

{
Expand Down
9 changes: 8 additions & 1 deletion compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::ty::{self, Instance, PatternKind, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::Session;
use rustc_session::config::{self, CrateType, EntryFnType};
Expand Down Expand Up @@ -275,6 +275,13 @@ pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let src_ty = src.layout.ty;
let dst_ty = dst.layout.ty;
match (src_ty.kind(), dst_ty.kind()) {
(&ty::Pat(s, sp), &ty::Pat(d, dp))
if let (PatternKind::NotNull, PatternKind::NotNull) = (*sp, *dp) =>
{
let src = src.project_type(bx, s);
let dst = dst.project_type(bx, d);
coerce_unsized_into(bx, src, dst)
}
(&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
let (base, info) = match bx.load_operand(src).val {
OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_const_eval/src/interpret/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let (_, field) = layout.non_1zst_field(self).unwrap();
self.unfold_transparent(field, may_unfold)
}
ty::Pat(base, _) => self.layout_of(*base).expect(
"if the layout of a pattern type could be computed, so can the layout of its base",
),
// Not a transparent type, no further unfolding.
_ => layout,
}
Expand Down
7 changes: 6 additions & 1 deletion compiler/rustc_const_eval/src/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {

// ... that contains a `NonNull`... (gladly, only a single field here)
assert_eq!(nonnull_ptr.layout().fields.count(), 1);
let raw_ptr = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // the actual raw ptr
let pat_ty = self.ecx().project_field(&nonnull_ptr, FieldIdx::ZERO)?; // `*mut T is !null`
let base = match *pat_ty.layout().ty.kind() {
ty::Pat(base, _) => self.ecx().layout_of(base)?,
_ => unreachable!(),
};
let raw_ptr = pat_ty.transmute(base, self.ecx())?; // The actual raw pointer

// ... whose only field finally is a raw ptr we can dereference.
self.visit_box(ty, &raw_ptr)?;
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use rustc_session::config::OptLevel;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
use rustc_target::callconv::FnAbi;
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
use tracing::debug;
use tracing::{debug, instrument, trace};
use {rustc_abi as abi, rustc_hir as hir};

use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
Expand Down Expand Up @@ -380,6 +380,7 @@ pub enum SizeSkeleton<'tcx> {
}

impl<'tcx> SizeSkeleton<'tcx> {
#[instrument(level = "trace", skip(tcx, typing_env), ret)]
pub fn compute(
ty: Ty<'tcx>,
tcx: TyCtxt<'tcx>,
Expand Down Expand Up @@ -429,6 +430,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
},
|| {},
);
trace!(?tail);

match tail.kind() {
ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
Expand Down
33 changes: 21 additions & 12 deletions compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rustc_index::{IndexVec, indexvec};
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{self, PatternKind, Ty, TyCtxt};

use crate::patch::MirPatch;

Expand All @@ -20,21 +20,27 @@ fn build_ptr_tys<'tcx>(
pointee: Ty<'tcx>,
unique_def: ty::AdtDef<'tcx>,
nonnull_def: ty::AdtDef<'tcx>,
) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
) -> (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>, Ty<'tcx>) {
let args = tcx.mk_args(&[pointee.into()]);
let unique_ty = Ty::new_adt(tcx, unique_def, args);
let nonnull_ty = Ty::new_adt(tcx, nonnull_def, args);
let ptr_ty = Ty::new_imm_ptr(tcx, pointee);
let pat_ty = Ty::new_pat(tcx, ptr_ty, tcx.mk_pat(PatternKind::NotNull));

(unique_ty, nonnull_ty, ptr_ty)
(unique_ty, nonnull_ty, pat_ty, ptr_ty)
}

/// Constructs the projection needed to access a Box's pointer
pub(super) fn build_projection<'tcx>(
unique_ty: Ty<'tcx>,
nonnull_ty: Ty<'tcx>,
) -> [PlaceElem<'tcx>; 2] {
[PlaceElem::Field(FieldIdx::ZERO, unique_ty), PlaceElem::Field(FieldIdx::ZERO, nonnull_ty)]
pat_ty: Ty<'tcx>,
) -> [PlaceElem<'tcx>; 3] {
[
PlaceElem::Field(FieldIdx::ZERO, unique_ty),
PlaceElem::Field(FieldIdx::ZERO, nonnull_ty),
PlaceElem::Field(FieldIdx::ZERO, pat_ty),
]
}

struct ElaborateBoxDerefVisitor<'a, 'tcx> {
Expand Down Expand Up @@ -66,7 +72,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
{
let source_info = self.local_decls[place.local].source_info;

let (unique_ty, nonnull_ty, ptr_ty) =
let (unique_ty, nonnull_ty, pat_ty, ptr_ty) =
build_ptr_tys(tcx, boxed_ty, self.unique_def, self.nonnull_def);

let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
Expand All @@ -78,7 +84,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
CastKind::Transmute,
Operand::Copy(
Place::from(place.local)
.project_deeper(&build_projection(unique_ty, nonnull_ty), tcx),
.project_deeper(&build_projection(unique_ty, nonnull_ty, pat_ty), tcx),
),
ptr_ty,
),
Expand All @@ -101,7 +107,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
&& let ty::Adt(box_adt, box_args) = Ty::new_box(tcx, pointee).kind()
{
let args = tcx.mk_args(&[pointee.into()]);
let (unique_ty, nonnull_ty, ptr_ty) =
// We skip the pointer type by directly transmuting from the `*const u8` of
// `ShallowInitBox` to the pattern type that will get placed inside `NonNull`
let (unique_ty, nonnull_ty, pat_ty, _ptr_ty) =
build_ptr_tys(tcx, pointee, self.unique_def, self.nonnull_def);
let adt_kind = |def: ty::AdtDef<'tcx>, args| {
Box::new(AggregateKind::Adt(def.did(), VariantIdx::ZERO, args, None, None))
Expand All @@ -114,11 +122,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'a, 'tcx> {
}))
};

let constptr = self.patch.new_temp(ptr_ty, source_info.span);
let constptr = self.patch.new_temp(pat_ty, source_info.span);
self.patch.add_assign(
location,
constptr.into(),
Rvalue::Cast(CastKind::Transmute, mutptr_to_u8.clone(), ptr_ty),
Rvalue::Cast(CastKind::Transmute, mutptr_to_u8.clone(), pat_ty),
);

let nonnull = self.patch.new_temp(nonnull_ty, source_info.span);
Expand Down Expand Up @@ -199,10 +207,11 @@ impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
let new_projections =
new_projections.get_or_insert_with(|| base.projection.to_vec());

let (unique_ty, nonnull_ty, ptr_ty) =
let (unique_ty, nonnull_ty, pat_ty, ptr_ty) =
build_ptr_tys(tcx, boxed_ty, unique_def, nonnull_def);

new_projections.extend_from_slice(&build_projection(unique_ty, nonnull_ty));
new_projections
.extend_from_slice(&build_projection(unique_ty, nonnull_ty, pat_ty));
// While we can't project into `NonNull<_>` in a basic block
// due to MCP#807, this is debug info where it's fine.
new_projections.push(PlaceElem::Field(FieldIdx::ZERO, ptr_ty));
Expand Down
17 changes: 9 additions & 8 deletions compiler/rustc_mir_transform/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,24 +669,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let fail_out_of_bounds = |this: &mut Self, location| {
this.fail(location, format!("Out of bounds field {f:?} for {parent_ty:?}"));
};

let kind = match parent_ty.ty.kind() {
&ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
self.tcx.type_of(def_id).instantiate(self.tcx, args).kind()
}
kind => kind,
};

let check_equal = |this: &mut Self, location, f_ty| {
if !this.mir_assign_valid_types(ty, f_ty) {
this.fail(
location,
format!(
"Field projection `{place_ref:?}.{f:?}` specified type `{ty}`, but actual type is `{f_ty}`"
"Field projection `{place_ref:?}.{f:?}` specified type `{ty}`, but actual field type of `{kind:?}` is `{f_ty}`"
)
)
}
};

let kind = match parent_ty.ty.kind() {
&ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
self.tcx.type_of(def_id).instantiate(self.tcx, args).kind()
}
kind => kind,
};

match kind {
ty::Tuple(fields) => {
let Some(f_ty) = fields.get(f.as_usize()) else {
Expand Down
Loading
Loading