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:
Mazdak Farrokhzad 2019-12-20 17:22:16 +01:00 committed by GitHub
commit ef01330887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
69 changed files with 1158 additions and 515 deletions

View File

@ -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) => {

View File

@ -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) => {

View File

@ -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:
///

View File

@ -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,
}

View File

@ -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);
}

View File

@ -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: [],

View File

@ -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(..) |

View File

@ -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;

View File

@ -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)

View File

@ -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)

View File

@ -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(..)

View File

@ -276,6 +276,7 @@ fn expr_as_place(
| ExprKind::Pointer { .. }
| ExprKind::Repeat { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Match { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }

View File

@ -276,6 +276,7 @@ fn expr_as_rvalue(
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Borrow { .. }
| ExprKind::AddressOf { .. }
| ExprKind::Adt { .. }
| ExprKind::Loop { .. }
| ExprKind::LogicalOp { .. }

View File

@ -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 { .. }

View File

@ -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,

View File

@ -335,6 +335,7 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
}
}
Rvalue::Ref(..)
| Rvalue::AddressOf(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
| Rvalue::NullaryOp(NullOp::SizeOf, _)

View File

@ -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,

View File

@ -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>>,

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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,
});
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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),
}
}

View File

@ -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)

View File

@ -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) |

View File

@ -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),

View File

@ -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,
}

View 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

View File

@ -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;
// }

View File

@ -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

View File

@ -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];
// }
//
// ...

View File

@ -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;

View 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)) };
}

View 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() {}

View 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`.

View File

@ -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() {}

View File

@ -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() {}

View File

@ -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`.

View 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() {}

View 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() {}

View 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`.

View File

@ -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
}

View File

@ -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`.

View 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() {}

View 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`.

View 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() {}

View 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`.

View 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() {}

View File

@ -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;
}

View File

@ -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`.

View 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() {}

View 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;
}

View 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() {}

View 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`.

View 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() {}

View File

@ -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() {}

View File

@ -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

View 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); }
}

View File

@ -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?

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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; }
}

View File

@ -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