mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 08:44:35 +00:00
Add raw address of expressions to the AST and HIR
This commit is contained in:
parent
9420ff4c0e
commit
a8efd31f2b
@ -1024,7 +1024,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
||||
visitor.visit_expr(left_expression);
|
||||
visitor.visit_expr(right_expression)
|
||||
}
|
||||
ExprKind::AddrOf(_, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
|
||||
ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
|
||||
visitor.visit_expr(subexpression)
|
||||
}
|
||||
ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
|
||||
|
@ -65,9 +65,9 @@ impl LoweringContext<'_> {
|
||||
let expr = P(self.lower_expr(expr));
|
||||
hir::ExprKind::Type(expr, self.lower_ty(ty, ImplTraitContext::disallowed()))
|
||||
}
|
||||
ExprKind::AddrOf(m, ref ohs) => {
|
||||
ExprKind::AddrOf(k, m, ref ohs) => {
|
||||
let ohs = P(self.lower_expr(ohs));
|
||||
hir::ExprKind::AddrOf(m, ohs)
|
||||
hir::ExprKind::AddrOf(k, m, ohs)
|
||||
}
|
||||
ExprKind::Let(ref pat, ref scrutinee) => self.lower_expr_let(e.span, pat, scrutinee),
|
||||
ExprKind::If(ref cond, ref then, ref else_opt) => {
|
||||
@ -1339,7 +1339,11 @@ impl LoweringContext<'_> {
|
||||
}
|
||||
|
||||
fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
|
||||
self.expr(span, hir::ExprKind::AddrOf(hir::Mutability::Mutable, e), ThinVec::new())
|
||||
self.expr(
|
||||
span,
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Mutable, e),
|
||||
ThinVec::new(),
|
||||
)
|
||||
}
|
||||
|
||||
fn expr_unit(&mut self, sp: Span) -> hir::Expr {
|
||||
|
@ -21,7 +21,8 @@ use syntax_pos::{Span, DUMMY_SP, MultiSpan};
|
||||
use syntax::source_map::Spanned;
|
||||
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect};
|
||||
use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy};
|
||||
pub use syntax::ast::{Mutability, Constness, Unsafety, Movability, CaptureBy, IsAuto, ImplPolarity};
|
||||
pub use syntax::ast::{Mutability, Constness, Unsafety, Movability, CaptureBy};
|
||||
pub use syntax::ast::{IsAuto, ImplPolarity, BorrowKind};
|
||||
use syntax::attr::{InlineAttr, OptimizeAttr};
|
||||
use syntax::symbol::{Symbol, kw};
|
||||
use syntax::tokenstream::TokenStream;
|
||||
@ -1493,8 +1494,20 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_place_expr(&self) -> bool {
|
||||
match self.kind {
|
||||
// Whether this looks like a place expr, without checking for deref
|
||||
// adjustments.
|
||||
// This will return `true` in some potentially surprising cases such as
|
||||
// `CONSTANT.field`.
|
||||
pub fn is_syntactic_place_expr(&self) -> bool {
|
||||
self.is_place_expr(|_| true)
|
||||
}
|
||||
|
||||
// Whether this is a place expression.
|
||||
// `allow_projections_from` should return `true` if indexing a field or
|
||||
// index expression based on the given expression should be considered a
|
||||
// place expression.
|
||||
pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> bool) -> bool {
|
||||
match self.kind {
|
||||
ExprKind::Path(QPath::Resolved(_, ref path)) => {
|
||||
match path.res {
|
||||
Res::Local(..)
|
||||
@ -1504,14 +1517,19 @@ impl Expr {
|
||||
}
|
||||
}
|
||||
|
||||
// Type ascription inherits its place expression kind from its
|
||||
// operand. See:
|
||||
// https://github.com/rust-lang/rfcs/blob/master/text/0803-type-ascription.md#type-ascription-and-temporaries
|
||||
ExprKind::Type(ref e, _) => {
|
||||
e.is_place_expr()
|
||||
e.is_place_expr(allow_projections_from)
|
||||
}
|
||||
|
||||
ExprKind::Unary(UnDeref, _) |
|
||||
ExprKind::Field(..) |
|
||||
ExprKind::Index(..) => {
|
||||
true
|
||||
ExprKind::Unary(UnDeref, _) => true,
|
||||
|
||||
ExprKind::Field(ref base, _) |
|
||||
ExprKind::Index(ref base, _) => {
|
||||
allow_projections_from(base)
|
||||
|| base.is_place_expr(allow_projections_from)
|
||||
}
|
||||
|
||||
// Partially qualified paths in expressions can only legally
|
||||
@ -1646,8 +1664,8 @@ pub enum ExprKind {
|
||||
/// Path to a definition, possibly containing lifetime or type parameters.
|
||||
Path(QPath),
|
||||
|
||||
/// A referencing operation (i.e., `&a` or `&mut a`).
|
||||
AddrOf(Mutability, P<Expr>),
|
||||
/// A referencing operation (i.e., `&a`, `&mut a`, `&raw const a`, or `&raw mut a`).
|
||||
AddrOf(BorrowKind, Mutability, P<Expr>),
|
||||
/// A `break`, with an optional label to break.
|
||||
Break(Destination, Option<P<Expr>>),
|
||||
/// A `continue`, with an optional label.
|
||||
|
@ -294,16 +294,12 @@ impl<'a> State<'a> {
|
||||
}
|
||||
hir::TyKind::Ptr(ref mt) => {
|
||||
self.s.word("*");
|
||||
match mt.mutbl {
|
||||
hir::Mutability::Mutable => self.word_nbsp("mut"),
|
||||
hir::Mutability::Immutable => self.word_nbsp("const"),
|
||||
}
|
||||
self.print_type(&mt.ty);
|
||||
self.print_mt(mt, true);
|
||||
}
|
||||
hir::TyKind::Rptr(ref lifetime, ref mt) => {
|
||||
self.s.word("&");
|
||||
self.print_opt_lifetime(lifetime);
|
||||
self.print_mt(mt);
|
||||
self.print_mt(mt, false);
|
||||
}
|
||||
hir::TyKind::Never => {
|
||||
self.s.word("!");
|
||||
@ -1178,11 +1174,18 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(&mut self,
|
||||
kind: hir::BorrowKind,
|
||||
mutability: hir::Mutability,
|
||||
expr: &hir::Expr)
|
||||
{
|
||||
{
|
||||
self.s.word("&");
|
||||
self.print_mutability(mutability);
|
||||
match kind {
|
||||
hir::BorrowKind::Ref => self.print_mutability(mutability, false),
|
||||
hir::BorrowKind::Raw => {
|
||||
self.word_nbsp("raw");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
|
||||
}
|
||||
|
||||
@ -1225,8 +1228,8 @@ impl<'a> State<'a> {
|
||||
hir::ExprKind::Unary(op, ref expr) => {
|
||||
self.print_expr_unary(op, &expr);
|
||||
}
|
||||
hir::ExprKind::AddrOf(m, ref expr) => {
|
||||
self.print_expr_addr_of(m, &expr);
|
||||
hir::ExprKind::AddrOf(k, m, ref expr) => {
|
||||
self.print_expr_addr_of(k, m, &expr);
|
||||
}
|
||||
hir::ExprKind::Lit(ref lit) => {
|
||||
self.print_literal(&lit);
|
||||
@ -1629,11 +1632,11 @@ impl<'a> State<'a> {
|
||||
match binding_mode {
|
||||
hir::BindingAnnotation::Ref => {
|
||||
self.word_nbsp("ref");
|
||||
self.print_mutability(hir::Mutability::Immutable);
|
||||
self.print_mutability(hir::Mutability::Immutable, false);
|
||||
}
|
||||
hir::BindingAnnotation::RefMut => {
|
||||
self.word_nbsp("ref");
|
||||
self.print_mutability(hir::Mutability::Mutable);
|
||||
self.print_mutability(hir::Mutability::Mutable, false);
|
||||
}
|
||||
hir::BindingAnnotation::Unannotated => {}
|
||||
hir::BindingAnnotation::Mutable => {
|
||||
@ -2060,15 +2063,15 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_mutability(&mut self, mutbl: hir::Mutability) {
|
||||
pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) {
|
||||
match mutbl {
|
||||
hir::Mutability::Mutable => self.word_nbsp("mut"),
|
||||
hir::Mutability::Immutable => {},
|
||||
hir::Mutability::Immutable => if print_const { self.word_nbsp("const") },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_mt(&mut self, mt: &hir::MutTy) {
|
||||
self.print_mutability(mt.mutbl);
|
||||
pub fn print_mt(&mut self, mt: &hir::MutTy, print_const: bool) {
|
||||
self.print_mutability(mt.mutbl, print_const);
|
||||
self.print_type(&mt.ty)
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
self.consume_exprs(exprs);
|
||||
}
|
||||
|
||||
hir::ExprKind::AddrOf(m, ref base) => { // &base
|
||||
hir::ExprKind::AddrOf(_, m, ref base) => { // &base
|
||||
// make sure that the thing we are pointing out stays valid
|
||||
// for the lifetime `scope_r` of the resulting ptr:
|
||||
let bk = ty::BorrowKind::from_mutbl(m);
|
||||
|
@ -1241,7 +1241,7 @@ fn resolve_local<'tcx>(
|
||||
blk_id: Option<Scope>,
|
||||
) {
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, ref subexpr) => {
|
||||
hir::ExprKind::AddrOf(_, _, ref subexpr) => {
|
||||
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id);
|
||||
record_rvalue_scope(visitor, &subexpr, blk_id);
|
||||
}
|
||||
@ -1301,7 +1301,7 @@ fn resolve_local<'tcx>(
|
||||
visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope);
|
||||
|
||||
match expr.kind {
|
||||
hir::ExprKind::AddrOf(_, ref subexpr) |
|
||||
hir::ExprKind::AddrOf(_, _, ref subexpr) |
|
||||
hir::ExprKind::Unary(hir::UnDeref, ref subexpr) |
|
||||
hir::ExprKind::Field(ref subexpr, _) |
|
||||
hir::ExprKind::Index(ref subexpr, _) => {
|
||||
|
@ -409,6 +409,7 @@ E0741: include_str!("./error_codes/E0741.md"),
|
||||
E0742: include_str!("./error_codes/E0742.md"),
|
||||
E0743: include_str!("./error_codes/E0743.md"),
|
||||
E0744: include_str!("./error_codes/E0744.md"),
|
||||
E0745: include_str!("./error_codes/E0745.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
20
src/librustc_error_codes/error_codes/E0745.md
Normal file
20
src/librustc_error_codes/error_codes/E0745.md
Normal file
@ -0,0 +1,20 @@
|
||||
Cannot take address of temporary value.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0745
|
||||
# #![feature(raw_ref_op)]
|
||||
fn temp_address() {
|
||||
let ptr = &raw const 2; // ERROR
|
||||
}
|
||||
```
|
||||
|
||||
To avoid the error, first bind the temporary to a named local variable.
|
||||
|
||||
```ignore
|
||||
# #![feature(raw_ref_op)]
|
||||
fn temp_address() {
|
||||
let val = 2;
|
||||
let ptr = &raw const val;
|
||||
}
|
||||
```
|
@ -137,55 +137,8 @@ fn apply_adjustment<'a, 'tcx>(
|
||||
arg: expr.to_ref(),
|
||||
}
|
||||
}
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(m)) => {
|
||||
// Convert this to a suitable `&foo` and
|
||||
// then an unsafe coercion.
|
||||
expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased,
|
||||
ty::TypeAndMut {
|
||||
ty: expr.ty,
|
||||
mutbl: m,
|
||||
}),
|
||||
span,
|
||||
kind: ExprKind::Borrow {
|
||||
borrow_kind: m.to_borrow_kind(),
|
||||
arg: expr.to_ref(),
|
||||
},
|
||||
};
|
||||
let cast_expr = Expr {
|
||||
temp_lifetime,
|
||||
ty: adjustment.target,
|
||||
span,
|
||||
kind: ExprKind::Cast { source: 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() }
|
||||
Adjust::Borrow(AutoBorrow::RawPtr(mutbl)) => {
|
||||
raw_ref_shim(cx, expr.to_ref(), adjustment.target, mutbl, span, temp_lifetime)
|
||||
}
|
||||
};
|
||||
|
||||
@ -302,13 +255,26 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::AddrOf(mutbl, ref expr) => {
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, ref arg) => {
|
||||
ExprKind::Borrow {
|
||||
borrow_kind: mutbl.to_borrow_kind(),
|
||||
arg: expr.to_ref(),
|
||||
arg: arg.to_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
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::Block(ref blk, _) => ExprKind::Block { body: &blk },
|
||||
|
||||
hir::ExprKind::Assign(ref lhs, ref rhs) => {
|
||||
@ -742,7 +708,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
||||
let user_provided_types = cx.tables.user_provided_types();
|
||||
let user_ty = user_provided_types.get(ty.hir_id).map(|u_ty| *u_ty);
|
||||
debug!("make_mirror_unadjusted: (type) user_ty={:?}", user_ty);
|
||||
if source.is_place_expr() {
|
||||
if source.is_syntactic_place_expr() {
|
||||
ExprKind::PlaceTypeAscription {
|
||||
source: source.to_ref(),
|
||||
user_ty,
|
||||
@ -1123,6 +1089,67 @@ 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,
|
||||
|
@ -726,7 +726,7 @@ impl<'a> Parser<'a> {
|
||||
let sum_with_parens = pprust::to_string(|s| {
|
||||
s.s.word("&");
|
||||
s.print_opt_lifetime(lifetime);
|
||||
s.print_mutability(mut_ty.mutbl);
|
||||
s.print_mutability(mut_ty.mutbl, false);
|
||||
s.popen();
|
||||
s.print_type(&mut_ty.ty);
|
||||
s.print_type_bounds(" +", &bounds);
|
||||
|
@ -442,11 +442,7 @@ impl<'a> Parser<'a> {
|
||||
(lo.to(span), self.mk_unary(UnOp::Deref, e))
|
||||
}
|
||||
token::BinOp(token::And) | token::AndAnd => {
|
||||
self.expect_and()?;
|
||||
let m = self.parse_mutability();
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
(lo.to(span), ExprKind::AddrOf(m, e))
|
||||
self.parse_address_of(lo)?
|
||||
}
|
||||
token::Ident(..) if self.token.is_keyword(kw::Box) => {
|
||||
self.bump();
|
||||
@ -596,6 +592,25 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`
|
||||
fn parse_address_of(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
|
||||
self.expect_and()?;
|
||||
let (k, m) = if self.check_keyword(kw::Raw)
|
||||
&& self.look_ahead(1, Token::is_mutability)
|
||||
{
|
||||
let found_raw = self.eat_keyword(kw::Raw);
|
||||
assert!(found_raw);
|
||||
let mutability = self.parse_const_or_mut().unwrap();
|
||||
self.sess.gated_spans.gate(sym::raw_ref_op, lo.to(self.prev_span));
|
||||
(ast::BorrowKind::Raw, mutability)
|
||||
} else {
|
||||
(ast::BorrowKind::Ref, self.parse_mutability())
|
||||
};
|
||||
let e = self.parse_prefix_expr(None);
|
||||
let (span, e) = self.interpolated_or_expr_span(e)?;
|
||||
Ok((lo.to(span), ExprKind::AddrOf(k, m, e)))
|
||||
}
|
||||
|
||||
/// Parses `a.b` or `a(13)` or `a[4]` or just `a`.
|
||||
fn parse_dot_or_call_expr(
|
||||
&mut self,
|
||||
|
@ -1174,7 +1174,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
}
|
||||
|
||||
hir::ExprKind::Box(ref e) |
|
||||
hir::ExprKind::AddrOf(_, ref e) |
|
||||
hir::ExprKind::AddrOf(_, _, ref e) |
|
||||
hir::ExprKind::Cast(ref e, _) |
|
||||
hir::ExprKind::Type(ref e, _) |
|
||||
hir::ExprKind::DropTemps(ref e) |
|
||||
|
@ -484,7 +484,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
},
|
||||
(hir::ExprKind::AddrOf(_, ref expr), _, &ty::Ref(_, checked, _)) if {
|
||||
(
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
|
||||
_,
|
||||
&ty::Ref(_, checked, _)
|
||||
) if {
|
||||
self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro
|
||||
} => {
|
||||
// We have `&T`, check if what was expected was `T`. If so,
|
||||
|
@ -238,8 +238,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
ExprKind::Unary(unop, ref oprnd) => {
|
||||
self.check_expr_unary(unop, oprnd, expected, needs, expr)
|
||||
}
|
||||
ExprKind::AddrOf(mutbl, ref oprnd) => {
|
||||
self.check_expr_addr_of(mutbl, oprnd, expected, expr)
|
||||
ExprKind::AddrOf(kind, mutbl, ref oprnd) => {
|
||||
self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr)
|
||||
}
|
||||
ExprKind::Path(ref qpath) => {
|
||||
self.check_expr_path(qpath, expr)
|
||||
@ -424,6 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
fn check_expr_addr_of(
|
||||
&self,
|
||||
kind: hir::BorrowKind,
|
||||
mutbl: hir::Mutability,
|
||||
oprnd: &'tcx hir::Expr,
|
||||
expected: Expectation<'tcx>,
|
||||
@ -432,7 +433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
|
||||
match ty.kind {
|
||||
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
|
||||
if oprnd.is_place_expr() {
|
||||
if oprnd.is_syntactic_place_expr() {
|
||||
// Places may legitimately have unsized types.
|
||||
// For example, dereferences of a fat pointer and
|
||||
// the last field of a struct can be unsized.
|
||||
@ -448,24 +449,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let ty = self.check_expr_with_expectation_and_needs(&oprnd, hint, needs);
|
||||
|
||||
let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
|
||||
if tm.ty.references_error() {
|
||||
self.tcx.types.err
|
||||
} else {
|
||||
// Note: at this point, we cannot say what the best lifetime
|
||||
// is to use for resulting pointer. We want to use the
|
||||
// shortest lifetime possible so as to avoid spurious borrowck
|
||||
// errors. Moreover, the longest lifetime will depend on the
|
||||
// precise details of the value whose address is being taken
|
||||
// (and how long it is valid), which we don't know yet until type
|
||||
// inference is complete.
|
||||
match kind {
|
||||
_ if tm.ty.references_error() => self.tcx.types.err,
|
||||
hir::BorrowKind::Raw => {
|
||||
self.check_named_place_expr(oprnd);
|
||||
self.tcx.mk_ptr(tm)
|
||||
}
|
||||
hir::BorrowKind::Ref => {
|
||||
// Note: at this point, we cannot say what the best lifetime
|
||||
// is to use for resulting pointer. We want to use the
|
||||
// shortest lifetime possible so as to avoid spurious borrowck
|
||||
// errors. Moreover, the longest lifetime will depend on the
|
||||
// precise details of the value whose address is being taken
|
||||
// (and how long it is valid), which we don't know yet until
|
||||
// type inference is complete.
|
||||
//
|
||||
// Therefore, here we simply generate a region variable. The
|
||||
// region inferencer will then select a suitable value.
|
||||
// Finally, borrowck will infer the value of the region again,
|
||||
// this time with enough precision to check that the value
|
||||
// whose address was taken can actually be made to live as long
|
||||
// as it needs to live.
|
||||
let region = self.next_region_var(infer::AddrOfRegion(expr.span));
|
||||
self.tcx.mk_ref(region, tm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Does this expression refer to a place that either:
|
||||
/// * Is based on a local or static.
|
||||
/// * Contains a dereference
|
||||
/// Note that the adjustments for the children of `expr` should already
|
||||
/// have been resolved.
|
||||
fn check_named_place_expr(&self, oprnd: &'tcx hir::Expr) {
|
||||
let is_named = oprnd.is_place_expr(|base| {
|
||||
// Allow raw borrows if there are any deref adjustments.
|
||||
//
|
||||
// Therefore, here we simply generate a region variable. The
|
||||
// region inferencer will then select the ultimate value.
|
||||
// Finally, borrowck is charged with guaranteeing that the
|
||||
// value whose address was taken can actually be made to live
|
||||
// as long as it needs to live.
|
||||
let region = self.next_region_var(infer::AddrOfRegion(expr.span));
|
||||
self.tcx.mk_ref(region, tm)
|
||||
// const VAL: (i32,) = (0,);
|
||||
// const REF: &(i32,) = &(0,);
|
||||
//
|
||||
// &raw const VAL.0; // ERROR
|
||||
// &raw const REF.0; // OK, same as &raw const (*REF).0;
|
||||
//
|
||||
// This is maybe too permissive, since it allows
|
||||
// `let u = &raw const Box::new((1,)).0`, which creates an
|
||||
// immediately dangling raw pointer.
|
||||
self.tables.borrow().adjustments().get(base.hir_id).map_or(false, |x| {
|
||||
x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
})
|
||||
})
|
||||
});
|
||||
if !is_named {
|
||||
struct_span_err!(self.tcx.sess, oprnd.span, E0745, "cannot take address of a temporary")
|
||||
.span_label(oprnd.span, "temporary value")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
@ -740,7 +780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
err.help(msg);
|
||||
}
|
||||
err.emit();
|
||||
} else if !lhs.is_place_expr() {
|
||||
} else if !lhs.is_syntactic_place_expr() {
|
||||
struct_span_err!(self.tcx.sess, expr.span, E0070,
|
||||
"invalid left-hand side expression")
|
||||
.span_label(expr.span, "left-hand of expression not valid")
|
||||
|
@ -33,7 +33,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
return_ty
|
||||
};
|
||||
|
||||
if !lhs_expr.is_place_expr() {
|
||||
if !lhs_expr.is_syntactic_place_expr() {
|
||||
struct_span_err!(
|
||||
self.tcx.sess, lhs_expr.span,
|
||||
E0067, "invalid left-hand side expression")
|
||||
|
@ -645,7 +645,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
|
||||
intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
hir::ExprKind::AddrOf(m, ref base) => {
|
||||
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref base) => {
|
||||
self.link_addr_of(expr, m, &base);
|
||||
|
||||
// Require that when you write a `&expr` expression, the
|
||||
|
@ -754,6 +754,21 @@ impl Mutability {
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of borrow in an `AddrOf` expression,
|
||||
/// e.g., `&place` or `&raw const place`.
|
||||
#[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.
|
||||
Raw,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)]
|
||||
pub enum BinOpKind {
|
||||
/// The `+` operator (addition)
|
||||
@ -1071,7 +1086,7 @@ impl Expr {
|
||||
|
||||
ExprKind::Paren(expr) => expr.to_ty().map(TyKind::Paren)?,
|
||||
|
||||
ExprKind::AddrOf(mutbl, expr) => expr
|
||||
ExprKind::AddrOf(BorrowKind::Ref, mutbl, expr) => expr
|
||||
.to_ty()
|
||||
.map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
|
||||
|
||||
@ -1262,8 +1277,8 @@ pub enum ExprKind {
|
||||
/// Optionally "qualified" (e.g., `<Vec<T> as SomeTrait>::SomeType`).
|
||||
Path(Option<QSelf>, Path),
|
||||
|
||||
/// A referencing operation (`&a` or `&mut a`).
|
||||
AddrOf(Mutability, P<Expr>),
|
||||
/// A referencing operation (`&a`, `&mut a`, `&raw const a` or `&raw mut a`).
|
||||
AddrOf(BorrowKind, Mutability, P<Expr>),
|
||||
/// A `break`, with an optional label to break, and an optional expression.
|
||||
Break(Option<Label>, Option<P<Expr>>),
|
||||
/// A `continue`, with an optional label.
|
||||
|
@ -1128,7 +1128,7 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr,
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::AddrOf(_m, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::AddrOf(_, _, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Let(pat, scrutinee) => {
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(scrutinee);
|
||||
|
@ -984,16 +984,12 @@ impl<'a> State<'a> {
|
||||
}
|
||||
ast::TyKind::Ptr(ref mt) => {
|
||||
self.s.word("*");
|
||||
match mt.mutbl {
|
||||
ast::Mutability::Mutable => self.word_nbsp("mut"),
|
||||
ast::Mutability::Immutable => self.word_nbsp("const"),
|
||||
}
|
||||
self.print_type(&mt.ty);
|
||||
self.print_mt(mt, true);
|
||||
}
|
||||
ast::TyKind::Rptr(ref lifetime, ref mt) => {
|
||||
self.s.word("&");
|
||||
self.print_opt_lifetime(lifetime);
|
||||
self.print_mt(mt);
|
||||
self.print_mt(mt, false);
|
||||
}
|
||||
ast::TyKind::Never => {
|
||||
self.s.word("!");
|
||||
@ -1974,10 +1970,17 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(&mut self,
|
||||
kind: ast::BorrowKind,
|
||||
mutability: ast::Mutability,
|
||||
expr: &ast::Expr) {
|
||||
self.s.word("&");
|
||||
self.print_mutability(mutability);
|
||||
match kind {
|
||||
ast::BorrowKind::Ref => self.print_mutability(mutability, false),
|
||||
ast::BorrowKind::Raw => {
|
||||
self.word_nbsp("raw");
|
||||
self.print_mutability(mutability, true);
|
||||
}
|
||||
}
|
||||
self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
|
||||
}
|
||||
|
||||
@ -2028,8 +2031,8 @@ impl<'a> State<'a> {
|
||||
ast::ExprKind::Unary(op, ref expr) => {
|
||||
self.print_expr_unary(op, expr);
|
||||
}
|
||||
ast::ExprKind::AddrOf(m, ref expr) => {
|
||||
self.print_expr_addr_of(m, expr);
|
||||
ast::ExprKind::AddrOf(k, m, ref expr) => {
|
||||
self.print_expr_addr_of(k, m, expr);
|
||||
}
|
||||
ast::ExprKind::Lit(ref lit) => {
|
||||
self.print_literal(lit);
|
||||
@ -2361,7 +2364,7 @@ impl<'a> State<'a> {
|
||||
match binding_mode {
|
||||
ast::BindingMode::ByRef(mutbl) => {
|
||||
self.word_nbsp("ref");
|
||||
self.print_mutability(mutbl);
|
||||
self.print_mutability(mutbl, false);
|
||||
}
|
||||
ast::BindingMode::ByValue(ast::Mutability::Immutable) => {}
|
||||
ast::BindingMode::ByValue(ast::Mutability::Mutable) => {
|
||||
@ -2504,17 +2507,17 @@ impl<'a> State<'a> {
|
||||
fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
|
||||
match explicit_self.node {
|
||||
SelfKind::Value(m) => {
|
||||
self.print_mutability(m);
|
||||
self.print_mutability(m, false);
|
||||
self.s.word("self")
|
||||
}
|
||||
SelfKind::Region(ref lt, m) => {
|
||||
self.s.word("&");
|
||||
self.print_opt_lifetime(lt);
|
||||
self.print_mutability(m);
|
||||
self.print_mutability(m, false);
|
||||
self.s.word("self")
|
||||
}
|
||||
SelfKind::Explicit(ref typ, m) => {
|
||||
self.print_mutability(m);
|
||||
self.print_mutability(m, false);
|
||||
self.s.word("self");
|
||||
self.word_space(":");
|
||||
self.print_type(typ)
|
||||
@ -2746,15 +2749,15 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_mutability(&mut self, mutbl: ast::Mutability) {
|
||||
pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
|
||||
match mutbl {
|
||||
ast::Mutability::Mutable => self.word_nbsp("mut"),
|
||||
ast::Mutability::Immutable => {},
|
||||
ast::Mutability::Immutable => if print_const { self.word_nbsp("const"); },
|
||||
}
|
||||
}
|
||||
|
||||
crate fn print_mt(&mut self, mt: &ast::MutTy) {
|
||||
self.print_mutability(mt.mutbl);
|
||||
crate fn print_mt(&mut self, mt: &ast::MutTy, print_const: bool) {
|
||||
self.print_mutability(mt.mutbl, print_const);
|
||||
self.print_type(&mt.ty)
|
||||
}
|
||||
|
||||
|
@ -708,7 +708,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
visitor.visit_expr(left_expression);
|
||||
visitor.visit_expr(right_expression)
|
||||
}
|
||||
ExprKind::AddrOf(_, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
|
||||
ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
|
||||
visitor.visit_expr(subexpression)
|
||||
}
|
||||
ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
|
||||
|
@ -270,7 +270,7 @@ impl<'a> ExtCtxt<'a> {
|
||||
}
|
||||
|
||||
pub fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
|
||||
self.expr(sp, ast::ExprKind::AddrOf(ast::Mutability::Immutable, e))
|
||||
self.expr(sp, ast::ExprKind::AddrOf(ast::BorrowKind::Ref, ast::Mutability::Immutable, e))
|
||||
}
|
||||
|
||||
pub fn expr_call(
|
||||
|
19
src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
Normal file
19
src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// Ensure that we don't allow taking the address of temporary values
|
||||
#![feature(raw_ref_op)]
|
||||
|
||||
const PAIR: (i32, i64) = (1, 2);
|
||||
const PAIR_REF: &(i32, i64) = &(1, 2);
|
||||
|
||||
const ARRAY: [i32; 2] = [1, 2];
|
||||
const ARRAY_REF: &[i32; 2] = &[3, 4];
|
||||
const SLICE_REF: &[i32] = &[5, 6];
|
||||
|
||||
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 field_deref_ref = &raw const ARRAY_REF[0]; //~ ERROR not yet implemented
|
||||
let deref_ref = &raw const *SLICE_REF; //~ ERROR not yet implemented
|
||||
let field_deref_ref = &raw const SLICE_REF[1]; //~ ERROR not yet implemented
|
||||
}
|
Loading…
Reference in New Issue
Block a user