Skip to content

Commit

Permalink
Make PointerLike opt-in as a trait
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Nov 20, 2024
1 parent 1c17ee2 commit ccfe08a
Show file tree
Hide file tree
Showing 17 changed files with 198 additions and 54 deletions.
91 changes: 75 additions & 16 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,23 @@ pub(super) fn check_trait<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let lang_items = tcx.lang_items();
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);
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
}));
res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
}));

res = res.and(
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
);
res.and(
checker
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
)
(|| {
checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
checker.check(lang_items.const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
})?;
checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
})?;
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)?;
Ok(())
})()
}

struct Checker<'tcx> {
Expand Down Expand Up @@ -663,3 +664,61 @@ 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();

// If an ADT is repr(transparent)...
if let ty::Adt(def, args) = *self_ty.kind()
&& def.repr().transparent()
{
// 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(),
);
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())
}
6 changes: 6 additions & 0 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ use core::error::{self, Error};
use core::fmt;
use core::future::Future;
use core::hash::{Hash, Hasher};
#[cfg(not(bootstrap))]
use core::marker::PointerLike;
use core::marker::{Tuple, Unsize};
use core::mem::{self, SizedTypeProperties};
use core::ops::{
Expand Down Expand Up @@ -2129,3 +2131,7 @@ impl<E: Error> Error for Box<E> {
Error::provide(&**self, request);
}
}

#[cfg(not(bootstrap))]
#[unstable(feature = "pointer_like_trait", issue = "none")]
impl<T> PointerLike for Box<T> {}
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@
#![feature(panic_internals)]
#![feature(pattern)]
#![feature(pin_coerce_unsized_trait)]
#![feature(pointer_like_trait)]
#![feature(ptr_internals)]
#![feature(ptr_metadata)]
#![feature(ptr_sub_ptr)]
Expand Down
12 changes: 12 additions & 0 deletions library/core/src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,18 @@ pub trait Tuple {}
)]
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.
///
/// These types must have a proper equivalence relation (`Eq`) and it must be automatically
Expand Down
16 changes: 0 additions & 16 deletions tests/crashes/113280.rs

This file was deleted.

8 changes: 0 additions & 8 deletions tests/crashes/127676.rs

This file was deleted.

9 changes: 9 additions & 0 deletions tests/ui/dyn-star/async-block-dyn-star.rs
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions tests/ui/dyn-star/async-block-dyn-star.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
error[E0277]: `&T` needs to have the same ABI as a pointer
--> $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);
| ^ `&T` needs to be a pointer-like type
|
= help: the trait `PointerLike` is not implemented for `&T`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
= note: required for `&T` to implement `PointerLike`
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

Expand Down
11 changes: 7 additions & 4 deletions tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
error[E0277]: `&T` needs to have the same ABI as a pointer
--> $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);
| ^ `&T` needs to be a pointer-like type
|
= help: the trait `PointerLike` is not implemented for `&T`
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
= note: required for `&T` to implement `PointerLike`
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

Expand Down
7 changes: 6 additions & 1 deletion tests/ui/dyn-star/drop.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
//@ run-pass
//@ check-run-results
#![feature(dyn_star)]
#![feature(dyn_star, pointer_like_trait)]
#![allow(incomplete_features)]

use std::fmt::Debug;
use std::marker::PointerLike;

#[derive(Debug)]
#[repr(transparent)]
struct Foo(#[allow(dead_code)] usize);

// FIXME(dyn_star): Make this into a derive.
impl PointerLike for Foo {}

impl Drop for Foo {
fn drop(&mut self) {
println!("destructor called");
Expand Down
7 changes: 6 additions & 1 deletion tests/ui/dyn-star/enum-cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
// This used to ICE, because the compiler confused a pointer-like to dyn* coercion
// with a c-like enum to integer cast.

#![feature(dyn_star)]
#![feature(dyn_star, pointer_like_trait)]
#![expect(incomplete_features)]

use std::marker::PointerLike;

#[repr(transparent)]
enum E {
Num(usize),
}

impl PointerLike for E {}

trait Trait {}
impl Trait for E {}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/dyn-star/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ trait Foo {}

fn make_dyn_star() {
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() {}
4 changes: 2 additions & 2 deletions tests/ui/dyn-star/error.stderr
Original file line number Diff line number Diff line change
@@ -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
|
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
--> $DIR/error.rs:6:1
Expand Down
16 changes: 16 additions & 0 deletions tests/ui/dyn-star/float-as-dyn-star.rs
Original file line number Diff line number Diff line change
@@ -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());
}
21 changes: 21 additions & 0 deletions tests/ui/dyn-star/float-as-dyn-star.stderr
Original file line number Diff line number Diff line change
@@ -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`.
10 changes: 9 additions & 1 deletion tests/ui/dyn-star/upcast.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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: `#[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
--> $DIR/upcast.rs:30:23
|
Expand All @@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w;
|
= 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`.

0 comments on commit ccfe08a

Please sign in to comment.