Auto merge of #136389 - matthiaskrgr:rollup-x453dy9, r=matthiaskrgr

Rollup of 6 pull requests

Successful merges:

 - #130514 (Implement MIR lowering for unsafe binders)
 - #135684 (docs: Documented Send and Sync requirements for Mutex + MutexGuard)
 - #136307 (Implement all mix/max functions in a (hopefully) more optimization amendable way)
 - #136360 (Stabilize `once_wait`)
 - #136364 (document that ptr cmp is unsigned)
 - #136374 (Add link attribute for Enzyme's LLVMRust FFI)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-02-01 20:07:58 +00:00
commit 8239a37f9c
63 changed files with 774 additions and 149 deletions

View File

@ -1657,7 +1657,7 @@ impl GenBlockKind {
} }
/// Whether we're unwrapping or wrapping an unsafe binder /// Whether we're unwrapping or wrapping an unsafe binder
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic)] #[derive(Encodable, Decodable, HashStable_Generic)]
pub enum UnsafeBinderCastKind { pub enum UnsafeBinderCastKind {
// e.g. `&i32` -> `unsafe<'a> &'a i32` // e.g. `&i32` -> `unsafe<'a> &'a i32`

View File

@ -3915,7 +3915,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::ConstantIndex { .. } ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(_) | ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => kind, | ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => kind,
}, },
place_ty.projection_ty(tcx, elem), place_ty.projection_ty(tcx, elem),
) )

View File

@ -370,6 +370,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
ProjectionElem::Downcast(..) => (), ProjectionElem::Downcast(..) => (),
ProjectionElem::OpaqueCast(..) => (), ProjectionElem::OpaqueCast(..) => (),
ProjectionElem::Subtype(..) => (), ProjectionElem::Subtype(..) => (),
ProjectionElem::UnwrapUnsafeBinder(_) => (),
ProjectionElem::Field(field, _ty) => { ProjectionElem::Field(field, _ty) => {
// FIXME(project-rfc_2229#36): print capture precisely here. // FIXME(project-rfc_2229#36): print capture precisely here.
if let Some(field) = self.is_upvar_field_projection(PlaceRef { if let Some(field) = self.is_upvar_field_projection(PlaceRef {
@ -450,9 +451,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx)
} }
ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx),
ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => { ProjectionElem::Subtype(ty)
PlaceTy::from_ty(*ty) | ProjectionElem::OpaqueCast(ty)
} | ProjectionElem::UnwrapUnsafeBinder(ty) => PlaceTy::from_ty(*ty),
ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type),
}, },
}; };

View File

@ -167,7 +167,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::OpaqueCast { .. } | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(..), | ProjectionElem::Downcast(..)
| ProjectionElem::UnwrapUnsafeBinder(_),
], ],
} => bug!("Unexpected immutable place."), } => bug!("Unexpected immutable place."),
} }

View File

@ -1398,6 +1398,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
self.consume_operand(location, (operand, span), state); self.consume_operand(location, (operand, span), state);
} }
} }
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, (op, span), state);
}
} }
} }
@ -1770,7 +1774,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// So it's safe to skip these. // So it's safe to skip these.
ProjectionElem::OpaqueCast(_) ProjectionElem::OpaqueCast(_)
| ProjectionElem::Subtype(_) | ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _) => (), | ProjectionElem::Downcast(_, _)
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
} }
place_ty = place_ty.projection_ty(tcx, elem); place_ty = place_ty.projection_ty(tcx, elem);
@ -2004,6 +2009,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
// FIXME: is this true even if P is an adt with a dtor? // FIXME: is this true even if P is an adt with a dtor?
{ } { }
ProjectionElem::UnwrapUnsafeBinder(_) => {
check_parent_of_field(self, location, place_base, span, state);
}
// assigning to (*P) requires P to be initialized // assigning to (*P) requires P to be initialized
ProjectionElem::Deref => { ProjectionElem::Deref => {
self.check_if_full_path_is_moved( self.check_if_full_path_is_moved(
@ -2384,7 +2393,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(..) | ProjectionElem::Subtype(..)
| ProjectionElem::OpaqueCast { .. } | ProjectionElem::OpaqueCast { .. }
| ProjectionElem::Downcast(..) => { | ProjectionElem::Downcast(..)
| ProjectionElem::UnwrapUnsafeBinder(_) => {
let upvar_field_projection = self.is_upvar_field_projection(place); let upvar_field_projection = self.is_upvar_field_projection(place);
if let Some(field) = upvar_field_projection { if let Some(field) = upvar_field_projection {
let upvar = &self.upvars[field.index()]; let upvar = &self.upvars[field.index()];

View File

@ -250,7 +250,8 @@ fn place_components_conflict<'tcx>(
| (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _)
| (ProjectionElem::OpaqueCast { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _)
| (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Subtype(_), _, _)
| (ProjectionElem::Downcast { .. }, _, _) => { | (ProjectionElem::Downcast { .. }, _, _)
| (ProjectionElem::UnwrapUnsafeBinder(_), _, _) => {
// Recursive case. This can still be disjoint on a // Recursive case. This can still be disjoint on a
// further iteration if this a shallow access and // further iteration if this a shallow access and
// there's a deref later on, e.g., a borrow // there's a deref later on, e.g., a borrow
@ -519,5 +520,9 @@ fn place_projection_conflict<'tcx>(
pi1_elem, pi1_elem,
pi2_elem pi2_elem
), ),
(ProjectionElem::UnwrapUnsafeBinder(_), _) => {
todo!()
}
} }
} }

View File

@ -325,6 +325,10 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
self.consume_operand(location, operand); self.consume_operand(location, operand);
} }
} }
Rvalue::WrapUnsafeBinder(op, _) => {
self.consume_operand(location, op);
}
} }
} }

View File

@ -66,6 +66,10 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
self.next = Some(cursor_base); self.next = Some(cursor_base);
return Some(cursor); return Some(cursor);
} }
ProjectionElem::UnwrapUnsafeBinder(_) => {
self.next = Some(cursor_base);
return Some(cursor);
}
ProjectionElem::Downcast(..) ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::OpaqueCast { .. } | ProjectionElem::OpaqueCast { .. }

View File

@ -302,6 +302,25 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
) )
.unwrap(); .unwrap();
} }
ProjectionElem::UnwrapUnsafeBinder(ty) => {
let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else {
unreachable!();
};
let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars(
self.body().source_info(location).span,
BoundRegionConversionTime::HigherRankedType,
binder_ty.into(),
);
self.typeck
.relate_types(
ty,
context.ambient_variance(),
found_ty,
location.to_locations(),
ConstraintCategory::Boring,
)
.unwrap();
}
ProjectionElem::Subtype(_) => { ProjectionElem::Subtype(_) => {
bug!("ProjectionElem::Subtype shouldn't exist in borrowck") bug!("ProjectionElem::Subtype shouldn't exist in borrowck")
} }
@ -2233,6 +2252,27 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_operand(right, location); self.check_operand(right, location);
} }
Rvalue::WrapUnsafeBinder(op, ty) => {
self.check_operand(op, location);
let operand_ty = op.ty(self.body, self.tcx());
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
unreachable!();
};
let expected_ty = self.infcx.instantiate_binder_with_fresh_vars(
self.body().source_info(location).span,
BoundRegionConversionTime::HigherRankedType,
binder_ty.into(),
);
self.sub_types(
operand_ty,
expected_ty,
location.to_locations(),
ConstraintCategory::Boring,
)
.unwrap();
}
Rvalue::RawPtr(..) Rvalue::RawPtr(..)
| Rvalue::ThreadLocalRef(..) | Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..) | Rvalue::Len(..)
@ -2258,7 +2298,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| Rvalue::NullaryOp(..) | Rvalue::NullaryOp(..)
| Rvalue::CopyForDeref(..) | Rvalue::CopyForDeref(..)
| Rvalue::UnaryOp(..) | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => None, | Rvalue::Discriminant(..)
| Rvalue::WrapUnsafeBinder(..) => None,
Rvalue::Aggregate(aggregate, _) => match **aggregate { Rvalue::Aggregate(aggregate, _) => match **aggregate {
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty, AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@ -2450,7 +2491,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
| ProjectionElem::OpaqueCast(..) | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Index(..) | ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => { | ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {
// other field access // other field access
} }
ProjectionElem::Subtype(_) => { ProjectionElem::Subtype(_) => {

View File

@ -925,6 +925,10 @@ fn codegen_stmt<'tcx>(
} }
crate::discriminant::codegen_set_discriminant(fx, lval, variant_index); crate::discriminant::codegen_set_discriminant(fx, lval, variant_index);
} }
Rvalue::WrapUnsafeBinder(ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
lval.write_cvalue_transmute(fx, operand);
}
} }
} }
StatementKind::StorageLive(_) StatementKind::StorageLive(_)
@ -993,7 +997,9 @@ pub(crate) fn codegen_place<'tcx>(
cplace = cplace.place_deref(fx); cplace = cplace.place_deref(fx);
} }
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)), PlaceElem::Subtype(ty) | PlaceElem::UnwrapUnsafeBinder(ty) => {
cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty));
}
PlaceElem::Field(field, _ty) => { PlaceElem::Field(field, _ty) => {
cplace = cplace.place_field(fx, field); cplace = cplace.place_field(fx, field);
} }

View File

@ -4,6 +4,8 @@ use libc::{c_char, c_uint};
use super::ffi::{BasicBlock, Metadata, Module, Type, Value}; use super::ffi::{BasicBlock, Metadata, Module, Type, Value};
use crate::llvm::Bool; use crate::llvm::Bool;
#[link(name = "llvm-wrapper", kind = "static")]
extern "C" { extern "C" {
// Enzyme // Enzyme
pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool; pub fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool;
@ -12,10 +14,13 @@ extern "C" {
pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>; pub fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>;
pub fn LLVMRustEraseInstFromParent(V: &Value); pub fn LLVMRustEraseInstFromParent(V: &Value);
pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value; pub fn LLVMRustGetTerminator<'a>(B: &BasicBlock) -> &'a Value;
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
}
extern "C" {
// Enzyme
pub fn LLVMDumpModule(M: &Module); pub fn LLVMDumpModule(M: &Module);
pub fn LLVMDumpValue(V: &Value); pub fn LLVMDumpValue(V: &Value);
pub fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool;
pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint; pub fn LLVMGetFunctionCallConv(F: &Value) -> c_uint;
pub fn LLVMGetReturnType(T: &Type) -> &Type; pub fn LLVMGetReturnType(T: &Type) -> &Type;
pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value); pub fn LLVMGetParams(Fnc: &Value, parms: *mut &Value);

View File

@ -502,6 +502,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bug!("encountered OpaqueCast({ty}) in codegen") bug!("encountered OpaqueCast({ty}) in codegen")
} }
mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)),
mir::ProjectionElem::UnwrapUnsafeBinder(ty) => {
cg_base.project_type(bx, self.monomorphize(ty))
}
mir::ProjectionElem::Index(index) => { mir::ProjectionElem::Index(index) => {
let index = &mir::Operand::Copy(mir::Place::from(index)); let index = &mir::Operand::Copy(mir::Place::from(index));
let index = self.codegen_operand(bx, index); let index = self.codegen_operand(bx, index);

View File

@ -823,6 +823,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
OperandRef { val: OperandValue::Immediate(val), layout: box_layout } OperandRef { val: OperandValue::Immediate(val), layout: box_layout }
} }
mir::Rvalue::WrapUnsafeBinder(ref operand, binder_ty) => {
let operand = self.codegen_operand(bx, operand);
let binder_ty = self.monomorphize(binder_ty);
let layout = bx.cx().layout_of(binder_ty);
OperandRef { val: operand.val, layout }
}
} }
} }
@ -1123,7 +1129,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
mir::Rvalue::Discriminant(..) | mir::Rvalue::Discriminant(..) |
mir::Rvalue::NullaryOp(..) | mir::Rvalue::NullaryOp(..) |
mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::ThreadLocalRef(_) |
mir::Rvalue::Use(..) => // (*) mir::Rvalue::Use(..) |
mir::Rvalue::WrapUnsafeBinder(..) => // (*)
true, true,
// Arrays are always aggregates, so it's not worth checking anything here. // Arrays are always aggregates, so it's not worth checking anything here.
// (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)

View File

@ -728,6 +728,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
); );
} }
} }
Rvalue::WrapUnsafeBinder(..) => {
// Unsafe binders are always trivial to create.
}
} }
} }

View File

@ -258,6 +258,8 @@ where
in_place::<Q, _>(cx, in_local, place.as_ref()) in_place::<Q, _>(cx, in_local, place.as_ref())
} }
Rvalue::WrapUnsafeBinder(op, _) => in_operand::<Q, _>(cx, in_local, op),
Rvalue::Aggregate(kind, operands) => { Rvalue::Aggregate(kind, operands) => {
// Return early if we know that the struct or enum being constructed is always // Return early if we know that the struct or enum being constructed is always
// qualified. // qualified.
@ -297,7 +299,8 @@ where
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _) | ProjectionElem::Downcast(_, _)
| ProjectionElem::Index(_) => {} | ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
} }
let base_ty = place_base.ty(cx.body, cx.tcx); let base_ty = place_base.ty(cx.body, cx.tcx);

View File

@ -202,7 +202,8 @@ where
| mir::Rvalue::NullaryOp(..) | mir::Rvalue::NullaryOp(..)
| mir::Rvalue::UnaryOp(..) | mir::Rvalue::UnaryOp(..)
| mir::Rvalue::Discriminant(..) | mir::Rvalue::Discriminant(..)
| mir::Rvalue::Aggregate(..) => {} | mir::Rvalue::Aggregate(..)
| mir::Rvalue::WrapUnsafeBinder(..) => {}
} }
} }

View File

@ -381,6 +381,7 @@ where
OpaqueCast(ty) => { OpaqueCast(ty) => {
span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck")
} }
UnwrapUnsafeBinder(target) => base.transmute(self.layout_of(target)?, self)?,
// We don't want anything happening here, this is here as a dummy. // We don't want anything happening here, this is here as a dummy.
Subtype(_) => base.transmute(base.layout(), self)?, Subtype(_) => base.transmute(base.layout(), self)?,
Field(field, _) => self.project_field(base, field.index())?, Field(field, _) => self.project_field(base, field.index())?,

View File

@ -277,6 +277,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
let discr = self.discriminant_for_variant(op.layout.ty, variant)?; let discr = self.discriminant_for_variant(op.layout.ty, variant)?;
self.write_immediate(*discr, &dest)?; self.write_immediate(*discr, &dest)?;
} }
WrapUnsafeBinder(ref op, _ty) => {
// Constructing an unsafe binder acts like a transmute
// since the operand's layout does not change.
let op = self.eval_operand(op, None)?;
self.copy_op_allow_transmute(&op, &dest)?;
}
} }
trace!("{:?}", self.dump_place(&dest)); trace!("{:?}", self.dump_place(&dest));

View File

@ -1658,8 +1658,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir_ty: Option<&'tcx hir::Ty<'tcx>>, hir_ty: Option<&'tcx hir::Ty<'tcx>>,
expected: Expectation<'tcx>, expected: Expectation<'tcx>,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
self.dcx().span_err(inner_expr.span, "unsafe binder casts are not fully implemented");
match kind { match kind {
hir::UnsafeBinderCastKind::Wrap => { hir::UnsafeBinderCastKind::Wrap => {
let ascribed_ty = let ascribed_ty =

View File

@ -1248,6 +1248,10 @@ impl<'tcx> Debug for Rvalue<'tcx> {
ShallowInitBox(ref place, ref ty) => { ShallowInitBox(ref place, ref ty) => {
with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})")) with_no_trimmed_paths!(write!(fmt, "ShallowInitBox({place:?}, {ty})"))
} }
WrapUnsafeBinder(ref op, ty) => {
with_no_trimmed_paths!(write!(fmt, "wrap_binder!({op:?}; {ty})"))
}
} }
} }
} }
@ -1308,6 +1312,9 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
ProjectionElem::Index(_) ProjectionElem::Index(_)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => {} | ProjectionElem::Subslice { .. } => {}
ProjectionElem::UnwrapUnsafeBinder(_) => {
write!(fmt, "unwrap_binder!(")?;
}
} }
} }
@ -1356,6 +1363,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) ->
ProjectionElem::Subslice { from, to, from_end: false } => { ProjectionElem::Subslice { from, to, from_end: false } => {
write!(fmt, "[{from:?}..{to:?}]")?; write!(fmt, "[{from:?}..{to:?}]")?;
} }
ProjectionElem::UnwrapUnsafeBinder(ty) => {
write!(fmt, "; {ty})")?;
}
} }
} }

View File

@ -62,7 +62,8 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_) | Self::Subtype(_)
| Self::ConstantIndex { .. } | Self::ConstantIndex { .. }
| Self::Subslice { .. } | Self::Subslice { .. }
| Self::Downcast(_, _) => false, | Self::Downcast(_, _)
| Self::UnwrapUnsafeBinder(..) => false,
} }
} }
@ -76,7 +77,8 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_) | Self::Subtype(_)
| Self::ConstantIndex { .. } | Self::ConstantIndex { .. }
| Self::Subslice { .. } | Self::Subslice { .. }
| Self::Downcast(_, _) => true, | Self::Downcast(_, _)
| Self::UnwrapUnsafeBinder(..) => true,
} }
} }
@ -102,6 +104,9 @@ impl<V, T> ProjectionElem<V, T> {
| Self::Subtype(_) | Self::Subtype(_)
| Self::OpaqueCast(_) | Self::OpaqueCast(_)
| Self::Subslice { .. } => false, | Self::Subslice { .. } => false,
// FIXME(unsafe_binders): Figure this out.
Self::UnwrapUnsafeBinder(..) => false,
} }
} }
} }
@ -443,7 +448,8 @@ impl<'tcx> Rvalue<'tcx> {
| Rvalue::UnaryOp(_, _) | Rvalue::UnaryOp(_, _)
| Rvalue::Discriminant(_) | Rvalue::Discriminant(_)
| Rvalue::Aggregate(_, _) | Rvalue::Aggregate(_, _)
| Rvalue::ShallowInitBox(_, _) => true, | Rvalue::ShallowInitBox(_, _)
| Rvalue::WrapUnsafeBinder(_, _) => true,
} }
} }
} }

View File

@ -1276,6 +1276,10 @@ pub enum ProjectionElem<V, T> {
/// requiring an intermediate variable. /// requiring an intermediate variable.
OpaqueCast(T), OpaqueCast(T),
/// A transmute from an unsafe binder to the type that it wraps. This is a projection
/// of a place, so it doesn't necessarily constitute a move out of the binder.
UnwrapUnsafeBinder(T),
/// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
/// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping
/// explicit during optimizations and codegen. /// explicit during optimizations and codegen.
@ -1493,6 +1497,9 @@ pub enum Rvalue<'tcx> {
/// optimizations and codegen backends that previously had to handle deref operations anywhere /// optimizations and codegen backends that previously had to handle deref operations anywhere
/// in a place. /// in a place.
CopyForDeref(Place<'tcx>), CopyForDeref(Place<'tcx>),
/// Wraps a value in an unsafe binder.
WrapUnsafeBinder(Operand<'tcx>, Ty<'tcx>),
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]

View File

@ -146,6 +146,11 @@ impl<'tcx> PlaceTy<'tcx> {
ProjectionElem::Subtype(ty) => { ProjectionElem::Subtype(ty) => {
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
} }
// FIXME(unsafe_binders): Rename `handle_opaque_cast_and_subtype` to be more general.
ProjectionElem::UnwrapUnsafeBinder(ty) => {
PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty))
}
}; };
debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
answer answer
@ -241,6 +246,7 @@ impl<'tcx> Rvalue<'tcx> {
}, },
Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty), Rvalue::ShallowInitBox(_, ty) => Ty::new_box(tcx, ty),
Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty, Rvalue::CopyForDeref(ref place) => place.ty(local_decls, tcx).ty,
Rvalue::WrapUnsafeBinder(_, ty) => ty,
} }
} }

View File

@ -1,6 +1,7 @@
//! `TypeFoldable` implementations for MIR types //! `TypeFoldable` implementations for MIR types
use rustc_ast::InlineAsmTemplatePiece; use rustc_ast::InlineAsmTemplatePiece;
use rustc_hir::UnsafeBinderCastKind;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use super::*; use super::*;
@ -21,6 +22,7 @@ TrivialTypeTraversalImpls! {
SwitchTargets, SwitchTargets,
CoroutineKind, CoroutineKind,
CoroutineSavedLocal, CoroutineSavedLocal,
UnsafeBinderCastKind,
} }
TrivialTypeTraversalImpls! { TrivialTypeTraversalImpls! {

View File

@ -781,6 +781,11 @@ macro_rules! make_mir_visitor {
self.visit_operand(operand, location); self.visit_operand(operand, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
} }
Rvalue::WrapUnsafeBinder(op, ty) => {
self.visit_operand(op, location);
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
} }
} }
@ -1151,6 +1156,11 @@ macro_rules! visit_place_fns {
self.visit_ty(&mut new_ty, TyContext::Location(location)); self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None } if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None }
} }
PlaceElem::UnwrapUnsafeBinder(ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::UnwrapUnsafeBinder(new_ty)) } else { None }
}
PlaceElem::Deref PlaceElem::Deref
| PlaceElem::ConstantIndex { .. } | PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. } | PlaceElem::Subslice { .. }
@ -1219,7 +1229,8 @@ macro_rules! visit_place_fns {
match elem { match elem {
ProjectionElem::OpaqueCast(ty) ProjectionElem::OpaqueCast(ty)
| ProjectionElem::Subtype(ty) | ProjectionElem::Subtype(ty)
| ProjectionElem::Field(_, ty) => { | ProjectionElem::Field(_, ty)
| ProjectionElem::UnwrapUnsafeBinder(ty) => {
self.visit_ty(ty, TyContext::Location(location)); self.visit_ty(ty, TyContext::Location(location));
} }
ProjectionElem::Index(local) => { ProjectionElem::Index(local) => {

View File

@ -489,6 +489,19 @@ pub enum ExprKind<'tcx> {
user_ty: UserTy<'tcx>, user_ty: UserTy<'tcx>,
user_ty_span: Span, user_ty_span: Span,
}, },
/// An unsafe binder cast on a place, e.g. `unwrap_binder!(*ptr)`.
PlaceUnwrapUnsafeBinder {
source: ExprId,
},
/// An unsafe binder cast on a value, e.g. `unwrap_binder!(rvalue())`,
/// which makes a temporary.
ValueUnwrapUnsafeBinder {
source: ExprId,
},
/// Construct an unsafe binder, e.g. `wrap_binder(&ref)`.
WrapUnsafeBinder {
source: ExprId,
},
/// A closure definition. /// A closure definition.
Closure(Box<ClosureExpr<'tcx>>), Closure(Box<ClosureExpr<'tcx>>),
/// A literal. /// A literal.

View File

@ -136,6 +136,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
| ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => { | ValueTypeAscription { source, user_ty: _, user_ty_span: _ } => {
visitor.visit_expr(&visitor.thir()[source]) visitor.visit_expr(&visitor.thir()[source])
} }
PlaceUnwrapUnsafeBinder { source }
| ValueUnwrapUnsafeBinder { source }
| WrapUnsafeBinder { source } => visitor.visit_expr(&visitor.thir()[source]),
Closure(box ClosureExpr { Closure(box ClosureExpr {
closure_id: _, closure_id: _,
args: _, args: _,

View File

@ -361,6 +361,18 @@ mir_build_unreachable_pattern = unreachable pattern
.unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings .unreachable_pattern_let_binding = there is a binding of the same name; if you meant to pattern match against the value of that binding, that is a feature of constants that is not available for `let` bindings
.suggestion = remove the match arm .suggestion = remove the match arm
mir_build_unsafe_binder_cast_requires_unsafe =
unsafe binder cast is unsafe and requires unsafe block
.label = unsafe binder cast
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
information that may be required to uphold safety guarantees of a type
mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
unsafe binder cast is unsafe and requires unsafe block or unsafe fn
.label = unsafe binder cast
.note = casting to or from an `unsafe<...>` binder type is unsafe since it erases lifetime
information that may be required to uphold safety guarantees of a type
mir_build_unsafe_field_requires_unsafe = mir_build_unsafe_field_requires_unsafe =
use of unsafe field is unsafe and requires unsafe block use of unsafe field is unsafe and requires unsafe block
.note = unsafe fields may carry library invariants .note = unsafe fields may carry library invariants

View File

@ -105,7 +105,8 @@ fn convert_to_hir_projections_and_truncate_for_capture(
ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue,
ProjectionElem::Index(..) ProjectionElem::Index(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => { | ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {
// We don't capture array-access projections. // We don't capture array-access projections.
// We can stop here as arrays are captured completely. // We can stop here as arrays are captured completely.
break; break;
@ -523,6 +524,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(PlaceBuilder::from(temp)) block.and(PlaceBuilder::from(temp))
} }
ExprKind::PlaceUnwrapUnsafeBinder { source } => {
let place_builder = unpack!(
block = this.expr_as_place(block, source, mutability, fake_borrow_temps,)
);
block.and(place_builder.project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
}
ExprKind::ValueUnwrapUnsafeBinder { source } => {
let source_expr = &this.thir[source];
let temp = unpack!(
block = this.as_temp(block, source_expr.temp_lifetime, source, mutability)
);
block.and(PlaceBuilder::from(temp).project(PlaceElem::UnwrapUnsafeBinder(expr.ty)))
}
ExprKind::Array { .. } ExprKind::Array { .. }
| ExprKind::Tuple { .. } | ExprKind::Tuple { .. }
| ExprKind::Adt { .. } | ExprKind::Adt { .. }
@ -560,7 +575,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::OffsetOf { .. } | ExprKind::OffsetOf { .. }
| ExprKind::Yield { .. } | ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_) | ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => { | ExprKind::Call { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
// these are not places, so we need to make a temporary. // these are not places, so we need to make a temporary.
debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place)));
let temp = let temp =
@ -776,7 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ProjectionElem::OpaqueCast(..) | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subtype(..) | ProjectionElem::Subtype(..)
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. } => (), | ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => (),
} }
} }
} }

View File

@ -508,6 +508,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(Rvalue::Use(Operand::Constant(Box::new(constant)))) block.and(Rvalue::Use(Operand::Constant(Box::new(constant))))
} }
ExprKind::WrapUnsafeBinder { source } => {
let source = unpack!(
block = this.as_operand(
block,
scope,
source,
LocalInfo::Boring,
NeedsTemporary::Maybe
)
);
block.and(Rvalue::WrapUnsafeBinder(source, expr.ty))
}
ExprKind::Yield { .. } ExprKind::Yield { .. }
| ExprKind::Block { .. } | ExprKind::Block { .. }
| ExprKind::Match { .. } | ExprKind::Match { .. }
@ -532,7 +545,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Become { .. } | ExprKind::Become { .. }
| ExprKind::InlineAsm { .. } | ExprKind::InlineAsm { .. }
| ExprKind::PlaceTypeAscription { .. } | ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => { | ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
// these do not have corresponding `Rvalue` variants, // these do not have corresponding `Rvalue` variants,
// so make an operand and then return that // so make an operand and then return that
debug_assert!(!matches!( debug_assert!(!matches!(

View File

@ -41,7 +41,9 @@ impl Category {
| ExprKind::UpvarRef { .. } | ExprKind::UpvarRef { .. }
| ExprKind::VarRef { .. } | ExprKind::VarRef { .. }
| ExprKind::PlaceTypeAscription { .. } | ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place), | ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => Some(Category::Place),
ExprKind::LogicalOp { .. } ExprKind::LogicalOp { .. }
| ExprKind::Match { .. } | ExprKind::Match { .. }
@ -68,7 +70,8 @@ impl Category {
| ExprKind::Assign { .. } | ExprKind::Assign { .. }
| ExprKind::AssignOp { .. } | ExprKind::AssignOp { .. }
| ExprKind::ThreadLocalRef(_) | ExprKind::ThreadLocalRef(_)
| ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), | ExprKind::OffsetOf { .. }
| ExprKind::WrapUnsafeBinder { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. } ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. } | ExprKind::Literal { .. }

View File

@ -554,7 +554,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ExprKind::VarRef { .. } ExprKind::VarRef { .. }
| ExprKind::UpvarRef { .. } | ExprKind::UpvarRef { .. }
| ExprKind::PlaceTypeAscription { .. } | ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } => { | ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. } => {
debug_assert!(Category::of(&expr.kind) == Some(Category::Place)); debug_assert!(Category::of(&expr.kind) == Some(Category::Place));
let place = unpack!(block = this.as_place(block, expr_id)); let place = unpack!(block = this.as_place(block, expr_id));
@ -613,7 +615,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstParam { .. } | ExprKind::ConstParam { .. }
| ExprKind::ThreadLocalRef(_) | ExprKind::ThreadLocalRef(_)
| ExprKind::StaticRef { .. } | ExprKind::StaticRef { .. }
| ExprKind::OffsetOf { .. } => { | ExprKind::OffsetOf { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() { debug_assert!(match Category::of(&expr.kind).unwrap() {
// should be handled above // should be handled above
Category::Rvalue(RvalueFunc::Into) => false, Category::Rvalue(RvalueFunc::Into) => false,

View File

@ -439,6 +439,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::NeverToAny { .. } | ExprKind::NeverToAny { .. }
| ExprKind::PlaceTypeAscription { .. } | ExprKind::PlaceTypeAscription { .. }
| ExprKind::ValueTypeAscription { .. } | ExprKind::ValueTypeAscription { .. }
| ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. }
| ExprKind::WrapUnsafeBinder { .. }
| ExprKind::PointerCoercion { .. } | ExprKind::PointerCoercion { .. }
| ExprKind::Repeat { .. } | ExprKind::Repeat { .. }
| ExprKind::StaticRef { .. } | ExprKind::StaticRef { .. }
@ -680,6 +683,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
} }
} }
} }
ExprKind::PlaceUnwrapUnsafeBinder { .. }
| ExprKind::ValueUnwrapUnsafeBinder { .. }
| ExprKind::WrapUnsafeBinder { .. } => {
self.requires_unsafe(expr.span, UnsafeBinderCast);
}
_ => {} _ => {}
} }
visit::walk_expr(self, expr); visit::walk_expr(self, expr);
@ -728,6 +736,7 @@ enum UnsafeOpKind {
/// (e.g., with `-C target-feature`). /// (e.g., with `-C target-feature`).
build_enabled: Vec<Symbol>, build_enabled: Vec<Symbol>,
}, },
UnsafeBinderCast,
} }
use UnsafeOpKind::*; use UnsafeOpKind::*;
@ -891,6 +900,15 @@ impl UnsafeOpKind {
unsafe_not_inherited_note, unsafe_not_inherited_note,
}, },
), ),
UnsafeBinderCast => tcx.emit_node_span_lint(
UNSAFE_OP_IN_UNSAFE_FN,
hir_id,
span,
UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
span,
unsafe_not_inherited_note,
},
),
} }
} }
@ -1099,6 +1117,15 @@ impl UnsafeOpKind {
function: tcx.def_path_str(*function), function: tcx.def_path_str(*function),
}); });
} }
UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
span,
unsafe_not_inherited_note,
});
}
UnsafeBinderCast => {
dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
}
} }
} }
} }

View File

@ -160,6 +160,18 @@ pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
} }
#[derive(LintDiagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe,
code = E0133,
)]
pub(crate) struct UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>,
}
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)]
#[help] #[help]
@ -494,6 +506,32 @@ pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
} }
#[derive(Diagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe,
code = E0133,
)]
pub(crate) struct UnsafeBinderCastRequiresUnsafe {
#[primary_span]
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Diagnostic)]
#[diag(
mir_build_unsafe_binder_cast_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
code = E0133,
)]
pub(crate) struct UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
#[primary_span]
#[label]
pub(crate) span: Span,
#[subdiagnostic]
pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>,
}
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[label(mir_build_unsafe_not_inherited)] #[label(mir_build_unsafe_not_inherited)]
pub(crate) struct UnsafeNotInheritedNote { pub(crate) struct UnsafeNotInheritedNote {

View File

@ -1,5 +1,6 @@
use itertools::Itertools; use itertools::Itertools;
use rustc_abi::{FIRST_VARIANT, FieldIdx}; use rustc_abi::{FIRST_VARIANT, FieldIdx};
use rustc_ast::UnsafeBinderCastKind;
use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@ -910,8 +911,19 @@ impl<'tcx> Cx<'tcx> {
} }
} }
hir::ExprKind::UnsafeBinderCast(_kind, _source, _ty) => { hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, source, _ty) => {
unreachable!("unsafe binders are not yet implemented") // FIXME(unsafe_binders): Take into account the ascribed type, too.
let mirrored = self.mirror_expr(source);
if source.is_syntactic_place_expr() {
ExprKind::PlaceUnwrapUnsafeBinder { source: mirrored }
} else {
ExprKind::ValueUnwrapUnsafeBinder { source: mirrored }
}
}
hir::ExprKind::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, source, _ty) => {
// FIXME(unsafe_binders): Take into account the ascribed type, too.
let mirrored = self.mirror_expr(source);
ExprKind::WrapUnsafeBinder { source: mirrored }
} }
hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) }, hir::ExprKind::DropTemps(source) => ExprKind::Use { source: self.mirror_expr(source) },

View File

@ -326,9 +326,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
| Use { source } | Use { source }
| PointerCoercion { source, .. } | PointerCoercion { source, .. }
| PlaceTypeAscription { source, .. } | PlaceTypeAscription { source, .. }
| ValueTypeAscription { source, .. } => { | ValueTypeAscription { source, .. }
self.is_known_valid_scrutinee(&self.thir()[*source]) | PlaceUnwrapUnsafeBinder { source }
} | ValueUnwrapUnsafeBinder { source }
| WrapUnsafeBinder { source } => self.is_known_valid_scrutinee(&self.thir()[*source]),
// These diverge. // These diverge.
Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true, Become { .. } | Break { .. } | Continue { .. } | Return { .. } => true,

View File

@ -477,6 +477,24 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_expr(*source, depth_lvl + 2); self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl); print_indented!(self, "}", depth_lvl);
} }
PlaceUnwrapUnsafeBinder { source } => {
print_indented!(self, "PlaceUnwrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
ValueUnwrapUnsafeBinder { source } => {
print_indented!(self, "ValueUnwrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
WrapUnsafeBinder { source } => {
print_indented!(self, "WrapUnsafeBinder {", depth_lvl);
print_indented!(self, "source:", depth_lvl + 1);
self.print_expr(*source, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
Closure(closure_expr) => { Closure(closure_expr) => {
print_indented!(self, "Closure {", depth_lvl); print_indented!(self, "Closure {", depth_lvl);
print_indented!(self, "closure_expr:", depth_lvl + 1); print_indented!(self, "closure_expr:", depth_lvl + 1);

View File

@ -97,7 +97,8 @@ where
| Rvalue::UnaryOp(..) | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) | Rvalue::Discriminant(..)
| Rvalue::Aggregate(..) | Rvalue::Aggregate(..)
| Rvalue::CopyForDeref(..) => {} | Rvalue::CopyForDeref(..)
| Rvalue::WrapUnsafeBinder(..) => {}
} }
} }

View File

@ -32,6 +32,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> {
} }
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u),
ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()), ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()),
ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()),
} }
} }
} }

View File

@ -208,7 +208,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| ty::Infer(_) | ty::Infer(_)
| ty::Error(_) | ty::Error(_)
| ty::Placeholder(_) => bug!( | ty::Placeholder(_) => bug!(
"When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}" "When Place contains ProjectionElem::Field its type shouldn't be {place_ty:#?}"
), ),
}, },
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
@ -226,6 +226,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
} }
_ => bug!("Unexpected type {place_ty:#?}"), _ => bug!("Unexpected type {place_ty:#?}"),
}, },
ProjectionElem::UnwrapUnsafeBinder(_) => {}
// `OpaqueCast`:Only transmutes the type, so no moves there. // `OpaqueCast`:Only transmutes the type, so no moves there.
// `Downcast` :Only changes information about a `Place` without moving. // `Downcast` :Only changes information about a `Place` without moving.
// `Subtype` :Only transmutes the type, so moves. // `Subtype` :Only transmutes the type, so moves.
@ -399,7 +400,8 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
| Rvalue::Repeat(ref operand, _) | Rvalue::Repeat(ref operand, _)
| Rvalue::Cast(_, ref operand, _) | Rvalue::Cast(_, ref operand, _)
| Rvalue::ShallowInitBox(ref operand, _) | Rvalue::ShallowInitBox(ref operand, _)
| Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand), | Rvalue::UnaryOp(_, ref operand)
| Rvalue::WrapUnsafeBinder(ref operand, _) => self.gather_operand(operand),
Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => { Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
self.gather_operand(lhs); self.gather_operand(lhs);
self.gather_operand(rhs); self.gather_operand(rhs);

View File

@ -504,7 +504,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
| Rvalue::Cast(..) | Rvalue::Cast(..)
| Rvalue::BinaryOp(..) | Rvalue::BinaryOp(..)
| Rvalue::Aggregate(..) | Rvalue::Aggregate(..)
| Rvalue::ShallowInitBox(..) => { | Rvalue::ShallowInitBox(..)
| Rvalue::WrapUnsafeBinder(..) => {
// No modification is possible through these r-values. // No modification is possible through these r-values.
return ValueOrPlace::TOP; return ValueOrPlace::TOP;
} }

View File

@ -575,6 +575,9 @@ impl WriteInfo {
self.add_operand(op); self.add_operand(op);
} }
} }
Rvalue::WrapUnsafeBinder(op, _) => {
self.add_operand(op);
}
Rvalue::ThreadLocalRef(_) Rvalue::ThreadLocalRef(_)
| Rvalue::NullaryOp(_, _) | Rvalue::NullaryOp(_, _)
| Rvalue::Ref(_, _, _) | Rvalue::Ref(_, _, _)

View File

@ -476,6 +476,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
} }
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
ProjectionElem::UnwrapUnsafeBinder(ty) => {
ProjectionElem::UnwrapUnsafeBinder(ty)
}
// This should have been replaced by a `ConstantIndex` earlier. // This should have been replaced by a `ConstantIndex` earlier.
ProjectionElem::Index(_) => return None, ProjectionElem::Index(_) => return None,
}; };
@ -713,6 +716,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
} }
ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty),
ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty),
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
}; };
Some(self.insert(Value::Projection(value, proj))) Some(self.insert(Value::Projection(value, proj)))
@ -867,6 +871,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
self.simplify_place_projection(place, location); self.simplify_place_projection(place, location);
return self.new_pointer(*place, AddressKind::Address(mutbl)); return self.new_pointer(*place, AddressKind::Address(mutbl));
} }
Rvalue::WrapUnsafeBinder(ref mut op, _) => {
return self.simplify_operand(op, location);
}
// Operations. // Operations.
Rvalue::Len(ref mut place) => return self.simplify_len(place, location), Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
@ -931,6 +938,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx), ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx), ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(ty),
}) })
} }

View File

@ -444,7 +444,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
| Rvalue::Cast(..) | Rvalue::Cast(..)
| Rvalue::ShallowInitBox(..) | Rvalue::ShallowInitBox(..)
| Rvalue::Discriminant(..) | Rvalue::Discriminant(..)
| Rvalue::NullaryOp(..) => {} | Rvalue::NullaryOp(..)
| Rvalue::WrapUnsafeBinder(..) => {}
} }
// FIXME we need to revisit this for #67176 // FIXME we need to revisit this for #67176
@ -546,7 +547,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let val: Value<'_> = match *rvalue { let val: Value<'_> = match *rvalue {
ThreadLocalRef(_) => return None, ThreadLocalRef(_) => return None,
Use(ref operand) => self.eval_operand(operand)?.into(), Use(ref operand) | WrapUnsafeBinder(ref operand, _) => {
self.eval_operand(operand)?.into()
}
CopyForDeref(place) => self.eval_place(place)?.into(), CopyForDeref(place) => self.eval_place(place)?.into(),

View File

@ -293,7 +293,8 @@ impl<'tcx> Validator<'_, 'tcx> {
// Recurse directly. // Recurse directly.
ProjectionElem::ConstantIndex { .. } ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subtype(_) | ProjectionElem::Subtype(_)
| ProjectionElem::Subslice { .. } => {} | ProjectionElem::Subslice { .. }
| ProjectionElem::UnwrapUnsafeBinder(_) => {}
// Never recurse. // Never recurse.
ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => { ProjectionElem::OpaqueCast(..) | ProjectionElem::Downcast(..) => {
@ -426,7 +427,9 @@ impl<'tcx> Validator<'_, 'tcx> {
fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
match rvalue { match rvalue {
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => { Rvalue::Use(operand)
| Rvalue::Repeat(operand, _)
| Rvalue::WrapUnsafeBinder(operand, _) => {
self.validate_operand(operand)?; self.validate_operand(operand)?;
} }
Rvalue::CopyForDeref(place) => { Rvalue::CopyForDeref(place) => {

View File

@ -807,6 +807,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
) )
} }
} }
ProjectionElem::UnwrapUnsafeBinder(unwrapped_ty) => {
let binder_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let ty::UnsafeBinder(binder_ty) = *binder_ty.ty.kind() else {
self.fail(
location,
format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
);
return;
};
let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
self.fail(
location,
format!(
"Cannot unwrap unsafe binder {binder_ty:?} into type {unwrapped_ty:?}"
),
);
}
}
_ => {} _ => {}
} }
self.super_projection_elem(place_ref, elem, context, location); self.super_projection_elem(place_ref, elem, context, location);
@ -1362,6 +1381,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| Rvalue::RawPtr(_, _) | Rvalue::RawPtr(_, _)
| Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _) | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::UbChecks, _)
| Rvalue::Discriminant(_) => {} | Rvalue::Discriminant(_) => {}
Rvalue::WrapUnsafeBinder(op, ty) => {
let unwrapped_ty = op.ty(self.body, self.tcx);
let ty::UnsafeBinder(binder_ty) = *ty.kind() else {
self.fail(
location,
format!("WrapUnsafeBinder does not produce a ty::UnsafeBinder"),
);
return;
};
let binder_inner_ty = self.tcx.instantiate_bound_regions_with_erased(*binder_ty);
if !self.mir_assign_valid_types(unwrapped_ty, binder_inner_ty) {
self.fail(
location,
format!("Cannot wrap {unwrapped_ty:?} into unsafe binder {binder_ty:?}"),
);
}
}
} }
self.super_rvalue(rvalue, location); self.super_rvalue(rvalue, location);
} }

View File

@ -217,6 +217,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> {
stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables)) stable_mir::mir::Rvalue::ShallowInitBox(op.stable(tables), ty.stable(tables))
} }
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)), CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable(tables)),
WrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
} }
} }
} }
@ -395,6 +396,7 @@ impl<'tcx> Stable<'tcx> for mir::PlaceElem<'tcx> {
Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)), Downcast(_, idx) => stable_mir::mir::ProjectionElem::Downcast(idx.stable(tables)),
OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)), OpaqueCast(ty) => stable_mir::mir::ProjectionElem::OpaqueCast(ty.stable(tables)),
Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)), Subtype(ty) => stable_mir::mir::ProjectionElem::Subtype(ty.stable(tables)),
UnwrapUnsafeBinder(..) => todo!("FIXME(unsafe_binders):"),
} }
} }
} }

View File

@ -2152,7 +2152,6 @@ symbols! {
unwrap, unwrap,
unwrap_binder, unwrap_binder,
unwrap_or, unwrap_or,
unwrap_unsafe_binder,
use_extern_macros, use_extern_macros,
use_nested_groups, use_nested_groups,
used, used,

View File

@ -830,8 +830,25 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
// Let the visitor iterate into the argument/return // Let the visitor iterate into the argument/return
// types appearing in the fn signature. // types appearing in the fn signature.
} }
ty::UnsafeBinder(_) => { ty::UnsafeBinder(ty) => {
// FIXME(unsafe_binders): We should also recurse into the binder here. // FIXME(unsafe_binders): For now, we have no way to express
// that a type must be `ManuallyDrop` OR `Copy` (or a pointer).
if !ty.has_escaping_bound_vars() {
self.out.push(traits::Obligation::new(
self.tcx(),
self.cause(ObligationCauseCode::Misc),
self.param_env,
ty.map_bound(|ty| {
ty::TraitRef::new(
self.tcx(),
self.tcx().require_lang_item(LangItem::Copy, Some(self.span)),
[ty],
)
}),
));
}
// We recurse into the binder below.
} }
ty::Dynamic(data, r, _) => { ty::Dynamic(data, r, _) => {

View File

@ -116,6 +116,11 @@ fn recurse_build<'tcx>(
| &ExprKind::ValueTypeAscription { source, .. } => { | &ExprKind::ValueTypeAscription { source, .. } => {
recurse_build(tcx, body, source, root_span)? recurse_build(tcx, body, source, root_span)?
} }
&ExprKind::PlaceUnwrapUnsafeBinder { .. }
| &ExprKind::ValueUnwrapUnsafeBinder { .. }
| &ExprKind::WrapUnsafeBinder { .. } => {
todo!("FIXME(unsafe_binders)")
}
&ExprKind::Literal { lit, neg } => { &ExprKind::Literal { lit, neg } => {
let sp = node.span; let sp = node.span;
tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg })
@ -347,6 +352,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
| thir::ExprKind::Adt(_) | thir::ExprKind::Adt(_)
| thir::ExprKind::PlaceTypeAscription { .. } | thir::ExprKind::PlaceTypeAscription { .. }
| thir::ExprKind::ValueTypeAscription { .. } | thir::ExprKind::ValueTypeAscription { .. }
| thir::ExprKind::PlaceUnwrapUnsafeBinder { .. }
| thir::ExprKind::ValueUnwrapUnsafeBinder { .. }
| thir::ExprKind::WrapUnsafeBinder { .. }
| thir::ExprKind::Closure(_) | thir::ExprKind::Closure(_)
| thir::ExprKind::Literal { .. } | thir::ExprKind::Literal { .. }
| thir::ExprKind::NonHirLiteral { .. } | thir::ExprKind::NonHirLiteral { .. }

View File

@ -973,6 +973,24 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// assert_eq!(1.max(2), 2); /// assert_eq!(1.max(2), 2);
/// assert_eq!(2.max(2), 2); /// assert_eq!(2.max(2), 2);
/// ``` /// ```
/// ```
/// use std::cmp::Ordering;
///
/// #[derive(Eq)]
/// struct Equal(&'static str);
///
/// impl PartialEq for Equal {
/// fn eq(&self, other: &Self) -> bool { true }
/// }
/// impl PartialOrd for Equal {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
/// }
/// impl Ord for Equal {
/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
/// }
///
/// assert_eq!(Equal("self").max(Equal("other")).0, "other");
/// ```
#[stable(feature = "ord_max_min", since = "1.21.0")] #[stable(feature = "ord_max_min", since = "1.21.0")]
#[inline] #[inline]
#[must_use] #[must_use]
@ -981,7 +999,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
where where
Self: Sized, Self: Sized,
{ {
max_by(self, other, Ord::cmp) if other < self { self } else { other }
} }
/// Compares and returns the minimum of two values. /// Compares and returns the minimum of two values.
@ -994,6 +1012,24 @@ pub trait Ord: Eq + PartialOrd<Self> {
/// assert_eq!(1.min(2), 1); /// assert_eq!(1.min(2), 1);
/// assert_eq!(2.min(2), 2); /// assert_eq!(2.min(2), 2);
/// ``` /// ```
/// ```
/// use std::cmp::Ordering;
///
/// #[derive(Eq)]
/// struct Equal(&'static str);
///
/// impl PartialEq for Equal {
/// fn eq(&self, other: &Self) -> bool { true }
/// }
/// impl PartialOrd for Equal {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
/// }
/// impl Ord for Equal {
/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
/// }
///
/// assert_eq!(Equal("self").min(Equal("other")).0, "self");
/// ```
#[stable(feature = "ord_max_min", since = "1.21.0")] #[stable(feature = "ord_max_min", since = "1.21.0")]
#[inline] #[inline]
#[must_use] #[must_use]
@ -1002,7 +1038,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
where where
Self: Sized, Self: Sized,
{ {
min_by(self, other, Ord::cmp) if other < self { other } else { self }
} }
/// Restrict a value to a certain interval. /// Restrict a value to a certain interval.
@ -1414,6 +1450,24 @@ pub macro PartialOrd($item:item) {
/// assert_eq!(cmp::min(1, 2), 1); /// assert_eq!(cmp::min(1, 2), 1);
/// assert_eq!(cmp::min(2, 2), 2); /// assert_eq!(cmp::min(2, 2), 2);
/// ``` /// ```
/// ```
/// use std::cmp::{self, Ordering};
///
/// #[derive(Eq)]
/// struct Equal(&'static str);
///
/// impl PartialEq for Equal {
/// fn eq(&self, other: &Self) -> bool { true }
/// }
/// impl PartialOrd for Equal {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
/// }
/// impl Ord for Equal {
/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
/// }
///
/// assert_eq!(cmp::min(Equal("v1"), Equal("v2")).0, "v1");
/// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -1431,20 +1485,22 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
/// ``` /// ```
/// use std::cmp; /// use std::cmp;
/// ///
/// let result = cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); /// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
/// assert_eq!(result, 1);
/// ///
/// let result = cmp::min_by(-2, 3, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); /// let result = cmp::min_by(2, -1, abs_cmp);
/// assert_eq!(result, -2); /// assert_eq!(result, -1);
///
/// let result = cmp::min_by(2, -3, abs_cmp);
/// assert_eq!(result, 2);
///
/// let result = cmp::min_by(1, -1, abs_cmp);
/// assert_eq!(result, 1);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
match compare(&v1, &v2) { if compare(&v2, &v1).is_lt() { v2 } else { v1 }
Ordering::Less | Ordering::Equal => v1,
Ordering::Greater => v2,
}
} }
/// Returns the element that gives the minimum value from the specified function. /// Returns the element that gives the minimum value from the specified function.
@ -1456,17 +1512,20 @@ pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
/// ``` /// ```
/// use std::cmp; /// use std::cmp;
/// ///
/// let result = cmp::min_by_key(-2, 1, |x: &i32| x.abs()); /// let result = cmp::min_by_key(2, -1, |x: &i32| x.abs());
/// assert_eq!(result, 1); /// assert_eq!(result, -1);
/// ///
/// let result = cmp::min_by_key(-2, 2, |x: &i32| x.abs()); /// let result = cmp::min_by_key(2, -3, |x: &i32| x.abs());
/// assert_eq!(result, -2); /// assert_eq!(result, 2);
///
/// let result = cmp::min_by_key(1, -1, |x: &i32| x.abs());
/// assert_eq!(result, 1);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) if f(&v2) < f(&v1) { v2 } else { v1 }
} }
/// Compares and returns the maximum of two values. /// Compares and returns the maximum of two values.
@ -1483,6 +1542,24 @@ pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
/// assert_eq!(cmp::max(1, 2), 2); /// assert_eq!(cmp::max(1, 2), 2);
/// assert_eq!(cmp::max(2, 2), 2); /// assert_eq!(cmp::max(2, 2), 2);
/// ``` /// ```
/// ```
/// use std::cmp::{self, Ordering};
///
/// #[derive(Eq)]
/// struct Equal(&'static str);
///
/// impl PartialEq for Equal {
/// fn eq(&self, other: &Self) -> bool { true }
/// }
/// impl PartialOrd for Equal {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
/// }
/// impl Ord for Equal {
/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
/// }
///
/// assert_eq!(cmp::max(Equal("v1"), Equal("v2")).0, "v2");
/// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -1500,20 +1577,22 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
/// ``` /// ```
/// use std::cmp; /// use std::cmp;
/// ///
/// let result = cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); /// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
///
/// let result = cmp::max_by(3, -2, abs_cmp) ;
/// assert_eq!(result, 3);
///
/// let result = cmp::max_by(1, -2, abs_cmp);
/// assert_eq!(result, -2); /// assert_eq!(result, -2);
/// ///
/// let result = cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())) ; /// let result = cmp::max_by(1, -1, abs_cmp);
/// assert_eq!(result, 2); /// assert_eq!(result, -1);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T { pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
match compare(&v1, &v2) { if compare(&v2, &v1).is_lt() { v1 } else { v2 }
Ordering::Less | Ordering::Equal => v2,
Ordering::Greater => v1,
}
} }
/// Returns the element that gives the maximum value from the specified function. /// Returns the element that gives the maximum value from the specified function.
@ -1525,17 +1604,20 @@ pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
/// ``` /// ```
/// use std::cmp; /// use std::cmp;
/// ///
/// let result = cmp::max_by_key(-2, 1, |x: &i32| x.abs()); /// let result = cmp::max_by_key(3, -2, |x: &i32| x.abs());
/// assert_eq!(result, 3);
///
/// let result = cmp::max_by_key(1, -2, |x: &i32| x.abs());
/// assert_eq!(result, -2); /// assert_eq!(result, -2);
/// ///
/// let result = cmp::max_by_key(-2, 2, |x: &i32| x.abs()); /// let result = cmp::max_by_key(1, -1, |x: &i32| x.abs());
/// assert_eq!(result, 2); /// assert_eq!(result, -1);
/// ``` /// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[stable(feature = "cmp_min_max_by", since = "1.53.0")] #[stable(feature = "cmp_min_max_by", since = "1.53.0")]
pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T { pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) if f(&v2) < f(&v1) { v1 } else { v2 }
} }
/// Compares and sorts two values, returning minimum and maximum. /// Compares and sorts two values, returning minimum and maximum.
@ -1549,13 +1631,32 @@ pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
/// use std::cmp; /// use std::cmp;
/// ///
/// assert_eq!(cmp::minmax(1, 2), [1, 2]); /// assert_eq!(cmp::minmax(1, 2), [1, 2]);
/// assert_eq!(cmp::minmax(2, 2), [2, 2]); /// assert_eq!(cmp::minmax(2, 1), [1, 2]);
/// ///
/// // You can destructure the result using array patterns /// // You can destructure the result using array patterns
/// let [min, max] = cmp::minmax(42, 17); /// let [min, max] = cmp::minmax(42, 17);
/// assert_eq!(min, 17); /// assert_eq!(min, 17);
/// assert_eq!(max, 42); /// assert_eq!(max, 42);
/// ``` /// ```
/// ```
/// #![feature(cmp_minmax)]
/// use std::cmp::{self, Ordering};
///
/// #[derive(Eq)]
/// struct Equal(&'static str);
///
/// impl PartialEq for Equal {
/// fn eq(&self, other: &Self) -> bool { true }
/// }
/// impl PartialOrd for Equal {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(Ordering::Equal) }
/// }
/// impl Ord for Equal {
/// fn cmp(&self, other: &Self) -> Ordering { Ordering::Equal }
/// }
///
/// assert_eq!(cmp::minmax(Equal("v1"), Equal("v2")).map(|v| v.0), ["v1", "v2"]);
/// ```
#[inline] #[inline]
#[must_use] #[must_use]
#[unstable(feature = "cmp_minmax", issue = "115939")] #[unstable(feature = "cmp_minmax", issue = "115939")]
@ -1563,7 +1664,7 @@ pub fn minmax<T>(v1: T, v2: T) -> [T; 2]
where where
T: Ord, T: Ord,
{ {
if v1 <= v2 { [v1, v2] } else { [v2, v1] } if v2 < v1 { [v2, v1] } else { [v1, v2] }
} }
/// Returns minimum and maximum values with respect to the specified comparison function. /// Returns minimum and maximum values with respect to the specified comparison function.
@ -1576,11 +1677,14 @@ where
/// #![feature(cmp_minmax)] /// #![feature(cmp_minmax)]
/// use std::cmp; /// use std::cmp;
/// ///
/// assert_eq!(cmp::minmax_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [1, -2]); /// let abs_cmp = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
/// assert_eq!(cmp::minmax_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), [-2, 2]); ///
/// assert_eq!(cmp::minmax_by(-2, 1, abs_cmp), [1, -2]);
/// assert_eq!(cmp::minmax_by(-1, 2, abs_cmp), [-1, 2]);
/// assert_eq!(cmp::minmax_by(-2, 2, abs_cmp), [-2, 2]);
/// ///
/// // You can destructure the result using array patterns /// // You can destructure the result using array patterns
/// let [min, max] = cmp::minmax_by(-42, 17, |x: &i32, y: &i32| x.abs().cmp(&y.abs())); /// let [min, max] = cmp::minmax_by(-42, 17, abs_cmp);
/// assert_eq!(min, 17); /// assert_eq!(min, 17);
/// assert_eq!(max, -42); /// assert_eq!(max, -42);
/// ``` /// ```
@ -1591,7 +1695,7 @@ pub fn minmax_by<T, F>(v1: T, v2: T, compare: F) -> [T; 2]
where where
F: FnOnce(&T, &T) -> Ordering, F: FnOnce(&T, &T) -> Ordering,
{ {
if compare(&v1, &v2).is_le() { [v1, v2] } else { [v2, v1] } if compare(&v2, &v1).is_lt() { [v2, v1] } else { [v1, v2] }
} }
/// Returns minimum and maximum values with respect to the specified key function. /// Returns minimum and maximum values with respect to the specified key function.
@ -1620,7 +1724,7 @@ where
F: FnMut(&T) -> K, F: FnMut(&T) -> K,
K: Ord, K: Ord,
{ {
minmax_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) if f(&v2) < f(&v1) { [v2, v1] } else { [v1, v2] }
} }
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types

View File

@ -1681,7 +1681,7 @@ impl<T, const N: usize> *const [T; N] {
} }
} }
// Equality for pointers /// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialEq for *const T { impl<T: ?Sized> PartialEq for *const T {
#[inline] #[inline]
@ -1691,10 +1691,11 @@ impl<T: ?Sized> PartialEq for *const T {
} }
} }
/// Pointer equality is an equivalence relation.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Eq for *const T {} impl<T: ?Sized> Eq for *const T {}
// Comparison for pointers /// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Ord for *const T { impl<T: ?Sized> Ord for *const T {
#[inline] #[inline]
@ -1710,6 +1711,7 @@ impl<T: ?Sized> Ord for *const T {
} }
} }
/// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialOrd for *const T { impl<T: ?Sized> PartialOrd for *const T {
#[inline] #[inline]

View File

@ -2097,7 +2097,7 @@ impl<T, const N: usize> *mut [T; N] {
} }
} }
// Equality for pointers /// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialEq for *mut T { impl<T: ?Sized> PartialEq for *mut T {
#[inline(always)] #[inline(always)]
@ -2107,9 +2107,11 @@ impl<T: ?Sized> PartialEq for *mut T {
} }
} }
/// Pointer equality is an equivalence relation.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Eq for *mut T {} impl<T: ?Sized> Eq for *mut T {}
/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Ord for *mut T { impl<T: ?Sized> Ord for *mut T {
#[inline] #[inline]
@ -2125,6 +2127,7 @@ impl<T: ?Sized> Ord for *mut T {
} }
} }
/// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> PartialOrd for *mut T { impl<T: ?Sized> PartialOrd for *mut T {
#[inline(always)] #[inline(always)]

View File

@ -174,8 +174,6 @@ impl<T> OnceLock<T> {
/// ///
/// Waiting for a computation on another thread to finish: /// Waiting for a computation on another thread to finish:
/// ```rust /// ```rust
/// #![feature(once_wait)]
///
/// use std::thread; /// use std::thread;
/// use std::sync::OnceLock; /// use std::sync::OnceLock;
/// ///
@ -189,7 +187,7 @@ impl<T> OnceLock<T> {
/// }) /// })
/// ``` /// ```
#[inline] #[inline]
#[unstable(feature = "once_wait", issue = "127527")] #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
pub fn wait(&self) -> &T { pub fn wait(&self) -> &T {
self.once.wait_force(); self.once.wait_force();

View File

@ -181,10 +181,29 @@ pub struct Mutex<T: ?Sized> {
data: UnsafeCell<T>, data: UnsafeCell<T>,
} }
// these are the only places where `T: Send` matters; all other /// `T` must be `Send` for a [`Mutex`] to be `Send` because it is possible to acquire
// functionality works fine on a single thread. /// the owned `T` from the `Mutex` via [`into_inner`].
///
/// [`into_inner`]: Mutex::into_inner
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
/// `T` must be `Send` for [`Mutex`] to be `Sync`.
/// This ensures that the protected data can be accessed safely from multiple threads
/// without causing data races or other unsafe behavior.
///
/// [`Mutex<T>`] provides mutable access to `T` to one thread at a time. However, it's essential
/// for `T` to be `Send` because it's not safe for non-`Send` structures to be accessed in
/// this manner. For instance, consider [`Rc`], a non-atomic reference counted smart pointer,
/// which is not `Send`. With `Rc`, we can have multiple copies pointing to the same heap
/// allocation with a non-atomic reference count. If we were to use `Mutex<Rc<_>>`, it would
/// only protect one instance of `Rc` from shared access, leaving other copies vulnerable
/// to potential data races.
///
/// Also note that it is not necessary for `T` to be `Sync` as `&T` is only made available
/// to one thread at a time if `T` is not `Sync`.
///
/// [`Rc`]: crate::rc::Rc
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
@ -211,8 +230,17 @@ pub struct MutexGuard<'a, T: ?Sized + 'a> {
poison: poison::Guard, poison: poison::Guard,
} }
/// A [`MutexGuard`] is not `Send` to maximize platform portablity.
///
/// On platforms that use POSIX threads (commonly referred to as pthreads) there is a requirement to
/// release mutex locks on the same thread they were acquired.
/// For this reason, [`MutexGuard`] must not implement `Send` to prevent it being dropped from
/// another thread.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for MutexGuard<'_, T> {} impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
/// `T` must be `Sync` for a [`MutexGuard<T>`] to be `Sync`
/// because it is possible to get a `&T` from `&MutexGuard` (via `Deref`).
#[stable(feature = "mutexguard", since = "1.19.0")] #[stable(feature = "mutexguard", since = "1.19.0")]
unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {} unsafe impl<T: ?Sized + Sync> Sync for MutexGuard<'_, T> {}

View File

@ -269,8 +269,6 @@ impl Once {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// #![feature(once_wait)]
///
/// use std::sync::Once; /// use std::sync::Once;
/// use std::thread; /// use std::thread;
/// ///
@ -289,7 +287,7 @@ impl Once {
/// If this [`Once`] has been poisoned because an initialization closure has /// If this [`Once`] has been poisoned because an initialization closure has
/// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force)
/// if this behavior is not desired. /// if this behavior is not desired.
#[unstable(feature = "once_wait", issue = "127527")] #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
pub fn wait(&self) { pub fn wait(&self) {
if !self.inner.is_completed() { if !self.inner.is_completed() {
self.inner.wait(false); self.inner.wait(false);
@ -298,7 +296,7 @@ impl Once {
/// Blocks the current thread until initialization has completed, ignoring /// Blocks the current thread until initialization has completed, ignoring
/// poisoning. /// poisoning.
#[unstable(feature = "once_wait", issue = "127527")] #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")]
pub fn wait_force(&self) { pub fn wait_force(&self) {
if !self.inner.is_completed() { if !self.inner.is_completed() {
self.inner.wait(true); self.inner.wait(true);

View File

@ -116,6 +116,7 @@ fn check_rvalue<'tcx>(
Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv), Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
Rvalue::Repeat(operand, _) Rvalue::Repeat(operand, _)
| Rvalue::Use(operand) | Rvalue::Use(operand)
| Rvalue::WrapUnsafeBinder(operand, _)
| Rvalue::Cast( | Rvalue::Cast(
CastKind::PointerWithExposedProvenance CastKind::PointerWithExposedProvenance
| CastKind::IntToInt | CastKind::IntToInt
@ -289,7 +290,8 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B
| ProjectionElem::Downcast(..) | ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. } | ProjectionElem::Subslice { .. }
| ProjectionElem::Subtype(_) | ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => {}, | ProjectionElem::Index(_)
| ProjectionElem::UnwrapUnsafeBinder(_) => {},
} }
} }

View File

@ -1,3 +1,5 @@
//@ check-pass
#![feature(unsafe_binders)] #![feature(unsafe_binders)]
//~^ WARN the feature `unsafe_binders` is incomplete //~^ WARN the feature `unsafe_binders` is incomplete
@ -7,8 +9,6 @@ fn main() {
unsafe { unsafe {
let x = 1; let x = 1;
let binder: unsafe<'a> &'a i32 = wrap_binder!(&x); let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
//~^ ERROR unsafe binder casts are not fully implemented
let rx = *unwrap_binder!(binder); let rx = *unwrap_binder!(binder);
//~^ ERROR unsafe binder casts are not fully implemented
} }
} }

View File

@ -1,5 +1,5 @@
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/expr.rs:1:12 --> $DIR/expr.rs:3:12
| |
LL | #![feature(unsafe_binders)] LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^
@ -7,17 +7,5 @@ LL | #![feature(unsafe_binders)]
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error: unsafe binder casts are not fully implemented warning: 1 warning emitted
--> $DIR/expr.rs:9:55
|
LL | let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
| ^^
error: unsafe binder casts are not fully implemented
--> $DIR/expr.rs:11:34
|
LL | let rx = *unwrap_binder!(binder);
| ^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -5,38 +5,31 @@ use std::unsafe_binder::{wrap_binder, unwrap_binder};
fn a() { fn a() {
let _: unsafe<'a> &'a i32 = wrap_binder!(&()); let _: unsafe<'a> &'a i32 = wrap_binder!(&());
//~^ ERROR unsafe binder casts are not fully implemented //~^ ERROR mismatched types
//~| ERROR mismatched types
} }
fn b() { fn b() {
let _: i32 = wrap_binder!(&()); let _: i32 = wrap_binder!(&());
//~^ ERROR unsafe binder casts are not fully implemented //~^ ERROR `wrap_binder!()` can only wrap into unsafe binder
//~| ERROR `wrap_binder!()` can only wrap into unsafe binder
} }
fn c() { fn c() {
let y = 1; let y = 1;
unwrap_binder!(y); unwrap_binder!(y);
//~^ ERROR unsafe binder casts are not fully implemented //~^ ERROR expected unsafe binder, found integer as input
//~| ERROR expected unsafe binder, found integer as input
} }
fn d() { fn d() {
let unknown = Default::default(); let unknown = Default::default();
//~^ ERROR type annotations needed
unwrap_binder!(unknown); unwrap_binder!(unknown);
//~^ ERROR unsafe binder casts are not fully implemented
// FIXME(unsafe_binders): This should report ambiguity once we've removed
// the error above which taints the infcx.
} }
fn e() { fn e() {
let x = wrap_binder!(&42); let x = wrap_binder!(&42);
//~^ ERROR unsafe binder casts are not fully implemented //~^ ERROR type annotations needed
// Currently, type inference doesn't flow backwards for unsafe binders. // Currently, type inference doesn't flow backwards for unsafe binders.
// It could, perhaps, but that may cause even more surprising corners. // It could, perhaps, but that may cause even more surprising corners.
// FIXME(unsafe_binders): This should report ambiguity once we've removed
// the error above which taints the infcx.
let _: unsafe<'a> &'a i32 = x; let _: unsafe<'a> &'a i32 = x;
} }

View File

@ -7,12 +7,6 @@ LL | #![feature(unsafe_binders)]
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information = note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default = note: `#[warn(incomplete_features)]` on by default
error: unsafe binder casts are not fully implemented
--> $DIR/mismatch.rs:7:46
|
LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&());
| ^^^
error[E0308]: mismatched types error[E0308]: mismatched types
--> $DIR/mismatch.rs:7:46 --> $DIR/mismatch.rs:7:46
| |
@ -22,14 +16,8 @@ LL | let _: unsafe<'a> &'a i32 = wrap_binder!(&());
= note: expected reference `&i32` = note: expected reference `&i32`
found reference `&()` found reference `&()`
error: unsafe binder casts are not fully implemented
--> $DIR/mismatch.rs:13:31
|
LL | let _: i32 = wrap_binder!(&());
| ^^^
error: `wrap_binder!()` can only wrap into unsafe binder, not `i32` error: `wrap_binder!()` can only wrap into unsafe binder, not `i32`
--> $DIR/mismatch.rs:13:18 --> $DIR/mismatch.rs:12:18
| |
LL | let _: i32 = wrap_binder!(&()); LL | let _: i32 = wrap_binder!(&());
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
@ -37,32 +25,35 @@ LL | let _: i32 = wrap_binder!(&());
= note: unsafe binders are the only valid output of wrap = note: unsafe binders are the only valid output of wrap
= note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `wrap_binder` (in Nightly builds, run with -Z macro-backtrace for more info)
error: unsafe binder casts are not fully implemented
--> $DIR/mismatch.rs:20:20
|
LL | unwrap_binder!(y);
| ^
error: expected unsafe binder, found integer as input of `unwrap_binder!()` error: expected unsafe binder, found integer as input of `unwrap_binder!()`
--> $DIR/mismatch.rs:20:20 --> $DIR/mismatch.rs:18:20
| |
LL | unwrap_binder!(y); LL | unwrap_binder!(y);
| ^ | ^
| |
= note: only an unsafe binder type can be unwrapped = note: only an unsafe binder type can be unwrapped
error: unsafe binder casts are not fully implemented error[E0282]: type annotations needed
--> $DIR/mismatch.rs:27:20 --> $DIR/mismatch.rs:23:9
| |
LL | unwrap_binder!(unknown); LL | let unknown = Default::default();
| ^^^^^^^ | ^^^^^^^
LL |
LL | unwrap_binder!(unknown);
| ------- type must be known at this point
|
help: consider giving `unknown` an explicit type
|
LL | let unknown: /* Type */ = Default::default();
| ++++++++++++
error: unsafe binder casts are not fully implemented error[E0282]: type annotations needed
--> $DIR/mismatch.rs:34:26 --> $DIR/mismatch.rs:29:26
| |
LL | let x = wrap_binder!(&42); LL | let x = wrap_binder!(&42);
| ^^^ | ^^^ cannot infer type
error: aborting due to 8 previous errors; 1 warning emitted error: aborting due to 5 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0308`. Some errors have detailed explanations: E0282, E0308.
For more information about an error, try `rustc --explain E0282`.

View File

@ -0,0 +1,41 @@
//@ known-bug: unknown
#![feature(unsafe_binders)]
// FIXME(unsafe_binders) ~^ WARN the feature `unsafe_binders` is incomplete
use std::unsafe_binder::{wrap_binder, unwrap_binder};
use std::mem::{drop, ManuallyDrop};
struct NotCopyInner;
type NotCopy = ManuallyDrop<NotCopyInner>;
fn use_after_wrap() {
unsafe {
let base = NotCopy;
let binder: unsafe<> NotCopy = wrap_binder!(base);
drop(base);
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `base`
}
}
fn move_out_of_wrap() {
unsafe {
let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
drop(unwrap_binder!(binder));
drop(unwrap_binder!(binder));
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder`
}
}
fn not_conflicting() {
unsafe {
let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
drop(unwrap_binder!(binder).0);
drop(unwrap_binder!(binder).1);
// ^ NOT a problem.
drop(unwrap_binder!(binder).0);
// FIXME(unsafe_binders) ~^ ERROR use of moved value: `binder.0`
}
}
fn main() {}

View File

@ -0,0 +1,85 @@
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:14:20
|
LL | let base = NotCopy;
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:23:53
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:32:65
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^
|
= note: can't use a type alias as a constructor
error[E0423]: expected value, found type alias `NotCopy`
--> $DIR/moves.rs:32:74
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^
|
= note: can't use a type alias as a constructor
warning: the feature `unsafe_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/moves.rs:3:12
|
LL | #![feature(unsafe_binders)]
| ^^^^^^^^^^^^^^
|
= note: see issue #130516 <https://github.com/rust-lang/rust/issues/130516> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:15:21
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(base);
| ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:23:21
|
LL | let binder: unsafe<> NotCopy = wrap_binder!(NotCopy);
| ^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error[E0277]: the trait bound `NotCopyInner: Copy` is not satisfied
--> $DIR/moves.rs:32:21
|
LL | let binder: unsafe<> (NotCopy, NotCopy) = wrap_binder!((NotCopy, NotCopy));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopyInner`
|
= note: required for `ManuallyDrop<NotCopyInner>` to implement `Copy`
= note: required because it appears within the type `(ManuallyDrop<NotCopyInner>, ManuallyDrop<NotCopyInner>)`
help: consider annotating `NotCopyInner` with `#[derive(Copy)]`
|
LL + #[derive(Copy)]
LL | struct NotCopyInner;
|
error: aborting due to 7 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0423.
For more information about an error, try `rustc --explain E0277`.