Rollup merge of #64588 - matthewjasper:mir-address-of, r=oli-obk
Add a raw "address of" operator * Parse and feature gate `&raw [const | mut] expr` (feature gate name is `raw_address_of`) * Add `mir::Rvalue::AddressOf` * Use the new `Rvalue` for: * the new syntax * reference to pointer casts * drop shims for slices and arrays * Stop using `mir::Rvalue::Cast` with a reference as the operand * Correctly evaluate `mir::Rvalue::{Ref, AddressOf}` in constant propagation cc @Centril @RalfJung @oli-obk @eddyb cc #64490
This commit is contained in:
commit
ef01330887
@ -2060,6 +2060,11 @@ pub enum Rvalue<'tcx> {
|
||||
/// &x or &mut x
|
||||
Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
|
||||
|
||||
/// Create a raw pointer to the given place
|
||||
/// Can be generated by raw address of expressions (`&raw const x`),
|
||||
/// or when casting a reference to a raw pointer.
|
||||
AddressOf(Mutability, Place<'tcx>),
|
||||
|
||||
/// length of a [X] or [X;n] value
|
||||
Len(Place<'tcx>),
|
||||
|
||||
@ -2214,6 +2219,15 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "&{}{}{:?}", region, kind_str, place)
|
||||
}
|
||||
|
||||
AddressOf(mutability, ref place) => {
|
||||
let kind_str = match mutability {
|
||||
Mutability::Mut => "mut",
|
||||
Mutability::Not => "const",
|
||||
};
|
||||
|
||||
write!(fmt, "&raw {} {:?}", kind_str, place)
|
||||
}
|
||||
|
||||
Aggregate(ref kind, ref places) => {
|
||||
fn fmt_tuple(fmt: &mut Formatter<'_>, places: &[Operand<'_>]) -> fmt::Result {
|
||||
let mut tuple_fmt = fmt.debug_tuple("");
|
||||
@ -3085,6 +3099,9 @@ fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
Ref(region, bk, ref place) => {
|
||||
Ref(region.fold_with(folder), bk, place.fold_with(folder))
|
||||
}
|
||||
AddressOf(mutability, ref place) => {
|
||||
AddressOf(mutability, place.fold_with(folder))
|
||||
}
|
||||
Len(ref place) => Len(place.fold_with(folder)),
|
||||
Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
|
||||
BinaryOp(op, ref rhs, ref lhs) => {
|
||||
@ -3125,6 +3142,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
|
||||
Use(ref op) => op.visit_with(visitor),
|
||||
Repeat(ref op, _) => op.visit_with(visitor),
|
||||
Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
|
||||
AddressOf(_, ref place) => place.visit_with(visitor),
|
||||
Len(ref place) => place.visit_with(visitor),
|
||||
Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
|
||||
BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
|
||||
|
@ -172,6 +172,13 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
|
||||
}
|
||||
)
|
||||
}
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let place_ty = place.ty(local_decls, tcx).ty;
|
||||
tcx.mk_ptr(ty::TypeAndMut {
|
||||
ty: place_ty,
|
||||
mutbl: mutability.into(),
|
||||
})
|
||||
}
|
||||
Rvalue::Len(..) => tcx.types.usize,
|
||||
Rvalue::Cast(.., ty) => ty,
|
||||
Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
|
||||
|
@ -570,6 +570,18 @@ fn super_rvalue(&mut self,
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(m, path) => {
|
||||
let ctx = match m {
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AddressOf
|
||||
),
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::AddressOf
|
||||
),
|
||||
};
|
||||
self.visit_place(path, ctx, location);
|
||||
}
|
||||
|
||||
Rvalue::Len(path) => {
|
||||
self.visit_place(
|
||||
path,
|
||||
@ -1031,6 +1043,8 @@ pub enum NonMutatingUseContext {
|
||||
ShallowBorrow,
|
||||
/// Unique borrow.
|
||||
UniqueBorrow,
|
||||
/// AddressOf for *const pointer.
|
||||
AddressOf,
|
||||
/// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
|
||||
/// For example, the projection `x.y` is not marked as a mutation in these cases:
|
||||
///
|
||||
@ -1054,6 +1068,8 @@ pub enum MutatingUseContext {
|
||||
Drop,
|
||||
/// Mutable borrow.
|
||||
Borrow,
|
||||
/// AddressOf for *mut pointer.
|
||||
AddressOf,
|
||||
/// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
|
||||
/// For example, the projection `x.y` is marked as a mutation in these cases:
|
||||
///
|
||||
|
@ -28,8 +28,6 @@ pub enum CastTy<'tcx> {
|
||||
FnPtr,
|
||||
/// Raw pointers
|
||||
Ptr(ty::TypeAndMut<'tcx>),
|
||||
/// References
|
||||
RPtr(ty::TypeAndMut<'tcx>),
|
||||
}
|
||||
|
||||
/// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs)
|
||||
@ -63,7 +61,6 @@ pub fn from_ty(t: Ty<'tcx>) -> Option<CastTy<'tcx>> {
|
||||
ty::Adt(d,_) if d.is_enum() && d.is_payloadfree() =>
|
||||
Some(CastTy::Int(IntTy::CEnum)),
|
||||
ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
|
||||
ty::Ref(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })),
|
||||
ty::FnPtr(..) => Some(CastTy::FnPtr),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -340,10 +340,12 @@ fn visit_local(&mut self,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Projection) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => {
|
||||
self.not_ssa(local);
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ pub fn codegen_place(
|
||||
let cx = self.cx;
|
||||
let tcx = self.cx.tcx();
|
||||
|
||||
let result = match &place_ref {
|
||||
let result = match place_ref {
|
||||
mir::PlaceRef {
|
||||
base: mir::PlaceBase::Local(index),
|
||||
projection: [],
|
||||
|
@ -7,7 +7,7 @@
|
||||
use crate::common::{self, RealPredicate, IntPredicate};
|
||||
use crate::traits::*;
|
||||
|
||||
use rustc::ty::{self, Ty, adjustment::{PointerCast}, Instance};
|
||||
use rustc::ty::{self, Ty, TyCtxt, adjustment::{PointerCast}, Instance};
|
||||
use rustc::ty::cast::{CastTy, IntTy};
|
||||
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
|
||||
use rustc::mir;
|
||||
@ -349,8 +349,7 @@ pub fn codegen_rvalue_operand(
|
||||
}
|
||||
}
|
||||
(CastTy::Ptr(_), CastTy::Ptr(_)) |
|
||||
(CastTy::FnPtr, CastTy::Ptr(_)) |
|
||||
(CastTy::RPtr(_), CastTy::Ptr(_)) =>
|
||||
(CastTy::FnPtr, CastTy::Ptr(_)) =>
|
||||
bx.pointercast(llval, ll_t_out),
|
||||
(CastTy::Ptr(_), CastTy::Int(_)) |
|
||||
(CastTy::FnPtr, CastTy::Int(_)) =>
|
||||
@ -375,24 +374,18 @@ pub fn codegen_rvalue_operand(
|
||||
}
|
||||
|
||||
mir::Rvalue::Ref(_, bk, ref place) => {
|
||||
let cg_place = self.codegen_place(&mut bx, &place.as_ref());
|
||||
let mk_ref = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
|
||||
);
|
||||
self.codegen_place_to_pointer(bx, place, mk_ref)
|
||||
}
|
||||
|
||||
let ty = cg_place.layout.ty;
|
||||
|
||||
// Note: places are indirect, so storing the `llval` into the
|
||||
// destination effectively creates a reference.
|
||||
let val = if !bx.cx().type_has_metadata(ty) {
|
||||
OperandValue::Immediate(cg_place.llval)
|
||||
} else {
|
||||
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
|
||||
};
|
||||
(bx, OperandRef {
|
||||
val,
|
||||
layout: self.cx.layout_of(self.cx.tcx().mk_ref(
|
||||
self.cx.tcx().lifetimes.re_erased,
|
||||
ty::TypeAndMut { ty, mutbl: bk.to_mutbl_lossy() }
|
||||
)),
|
||||
})
|
||||
mir::Rvalue::AddressOf(mutability, ref place) => {
|
||||
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| tcx.mk_ptr(
|
||||
ty::TypeAndMut { ty, mutbl: mutability.into() }
|
||||
);
|
||||
self.codegen_place_to_pointer(bx, place, mk_ptr)
|
||||
}
|
||||
|
||||
mir::Rvalue::Len(ref place) => {
|
||||
@ -548,6 +541,30 @@ fn evaluate_array_len(
|
||||
cg_value.len(bx.cx())
|
||||
}
|
||||
|
||||
/// Codegen an `Rvalue::AddressOf` or `Rvalue::Ref`
|
||||
fn codegen_place_to_pointer(
|
||||
&mut self,
|
||||
mut bx: Bx,
|
||||
place: &mir::Place<'tcx>,
|
||||
mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
|
||||
) -> (Bx, OperandRef<'tcx, Bx::Value>) {
|
||||
let cg_place = self.codegen_place(&mut bx, &place.as_ref());
|
||||
|
||||
let ty = cg_place.layout.ty;
|
||||
|
||||
// Note: places are indirect, so storing the `llval` into the
|
||||
// destination effectively creates a reference.
|
||||
let val = if !bx.cx().type_has_metadata(ty) {
|
||||
OperandValue::Immediate(cg_place.llval)
|
||||
} else {
|
||||
OperandValue::Pair(cg_place.llval, cg_place.llextra.unwrap())
|
||||
};
|
||||
(bx, OperandRef {
|
||||
val,
|
||||
layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn codegen_scalar_binop(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
@ -704,6 +721,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
|
||||
match *rvalue {
|
||||
mir::Rvalue::Ref(..) |
|
||||
mir::Rvalue::AddressOf(..) |
|
||||
mir::Rvalue::Len(..) |
|
||||
mir::Rvalue::Cast(..) | // (*)
|
||||
mir::Rvalue::BinaryOp(..) |
|
||||
|
@ -11,7 +11,7 @@ fn temp_address() {
|
||||
|
||||
To avoid the error, first bind the temporary to a named local variable.
|
||||
|
||||
```ignore (not yet implemented)
|
||||
```
|
||||
# #![feature(raw_ref_op)]
|
||||
fn temp_address() {
|
||||
let val = 2;
|
||||
|
@ -3,7 +3,7 @@
|
||||
use rustc::mir::{BasicBlock, Location, Body, Place, ReadOnlyBodyAndCache, Rvalue};
|
||||
use rustc::mir::{Statement, StatementKind};
|
||||
use rustc::mir::TerminatorKind;
|
||||
use rustc::mir::{Operand, BorrowKind};
|
||||
use rustc::mir::{Operand, BorrowKind, Mutability};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
|
||||
use crate::dataflow::indexes::BorrowIndex;
|
||||
@ -337,6 +337,22 @@ fn consume_rvalue(
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
}))),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
place,
|
||||
access_kind,
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||
|
@ -1233,6 +1233,31 @@ fn consume_rvalue(
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Rvalue::AddressOf(mutability, ref place) => {
|
||||
let access_kind = match mutability {
|
||||
Mutability::Mut => (Deep, Write(WriteKind::MutableBorrow(BorrowKind::Mut {
|
||||
allow_two_phase_borrow: false,
|
||||
}))),
|
||||
Mutability::Not => (Deep, Read(ReadKind::Borrow(BorrowKind::Shared))),
|
||||
};
|
||||
|
||||
self.access_place(
|
||||
location,
|
||||
(place, span),
|
||||
access_kind,
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
);
|
||||
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
location,
|
||||
InitializationRequiringAction::Borrow,
|
||||
(place.as_ref(), span),
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::UnaryOp(_ /*un_op*/, ref operand)
|
||||
|
@ -2273,41 +2273,6 @@ fn check_rvalue(
|
||||
let cast_ty_from = CastTy::from_ty(ty_from);
|
||||
let cast_ty_to = CastTy::from_ty(ty);
|
||||
match (cast_ty_from, cast_ty_to) {
|
||||
(Some(CastTy::RPtr(ref_tm)), Some(CastTy::Ptr(ptr_tm))) => {
|
||||
if let hir::Mutability::Mutable = ptr_tm.mutbl {
|
||||
if let Err(terr) = self.eq_types(
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"equating {:?} with {:?} yields {:?}",
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
terr
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if let Err(terr) = self.sub_types(
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Cast,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"relating {:?} with {:?} yields {:?}",
|
||||
ref_tm.ty,
|
||||
ptr_tm.ty,
|
||||
terr
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
(None, _)
|
||||
| (_, None)
|
||||
| (_, Some(CastTy::FnPtr))
|
||||
@ -2320,7 +2285,15 @@ fn check_rvalue(
|
||||
ty_from,
|
||||
ty,
|
||||
),
|
||||
_ => (),
|
||||
(Some(CastTy::Int(_)), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Float), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Int(_)), Some(CastTy::Float))
|
||||
| (Some(CastTy::Float), Some(CastTy::Float))
|
||||
| (Some(CastTy::Ptr(_)), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::FnPtr), Some(CastTy::Int(_)))
|
||||
| (Some(CastTy::Int(_)), Some(CastTy::Ptr(_)))
|
||||
| (Some(CastTy::Ptr(_)), Some(CastTy::Ptr(_)))
|
||||
| (Some(CastTy::FnPtr), Some(CastTy::Ptr(_))) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2371,7 +2344,8 @@ fn check_rvalue(
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::Use(..)
|
||||
Rvalue::AddressOf(..)
|
||||
| Rvalue::Use(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
@ -2388,6 +2362,7 @@ fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotationInde
|
||||
Rvalue::Use(_)
|
||||
| Rvalue::Repeat(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::AddressOf(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::Cast(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
|
@ -276,6 +276,7 @@ fn expr_as_place(
|
||||
| ExprKind::Pointer { .. }
|
||||
| ExprKind::Repeat { .. }
|
||||
| ExprKind::Borrow { .. }
|
||||
| ExprKind::AddressOf { .. }
|
||||
| ExprKind::Match { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::Block { .. }
|
||||
|
@ -276,6 +276,7 @@ fn expr_as_rvalue(
|
||||
| ExprKind::NeverToAny { .. }
|
||||
| ExprKind::Use { .. }
|
||||
| ExprKind::Borrow { .. }
|
||||
| ExprKind::AddressOf { .. }
|
||||
| ExprKind::Adt { .. }
|
||||
| ExprKind::Loop { .. }
|
||||
| ExprKind::LogicalOp { .. }
|
||||
|
@ -49,6 +49,7 @@ pub fn of(ek: &ExprKind<'_>) -> Option<Category> {
|
||||
| ExprKind::Use { .. }
|
||||
| ExprKind::Adt { .. }
|
||||
| ExprKind::Borrow { .. }
|
||||
| ExprKind::AddressOf { .. }
|
||||
| ExprKind::Call { .. } => Some(Category::Rvalue(RvalueFunc::Into)),
|
||||
|
||||
ExprKind::Array { .. }
|
||||
|
@ -3,6 +3,7 @@
|
||||
use crate::build::expr::category::{Category, RvalueFunc};
|
||||
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
||||
use crate::hair::*;
|
||||
use rustc::hir;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, CanonicalUserTypeAnnotation};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
@ -295,6 +296,23 @@ pub fn into_expr(
|
||||
this.cfg.push_assign(block, source_info, destination, borrow);
|
||||
block.unit()
|
||||
}
|
||||
ExprKind::AddressOf {
|
||||
mutability,
|
||||
arg,
|
||||
} => {
|
||||
let address_of = match mutability {
|
||||
hir::Mutability::Immutable => Rvalue::AddressOf(
|
||||
Mutability::Not,
|
||||
unpack!(block = this.as_read_only_place(block, arg)),
|
||||
),
|
||||
hir::Mutability::Mutable => Rvalue::AddressOf(
|
||||
Mutability::Mut,
|
||||
unpack!(block = this.as_place(block, arg)),
|
||||
),
|
||||
};
|
||||
this.cfg.push_assign(block, source_info, destination, address_of);
|
||||
block.unit()
|
||||
}
|
||||
ExprKind::Adt {
|
||||
adt_def,
|
||||
variant_index,
|
||||
|
@ -335,6 +335,7 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
|
||||
}
|
||||
}
|
||||
Rvalue::Ref(..)
|
||||
| Rvalue::AddressOf(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::NullaryOp(NullOp::SizeOf, _)
|
||||
|
@ -137,8 +137,11 @@ fn apply_adjustment<'a, 'tcx>(
|
||||
arg: expr.to_ref(),
|
||||
}
|
||||
}
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(mutbl)) => {
|
||||
raw_ref_shim(cx, expr.to_ref(), adjustment.target, mutbl, span, temp_lifetime)
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => {
|
||||
ExprKind::AddressOf {
|
||||
mutability,
|
||||
arg: expr.to_ref(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -262,17 +265,11 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutbl, ref arg) => {
|
||||
cx.tcx.sess
|
||||
.struct_span_err(
|
||||
expr.span,
|
||||
"raw borrows are not yet implemented"
|
||||
)
|
||||
.note("for more information, see https://github.com/rust-lang/rust/issues/64490")
|
||||
.emit();
|
||||
|
||||
// Lower to an approximation to avoid further errors.
|
||||
raw_ref_shim(cx, arg.to_ref(), expr_ty, mutbl, expr.span, temp_lifetime)
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Raw, mutability, ref arg) => {
|
||||
ExprKind::AddressOf {
|
||||
mutability,
|
||||
arg: arg.to_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::Block(ref blk, _) => ExprKind::Block { body: &blk },
|
||||
@ -1082,67 +1079,6 @@ fn convert_var(
|
||||
}
|
||||
|
||||
|
||||
/// Fake `&raw [mut|const] expr` using a borrow and a cast until `AddressOf`
|
||||
/// exists in MIR.
|
||||
fn raw_ref_shim<'tcx>(
|
||||
cx: &mut Cx<'_, 'tcx>,
|
||||
arg: ExprRef<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
mutbl: hir::Mutability,
|
||||
span: Span,
|
||||
temp_lifetime: Option<region::Scope>,
|
||||
) -> ExprKind<'tcx> {
|
||||
let arg_tm = if let ty::RawPtr(type_mutbl) = ty.kind {
|
||||
type_mutbl
|
||||
} else {
|
||||
bug!("raw_ref_shim called with non-raw pointer type");
|
||||
};
|
||||
// Convert this to a suitable `&foo` and
|
||||
// then an unsafe coercion.
|
||||
let borrow_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, arg_tm),
|
||||
span,
|
||||
kind: ExprKind::Borrow {
|
||||
borrow_kind: mutbl.to_borrow_kind(),
|
||||
arg,
|
||||
},
|
||||
};
|
||||
let cast_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty,
|
||||
span,
|
||||
kind: ExprKind::Cast { source: borrow_expr.to_ref() }
|
||||
};
|
||||
|
||||
// To ensure that both implicit and explicit coercions are
|
||||
// handled the same way, we insert an extra layer of indirection here.
|
||||
// For explicit casts (e.g., 'foo as *const T'), the source of the 'Use'
|
||||
// will be an ExprKind::Hair with the appropriate cast expression. Here,
|
||||
// we make our Use source the generated Cast from the original coercion.
|
||||
//
|
||||
// In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by
|
||||
// as_operand, not by as_rvalue - causing the cast result to be stored in a temporary.
|
||||
// Ordinary, this is identical to using the cast directly as an rvalue. However, if the
|
||||
// source of the cast was previously borrowed as mutable, storing the cast in a
|
||||
// temporary gives the source a chance to expire before the cast is used. For
|
||||
// structs with a self-referential *mut ptr, this allows assignment to work as
|
||||
// expected.
|
||||
//
|
||||
// For example, consider the type 'struct Foo { field: *mut Foo }',
|
||||
// The method 'fn bar(&mut self) { self.field = self }'
|
||||
// triggers a coercion from '&mut self' to '*mut self'. In order
|
||||
// for the assignment to be valid, the implicit borrow
|
||||
// of 'self' involved in the coercion needs to end before the local
|
||||
// containing the '*mut T' is assigned to 'self.field' - otherwise,
|
||||
// we end up trying to assign to 'self.field' while we have another mutable borrow
|
||||
// active.
|
||||
//
|
||||
// We only need to worry about this kind of thing for coercions from refs to ptrs,
|
||||
// since they get rid of a borrow implicitly.
|
||||
ExprKind::Use { source: cast_expr.to_ref() }
|
||||
}
|
||||
|
||||
fn bin_op(op: hir::BinOpKind) -> BinOp {
|
||||
match op {
|
||||
hir::BinOpKind::Add => BinOp::Add,
|
||||
|
@ -212,6 +212,11 @@ pub enum ExprKind<'tcx> {
|
||||
borrow_kind: BorrowKind,
|
||||
arg: ExprRef<'tcx>,
|
||||
},
|
||||
/// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
|
||||
AddressOf {
|
||||
mutability: hir::Mutability,
|
||||
arg: ExprRef<'tcx>,
|
||||
},
|
||||
Break {
|
||||
label: region::Scope,
|
||||
value: Option<ExprRef<'tcx>>,
|
||||
|
@ -248,7 +248,7 @@ pub fn eval_rvalue_into_place(
|
||||
)?;
|
||||
}
|
||||
|
||||
Ref(_, _, ref place) => {
|
||||
AddressOf(_, ref place) | Ref(_, _, ref place) => {
|
||||
let src = self.eval_place(place)?;
|
||||
let place = self.force_allocation(src)?;
|
||||
if place.layout.size.bytes() > 0 {
|
||||
|
@ -136,21 +136,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndC
|
||||
// iterate backwards using indices.
|
||||
for i in (0..block_data.statements.len()).rev() {
|
||||
let (retag_kind, place) = match block_data.statements[i].kind {
|
||||
// If we are casting *from* a reference, we may have to retag-as-raw.
|
||||
StatementKind::Assign(box(ref place, Rvalue::Cast(
|
||||
CastKind::Misc,
|
||||
ref src,
|
||||
dest_ty,
|
||||
))) => {
|
||||
let src_ty = src.ty(&*local_decls, tcx);
|
||||
if src_ty.is_region_ptr() {
|
||||
// The only `Misc` casts on references are those creating raw pointers.
|
||||
assert!(dest_ty.is_unsafe_ptr());
|
||||
(RetagKind::Raw, place.clone())
|
||||
} else {
|
||||
// Some other cast, no retag
|
||||
continue
|
||||
}
|
||||
// Retag-as-raw after escaping to a raw pointer.
|
||||
StatementKind::Assign(box (ref place, Rvalue::AddressOf(..))) => {
|
||||
(RetagKind::Raw, place.clone())
|
||||
}
|
||||
// Assignments of reference or ptr type are the ones where we may have
|
||||
// to update tags. This includes `x = &[mut] ...` and hence
|
||||
|
@ -224,6 +224,23 @@ fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutAddressOf;
|
||||
impl NonConstOp for MutAddressOf {
|
||||
fn feature_gate(tcx: TyCtxt<'_>) -> Option<bool> {
|
||||
Some(tcx.features().const_mut_refs)
|
||||
}
|
||||
|
||||
fn emit_error(&self, item: &Item<'_, '_>, span: Span) {
|
||||
feature_err(
|
||||
&item.tcx.sess.parse_sess,
|
||||
sym::const_mut_refs,
|
||||
span,
|
||||
&format!("`&raw mut` is not allowed in {}s", item.const_kind())
|
||||
).emit();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct MutDeref;
|
||||
impl NonConstOp for MutDeref {
|
||||
|
@ -151,17 +151,15 @@ fn in_rvalue_structurally(
|
||||
Self::in_operand(cx, per_local, lhs) || Self::in_operand(cx, per_local, rhs)
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, _, ref place) => {
|
||||
Rvalue::Ref(_, _, ref place) | Rvalue::AddressOf(_, ref place) => {
|
||||
// Special-case reborrows to be more like a copy of the reference.
|
||||
if let &[ref proj_base @ .., elem] = place.projection.as_ref() {
|
||||
if ProjectionElem::Deref == elem {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *cx.body, cx.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return Self::in_place(cx, per_local, PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,6 +276,27 @@ fn check_static(&mut self, def_id: DefId, span: Span) {
|
||||
self.check_op_spanned(ops::StaticAccess, span)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_immutable_borrow_like(
|
||||
&mut self,
|
||||
location: Location,
|
||||
place: &Place<'tcx>,
|
||||
) {
|
||||
// FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
|
||||
// seek the cursors beforehand.
|
||||
self.qualifs.has_mut_interior.cursor.seek_before(location);
|
||||
self.qualifs.indirectly_mutable.seek(location);
|
||||
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&|local| self.qualifs.has_mut_interior_eager_seek(local),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for Validator<'_, 'mir, 'tcx> {
|
||||
@ -302,26 +323,44 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
trace!("visit_rvalue: rvalue={:?} location={:?}", rvalue, location);
|
||||
|
||||
// Special-case reborrows to be more like a copy of a reference.
|
||||
if let Rvalue::Ref(_, kind, ref place) = *rvalue {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow,
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow,
|
||||
),
|
||||
BorrowKind::Unique => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::UniqueBorrow,
|
||||
),
|
||||
BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Borrow,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
match *rvalue {
|
||||
Rvalue::Ref(_, kind, ref place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match kind {
|
||||
BorrowKind::Shared => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow,
|
||||
),
|
||||
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::ShallowBorrow,
|
||||
),
|
||||
BorrowKind::Unique => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::UniqueBorrow,
|
||||
),
|
||||
BorrowKind::Mut { .. } => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Borrow,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Rvalue::AddressOf(mutbl, ref place) => {
|
||||
if let Some(reborrowed_proj) = place_as_reborrow(self.tcx, *self.body, place) {
|
||||
let ctx = match mutbl {
|
||||
Mutability::Not => PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::AddressOf,
|
||||
),
|
||||
Mutability::Mut => PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AddressOf,
|
||||
),
|
||||
};
|
||||
self.visit_place_base(&place.base, ctx, location);
|
||||
self.visit_projection(&place.base, reborrowed_proj, ctx, location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.super_rvalue(rvalue, location);
|
||||
@ -367,34 +406,25 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(Mutability::Mut, _) => {
|
||||
self.check_op(ops::MutAddressOf)
|
||||
}
|
||||
|
||||
// At the moment, `PlaceBase::Static` is only used for promoted MIR.
|
||||
| Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place)
|
||||
| Rvalue::AddressOf(Mutability::Not, ref place)
|
||||
if matches!(place.base, PlaceBase::Static(_))
|
||||
=> bug!("Saw a promoted during const-checking, which must run before promotion"),
|
||||
|
||||
| Rvalue::Ref(_, kind @ BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, kind @ BorrowKind::Shallow, ref place)
|
||||
=> {
|
||||
// FIXME: Change the `in_*` methods to take a `FnMut` so we don't have to manually
|
||||
// seek the cursors beforehand.
|
||||
self.qualifs.has_mut_interior.cursor.seek_before(location);
|
||||
self.qualifs.indirectly_mutable.seek(location);
|
||||
| Rvalue::Ref(_, BorrowKind::Shared, ref place)
|
||||
| Rvalue::Ref(_, BorrowKind::Shallow, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
},
|
||||
|
||||
let borrowed_place_has_mut_interior = HasMutInterior::in_place(
|
||||
&self.item,
|
||||
&|local| self.qualifs.has_mut_interior_eager_seek(local),
|
||||
place.as_ref(),
|
||||
);
|
||||
|
||||
if borrowed_place_has_mut_interior {
|
||||
if let BorrowKind::Mut{ .. } = kind {
|
||||
self.check_op(ops::MutBorrow);
|
||||
} else {
|
||||
self.check_op(ops::CellBorrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
Rvalue::AddressOf(Mutability::Not, ref place) => {
|
||||
self.check_immutable_borrow_like(location, place)
|
||||
},
|
||||
|
||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => {
|
||||
let operand_ty = operand.ty(*self.body, self.tcx);
|
||||
|
@ -196,7 +196,12 @@ fn visit_local(&mut self,
|
||||
} else if let TempState::Defined { ref mut uses, .. } = *temp {
|
||||
// We always allow borrows, even mutable ones, as we need
|
||||
// to promote mutable borrows of some ZSTs e.g., `&mut []`.
|
||||
let allowed_use = context.is_borrow() || context.is_nonmutating_use();
|
||||
let allowed_use = match context {
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
|
||||
| PlaceContext::NonMutatingUse(_) => true,
|
||||
PlaceContext::MutatingUse(_)
|
||||
| PlaceContext::NonUse(_) => false,
|
||||
};
|
||||
debug!("visit_local: allowed_use={:?}", allowed_use);
|
||||
if allowed_use {
|
||||
*uses += 1;
|
||||
@ -618,6 +623,21 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
||||
self.validate_operand(rhs)
|
||||
}
|
||||
|
||||
Rvalue::AddressOf(_, place) => {
|
||||
// Raw reborrows can come from reference to pointer coercions,
|
||||
// so are allowed.
|
||||
if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() {
|
||||
let base_ty = Place::ty_from(&place.base, proj_base, *self.body, self.tcx).ty;
|
||||
if let ty::Ref(..) = base_ty.kind {
|
||||
return self.validate_place(PlaceRef {
|
||||
base: &place.base,
|
||||
projection: proj_base,
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(Unpromotable)
|
||||
}
|
||||
|
||||
Rvalue::Ref(_, kind, place) => {
|
||||
if let BorrowKind::Mut { .. } = kind {
|
||||
let ty = place.ty(*self.body, self.tcx).ty;
|
||||
@ -950,7 +970,7 @@ fn promote_candidate(
|
||||
Candidate::Ref(loc) => {
|
||||
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
|
||||
match statement.kind {
|
||||
StatementKind::Assign(box(_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
StatementKind::Assign(box (_, Rvalue::Ref(_, _, ref mut place))) => {
|
||||
// Use the underlying local for this (necessarily interior) borrow.
|
||||
let ty = place.base.ty(local_decls).ty;
|
||||
let span = statement.source_info.span;
|
||||
|
@ -135,7 +135,10 @@ fn check_rvalue(
|
||||
Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
|
||||
check_operand(tcx, operand, span, def_id, body)
|
||||
}
|
||||
Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
|
||||
Rvalue::Len(place)
|
||||
| Rvalue::Discriminant(place)
|
||||
| Rvalue::Ref(_, _, place)
|
||||
| Rvalue::AddressOf(_, place) => {
|
||||
check_place(tcx, place, span, def_id, body)
|
||||
}
|
||||
Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
|
||||
@ -147,9 +150,6 @@ fn check_rvalue(
|
||||
span,
|
||||
"casting pointers to ints is unstable in const fn".into(),
|
||||
)),
|
||||
(CastTy::RPtr(_), CastTy::Float) => bug!(),
|
||||
(CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
|
||||
(CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
|
||||
_ => check_operand(tcx, operand, span, def_id, body),
|
||||
}
|
||||
}
|
||||
|
@ -557,10 +557,10 @@ fn destructor_call_block(&mut self, (succ, unwind): (BasicBlock, Unwind)) -> Bas
|
||||
/// if can_go then succ else drop-block
|
||||
/// drop-block:
|
||||
/// if ptr_based {
|
||||
/// ptr = &mut *cur
|
||||
/// ptr = cur
|
||||
/// cur = cur.offset(1)
|
||||
/// } else {
|
||||
/// ptr = &mut P[cur]
|
||||
/// ptr = &raw mut P[cur]
|
||||
/// cur = cur + 1
|
||||
/// }
|
||||
/// drop(ptr)
|
||||
@ -574,34 +574,28 @@ fn drop_loop(
|
||||
unwind: Unwind,
|
||||
ptr_based: bool,
|
||||
) -> BasicBlock {
|
||||
let copy = |place: &Place<'tcx>| Operand::Copy(place.clone());
|
||||
let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
|
||||
let copy = |place: Place<'tcx>| Operand::Copy(place);
|
||||
let move_ = |place: Place<'tcx>| Operand::Move(place);
|
||||
let tcx = self.tcx();
|
||||
|
||||
let ref_ty = tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut {
|
||||
let ptr_ty = tcx.mk_ptr(ty::TypeAndMut {
|
||||
ty: ety,
|
||||
mutbl: hir::Mutability::Mutable
|
||||
});
|
||||
let ptr = &Place::from(self.new_temp(ref_ty));
|
||||
let can_go = &Place::from(self.new_temp(tcx.types.bool));
|
||||
let ptr = &Place::from(self.new_temp(ptr_ty));
|
||||
let can_go = Place::from(self.new_temp(tcx.types.bool));
|
||||
|
||||
let one = self.constant_usize(1);
|
||||
let (ptr_next, cur_next) = if ptr_based {
|
||||
(Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
Place {
|
||||
base: PlaceBase::Local(cur),
|
||||
projection: tcx.intern_place_elems(&vec![ProjectionElem::Deref]),
|
||||
}
|
||||
),
|
||||
Rvalue::BinaryOp(BinOp::Offset, move_(&Place::from(cur)), one))
|
||||
(
|
||||
Rvalue::Use(copy(cur.into())),
|
||||
Rvalue::BinaryOp(BinOp::Offset, move_(cur.into()), one),
|
||||
)
|
||||
} else {
|
||||
(Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
tcx.mk_place_index(self.place.clone(), cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, move_(&Place::from(cur)), one))
|
||||
(
|
||||
Rvalue::AddressOf(Mutability::Mut, tcx.mk_place_index(self.place.clone(), cur)),
|
||||
Rvalue::BinaryOp(BinOp::Add, move_(cur.into()), one),
|
||||
)
|
||||
};
|
||||
|
||||
let drop_block = BasicBlockData {
|
||||
@ -620,9 +614,9 @@ fn drop_loop(
|
||||
|
||||
let loop_block = BasicBlockData {
|
||||
statements: vec![
|
||||
self.assign(can_go, Rvalue::BinaryOp(BinOp::Eq,
|
||||
copy(&Place::from(cur)),
|
||||
copy(length_or_end)))
|
||||
self.assign(&can_go, Rvalue::BinaryOp(BinOp::Eq,
|
||||
copy(Place::from(cur)),
|
||||
copy(length_or_end.clone())))
|
||||
],
|
||||
is_cleanup: unwind.is_cleanup(),
|
||||
terminator: Some(Terminator {
|
||||
@ -725,8 +719,6 @@ fn drop_loop_pair(
|
||||
|
||||
let cur = self.new_temp(iter_ty);
|
||||
let length_or_end = if ptr_based {
|
||||
// FIXME check if we want to make it return a `Place` directly
|
||||
// if all use sites want a `Place::Base` anyway.
|
||||
Place::from(self.new_temp(iter_ty))
|
||||
} else {
|
||||
length.clone()
|
||||
@ -753,23 +745,16 @@ fn drop_loop_pair(
|
||||
let drop_block_stmts = if ptr_based {
|
||||
let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place));
|
||||
let tmp = Place::from(self.new_temp(tmp_ty));
|
||||
// tmp = &mut P;
|
||||
// tmp = &raw mut P;
|
||||
// cur = tmp as *mut T;
|
||||
// end = Offset(cur, len);
|
||||
vec![
|
||||
self.assign(&tmp, Rvalue::Ref(
|
||||
tcx.lifetimes.re_erased,
|
||||
BorrowKind::Mut { allow_two_phase_borrow: false },
|
||||
self.place.clone()
|
||||
)),
|
||||
self.assign(
|
||||
&cur,
|
||||
Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty),
|
||||
),
|
||||
self.assign(&tmp, Rvalue::AddressOf(Mutability::Mut, self.place.clone())),
|
||||
self.assign(&cur, Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty)),
|
||||
self.assign(
|
||||
&length_or_end,
|
||||
Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)
|
||||
)),
|
||||
Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length)),
|
||||
),
|
||||
]
|
||||
} else {
|
||||
// cur = 0 (length already pushed)
|
||||
|
@ -167,6 +167,8 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
|
||||
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
|
||||
|
@ -469,22 +469,48 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
(Some(t_from), Some(t_cast)) => (t_from, t_cast),
|
||||
// Function item types may need to be reified before casts.
|
||||
(None, Some(t_cast)) => {
|
||||
if let ty::FnDef(..) = self.expr_ty.kind {
|
||||
// Attempt a coercion to a fn pointer type.
|
||||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
fcx.tcx.mk_fn_ptr(f),
|
||||
AllowTwoPhase::No);
|
||||
if let Err(TypeError::IntrinsicCast) = res {
|
||||
return Err(CastError::IllegalCast);
|
||||
match self.expr_ty.kind {
|
||||
ty::FnDef(..) => {
|
||||
// Attempt a coercion to a fn pointer type.
|
||||
let f = self.expr_ty.fn_sig(fcx.tcx);
|
||||
let res = fcx.try_coerce(self.expr,
|
||||
self.expr_ty,
|
||||
fcx.tcx.mk_fn_ptr(f),
|
||||
AllowTwoPhase::No);
|
||||
if let Err(TypeError::IntrinsicCast) = res {
|
||||
return Err(CastError::IllegalCast);
|
||||
}
|
||||
if res.is_err() {
|
||||
return Err(CastError::NonScalar);
|
||||
}
|
||||
(FnPtr, t_cast)
|
||||
}
|
||||
if res.is_err() {
|
||||
return Err(CastError::NonScalar);
|
||||
// Special case some errors for references, and check for
|
||||
// array-ptr-casts. `Ref` is not a CastTy because the cast
|
||||
// is split into a coercion to a pointer type, followed by
|
||||
// a cast.
|
||||
ty::Ref(_, inner_ty, mutbl) => {
|
||||
return match t_cast {
|
||||
Int(_) | Float => match inner_ty.kind {
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Float(_) |
|
||||
ty::Infer(ty::InferTy::IntVar(_)) |
|
||||
ty::Infer(ty::InferTy::FloatVar(_)) => {
|
||||
Err(CastError::NeedDeref)
|
||||
}
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
// array-ptr-cast
|
||||
Ptr(mt) => self.check_ref_cast(
|
||||
fcx,
|
||||
TypeAndMut { mutbl, ty: inner_ty },
|
||||
mt,
|
||||
),
|
||||
_ => Err(CastError::NonScalar),
|
||||
};
|
||||
}
|
||||
(FnPtr, t_cast)
|
||||
} else {
|
||||
return Err(CastError::NonScalar);
|
||||
_ => return Err(CastError::NonScalar),
|
||||
}
|
||||
}
|
||||
_ => return Err(CastError::NonScalar),
|
||||
@ -492,7 +518,7 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
|
||||
match (t_from, t_cast) {
|
||||
// These types have invariants! can't cast into them.
|
||||
(_, RPtr(_)) | (_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
(_, Int(CEnum)) | (_, FnPtr) => Err(CastError::NonScalar),
|
||||
|
||||
// * -> Bool
|
||||
(_, Int(Bool)) => Err(CastError::CastToBool),
|
||||
@ -517,28 +543,10 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
|
||||
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
|
||||
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
|
||||
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
|
||||
(RPtr(p), Int(_)) |
|
||||
(RPtr(p), Float) => {
|
||||
match p.ty.kind {
|
||||
ty::Int(_) |
|
||||
ty::Uint(_) |
|
||||
ty::Float(_) => {
|
||||
Err(CastError::NeedDeref)
|
||||
}
|
||||
ty::Infer(t) => {
|
||||
match t {
|
||||
ty::InferTy::IntVar(_) |
|
||||
ty::InferTy::FloatVar(_) => Err(CastError::NeedDeref),
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
}
|
||||
_ => Err(CastError::NeedViaPtr),
|
||||
}
|
||||
}
|
||||
|
||||
// * -> ptr
|
||||
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
|
||||
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
|
||||
(RPtr(rmt), Ptr(mt)) => self.check_ref_cast(fcx, rmt, mt), // array-ptr-cast
|
||||
|
||||
// prim -> prim
|
||||
(Int(CEnum), Int(_)) => Ok(CastKind::EnumCast),
|
||||
|
@ -728,13 +728,13 @@ pub fn prefix_str(&self) -> &'static str {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
#[derive(RustcEncodable, RustcDecodable, HashStable_Generic)]
|
||||
pub enum BorrowKind {
|
||||
/// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
|
||||
/// The resulting type is either `*const T` or `*mut T`
|
||||
/// where `T = typeof($expr)`.
|
||||
Ref,
|
||||
/// A normal borrow, `&$expr` or `&mut $expr`.
|
||||
/// The resulting type is either `&'a T` or `&'a mut T`
|
||||
/// where `T = typeof($expr)` and `'a` is some lifetime.
|
||||
Ref,
|
||||
/// A raw borrow, `&raw const $expr` or `&raw mut $expr`.
|
||||
/// The resulting type is either `*const T` or `*mut T`
|
||||
/// where `T = typeof($expr)`.
|
||||
Raw,
|
||||
}
|
||||
|
||||
|
112
src/test/mir-opt/address-of.rs
Normal file
112
src/test/mir-opt/address-of.rs
Normal file
@ -0,0 +1,112 @@
|
||||
fn address_of_reborrow() {
|
||||
let y = &[0; 10];
|
||||
let mut z = &mut [0; 10];
|
||||
|
||||
y as *const _;
|
||||
y as *const [i32; 10];
|
||||
y as *const dyn Send;
|
||||
y as *const [i32];
|
||||
y as *const i32; // This is a cast, not a coercion
|
||||
|
||||
let p: *const _ = y;
|
||||
let p: *const [i32; 10] = y;
|
||||
let p: *const dyn Send = y;
|
||||
let p: *const [i32] = y;
|
||||
|
||||
z as *const _;
|
||||
z as *const [i32; 10];
|
||||
z as *const dyn Send;
|
||||
z as *const [i32];
|
||||
|
||||
let p: *const _ = z;
|
||||
let p: *const [i32; 10] = z;
|
||||
let p: *const dyn Send = z;
|
||||
let p: *const [i32] = z;
|
||||
|
||||
z as *mut _;
|
||||
z as *mut [i32; 10];
|
||||
z as *mut dyn Send;
|
||||
z as *mut [i32];
|
||||
|
||||
let p: *mut _ = z;
|
||||
let p: *mut [i32; 10] = z;
|
||||
let p: *mut dyn Send = z;
|
||||
let p: *mut [i32] = z;
|
||||
}
|
||||
|
||||
// The normal borrows here should be preserved
|
||||
fn borrow_and_cast(mut x: i32) {
|
||||
let p = &x as *const i32;
|
||||
let q = &mut x as *const i32;
|
||||
let r = &mut x as *mut i32;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
// START rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _5 = &raw const (*_1); // & to *const casts
|
||||
// ...
|
||||
// _7 = &raw const (*_1);
|
||||
// ...
|
||||
// _11 = &raw const (*_1);
|
||||
// ...
|
||||
// _14 = &raw const (*_1);
|
||||
// ...
|
||||
// _16 = &raw const (*_1);
|
||||
// ...
|
||||
// _17 = &raw const (*_1); // & to *const coercions
|
||||
// ...
|
||||
// _18 = &raw const (*_1);
|
||||
// ...
|
||||
// _20 = &raw const (*_1);
|
||||
// ...
|
||||
// _22 = &raw const (*_1);
|
||||
// ...
|
||||
// _24 = &raw const (*_2); // &mut to *const casts
|
||||
// ...
|
||||
// _26 = &raw const (*_2);
|
||||
// ...
|
||||
// _30 = &raw const (*_2);
|
||||
// ...
|
||||
// _33 = &raw const (*_2);
|
||||
// ...
|
||||
// _34 = &raw const (*_2); // &mut to *const coercions
|
||||
// ...
|
||||
// _35 = &raw const (*_2);
|
||||
// ...
|
||||
// _37 = &raw const (*_2);
|
||||
// ...
|
||||
// _39 = &raw const (*_2);
|
||||
// ...
|
||||
// _41 = &raw mut (*_2); // &mut to *mut casts
|
||||
// ...
|
||||
// _43 = &raw mut (*_2);
|
||||
// ...
|
||||
// _47 = &raw mut (*_2);
|
||||
// ...
|
||||
// _50 = &raw mut (*_2);
|
||||
// ...
|
||||
// _51 = &raw mut (*_2); // &mut to *mut coercions
|
||||
// ...
|
||||
// _52 = &raw mut (*_2);
|
||||
// ...
|
||||
// _54 = &raw mut (*_2);
|
||||
// ...
|
||||
// _56 = &raw mut (*_2);
|
||||
// ...
|
||||
// }
|
||||
// END rustc.address_of_reborrow.SimplifyCfg-initial.after.mir
|
||||
|
||||
// START rustc.borrow_and_cast.EraseRegions.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _4 = &_1;
|
||||
// ...
|
||||
// _7 = &mut _1;
|
||||
// ...
|
||||
// _10 = &mut _1;
|
||||
// ...
|
||||
// }
|
||||
// END rustc.borrow_and_cast.EraseRegions.after.mir
|
@ -18,24 +18,23 @@ fn main() {
|
||||
// START rustc.main.EraseRegions.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _5 = &mut _2;
|
||||
// _4 = &mut (*_5);
|
||||
// _3 = move _4 as *mut usize (Misc);
|
||||
// _4 = &mut _2;
|
||||
// _3 = &raw mut (*_4);
|
||||
// ...
|
||||
// _7 = _3;
|
||||
// _6 = const foo(move _7) -> bb1;
|
||||
// _6 = _3;
|
||||
// _5 = const foo(move _6) -> bb1;
|
||||
// }
|
||||
//
|
||||
// bb1: {
|
||||
// ...
|
||||
// _8 = _2;
|
||||
// _9 = Len(_1);
|
||||
// _10 = Lt(_8, _9);
|
||||
// assert(move _10, "index out of bounds: the len is move _9 but the index is _8") -> bb2;
|
||||
// _7 = _2;
|
||||
// _8 = Len(_1);
|
||||
// _9 = Lt(_7, _8);
|
||||
// assert(move _9, "index out of bounds: the len is move _8 but the index is _7") -> bb2;
|
||||
// }
|
||||
//
|
||||
// bb2: {
|
||||
// _1[_8] = move _6;
|
||||
// _1[_7] = move _5;
|
||||
// ...
|
||||
// return;
|
||||
// }
|
||||
|
@ -11,25 +11,21 @@ fn main() {
|
||||
// START rustc.main.ConstProp.before.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _3 = _4;
|
||||
// _2 = move _3 as *const i32 (Misc);
|
||||
// ...
|
||||
// _2 = &raw const (*_3);
|
||||
// _1 = move _2 as usize (Misc);
|
||||
// ...
|
||||
// _6 = _1;
|
||||
// _5 = const read(move _6) -> bb1;
|
||||
// _5 = _1;
|
||||
// _4 = const read(move _5) -> bb1;
|
||||
// }
|
||||
// END rustc.main.ConstProp.before.mir
|
||||
// START rustc.main.ConstProp.after.mir
|
||||
// bb0: {
|
||||
// ...
|
||||
// _4 = const main::FOO;
|
||||
// _3 = _4;
|
||||
// _2 = move _3 as *const i32 (Misc);
|
||||
// ...
|
||||
// _3 = const main::FOO;
|
||||
// _2 = &raw const (*_3);
|
||||
// _1 = move _2 as usize (Misc);
|
||||
// ...
|
||||
// _6 = _1;
|
||||
// _5 = const read(move _6) -> bb1;
|
||||
// _5 = _1;
|
||||
// _4 = const read(move _5) -> bb1;
|
||||
// }
|
||||
// END rustc.main.ConstProp.after.mir
|
||||
|
@ -82,18 +82,16 @@ fn main() {
|
||||
// _10 = move _8;
|
||||
// Retag(_10);
|
||||
// ...
|
||||
// _13 = &mut (*_10);
|
||||
// Retag(_13);
|
||||
// _12 = move _13 as *mut i32 (Misc);
|
||||
// _12 = &raw mut (*_10);
|
||||
// Retag([raw] _12);
|
||||
// ...
|
||||
// _16 = move _17(move _18) -> bb5;
|
||||
// _15 = move _16(move _17) -> bb5;
|
||||
// }
|
||||
//
|
||||
// bb5: {
|
||||
// Retag(_16);
|
||||
// Retag(_15);
|
||||
// ...
|
||||
// _20 = const Test::foo_shr(move _21, move _23) -> [return: bb6, unwind: bb7];
|
||||
// _19 = const Test::foo_shr(move _20, move _22) -> [return: bb6, unwind: bb7];
|
||||
// }
|
||||
//
|
||||
// ...
|
||||
|
@ -10,15 +10,15 @@ fn main() {
|
||||
// let mut _2: usize;
|
||||
// let mut _3: usize;
|
||||
// let mut _4: usize;
|
||||
// let mut _5: &mut std::string::String;
|
||||
// let mut _5: *mut std::string::String;
|
||||
// let mut _6: bool;
|
||||
// let mut _7: &mut std::string::String;
|
||||
// let mut _7: *mut std::string::String;
|
||||
// let mut _8: bool;
|
||||
// let mut _9: *mut std::string::String;
|
||||
// let mut _10: *mut std::string::String;
|
||||
// let mut _11: &mut std::string::String;
|
||||
// let mut _11: *mut std::string::String;
|
||||
// let mut _12: bool;
|
||||
// let mut _13: &mut std::string::String;
|
||||
// let mut _13: *mut std::string::String;
|
||||
// let mut _14: bool;
|
||||
// let mut _15: *mut [std::string::String];
|
||||
// bb0: {
|
||||
@ -31,7 +31,7 @@ fn main() {
|
||||
// resume;
|
||||
// }
|
||||
// bb3 (cleanup): {
|
||||
// _5 = &mut (*_1)[_4];
|
||||
// _5 = &raw mut (*_1)[_4];
|
||||
// _4 = Add(move _4, const 1usize);
|
||||
// drop((*_5)) -> bb4;
|
||||
// }
|
||||
@ -40,7 +40,7 @@ fn main() {
|
||||
// switchInt(move _6) -> [false: bb3, otherwise: bb2];
|
||||
// }
|
||||
// bb5: {
|
||||
// _7 = &mut (*_1)[_4];
|
||||
// _7 = &raw mut (*_1)[_4];
|
||||
// _4 = Add(move _4, const 1usize);
|
||||
// drop((*_7)) -> [return: bb6, unwind: bb4];
|
||||
// }
|
||||
@ -56,7 +56,7 @@ fn main() {
|
||||
// goto -> bb7;
|
||||
// }
|
||||
// bb9 (cleanup): {
|
||||
// _11 = &mut (*_9);
|
||||
// _11 = _9;
|
||||
// _9 = Offset(move _9, const 1usize);
|
||||
// drop((*_11)) -> bb10;
|
||||
// }
|
||||
@ -65,7 +65,7 @@ fn main() {
|
||||
// switchInt(move _12) -> [false: bb9, otherwise: bb2];
|
||||
// }
|
||||
// bb11: {
|
||||
// _13 = &mut (*_9);
|
||||
// _13 = _9;
|
||||
// _9 = Offset(move _9, const 1usize);
|
||||
// drop((*_13)) -> [return: bb12, unwind: bb10];
|
||||
// }
|
||||
@ -74,7 +74,7 @@ fn main() {
|
||||
// switchInt(move _14) -> [false: bb11, otherwise: bb1];
|
||||
// }
|
||||
// bb13: {
|
||||
// _15 = &mut (*_1);
|
||||
// _15 = &raw mut (*_1);
|
||||
// _9 = move _15 as *mut std::string::String (Misc);
|
||||
// _10 = Offset(_9, move _3);
|
||||
// goto -> bb12;
|
||||
|
12
src/test/pretty/raw-address-of.rs
Normal file
12
src/test/pretty/raw-address-of.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// pp-exact
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const C_PTR: () = { let a = 1; &raw const a; };
|
||||
static S_PTR: () = { let b = false; &raw const b; };
|
||||
|
||||
fn main() {
|
||||
let x = 123;
|
||||
let mut y = 345;
|
||||
let c_p = &raw const x;
|
||||
let parens = unsafe { *(&raw mut (y)) };
|
||||
}
|
22
src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs
Normal file
22
src/test/ui/borrowck/borrow-raw-address-of-borrowed.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn address_of_shared() {
|
||||
let mut x = 0;
|
||||
let y = &x;
|
||||
|
||||
let q = &raw mut x; //~ ERROR cannot borrow
|
||||
|
||||
drop(y);
|
||||
}
|
||||
|
||||
fn address_of_mutably_borrowed() {
|
||||
let mut x = 0;
|
||||
let y = &mut x;
|
||||
|
||||
let p = &raw const x; //~ ERROR cannot borrow
|
||||
let q = &raw mut x; //~ ERROR cannot borrow
|
||||
|
||||
drop(y);
|
||||
}
|
||||
|
||||
fn main() {}
|
40
src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr
Normal file
40
src/test/ui/borrowck/borrow-raw-address-of-borrowed.stderr
Normal file
@ -0,0 +1,40 @@
|
||||
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
|
||||
--> $DIR/borrow-raw-address-of-borrowed.rs:7:13
|
||||
|
|
||||
LL | let y = &x;
|
||||
| -- immutable borrow occurs here
|
||||
LL |
|
||||
LL | let q = &raw mut x;
|
||||
| ^^^^^^^^^^ mutable borrow occurs here
|
||||
LL |
|
||||
LL | drop(y);
|
||||
| - immutable borrow later used here
|
||||
|
||||
error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/borrow-raw-address-of-borrowed.rs:16:13
|
||||
|
|
||||
LL | let y = &mut x;
|
||||
| ------ mutable borrow occurs here
|
||||
LL |
|
||||
LL | let p = &raw const x;
|
||||
| ^^^^^^^^^^^^ immutable borrow occurs here
|
||||
...
|
||||
LL | drop(y);
|
||||
| - mutable borrow later used here
|
||||
|
||||
error[E0499]: cannot borrow `x` as mutable more than once at a time
|
||||
--> $DIR/borrow-raw-address-of-borrowed.rs:17:13
|
||||
|
|
||||
LL | let y = &mut x;
|
||||
| ------ first mutable borrow occurs here
|
||||
...
|
||||
LL | let q = &raw mut x;
|
||||
| ^^^^^^^^^^ second mutable borrow occurs here
|
||||
LL |
|
||||
LL | drop(y);
|
||||
| - first borrow later used here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0499, E0502.
|
||||
For more information about an error, try `rustc --explain E0499`.
|
@ -0,0 +1,23 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn raw_reborrow() {
|
||||
let x = &0;
|
||||
let y = &mut 0;
|
||||
|
||||
let p = &raw const *x;
|
||||
let r = &raw const *y;
|
||||
let s = &raw mut *y;
|
||||
}
|
||||
|
||||
unsafe fn raw_reborrow_of_raw() {
|
||||
let x = &0 as *const i32;
|
||||
let y = &mut 0 as *mut i32;
|
||||
|
||||
let p = &raw const *x;
|
||||
let r = &raw const *y;
|
||||
let s = &raw mut *y;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,17 @@
|
||||
// Check that `&raw mut` cannot be used to turn a `&T` into a `*mut T`.
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn raw_reborrow() {
|
||||
let x = &0;
|
||||
|
||||
let q = &raw mut *x; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
unsafe fn raw_reborrow_of_raw() {
|
||||
let x = &0 as *const i32;
|
||||
|
||||
let q = &raw mut *x; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,21 @@
|
||||
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference
|
||||
--> $DIR/borrow-raw-address-of-deref-mutability.rs:8:13
|
||||
|
|
||||
LL | let x = &0;
|
||||
| -- help: consider changing this to be a mutable reference: `&mut 0`
|
||||
LL |
|
||||
LL | let q = &raw mut *x;
|
||||
| ^^^^^^^^^^^ `x` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
||||
|
||||
error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer
|
||||
--> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13
|
||||
|
|
||||
LL | let x = &0 as *const i32;
|
||||
| -- help: consider changing this to be a mutable pointer: `&mut 0`
|
||||
LL |
|
||||
LL | let q = &raw mut *x;
|
||||
| ^^^^^^^^^^^ `x` is a `*const` pointer, so the data it refers to cannot be borrowed as mutable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
44
src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
Normal file
44
src/test/ui/borrowck/borrow-raw-address-of-mutability-ok.rs
Normal file
@ -0,0 +1,44 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn mutable_address_of() {
|
||||
let mut x = 0;
|
||||
let y = &raw mut x;
|
||||
}
|
||||
|
||||
fn mutable_address_of_closure() {
|
||||
let mut x = 0;
|
||||
let mut f = || {
|
||||
let y = &raw mut x;
|
||||
};
|
||||
f();
|
||||
}
|
||||
|
||||
fn const_address_of_closure() {
|
||||
let x = 0;
|
||||
let f = || {
|
||||
let y = &raw const x;
|
||||
};
|
||||
f();
|
||||
}
|
||||
|
||||
fn make_fn<F: Fn()>(f: F) -> F { f }
|
||||
|
||||
fn const_address_of_fn_closure() {
|
||||
let x = 0;
|
||||
let f = make_fn(|| {
|
||||
let y = &raw const x;
|
||||
});
|
||||
f();
|
||||
}
|
||||
|
||||
fn const_address_of_fn_closure_move() {
|
||||
let x = 0;
|
||||
let f = make_fn(move || {
|
||||
let y = &raw const x;
|
||||
});
|
||||
f();
|
||||
}
|
||||
|
||||
fn main() {}
|
42
src/test/ui/borrowck/borrow-raw-address-of-mutability.rs
Normal file
42
src/test/ui/borrowck/borrow-raw-address-of-mutability.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn mutable_address_of() {
|
||||
let x = 0;
|
||||
let y = &raw mut x; //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn mutable_address_of_closure() {
|
||||
let x = 0;
|
||||
let mut f = || {
|
||||
let y = &raw mut x; //~ ERROR cannot borrow
|
||||
};
|
||||
f();
|
||||
}
|
||||
|
||||
fn mutable_address_of_imm_closure() {
|
||||
let mut x = 0;
|
||||
let f = || {
|
||||
let y = &raw mut x;
|
||||
};
|
||||
f(); //~ ERROR cannot borrow
|
||||
}
|
||||
|
||||
fn make_fn<F: Fn()>(f: F) -> F { f }
|
||||
|
||||
fn mutable_address_of_fn_closure() {
|
||||
let mut x = 0;
|
||||
let f = make_fn(|| {
|
||||
let y = &raw mut x; //~ ERROR cannot borrow
|
||||
});
|
||||
f();
|
||||
}
|
||||
|
||||
fn mutable_address_of_fn_closure_move() {
|
||||
let mut x = 0;
|
||||
let f = make_fn(move || {
|
||||
let y = &raw mut x; //~ ERROR cannot borrow
|
||||
});
|
||||
f();
|
||||
}
|
||||
|
||||
fn main() {}
|
59
src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
Normal file
59
src/test/ui/borrowck/borrow-raw-address-of-mutability.stderr
Normal file
@ -0,0 +1,59 @@
|
||||
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:5:13
|
||||
|
|
||||
LL | let x = 0;
|
||||
| - help: consider changing this to be mutable: `mut x`
|
||||
LL | let y = &raw mut x;
|
||||
| ^^^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:11:17
|
||||
|
|
||||
LL | let x = 0;
|
||||
| - help: consider changing this to be mutable: `mut x`
|
||||
LL | let mut f = || {
|
||||
LL | let y = &raw mut x;
|
||||
| ^^^^^^^^^^ cannot borrow as mutable
|
||||
|
||||
error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:21:5
|
||||
|
|
||||
LL | let f = || {
|
||||
| - help: consider changing this to be mutable: `mut f`
|
||||
...
|
||||
LL | f();
|
||||
| ^ cannot borrow as mutable
|
||||
|
||||
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:29:17
|
||||
|
|
||||
LL | let y = &raw mut x;
|
||||
| ^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
help: consider changing this to accept closures that implement `FnMut`
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:28:21
|
||||
|
|
||||
LL | let f = make_fn(|| {
|
||||
| _____________________^
|
||||
LL | | let y = &raw mut x;
|
||||
LL | | });
|
||||
| |_____^
|
||||
|
||||
error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:37:17
|
||||
|
|
||||
LL | let y = &raw mut x;
|
||||
| ^^^^^^^^^^ cannot borrow as mutable
|
||||
|
|
||||
help: consider changing this to accept closures that implement `FnMut`
|
||||
--> $DIR/borrow-raw-address-of-mutability.rs:36:21
|
||||
|
|
||||
LL | let f = make_fn(move || {
|
||||
| _____________________^
|
||||
LL | | let y = &raw mut x;
|
||||
LL | | });
|
||||
| |_____^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0596`.
|
@ -5,5 +5,5 @@ fn main() {
|
||||
let t = (1 + 2) as bool; //~ ERROR cannot cast as `bool`
|
||||
//~| HELP compare with zero instead
|
||||
//~| SUGGESTION (1 + 2) != 0
|
||||
let v = "hello" as bool; //~ ERROR cannot cast as `bool`
|
||||
let v = "hello" as bool; //~ ERROR casting `&'static str` as `bool` is invalid
|
||||
}
|
||||
|
@ -10,12 +10,13 @@ error[E0054]: cannot cast as `bool`
|
||||
LL | let t = (1 + 2) as bool;
|
||||
| ^^^^^^^^^^^^^^^ help: compare with zero instead: `(1 + 2) != 0`
|
||||
|
||||
error[E0054]: cannot cast as `bool`
|
||||
error[E0606]: casting `&'static str` as `bool` is invalid
|
||||
--> $DIR/cast-as-bool.rs:8:13
|
||||
|
|
||||
LL | let v = "hello" as bool;
|
||||
| ^^^^^^^^^^^^^^^ unsupported cast
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0054`.
|
||||
Some errors have detailed explanations: E0054, E0606.
|
||||
For more information about an error, try `rustc --explain E0054`.
|
||||
|
16
src/test/ui/consts/const-address-of-interior-mut.rs
Normal file
16
src/test/ui/consts/const-address-of-interior-mut.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
const A: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
|
||||
|
||||
static B: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
|
||||
|
||||
static mut C: () = { let x = Cell::new(2); &raw const x; }; //~ ERROR interior mutability
|
||||
|
||||
const fn foo() {
|
||||
let x = Cell::new(0);
|
||||
let y = &raw const x; //~ ERROR interior mutability
|
||||
}
|
||||
|
||||
fn main() {}
|
27
src/test/ui/consts/const-address-of-interior-mut.stderr
Normal file
27
src/test/ui/consts/const-address-of-interior-mut.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
|
||||
--> $DIR/const-address-of-interior-mut.rs:5:39
|
||||
|
|
||||
LL | const A: () = { let x = Cell::new(2); &raw const x; };
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
|
||||
--> $DIR/const-address-of-interior-mut.rs:7:40
|
||||
|
|
||||
LL | static B: () = { let x = Cell::new(2); &raw const x; };
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
|
||||
--> $DIR/const-address-of-interior-mut.rs:9:44
|
||||
|
|
||||
LL | static mut C: () = { let x = Cell::new(2); &raw const x; };
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error[E0492]: cannot borrow a constant which may contain interior mutability, create a static instead
|
||||
--> $DIR/const-address-of-interior-mut.rs:13:13
|
||||
|
|
||||
LL | let y = &raw const x;
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0492`.
|
14
src/test/ui/consts/const-address-of-mut.rs
Normal file
14
src/test/ui/consts/const-address-of-mut.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const A: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed
|
||||
|
||||
static B: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed
|
||||
|
||||
static mut C: () = { let mut x = 2; &raw mut x; }; //~ ERROR `&raw mut` is not allowed
|
||||
|
||||
const fn foo() {
|
||||
let mut x = 0;
|
||||
let y = &raw mut x; //~ ERROR `&raw mut` is not allowed
|
||||
}
|
||||
|
||||
fn main() {}
|
39
src/test/ui/consts/const-address-of-mut.stderr
Normal file
39
src/test/ui/consts/const-address-of-mut.stderr
Normal file
@ -0,0 +1,39 @@
|
||||
error[E0658]: `&raw mut` is not allowed in constants
|
||||
--> $DIR/const-address-of-mut.rs:3:32
|
||||
|
|
||||
LL | const A: () = { let mut x = 2; &raw mut x; };
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `&raw mut` is not allowed in statics
|
||||
--> $DIR/const-address-of-mut.rs:5:33
|
||||
|
|
||||
LL | static B: () = { let mut x = 2; &raw mut x; };
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `&raw mut` is not allowed in statics
|
||||
--> $DIR/const-address-of-mut.rs:7:37
|
||||
|
|
||||
LL | static mut C: () = { let mut x = 2; &raw mut x; };
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `&raw mut` is not allowed in constant functions
|
||||
--> $DIR/const-address-of-mut.rs:11:13
|
||||
|
|
||||
LL | let y = &raw mut x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
19
src/test/ui/consts/const-address-of.rs
Normal file
19
src/test/ui/consts/const-address-of.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const A: *const i32 = &raw const *&2;
|
||||
static B: () = { &raw const *&2; };
|
||||
static mut C: *const i32 = &raw const *&2;
|
||||
const D: () = { let x = 2; &raw const x; };
|
||||
static E: () = { let x = 2; &raw const x; };
|
||||
static mut F: () = { let x = 2; &raw const x; };
|
||||
|
||||
const fn const_ptr() {
|
||||
let x = 0;
|
||||
let ptr = &raw const x;
|
||||
let r = &x;
|
||||
let ptr2 = &raw const *r;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -2,7 +2,6 @@
|
||||
#![allow(unused)]
|
||||
#![allow(const_err)] // make sure we cannot allow away the errors tested here
|
||||
|
||||
// normalize-stderr-test "alignment \d+" -> "alignment N"
|
||||
// normalize-stderr-test "offset \d+" -> "offset N"
|
||||
// normalize-stderr-test "allocation \d+" -> "allocation N"
|
||||
// normalize-stderr-test "size \d+" -> "size N"
|
||||
@ -149,11 +148,23 @@ impl Trait for bool {}
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
|
||||
// # raw trait object
|
||||
const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust};
|
||||
const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust};
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust};
|
||||
//~^ ERROR it is undefined behavior to use this value
|
||||
const RAW_TRAIT_OBJ_CONTENT_INVALID: *const dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl } as *const _; // ok because raw
|
||||
|
||||
// Const eval fails for these, so they need to be statics to error.
|
||||
static mut RAW_TRAIT_OBJ_VTABLE_NULL_THROUGH_REF: *const dyn Trait = unsafe {
|
||||
DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
};
|
||||
static mut RAW_TRAIT_OBJ_VTABLE_INVALID_THROUGH_REF: *const dyn Trait = unsafe {
|
||||
DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust
|
||||
//~^ ERROR could not evaluate static initializer
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let _ = RAW_TRAIT_OBJ_VTABLE_NULL;
|
||||
let _ = RAW_TRAIT_OBJ_VTABLE_INVALID;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:87:1
|
||||
--> $DIR/ub-wide-ptr.rs:86:1
|
||||
|
|
||||
LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds)
|
||||
@ -7,7 +7,7 @@ LL | const STR_TOO_LONG: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr:
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:90:1
|
||||
--> $DIR/ub-wide-ptr.rs:89:1
|
||||
|
|
||||
LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
|
||||
@ -15,7 +15,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { SliceTransmute { bad: BadSliceRepr {
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:93:1
|
||||
--> $DIR/ub-wide-ptr.rs:92:1
|
||||
|
|
||||
LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
|
||||
@ -23,7 +23,7 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { SliceTransmute { bad: BadSliceRe
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:97:1
|
||||
--> $DIR/ub-wide-ptr.rs:96:1
|
||||
|
|
||||
LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
|
||||
@ -31,7 +31,7 @@ LL | const STR_NO_UTF8: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:100:1
|
||||
--> $DIR/ub-wide-ptr.rs:99:1
|
||||
|
|
||||
LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
|
||||
@ -39,7 +39,7 @@ LL | const MYSTR_NO_UTF8: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:107:1
|
||||
--> $DIR/ub-wide-ptr.rs:106:1
|
||||
|
|
||||
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
|
||||
@ -47,7 +47,7 @@ LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.sli
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:110:1
|
||||
--> $DIR/ub-wide-ptr.rs:109:1
|
||||
|
|
||||
LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling reference (not entirely in bounds)
|
||||
@ -55,7 +55,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { p
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:113:1
|
||||
--> $DIR/ub-wide-ptr.rs:112:1
|
||||
|
|
||||
LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer
|
||||
@ -63,7 +63,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:117:1
|
||||
--> $DIR/ub-wide-ptr.rs:116:1
|
||||
|
|
||||
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something less or equal to 1
|
||||
@ -71,7 +71,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { BoolTransmute { val: 3 }.
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:123:1
|
||||
--> $DIR/ub-wide-ptr.rs:122:1
|
||||
|
|
||||
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something less or equal to 1
|
||||
@ -79,7 +79,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { BoolTransmute {
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:126:1
|
||||
--> $DIR/ub-wide-ptr.rs:125:1
|
||||
|
|
||||
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something less or equal to 1
|
||||
@ -87,7 +87,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { BoolTrans
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:133:1
|
||||
--> $DIR/ub-wide-ptr.rs:132:1
|
||||
|
|
||||
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
|
||||
@ -95,7 +95,7 @@ LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:138:1
|
||||
--> $DIR/ub-wide-ptr.rs:137:1
|
||||
|
|
||||
LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
@ -103,7 +103,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { DynTransmute { repr:
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:141:1
|
||||
--> $DIR/ub-wide-ptr.rs:140:1
|
||||
|
|
||||
LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
@ -111,7 +111,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { DynTransmute { repr2:
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:144:1
|
||||
--> $DIR/ub-wide-ptr.rs:143:1
|
||||
|
|
||||
LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
@ -119,7 +119,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { DynTransmute { bad: BadDy
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:148:1
|
||||
--> $DIR/ub-wide-ptr.rs:147:1
|
||||
|
|
||||
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val: 3 }.bl };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.<dyn-downcast>, but expected something less or equal to 1
|
||||
@ -127,21 +127,33 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = &unsafe { BoolTransmute { val
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:152:1
|
||||
--> $DIR/ub-wide-ptr.rs:151:1
|
||||
|
|
||||
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.raw_rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error[E0080]: it is undefined behavior to use this value
|
||||
--> $DIR/ub-wide-ptr.rs:154:1
|
||||
--> $DIR/ub-wide-ptr.rs:153:1
|
||||
|
|
||||
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.raw_rust};
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable
|
||||
|
|
||||
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
|
||||
|
||||
error: aborting due to 18 previous errors
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/ub-wide-ptr.rs:159:5
|
||||
|
|
||||
LL | DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 0 } }.rust
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer
|
||||
|
||||
error[E0080]: could not evaluate static initializer
|
||||
--> $DIR/ub-wide-ptr.rs:163:5
|
||||
|
|
||||
LL | DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N
|
||||
|
||||
error: aborting due to 20 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
||||
|
30
src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
Normal file
30
src/test/ui/consts/const-mut-refs/const_mut_address_of.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(const_mut_refs)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
struct Foo {
|
||||
x: usize
|
||||
}
|
||||
|
||||
const fn foo() -> Foo {
|
||||
Foo { x: 0 }
|
||||
}
|
||||
|
||||
impl Foo {
|
||||
const fn bar(&mut self) -> *mut usize {
|
||||
&raw mut self.x
|
||||
}
|
||||
}
|
||||
|
||||
const fn baz(foo: &mut Foo)-> *mut usize {
|
||||
&raw mut foo.x
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
foo().bar();
|
||||
baz(&mut foo());
|
||||
};
|
||||
|
||||
fn main() {}
|
7
src/test/ui/consts/const-prop-ice3.rs
Normal file
7
src/test/ui/consts/const-prop-ice3.rs
Normal file
@ -0,0 +1,7 @@
|
||||
// run-pass (ensure that const-prop is run)
|
||||
|
||||
struct A<T: ?Sized>(T);
|
||||
|
||||
fn main() {
|
||||
let _x = &(&A([2, 3]) as &A<[i32]>).0 as *const [i32] as *const i32;
|
||||
}
|
17
src/test/ui/consts/min_const_fn/address_of.rs
Normal file
17
src/test/ui/consts/min_const_fn/address_of.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const fn mutable_address_of_in_const() {
|
||||
let mut a = 0;
|
||||
let b = &raw mut a; //~ ERROR `&raw mut` is not allowed
|
||||
}
|
||||
|
||||
struct X;
|
||||
|
||||
impl X {
|
||||
const fn inherent_mutable_address_of_in_const() {
|
||||
let mut a = 0;
|
||||
let b = &raw mut a; //~ ERROR `&raw mut` is not allowed
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
21
src/test/ui/consts/min_const_fn/address_of.stderr
Normal file
21
src/test/ui/consts/min_const_fn/address_of.stderr
Normal file
@ -0,0 +1,21 @@
|
||||
error[E0658]: `&raw mut` is not allowed in constant functions
|
||||
--> $DIR/address_of.rs:5:13
|
||||
|
|
||||
LL | let b = &raw mut a;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: `&raw mut` is not allowed in constant functions
|
||||
--> $DIR/address_of.rs:13:17
|
||||
|
|
||||
LL | let b = &raw mut a;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/57349
|
||||
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
19
src/test/ui/consts/min_const_fn/address_of_const.rs
Normal file
19
src/test/ui/consts/min_const_fn/address_of_const.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const fn const_address_of_in_const() {
|
||||
let mut a = 0;
|
||||
let b = &raw const a;
|
||||
}
|
||||
|
||||
struct X;
|
||||
|
||||
impl X {
|
||||
const fn inherent_const_address_of_in_const() {
|
||||
let mut a = 0;
|
||||
let b = &raw const a;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -3,7 +3,7 @@
|
||||
// Exercise the unused_mut attribute in some positive and negative cases
|
||||
|
||||
#![deny(unused_mut)]
|
||||
#![feature(async_closure)]
|
||||
#![feature(async_closure, raw_ref_op)]
|
||||
|
||||
async fn baz_async(
|
||||
mut a: i32,
|
||||
@ -177,6 +177,12 @@ fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
|
||||
// leading underscore should avoid the warning, just like the
|
||||
// unused variable lint.
|
||||
let mut _allowed = 1;
|
||||
|
||||
let mut raw_address_of_mut = 1; // OK
|
||||
let mut_ptr = &raw mut raw_address_of_mut;
|
||||
|
||||
let mut raw_address_of_const = 1; //~ ERROR: variable does not need to be mutable
|
||||
let const_ptr = &raw const raw_address_of_const;
|
||||
}
|
||||
|
||||
fn callback<F>(f: F) where F: FnOnce() {}
|
||||
|
@ -180,6 +180,14 @@ LL | let mut v : &mut Vec<()> = &mut vec![];
|
||||
| |
|
||||
| help: remove this `mut`
|
||||
|
||||
error: variable does not need to be mutable
|
||||
--> $DIR/lint-unused-mut-variables.rs:184:9
|
||||
|
|
||||
LL | let mut raw_address_of_const = 1;
|
||||
| ----^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| help: remove this `mut`
|
||||
|
||||
error: variable does not need to be mutable
|
||||
--> $DIR/lint-unused-mut-variables.rs:106:13
|
||||
|
|
||||
@ -197,7 +205,7 @@ LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
|
||||
| help: remove this `mut`
|
||||
|
||||
error: variable does not need to be mutable
|
||||
--> $DIR/lint-unused-mut-variables.rs:196:9
|
||||
--> $DIR/lint-unused-mut-variables.rs:202:9
|
||||
|
|
||||
LL | let mut b = vec![2];
|
||||
| ----^
|
||||
@ -205,10 +213,10 @@ LL | let mut b = vec![2];
|
||||
| help: remove this `mut`
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/lint-unused-mut-variables.rs:192:8
|
||||
--> $DIR/lint-unused-mut-variables.rs:198:8
|
||||
|
|
||||
LL | #[deny(unused_mut)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: aborting due to 25 previous errors
|
||||
error: aborting due to 26 previous errors
|
||||
|
||||
|
37
src/test/ui/packed/packed-struct-address-of-element.rs
Normal file
37
src/test/ui/packed/packed-struct-address-of-element.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// run-pass
|
||||
#![allow(dead_code)]
|
||||
#![deny(safe_packed_borrows)]
|
||||
#![feature(raw_ref_op)]
|
||||
// ignore-emscripten weird assertion?
|
||||
|
||||
#[repr(packed)]
|
||||
struct Foo1 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(packed(2))]
|
||||
struct Foo2 {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
#[repr(C, packed(4))]
|
||||
struct Foo4C {
|
||||
bar: u8,
|
||||
baz: usize
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let foo = Foo1 { bar: 1, baz: 2 };
|
||||
let brw = &raw const foo.baz;
|
||||
unsafe { assert_eq!(brw.read_unaligned(), 2); }
|
||||
|
||||
let foo = Foo2 { bar: 1, baz: 2 };
|
||||
let brw = &raw const foo.baz;
|
||||
unsafe { assert_eq!(brw.read_unaligned(), 2); }
|
||||
|
||||
let mut foo = Foo4C { bar: 1, baz: 2 };
|
||||
let brw = &raw mut foo.baz;
|
||||
unsafe { assert_eq!(brw.read_unaligned(), 2); }
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// run-pass
|
||||
// run-pass (note: this is spec-UB, but it works for now)
|
||||
#![allow(dead_code)]
|
||||
// ignore-emscripten weird assertion?
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
// FIXME(#64490): make this run-pass
|
||||
// run-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
fn main() {
|
||||
let mut x = 123;
|
||||
let c_p = &raw const x; //~ ERROR not yet implemented
|
||||
let m_p = &raw mut x; //~ ERROR not yet implemented
|
||||
let c_p = &raw const x;
|
||||
let m_p = &raw mut x;
|
||||
let i_r = &x;
|
||||
assert!(c_p == i_r);
|
||||
assert!(c_p == m_p);
|
||||
|
@ -1,18 +0,0 @@
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-op.rs:7:15
|
||||
|
|
||||
LL | let c_p = &raw const x;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-op.rs:8:15
|
||||
|
|
||||
LL | let m_p = &raw mut x;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -1,4 +1,4 @@
|
||||
// FIXME(#64490) This should be check-pass
|
||||
// check-pass
|
||||
// Check that taking the address of a place that contains a dereference is
|
||||
// allowed.
|
||||
#![feature(raw_ref_op, type_ascription)]
|
||||
@ -10,15 +10,15 @@
|
||||
|
||||
fn main() {
|
||||
// These are all OK, we're not taking the address of the temporary
|
||||
let deref_ref = &raw const *PAIR_REF; //~ ERROR not yet implemented
|
||||
let field_deref_ref = &raw const PAIR_REF.0; //~ ERROR not yet implemented
|
||||
let deref_ref = &raw const *ARRAY_REF; //~ ERROR not yet implemented
|
||||
let index_deref_ref = &raw const ARRAY_REF[0]; //~ ERROR not yet implemented
|
||||
let deref_ref = &raw const *SLICE_REF; //~ ERROR not yet implemented
|
||||
let index_deref_ref = &raw const SLICE_REF[1]; //~ ERROR not yet implemented
|
||||
let deref_ref = &raw const *PAIR_REF;
|
||||
let field_deref_ref = &raw const PAIR_REF.0;
|
||||
let deref_ref = &raw const *ARRAY_REF;
|
||||
let index_deref_ref = &raw const ARRAY_REF[0];
|
||||
let deref_ref = &raw const *SLICE_REF;
|
||||
let index_deref_ref = &raw const SLICE_REF[1];
|
||||
|
||||
let x = 0;
|
||||
let ascribe_ref = &raw const (x: i32); //~ ERROR not yet implemented
|
||||
let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]); //~ ERROR not yet implemented
|
||||
let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32); //~ ERROR not yet implemented
|
||||
let ascribe_ref = &raw const (x: i32);
|
||||
let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);
|
||||
let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);
|
||||
}
|
||||
|
@ -1,74 +0,0 @@
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:13:21
|
||||
|
|
||||
LL | let deref_ref = &raw const *PAIR_REF;
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:14:27
|
||||
|
|
||||
LL | let field_deref_ref = &raw const PAIR_REF.0;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:15:21
|
||||
|
|
||||
LL | let deref_ref = &raw const *ARRAY_REF;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:16:27
|
||||
|
|
||||
LL | let index_deref_ref = &raw const ARRAY_REF[0];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:17:21
|
||||
|
|
||||
LL | let deref_ref = &raw const *SLICE_REF;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:18:27
|
||||
|
|
||||
LL | let index_deref_ref = &raw const SLICE_REF[1];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:21:23
|
||||
|
|
||||
LL | let ascribe_ref = &raw const (x: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:22:25
|
||||
|
|
||||
LL | let ascribe_deref = &raw const (*ARRAY_REF: [i32; 2]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/raw-ref-temp-deref.rs:23:31
|
||||
|
|
||||
LL | let ascribe_index_deref = &raw const (ARRAY_REF[0]: i32);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: aborting due to 9 previous errors
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Ensure that we don't allow taking the address of temporary values
|
||||
#![feature(raw_ref_op, type_ascription)]
|
||||
|
||||
const FOUR: u64 = 4;
|
||||
|
||||
const PAIR: (i32, i64) = (1, 2);
|
||||
|
||||
const ARRAY: [i32; 2] = [1, 2];
|
||||
@ -8,8 +10,8 @@
|
||||
fn main() {
|
||||
let ref_expr = &raw const 2; //~ ERROR cannot take address
|
||||
let mut_ref_expr = &raw mut 3; //~ ERROR cannot take address
|
||||
let ref_const = &raw const 4; //~ ERROR cannot take address
|
||||
let mut_ref_const = &raw mut 5; //~ ERROR cannot take address
|
||||
let ref_const = &raw const FOUR; //~ ERROR cannot take address
|
||||
let mut_ref_const = &raw mut FOUR; //~ ERROR cannot take address
|
||||
|
||||
let field_ref_expr = &raw const (1, 2).0; //~ ERROR cannot take address
|
||||
let mut_field_ref_expr = &raw mut (1, 2).0; //~ ERROR cannot take address
|
||||
|
@ -1,95 +1,95 @@
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:9:31
|
||||
--> $DIR/raw-ref-temp.rs:11:31
|
||||
|
|
||||
LL | let ref_expr = &raw const 2;
|
||||
| ^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:10:33
|
||||
--> $DIR/raw-ref-temp.rs:12:33
|
||||
|
|
||||
LL | let mut_ref_expr = &raw mut 3;
|
||||
| ^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:11:32
|
||||
--> $DIR/raw-ref-temp.rs:13:32
|
||||
|
|
||||
LL | let ref_const = &raw const 4;
|
||||
| ^ temporary value
|
||||
LL | let ref_const = &raw const FOUR;
|
||||
| ^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:12:34
|
||||
--> $DIR/raw-ref-temp.rs:14:34
|
||||
|
|
||||
LL | let mut_ref_const = &raw mut 5;
|
||||
| ^ temporary value
|
||||
LL | let mut_ref_const = &raw mut FOUR;
|
||||
| ^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:14:37
|
||||
--> $DIR/raw-ref-temp.rs:16:37
|
||||
|
|
||||
LL | let field_ref_expr = &raw const (1, 2).0;
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:15:39
|
||||
--> $DIR/raw-ref-temp.rs:17:39
|
||||
|
|
||||
LL | let mut_field_ref_expr = &raw mut (1, 2).0;
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:16:32
|
||||
--> $DIR/raw-ref-temp.rs:18:32
|
||||
|
|
||||
LL | let field_ref = &raw const PAIR.0;
|
||||
| ^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:17:34
|
||||
--> $DIR/raw-ref-temp.rs:19:34
|
||||
|
|
||||
LL | let mut_field_ref = &raw mut PAIR.0;
|
||||
| ^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:19:37
|
||||
--> $DIR/raw-ref-temp.rs:21:37
|
||||
|
|
||||
LL | let index_ref_expr = &raw const [1, 2][0];
|
||||
| ^^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:20:39
|
||||
--> $DIR/raw-ref-temp.rs:22:39
|
||||
|
|
||||
LL | let mut_index_ref_expr = &raw mut [1, 2][0];
|
||||
| ^^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:21:32
|
||||
--> $DIR/raw-ref-temp.rs:23:32
|
||||
|
|
||||
LL | let index_ref = &raw const ARRAY[0];
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:22:34
|
||||
--> $DIR/raw-ref-temp.rs:24:34
|
||||
|
|
||||
LL | let mut_index_ref = &raw mut ARRAY[1];
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:24:34
|
||||
--> $DIR/raw-ref-temp.rs:26:34
|
||||
|
|
||||
LL | let ref_ascribe = &raw const (2: i32);
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:25:36
|
||||
--> $DIR/raw-ref-temp.rs:27:36
|
||||
|
|
||||
LL | let mut_ref_ascribe = &raw mut (3: i32);
|
||||
| ^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:27:40
|
||||
--> $DIR/raw-ref-temp.rs:29:40
|
||||
|
|
||||
LL | let ascribe_field_ref = &raw const (PAIR.0: i32);
|
||||
| ^^^^^^^^^^^^^ temporary value
|
||||
|
||||
error[E0745]: cannot take address of a temporary
|
||||
--> $DIR/raw-ref-temp.rs:28:38
|
||||
--> $DIR/raw-ref-temp.rs:30:38
|
||||
|
|
||||
LL | let ascribe_index_ref = &raw mut (ARRAY[0]: i32);
|
||||
| ^^^^^^^^^^^^^^^ temporary value
|
||||
|
@ -1,25 +1,22 @@
|
||||
// FIXME(#64490): make this check-pass
|
||||
// check-pass
|
||||
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const USES_PTR: () = { let u = (); &raw const u; }; //~ ERROR not yet implemented
|
||||
static ALSO_USES_PTR: () = { let u = (); &raw const u; }; //~ ERROR not yet implemented
|
||||
const USES_PTR: () = { let u = (); &raw const u; };
|
||||
static ALSO_USES_PTR: () = { let u = (); &raw const u; };
|
||||
|
||||
fn main() {
|
||||
#[cfg(FALSE)]
|
||||
{
|
||||
let x: [i32; { let u = 2; let x = &raw const u; 4 }]
|
||||
= [2; { let v = 3; let y = &raw const v; 4 }];
|
||||
let mut one = 1;
|
||||
let two = 2;
|
||||
if &raw const one == &raw mut one {
|
||||
match &raw const two {
|
||||
_ => {}
|
||||
}
|
||||
let x: [i32; { let u = 2; let x = &raw const u; 4 }]
|
||||
= [2; { let v = 3; let y = &raw const v; 4 }];
|
||||
let mut one = 1;
|
||||
let two = 2;
|
||||
if &raw const one == &raw mut one {
|
||||
match &raw const two {
|
||||
_ => {}
|
||||
}
|
||||
let three = 3;
|
||||
let mut four = 4;
|
||||
println!("{:p}", &raw const three);
|
||||
unsafe { &raw mut four; }
|
||||
}
|
||||
let three = 3;
|
||||
let mut four = 4;
|
||||
println!("{:p}", &raw const three);
|
||||
unsafe { &raw mut four; }
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/unusual_locations.rs:5:36
|
||||
|
|
||||
LL | const USES_PTR: () = { let u = (); &raw const u; };
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: raw borrows are not yet implemented
|
||||
--> $DIR/unusual_locations.rs:6:42
|
||||
|
|
||||
LL | static ALSO_USES_PTR: () = { let u = (); &raw const u; };
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: for more information, see https://github.com/rust-lang/rust/issues/64490
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user