Add raw address of expressions to the AST and HIR

This commit is contained in:
Matthew Jasper 2019-11-23 14:15:49 +00:00
parent 9420ff4c0e
commit a8efd31f2b
22 changed files with 308 additions and 139 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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