about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-11-23 14:15:49 +0000
committerMatthew Jasper <mjjasper1@gmail.com>2019-11-24 18:06:13 +0000
commita8efd31f2b97a043d73db2131dddfedd65485d50 (patch)
treed5eef5952391f5bf162f3ce4a4470255157843f0 /src
parent9420ff4c0ebea44b167d530bb59f9d5721d8ff0b (diff)
downloadrust-a8efd31f2b97a043d73db2131dddfedd65485d50.tar.gz
rust-a8efd31f2b97a043d73db2131dddfedd65485d50.zip
Add raw address of expressions to the AST and HIR
Diffstat (limited to 'src')
-rw-r--r--src/librustc/hir/intravisit.rs2
-rw-r--r--src/librustc/hir/lowering/expr.rs10
-rw-r--r--src/librustc/hir/mod.rs38
-rw-r--r--src/librustc/hir/print.rs35
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/region.rs4
-rw-r--r--src/librustc_error_codes/error_codes.rs1
-rw-r--r--src/librustc_error_codes/error_codes/E0745.md20
-rw-r--r--src/librustc_mir/hair/cx/expr.rs131
-rw-r--r--src/librustc_parse/parser/diagnostics.rs2
-rw-r--r--src/librustc_parse/parser/expr.rs25
-rw-r--r--src/librustc_passes/liveness.rs2
-rw-r--r--src/librustc_typeck/check/demand.rs6
-rw-r--r--src/librustc_typeck/check/expr.rs82
-rw-r--r--src/librustc_typeck/check/op.rs2
-rw-r--r--src/librustc_typeck/check/regionck.rs2
-rw-r--r--src/libsyntax/ast.rs21
-rw-r--r--src/libsyntax/mut_visit.rs2
-rw-r--r--src/libsyntax/print/pprust.rs37
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/libsyntax_expand/build.rs2
-rw-r--r--src/test/ui/raw-ref-op/raw-ref-temp-deref.rs19
22 files changed, 308 insertions, 139 deletions
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 91c19e269a7..a4557a0776c 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -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) => {
diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs
index 929dce7aa0f..f8465baeb13 100644
--- a/src/librustc/hir/lowering/expr.rs
+++ b/src/librustc/hir/lowering/expr.rs
@@ -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 {
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 64d22ae9435..66bb3a8d883 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -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.
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index 4cbe0e80991..a069331582e 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -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)
     }
 
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 4571f551aa4..00bddf50c29 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -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);
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 9ff205228a5..aa6f2839828 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -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, _) => {
diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs
index b11fe33880c..709ccce517a 100644
--- a/src/librustc_error_codes/error_codes.rs
+++ b/src/librustc_error_codes/error_codes.rs
@@ -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
diff --git a/src/librustc_error_codes/error_codes/E0745.md b/src/librustc_error_codes/error_codes/E0745.md
new file mode 100644
index 00000000000..7c478a1e0c8
--- /dev/null
+++ b/src/librustc_error_codes/error_codes/E0745.md
@@ -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;
+}
+```
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 694a3fd04ee..afc4e461c0d 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -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,
diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs
index eab35a86c69..8a79a733c30 100644
--- a/src/librustc_parse/parser/diagnostics.rs
+++ b/src/librustc_parse/parser/diagnostics.rs
@@ -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);
diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index a56a7bf1802..81442143f53 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -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,
diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs
index 8d7a0388122..81a39edf215 100644
--- a/src/librustc_passes/liveness.rs
+++ b/src/librustc_passes/liveness.rs
@@ -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) |
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 5d9b3a8fba4..b0a026b8ccc 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -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,
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 163412f6a16..6c24f3184ca 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -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")
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 28db09fe92b..321faa4a322 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -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")
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 2f9091282b7..f4fdc2882e7 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -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
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 14243076941..dc26929100a 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -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.
diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs
index a7bd587ac9b..fbe28215a56 100644
--- a/src/libsyntax/mut_visit.rs
+++ b/src/libsyntax/mut_visit.rs
@@ -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);
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 17a7cbddff9..0d2e8dddce6 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -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)
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index f7b06c55a3a..5ff337fb60e 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -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) => {
diff --git a/src/libsyntax_expand/build.rs b/src/libsyntax_expand/build.rs
index 7fe37f377a8..3d082101c41 100644
--- a/src/libsyntax_expand/build.rs
+++ b/src/libsyntax_expand/build.rs
@@ -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(
diff --git a/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs b/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
new file mode 100644
index 00000000000..22de148e4c2
--- /dev/null
+++ b/src/test/ui/raw-ref-op/raw-ref-temp-deref.rs
@@ -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
+}