Skip to content

Remove PointerLike trait #143308

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 1 addition & 11 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use rustc_macros::HashStable_Generic;

use crate::{
AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, Variants,
PointeeInfo, Primitive, Size, Variants,
};

// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
Expand Down Expand Up @@ -115,16 +115,6 @@ impl<'a> Layout<'a> {
pub fn unadjusted_abi_align(self) -> Align {
self.0.0.unadjusted_abi_align
}

/// Whether the layout is from a type that implements [`std::marker::PointerLike`].
///
/// Currently, that means that the type is pointer-sized, pointer-aligned,
/// and has a initialized (non-union), scalar ABI.
pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
self.size() == data_layout.pointer_size
&& self.align().abi == data_layout.pointer_align.abi
&& matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
}
}

/// The layout of a type, alongside the type itself.
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,6 @@ language_item_table! {
TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
TryTraitFromYeet, sym::from_yeet, from_yeet_fn, Target::Fn, GenericRequirement::None;

PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);

CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0);

ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
Expand Down
99 changes: 0 additions & 99 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ pub(super) fn check_trait<'tcx>(
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
checker.check(
lang_items.coerce_pointee_validated_trait(),
visit_implementation_of_coerce_pointee_validity,
Expand Down Expand Up @@ -707,104 +706,6 @@ fn infringing_fields_error<'tcx>(
err.emit()
}

fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
let impl_span = tcx.def_span(checker.impl_def_id);
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();

let is_permitted_primitive = match *self_ty.kind() {
ty::Adt(def, _) => def.is_box(),
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
_ => false,
};

if is_permitted_primitive
&& let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
return Ok(());
}

let why_disqualified = match *self_ty.kind() {
// If an ADT is repr(transparent)
ty::Adt(self_ty_def, args) => {
if self_ty_def.repr().transparent() {
// FIXME(compiler-errors): This should and could be deduplicated into a query.
// Find the nontrivial field.
let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, self_ty_def.did());
let nontrivial_field = self_ty_def.all_fields().find(|field_def| {
let field_ty = tcx.type_of(field_def.did).instantiate_identity();
!tcx.layout_of(adt_typing_env.as_query_input(field_ty))
.is_ok_and(|layout| layout.layout.is_1zst())
});

if let Some(nontrivial_field) = nontrivial_field {
// Check that the nontrivial field implements `PointerLike`.
let nontrivial_field_ty = nontrivial_field.ty(tcx, args);
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
let ocx = ObligationCtxt::new(&infcx);
ocx.register_bound(
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field_ty,
tcx.require_lang_item(LangItem::PointerLike, impl_span),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
return Ok(());
} else {
format!(
"the field `{field_name}` of {descr} `{self_ty}` \
does not implement `PointerLike`",
field_name = nontrivial_field.name,
descr = self_ty_def.descr()
)
}
} else {
format!(
"the {descr} `{self_ty}` is `repr(transparent)`, \
but does not have a non-trivial field (it is zero-sized)",
descr = self_ty_def.descr()
)
}
} else if self_ty_def.is_box() {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this box is not a thin pointer.

String::from("boxes of dynamically-sized types are too large to be `PointerLike`")
} else {
format!(
"the {descr} `{self_ty}` is not `repr(transparent)`",
descr = self_ty_def.descr()
)
}
}
ty::Ref(..) => {
// If we got here, then the `layout.is_pointer_like()` check failed
// and this reference is not a thin pointer.
String::from("references to dynamically-sized types are too large to be `PointerLike`")
}
ty::Dynamic(..) | ty::Foreign(..) => {
String::from("types of dynamic or unknown size may not implement `PointerLike`")
}
_ => {
// This is a white lie; it is true everywhere outside the standard library.
format!("only user-defined sized types are eligible for `impl PointerLike`")
}
};

Err(tcx
.dcx()
.struct_span_err(
impl_span,
"implementation must be applied to type that has the same ABI as a pointer, \
or is `repr(transparent)` and whose field is `PointerLike`",
)
.with_note(why_disqualified)
.emit())
}

fn visit_implementation_of_coerce_pointee_validity(
checker: &Checker<'_>,
) -> Result<(), ErrorGuaranteed> {
Expand Down
14 changes: 9 additions & 5 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1149,12 +1149,16 @@ impl<'tcx> TypingEnv<'tcx> {
{
// FIXME(#132279): We should assert that the value does not contain any placeholders
// as these placeholders are also local to the current inference context. However, we
// currently use pseudo-canonical queries in the trait solver which replaces params with
// placeholders. We should also simply not use pseudo-canonical queries in the trait
// solver, at which point we can readd this assert. As of writing this comment, this is
// only used by `fn layout_is_pointer_like` when calling `layout_of`.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't true :)

// currently use pseudo-canonical queries in the trait solver, which replaces params
// with placeholders during canonicalization. We should also simply not use pseudo-
// canonical queries in the trait solver, at which point we can readd this assert.
//
// debug_assert!(!value.has_placeholders());
// As of writing this comment, this is only used when normalizing consts that mention
// params.
/* debug_assert!(
!value.has_placeholders(),
"{value:?} which has placeholder shouldn't be pseudo-canonicalized"
); */
PseudoCanonicalInput { typing_env: self, value }
}
}
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,6 @@ symbols! {
pointee_sized,
pointee_trait,
pointer,
pointer_like,
poll,
poll_next,
position,
Expand Down
79 changes: 1 addition & 78 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
use rustc_middle::ty::{
self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
};
use rustc_middle::ty::{self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast};
use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId;
use thin_vec::thin_vec;
Expand Down Expand Up @@ -1147,38 +1145,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
));

// Require that all AFIT will return something that can be coerced into `dyn*`
// -- a shim will be responsible for doing the actual coercion to `dyn*`.
if let Some(principal) = data.principal() {
for supertrait in
elaborate::supertraits(tcx, principal.with_self_ty(tcx, source))
{
if tcx.is_trait_alias(supertrait.def_id()) {
continue;
}

for &assoc_item in tcx.associated_item_def_ids(supertrait.def_id()) {
if !tcx.is_impl_trait_in_trait(assoc_item) {
continue;
}

// RPITITs with `Self: Sized` don't need to be checked.
if tcx.generics_require_sized_self(assoc_item) {
continue;
}

let pointer_like_goal = pointer_like_goal_for_rpitit(
tcx,
supertrait,
assoc_item,
&obligation.cause,
);

nested.push(predicate_to_obligation(pointer_like_goal.upcast(tcx)));
}
}
}

ImplSource::Builtin(BuiltinImplSource::Misc, nested)
}

Expand Down Expand Up @@ -1344,46 +1310,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
}
}

/// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
/// implements the `PointerLike` trait, which is a requirement for the RPITIT to be
/// coercible to `dyn* Future`, which is itself a requirement for the RPITIT's parent
/// trait to be coercible to `dyn Trait`.
///
/// We do this given a supertrait's substitutions, and then augment the substitutions
/// with bound variables to compute the goal universally. Given that `PointerLike` has
/// no region requirements (at least for the built-in pointer types), this shouldn't
/// *really* matter, but it is the best choice for soundness.
fn pointer_like_goal_for_rpitit<'tcx>(
tcx: TyCtxt<'tcx>,
supertrait: ty::PolyTraitRef<'tcx>,
rpitit_item: DefId,
cause: &ObligationCause<'tcx>,
) -> ty::PolyTraitRef<'tcx> {
let mut bound_vars = supertrait.bound_vars().to_vec();

let args = supertrait.skip_binder().args.extend_to(tcx, rpitit_item, |arg, _| match arg.kind {
ty::GenericParamDefKind::Lifetime => {
let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id));
bound_vars.push(ty::BoundVariableKind::Region(kind));
ty::Region::new_bound(
tcx,
ty::INNERMOST,
ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind },
)
.into()
}
ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => {
unreachable!()
}
});

ty::Binder::bind_with_vars(
ty::TraitRef::new(
tcx,
tcx.require_lang_item(LangItem::PointerLike, cause.span),
[Ty::new_projection_from_args(tcx, rpitit_item, args)],
),
tcx.mk_bound_variable_kinds(&bound_vars),
)
}
5 changes: 1 addition & 4 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ use core::error::{self, Error};
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
use core::marker::{PointerLike, Tuple, Unsize};
use core::marker::{Tuple, Unsize};
use core::mem::{self, SizedTypeProperties};
use core::ops::{
AsyncFn, AsyncFnMut, AsyncFnOnce, CoerceUnsized, Coroutine, CoroutineState, Deref, DerefMut,
Expand Down Expand Up @@ -2132,6 +2132,3 @@ impl<E: Error> Error for Box<E> {
Error::provide(&**self, request);
}
}

#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T> PointerLike for Box<T> {}
1 change: 0 additions & 1 deletion library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@
#![feature(panic_internals)]
#![feature(pattern)]
#![feature(pin_coerce_unsized_trait)]
#![feature(pointer_like_trait)]
#![feature(ptr_alignment_type)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
Expand Down
11 changes: 1 addition & 10 deletions library/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@

use crate::cmp::Ordering;
use crate::fmt::{self, Debug, Display};
use crate::marker::{PhantomData, PointerLike, Unsize};
use crate::marker::{PhantomData, Unsize};
use crate::mem;
use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn};
use crate::panic::const_panic;
Expand Down Expand Up @@ -669,9 +669,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}

#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for Cell<T> {}

impl<T> Cell<[T]> {
/// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
///
Expand Down Expand Up @@ -2361,9 +2358,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}

#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for UnsafeCell<T> {}

/// [`UnsafeCell`], but [`Sync`].
///
/// This is just an `UnsafeCell`, except it implements `Sync`
Expand Down Expand Up @@ -2470,9 +2464,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell
//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}

#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T: PointerLike> PointerLike for SyncUnsafeCell<T> {}

#[allow(unused)]
fn assert_coerce_unsized(
a: UnsafeCell<&i32>,
Expand Down
31 changes: 0 additions & 31 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,37 +1066,6 @@ pub trait Destruct {}
#[rustc_do_not_implement_via_object]
pub trait Tuple {}

/// A marker for pointer-like types.
///
/// This trait can only be implemented for types that are certain to have
/// the same size and alignment as a [`usize`] or [`*const ()`](pointer).
/// To ensure this, there are special requirements on implementations
/// of `PointerLike` (other than the already-provided implementations
/// for built-in types):
///
/// * The type must have `#[repr(transparent)]`.
/// * The type’s sole non-zero-sized field must itself implement `PointerLike`.
#[unstable(feature = "pointer_like_trait", issue = "none")]
#[lang = "pointer_like"]
#[diagnostic::on_unimplemented(
message = "`{Self}` needs to have the same ABI as a pointer",
label = "`{Self}` needs to be a pointer-like type"
)]
#[rustc_do_not_implement_via_object]
pub trait PointerLike {}

marker_impls! {
#[unstable(feature = "pointer_like_trait", issue = "none")]
PointerLike for
isize,
usize,
{T} &T,
{T} &mut T,
{T} *const T,
{T} *mut T,
{T: PointerLike} crate::pin::Pin<T>,
}

/// A marker for types which can be used as types of `const` generic parameters.
///
/// These types must have a proper equivalence relation (`Eq`) and it must be automatically
Expand Down
6 changes: 1 addition & 5 deletions library/core/src/pin/unsafe_pinned.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::cell::UnsafeCell;
use crate::marker::{PointerLike, Unpin};
use crate::marker::Unpin;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::pin::Pin;
use crate::{fmt, ptr};
Expand Down Expand Up @@ -178,8 +178,4 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T>
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}

#[unstable(feature = "pointer_like_trait", issue = "none")]
// #[unstable(feature = "unsafe_pinned", issue = "125735")]
impl<T: PointerLike> PointerLike for UnsafePinned<T> {}

// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?
Loading
Loading