mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-21 14:23:45 +00:00
Rollup merge of #133226 - compiler-errors:opt-in-pointer-like, r=lcnr
Make `PointerLike` opt-in instead of built-in The `PointerLike` trait currently is a built-in trait that computes the layout of the type. This is a bit problematic, because types implement this trait automatically. Since this can be broken due to semver-compatible changes to a type's layout, this is undesirable. Also, calling `layout_of` in the trait system also causes cycles. This PR makes the trait implemented via regular impls, and adds additional validation on top to make sure that those impls are valid. This could eventually be `derive()`d for custom smart pointers, and we can trust *that* as a semver promise rather than risking library authors accidentally breaking it. On the other hand, we may never expose `PointerLike`, but at least now the implementation doesn't invoke `layout_of` which could cause ICEs or cause cycles. Right now for a `PointerLike` impl to be valid, it must be an ADT that is `repr(transparent)` and the non-1zst field needs to implement `PointerLike`. There are also some primitive impls for `&T`/ `&mut T`/`*const T`/`*mut T`/`Box<T>`.
This commit is contained in:
commit
fbed195b4d
@ -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
|
||||||
checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized),
|
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?;
|
||||||
);
|
checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?;
|
||||||
res.and(
|
Ok(())
|
||||||
checker
|
|
||||||
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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())
|
||||||
|
}
|
||||||
|
@ -602,19 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
|||||||
self.coroutine_is_async_gen(coroutine_def_id)
|
self.coroutine_is_async_gen(coroutine_def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't use `TypingEnv` here as it's only defined in `rustc_middle` and
|
|
||||||
// `rustc_next_trait_solver` shouldn't have to know about it.
|
|
||||||
fn layout_is_pointer_like(
|
|
||||||
self,
|
|
||||||
typing_mode: ty::TypingMode<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
let typing_env = ty::TypingEnv { typing_mode, param_env };
|
|
||||||
self.layout_of(self.erase_regions(typing_env).as_query_input(self.erase_regions(ty)))
|
|
||||||
.is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout))
|
|
||||||
}
|
|
||||||
|
|
||||||
type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
|
type UnsizingParams = &'tcx rustc_index::bit_set::BitSet<u32>;
|
||||||
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
|
fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams {
|
||||||
self.unsizing_params_for_adt(adt_def_id)
|
self.unsizing_params_for_adt(adt_def_id)
|
||||||
@ -688,7 +675,6 @@ bidirectional_lang_item_map! {
|
|||||||
Metadata,
|
Metadata,
|
||||||
Option,
|
Option,
|
||||||
PointeeTrait,
|
PointeeTrait,
|
||||||
PointerLike,
|
|
||||||
Poll,
|
Poll,
|
||||||
Sized,
|
Sized,
|
||||||
TransmuteTrait,
|
TransmuteTrait,
|
||||||
|
@ -159,13 +159,6 @@ where
|
|||||||
goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
) -> Result<Candidate<I>, NoSolution>;
|
) -> Result<Candidate<I>, NoSolution>;
|
||||||
|
|
||||||
/// A type is `PointerLike` if we can compute its layout, and that layout
|
|
||||||
/// matches the layout of `usize`.
|
|
||||||
fn consider_builtin_pointer_like_candidate(
|
|
||||||
ecx: &mut EvalCtxt<'_, D>,
|
|
||||||
goal: Goal<I, Self>,
|
|
||||||
) -> Result<Candidate<I>, NoSolution>;
|
|
||||||
|
|
||||||
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
/// A type is a `FnPtr` if it is of `FnPtr` type.
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, D>,
|
ecx: &mut EvalCtxt<'_, D>,
|
||||||
@ -449,9 +442,6 @@ where
|
|||||||
ty::ClosureKind::FnOnce,
|
ty::ClosureKind::FnOnce,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Some(TraitSolverLangItem::PointerLike) => {
|
|
||||||
G::consider_builtin_pointer_like_candidate(self, goal)
|
|
||||||
}
|
|
||||||
Some(TraitSolverLangItem::FnPtrTrait) => {
|
Some(TraitSolverLangItem::FnPtrTrait) => {
|
||||||
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
|
G::consider_builtin_fn_ptr_trait_candidate(self, goal)
|
||||||
}
|
}
|
||||||
|
@ -210,13 +210,6 @@ where
|
|||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_pointer_like_candidate(
|
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
|
||||||
_goal: Goal<I, Self>,
|
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
|
||||||
unreachable!("PointerLike is not const")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
_ecx: &mut EvalCtxt<'_, D>,
|
||||||
_goal: Goal<I, Self>,
|
_goal: Goal<I, Self>,
|
||||||
|
@ -363,13 +363,6 @@ where
|
|||||||
panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_pointer_like_candidate(
|
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
|
||||||
goal: Goal<I, Self>,
|
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
|
||||||
panic!("`PointerLike` does not have an associated type: {:?}", goal);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
_ecx: &mut EvalCtxt<'_, D>,
|
_ecx: &mut EvalCtxt<'_, D>,
|
||||||
goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
|
@ -248,32 +248,6 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_builtin_pointer_like_candidate(
|
|
||||||
ecx: &mut EvalCtxt<'_, D>,
|
|
||||||
goal: Goal<I, Self>,
|
|
||||||
) -> Result<Candidate<I>, NoSolution> {
|
|
||||||
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
|
|
||||||
return Err(NoSolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
let cx = ecx.cx();
|
|
||||||
// But if there are inference variables, we have to wait until it's resolved.
|
|
||||||
if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() {
|
|
||||||
return ecx.forced_ambiguity(MaybeCause::Ambiguity);
|
|
||||||
}
|
|
||||||
|
|
||||||
if cx.layout_is_pointer_like(
|
|
||||||
ecx.typing_mode(goal.param_env),
|
|
||||||
goal.param_env,
|
|
||||||
goal.predicate.self_ty(),
|
|
||||||
) {
|
|
||||||
ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc)
|
|
||||||
.enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes))
|
|
||||||
} else {
|
|
||||||
Err(NoSolution)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn consider_builtin_fn_ptr_trait_candidate(
|
fn consider_builtin_fn_ptr_trait_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, D>,
|
ecx: &mut EvalCtxt<'_, D>,
|
||||||
goal: Goal<I, Self>,
|
goal: Goal<I, Self>,
|
||||||
|
@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
|
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Tuple) {
|
} else if tcx.is_lang_item(def_id, LangItem::Tuple) {
|
||||||
self.assemble_candidate_for_tuple(obligation, &mut candidates);
|
self.assemble_candidate_for_tuple(obligation, &mut candidates);
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::PointerLike) {
|
|
||||||
self.assemble_candidate_for_pointer_like(obligation, &mut candidates);
|
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
|
} else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
|
||||||
self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
|
self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
|
||||||
} else {
|
} else {
|
||||||
@ -1216,35 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assemble_candidate_for_pointer_like(
|
|
||||||
&mut self,
|
|
||||||
obligation: &PolyTraitObligation<'tcx>,
|
|
||||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
|
||||||
) {
|
|
||||||
// The regions of a type don't affect the size of the type
|
|
||||||
let tcx = self.tcx();
|
|
||||||
let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty());
|
|
||||||
|
|
||||||
// But if there are inference variables, we have to wait until it's resolved.
|
|
||||||
if (obligation.param_env, self_ty).has_non_region_infer() {
|
|
||||||
candidates.ambiguous = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should erase regions from both the param-env and type, since both
|
|
||||||
// may have infer regions. Specifically, after canonicalizing and instantiating,
|
|
||||||
// early bound regions turn into region vars in both the new and old solver.
|
|
||||||
let key = self.infcx.pseudo_canonicalize_query(
|
|
||||||
tcx.erase_regions(obligation.param_env),
|
|
||||||
tcx.erase_regions(self_ty),
|
|
||||||
);
|
|
||||||
if let Ok(layout) = tcx.layout_of(key)
|
|
||||||
&& layout.layout.is_pointer_like(&tcx.data_layout)
|
|
||||||
{
|
|
||||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assemble_candidates_for_fn_ptr_trait(
|
fn assemble_candidates_for_fn_ptr_trait(
|
||||||
&mut self,
|
&mut self,
|
||||||
obligation: &PolyTraitObligation<'tcx>,
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
@ -13,7 +13,7 @@ use crate::lang_items::TraitSolverLangItem;
|
|||||||
use crate::relate::Relate;
|
use crate::relate::Relate;
|
||||||
use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
|
use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{self as ty, TypingMode, search_graph};
|
use crate::{self as ty, search_graph};
|
||||||
|
|
||||||
pub trait Interner:
|
pub trait Interner:
|
||||||
Sized
|
Sized
|
||||||
@ -278,13 +278,6 @@ pub trait Interner:
|
|||||||
fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
||||||
fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool;
|
||||||
|
|
||||||
fn layout_is_pointer_like(
|
|
||||||
self,
|
|
||||||
typing_mode: TypingMode<Self>,
|
|
||||||
param_env: Self::ParamEnv,
|
|
||||||
ty: Self::Ty,
|
|
||||||
) -> bool;
|
|
||||||
|
|
||||||
type UnsizingParams: Deref<Target = BitSet<u32>>;
|
type UnsizingParams: Deref<Target = BitSet<u32>>;
|
||||||
fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
|
fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams;
|
||||||
|
|
||||||
|
@ -31,7 +31,6 @@ pub enum TraitSolverLangItem {
|
|||||||
Metadata,
|
Metadata,
|
||||||
Option,
|
Option,
|
||||||
PointeeTrait,
|
PointeeTrait,
|
||||||
PointerLike,
|
|
||||||
Poll,
|
Poll,
|
||||||
Sized,
|
Sized,
|
||||||
TransmuteTrait,
|
TransmuteTrait,
|
||||||
|
@ -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> {}
|
||||||
|
@ -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)]
|
||||||
|
@ -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
|
||||||
|
@ -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)));
|
|
||||||
}
|
|
@ -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() {}
|
|
9
tests/ui/dyn-star/async-block-dyn-star.rs
Normal file
9
tests/ui/dyn-star/async-block-dyn-star.rs
Normal 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() {}
|
20
tests/ui/dyn-star/async-block-dyn-star.stderr
Normal file
20
tests/ui/dyn-star/async-block-dyn-star.stderr
Normal 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`.
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
@ -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 {}
|
||||||
|
|
||||||
|
@ -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() {}
|
||||||
|
@ -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
|
||||||
|
16
tests/ui/dyn-star/float-as-dyn-star.rs
Normal file
16
tests/ui/dyn-star/float-as-dyn-star.rs
Normal 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());
|
||||||
|
}
|
21
tests/ui/dyn-star/float-as-dyn-star.stderr
Normal file
21
tests/ui/dyn-star/float-as-dyn-star.stderr
Normal 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`.
|
@ -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`.
|
||||||
|
Loading…
Reference in New Issue
Block a user