Make PointerLike opt-in as a trait

This commit is contained in:
Michael Goulet 2024-11-20 02:46:56 +00:00
parent 06e66d78c3
commit 228068bc6e
17 changed files with 194 additions and 52 deletions

View File

@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>(
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let lang_items = tcx.lang_items(); let lang_items = tcx.lang_items();
let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { checker.check(lang_items.const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
})); })?;
res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
})); })?;
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
res = res.and(
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
);
res.and(
checker checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
) checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
Ok(())
} }
struct Checker<'tcx> { struct Checker<'tcx> {
@ -663,3 +660,63 @@ fn infringing_fields_error<'tcx>(
err.emit() 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();
// If an ADT is repr(transparent)...
if let ty::Adt(def, args) = *self_ty.kind()
&& 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, def.did());
let nontrivial_field = 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 = 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,
tcx.lang_items().pointer_like().unwrap(),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
return Ok(());
}
}
}
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(());
}
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`",
)
.emit())
}

View File

@ -191,6 +191,8 @@ use core::error::{self, Error};
use core::fmt; use core::fmt;
use core::future::Future; use core::future::Future;
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
#[cfg(not(bootstrap))]
use core::marker::PointerLike;
use core::marker::{Tuple, Unsize}; use core::marker::{Tuple, Unsize};
use core::mem::{self, SizedTypeProperties}; use core::mem::{self, SizedTypeProperties};
use core::ops::{ use core::ops::{
@ -2131,3 +2133,7 @@ impl<E: Error> Error for Box<E> {
Error::provide(&**self, request); Error::provide(&**self, request);
} }
} }
#[cfg(not(bootstrap))]
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T> PointerLike for Box<T> {}

View File

@ -136,6 +136,7 @@
#![feature(panic_internals)] #![feature(panic_internals)]
#![feature(pattern)] #![feature(pattern)]
#![feature(pin_coerce_unsized_trait)] #![feature(pin_coerce_unsized_trait)]
#![feature(pointer_like_trait)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
#![feature(ptr_metadata)] #![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)] #![feature(ptr_sub_ptr)]

View File

@ -981,6 +981,18 @@ pub trait Tuple {}
)] )]
pub trait PointerLike {} pub trait PointerLike {}
#[cfg(not(bootstrap))]
marker_impls! {
#[unstable(feature = "pointer_like_trait", issue = "none")]
PointerLike for
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. /// 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 /// These types must have a proper equivalence relation (`Eq`) and it must be automatically

View File

@ -1,16 +0,0 @@
//@ known-bug: #113280
//@ only-x86_64
#![feature(dyn_star, pointer_like_trait)]
#![allow(incomplete_features)]
use std::fmt::Debug;
use std::marker::PointerLike;
fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
f32::from_bits(0x1) as f64
}
fn main() {
println!("{:?}", make_dyn_star(Box::new(1i32)));
}

View File

@ -1,8 +0,0 @@
//@ known-bug: #127676
//@ edition:2018
#![feature(dyn_star,const_async_blocks)]
static S: dyn* Send + Sync = async { 42 };
pub fn main() {}

View File

@ -0,0 +1,9 @@
//@ edition:2018
#![feature(dyn_star, const_async_blocks)]
//~^ WARN the feature `dyn_star` is incomplete
static S: dyn* Send + Sync = async { 42 };
//~^ needs to have the same ABI as a pointer
pub fn main() {}

View File

@ -0,0 +1,20 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/async-block-dyn-star.rs:3:12
|
LL | #![feature(dyn_star, const_async_blocks)]
| ^^^^^^^^
|
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer
--> $DIR/async-block-dyn-star.rs:6:30
|
LL | static S: dyn* Send + Sync = async { 42 };
| ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type
|
= help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}`
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -1,14 +1,17 @@
error[E0277]: `&T` needs to have the same ABI as a pointer error[E0277]: `&T` needs to have the same ABI as a pointer
--> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
| |
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
| - this type parameter needs to be `Sized`
LL | dyn_debug(t); LL | dyn_debug(t);
| ^ `&T` needs to be a pointer-like type | ^ `&T` needs to be a pointer-like type
| |
= help: the trait `PointerLike` is not implemented for `&T` = note: required for `&T` to implement `PointerLike`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
LL + fn polymorphic<T: Debug>(t: &T) {
| |
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
| +++++++++++++++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -1,14 +1,17 @@
error[E0277]: `&T` needs to have the same ABI as a pointer error[E0277]: `&T` needs to have the same ABI as a pointer
--> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
| |
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
| - this type parameter needs to be `Sized`
LL | dyn_debug(t); LL | dyn_debug(t);
| ^ `&T` needs to be a pointer-like type | ^ `&T` needs to be a pointer-like type
| |
= help: the trait `PointerLike` is not implemented for `&T` = note: required for `&T` to implement `PointerLike`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
LL + fn polymorphic<T: Debug>(t: &T) {
| |
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
| +++++++++++++++++++++
error: aborting due to 1 previous error error: aborting due to 1 previous error

View File

@ -1,13 +1,18 @@
//@ run-pass //@ run-pass
//@ check-run-results //@ check-run-results
#![feature(dyn_star)] #![feature(dyn_star, pointer_like_trait)]
#![allow(incomplete_features)] #![allow(incomplete_features)]
use std::fmt::Debug; use std::fmt::Debug;
use std::marker::PointerLike;
#[derive(Debug)] #[derive(Debug)]
#[repr(transparent)]
struct Foo(#[allow(dead_code)] usize); struct Foo(#[allow(dead_code)] usize);
// FIXME(dyn_star): Make this into a derive.
impl PointerLike for Foo {}
impl Drop for Foo { impl Drop for Foo {
fn drop(&mut self) { fn drop(&mut self) {
println!("destructor called"); println!("destructor called");

View File

@ -3,13 +3,18 @@
// This used to ICE, because the compiler confused a pointer-like to dyn* coercion // This used to ICE, because the compiler confused a pointer-like to dyn* coercion
// with a c-like enum to integer cast. // with a c-like enum to integer cast.
#![feature(dyn_star)] #![feature(dyn_star, pointer_like_trait)]
#![expect(incomplete_features)] #![expect(incomplete_features)]
use std::marker::PointerLike;
#[repr(transparent)]
enum E { enum E {
Num(usize), Num(usize),
} }
impl PointerLike for E {}
trait Trait {} trait Trait {}
impl Trait for E {} impl Trait for E {}

View File

@ -7,7 +7,7 @@ trait Foo {}
fn make_dyn_star() { fn make_dyn_star() {
let i = 42; let i = 42;
let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied
} }
fn main() {} fn main() {}

View File

@ -1,8 +1,8 @@
error[E0277]: the trait bound `{integer}: Foo` is not satisfied error[E0277]: the trait bound `usize: Foo` is not satisfied
--> $DIR/error.rs:10:27 --> $DIR/error.rs:10:27
| |
LL | let dyn_i: dyn* Foo = i; LL | let dyn_i: dyn* Foo = i;
| ^ the trait `Foo` is not implemented for `{integer}` | ^ the trait `Foo` is not implemented for `usize`
| |
help: this trait has no implementations, consider adding one help: this trait has no implementations, consider adding one
--> $DIR/error.rs:6:1 --> $DIR/error.rs:6:1

View File

@ -0,0 +1,16 @@
//@ only-x86_64
#![feature(dyn_star, pointer_like_trait)]
//~^ WARN the feature `dyn_star` is incomplete
use std::fmt::Debug;
use std::marker::PointerLike;
fn make_dyn_star() -> dyn* Debug + 'static {
f32::from_bits(0x1) as f64
//~^ ERROR `f64` needs to have the same ABI as a pointer
}
fn main() {
println!("{:?}", make_dyn_star());
}

View File

@ -0,0 +1,21 @@
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/float-as-dyn-star.rs:3:12
|
LL | #![feature(dyn_star, pointer_like_trait)]
| ^^^^^^^^
|
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: `f64` needs to have the same ABI as a pointer
--> $DIR/float-as-dyn-star.rs:10:5
|
LL | f32::from_bits(0x1) as f64
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type
|
= help: the trait `PointerLike` is not implemented for `f64`
= help: the trait `PointerLike` is implemented for `usize`
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.

View File

@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)]
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information = note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error[E0277]: `W` needs to have the same ABI as a pointer
--> $DIR/upcast.rs:28:23
|
LL | let w: dyn* Foo = W(0);
| ^^^^ `W` needs to be a pointer-like type
|
= help: the trait `PointerLike` is not implemented for `W`
error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
--> $DIR/upcast.rs:30:23 --> $DIR/upcast.rs:30:23
| |
@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w;
| |
= help: the trait `PointerLike` is not implemented for `dyn* Foo` = help: the trait `PointerLike` is not implemented for `dyn* Foo`
error: aborting due to 1 previous error; 1 warning emitted error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0277`.