]> git.lizzy.rs Git - rust.git/commitdiff
review comments
authorNick Cameron <ncameron@mozilla.com>
Tue, 6 Oct 2015 19:26:22 +0000 (08:26 +1300)
committerNick Cameron <ncameron@mozilla.com>
Fri, 9 Oct 2015 08:44:44 +0000 (21:44 +1300)
mk/crates.mk
src/librustc/middle/astencode.rs
src/librustc_driver/pretty.rs
src/librustc_front/hir.rs
src/librustc_front/lowering.rs
src/librustdoc/test.rs
src/test/compile-fail/placement-expr-unsafe.rs [new file with mode: 0644]
src/test/compile-fail/placement-expr-unstable.rs [new file with mode: 0644]

index 0213070d7860255abad43ec4e98272921876f3c9..6673b9b28e7163a3c71e0fdd41dec83bd224a08d 100644 (file)
@@ -61,51 +61,55 @@ HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
 TOOLS := compiletest rustdoc rustc rustbook error-index-generator
 
 DEPS_core :=
+DEPS_alloc := core libc alloc_system
+DEPS_alloc_system := core libc
+DEPS_collections := core alloc rustc_unicode
 DEPS_libc := core
+DEPS_rand := core
+DEPS_rustc_bitflags := core
 DEPS_rustc_unicode := core
-DEPS_alloc := core libc alloc_system
+
 DEPS_std := core libc rand alloc collections rustc_unicode \
        native:rust_builtin native:backtrace \
        alloc_system
+DEPS_arena := std
+DEPS_glob := std
+DEPS_flate := std native:miniz
+DEPS_fmt_macros = std
+DEPS_getopts := std
 DEPS_graphviz := std
+DEPS_log := std
+DEPS_num := std
+DEPS_rbml := std log serialize
+DEPS_serialize := std log
+DEPS_term := std log
+DEPS_test := std getopts serialize rbml term native:rust_test_helpers
+
 DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
+
+DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\
+              log graphviz rustc_llvm rustc_back rustc_data_structures
+DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
+DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
+DEPS_rustc_data_structures := std log serialize
 DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
                      rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
                             rustc_trans rustc_privacy rustc_lint rustc_front
 
-DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
-                       log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
-DEPS_rustc_mir := rustc rustc_front syntax
-DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
-DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
-DEPS_rustc_resolve := rustc rustc_front log syntax
-DEPS_rustc_privacy := rustc rustc_front log syntax
 DEPS_rustc_front := std syntax log serialize
 DEPS_rustc_lint := rustc log syntax
-DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\
-              log graphviz rustc_llvm rustc_back rustc_data_structures
 DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
+DEPS_rustc_mir := rustc rustc_front syntax
+DEPS_rustc_resolve := rustc rustc_front log syntax
 DEPS_rustc_platform_intrinsics := rustc rustc_llvm
-DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
-DEPS_rustc_data_structures := std log serialize
+DEPS_rustc_privacy := rustc rustc_front log syntax
+DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
+                    log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
+DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
+
 DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
                 test rustc_lint rustc_front
-DEPS_rustc_bitflags := core
-DEPS_flate := std native:miniz
-DEPS_arena := std
-DEPS_graphviz := std
-DEPS_glob := std
-DEPS_serialize := std log
-DEPS_rbml := std log serialize
-DEPS_term := std log
-DEPS_getopts := std
-DEPS_collections := core alloc rustc_unicode
-DEPS_num := std
-DEPS_test := std getopts serialize rbml term native:rust_test_helpers
-DEPS_rand := core
-DEPS_log := std
-DEPS_fmt_macros = std
-DEPS_alloc_system := core libc
+
 
 TOOL_DEPS_compiletest := test getopts
 TOOL_DEPS_rustdoc := rustdoc
index dd96ea0460be8a48b2b39505c0d61f6cba9674fc..98f35ca5280086a3c4e79196f3dc43491bb48ee0 100644 (file)
@@ -1379,7 +1379,7 @@ fn parse_sess(&self) -> &parse::ParseSess { self }
 struct FakeNodeIdAssigner;
 
 #[cfg(test)]
-// It should go without sayingt that this may give unexpected results. Avoid
+// It should go without saying that this may give unexpected results. Avoid
 // lowering anything which needs new nodes.
 impl NodeIdAssigner for FakeNodeIdAssigner {
     fn next_node_id(&self) -> NodeId {
index 4e198a44b94831848ffde0c9758e8c70585b3b65..57186cb6ce837f0eab2411fc879b2234166d4a6b 100644 (file)
@@ -224,12 +224,12 @@ trait HirPrinterSupport<'ast>: pprust_hir::PpAnn {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn;
 }
 
-struct NoAnn<'ast, 'tcx> {
-    sess: &'tcx Session,
+struct NoAnn<'ast> {
+    sess: &'ast Session,
     ast_map: Option<hir_map::Map<'ast>>
 }
 
-impl<'ast, 'tcx> PrinterSupport<'ast> for NoAnn<'ast, 'tcx> {
+impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
     fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
@@ -239,7 +239,7 @@ fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast, 'tcx> HirPrinterSupport<'ast> for NoAnn<'ast, 'tcx> {
+impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
     fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
@@ -249,15 +249,15 @@ fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { self }
 }
 
-impl<'ast, 'tcx> pprust::PpAnn for NoAnn<'ast, 'tcx> {}
-impl<'ast, 'tcx> pprust_hir::PpAnn for NoAnn<'ast, 'tcx> {}
+impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
+impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
 
-struct IdentifiedAnnotation<'ast, 'tcx> {
-    sess: &'tcx Session,
+struct IdentifiedAnnotation<'ast> {
+    sess: &'ast Session,
     ast_map: Option<hir_map::Map<'ast>>,
 }
 
-impl<'ast, 'tcx> PrinterSupport<'ast> for IdentifiedAnnotation<'ast, 'tcx> {
+impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
     fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
@@ -267,7 +267,7 @@ fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast, 'tcx> pprust::PpAnn for IdentifiedAnnotation<'ast, 'tcx> {
+impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> {
     fn pre(&self,
            s: &mut pprust::State,
            node: pprust::AnnNode) -> io::Result<()> {
@@ -307,7 +307,7 @@ fn post(&self,
     }
 }
 
-impl<'ast, 'tcx> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast, 'tcx> {
+impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
     fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
@@ -317,7 +317,7 @@ fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
     fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { self }
 }
 
-impl<'ast, 'tcx> pprust_hir::PpAnn for IdentifiedAnnotation<'ast, 'tcx> {
+impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
     fn pre(&self,
            s: &mut pprust_hir::State,
            node: pprust_hir::AnnNode) -> io::Result<()> {
@@ -356,12 +356,12 @@ fn post(&self,
     }
 }
 
-struct HygieneAnnotation<'ast, 'tcx> {
-    sess: &'tcx Session,
+struct HygieneAnnotation<'ast> {
+    sess: &'ast Session,
     ast_map: Option<hir_map::Map<'ast>>,
 }
 
-impl<'ast, 'tcx> PrinterSupport<'ast> for HygieneAnnotation<'ast, 'tcx> {
+impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
     fn sess<'a>(&'a self) -> &'a Session { self.sess }
 
     fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
@@ -371,7 +371,7 @@ fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
     fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { self }
 }
 
-impl<'ast, 'tcx> pprust::PpAnn for HygieneAnnotation<'ast, 'tcx> {
+impl<'ast> pprust::PpAnn for HygieneAnnotation<'ast> {
     fn post(&self,
             s: &mut pprust::State,
             node: pprust::AnnNode) -> io::Result<()> {
index c9f13da063303d4ee8667a1ee2df6a6e083f0149..9066b93262cd64639fb0e8b4dfa1177b1395d596 100644 (file)
@@ -586,7 +586,7 @@ pub enum UnsafeSource {
 }
 
 /// An expression
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
 pub struct Expr {
     pub id: NodeId,
     pub node: Expr_,
index 681fc6144f35036975e4b1a66199f64e88aaa9de..4ee5fa2c1e9b5389c894dcfd4249f1e8f61e28a7 100644 (file)
 // 'folding' an existing one), then you create a new id using `next_id()`.
 //
 // You must ensure that ids are unique. That means that you should only use the
-// is from an AST node in a single HIR node (you can assume that AST node ids
+// id from an AST node in a single HIR node (you can assume that AST node ids
 // are unique). Every new node must have a unique id. Avoid cloning HIR nodes.
-// If you do, you must then set one of the node's id to a fresh one.
+// If you do, you must then set the new node's id to a fresh one.
 //
 // Lowering must be reproducable (the compiler only lowers once, but tools and
 // custom lints may lower an AST node to a HIR node to interact with the
-// compiler). The only interesting bit of this is ids - if you lower an AST node
+// compiler). The most interesting bit of this is ids - if you lower an AST node
 // and create new HIR nodes with fresh ids, when re-lowering the same node, you
 // must ensure you get the same ids! To do this, we keep track of the next id
 // when we translate a node which requires new ids. By checking this cache and
 // all increments being for lowering. This means that you should not call any
 // non-lowering function which will use new node ids.
 //
+// We must also cache gensym'ed Idents to ensure that we get the same Ident
+// every time we lower a node with gensym'ed names. One consequence of this is
+// that you can only gensym a name once in a lowering (you don't need to worry
+// about nested lowering though). That's because we cache based on the name and
+// the currently cached node id, which is unique per lowered node.
+//
 // Spans are used for error messages and for tools to map semantics back to
 // source code. It is therefore not as important with spans as ids to be strict
 // about use (you can't break the compiler by screwing up a span). Obviously, a
@@ -77,6 +83,10 @@ pub struct LoweringContext<'a> {
     // 0 == no cached id. Must be incremented to align with previous id
     // incrementing.
     cached_id: Cell<u32>,
+    // Keep track of gensym'ed idents.
+    gensym_cache: RefCell<HashMap<(NodeId, &'static str), Ident>>,
+    // A copy of cached_id, but is also set to an id while it is being cached.
+    gensym_key: Cell<u32>,
 }
 
 impl<'a, 'hir> LoweringContext<'a> {
@@ -96,6 +106,8 @@ pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContex
             id_cache: RefCell::new(HashMap::new()),
             id_assigner: id_assigner,
             cached_id: Cell::new(0),
+            gensym_cache: RefCell::new(HashMap::new()),
+            gensym_key: Cell::new(0),
         }
     }
 
@@ -108,6 +120,22 @@ fn next_id(&self) -> NodeId {
         self.cached_id.set(cached + 1);
         cached
     }
+
+    fn str_to_ident(&self, s: &'static str) -> Ident {
+        let cached_id = self.gensym_key.get();
+        if cached_id == 0 {
+            return token::gensym_ident(s);
+        }
+
+        let cached = self.gensym_cache.borrow().contains_key(&(cached_id, s));
+        if cached {
+            self.gensym_cache.borrow()[&(cached_id, s)]
+        } else {
+            let result = token::gensym_ident(s);
+            self.gensym_cache.borrow_mut().insert((cached_id, s), result);
+            result
+        }
+    }
 }
 
 pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
@@ -861,6 +889,11 @@ struct CachedIdSetter<'a> {
 
 impl<'a> CachedIdSetter<'a> {
     fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> {
+        // Only reset the id if it was previously 0, i.e., was not cached.
+        // If it was cached, we are in a nested node, but our id count will
+        // still count towards the parent's count.
+        let reset_cached_id = lctx.cached_id.get() == 0;
+
         let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
 
         if id_cache.contains_key(&expr_id) {
@@ -869,20 +902,20 @@ fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> {
                 // We're entering a node where we need to track ids, but are not
                 // yet tracking.
                 lctx.cached_id.set(id_cache[&expr_id]);
+                lctx.gensym_key.set(id_cache[&expr_id]);
             } else {
                 // We're already tracking - check that the tracked id is the same
                 // as the expected id.
                 assert!(cached_id == id_cache[&expr_id], "id mismatch");
             }
         } else {
-            id_cache.insert(expr_id, lctx.id_assigner.peek_node_id());
+            let next_id = lctx.id_assigner.peek_node_id();
+            id_cache.insert(expr_id, next_id);
+            lctx.gensym_key.set(next_id);
         }
 
         CachedIdSetter {
-            // Only reset the id if it was previously 0, i.e., was not cached.
-            // If it was cached, we are in a nested node, but our id count will
-            // still count towards the parent's count.
-            reset: lctx.cached_id.get() == 0,
+            reset: reset_cached_id,
             lctx: lctx,
         }
     }
@@ -892,6 +925,7 @@ impl<'a> Drop for CachedIdSetter<'a> {
     fn drop(&mut self) {
         if self.reset {
             self.lctx.cached_id.set(0);
+            self.lctx.gensym_key.set(0);
         }
     }
 }
@@ -936,9 +970,9 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 let placer_expr = lower_expr(lctx, placer);
                 let value_expr = lower_expr(lctx, value_expr);
 
-                let placer_ident = token::gensym_ident("placer");
-                let agent_ident = token::gensym_ident("place");
-                let p_ptr_ident = token::gensym_ident("p_ptr");
+                let placer_ident = lctx.str_to_ident("placer");
+                let agent_ident = lctx.str_to_ident("place");
+                let p_ptr_ident = lctx.str_to_ident("p_ptr");
 
                 let make_place = ["ops", "Placer", "make_place"];
                 let place_pointer = ["ops", "Place", "pointer"];
@@ -955,7 +989,13 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 let mk_stmt_let_mut = |lctx, bind, expr| stmt_let(lctx, e.span, true, bind, expr);
 
                 // let placer = <placer_expr> ;
-                let s1 = mk_stmt_let(lctx, placer_ident, placer_expr);
+                let s1 = mk_stmt_let(lctx,
+                                     placer_ident,
+                                     signal_block_expr(lctx,
+                                                       vec![],
+                                                       placer_expr,
+                                                       e.span,
+                                                       hir::PopUnstableBlock));
 
                 // let mut place = Placer::make_place(placer);
                 let s2 = {
@@ -1310,7 +1350,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 // expand <head>
                 let head = lower_expr(lctx, head);
 
-                let iter = token::gensym_ident("iter");
+                let iter = lctx.str_to_ident("iter");
 
                 // `::std::option::Option::Some(<pat>) => <body>`
                 let pat_arm = {
@@ -1385,7 +1425,7 @@ pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
                 let match_expr = expr_match(lctx, e.span, into_iter_expr, vec![iter_arm]);
 
                 // `{ let result = ...; result }`
-                let result_ident = token::gensym_ident("result");
+                let result_ident = lctx.str_to_ident("result");
                 return expr_block(lctx,
                                   block_all(lctx,
                                             e.span,
@@ -1722,3 +1762,103 @@ fn signal_block_expr(lctx: &LoweringContext,
                    expr: Some(expr),
                }))
 }
+
+
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use syntax::ast::{self, NodeId, NodeIdAssigner};
+    use syntax::{parse, codemap};
+    use syntax::fold::Folder;
+    use std::cell::Cell;
+
+    struct MockAssigner {
+        next_id: Cell<NodeId>,
+    }
+
+    impl MockAssigner {
+        fn new() -> MockAssigner {
+            MockAssigner {
+                next_id: Cell::new(0),
+            }
+        }
+    }
+
+    trait FakeExtCtxt {
+        fn call_site(&self) -> codemap::Span;
+        fn cfg(&self) -> ast::CrateConfig;
+        fn ident_of(&self, st: &str) -> ast::Ident;
+        fn name_of(&self, st: &str) -> ast::Name;
+        fn parse_sess(&self) -> &parse::ParseSess;
+    }
+
+    impl FakeExtCtxt for parse::ParseSess {
+        fn call_site(&self) -> codemap::Span {
+            codemap::Span {
+                lo: codemap::BytePos(0),
+                hi: codemap::BytePos(0),
+                expn_id: codemap::NO_EXPANSION,
+            }
+        }
+        fn cfg(&self) -> ast::CrateConfig { Vec::new() }
+        fn ident_of(&self, st: &str) -> ast::Ident {
+            parse::token::str_to_ident(st)
+        }
+        fn name_of(&self, st: &str) -> ast::Name {
+            parse::token::intern(st)
+        }
+        fn parse_sess(&self) -> &parse::ParseSess { self }
+    }
+
+    impl NodeIdAssigner for MockAssigner {
+        fn next_node_id(&self) -> NodeId {
+            let result = self.next_id.get();
+            self.next_id.set(result + 1);
+            result
+        }
+
+        fn peek_node_id(&self) -> NodeId {
+            self.next_id.get()
+        }
+    }
+
+    impl Folder for MockAssigner {
+        fn new_id(&mut self, old_id: NodeId) -> NodeId {
+            assert_eq!(old_id, ast::DUMMY_NODE_ID);
+            self.next_node_id()
+        }
+    }
+
+    #[test]
+    fn test_preserves_ids() {
+        let cx = parse::ParseSess::new();
+        let mut assigner = MockAssigner::new();
+
+        let ast_if_let = quote_expr!(&cx, if let Some(foo) = baz { bar(foo); });
+        let ast_if_let = assigner.fold_expr(ast_if_let);
+        let ast_while_let = quote_expr!(&cx, while let Some(foo) = baz { bar(foo); });
+        let ast_while_let = assigner.fold_expr(ast_while_let);
+        let ast_for = quote_expr!(&cx, for i in 0..10 { foo(i); });
+        let ast_for = assigner.fold_expr(ast_for);
+        let ast_in = quote_expr!(&cx, in HEAP { foo() });
+        let ast_in = assigner.fold_expr(ast_in);
+
+        let lctx = LoweringContext::new(&assigner, None);
+        let hir1 = lower_expr(&lctx, &ast_if_let);
+        let hir2 = lower_expr(&lctx, &ast_if_let);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_while_let);
+        let hir2 = lower_expr(&lctx, &ast_while_let);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_for);
+        let hir2 = lower_expr(&lctx, &ast_for);
+        assert!(hir1 == hir2);
+
+        let hir1 = lower_expr(&lctx, &ast_in);
+        let hir2 = lower_expr(&lctx, &ast_in);
+        assert!(hir1 == hir2);
+    }
+}
index 87e1d8a0392461bc89b7ebdda4241c8e3d66a983..d6114737ab5a2bfab0eadcb8b44453457267ef18 100644 (file)
@@ -92,13 +92,8 @@ pub fn run(input: &str,
     let map = hir_map::map_crate(&mut forest);
 
     let ctx = core::DocContext {
-<<<<<<< HEAD
         map: &map,
-        maybe_typed: core::NotTyped(sess),
-=======
-        krate: &krate,
         maybe_typed: core::NotTyped(&sess),
->>>>>>> Fixes to rustdoc, etc.
         input: input,
         external_paths: RefCell::new(Some(HashMap::new())),
         external_traits: RefCell::new(None),
diff --git a/src/test/compile-fail/placement-expr-unsafe.rs b/src/test/compile-fail/placement-expr-unsafe.rs
new file mode 100644 (file)
index 0000000..50a840e
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that placement in respects unsafe code checks.
+
+#![feature(box_heap)]
+#![feature(placement_in_syntax)]
+
+fn main() {
+    use std::boxed::HEAP;
+
+    let p: *const i32 = &42;
+    let _ = in HEAP { *p }; //~ ERROR requires unsafe
+
+    let p: *const _ = &HEAP;
+    let _ = in *p { 42 }; //~ ERROR requires unsafe
+}
diff --git a/src/test/compile-fail/placement-expr-unstable.rs b/src/test/compile-fail/placement-expr-unstable.rs
new file mode 100644 (file)
index 0000000..d981b71
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that placement in respects unstable code checks.
+
+#![feature(placement_in_syntax)]
+#![feature(core)]
+
+extern crate core;
+
+fn main() {
+    use std::boxed::HEAP; //~ ERROR use of unstable library feature
+
+    let _ = in HEAP { //~ ERROR use of unstable library feature
+        ::core::raw::Slice { //~ ERROR use of unstable library feature
+            data: &42, //~ ERROR use of unstable library feature
+            len: 1 //~ ERROR use of unstable library feature
+        }
+    };
+}