Skip to content

Commit ccfe08a

Browse files
Make PointerLike opt-in as a trait
1 parent 1c17ee2 commit ccfe08a

17 files changed

+198
-54
lines changed

compiler/rustc_hir_analysis/src/coherence/builtin.rs

+75-16
Original file line numberDiff line numberDiff line change
@@ -37,22 +37,23 @@ pub(super) fn check_trait<'tcx>(
3737
) -> Result<(), ErrorGuaranteed> {
3838
let lang_items = tcx.lang_items();
3939
let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header };
40-
let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
41-
res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
42-
res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| {
43-
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
44-
}));
45-
res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
46-
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
47-
}));
48-
49-
res = res.and(
50-
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
51-
);
52-
res.and(
53-
checker
54-
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
55-
)
40+
(|| {
41+
checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?;
42+
checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?;
43+
checker.check(lang_items.const_param_ty_trait(), |checker| {
44+
visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy)
45+
})?;
46+
checker.check(lang_items.unsized_const_param_ty_trait(), |checker| {
47+
visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy)
48+
})?;
49+
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?;
50+
checker.check(
51+
lang_items.dispatch_from_dyn_trait(),
52+
visit_implementation_of_dispatch_from_dyn,
53+
)?;
54+
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
55+
Ok(())
56+
})()
5657
}
5758

5859
struct Checker<'tcx> {
@@ -663,3 +664,61 @@ fn infringing_fields_error<'tcx>(
663664

664665
err.emit()
665666
}
667+
668+
fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
669+
let tcx = checker.tcx;
670+
let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id);
671+
let impl_span = tcx.def_span(checker.impl_def_id);
672+
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
673+
674+
// If an ADT is repr(transparent)...
675+
if let ty::Adt(def, args) = *self_ty.kind()
676+
&& def.repr().transparent()
677+
{
678+
// Find the nontrivial field.
679+
let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did());
680+
let nontrivial_field = def.all_fields().find(|field_def| {
681+
let field_ty = tcx.type_of(field_def.did).instantiate_identity();
682+
!tcx.layout_of(adt_typing_env.as_query_input(field_ty))
683+
.is_ok_and(|layout| layout.layout.is_1zst())
684+
});
685+
686+
if let Some(nontrivial_field) = nontrivial_field {
687+
// Check that the nontrivial field implements `PointerLike`.
688+
let nontrivial_field = nontrivial_field.ty(tcx, args);
689+
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
690+
let ocx = ObligationCtxt::new(&infcx);
691+
ocx.register_bound(
692+
ObligationCause::misc(impl_span, checker.impl_def_id),
693+
param_env,
694+
nontrivial_field,
695+
tcx.lang_items().pointer_like().unwrap(),
696+
);
697+
if ocx.select_all_or_error().is_empty() {
698+
return Ok(());
699+
}
700+
}
701+
}
702+
703+
let is_permitted_primitive = match *self_ty.kind() {
704+
ty::Adt(def, _) => def.is_box(),
705+
ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true,
706+
_ => false,
707+
};
708+
709+
if is_permitted_primitive
710+
&& let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty))
711+
&& layout.layout.is_pointer_like(&tcx.data_layout)
712+
{
713+
return Ok(());
714+
}
715+
716+
Err(tcx
717+
.dcx()
718+
.struct_span_err(
719+
impl_span,
720+
"implementation must be applied to type that has the same ABI as a pointer, \
721+
or is `repr(transparent)` and whose field is `PointerLike`",
722+
)
723+
.emit())
724+
}

library/alloc/src/boxed.rs

+6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ use core::error::{self, Error};
191191
use core::fmt;
192192
use core::future::Future;
193193
use core::hash::{Hash, Hasher};
194+
#[cfg(not(bootstrap))]
195+
use core::marker::PointerLike;
194196
use core::marker::{Tuple, Unsize};
195197
use core::mem::{self, SizedTypeProperties};
196198
use core::ops::{
@@ -2129,3 +2131,7 @@ impl<E: Error> Error for Box<E> {
21292131
Error::provide(&**self, request);
21302132
}
21312133
}
2134+
2135+
#[cfg(not(bootstrap))]
2136+
#[unstable(feature = "pointer_like_trait", issue = "none")]
2137+
impl<T> PointerLike for Box<T> {}

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@
136136
#![feature(panic_internals)]
137137
#![feature(pattern)]
138138
#![feature(pin_coerce_unsized_trait)]
139+
#![feature(pointer_like_trait)]
139140
#![feature(ptr_internals)]
140141
#![feature(ptr_metadata)]
141142
#![feature(ptr_sub_ptr)]

library/core/src/marker.rs

+12
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,18 @@ pub trait Tuple {}
981981
)]
982982
pub trait PointerLike {}
983983

984+
#[cfg(not(bootstrap))]
985+
marker_impls! {
986+
#[unstable(feature = "pointer_like_trait", issue = "none")]
987+
PointerLike for
988+
usize,
989+
{T} &T,
990+
{T} &mut T,
991+
{T} *const T,
992+
{T} *mut T,
993+
{T: PointerLike} crate::pin::Pin<T>,
994+
}
995+
984996
/// A marker for types which can be used as types of `const` generic parameters.
985997
///
986998
/// These types must have a proper equivalence relation (`Eq`) and it must be automatically

tests/crashes/113280.rs

-16
This file was deleted.

tests/crashes/127676.rs

-8
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//@ edition:2018
2+
3+
#![feature(dyn_star, const_async_blocks)]
4+
//~^ WARN the feature `dyn_star` is incomplete
5+
6+
static S: dyn* Send + Sync = async { 42 };
7+
//~^ needs to have the same ABI as a pointer
8+
9+
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/async-block-dyn-star.rs:3:12
3+
|
4+
LL | #![feature(dyn_star, const_async_blocks)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer
11+
--> $DIR/async-block-dyn-star.rs:6:30
12+
|
13+
LL | static S: dyn* Send + Sync = async { 42 };
14+
| ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type
15+
|
16+
= help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}`
17+
18+
error: aborting due to 1 previous error; 1 warning emitted
19+
20+
For more information about this error, try `rustc --explain E0277`.

tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
error[E0277]: `&T` needs to have the same ABI as a pointer
22
--> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
33
|
4+
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
5+
| - this type parameter needs to be `Sized`
46
LL | dyn_debug(t);
57
| ^ `&T` needs to be a pointer-like type
68
|
7-
= help: the trait `PointerLike` is not implemented for `&T`
8-
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
9+
= note: required for `&T` to implement `PointerLike`
10+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
11+
|
12+
LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
13+
LL + fn polymorphic<T: Debug>(t: &T) {
914
|
10-
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
11-
| +++++++++++++++++++++
1215

1316
error: aborting due to 1 previous error
1417

tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
error[E0277]: `&T` needs to have the same ABI as a pointer
22
--> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15
33
|
4+
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) {
5+
| - this type parameter needs to be `Sized`
46
LL | dyn_debug(t);
57
| ^ `&T` needs to be a pointer-like type
68
|
7-
= help: the trait `PointerLike` is not implemented for `&T`
8-
help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
9+
= note: required for `&T` to implement `PointerLike`
10+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
11+
|
12+
LL - fn polymorphic<T: Debug + ?Sized>(t: &T) {
13+
LL + fn polymorphic<T: Debug>(t: &T) {
914
|
10-
LL | fn polymorphic<T: Debug + ?Sized>(t: &T) where &T: PointerLike {
11-
| +++++++++++++++++++++
1215

1316
error: aborting due to 1 previous error
1417

tests/ui/dyn-star/drop.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
//@ run-pass
22
//@ check-run-results
3-
#![feature(dyn_star)]
3+
#![feature(dyn_star, pointer_like_trait)]
44
#![allow(incomplete_features)]
55

66
use std::fmt::Debug;
7+
use std::marker::PointerLike;
78

89
#[derive(Debug)]
10+
#[repr(transparent)]
911
struct Foo(#[allow(dead_code)] usize);
1012

13+
// FIXME(dyn_star): Make this into a derive.
14+
impl PointerLike for Foo {}
15+
1116
impl Drop for Foo {
1217
fn drop(&mut self) {
1318
println!("destructor called");

tests/ui/dyn-star/enum-cast.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
// This used to ICE, because the compiler confused a pointer-like to dyn* coercion
44
// with a c-like enum to integer cast.
55

6-
#![feature(dyn_star)]
6+
#![feature(dyn_star, pointer_like_trait)]
77
#![expect(incomplete_features)]
88

9+
use std::marker::PointerLike;
10+
11+
#[repr(transparent)]
912
enum E {
1013
Num(usize),
1114
}
1215

16+
impl PointerLike for E {}
17+
1318
trait Trait {}
1419
impl Trait for E {}
1520

tests/ui/dyn-star/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ trait Foo {}
77

88
fn make_dyn_star() {
99
let i = 42;
10-
let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied
10+
let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied
1111
}
1212

1313
fn main() {}

tests/ui/dyn-star/error.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0277]: the trait bound `{integer}: Foo` is not satisfied
1+
error[E0277]: the trait bound `usize: Foo` is not satisfied
22
--> $DIR/error.rs:10:27
33
|
44
LL | let dyn_i: dyn* Foo = i;
5-
| ^ the trait `Foo` is not implemented for `{integer}`
5+
| ^ the trait `Foo` is not implemented for `usize`
66
|
77
help: this trait has no implementations, consider adding one
88
--> $DIR/error.rs:6:1
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//@ only-x86_64
2+
3+
#![feature(dyn_star, pointer_like_trait)]
4+
//~^ WARN the feature `dyn_star` is incomplete
5+
6+
use std::fmt::Debug;
7+
use std::marker::PointerLike;
8+
9+
fn make_dyn_star() -> dyn* Debug + 'static {
10+
f32::from_bits(0x1) as f64
11+
//~^ ERROR `f64` needs to have the same ABI as a pointer
12+
}
13+
14+
fn main() {
15+
println!("{:?}", make_dyn_star());
16+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
2+
--> $DIR/float-as-dyn-star.rs:3:12
3+
|
4+
LL | #![feature(dyn_star, pointer_like_trait)]
5+
| ^^^^^^^^
6+
|
7+
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
8+
= note: `#[warn(incomplete_features)]` on by default
9+
10+
error[E0277]: `f64` needs to have the same ABI as a pointer
11+
--> $DIR/float-as-dyn-star.rs:10:5
12+
|
13+
LL | f32::from_bits(0x1) as f64
14+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type
15+
|
16+
= help: the trait `PointerLike` is not implemented for `f64`
17+
= help: the trait `PointerLike` is implemented for `usize`
18+
19+
error: aborting due to 1 previous error; 1 warning emitted
20+
21+
For more information about this error, try `rustc --explain E0277`.

tests/ui/dyn-star/upcast.stderr

+9-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)]
77
= note: see issue #102425 <https://github.com/rust-lang/rust/issues/102425> for more information
88
= note: `#[warn(incomplete_features)]` on by default
99

10+
error[E0277]: `W` needs to have the same ABI as a pointer
11+
--> $DIR/upcast.rs:28:23
12+
|
13+
LL | let w: dyn* Foo = W(0);
14+
| ^^^^ `W` needs to be a pointer-like type
15+
|
16+
= help: the trait `PointerLike` is not implemented for `W`
17+
1018
error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer
1119
--> $DIR/upcast.rs:30:23
1220
|
@@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w;
1523
|
1624
= help: the trait `PointerLike` is not implemented for `dyn* Foo`
1725

18-
error: aborting due to 1 previous error; 1 warning emitted
26+
error: aborting due to 2 previous errors; 1 warning emitted
1927

2028
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)