Auto merge of #122045 - matthiaskrgr:rollup-5l3vpn7, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #121065 (Add basic i18n guidance for `Display`) - #121744 (Stop using Bubble in coherence and instead emulate it with an intercrate check) - #121829 (Dummy tweaks (attempt 2)) - #121857 (Implement async closure signature deduction) - #121894 (const_eval_select: make it safe but be careful with what we expose on stable for now) - #122014 (Change some attributes to only_local.) - #122016 (will_wake tests fail on Miri and that is expected) - #122018 (only set noalias on Box with the global allocator) - #122028 (Remove some dead code) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
b77e0184a9
44 changed files with 291 additions and 133 deletions
|
@ -1612,8 +1612,9 @@ pub enum PointerKind {
|
||||||
SharedRef { frozen: bool },
|
SharedRef { frozen: bool },
|
||||||
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
||||||
MutableRef { unpin: bool },
|
MutableRef { unpin: bool },
|
||||||
/// Box. `unpin` indicates the absence of any pinned data.
|
/// Box. `unpin` indicates the absence of any pinned data. `global` indicates whether this box
|
||||||
Box { unpin: bool },
|
/// uses the global allocator or a custom one.
|
||||||
|
Box { unpin: bool, global: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
/// Note that this information is advisory only, and backends are free to ignore it.
|
||||||
|
@ -1622,6 +1623,8 @@ pub enum PointerKind {
|
||||||
pub struct PointeeInfo {
|
pub struct PointeeInfo {
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub align: Align,
|
pub align: Align,
|
||||||
|
/// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
|
||||||
|
/// be reliable.
|
||||||
pub safe: Option<PointerKind>,
|
pub safe: Option<PointerKind>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1604,7 +1604,10 @@ pub fn noop_visit_capture_by<T: MutVisitor>(capture_by: &mut CaptureBy, vis: &mu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Some value for the AST node that is valid but possibly meaningless.
|
/// Some value for the AST node that is valid but possibly meaningless. Similar
|
||||||
|
/// to `Default` but not intended for wide use. The value will never be used
|
||||||
|
/// meaningfully, it exists just to support unwinding in `visit_clobber` in the
|
||||||
|
/// case where its closure panics.
|
||||||
pub trait DummyAstNode {
|
pub trait DummyAstNode {
|
||||||
fn dummy() -> Self;
|
fn dummy() -> Self;
|
||||||
}
|
}
|
||||||
|
@ -1679,19 +1682,6 @@ impl DummyAstNode for Stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DummyAstNode for Block {
|
|
||||||
fn dummy() -> Self {
|
|
||||||
Block {
|
|
||||||
stmts: Default::default(),
|
|
||||||
id: DUMMY_NODE_ID,
|
|
||||||
rules: BlockCheckMode::Default,
|
|
||||||
span: Default::default(),
|
|
||||||
tokens: Default::default(),
|
|
||||||
could_be_bare_literal: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DummyAstNode for Crate {
|
impl DummyAstNode for Crate {
|
||||||
fn dummy() -> Self {
|
fn dummy() -> Self {
|
||||||
Crate {
|
Crate {
|
||||||
|
|
|
@ -525,8 +525,11 @@ pub struct Unique<T: ?Sized> {
|
||||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||||
|
|
||||||
|
#[lang = "global_alloc_ty"]
|
||||||
|
pub struct Global;
|
||||||
|
|
||||||
#[lang = "owned_box"]
|
#[lang = "owned_box"]
|
||||||
pub struct Box<T: ?Sized, A = ()>(Unique<T>, A);
|
pub struct Box<T: ?Sized, A = Global>(Unique<T>, A);
|
||||||
|
|
||||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
||||||
|
|
||||||
|
@ -536,7 +539,7 @@ impl<T> Box<T> {
|
||||||
let size = intrinsics::size_of::<T>();
|
let size = intrinsics::size_of::<T>();
|
||||||
let ptr = libc::malloc(size);
|
let ptr = libc::malloc(size);
|
||||||
intrinsics::copy(&val as *const T as *const u8, ptr, size);
|
intrinsics::copy(&val as *const T as *const u8, ptr, size);
|
||||||
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, ())
|
Box(Unique { pointer: NonNull(ptr as *const T), _marker: PhantomData }, Global)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,10 +74,6 @@ fn unsize_ptr<'tcx>(
|
||||||
| (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
|
| (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
|
||||||
(src, unsized_info(fx, *a, *b, old_info))
|
(src, unsized_info(fx, *a, *b, old_info))
|
||||||
}
|
}
|
||||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
|
|
||||||
let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty());
|
|
||||||
(src, unsized_info(fx, a, b, old_info))
|
|
||||||
}
|
|
||||||
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
||||||
assert_eq!(def_a, def_b);
|
assert_eq!(def_a, def_b);
|
||||||
|
|
||||||
|
|
|
@ -472,6 +472,7 @@ pub trait Allocator {
|
||||||
|
|
||||||
impl Allocator for () {}
|
impl Allocator for () {}
|
||||||
|
|
||||||
|
#[lang = "global_alloc_ty"]
|
||||||
pub struct Global;
|
pub struct Global;
|
||||||
|
|
||||||
impl Allocator for Global {}
|
impl Allocator for Global {}
|
||||||
|
|
|
@ -454,9 +454,13 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D
|
||||||
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
|
ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
|
||||||
build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
|
build_pointer_or_reference_di_node(cx, t, pointee_type, unique_type_id)
|
||||||
}
|
}
|
||||||
// Box<T, A> may have a non-1-ZST allocator A. In that case, we
|
// Some `Box` are newtyped pointers, make debuginfo aware of that.
|
||||||
// cannot treat Box<T, A> as just an owned alias of `*mut T`.
|
// Only works if the allocator argument is a 1-ZST and hence irrelevant for layout
|
||||||
ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_1zst() => {
|
// (or if there is no allocator argument).
|
||||||
|
ty::Adt(def, args)
|
||||||
|
if def.is_box()
|
||||||
|
&& args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) =>
|
||||||
|
{
|
||||||
build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
|
build_pointer_or_reference_di_node(cx, t, t.boxed_ty(), unique_type_id)
|
||||||
}
|
}
|
||||||
ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),
|
ty::FnDef(..) | ty::FnPtr(_) => build_subroutine_type_di_node(cx, unique_type_id),
|
||||||
|
|
|
@ -852,7 +852,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance = match intrinsic {
|
let instance = match intrinsic {
|
||||||
None | Some(ty::IntrinsicDef { name: sym::drop_in_place, .. }) => instance,
|
None => instance,
|
||||||
Some(intrinsic) => {
|
Some(intrinsic) => {
|
||||||
let mut llargs = Vec::with_capacity(1);
|
let mut llargs = Vec::with_capacity(1);
|
||||||
let ret_dest = self.make_return_dest(
|
let ret_dest = self.make_return_dest(
|
||||||
|
|
|
@ -204,6 +204,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
|
||||||
|
|
||||||
pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
|
pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
|
||||||
if self.layout.ty.is_box() {
|
if self.layout.ty.is_box() {
|
||||||
|
// Derefer should have removed all Box derefs
|
||||||
bug!("dereferencing {:?} in codegen", self.layout.ty);
|
bug!("dereferencing {:?} in codegen", self.layout.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -437,6 +437,7 @@ where
|
||||||
trace!("deref to {} on {:?}", val.layout.ty, *val);
|
trace!("deref to {} on {:?}", val.layout.ty, *val);
|
||||||
|
|
||||||
if val.layout.ty.is_box() {
|
if val.layout.ty.is_box() {
|
||||||
|
// Derefer should have removed all Box derefs
|
||||||
bug!("dereferencing {}", val.layout.ty);
|
bug!("dereferencing {}", val.layout.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -359,14 +359,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(Some(match ty.kind() {
|
Ok(Some(match ty.kind() {
|
||||||
ty::Ref(_, ty, _) => *ty,
|
ty::Ref(_, ty, _) => *ty,
|
||||||
ty::RawPtr(mt) => mt.ty,
|
ty::RawPtr(mt) => mt.ty,
|
||||||
// We should only accept `Box` with the default allocator.
|
// We only accept `Box` with the default allocator.
|
||||||
// It's hard to test for that though so we accept every 1-ZST allocator.
|
_ if ty.is_box_global(*self.tcx) => ty.boxed_ty(),
|
||||||
ty::Adt(def, args)
|
|
||||||
if def.is_box()
|
|
||||||
&& self.layout_of(args[1].expect_ty()).is_ok_and(|l| l.is_1zst()) =>
|
|
||||||
{
|
|
||||||
args[0].expect_ty()
|
|
||||||
}
|
|
||||||
_ => return Ok(None),
|
_ => return Ok(None),
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::expand::{self, AstFragment, Invocation};
|
||||||
use crate::module::DirOwnership;
|
use crate::module::DirOwnership;
|
||||||
|
|
||||||
use rustc_ast::attr::MarkedAttrs;
|
use rustc_ast::attr::MarkedAttrs;
|
||||||
use rustc_ast::mut_visit::DummyAstNode;
|
|
||||||
use rustc_ast::ptr::P;
|
use rustc_ast::ptr::P;
|
||||||
use rustc_ast::token::{self, Nonterminal};
|
use rustc_ast::token::{self, Nonterminal};
|
||||||
use rustc_ast::tokenstream::TokenStream;
|
use rustc_ast::tokenstream::TokenStream;
|
||||||
|
@ -582,6 +581,17 @@ impl DummyResult {
|
||||||
tokens: None,
|
tokens: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A plain dummy crate.
|
||||||
|
pub fn raw_crate() -> ast::Crate {
|
||||||
|
ast::Crate {
|
||||||
|
attrs: Default::default(),
|
||||||
|
items: Default::default(),
|
||||||
|
spans: Default::default(),
|
||||||
|
id: ast::DUMMY_NODE_ID,
|
||||||
|
is_placeholder: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MacResult for DummyResult {
|
impl MacResult for DummyResult {
|
||||||
|
@ -650,7 +660,7 @@ impl MacResult for DummyResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_crate(self: Box<DummyResult>) -> Option<ast::Crate> {
|
fn make_crate(self: Box<DummyResult>) -> Option<ast::Crate> {
|
||||||
Some(DummyAstNode::dummy())
|
Some(DummyResult::raw_crate())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -709,7 +709,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// Internal attributes, Const related:
|
// Internal attributes, Const related:
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
rustc_attr!(rustc_promotable, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
|
rustc_attr!(
|
||||||
|
rustc_promotable, Normal, template!(Word), WarnFollowing,
|
||||||
|
@only_local: true, IMPL_DETAIL),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
||||||
INTERNAL_UNSTABLE
|
INTERNAL_UNSTABLE
|
||||||
|
@ -784,7 +786,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
|
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing,
|
rustc_box, AttributeType::Normal, template!(Word), ErrorFollowing, @only_local: true,
|
||||||
"#[rustc_box] allows creating boxes \
|
"#[rustc_box] allows creating boxes \
|
||||||
and it is only intended to be used in `alloc`."
|
and it is only intended to be used in `alloc`."
|
||||||
),
|
),
|
||||||
|
@ -806,11 +808,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
gated!(
|
gated!(
|
||||||
// Used in resolve:
|
// Used in resolve:
|
||||||
prelude_import, Normal, template!(Word), WarnFollowing,
|
prelude_import, Normal, template!(Word), WarnFollowing,
|
||||||
"`#[prelude_import]` is for use by rustc only",
|
@only_local: true, "`#[prelude_import]` is for use by rustc only",
|
||||||
),
|
),
|
||||||
gated!(
|
gated!(
|
||||||
rustc_paren_sugar, Normal, template!(Word), WarnFollowing, unboxed_closures,
|
rustc_paren_sugar, Normal, template!(Word), WarnFollowing, @only_local: true,
|
||||||
"unboxed_closures are still evolving",
|
unboxed_closures, "unboxed_closures are still evolving",
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true,
|
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, @only_local: true,
|
||||||
|
@ -826,27 +828,31 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
|
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
|
||||||
"the `#[rustc_test_marker]` attribute is used internally to track tests",
|
@only_local: true, "the `#[rustc_test_marker]` attribute is used internally to track tests",
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_unsafe_specialization_marker, Normal, template!(Word), WarnFollowing,
|
rustc_unsafe_specialization_marker, Normal, template!(Word),
|
||||||
|
WarnFollowing, @only_local: true,
|
||||||
"the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
|
"the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_specialization_trait, Normal, template!(Word), WarnFollowing,
|
rustc_specialization_trait, Normal, template!(Word),
|
||||||
|
WarnFollowing, @only_local: true,
|
||||||
"the `#[rustc_specialization_trait]` attribute is used to check specializations"
|
"the `#[rustc_specialization_trait]` attribute is used to check specializations"
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_main, Normal, template!(Word), WarnFollowing,
|
rustc_main, Normal, template!(Word), WarnFollowing, @only_local: true,
|
||||||
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
|
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_skip_array_during_method_dispatch, Normal, template!(Word), WarnFollowing,
|
rustc_skip_array_during_method_dispatch, Normal, template!(Word),
|
||||||
|
WarnFollowing, @only_local: true,
|
||||||
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
"the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
|
||||||
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
from method dispatch when the receiver is an array, for compatibility in editions < 2021."
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing,
|
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
|
||||||
|
ErrorFollowing, @only_local: true,
|
||||||
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
||||||
definition of a trait, it's currently in experimental form and should be changed before \
|
definition of a trait, it's currently in experimental form and should be changed before \
|
||||||
being exposed outside of the std"
|
being exposed outside of the std"
|
||||||
|
@ -857,6 +863,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
|
rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing,
|
||||||
|
@only_local: true,
|
||||||
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
|
"the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
|
||||||
),
|
),
|
||||||
rustc_attr!(
|
rustc_attr!(
|
||||||
|
@ -877,8 +884,14 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(
|
||||||
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
|
TEST, rustc_outlives, Normal, template!(Word),
|
||||||
|
WarnFollowing, @only_local: true
|
||||||
|
),
|
||||||
|
rustc_attr!(
|
||||||
|
TEST, rustc_capture_analysis, Normal, template!(Word),
|
||||||
|
WarnFollowing, @only_local: true
|
||||||
|
),
|
||||||
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
|
||||||
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
|
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
|
||||||
|
|
|
@ -267,6 +267,8 @@ language_item_table! {
|
||||||
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
|
EhCatchTypeinfo, sym::eh_catch_typeinfo, eh_catch_typeinfo, Target::Static, GenericRequirement::None;
|
||||||
|
|
||||||
OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
|
OwnedBox, sym::owned_box, owned_box, Target::Struct, GenericRequirement::Minimum(1);
|
||||||
|
GlobalAlloc, sym::global_alloc_ty, global_alloc_ty, Target::Struct, GenericRequirement::None;
|
||||||
|
|
||||||
// Experimental language item for Miri
|
// Experimental language item for Miri
|
||||||
PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
|
PtrUnique, sym::ptr_unique, ptr_unique, Target::Struct, GenericRequirement::Exact(1);
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,8 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
|
||||||
| sym::fsub_algebraic
|
| sym::fsub_algebraic
|
||||||
| sym::fmul_algebraic
|
| sym::fmul_algebraic
|
||||||
| sym::fdiv_algebraic
|
| sym::fdiv_algebraic
|
||||||
| sym::frem_algebraic => hir::Unsafety::Normal,
|
| sym::frem_algebraic
|
||||||
|
| sym::const_eval_select => hir::Unsafety::Normal,
|
||||||
_ => hir::Unsafety::Unsafe,
|
_ => hir::Unsafety::Unsafe,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,7 +248,6 @@ pub fn check_intrinsic_type(
|
||||||
],
|
],
|
||||||
Ty::new_unit(tcx),
|
Ty::new_unit(tcx),
|
||||||
),
|
),
|
||||||
sym::drop_in_place => (1, 0, vec![Ty::new_mut_ptr(tcx, param(0))], Ty::new_unit(tcx)),
|
|
||||||
sym::needs_drop => (1, 0, vec![], tcx.types.bool),
|
sym::needs_drop => (1, 0, vec![], tcx.types.bool),
|
||||||
|
|
||||||
sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
|
sym::type_name => (1, 0, vec![], Ty::new_static_str(tcx)),
|
||||||
|
|
|
@ -56,18 +56,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// It's always helpful for inference if we know the kind of
|
// It's always helpful for inference if we know the kind of
|
||||||
// closure sooner rather than later, so first examine the expected
|
// closure sooner rather than later, so first examine the expected
|
||||||
// type, and see if can glean a closure kind from there.
|
// type, and see if can glean a closure kind from there.
|
||||||
let (expected_sig, expected_kind) = match closure.kind {
|
let (expected_sig, expected_kind) = match expected.to_option(self) {
|
||||||
hir::ClosureKind::Closure => match expected.to_option(self) {
|
Some(ty) => self.deduce_closure_signature(
|
||||||
Some(ty) => {
|
self.try_structurally_resolve_type(expr_span, ty),
|
||||||
self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty))
|
closure.kind,
|
||||||
}
|
),
|
||||||
None => (None, None),
|
None => (None, None),
|
||||||
},
|
|
||||||
// We don't want to deduce a signature from `Fn` bounds for coroutines
|
|
||||||
// or coroutine-closures, because the former does not implement `Fn`
|
|
||||||
// ever, and the latter's signature doesn't correspond to the coroutine
|
|
||||||
// type that it returns.
|
|
||||||
hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => (None, None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ClosureSignatures { bound_sig, mut liberated_sig } =
|
let ClosureSignatures { bound_sig, mut liberated_sig } =
|
||||||
|
@ -323,11 +317,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn deduce_closure_signature(
|
fn deduce_closure_signature(
|
||||||
&self,
|
&self,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
match *expected_ty.kind() {
|
match *expected_ty.kind() {
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||||
.deduce_closure_signature_from_predicates(
|
.deduce_closure_signature_from_predicates(
|
||||||
expected_ty,
|
expected_ty,
|
||||||
|
closure_kind,
|
||||||
self.tcx
|
self.tcx
|
||||||
.explicit_item_bounds(def_id)
|
.explicit_item_bounds(def_id)
|
||||||
.iter_instantiated_copied(self.tcx, args)
|
.iter_instantiated_copied(self.tcx, args)
|
||||||
|
@ -336,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty::Dynamic(object_type, ..) => {
|
ty::Dynamic(object_type, ..) => {
|
||||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
||||||
self.deduce_sig_from_projection(None, pb)
|
self.deduce_sig_from_projection(None, closure_kind, pb)
|
||||||
});
|
});
|
||||||
let kind = object_type
|
let kind = object_type
|
||||||
.principal_def_id()
|
.principal_def_id()
|
||||||
|
@ -345,12 +341,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
|
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
|
||||||
Ty::new_var(self.tcx, self.root_var(vid)),
|
Ty::new_var(self.tcx, self.root_var(vid)),
|
||||||
|
closure_kind,
|
||||||
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
||||||
),
|
),
|
||||||
ty::FnPtr(sig) => {
|
ty::FnPtr(sig) => match closure_kind {
|
||||||
let expected_sig = ExpectedSig { cause_span: None, sig };
|
hir::ClosureKind::Closure => {
|
||||||
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
let expected_sig = ExpectedSig { cause_span: None, sig };
|
||||||
}
|
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
||||||
|
}
|
||||||
|
hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => {
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => (None, None),
|
_ => (None, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,6 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn deduce_closure_signature_from_predicates(
|
fn deduce_closure_signature_from_predicates(
|
||||||
&self,
|
&self,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
let mut expected_sig = None;
|
let mut expected_sig = None;
|
||||||
|
@ -386,6 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
span,
|
span,
|
||||||
self.deduce_sig_from_projection(
|
self.deduce_sig_from_projection(
|
||||||
Some(span),
|
Some(span),
|
||||||
|
closure_kind,
|
||||||
bound_predicate.rebind(proj_predicate),
|
bound_predicate.rebind(proj_predicate),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -422,13 +426,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
|
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(closure_kind) =
|
|
||||||
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
|
if let Some(trait_def_id) = trait_def_id {
|
||||||
{
|
let found_kind = match closure_kind {
|
||||||
expected_kind = Some(
|
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
||||||
expected_kind
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
|
||||||
.map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
|
self.tcx.async_fn_trait_kind_from_def_id(trait_def_id)
|
||||||
);
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(found_kind) = found_kind {
|
||||||
|
expected_kind = Some(
|
||||||
|
expected_kind
|
||||||
|
.map_or_else(|| found_kind, |current| cmp::min(current, found_kind)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,14 +458,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
fn deduce_sig_from_projection(
|
fn deduce_sig_from_projection(
|
||||||
&self,
|
&self,
|
||||||
cause_span: Option<Span>,
|
cause_span: Option<Span>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
projection: ty::PolyProjectionPredicate<'tcx>,
|
projection: ty::PolyProjectionPredicate<'tcx>,
|
||||||
) -> Option<ExpectedSig<'tcx>> {
|
) -> Option<ExpectedSig<'tcx>> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let trait_def_id = projection.trait_def_id(tcx);
|
let trait_def_id = projection.trait_def_id(tcx);
|
||||||
// For now, we only do signature deduction based off of the `Fn` traits.
|
|
||||||
if !tcx.is_fn_trait(trait_def_id) {
|
// For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
|
||||||
return None;
|
// for closures and async closures, respectively.
|
||||||
|
match closure_kind {
|
||||||
|
hir::ClosureKind::Closure
|
||||||
|
if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
|
||||||
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
|
||||||
|
if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
|
||||||
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
||||||
|
|
|
@ -100,6 +100,15 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) if def_id.is_local() => {
|
||||||
let def_id = def_id.expect_local();
|
let def_id = def_id.expect_local();
|
||||||
|
if self.intercrate {
|
||||||
|
// See comment on `insert_hidden_type` for why this is sufficient in coherence
|
||||||
|
return Some(self.register_hidden_type(
|
||||||
|
OpaqueTypeKey { def_id, args },
|
||||||
|
cause.clone(),
|
||||||
|
param_env,
|
||||||
|
b,
|
||||||
|
));
|
||||||
|
}
|
||||||
match self.defining_use_anchor {
|
match self.defining_use_anchor {
|
||||||
DefiningAnchor::Bind(_) => {
|
DefiningAnchor::Bind(_) => {
|
||||||
// Check that this is `impl Trait` type is
|
// Check that this is `impl Trait` type is
|
||||||
|
@ -141,8 +150,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DefiningAnchor::Bubble => {}
|
DefiningAnchor::Bubble => {}
|
||||||
DefiningAnchor::Error => return None,
|
DefiningAnchor::Error => {
|
||||||
};
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() {
|
||||||
// We could accept this, but there are various ways to handle this situation, and we don't
|
// We could accept this, but there are various ways to handle this situation, and we don't
|
||||||
// want to make a decision on it right now. Likely this case is so super rare anyway, that
|
// want to make a decision on it right now. Likely this case is so super rare anyway, that
|
||||||
|
|
|
@ -969,6 +969,8 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Compute the information for the pointer stored at the given offset inside this type.
|
||||||
|
/// This will recurse into fields of ADTs to find the inner pointer.
|
||||||
fn ty_and_layout_pointee_info_at(
|
fn ty_and_layout_pointee_info_at(
|
||||||
this: TyAndLayout<'tcx>,
|
this: TyAndLayout<'tcx>,
|
||||||
cx: &C,
|
cx: &C,
|
||||||
|
@ -1068,15 +1070,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
|
// Fixup info for the first field of a `Box`. Recursive traversal will have found
|
||||||
|
// the raw pointer, so size and align are set to the boxed type, but `pointee.safe`
|
||||||
|
// will still be `None`.
|
||||||
if let Some(ref mut pointee) = result {
|
if let Some(ref mut pointee) = result {
|
||||||
if let ty::Adt(def, _) = this.ty.kind() {
|
if offset.bytes() == 0 && this.ty.is_box() {
|
||||||
if def.is_box() && offset.bytes() == 0 {
|
debug_assert!(pointee.safe.is_none());
|
||||||
let optimize = tcx.sess.opts.optimize != OptLevel::No;
|
let optimize = tcx.sess.opts.optimize != OptLevel::No;
|
||||||
pointee.safe = Some(PointerKind::Box {
|
pointee.safe = Some(PointerKind::Box {
|
||||||
unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
|
unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
|
||||||
});
|
global: this.ty.is_box_global(tcx),
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1999,6 +1999,27 @@ impl<'tcx> Ty<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tests whether this is a Box using the global allocator.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_box_global(self, tcx: TyCtxt<'tcx>) -> bool {
|
||||||
|
match self.kind() {
|
||||||
|
Adt(def, args) if def.is_box() => {
|
||||||
|
let Some(alloc) = args.get(1) else {
|
||||||
|
// Single-argument Box is always global. (for "minicore" tests)
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if let Some(alloc_adt) = alloc.expect_ty().ty_adt_def() {
|
||||||
|
let global_alloc = tcx.require_lang_item(LangItem::GlobalAlloc, None);
|
||||||
|
alloc_adt.did() == global_alloc
|
||||||
|
} else {
|
||||||
|
// Allocator is not an ADT...
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Panics if called on any type other than `Box<T>`.
|
/// Panics if called on any type other than `Box<T>`.
|
||||||
pub fn boxed_ty(self) -> Ty<'tcx> {
|
pub fn boxed_ty(self) -> Ty<'tcx> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
|
|
|
@ -896,6 +896,7 @@ symbols! {
|
||||||
generic_const_items,
|
generic_const_items,
|
||||||
generic_param_attrs,
|
generic_param_attrs,
|
||||||
get_context,
|
get_context,
|
||||||
|
global_alloc_ty,
|
||||||
global_allocator,
|
global_allocator,
|
||||||
global_asm,
|
global_asm,
|
||||||
globs,
|
globs,
|
||||||
|
|
|
@ -26,7 +26,6 @@ use rustc_infer::traits::{util, FulfillmentErrorCode, TraitEngine, TraitEngineEx
|
||||||
use rustc_middle::traits::query::NoSolution;
|
use rustc_middle::traits::query::NoSolution;
|
||||||
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
|
||||||
use rustc_middle::traits::specialization_graph::OverlapMode;
|
use rustc_middle::traits::specialization_graph::OverlapMode;
|
||||||
use rustc_middle::traits::DefiningAnchor;
|
|
||||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||||
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||||
|
@ -207,7 +206,6 @@ fn overlap<'tcx>(
|
||||||
|
|
||||||
let infcx = tcx
|
let infcx = tcx
|
||||||
.infer_ctxt()
|
.infer_ctxt()
|
||||||
.with_opaque_type_inference(DefiningAnchor::Bubble)
|
|
||||||
.skip_leak_check(skip_leak_check.is_yes())
|
.skip_leak_check(skip_leak_check.is_yes())
|
||||||
.intercrate(true)
|
.intercrate(true)
|
||||||
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
|
.with_next_trait_solver(tcx.next_trait_solver_in_coherence())
|
||||||
|
|
|
@ -452,7 +452,7 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
let no_alias = match kind {
|
let no_alias = match kind {
|
||||||
PointerKind::SharedRef { frozen } => frozen,
|
PointerKind::SharedRef { frozen } => frozen,
|
||||||
PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
|
PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
|
||||||
PointerKind::Box { unpin } => unpin && noalias_for_box,
|
PointerKind::Box { unpin, global } => unpin && global && noalias_for_box,
|
||||||
};
|
};
|
||||||
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
||||||
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
||||||
|
|
|
@ -50,6 +50,8 @@ extern "Rust" {
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
|
// the compiler needs to know when a Box uses the global allocator vs a custom one
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "global_alloc_ty")]
|
||||||
pub struct Global;
|
pub struct Global;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -385,6 +387,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "panic_immediate_abort"))]
|
#[cfg(not(feature = "panic_immediate_abort"))]
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
unsafe {
|
unsafe {
|
||||||
core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
|
core::intrinsics::const_eval_select((layout,), ct_error, rt_error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2062,6 +2062,9 @@ impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box
|
||||||
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||||
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
|
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
|
||||||
|
|
||||||
|
// It is quite crucial that we only allow the `Global` allocator here.
|
||||||
|
// Handling arbitrary custom allocators (which can affect the `Box` layout heavily!)
|
||||||
|
// would need a lot of codegen and interpreter adjustments.
|
||||||
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
|
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T, Global> {}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ use alloc::task::{LocalWake, Wake};
|
||||||
use core::task::{LocalWaker, Waker};
|
use core::task::{LocalWaker, Waker};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails
|
||||||
fn test_waker_will_wake_clone() {
|
fn test_waker_will_wake_clone() {
|
||||||
struct NoopWaker;
|
struct NoopWaker;
|
||||||
|
|
||||||
|
@ -19,6 +20,7 @@ fn test_waker_will_wake_clone() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(miri, should_panic)] // `will_wake` doesn't guarantee that this test will work, and indeed on Miri it fails
|
||||||
fn test_local_waker_will_wake_clone() {
|
fn test_local_waker_will_wake_clone() {
|
||||||
struct NoopWaker;
|
struct NoopWaker;
|
||||||
|
|
||||||
|
|
|
@ -428,10 +428,13 @@ impl CStr {
|
||||||
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
unsafe { &*(bytes as *const [u8] as *const CStr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The const and runtime versions have identical behavior
|
// SAFETY: The const and runtime versions have identical behavior
|
||||||
// unless the safety contract of `from_bytes_with_nul_unchecked` is
|
// unless the safety contract of `from_bytes_with_nul_unchecked` is
|
||||||
// violated, which is UB.
|
// violated, which is UB.
|
||||||
unsafe { intrinsics::const_eval_select((bytes,), const_impl, rt_impl) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((bytes,), const_impl, rt_impl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner pointer to this C string.
|
/// Returns the inner pointer to this C string.
|
||||||
|
@ -719,6 +722,9 @@ const unsafe fn const_strlen(ptr: *const c_char) -> usize {
|
||||||
unsafe { strlen(s) }
|
unsafe { strlen(s) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: the two functions always provide equivalent functionality
|
// SAFETY: the two functions always provide equivalent functionality
|
||||||
unsafe { intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -633,6 +633,23 @@ pub use macros::Debug;
|
||||||
/// [tostring]: ../../std/string/trait.ToString.html
|
/// [tostring]: ../../std/string/trait.ToString.html
|
||||||
/// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string
|
/// [tostring_function]: ../../std/string/trait.ToString.html#tymethod.to_string
|
||||||
///
|
///
|
||||||
|
/// # Internationalization
|
||||||
|
///
|
||||||
|
/// Because a type can only have one `Display` implementation, it is often preferable
|
||||||
|
/// to only implement `Display` when there is a single most "obvious" way that
|
||||||
|
/// values can be formatted as text. This could mean formatting according to the
|
||||||
|
/// "invariant" culture and "undefined" locale, or it could mean that the type
|
||||||
|
/// display is designed for a specific culture/locale, such as developer logs.
|
||||||
|
///
|
||||||
|
/// If not all values have a justifiably canonical textual format or if you want
|
||||||
|
/// to support alternative formats not covered by the standard set of possible
|
||||||
|
/// [formatting traits], the most flexible approach is display adapters: methods
|
||||||
|
/// like [`str::escape_default`] or [`Path::display`] which create a wrapper
|
||||||
|
/// implementing `Display` to output the specific display format.
|
||||||
|
///
|
||||||
|
/// [formatting traits]: ../../std/fmt/index.html#formatting-traits
|
||||||
|
/// [`Path::display`]: ../../std/path/struct.Path.html#method.display
|
||||||
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// Implementing `Display` on a type:
|
/// Implementing `Display` on a type:
|
||||||
|
|
|
@ -2514,6 +2514,8 @@ extern "rust-intrinsic" {
|
||||||
/// intrinsic will be replaced with a call to `called_in_const`. It gets
|
/// intrinsic will be replaced with a call to `called_in_const`. It gets
|
||||||
/// replaced with a call to `called_at_rt` otherwise.
|
/// replaced with a call to `called_at_rt` otherwise.
|
||||||
///
|
///
|
||||||
|
/// This function is safe to call, but note the stability concerns below.
|
||||||
|
///
|
||||||
/// # Type Requirements
|
/// # Type Requirements
|
||||||
///
|
///
|
||||||
/// The two functions must be both function items. They cannot be function
|
/// The two functions must be both function items. They cannot be function
|
||||||
|
@ -2523,45 +2525,47 @@ extern "rust-intrinsic" {
|
||||||
/// the two functions, therefore, both functions must accept the same type of
|
/// the two functions, therefore, both functions must accept the same type of
|
||||||
/// arguments. Both functions must return RET.
|
/// arguments. Both functions must return RET.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Stability concerns
|
||||||
///
|
///
|
||||||
/// The two functions must behave observably equivalent. Safe code in other
|
/// Rust has not yet decided that `const fn` are allowed to tell whether
|
||||||
/// crates may assume that calling a `const fn` at compile-time and at run-time
|
/// they run at compile-time or at runtime. Therefore, when using this
|
||||||
/// produces the same result. A function that produces a different result when
|
/// intrinsic anywhere that can be reached from stable, it is crucial that
|
||||||
/// evaluated at run-time, or has any other observable side-effects, is
|
/// the end-to-end behavior of the stable `const fn` is the same for both
|
||||||
/// *unsound*.
|
/// modes of execution. (Here, Undefined Behavior is considered "the same"
|
||||||
|
/// as any other behavior, so if the function exhibits UB at runtime then
|
||||||
|
/// it may do whatever it wants at compile-time.)
|
||||||
///
|
///
|
||||||
/// Here is an example of how this could cause a problem:
|
/// Here is an example of how this could cause a problem:
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// #![feature(const_eval_select)]
|
/// #![feature(const_eval_select)]
|
||||||
/// #![feature(core_intrinsics)]
|
/// #![feature(core_intrinsics)]
|
||||||
/// # #![allow(internal_features)]
|
/// # #![allow(internal_features)]
|
||||||
/// use std::hint::unreachable_unchecked;
|
/// # #![cfg_attr(bootstrap, allow(unused))]
|
||||||
/// use std::intrinsics::const_eval_select;
|
/// use std::intrinsics::const_eval_select;
|
||||||
///
|
///
|
||||||
/// // Crate A
|
/// // Standard library
|
||||||
|
/// # #[cfg(not(bootstrap))]
|
||||||
/// pub const fn inconsistent() -> i32 {
|
/// pub const fn inconsistent() -> i32 {
|
||||||
/// fn runtime() -> i32 { 1 }
|
/// fn runtime() -> i32 { 1 }
|
||||||
/// const fn compiletime() -> i32 { 2 }
|
/// const fn compiletime() -> i32 { 2 }
|
||||||
///
|
///
|
||||||
/// unsafe {
|
// // ⚠ This code violates the required equivalence of `compiletime`
|
||||||
// // ⚠ This code violates the required equivalence of `compiletime`
|
/// // and `runtime`.
|
||||||
/// // and `runtime`.
|
/// const_eval_select((), compiletime, runtime)
|
||||||
/// const_eval_select((), compiletime, runtime)
|
|
||||||
/// }
|
|
||||||
/// }
|
/// }
|
||||||
|
/// # #[cfg(bootstrap)]
|
||||||
|
/// # pub const fn inconsistent() -> i32 { 0 }
|
||||||
///
|
///
|
||||||
/// // Crate B
|
/// // User Crate
|
||||||
/// const X: i32 = inconsistent();
|
/// const X: i32 = inconsistent();
|
||||||
/// let x = inconsistent();
|
/// let x = inconsistent();
|
||||||
/// if x != X { unsafe { unreachable_unchecked(); }}
|
/// assert_eq!(x, X);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This code causes Undefined Behavior when being run, since the
|
/// Currently such an assertion would always succeed; until Rust decides
|
||||||
/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
|
/// otherwise, that principle should not be violated.
|
||||||
/// which violates the principle that a `const fn` must behave the same at
|
|
||||||
/// compile-time and at run-time. The unsafe code in crate B is fine.
|
|
||||||
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
|
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
|
||||||
|
#[cfg_attr(not(bootstrap), rustc_safe_intrinsic)]
|
||||||
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
|
pub fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
arg: ARG,
|
arg: ARG,
|
||||||
called_in_const: F,
|
called_in_const: F,
|
||||||
|
|
|
@ -1153,8 +1153,11 @@ impl f32 {
|
||||||
// Stability concerns.
|
// Stability concerns.
|
||||||
unsafe { mem::transmute(x) }
|
unsafe { mem::transmute(x) }
|
||||||
}
|
}
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
||||||
unsafe { intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((self,), ct_f32_to_u32, rt_f32_to_u32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw transmutation from `u32`.
|
/// Raw transmutation from `u32`.
|
||||||
|
@ -1245,8 +1248,11 @@ impl f32 {
|
||||||
// Stability concerns.
|
// Stability concerns.
|
||||||
unsafe { mem::transmute(x) }
|
unsafe { mem::transmute(x) }
|
||||||
}
|
}
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
||||||
unsafe { intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((v,), ct_u32_to_f32, rt_u32_to_f32)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the memory representation of this floating point number as a byte array in
|
/// Return the memory representation of this floating point number as a byte array in
|
||||||
|
|
|
@ -1146,8 +1146,11 @@ impl f64 {
|
||||||
// Stability concerns.
|
// Stability concerns.
|
||||||
unsafe { mem::transmute::<f64, u64>(rt) }
|
unsafe { mem::transmute::<f64, u64>(rt) }
|
||||||
}
|
}
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
||||||
unsafe { intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((self,), ct_f64_to_u64, rt_f64_to_u64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Raw transmutation from `u64`.
|
/// Raw transmutation from `u64`.
|
||||||
|
@ -1243,8 +1246,11 @@ impl f64 {
|
||||||
// Stability concerns.
|
// Stability concerns.
|
||||||
unsafe { mem::transmute::<u64, f64>(rt) }
|
unsafe { mem::transmute::<u64, f64>(rt) }
|
||||||
}
|
}
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
// SAFETY: We use internal implementations that either always work or fail at compile time.
|
||||||
unsafe { intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64) }
|
unsafe {
|
||||||
|
intrinsics::const_eval_select((v,), ct_u64_to_f64, rt_u64_to_f64)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the memory representation of this floating point number as a byte array in
|
/// Return the memory representation of this floating point number as a byte array in
|
||||||
|
|
|
@ -117,6 +117,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
|
||||||
panic_fmt(fmt);
|
panic_fmt(fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: const panic does not care about unwinding
|
// SAFETY: const panic does not care about unwinding
|
||||||
unsafe {
|
unsafe {
|
||||||
super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime);
|
super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime);
|
||||||
|
|
|
@ -48,8 +48,11 @@ impl<T: ?Sized> *const T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The two versions are equivalent at runtime.
|
// SAFETY: The two versions are equivalent at runtime.
|
||||||
unsafe { const_eval_select((self as *const u8,), const_impl, runtime_impl) }
|
unsafe {
|
||||||
|
const_eval_select((self as *const u8,), const_impl, runtime_impl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts to a pointer of another type.
|
/// Casts to a pointer of another type.
|
||||||
|
@ -806,6 +809,7 @@ impl<T: ?Sized> *const T {
|
||||||
where
|
where
|
||||||
T: Sized,
|
T: Sized,
|
||||||
{
|
{
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The comparison has no side-effects, and the intrinsic
|
// SAFETY: The comparison has no side-effects, and the intrinsic
|
||||||
// does this check internally in the CTFE implementation.
|
// does this check internally in the CTFE implementation.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -1623,8 +1627,11 @@ impl<T: ?Sized> *const T {
|
||||||
ptr.align_offset(align) == 0
|
ptr.align_offset(align) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The two versions are equivalent at runtime.
|
// SAFETY: The two versions are equivalent at runtime.
|
||||||
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
|
unsafe {
|
||||||
|
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -995,6 +995,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: the caller must guarantee that `x` and `y` are
|
// SAFETY: the caller must guarantee that `x` and `y` are
|
||||||
// valid for writes and properly aligned.
|
// valid for writes and properly aligned.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -48,8 +48,11 @@ impl<T: ?Sized> *mut T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The two versions are equivalent at runtime.
|
// SAFETY: The two versions are equivalent at runtime.
|
||||||
unsafe { const_eval_select((self as *mut u8,), const_impl, runtime_impl) }
|
unsafe {
|
||||||
|
const_eval_select((self as *mut u8,), const_impl, runtime_impl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts to a pointer of another type.
|
/// Casts to a pointer of another type.
|
||||||
|
@ -1896,8 +1899,11 @@ impl<T: ?Sized> *mut T {
|
||||||
ptr.align_offset(align) == 0
|
ptr.align_offset(align) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: The two versions are equivalent at runtime.
|
// SAFETY: The two versions are equivalent at runtime.
|
||||||
unsafe { const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl) }
|
unsafe {
|
||||||
|
const_eval_select((self.cast::<()>(), align), const_impl, runtime_impl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ where
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||||
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: we are just panicking here
|
// SAFETY: we are just panicking here
|
||||||
unsafe {
|
unsafe {
|
||||||
const_eval_select(
|
const_eval_select(
|
||||||
|
@ -63,6 +64,7 @@ const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||||
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: we are just panicking here
|
// SAFETY: we are just panicking here
|
||||||
unsafe {
|
unsafe {
|
||||||
const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
|
const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt)
|
||||||
|
@ -87,8 +89,11 @@ const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! {
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
#[rustc_const_unstable(feature = "const_slice_index", issue = "none")]
|
||||||
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: we are just panicking here
|
// SAFETY: we are just panicking here
|
||||||
unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) }
|
unsafe {
|
||||||
|
const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME const-hack
|
// FIXME const-hack
|
||||||
|
|
|
@ -86,6 +86,7 @@ use iter::{MatchesInternal, SplitNInternal};
|
||||||
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
#[rustc_allow_const_fn_unstable(const_eval_select)]
|
||||||
#[cfg(not(feature = "panic_immediate_abort"))]
|
#[cfg(not(feature = "panic_immediate_abort"))]
|
||||||
const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
|
const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
|
||||||
|
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // on bootstrap bump, remove unsafe block
|
||||||
// SAFETY: panics for both branches
|
// SAFETY: panics for both branches
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::intrinsics::const_eval_select(
|
crate::intrinsics::const_eval_select(
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![feature(dyn_star)]
|
#![feature(dyn_star)]
|
||||||
#![feature(generic_nonzero)]
|
#![feature(generic_nonzero)]
|
||||||
|
#![feature(allocator_api)]
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use std::num::NonZero;
|
use std::num::NonZero;
|
||||||
|
@ -182,6 +183,15 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With a custom allocator, it should *not* have `noalias`. (See
|
||||||
|
// <https://github.com/rust-lang/miri/issues/3341> for why.) The second argument is the allocator,
|
||||||
|
// which is a reference here that still carries `noalias` as usual.
|
||||||
|
// CHECK: @_box_custom(ptr noundef nonnull align 4 %x.0, ptr noalias noundef nonnull readonly align 1 %x.1)
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn _box_custom(x: Box<i32, &std::alloc::Global>) {
|
||||||
|
drop(x)
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
|
// CHECK: noundef nonnull align 4 ptr @notunpin_box(ptr noundef nonnull align 4 %x)
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
||||||
|
|
|
@ -160,6 +160,7 @@ mod prelude {
|
||||||
pub _marker: PhantomData<T>,
|
pub _marker: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[lang = "global_alloc_ty"]
|
||||||
pub struct Global;
|
pub struct Global;
|
||||||
|
|
||||||
#[lang = "owned_box"]
|
#[lang = "owned_box"]
|
||||||
|
|
10
tests/ui/async-await/async-closures/signature-deduction.rs
Normal file
10
tests/ui/async-await/async-closures/signature-deduction.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
//@ check-pass
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
|
async fn foo(x: impl async Fn(&str) -> &str) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo(async |x| x);
|
||||||
|
}
|
|
@ -12,8 +12,5 @@ fn uhoh() {
|
||||||
const fn c() {}
|
const fn c() {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// safety: this is unsound and just used to test
|
std::intrinsics::const_eval_select((), c, uhoh);
|
||||||
unsafe {
|
|
||||||
std::intrinsics::const_eval_select((), c, uhoh);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
thread 'main' panicked at $DIR/const-eval-select-backtrace.rs:17:9:
|
thread 'main' panicked at $DIR/const-eval-select-backtrace.rs:15:5:
|
||||||
Aaah!
|
Aaah!
|
||||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||||
|
|
|
@ -13,7 +13,7 @@ const fn nothing(){}
|
||||||
|
|
||||||
#[stable(since = "1.0", feature = "hey")]
|
#[stable(since = "1.0", feature = "hey")]
|
||||||
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
|
#[rustc_const_stable(since = "1.0", feature = "const_hey")]
|
||||||
pub const unsafe fn hey() {
|
pub const fn hey() {
|
||||||
const_eval_select((), nothing, log);
|
const_eval_select((), nothing, log);
|
||||||
//~^ ERROR `const_eval_select` is not yet stable as a const fn
|
//~^ ERROR `const_eval_select` is not yet stable as a const fn
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,9 +22,7 @@ fn eq_rt(x: [i32; 4], y: [i32; 4]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn eq(x: [i32; 4], y: [i32; 4]) -> bool {
|
const fn eq(x: [i32; 4], y: [i32; 4]) -> bool {
|
||||||
unsafe {
|
const_eval_select((x, y), eq_ct, eq_rt)
|
||||||
const_eval_select((x, y), eq_ct, eq_rt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -13,9 +13,9 @@ fn no() -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
// not a sound use case; testing only
|
// not allowed on stable; testing only
|
||||||
const fn is_const_eval() -> bool {
|
const fn is_const_eval() -> bool {
|
||||||
unsafe { const_eval_select((), yes, no) }
|
const_eval_select((), yes, no)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -511,6 +511,7 @@ const fn drop<T: ~const Destruct>(_: T) {}
|
||||||
|
|
||||||
extern "rust-intrinsic" {
|
extern "rust-intrinsic" {
|
||||||
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
#[rustc_const_stable(feature = "const_eval_select", since = "1.0.0")]
|
||||||
|
#[rustc_safe_intrinsic]
|
||||||
fn const_eval_select<ARG: Tuple, F, G, RET>(
|
fn const_eval_select<ARG: Tuple, F, G, RET>(
|
||||||
arg: ARG,
|
arg: ARG,
|
||||||
called_in_const: F,
|
called_in_const: F,
|
||||||
|
@ -525,5 +526,5 @@ fn test_const_eval_select() {
|
||||||
const fn const_fn() {}
|
const fn const_fn() {}
|
||||||
fn rt_fn() {}
|
fn rt_fn() {}
|
||||||
|
|
||||||
unsafe { const_eval_select((), const_fn, rt_fn); }
|
const_eval_select((), const_fn, rt_fn);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue