]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #27137 - dhuseby:fixing_bitrig_linking, r=alexcrichton
authorSteve Klabnik <steve@steveklabnik.com>
Fri, 24 Jul 2015 18:56:01 +0000 (14:56 -0400)
committerSteve Klabnik <steve@steveklabnik.com>
Fri, 24 Jul 2015 18:56:01 +0000 (14:56 -0400)
fixes the linking error on bitrig.

50 files changed:
src/liballoc/boxed.rs
src/liballoc/lib.rs
src/libcore/intrinsics.rs
src/libcore/ops.rs
src/librustc/middle/effect.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/stability.rs
src/librustc/middle/ty.rs
src/librustc_back/target/freebsd_base.rs
src/librustc_lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_llvm/lib.rs
src/librustc_trans/back/lto.rs
src/librustc_trans/back/msvc/registry.rs
src/librustc_trans/back/write.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/context.rs
src/librustc_typeck/check/mod.rs
src/libstd/lib.rs
src/libstd/rt/unwind/gcc.rs
src/libstd/sys/windows/stack_overflow.rs
src/libstd/thread/local.rs
src/libsyntax/ast.rs
src/libsyntax/codemap.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/pushpop_safe.rs [new file with mode: 0644]
src/libsyntax/feature_gate.rs
src/libsyntax/lib.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/rustllvm/ArchiveWrapper.cpp
src/test/auxiliary/xcrate-static.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-box-expr.rs
src/test/compile-fail/feature-gate-placement-expr.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-pushpop-unsafe.rs [new file with mode: 0644]
src/test/compile-fail/issue-14084.rs
src/test/compile-fail/issue-14309.rs
src/test/compile-fail/issue-16250.rs
src/test/compile-fail/lint-ctypes-enum.rs
src/test/compile-fail/lint-ctypes.rs
src/test/compile-fail/pushpop-unsafe-rejects.rs [new file with mode: 0644]
src/test/compile-fail/warn-foreign-int-types.rs
src/test/parse-fail/parenthesized-box-expr-message.rs
src/test/run-make/execution-engine/test.rs
src/test/run-pass/intrinsic-move-val.rs
src/test/run-pass/new-box-syntax.rs
src/test/run-pass/placement-in-syntax.rs [new file with mode: 0644]
src/test/run-pass/pushpop-unsafe-okay.rs [new file with mode: 0644]
src/test/run-pass/xcrate-static.rs [new file with mode: 0644]

index d9653cecc73cfe17bbcf8204d828e39f9ce5593a..acf22094233230f5405f1b0c906c39ef83ef581c 100644 (file)
 
 use core::prelude::*;
 
+use heap;
+
 use core::any::Any;
 use core::cmp::Ordering;
 use core::fmt;
 use core::hash::{self, Hash};
-use core::marker::Unsize;
+use core::marker::{self, Unsize};
 use core::mem;
 use core::ops::{CoerceUnsized, Deref, DerefMut};
+use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
 use core::ptr::Unique;
 use core::raw::{TraitObject};
 
@@ -72,7 +75,7 @@
 ///
 /// ```
 /// # #![feature(box_heap)]
-/// #![feature(box_syntax)]
+/// #![feature(box_syntax, placement_in_syntax)]
 /// use std::boxed::HEAP;
 ///
 /// fn main() {
 #[lang = "exchange_heap"]
 #[unstable(feature = "box_heap",
            reason = "may be renamed; uncertain about custom allocator design")]
-pub const HEAP: () = ();
+pub const HEAP: ExchangeHeapSingleton =
+    ExchangeHeapSingleton { _force_singleton: () };
+
+/// This the singleton type used solely for `boxed::HEAP`.
+#[derive(Copy, Clone)]
+pub struct ExchangeHeapSingleton { _force_singleton: () }
 
 /// A pointer type for heap allocation.
 ///
 #[lang = "owned_box"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[fundamental]
-pub struct Box<T>(Unique<T>);
+pub struct Box<T: ?Sized>(Unique<T>);
+
+/// `IntermediateBox` represents uninitialized backing storage for `Box`.
+///
+/// FIXME (pnkfelix): Ideally we would just reuse `Box<T>` instead of
+/// introducing a separate `IntermediateBox<T>`; but then you hit
+/// issues when you e.g. attempt to destructure an instance of `Box`,
+/// since it is a lang item and so it gets special handling by the
+/// compiler.  Easier just to make this parallel type for now.
+///
+/// FIXME (pnkfelix): Currently the `box` protocol only supports
+/// creating instances of sized types. This IntermediateBox is
+/// designed to be forward-compatible with a future protocol that
+/// supports creating instances of unsized types; that is why the type
+/// parameter has the `?Sized` generalization marker, and is also why
+/// this carries an explicit size. However, it probably does not need
+/// to carry the explicit alignment; that is just a work-around for
+/// the fact that the `align_of` intrinsic currently requires the
+/// input type to be Sized (which I do not think is strictly
+/// necessary).
+#[unstable(feature = "placement_in", reason = "placement box design is still being worked out.")]
+pub struct IntermediateBox<T: ?Sized>{
+    ptr: *mut u8,
+    size: usize,
+    align: usize,
+    marker: marker::PhantomData<*mut T>,
+}
+
+impl<T> Place<T> for IntermediateBox<T> {
+    fn pointer(&mut self) -> *mut T {
+        unsafe { ::core::mem::transmute(self.ptr) }
+    }
+}
+
+unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
+    let p = b.ptr as *mut T;
+    mem::forget(b);
+    mem::transmute(p)
+}
+
+fn make_place<T>() -> IntermediateBox<T> {
+    let size = mem::size_of::<T>();
+    let align = mem::align_of::<T>();
+
+    let p = if size == 0 {
+        heap::EMPTY as *mut u8
+    } else {
+        let p = unsafe {
+            heap::allocate(size, align)
+        };
+        if p.is_null() {
+            panic!("Box make_place allocation failure.");
+        }
+        p
+    };
+
+    IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData }
+}
+
+impl<T> BoxPlace<T> for IntermediateBox<T> {
+    fn make_place() -> IntermediateBox<T> { make_place() }
+}
+
+impl<T> InPlace<T> for IntermediateBox<T> {
+    type Owner = Box<T>;
+    unsafe fn finalize(self) -> Box<T> { finalize(self) }
+}
+
+impl<T> Boxed for Box<T> {
+    type Data = T;
+    type Place = IntermediateBox<T>;
+    unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> { finalize(b) }
+}
+
+impl<T> Placer<T> for ExchangeHeapSingleton {
+    type Place = IntermediateBox<T>;
+
+    fn make_place(self) -> IntermediateBox<T> {
+        make_place()
+    }
+}
+
+impl<T: ?Sized> Drop for IntermediateBox<T> {
+    fn drop(&mut self) {
+        if self.size > 0 {
+            unsafe {
+                heap::deallocate(self.ptr, self.size, self.align)
+            }
+        }
+    }
+}
 
 impl<T> Box<T> {
     /// Allocates memory on the heap and then moves `x` into it.
@@ -199,8 +297,7 @@ impl<T: Clone> Clone for Box<T> {
     /// let y = x.clone();
     /// ```
     #[inline]
-    fn clone(&self) -> Box<T> { box {(**self).clone()} }
-
+    fn clone(&self) -> Box<T> { box (HEAP) {(**self).clone()} }
     /// Copies `source`'s contents into `self` without creating a new allocation.
     ///
     /// # Examples
index ead0b4259a987cdf4f0357fca67e3305b1e499e7..f66495c4057c4c283350eaef90296ac81bf0ca51 100644 (file)
@@ -70,6 +70,8 @@
        test(no_crate_inject))]
 #![no_std]
 
+// SNAP d4432b3
+#![allow(unused_features)] // until feature(placement_in_syntax) is in snap
 #![feature(allocator)]
 #![feature(box_syntax)]
 #![feature(coerce_unsized)]
@@ -82,6 +84,8 @@
 #![feature(no_std)]
 #![feature(nonzero)]
 #![feature(optin_builtin_traits)]
+#![feature(placement_in_syntax)]
+#![feature(placement_new_protocol)]
 #![feature(raw)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
index ef022179772c4cd4c9a60eb53a143e6d1eca9291..1d466895f2cfbb826287d677017ebc5b0fc7413e 100644 (file)
     /// elements.
     pub fn size_of<T>() -> usize;
 
+    #[cfg(not(stage0))]
+    /// Moves a value to an uninitialized memory location.
+    ///
+    /// Drop glue is not run on the destination.
+    pub fn move_val_init<T>(dst: *mut T, src: T);
+
+    // SNAP d4432b3
+    #[cfg(stage0)]
     /// Moves a value to an uninitialized memory location.
     ///
     /// Drop glue is not run on the destination.
index c2a9b8c8308cd5c6c91f80637fabe69992f565c9..2ea42011a5cf2ff6a2206c52ad780a689bc25394 100644 (file)
@@ -1266,3 +1266,120 @@ impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 
 // *const T -> *const U
 impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+
+/// Both `in (PLACE) EXPR` and `box EXPR` desugar into expressions
+/// that allocate an intermediate "place" that holds uninitialized
+/// state.  The desugaring evaluates EXPR, and writes the result at
+/// the address returned by the `pointer` method of this trait.
+///
+/// A `Place` can be thought of as a special representation for a
+/// hypothetical `&uninit` reference (which Rust cannot currently
+/// express directly). That is, it represents a pointer to
+/// uninitialized storage.
+///
+/// The client is responsible for two steps: First, initializing the
+/// payload (it can access its address via `pointer`). Second,
+/// converting the agent to an instance of the owning pointer, via the
+/// appropriate `finalize` method (see the `InPlace`.
+///
+/// If evaluating EXPR fails, then the destructor for the
+/// implementation of Place to clean up any intermediate state
+/// (e.g. deallocate box storage, pop a stack, etc).
+#[unstable(feature = "placement_new_protocol")]
+pub trait Place<Data: ?Sized> {
+    /// Returns the address where the input value will be written.
+    /// Note that the data at this address is generally uninitialized,
+    /// and thus one should use `ptr::write` for initializing it.
+    fn pointer(&mut self) -> *mut Data;
+}
+
+/// Interface to implementations of  `in (PLACE) EXPR`.
+///
+/// `in (PLACE) EXPR` effectively desugars into:
+///
+/// ```rust,ignore
+/// let p = PLACE;
+/// let mut place = Placer::make_place(p);
+/// let raw_place = Place::pointer(&mut place);
+/// let value = EXPR;
+/// unsafe {
+///     std::ptr::write(raw_place, value);
+///     InPlace::finalize(place)
+/// }
+/// ```
+///
+/// The type of `in (PLACE) EXPR` is derived from the type of `PLACE`;
+/// if the type of `PLACE` is `P`, then the final type of the whole
+/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed`
+/// traits).
+///
+/// Values for types implementing this trait usually are transient
+/// intermediate values (e.g. the return value of `Vec::emplace_back`)
+/// or `Copy`, since the `make_place` method takes `self` by value.
+#[unstable(feature = "placement_new_protocol")]
+pub trait Placer<Data: ?Sized> {
+    /// `Place` is the intermedate agent guarding the
+    /// uninitialized state for `Data`.
+    type Place: InPlace<Data>;
+
+    /// Creates a fresh place from `self`.
+    fn make_place(self) -> Self::Place;
+}
+
+/// Specialization of `Place` trait supporting `in (PLACE) EXPR`.
+#[unstable(feature = "placement_new_protocol")]
+pub trait InPlace<Data: ?Sized>: Place<Data> {
+    /// `Owner` is the type of the end value of `in (PLACE) EXPR`
+    ///
+    /// Note that when `in (PLACE) EXPR` is solely used for
+    /// side-effecting an existing data-structure,
+    /// e.g. `Vec::emplace_back`, then `Owner` need not carry any
+    /// information at all (e.g. it can be the unit type `()` in that
+    /// case).
+    type Owner;
+
+    /// Converts self into the final value, shifting
+    /// deallocation/cleanup responsibilities (if any remain), over to
+    /// the returned instance of `Owner` and forgetting self.
+    unsafe fn finalize(self) -> Self::Owner;
+}
+
+/// Core trait for the `box EXPR` form.
+///
+/// `box EXPR` effectively desugars into:
+///
+/// ```rust,ignore
+/// let mut place = BoxPlace::make_place();
+/// let raw_place = Place::pointer(&mut place);
+/// let value = EXPR;
+/// unsafe {
+///     ::std::ptr::write(raw_place, value);
+///     Boxed::finalize(place)
+/// }
+/// ```
+///
+/// The type of `box EXPR` is supplied from its surrounding
+/// context; in the above expansion, the result type `T` is used
+/// to determine which implementation of `Boxed` to use, and that
+/// `<T as Boxed>` in turn dictates determines which
+/// implementation of `BoxPlace` to use, namely:
+/// `<<T as Boxed>::Place as BoxPlace>`.
+#[unstable(feature = "placement_new_protocol")]
+pub trait Boxed {
+    /// The kind of data that is stored in this kind of box.
+    type Data;  /* (`Data` unused b/c cannot yet express below bound.) */
+    /// The place that will negotiate the storage of the data.
+    type Place: BoxPlace<Self::Data>;
+
+    /// Converts filled place into final owning value, shifting
+    /// deallocation/cleanup responsibilities (if any remain), over to
+    /// returned instance of `Self` and forgetting `filled`.
+    unsafe fn finalize(filled: Self::Place) -> Self;
+}
+
+/// Specialization of `Place` trait supporting `box EXPR`.
+#[unstable(feature = "placement_new_protocol")]
+pub trait BoxPlace<Data: ?Sized> : Place<Data> {
+    /// Creates a globally fresh place.
+    fn make_place() -> Self;
+}
index b2a064bf86c6a08e3bd6b3a18a14db1f935d4559..3fe1e2f5e8369903974114a506d532c48e1dd2d1 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Enforces the Rust effect system. Currently there is just one effect,
 //! `unsafe`.
-use self::UnsafeContext::*;
+use self::RootUnsafeContext::*;
 
 use middle::def;
 use middle::ty::{self, Ty};
 use syntax::visit;
 use syntax::visit::Visitor;
 
+#[derive(Copy, Clone)]
+struct UnsafeContext {
+    push_unsafe_count: usize,
+    root: RootUnsafeContext,
+}
+
+impl UnsafeContext {
+    fn new(root: RootUnsafeContext) -> UnsafeContext {
+        UnsafeContext { root: root, push_unsafe_count: 0 }
+    }
+}
+
 #[derive(Copy, Clone, PartialEq)]
-enum UnsafeContext {
+enum RootUnsafeContext {
     SafeContext,
     UnsafeFn,
     UnsafeBlock(ast::NodeId),
@@ -44,7 +56,8 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> {
     fn require_unsafe(&mut self, span: Span, description: &str) {
-        match self.unsafe_context {
+        if self.unsafe_context.push_unsafe_count > 0 { return; }
+        match self.unsafe_context.root {
             SafeContext => {
                 // Report an error.
                 span_err!(self.tcx.sess, span, E0133,
@@ -75,9 +88,9 @@ fn visit_fn(&mut self, fn_kind: visit::FnKind<'v>, fn_decl: &'v ast::FnDecl,
 
         let old_unsafe_context = self.unsafe_context;
         if is_unsafe_fn {
-            self.unsafe_context = UnsafeFn
+            self.unsafe_context = UnsafeContext::new(UnsafeFn)
         } else if is_item_fn {
-            self.unsafe_context = SafeContext
+            self.unsafe_context = UnsafeContext::new(SafeContext)
         }
 
         visit::walk_fn(self, fn_kind, fn_decl, block, span);
@@ -105,10 +118,18 @@ fn visit_block(&mut self, block: &ast::Block) {
                 // external blocks (e.g. `unsafe { println("") }`,
                 // expands to `unsafe { ... unsafe { ... } }` where
                 // the inner one is compiler generated).
-                if self.unsafe_context == SafeContext || source == ast::CompilerGenerated {
-                    self.unsafe_context = UnsafeBlock(block.id)
+                if self.unsafe_context.root == SafeContext || source == ast::CompilerGenerated {
+                    self.unsafe_context.root = UnsafeBlock(block.id)
                 }
             }
+            ast::PushUnsafeBlock(..) => {
+                self.unsafe_context.push_unsafe_count =
+                    self.unsafe_context.push_unsafe_count.checked_add(1).unwrap();
+            }
+            ast::PopUnsafeBlock(..) => {
+                self.unsafe_context.push_unsafe_count =
+                    self.unsafe_context.push_unsafe_count.checked_sub(1).unwrap();
+            }
         }
 
         visit::walk_block(self, block);
@@ -162,7 +183,7 @@ fn visit_expr(&mut self, expr: &ast::Expr) {
 pub fn check_crate(tcx: &ty::ctxt) {
     let mut visitor = EffectCheckVisitor {
         tcx: tcx,
-        unsafe_context: SafeContext,
+        unsafe_context: UnsafeContext::new(SafeContext),
     };
 
     visit::walk_crate(&mut visitor, tcx.map.krate());
index 54fc2daff2b8e55165f147b11e093f9d07669967..f27a96545ddfa4835ca2a782ef8579f5e0b99f80 100644 (file)
@@ -555,6 +555,11 @@ pub fn walk_expr(&mut self, expr: &ast::Expr) {
                     None => {}
                 }
                 self.consume_expr(&**base);
+                if place.is_some() {
+                    self.tcx().sess.span_bug(
+                        expr.span,
+                        "box with explicit place remains after expansion");
+                }
             }
 
             ast::ExprMac(..) => {
index 30553d62719bfbf8b96a4535965e7ea4d75539e3..6d3bc7fb68c1418ca20b6775212eecb3b056bb9d 100644 (file)
@@ -543,9 +543,19 @@ pub fn check_pat(tcx: &ty::ctxt, pat: &ast::Pat,
 
 fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
                             cb: &mut FnMut(ast::DefId, Span, &Option<&Stability>)) {
-    if !is_staged_api(tcx, id) { return  }
-    if is_internal(tcx, span) { return }
+    if !is_staged_api(tcx, id) {
+        debug!("maybe_do_stability_check: \
+                skipping id={:?} since it is not staged_api", id);
+        return;
+    }
+    if is_internal(tcx, span) {
+        debug!("maybe_do_stability_check: \
+                skipping span={:?} since it is internal", span);
+        return;
+    }
     let ref stability = lookup(tcx, id);
+    debug!("maybe_do_stability_check: \
+            inspecting id={:?} span={:?} of stability={:?}", id, span, stability);
     cb(id, span, stability);
 }
 
index 17a76f6eed9c5af59e415b23d4791d3d81e7a973..64e707f6264e6cae2bdf35ea569ea228e0fd8962 100644 (file)
@@ -3967,7 +3967,6 @@ mod TC {
         None                                = 0b0000_0000__0000_0000__0000,
 
         // Things that are interior to the value (first nibble):
-        InteriorUnsized                     = 0b0000_0000__0000_0000__0001,
         InteriorUnsafe                      = 0b0000_0000__0000_0000__0010,
         InteriorParam                       = 0b0000_0000__0000_0000__0100,
         // InteriorAll                         = 0b00000000__00000000__1111,
@@ -3977,18 +3976,9 @@ mod TC {
         OwnsDtor                            = 0b0000_0000__0000_0010__0000,
         OwnsAll                             = 0b0000_0000__1111_1111__0000,
 
-        // Things that are reachable by the value in any way (fourth nibble):
-        ReachesBorrowed                     = 0b0000_0010__0000_0000__0000,
-        ReachesMutable                      = 0b0000_1000__0000_0000__0000,
-        ReachesFfiUnsafe                    = 0b0010_0000__0000_0000__0000,
-        ReachesAll                          = 0b0011_1111__0000_0000__0000,
-
         // Things that mean drop glue is necessary
         NeedsDrop                           = 0b0000_0000__0000_0111__0000,
 
-        // Things that prevent values from being considered sized
-        Nonsized                            = 0b0000_0000__0000_0000__0001,
-
         // All bits
         All                                 = 0b1111_1111__1111_1111__1111
     }
@@ -4007,10 +3997,6 @@ pub fn owns_owned(&self) -> bool {
         self.intersects(TC::OwnsOwned)
     }
 
-    pub fn is_sized(&self, _: &ctxt) -> bool {
-        !self.intersects(TC::Nonsized)
-    }
-
     pub fn interior_param(&self) -> bool {
         self.intersects(TC::InteriorParam)
     }
@@ -4019,29 +4005,13 @@ pub fn interior_unsafe(&self) -> bool {
         self.intersects(TC::InteriorUnsafe)
     }
 
-    pub fn interior_unsized(&self) -> bool {
-        self.intersects(TC::InteriorUnsized)
-    }
-
     pub fn needs_drop(&self, _: &ctxt) -> bool {
         self.intersects(TC::NeedsDrop)
     }
 
     /// Includes only those bits that still apply when indirected through a `Box` pointer
     pub fn owned_pointer(&self) -> TypeContents {
-        TC::OwnsOwned | (
-            *self & (TC::OwnsAll | TC::ReachesAll))
-    }
-
-    /// Includes only those bits that still apply when indirected through a reference (`&`)
-    pub fn reference(&self, bits: TypeContents) -> TypeContents {
-        bits | (
-            *self & TC::ReachesAll)
-    }
-
-    /// Includes only those bits that still apply when indirected through a raw pointer (`*`)
-    pub fn unsafe_pointer(&self) -> TypeContents {
-        *self & TC::ReachesAll
+        TC::OwnsOwned | (*self & TC::OwnsAll)
     }
 
     pub fn union<T, F>(v: &[T], mut f: F) -> TypeContents where
@@ -4129,7 +4099,7 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
             let result = match ty.sty {
                 // usize and isize are ffi-unsafe
                 TyUint(ast::TyUs) | TyInt(ast::TyIs) => {
-                    TC::ReachesFfiUnsafe
+                    TC::None
                 }
 
                 // Scalar and unique types are sendable, and durable
@@ -4140,20 +4110,19 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TyBox(typ) => {
-                    TC::ReachesFfiUnsafe | tc_ty(cx, typ, cache).owned_pointer()
+                    tc_ty(cx, typ, cache).owned_pointer()
                 }
 
-                TyTrait(box TraitTy { ref bounds, .. }) => {
-                    object_contents(bounds) | TC::ReachesFfiUnsafe | TC::Nonsized
+                TyTrait(_) => {
+                    TC::All - TC::InteriorParam
                 }
 
-                TyRawPtr(ref mt) => {
-                    tc_ty(cx, mt.ty, cache).unsafe_pointer()
+                TyRawPtr(_) => {
+                    TC::None
                 }
 
-                TyRef(r, ref mt) => {
-                    tc_ty(cx, mt.ty, cache).reference(borrowed_contents(*r, mt.mutbl)) |
-                        TC::ReachesFfiUnsafe
+                TyRef(_, _) => {
+                    TC::None
                 }
 
                 TyArray(ty, _) => {
@@ -4161,19 +4130,15 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TySlice(ty) => {
-                    tc_ty(cx, ty, cache) | TC::Nonsized
+                    tc_ty(cx, ty, cache)
                 }
-                TyStr => TC::Nonsized,
+                TyStr => TC::None,
 
                 TyStruct(did, substs) => {
                     let flds = cx.struct_fields(did, substs);
                     let mut res =
                         TypeContents::union(&flds[..],
-                                            |f| tc_mt(cx, f.mt, cache));
-
-                    if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) {
-                        res = res | TC::ReachesFfiUnsafe;
-                    }
+                                            |f| tc_ty(cx, f.mt.ty, cache));
 
                     if cx.has_dtor(did) {
                         res = res | TC::OwnsDtor;
@@ -4182,7 +4147,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                 }
 
                 TyClosure(did, substs) => {
-                    // FIXME(#14449): `borrowed_contents` below assumes `&mut` closure.
                     let param_env = cx.empty_parameter_environment();
                     let infcx = infer::new_infer_ctxt(cx, &cx.tables, Some(param_env), false);
                     let upvars = infcx.closure_upvars(did, substs).unwrap();
@@ -4208,44 +4172,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
                         res = res | TC::OwnsDtor;
                     }
 
-                    if !variants.is_empty() {
-                        let repr_hints = cx.lookup_repr_hints(did);
-                        if repr_hints.len() > 1 {
-                            // this is an error later on, but this type isn't safe
-                            res = res | TC::ReachesFfiUnsafe;
-                        }
-
-                        match repr_hints.get(0) {
-                            Some(h) => if !h.is_ffi_safe() {
-                                res = res | TC::ReachesFfiUnsafe;
-                            },
-                            // ReprAny
-                            None => {
-                                res = res | TC::ReachesFfiUnsafe;
-
-                                // We allow ReprAny enums if they are eligible for
-                                // the nullable pointer optimization and the
-                                // contained type is an `extern fn`
-
-                                if variants.len() == 2 {
-                                    let mut data_idx = 0;
-
-                                    if variants[0].args.is_empty() {
-                                        data_idx = 1;
-                                    }
-
-                                    if variants[data_idx].args.len() == 1 {
-                                        match variants[data_idx].args[0].sty {
-                                            TyBareFn(..) => { res = res - TC::ReachesFfiUnsafe; }
-                                            _ => { }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-
                     apply_lang_items(cx, did, res)
                 }
 
@@ -4264,14 +4190,6 @@ fn tc_ty<'tcx>(cx: &ctxt<'tcx>,
             result
         }
 
-        fn tc_mt<'tcx>(cx: &ctxt<'tcx>,
-                       mt: TypeAndMut<'tcx>,
-                       cache: &mut FnvHashMap<Ty<'tcx>, TypeContents>) -> TypeContents
-        {
-            let mc = TC::ReachesMutable.when(mt.mutbl == MutMutable);
-            mc | tc_ty(cx, mt.ty, cache)
-        }
-
         fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents)
                             -> TypeContents {
             if Some(did) == cx.lang_items.unsafe_cell_type() {
@@ -4280,32 +4198,6 @@ fn apply_lang_items(cx: &ctxt, did: ast::DefId, tc: TypeContents)
                 tc
             }
         }
-
-        /// Type contents due to containing a reference with
-        /// the region `region` and borrow kind `bk`.
-        fn borrowed_contents(region: ty::Region,
-                             mutbl: ast::Mutability)
-                             -> TypeContents {
-            let b = match mutbl {
-                ast::MutMutable => TC::ReachesMutable,
-                ast::MutImmutable => TC::None,
-            };
-            b | (TC::ReachesBorrowed).when(region != ty::ReStatic)
-        }
-
-        fn object_contents(bounds: &ExistentialBounds) -> TypeContents {
-            // These are the type contents of the (opaque) interior. We
-            // make no assumptions (other than that it cannot have an
-            // in-scope type parameter within, which makes no sense).
-            let mut tc = TC::All - TC::InteriorParam;
-            for bound in &bounds.builtin_bounds {
-                tc = tc - match bound {
-                    BoundSync | BoundSend | BoundCopy => TC::None,
-                    BoundSized => TC::Nonsized,
-                };
-            }
-            return tc;
-        }
     }
 
     fn impls_bound<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
@@ -4399,10 +4291,6 @@ fn is_sized_uncached<'a>(&'tcx self, param_env: &ParameterEnvironment<'a,'tcx>,
         result
     }
 
-    pub fn is_ffi_safe(&'tcx self, cx: &ctxt<'tcx>) -> bool {
-        !self.type_contents(cx).intersects(TC::ReachesFfiUnsafe)
-    }
-
     // True if instantiating an instance of `r_ty` requires an instance of `r_ty`.
     pub fn is_instantiable(&'tcx self, cx: &ctxt<'tcx>) -> bool {
         fn type_requires<'tcx>(cx: &ctxt<'tcx>, seen: &mut Vec<DefId>,
index 2c3d240dbf3d53851ad732980b532c4620d1fb29..5cf83e575794c83cee2fa0ccee142d1b78bd5cec 100644 (file)
@@ -18,7 +18,7 @@ pub fn opts() -> TargetOptions {
         executables: true,
         morestack: true,
         has_rpath: true,
-        archive_format: "bsd".to_string(),
+        archive_format: "gnu".to_string(),
 
         .. Default::default()
     }
index ae95466e6e675e4fd60682262ed02f8317c0ba5e..6289d50588104bbffa0baf63dd9379b38862e535 100644 (file)
 #![allow(deprecated)]
 
 use metadata::{csearch, decoder};
+use middle::{cfg, def, infer, pat_util, stability, traits};
 use middle::def::*;
-use middle::infer;
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
-use middle::traits;
-use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
 use middle::const_eval::EvalHint::ExprTypeChecked;
-use middle::cfg;
 use rustc::ast_map;
-use util::nodemap::{FnvHashMap, NodeSet};
+use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet};
 use lint::{Level, Context, LintPass, LintArray, Lint};
 
 use std::collections::{HashSet, BitSet};
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 use std::{cmp, slice};
 use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
+use std::rc::Rc;
 
 use syntax::{abi, ast};
 use syntax::ast_util::{self, is_shift_binop, local_def};
@@ -405,43 +403,288 @@ struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
     cx: &'a Context<'a, 'tcx>
 }
 
+enum FfiResult {
+    FfiSafe,
+    FfiUnsafe(&'static str),
+    FfiBadStruct(ast::DefId, &'static str),
+    FfiBadEnum(ast::DefId, &'static str)
+}
+
+/// Check if this enum can be safely exported based on the
+/// "nullable pointer optimization". Currently restricted
+/// to function pointers and references, but could be
+/// expanded to cover NonZero raw pointers and newtypes.
+/// FIXME: This duplicates code in trans.
+fn is_repr_nullable_ptr<'tcx>(variants: &Vec<Rc<ty::VariantInfo<'tcx>>>) -> bool {
+    if variants.len() == 2 {
+        let mut data_idx = 0;
+
+        if variants[0].args.is_empty() {
+            data_idx = 1;
+        } else if !variants[1].args.is_empty() {
+            return false;
+        }
+
+        if variants[data_idx].args.len() == 1 {
+            match variants[data_idx].args[0].sty {
+                ty::TyBareFn(None, _) => { return true; }
+                ty::TyRef(..) => { return true; }
+                _ => { }
+            }
+        }
+    }
+    false
+}
+
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
-    fn check_def(&mut self, sp: Span, id: ast::NodeId) {
-        match self.cx.tcx.def_map.borrow().get(&id).unwrap().full_def() {
-            def::DefPrimTy(ast::TyInt(ast::TyIs)) => {
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                  "found rust type `isize` in foreign module, while \
-                                   libc::c_int or libc::c_long should be used");
+    /// Check if the given type is "ffi-safe" (has a stable, well-defined
+    /// representation which can be exported to C code).
+    fn check_type_for_ffi(&self,
+                          cache: &mut FnvHashSet<Ty<'tcx>>,
+                          ty: Ty<'tcx>)
+                          -> FfiResult {
+        use self::FfiResult::*;
+        let cx = &self.cx.tcx;
+
+        // Protect against infinite recursion, for example
+        // `struct S(*mut S);`.
+        // FIXME: A recursion limit is necessary as well, for irregular
+        // recusive types.
+        if !cache.insert(ty) {
+            return FfiSafe;
+        }
+
+        match ty.sty {
+            ty::TyStruct(did, substs) => {
+                if !cx.lookup_repr_hints(did).contains(&attr::ReprExtern) {
+                    return FfiUnsafe(
+                        "found struct without foreign-function-safe \
+                         representation annotation in foreign module, \
+                         consider adding a #[repr(C)] attribute to \
+                         the type");
+                }
+
+                // We can't completely trust repr(C) markings; make sure the
+                // fields are actually safe.
+                let fields = cx.struct_fields(did, substs);
+
+                if fields.is_empty() {
+                    return FfiUnsafe(
+                        "found zero-size struct in foreign module, consider \
+                         adding a member to this struct");
+                }
+
+                for field in fields {
+                    let field_ty = infer::normalize_associated_type(cx, &field.mt.ty);
+                    let r = self.check_type_for_ffi(cache, field_ty);
+                    match r {
+                        FfiSafe => {}
+                        FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                        FfiUnsafe(s) => { return FfiBadStruct(did, s); }
+                    }
+                }
+                FfiSafe
             }
-            def::DefPrimTy(ast::TyUint(ast::TyUs)) => {
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                  "found rust type `usize` in foreign module, while \
-                                   libc::c_uint or libc::c_ulong should be used");
+            ty::TyEnum(did, substs) => {
+                let variants = cx.substd_enum_variants(did, substs);
+                if variants.is_empty() {
+                    // Empty enums are okay... although sort of useless.
+                    return FfiSafe
+                }
+
+                // Check for a repr() attribute to specify the size of the
+                // discriminant.
+                let repr_hints = cx.lookup_repr_hints(did);
+                match &**repr_hints {
+                    [] => {
+                        // Special-case types like `Option<extern fn()>`.
+                        if !is_repr_nullable_ptr(&variants) {
+                            return FfiUnsafe(
+                                "found enum without foreign-function-safe \
+                                 representation annotation in foreign module, \
+                                 consider adding a #[repr(...)] attribute to \
+                                 the type")
+                        }
+                    }
+                    [ref hint] => {
+                        if !hint.is_ffi_safe() {
+                            // FIXME: This shouldn't be reachable: we should check
+                            // this earlier.
+                            return FfiUnsafe(
+                                "enum has unexpected #[repr(...)] attribute")
+                        }
+
+                        // Enum with an explicitly sized discriminant; either
+                        // a C-style enum or a discriminated union.
+
+                        // The layout of enum variants is implicitly repr(C).
+                        // FIXME: Is that correct?
+                    }
+                    _ => {
+                        // FIXME: This shouldn't be reachable: we should check
+                        // this earlier.
+                        return FfiUnsafe(
+                            "enum has too many #[repr(...)] attributes");
+                    }
+                }
+
+                // Check the contained variants.
+                for variant in variants {
+                    for arg in &variant.args {
+                        let arg = infer::normalize_associated_type(cx, arg);
+                        let r = self.check_type_for_ffi(cache, arg);
+                        match r {
+                            FfiSafe => {}
+                            FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+                            FfiUnsafe(s) => { return FfiBadEnum(did, s); }
+                        }
+                    }
+                }
+                FfiSafe
+            }
+
+            ty::TyInt(ast::TyIs) => {
+                FfiUnsafe("found Rust type `isize` in foreign module, while \
+                          `libc::c_int` or `libc::c_long` should be used")
+            }
+            ty::TyUint(ast::TyUs) => {
+                FfiUnsafe("found Rust type `usize` in foreign module, while \
+                          `libc::c_uint` or `libc::c_ulong` should be used")
+            }
+            ty::TyChar => {
+                FfiUnsafe("found Rust type `char` in foreign module, while \
+                           `u32` or `libc::wchar_t` should be used")
+            }
+
+            // Primitive types with a stable representation.
+            ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
+            ty::TyFloat(..) => FfiSafe,
+
+            ty::TyBox(..) => {
+                FfiUnsafe("found Rust type Box<_> in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TySlice(_) => {
+                FfiUnsafe("found Rust slice type in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TyTrait(..) => {
+                FfiUnsafe("found Rust trait type in foreign module, \
+                           consider using a raw pointer instead")
+            }
+
+            ty::TyStr => {
+                FfiUnsafe("found Rust type `str` in foreign module; \
+                           consider using a `*const libc::c_char`")
             }
-            def::DefTy(..) => {
-                let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
-                    Some(&t) => t,
-                    None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
-                };
 
-                if !tty.is_ffi_safe(self.cx.tcx) {
-                    self.cx.span_lint(IMPROPER_CTYPES, sp,
-                                      "found type without foreign-function-safe \
-                                       representation annotation in foreign module, consider \
-                                       adding a #[repr(...)] attribute to the type");
+            ty::TyTuple(_) => {
+                FfiUnsafe("found Rust tuple type in foreign module; \
+                           consider using a struct instead`")
+            }
+
+            ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
+                self.check_type_for_ffi(cache, m.ty)
+            }
+
+            ty::TyArray(ty, _) => {
+                self.check_type_for_ffi(cache, ty)
+            }
+
+            ty::TyBareFn(None, bare_fn) => {
+                match bare_fn.abi {
+                    abi::Rust |
+                    abi::RustIntrinsic |
+                    abi::RustCall => {
+                        return FfiUnsafe(
+                            "found function pointer with Rust calling \
+                             convention in foreign module; consider using an \
+                             `extern` function pointer")
+                    }
+                    _ => {}
                 }
+
+                let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+                match sig.output {
+                    ty::FnDiverging => {}
+                    ty::FnConverging(output) => {
+                        if !output.is_nil() {
+                            let r = self.check_type_for_ffi(cache, output);
+                            match r {
+                                FfiSafe => {}
+                                _ => { return r; }
+                            }
+                        }
+                    }
+                }
+                for arg in sig.inputs {
+                    let r = self.check_type_for_ffi(cache, arg);
+                    match r {
+                        FfiSafe => {}
+                        _ => { return r; }
+                    }
+                }
+                FfiSafe
+            }
+
+            ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
+            ty::TyClosure(..) | ty::TyProjection(..) |
+            ty::TyBareFn(Some(_), _) => {
+                panic!("Unexpected type in foreign function")
+            }
+        }
+    }
+
+    fn check_def(&mut self, sp: Span, id: ast::NodeId) {
+        let tty = match self.cx.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
+            Some(&t) => t,
+            None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
+        };
+        let tty = infer::normalize_associated_type(self.cx.tcx, &tty);
+
+        match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
+            FfiResult::FfiSafe => {}
+            FfiResult::FfiUnsafe(s) => {
+                self.cx.span_lint(IMPROPER_CTYPES, sp, s);
+            }
+            FfiResult::FfiBadStruct(_, s) => {
+                // FIXME: This diagnostic is difficult to read, and doesn't
+                // point at the relevant field.
+                self.cx.span_lint(IMPROPER_CTYPES, sp,
+                    &format!("found non-foreign-function-safe member in \
+                              struct marked #[repr(C)]: {}", s));
+            }
+            FfiResult::FfiBadEnum(_, s) => {
+                // FIXME: This diagnostic is difficult to read, and doesn't
+                // point at the relevant variant.
+                self.cx.span_lint(IMPROPER_CTYPES, sp,
+                    &format!("found non-foreign-function-safe member in \
+                              enum: {}", s));
             }
-            _ => ()
         }
     }
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
     fn visit_ty(&mut self, ty: &ast::Ty) {
-        if let ast::TyPath(..) = ty.node {
-            self.check_def(ty.span, ty.id);
+        match ty.node {
+            ast::TyPath(..) |
+            ast::TyBareFn(..) => self.check_def(ty.span, ty.id),
+            ast::TyVec(..) => {
+                self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+                    "found Rust slice type in foreign module, consider \
+                     using a raw pointer instead");
+            }
+            ast::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
+            ast::TyTup(..) => {
+                self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+                    "found Rust tuple type in foreign module; \
+                     consider using a struct instead`")
+            }
+            _ => visit::walk_ty(self, ty)
         }
-        visit::walk_ty(self, ty);
     }
 }
 
index 54c1a79e10a9b709a43e8ea5c05d2dce6fd2f6dc..8d6dfb929873064aad959f9c7275ea910d01efb8 100644 (file)
@@ -38,6 +38,7 @@
 #![feature(ref_slice)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
+#![feature(slice_patterns)]
 #![feature(staged_api)]
 #![feature(str_char)]
 
index 83f8619c5eeabd1e2976b976eae81da9891b3adf..9ee046915daca66a4a526b90df3cc8d64998e46f 100644 (file)
@@ -685,7 +685,7 @@ pub fn LLVMVectorType(ElementType: TypeRef, ElementCount: c_uint)
     pub fn LLVMGetArrayLength(ArrayTy: TypeRef) -> c_uint;
     pub fn LLVMGetPointerAddressSpace(PointerTy: TypeRef) -> c_uint;
     pub fn LLVMGetPointerToGlobal(EE: ExecutionEngineRef, V: ValueRef)
-                                  -> *const ();
+                                  -> *const c_void;
     pub fn LLVMGetVectorSize(VectorTy: TypeRef) -> c_uint;
 
     /* Operations on other types */
index dfeb866c5b3f00a2fd7b69e8079bad0a50edb58d..518add44b4c4a6b5622adad232e10daa0e8983ef 100644 (file)
@@ -16,6 +16,7 @@
 use llvm::{ModuleRef, TargetMachineRef, True, False};
 use rustc::metadata::cstore;
 use rustc::util::common::time;
+use back::write::{ModuleConfig, with_llvm_pmb};
 
 use libc;
 use flate;
@@ -23,7 +24,8 @@
 use std::ffi::CString;
 
 pub fn run(sess: &session::Session, llmod: ModuleRef,
-           tm: TargetMachineRef, reachable: &[String]) {
+           tm: TargetMachineRef, reachable: &[String],
+           config: &ModuleConfig) {
     if sess.opts.cg.prefer_dynamic {
         sess.err("cannot prefer dynamic linking when performing LTO");
         sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
@@ -144,19 +146,11 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
         llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
         llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
 
-        let opt = match sess.opts.optimize {
-            config::No => 0,
-            config::Less => 1,
-            config::Default => 2,
-            config::Aggressive => 3,
-        };
-
-        let builder = llvm::LLVMPassManagerBuilderCreate();
-        llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
-        llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
-            /* Internalize = */ False,
-            /* RunInliner = */ True);
-        llvm::LLVMPassManagerBuilderDispose(builder);
+        with_llvm_pmb(llmod, config, &mut |b| {
+            llvm::LLVMPassManagerBuilderPopulateLTOPassManager(b, pm,
+                /* Internalize = */ False,
+                /* RunInliner = */ True);
+        });
 
         llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
 
index 97fd7f99d197e4714f3f08ad5466020a12bb4486..21078641c1f536ccd7c917a1c926e30633d2220e 100644 (file)
@@ -13,6 +13,7 @@
 use std::os::windows::prelude::*;
 use std::ops::RangeFrom;
 use libc::{DWORD, LPCWSTR, LONG, LPDWORD, LPBYTE, ERROR_SUCCESS};
+use libc::c_void;
 
 const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY;
 const KEY_WOW64_32KEY: REGSAM = 0x0200;
@@ -32,7 +33,7 @@ enum __HKEY__ {}
 pub type PHKEY = *mut HKEY;
 pub type REGSAM = DWORD;
 pub type LPWSTR = *mut u16;
-pub type PFILETIME = *mut ();
+pub type PFILETIME = *mut c_void;
 
 #[link(name = "advapi32")]
 extern "system" {
index 1f97a9b93edf5d9cb49db077e4fa3adffbfadcf3..b901e31a53a001861661355ee8b23b7c7a52fd24 100644 (file)
@@ -249,7 +249,7 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
 
 /// Module-specific configuration for `optimize_and_codegen`.
 #[derive(Clone)]
-struct ModuleConfig {
+pub struct ModuleConfig {
     /// LLVM TargetMachine to use for codegen.
     tm: TargetMachineRef,
     /// Names of additional optimization passes to run.
@@ -444,72 +444,72 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
     }
 
-    match config.opt_level {
-        Some(opt_level) => {
-            // Create the two optimizing pass managers. These mirror what clang
-            // does, and are by populated by LLVM's default PassManagerBuilder.
-            // Each manager has a different set of passes, but they also share
-            // some common passes.
-            let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
-            let mpm = llvm::LLVMCreatePassManager();
-
-            // If we're verifying or linting, add them to the function pass
-            // manager.
-            let addpass = |pass: &str| {
-                let pass = CString::new(pass).unwrap();
-                llvm::LLVMRustAddPass(fpm, pass.as_ptr())
-            };
+    if config.opt_level.is_some() {
+        // Create the two optimizing pass managers. These mirror what clang
+        // does, and are by populated by LLVM's default PassManagerBuilder.
+        // Each manager has a different set of passes, but they also share
+        // some common passes.
+        let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
+        let mpm = llvm::LLVMCreatePassManager();
+
+        // If we're verifying or linting, add them to the function pass
+        // manager.
+        let addpass = |pass: &str| {
+            let pass = CString::new(pass).unwrap();
+            llvm::LLVMRustAddPass(fpm, pass.as_ptr())
+        };
 
-            if !config.no_verify { assert!(addpass("verify")); }
-            if !config.no_prepopulate_passes {
-                llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
-                llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
-                populate_llvm_passes(fpm, mpm, llmod, opt_level, &config);
-            }
+        if !config.no_verify { assert!(addpass("verify")); }
+        if !config.no_prepopulate_passes {
+            llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
+            llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
+            with_llvm_pmb(llmod, &config, &mut |b| {
+                llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
+                llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
+            })
+        }
 
-            for pass in &config.passes {
-                if !addpass(pass) {
-                    cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
-                                               pass));
-                }
+        for pass in &config.passes {
+            if !addpass(pass) {
+                cgcx.handler.warn(&format!("unknown pass `{}`, ignoring",
+                                           pass));
             }
+        }
 
-            for pass in &cgcx.plugin_passes {
-                if !addpass(pass) {
-                    cgcx.handler.err(&format!("a plugin asked for LLVM pass \
-                                               `{}` but LLVM does not \
-                                               recognize it", pass));
-                }
+        for pass in &cgcx.plugin_passes {
+            if !addpass(pass) {
+                cgcx.handler.err(&format!("a plugin asked for LLVM pass \
+                                           `{}` but LLVM does not \
+                                           recognize it", pass));
             }
+        }
 
-            cgcx.handler.abort_if_errors();
+        cgcx.handler.abort_if_errors();
 
-            // Finally, run the actual optimization passes
-            time(config.time_passes, "llvm function passes", (), |()|
-                 llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
-            time(config.time_passes, "llvm module passes", (), |()|
-                 llvm::LLVMRunPassManager(mpm, llmod));
+        // Finally, run the actual optimization passes
+        time(config.time_passes, "llvm function passes", (), |()|
+             llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
+        time(config.time_passes, "llvm module passes", (), |()|
+             llvm::LLVMRunPassManager(mpm, llmod));
 
-            // Deallocate managers that we're now done with
-            llvm::LLVMDisposePassManager(fpm);
-            llvm::LLVMDisposePassManager(mpm);
+        // Deallocate managers that we're now done with
+        llvm::LLVMDisposePassManager(fpm);
+        llvm::LLVMDisposePassManager(mpm);
 
-            match cgcx.lto_ctxt {
-                Some((sess, reachable)) if sess.lto() =>  {
-                    time(sess.time_passes(), "all lto passes", (), |()|
-                         lto::run(sess, llmod, tm, reachable));
+        match cgcx.lto_ctxt {
+            Some((sess, reachable)) if sess.lto() =>  {
+                time(sess.time_passes(), "all lto passes", (), |()|
+                     lto::run(sess, llmod, tm, reachable, &config));
 
-                    if config.emit_lto_bc {
-                        let name = format!("{}.lto.bc", name_extra);
-                        let out = output_names.with_extension(&name);
-                        let out = path2cstr(&out);
-                        llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
-                    }
-                },
-                _ => {},
-            }
-        },
-        None => {},
+                if config.emit_lto_bc {
+                    let name = format!("{}.lto.bc", name_extra);
+                    let out = output_names.with_extension(&name);
+                    let out = path2cstr(&out);
+                    llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
+                }
+            },
+            _ => {},
+        }
     }
 
     // A codegen-specific pass manager is used to generate object
@@ -1001,15 +1001,14 @@ pub unsafe fn configure_llvm(sess: &Session) {
                                  llvm_args.as_ptr());
 }
 
-unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
-                               mpm: llvm::PassManagerRef,
-                               llmod: ModuleRef,
-                               opt: llvm::CodeGenOptLevel,
-                               config: &ModuleConfig) {
+pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
+                            config: &ModuleConfig,
+                            f: &mut FnMut(llvm::PassManagerBuilderRef)) {
     // Create the PassManagerBuilder for LLVM. We configure it with
     // reasonable defaults and prepare it to actually populate the pass
     // manager.
     let builder = llvm::LLVMPassManagerBuilderCreate();
+    let opt = config.opt_level.unwrap_or(llvm::CodeGenLevelNone);
 
     llvm::LLVMRustConfigurePassManagerBuilder(builder, opt,
                                               config.merge_functions,
@@ -1037,8 +1036,6 @@ unsafe fn populate_llvm_passes(fpm: llvm::PassManagerRef,
         }
     }
 
-    // Use the builder to populate the function/module pass managers.
-    llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm);
-    llvm::LLVMPassManagerBuilderPopulateModulePassManager(builder, mpm);
+    f(builder);
     llvm::LLVMPassManagerBuilderDispose(builder);
 }
index 4aeba2fe062872fc93a519ef83bbff8c07c3e5c2..258051357b1057b21ab41be45deba19a7f00ba11 100644 (file)
@@ -228,6 +228,7 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
     // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
     // FIXME(nagisa): investigate whether it can be changed into define_global
     let c = declare::declare_global(ccx, &name[..], ty);
+
     // Thread-local statics in some other crate need to *always* be linked
     // against in a thread-local fashion, so we need to be sure to apply the
     // thread-local attribute locally if it was present remotely. If we
@@ -239,7 +240,42 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
             llvm::set_thread_local(c, true);
         }
     }
-    if ccx.use_dll_storage_attrs() {
+
+    // MSVC is a little ornery about how items are imported across dlls, and for
+    // lots more info on dllimport/dllexport see the large comment in
+    // SharedCrateContext::new. Unfortunately, unlike functions, statics
+    // imported from dlls *must* be tagged with dllimport (if you forget
+    // dllimport on a function then the linker fixes it up with an injected
+    // shim). This means that to link correctly to an upstream Rust dynamic
+    // library we need to make sure its statics are tagged with dllimport.
+    //
+    // Hence, if this translation is using dll storage attributes and the crate
+    // that this const originated from is being imported as a dylib at some
+    // point we tag this with dllimport.
+    //
+    // Note that this is not 100% correct for a variety of reasons:
+    //
+    // 1. If we are producing an rlib and linking to an upstream rlib, we'll
+    //    omit the dllimport. It's a possibility, though, that some later
+    //    downstream compilation will link the same upstream dependency as a
+    //    dylib and use our rlib, causing linker errors because we didn't use
+    //    dllimport.
+    // 2. We may have multiple crate output types. For example if we are
+    //    emitting a statically linked binary as well as a dynamic library we'll
+    //    want to omit dllimport for the binary but we need to have it for the
+    //    dylib.
+    //
+    // For most every day uses, however, this should suffice. During the
+    // bootstrap we're almost always linking upstream to a dylib for some crate
+    // type output, so most imports will be tagged with dllimport (somewhat
+    // appropriately). Otherwise rust dylibs linking against rust dylibs is
+    // pretty rare in Rust so this will likely always be `false` and we'll never
+    // tag with dllimport.
+    //
+    // Note that we can't just blindly tag all constants with dllimport as can
+    // cause linkage errors when we're not actually linking against a dll. For
+    // more info on this see rust-lang/rust#26591.
+    if ccx.use_dll_storage_attrs() && ccx.upstream_dylib_used(did.krate) {
         llvm::SetDLLStorageClass(c, llvm::DLLImportStorageClass);
     }
     ccx.externs().borrow_mut().insert(name.to_string(), c);
index 760a4ae827aac66ef86adb86d07278e3d26b7f58..699b25b9ed09273660aa963c8a0ed2d17ca32a10 100644 (file)
@@ -11,6 +11,7 @@
 use llvm;
 use llvm::{ContextRef, ModuleRef, ValueRef, BuilderRef};
 use metadata::common::LinkMeta;
+use metadata::cstore;
 use middle::def::ExportMap;
 use middle::traits;
 use trans::adt;
@@ -784,6 +785,29 @@ pub fn check_drop_flag_for_sanity(&self) -> bool {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.shared.use_dll_storage_attrs()
     }
+
+    /// Tests whether the given `krate` (an upstream crate) is ever used as a
+    /// dynamic library for the final linkage of this crate.
+    pub fn upstream_dylib_used(&self, krate: ast::CrateNum) -> bool {
+        let tcx = self.tcx();
+        let formats = tcx.dependency_formats.borrow();
+        tcx.sess.crate_types.borrow().iter().any(|ct| {
+            match formats[ct].get(krate as usize - 1) {
+                // If a crate is explicitly linked dynamically then we're
+                // definitely using it dynamically. If it's not being linked
+                // then currently that means it's being included through another
+                // dynamic library, so we're including it dynamically.
+                Some(&Some(cstore::RequireDynamic)) |
+                Some(&None) => true,
+
+                // Static linkage isn't included dynamically and if there's not
+                // an entry in the array then this crate type isn't actually
+                // doing much linkage so there's nothing dynamic going on.
+                Some(&Some(cstore::RequireStatic)) |
+                None => false,
+            }
+        })
+    }
 }
 
 /// Declare any llvm intrinsics that you might need
index d77d48eea48c2d30bef7f331f6f637ce250225be..9486e4953f8516042bdf14e4c9423bc5246c4b58 100644 (file)
@@ -232,12 +232,13 @@ fn adjust_for_branches<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> {
 pub struct UnsafetyState {
     pub def: ast::NodeId,
     pub unsafety: ast::Unsafety,
+    pub unsafe_push_count: u32,
     from_fn: bool
 }
 
 impl UnsafetyState {
     pub fn function(unsafety: ast::Unsafety, def: ast::NodeId) -> UnsafetyState {
-        UnsafetyState { def: def, unsafety: unsafety, from_fn: true }
+        UnsafetyState { def: def, unsafety: unsafety, unsafe_push_count: 0, from_fn: true }
     }
 
     pub fn recurse(&mut self, blk: &ast::Block) -> UnsafetyState {
@@ -249,13 +250,20 @@ pub fn recurse(&mut self, blk: &ast::Block) -> UnsafetyState {
             ast::Unsafety::Unsafe if self.from_fn => *self,
 
             unsafety => {
-                let (unsafety, def) = match blk.rules {
-                    ast::UnsafeBlock(..) => (ast::Unsafety::Unsafe, blk.id),
-                    ast::DefaultBlock => (unsafety, self.def),
+                let (unsafety, def, count) = match blk.rules {
+                    ast::PushUnsafeBlock(..) =>
+                        (unsafety, blk.id, self.unsafe_push_count.checked_add(1).unwrap()),
+                    ast::PopUnsafeBlock(..) =>
+                        (unsafety, blk.id, self.unsafe_push_count.checked_sub(1).unwrap()),
+                    ast::UnsafeBlock(..) =>
+                        (ast::Unsafety::Unsafe, blk.id, self.unsafe_push_count),
+                    ast::DefaultBlock =>
+                        (unsafety, self.def, self.unsafe_push_count),
                 };
                 UnsafetyState{ def: def,
-                             unsafety: unsafety,
-                             from_fn: false }
+                               unsafety: unsafety,
+                               unsafe_push_count: count,
+                               from_fn: false }
             }
         }
     }
@@ -4884,9 +4892,7 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
             "move_val_init" => {
                 (1,
                  vec!(
-                    tcx.mk_mut_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
-                                                                  ty::BrAnon(0))),
-                                    param(ccx, 0)),
+                    tcx.mk_mut_ptr(param(ccx, 0)),
                     param(ccx, 0)
                   ),
                tcx.mk_nil())
index 82bc1314ad547dc14038760e2ec26c4b536e18d7..907eb3ed401ff6c795ccb7e8e658a180759f464c 100644 (file)
        test(no_crate_inject, attr(deny(warnings))),
        test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
 
+#![cfg_attr(stage0, allow(unused_features))]
 #![feature(alloc)]
 #![feature(allow_internal_unstable)]
 #![feature(associated_consts)]
 #![feature(no_std)]
 #![feature(oom)]
 #![feature(optin_builtin_traits)]
+#![feature(placement_in_syntax)]
 #![feature(rand)]
 #![feature(raw)]
 #![feature(reflect_marker)]
index 87941e79b2f7d79e6d2aa87b1454172ea9035be9..59fc8df6107310367ceeb26cc8cb34be05d7e291 100644 (file)
@@ -251,12 +251,11 @@ pub mod eabi {
     use rt::libunwind as uw;
     use libc::{c_void, c_int};
 
-    #[repr(C)]
-    pub struct EXCEPTION_RECORD;
-    #[repr(C)]
-    pub struct CONTEXT;
-    #[repr(C)]
-    pub struct DISPATCHER_CONTEXT;
+    // Fake definitions; these are actually complicated structs,
+    // but we don't use the contents here.
+    pub type EXCEPTION_RECORD = c_void;
+    pub type CONTEXT = c_void;
+    pub type DISPATCHER_CONTEXT = c_void;
 
     #[repr(C)]
     #[derive(Copy, Clone)]
index cf827848db5c99f0f70de6295220a007ecb4fb76..491b53c4ed95ca06ea2c41f1e4398d599cd46f03 100644 (file)
@@ -82,6 +82,7 @@ pub unsafe fn make_handler() -> Handler {
     Handler { _data: 0 as *mut libc::c_void }
 }
 
+#[repr(C)]
 pub struct EXCEPTION_RECORD {
     pub ExceptionCode: DWORD,
     pub ExceptionFlags: DWORD,
@@ -91,6 +92,7 @@ pub struct EXCEPTION_RECORD {
     pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS]
 }
 
+#[repr(C)]
 pub struct EXCEPTION_POINTERS {
     pub ExceptionRecord: *mut EXCEPTION_RECORD,
     pub ContextRecord: LPVOID
index e2873601a7b6638e2463a932483e19cbaca0859d..11b375dcce2f4c20a3581019cd20d898785bd716 100644 (file)
@@ -335,13 +335,13 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
             #[linkage = "extern_weak"]
             static __dso_handle: *mut u8;
             #[linkage = "extern_weak"]
-            static __cxa_thread_atexit_impl: *const ();
+            static __cxa_thread_atexit_impl: *const libc::c_void;
         }
         if !__cxa_thread_atexit_impl.is_null() {
             type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
                                       arg: *mut u8,
                                       dso_handle: *mut u8) -> libc::c_int;
-            mem::transmute::<*const (), F>(__cxa_thread_atexit_impl)
+            mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
             (dtor, t, &__dso_handle as *const _ as *mut _);
             return
         }
index a0059d33bed840c53d80a0c64cc12e0b8aee029d..fba9db401dbb1a2423762c0980beccd87d74f67c 100644 (file)
@@ -810,6 +810,8 @@ pub struct Field {
 pub enum BlockCheckMode {
     DefaultBlock,
     UnsafeBlock(UnsafeSource),
+    PushUnsafeBlock(UnsafeSource),
+    PopUnsafeBlock(UnsafeSource),
 }
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
index e6bc3218897d91f3ec907c86cc256a81a1504343..17e6b2c2e12df69fc03d79c0793281d380e528bc 100644 (file)
@@ -980,6 +980,10 @@ pub fn span_allows_unstable(&self, span: Span) -> bool {
                             mac_span.lo <= span.lo && span.hi <= mac_span.hi
                         });
 
+                    debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}",
+                           (span.lo, span.hi),
+                           (info.call_site.lo, info.call_site.hi),
+                           info.callee.span.map(|x| (x.lo, x.hi)));
                     debug!("span_allows_unstable: from this expansion? {}, allows unstable? {}",
                            span_comes_from_this_expansion,
                            info.callee.allow_internal_unstable);
index 499562edc0cc9e153b62837126396f14b252d564..409ae86db35d4ebe53404379c8a674e8b3e35c0f 100644 (file)
@@ -591,6 +591,12 @@ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension {
     syntax_expanders.insert(intern("cfg"),
                             builtin_normal_expander(
                                     ext::cfg::expand_cfg));
+    syntax_expanders.insert(intern("push_unsafe"),
+                            builtin_normal_expander(
+                                ext::pushpop_safe::expand_push_unsafe));
+    syntax_expanders.insert(intern("pop_unsafe"),
+                            builtin_normal_expander(
+                                ext::pushpop_safe::expand_pop_unsafe));
     syntax_expanders.insert(intern("trace_macros"),
                             builtin_normal_expander(
                                     ext::trace_macros::expand_trace_macros));
index 53befc092da88f363d9e10b91fa8a4d1a48f36d7..faa1e5b2f515fff67234c75677733d14e69e8b85 100644 (file)
 use visit::Visitor;
 use std_inject;
 
+// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+fn mk_core_path(fld: &mut MacroExpander,
+                span: Span,
+                suffix: &[&'static str]) -> ast::Path {
+    let mut idents = vec![fld.cx.ident_of_std("core")];
+    for s in suffix.iter() { idents.push(fld.cx.ident_of(*s)); }
+    fld.cx.path_global(span, idents)
+}
+
 pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
     fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc: &str) {
         fld.cx.bt_push(ExpnInfo {
@@ -40,13 +50,26 @@ fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc:
             callee: NameAndSpan {
                 name: expansion_desc.to_string(),
                 format: CompilerExpansion,
+
+                // This does *not* mean code generated after
+                // `push_compiler_expansion` is automatically exempt
+                // from stability lints; must also tag such code with
+                // an appropriate span from `fld.cx.backtrace()`.
                 allow_internal_unstable: true,
+
                 span: None,
             },
         });
     }
 
-    e.and_then(|ast::Expr {id, node, span}| match node {
+    // Sets the expn_id so that we can use unstable methods.
+    fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span {
+        Span { expn_id: fld.cx.backtrace(), ..span }
+    }
+
+    let expr_span = e.span;
+    return e.and_then(|ast::Expr {id, node, span}| match node {
+
         // expr_mac should really be expr_ext or something; it's the
         // entry-point for all syntax extensions.
         ast::ExprMac(mac) => {
@@ -71,6 +94,118 @@ fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc:
             })
         }
 
+        // Desugar ExprBox: `in (PLACE) EXPR`
+        ast::ExprBox(Some(placer), value_expr) => {
+            // to:
+            //
+            // let p = PLACE;
+            // let mut place = Placer::make_place(p);
+            // let raw_place = Place::pointer(&mut place);
+            // push_unsafe!({
+            //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+            //     InPlace::finalize(place)
+            // })
+
+            // Ensure feature-gate is enabled
+            feature_gate::check_for_placement_in(
+                fld.cx.ecfg.features,
+                &fld.cx.parse_sess.span_diagnostic,
+                expr_span);
+
+            push_compiler_expansion(fld, expr_span, "placement-in expansion");
+
+            let value_span = value_expr.span;
+            let placer_span = placer.span;
+
+            let placer_expr = fld.fold_expr(placer);
+            let value_expr = fld.fold_expr(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 = fld.cx.expr_ident(span, placer_ident);
+            let agent = fld.cx.expr_ident(span, agent_ident);
+            let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);
+
+            let make_place = ["ops", "Placer", "make_place"];
+            let place_pointer = ["ops", "Place", "pointer"];
+            let move_val_init = ["intrinsics", "move_val_init"];
+            let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+            let make_call = |fld: &mut MacroExpander, p, args| {
+                // We feed in the `expr_span` because codemap's span_allows_unstable
+                // allows the call_site span to inherit the `allow_internal_unstable`
+                // setting.
+                let span_unstable = allow_unstable(fld, expr_span);
+                let path = mk_core_path(fld, span_unstable, p);
+                let path = fld.cx.expr_path(path);
+                let expr_span_unstable = allow_unstable(fld, span);
+                fld.cx.expr_call(expr_span_unstable, path, args)
+            };
+
+            let stmt_let = |fld: &mut MacroExpander, bind, expr| {
+                fld.cx.stmt_let(placer_span, false, bind, expr)
+            };
+            let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
+                fld.cx.stmt_let(placer_span, true, bind, expr)
+            };
+
+            // let placer = <placer_expr> ;
+            let s1 = stmt_let(fld, placer_ident, placer_expr);
+
+            // let mut place = Placer::make_place(placer);
+            let s2 = {
+                let call = make_call(fld, &make_place, vec![placer]);
+                stmt_let_mut(fld, agent_ident, call)
+            };
+
+            // let p_ptr = Place::pointer(&mut place);
+            let s3 = {
+                let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
+                let call = make_call(fld, &place_pointer, args);
+                stmt_let(fld, p_ptr_ident, call)
+            };
+
+            // pop_unsafe!(EXPR));
+            let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span);
+
+            // push_unsafe!({
+            //     ptr::write(p_ptr, pop_unsafe!(<value_expr>));
+            //     InPlace::finalize(place)
+            // })
+            let expr = {
+                let call_move_val_init = StmtSemi(make_call(
+                    fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID);
+                let call_move_val_init = codemap::respan(value_span, call_move_val_init);
+
+                let call = make_call(fld, &inplace_finalize, vec![agent]);
+                Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span))
+            };
+
+            let block = fld.cx.block_all(span, vec![s1, s2, s3], expr);
+            let result = fld.cx.expr_block(block);
+            fld.cx.bt_pop();
+            result
+        }
+
+        // Issue #22181:
+        // Eventually a desugaring for `box EXPR`
+        // (similar to the desugaring above for `in PLACE BLOCK`)
+        // should go here, desugaring
+        //
+        // to:
+        //
+        // let mut place = BoxPlace::make_place();
+        // let raw_place = Place::pointer(&mut place);
+        // let value = $value;
+        // unsafe {
+        //     ::std::ptr::write(raw_place, value);
+        //     Boxed::finalize(place)
+        // }
+        //
+        // But for now there are type-inference issues doing that.
+
         ast::ExprWhile(cond, body, opt_ident) => {
             let cond = fld.fold_expr(cond);
             let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
@@ -360,7 +495,26 @@ fn push_compiler_expansion(fld: &mut MacroExpander, span: Span, expansion_desc:
                 span: span
             }, fld))
         }
-    })
+    });
+
+    fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec<P<ast::Stmt>>,
+                        expr: P<ast::Expr>, span: Span)
+                        -> P<ast::Expr> {
+        let rules = ast::PushUnsafeBlock(ast::CompilerGenerated);
+        cx.expr_block(P(ast::Block {
+            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
+            stmts: stmts, expr: Some(expr),
+        }))
+    }
+
+    fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P<ast::Expr>, span: Span)
+                       -> P<ast::Expr> {
+        let rules = ast::PopUnsafeBlock(ast::CompilerGenerated);
+        cx.expr_block(P(ast::Block {
+            rules: rules, span: span, id: ast::DUMMY_NODE_ID,
+            stmts: vec![], expr: Some(expr),
+        }))
+    }
 }
 
 /// Expand a (not-ident-style) macro invocation. Returns the result
@@ -1504,6 +1658,7 @@ fn enable_concat_idents = allow_concat_idents,
         fn enable_trace_macros = allow_trace_macros,
         fn enable_allow_internal_unstable = allow_internal_unstable,
         fn enable_custom_derive = allow_custom_derive,
+        fn enable_pushpop_unsafe = allow_pushpop_unsafe,
     }
 }
 
diff --git a/src/libsyntax/ext/pushpop_safe.rs b/src/libsyntax/ext/pushpop_safe.rs
new file mode 100644 (file)
index 0000000..a67d550
--- /dev/null
@@ -0,0 +1,94 @@
+// 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.
+
+/*
+ * The compiler code necessary to support the `push_unsafe!` and
+ * `pop_unsafe!` macros.
+ *
+ * This is a hack to allow a kind of "safety hygiene", where a macro
+ * can generate code with an interior expression that inherits the
+ * safety of some outer context.
+ *
+ * For example, in:
+ *
+ * ```rust
+ * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) }
+ * ```
+ *
+ * the `EXPR_1` is considered to be in an `unsafe` context,
+ * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context.
+ *
+ * For comparison, in:
+ *
+ * ```rust
+ * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } }
+ * ```
+ *
+ * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe`
+ * contexts.
+ *
+ */
+
+use ast;
+use codemap::Span;
+use ext::base::*;
+use ext::base;
+use ext::build::AstBuilder;
+use feature_gate;
+use ptr::P;
+
+enum PushPop { Push, Pop }
+
+pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                               -> Box<base::MacResult+'cx> {
+    expand_pushpop_unsafe(cx, sp, tts, PushPop::Push)
+}
+
+pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
+                               -> Box<base::MacResult+'cx> {
+    expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop)
+}
+
+fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree],
+                                  pp: PushPop) -> Box<base::MacResult+'cx> {
+    feature_gate::check_for_pushpop_syntax(
+        cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp);
+
+    let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
+        Some(exprs) => exprs.into_iter(),
+        None => return DummyResult::expr(sp),
+    };
+
+    let expr = match (exprs.next(), exprs.next()) {
+        (Some(expr), None) => expr,
+        _ => {
+            let msg = match pp {
+                PushPop::Push => "push_unsafe! takes 1 arguments",
+                PushPop::Pop => "pop_unsafe! takes 1 arguments",
+            };
+            cx.span_err(sp, msg);
+            return DummyResult::expr(sp);
+        }
+    };
+
+    let source = ast::UnsafeSource::CompilerGenerated;
+    let check_mode = match pp {
+        PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source),
+        PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source),
+    };
+
+    MacEager::expr(cx.expr_block(P(ast::Block {
+        stmts: vec![],
+        expr: Some(expr),
+        id: ast::DUMMY_NODE_ID,
+        rules: check_mode,
+        span: sp
+    })))
+}
index ab8cf9ae6b64f98ad861a423f3f820ca129fe433..8c6855036f6e9dc4058538179ec02b7207fcc7b2 100644 (file)
@@ -80,6 +80,8 @@
     ("visible_private_types", "1.0.0", Active),
     ("slicing_syntax", "1.0.0", Accepted),
     ("box_syntax", "1.0.0", Active),
+    ("placement_in_syntax", "1.0.0", Active),
+    ("pushpop_unsafe", "1.2.0", Active),
     ("on_unimplemented", "1.0.0", Active),
     ("simd_ffi", "1.0.0", Active),
     ("allocator", "1.0.0", Active),
@@ -325,6 +327,9 @@ pub struct Features {
     pub allow_trace_macros: bool,
     pub allow_internal_unstable: bool,
     pub allow_custom_derive: bool,
+    pub allow_placement_in: bool,
+    pub allow_box: bool,
+    pub allow_pushpop_unsafe: bool,
     pub simd_ffi: bool,
     pub unmarked_api: bool,
     pub negate_unsigned: bool,
@@ -348,6 +353,9 @@ pub fn new() -> Features {
             allow_trace_macros: false,
             allow_internal_unstable: false,
             allow_custom_derive: false,
+            allow_placement_in: false,
+            allow_box: false,
+            allow_pushpop_unsafe: false,
             simd_ffi: false,
             unmarked_api: false,
             negate_unsigned: false,
@@ -358,6 +366,36 @@ pub fn new() -> Features {
     }
 }
 
+const EXPLAIN_BOX_SYNTAX: &'static str =
+    "box expression syntax is experimental; you can call `Box::new` instead.";
+
+const EXPLAIN_PLACEMENT_IN: &'static str =
+    "placement-in expression syntax is experimental and subject to change.";
+
+const EXPLAIN_PUSHPOP_UNSAFE: &'static str =
+    "push/pop_unsafe macros are experimental and subject to change.";
+
+pub fn check_for_box_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+    if let Some(&Features { allow_box: true, .. }) = f {
+        return;
+    }
+    emit_feature_err(diag, "box_syntax", span, EXPLAIN_BOX_SYNTAX);
+}
+
+pub fn check_for_placement_in(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+    if let Some(&Features { allow_placement_in: true, .. }) = f {
+        return;
+    }
+    emit_feature_err(diag, "placement_in_syntax", span, EXPLAIN_PLACEMENT_IN);
+}
+
+pub fn check_for_pushpop_syntax(f: Option<&Features>, diag: &SpanHandler, span: Span) {
+    if let Some(&Features { allow_pushpop_unsafe: true, .. }) = f {
+        return;
+    }
+    emit_feature_err(diag, "pushpop_unsafe", span, EXPLAIN_PUSHPOP_UNSAFE);
+}
+
 struct Context<'a> {
     features: Vec<&'static str>,
     span_handler: &'a SpanHandler,
@@ -366,6 +404,11 @@ struct Context<'a> {
 }
 
 impl<'a> Context<'a> {
+    fn enable_feature(&mut self, feature: &'static str) {
+        debug!("enabling feature: {}", feature);
+        self.features.push(feature);
+    }
+
     fn gate_feature(&self, feature: &str, span: Span, explain: &str) {
         let has_feature = self.has_feature(feature);
         debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", feature, span, has_feature);
@@ -488,6 +531,26 @@ fn visit_mac(&mut self, mac: &ast::Mac) {
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
         self.context.check_attribute(attr, true);
     }
+
+    fn visit_expr(&mut self, e: &ast::Expr) {
+        // Issue 22181: overloaded-`box` and placement-`in` are
+        // implemented via a desugaring expansion, so their feature
+        // gates go into MacroVisitor since that works pre-expansion.
+        //
+        // Issue 22234: we also check during expansion as well.
+        // But we keep these checks as a pre-expansion check to catch
+        // uses in e.g. conditionalized code.
+
+        if let ast::ExprBox(None, _) = e.node {
+            self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
+        }
+
+        if let ast::ExprBox(Some(_), _) = e.node {
+            self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
+        }
+
+        visit::walk_expr(self, e);
+    }
 }
 
 struct PostExpansionVisitor<'a> {
@@ -754,7 +817,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
                     match KNOWN_FEATURES.iter()
                                         .find(|& &(n, _, _)| name == n) {
                         Some(&(name, _, Active)) => {
-                            cx.features.push(name);
+                            cx.enable_feature(name);
                         }
                         Some(&(_, _, Removed)) => {
                             span_handler.span_err(mi.span, "feature has been removed");
@@ -787,6 +850,9 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
         allow_trace_macros: cx.has_feature("trace_macros"),
         allow_internal_unstable: cx.has_feature("allow_internal_unstable"),
         allow_custom_derive: cx.has_feature("custom_derive"),
+        allow_placement_in: cx.has_feature("placement_in_syntax"),
+        allow_box: cx.has_feature("box_syntax"),
+        allow_pushpop_unsafe: cx.has_feature("pushpop_unsafe"),
         simd_ffi: cx.has_feature("simd_ffi"),
         unmarked_api: cx.has_feature("unmarked_api"),
         negate_unsigned: cx.has_feature("negate_unsigned"),
index d93af5da13c1e2803a2aa263e9340d3df035a42b..5424c0b214a4ee980222d7b4fae62b73dfccb3e0 100644 (file)
@@ -120,6 +120,7 @@ pub mod ext {
     pub mod log_syntax;
     pub mod mtwt;
     pub mod quote;
+    pub mod pushpop_safe;
     pub mod source_util;
     pub mod trace_macros;
 
index 4adfa3c311953210fe795d8eacd8be7bc73e8f0b..c2a2259a80adf7bca2d281e51e31c0521fc2ea7b 100644 (file)
@@ -2612,18 +2612,43 @@ pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> {
             ex = ExprAddrOf(m, e);
           }
           token::Ident(_, _) => {
-            if !self.check_keyword(keywords::Box) {
+            if !self.check_keyword(keywords::Box) && !self.check_keyword(keywords::In) {
                 return self.parse_dot_or_call_expr();
             }
 
             let lo = self.span.lo;
-            let box_hi = self.span.hi;
+            let keyword_hi = self.span.hi;
 
+            let is_in = self.token.is_keyword(keywords::In);
             try!(self.bump());
 
-            // Check for a place: `box(PLACE) EXPR`.
+            if is_in {
+              let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
+              let blk = try!(self.parse_block());
+              hi = blk.span.hi;
+              let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk));
+              ex = ExprBox(Some(place), blk_expr);
+              return Ok(self.mk_expr(lo, hi, ex));
+            }
+
+            // FIXME (#22181) Remove `box (PLACE) EXPR` support
+            // entirely after next release (enabling `(box (EXPR))`),
+            // since it will be replaced by `in PLACE { EXPR }`, ...
+            //
+            // ... but for now: check for a place: `box(PLACE) EXPR`.
+
             if try!(self.eat(&token::OpenDelim(token::Paren)) ){
-                // Support `box() EXPR` as the default.
+                // SNAP d4432b3
+                // Enable this warning after snapshot ...
+                //
+                // let box_span = mk_sp(lo, self.last_span.hi);
+                // self.span_warn(
+                //     box_span,
+                //     "deprecated syntax; use the `in` keyword now \
+                //            (e.g. change `box (<expr>) <expr>` to \
+                //                         `in <expr> { <expr> }`)");
+
+                // Continue supporting `box () EXPR` (temporarily)
                 if !try!(self.eat(&token::CloseDelim(token::Paren)) ){
                     let place = try!(self.parse_expr_nopanic());
                     try!(self.expect(&token::CloseDelim(token::Paren)));
@@ -2634,10 +2659,15 @@ pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> {
                         self.span_err(span,
                                       &format!("expected expression, found `{}`",
                                               this_token_to_string));
-                        let box_span = mk_sp(lo, box_hi);
+
+                        // Spanning just keyword avoids constructing
+                        // printout of arg expression (which starts
+                        // with parenthesis, as established above).
+
+                        let box_span = mk_sp(lo, keyword_hi);
                         self.span_suggestion(box_span,
-                                             "try using `box()` instead:",
-                                             "box()".to_string());
+                                             "try using `box ()` instead:",
+                                             format!("box ()"));
                         self.abort_if_errors();
                     }
                     let subexpression = try!(self.parse_prefix_expr());
@@ -2650,6 +2680,7 @@ pub fn parse_prefix_expr(&mut self) -> PResult<P<Expr>> {
             // Otherwise, we use the unique pointer default.
             let subexpression = try!(self.parse_prefix_expr());
             hi = subexpression.span.hi;
+
             // FIXME (pnkfelix): After working out kinks with box
             // desugaring, should be `ExprBox(None, subexpression)`
             // instead.
index 6693eed6aced5b63f7c67b72df03c224509b5ab3..448857389da6172b652d71a16b5704aa90c0164c 100644 (file)
@@ -1434,8 +1434,8 @@ pub fn print_block_maybe_unclosed(&mut self,
                                       attrs: &[ast::Attribute],
                                       close_box: bool) -> io::Result<()> {
         match blk.rules {
-            ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
-            ast::DefaultBlock => ()
+            ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")),
+            ast::DefaultBlock    | ast::PopUnsafeBlock(..) => ()
         }
         try!(self.maybe_print_comment(blk.span.lo));
         try!(self.ann.pre(self, NodeBlock(blk)));
index 86225874df77d39b6e89e702b821bd092b9ae47b..a40f0a245d17e62c9256a50d119fabc6f34cbf2f 100644 (file)
@@ -168,7 +168,7 @@ LLVMRustWriteArchive(char *Dst,
       Members.push_back(NewArchiveIterator(Member->child, Member->name));
     }
   }
-  auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, false);
+  auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
   if (!pair.second)
     return 0;
   LLVMRustSetLastError(pair.second.message().c_str());
diff --git a/src/test/auxiliary/xcrate-static.rs b/src/test/auxiliary/xcrate-static.rs
new file mode 100644 (file)
index 0000000..8509386
--- /dev/null
@@ -0,0 +1,15 @@
+// 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub static FOO: u8 = 8;
index 8f8b035f4a96b82b16ee2dd136df4005076f2637..9640b2b475b6a028da18e3a878b8097d7af3fae4 100644 (file)
@@ -8,15 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-fn main() {
-    use std::boxed::HEAP;
+// Check that `box EXPR` is feature-gated.
+//
+// See also feature-gate-placement-expr.rs
+//
+// (Note that the two tests are separated since the checks appear to
+// be performed at distinct phases, with an abort_if_errors call
+// separating them.)
 
+fn main() {
     let x = box 'c'; //~ ERROR box expression syntax is experimental
     println!("x: {}", x);
 
     let x = box () 'c'; //~ ERROR box expression syntax is experimental
     println!("x: {}", x);
-
-    let x = box (HEAP) 'c'; //~ ERROR box expression syntax is experimental
-    println!("x: {}", x);
 }
diff --git a/src/test/compile-fail/feature-gate-placement-expr.rs b/src/test/compile-fail/feature-gate-placement-expr.rs
new file mode 100644 (file)
index 0000000..64a1d49
--- /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 `in PLACE { EXPR }` is feature-gated.
+//
+// See also feature-gate-box-expr.rs
+//
+// (Note that the two tests are separated since the checks appear to
+// be performed at distinct phases, with an abort_if_errors call
+// separating them.)
+
+fn main() {
+    use std::boxed::HEAP;
+
+    let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental
+    println!("x: {}", x);
+
+    let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental
+    println!("x: {}", x);
+}
diff --git a/src/test/compile-fail/feature-gate-pushpop-unsafe.rs b/src/test/compile-fail/feature-gate-pushpop-unsafe.rs
new file mode 100644 (file)
index 0000000..e317b4c
--- /dev/null
@@ -0,0 +1,14 @@
+// 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.
+
+fn main() {
+    let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
+    let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
+}
index 003c6644f7f0229061662a995ecc8ab5eff03ba1..8e566d7aafa68f9dc5ded35ea24ac626b9f11912 100644 (file)
@@ -9,8 +9,10 @@
 // except according to those terms.
 
 #![feature(box_syntax)]
+#![feature(placement_in_syntax)]
 
 fn main() {
     box ( () ) 0;
-    //~^ ERROR: only the exchange heap is currently supported
+    //~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
+    //~| ERROR: the trait `core::ops::Placer<_>` is not implemented
 }
index 9225889ef6348df7df644b98304b1b30162d4947..56261c34a030850e1fe3938347797c2e01ca2838 100644 (file)
@@ -37,7 +37,7 @@ struct D {
 }
 
 extern "C" {
-    fn foo(x: A); //~ ERROR found type without foreign-function-safe
+    fn foo(x: A); //~ ERROR found struct without foreign-function-safe
     fn bar(x: B); //~ ERROR foreign-function-safe
     fn baz(x: C);
     fn qux(x: A2); //~ ERROR foreign-function-safe
index c886c97a63607bc43143181b5f06e2f8336bb1ed..b5aa3568122ad49108a03ec12f87ce6bc3fb9175 100644 (file)
@@ -11,7 +11,7 @@
 #![deny(warnings)]
 
 extern {
-    pub fn foo(x: (isize)); //~ ERROR found rust type `isize` in foreign module
+    pub fn foo(x: (isize)); //~ ERROR found Rust type `isize` in foreign module
 }
 
 fn main() {
index dea933085de4e0c098e6a5a0790f8b2e9c487fb2..e35dadbea9d4d16429de2519f318e91524d8c080 100644 (file)
@@ -18,9 +18,9 @@ enum T { E, F, G }
 
 extern {
    fn zf(x: Z);
-   fn uf(x: U); //~ ERROR found type without foreign-function-safe
-   fn bf(x: B); //~ ERROR found type without foreign-function-safe
-   fn tf(x: T); //~ ERROR found type without foreign-function-safe
+   fn uf(x: U); //~ ERROR found enum without foreign-function-safe
+   fn bf(x: B); //~ ERROR found enum without foreign-function-safe
+   fn tf(x: T); //~ ERROR found enum without foreign-function-safe
 }
 
 pub fn main() { }
index 3f25e9c7b76aac34ea92298574f4584b3faf16c2..614f8e6fde81a966cd2244471a062024e07b3922 100644 (file)
 
 extern crate libc;
 
+trait Mirror { type It; }
+impl<T> Mirror for T { type It = Self; }
+#[repr(C)]
+pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
+#[repr(C)]
+pub struct StructWithProjectionAndLifetime<'a>(
+    &'a mut <StructWithProjectionAndLifetime<'a> as Mirror>::It
+);
+pub type I32Pair = (i32, i32);
+#[repr(C)]
+pub struct ZeroSize;
+pub type RustFn = fn();
+pub type RustBadRet = extern fn() -> Box<u32>;
+
 extern {
-    pub fn bare_type1(size: isize); //~ ERROR: found rust type
-    pub fn bare_type2(size: usize); //~ ERROR: found rust type
-    pub fn ptr_type1(size: *const isize); //~ ERROR: found rust type
-    pub fn ptr_type2(size: *const usize); //~ ERROR: found rust type
+    pub fn bare_type1(size: isize); //~ ERROR: found Rust type
+    pub fn bare_type2(size: usize); //~ ERROR: found Rust type
+    pub fn ptr_type1(size: *const isize); //~ ERROR: found Rust type
+    pub fn ptr_type2(size: *const usize); //~ ERROR: found Rust type
+    pub fn slice_type(p: &[u32]); //~ ERROR: found Rust slice type
+    pub fn str_type(p: &str); //~ ERROR: found Rust type
+    pub fn box_type(p: Box<u32>); //~ ERROR found Rust type
+    pub fn char_type(p: char); //~ ERROR found Rust type
+    pub fn trait_type(p: &Clone); //~ ERROR found Rust trait type
+    pub fn tuple_type(p: (i32, i32)); //~ ERROR found Rust tuple type
+    pub fn tuple_type2(p: I32Pair); //~ ERROR found Rust tuple type
+    pub fn zero_size(p: ZeroSize); //~ ERROR found zero-size struct
+    pub fn fn_type(p: RustFn); //~ ERROR found function pointer with Rust
+    pub fn fn_type2(p: fn()); //~ ERROR found function pointer with Rust
+    pub fn fn_contained(p: RustBadRet); //~ ERROR: found Rust type
 
     pub fn good1(size: *const libc::c_int);
     pub fn good2(size: *const libc::c_uint);
+    pub fn good3(fptr: Option<extern fn()>);
+    pub fn good4(aptr: &[u8; 4 as usize]);
+    pub fn good5(s: StructWithProjection);
+    pub fn good6(s: StructWithProjectionAndLifetime);
+    pub fn good7(fptr: extern fn() -> ());
+    pub fn good8(fptr: extern fn() -> !);
 }
 
 fn main() {
diff --git a/src/test/compile-fail/pushpop-unsafe-rejects.rs b/src/test/compile-fail/pushpop-unsafe-rejects.rs
new file mode 100644 (file)
index 0000000..72c065a
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2012 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.
+
+// Basic sanity check for `push_unsafe!(EXPR)` and
+// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
+// positive number of pushes in the stack, or if we are within a
+// normal `unsafe` block, but otherwise cannot.
+
+#![feature(pushpop_unsafe)]
+
+static mut X: i32 = 0;
+
+unsafe fn f() { X += 1; return; }
+fn g() { unsafe { X += 1_000; } return; }
+
+fn main() {
+    push_unsafe!( {
+        f(); pop_unsafe!({
+            f() //~ ERROR: call to unsafe function
+        })
+    } );
+
+    push_unsafe!({
+        f();
+        pop_unsafe!({
+            g();
+            f(); //~ ERROR: call to unsafe function
+        })
+    } );
+
+    push_unsafe!({
+        g(); pop_unsafe!({
+            unsafe {
+                f();
+            }
+            f(); //~ ERROR: call to unsafe function
+        })
+    });
+
+
+    // Note: For implementation simplicity the compiler just
+    // ICE's if you underflow the push_unsafe stack.
+    //
+    // Thus all of the following cases cause an ICE.
+    //
+    // (The "ERROR" notes are from an earlier version
+    //  that used saturated arithmetic rather than checked
+    //  arithmetic.)
+
+    //    pop_unsafe!{ g() };
+    //
+    //    push_unsafe!({
+    //        pop_unsafe!(pop_unsafe!{ g() })
+    //    });
+    //
+    //    push_unsafe!({
+    //        g();
+    //        pop_unsafe!(pop_unsafe!({
+    //            f() // ERROR: call to unsafe function
+    //        }))
+    //    });
+    //
+    //    pop_unsafe!({
+    //        f(); // ERROR: call to unsafe function
+    //    })
+
+}
index 9ff0f011e1dc795f622c6fae10d52b37dca5ad87..b77f25a0a344f6151c4daab2c1c0231de9079811 100644 (file)
@@ -13,9 +13,9 @@
 
 mod xx {
     extern {
-        pub fn strlen(str: *const u8) -> usize; //~ ERROR found rust type `usize`
-        pub fn foo(x: isize, y: usize); //~ ERROR found rust type `isize`
-        //~^ ERROR found rust type `usize`
+        pub fn strlen(str: *const u8) -> usize; //~ ERROR found Rust type `usize`
+        pub fn foo(x: isize, y: usize); //~ ERROR found Rust type `isize`
+        //~^ ERROR found Rust type `usize`
     }
 }
 
index 09d32a71dea48f6d5e0f660da9d1cd94633ad516..4c32d2f041e3c7fabc08c436e972686aab2e7cff 100644 (file)
@@ -12,7 +12,7 @@
 
 fn main() {
     box (1 + 1)
-    //~^ HELP try using `box()` instead:
-    //~| SUGGESTION box() (1 + 1)
+    //~^ HELP try using `box ()` instead:
+    //~| SUGGESTION box () (1 + 1)
     ; //~ ERROR expected expression, found `;`
 }
index 8af3844e62eefdee3de563b9c759018b42101a84..771fce31023e13f6a2fd5d115e5dbe6556f13514 100644 (file)
@@ -9,7 +9,9 @@
 // except according to those terms.
 
 #![feature(rustc_private)]
+#![feature(libc)]
 
+extern crate libc;
 extern crate rustc;
 extern crate rustc_driver;
 extern crate rustc_lint;
@@ -29,6 +31,7 @@
 use rustc::session::build_session;
 use rustc_driver::driver;
 use rustc_resolve::MakeGlobMap;
+use libc::c_void;
 
 use syntax::diagnostics::registry::Registry;
 
@@ -111,7 +114,7 @@ pub fn add_module(&mut self, program: &str) {
     }
 
     /// Returns a raw pointer to the named function.
-    pub fn get_function(&mut self, name: &str) -> Option<*const ()> {
+    pub fn get_function(&mut self, name: &str) -> Option<*const c_void> {
         let s = CString::new(name.as_bytes()).unwrap();
 
         for &m in &self.modules {
@@ -128,7 +131,7 @@ pub fn get_function(&mut self, name: &str) -> Option<*const ()> {
     }
 
     /// Returns a raw pointer to the named global item.
-    pub fn get_global(&mut self, name: &str) -> Option<*const ()> {
+    pub fn get_global(&mut self, name: &str) -> Option<*const c_void> {
         let s = CString::new(name.as_bytes()).unwrap();
 
         for &m in &self.modules {
index 2e75f2dccd1baf84168ca603415d20662530d48d..84af4fd0a08eae24410d7444eeb7ce1f4fa26b59 100644 (file)
@@ -20,7 +20,7 @@
 mod rusti {
     extern "rust-intrinsic" {
         pub fn init<T>() -> T;
-        pub fn move_val_init<T>(dst: &mut T, src: T);
+        pub fn move_val_init<T>(dst: *mut T, src: T);
     }
 }
 
index b5a54a90ae758ef778d7ebbbdb372b45819f21b5..da57e8682ca602b0e11183da4f669081e1490dbe 100644 (file)
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-#![allow(warnings)]
+#![allow(dead_code, unused_variables)]
 #![feature(box_syntax, box_heap)]
+#![feature(placement_in_syntax)]
+
+// during check-pretty, the expanded code needs to opt into these
+// features
+#![feature(placement_new_protocol, core_intrinsics)]
 
 // Tests that the new `box` syntax works with unique pointers.
 
@@ -30,4 +35,9 @@ pub fn main() {
     let y: Box<isize> = box 2;
     let b: Box<isize> = box()(1 + 2);
     let c = box()(3 + 4);
+
+    let s: Box<Structure> = box Structure {
+        x: 3,
+        y: 4,
+    };
 }
diff --git a/src/test/run-pass/placement-in-syntax.rs b/src/test/run-pass/placement-in-syntax.rs
new file mode 100644 (file)
index 0000000..7bda9ae
--- /dev/null
@@ -0,0 +1,37 @@
+// 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.
+
+#![allow(dead_code, unused_variables)]
+#![feature(box_heap)]
+#![feature(placement_in_syntax)]
+
+// Tests that the new `in` syntax works with unique pointers.
+//
+// Compare with new-box-syntax.rs
+
+use std::boxed::{Box, HEAP};
+
+struct Structure {
+    x: isize,
+    y: isize,
+}
+
+pub fn main() {
+    let x: Box<isize> = in HEAP { 2 };
+    let b: Box<isize> = in HEAP { 1 + 2 };
+    let c = in HEAP { 3 + 4 };
+
+    let s: Box<Structure> = in HEAP {
+        Structure {
+            x: 3,
+            y: 4,
+        }
+    };
+}
diff --git a/src/test/run-pass/pushpop-unsafe-okay.rs b/src/test/run-pass/pushpop-unsafe-okay.rs
new file mode 100644 (file)
index 0000000..fc402d4
--- /dev/null
@@ -0,0 +1,56 @@
+// 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.
+
+// Basic sanity check for `push_unsafe!(EXPR)` and
+// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
+// positive number of pushes in the stack, or if we are within a
+// normal `unsafe` block, but otherwise cannot.
+
+// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros
+// are not integrated with the pretty-printer.
+
+#![feature(pushpop_unsafe)]
+
+static mut X: i32 = 0;
+
+unsafe fn f() { X += 1; return; }
+fn g() { unsafe { X += 1_000; } return; }
+
+fn check_reset_x(x: i32) -> bool {
+    #![allow(unused_parens)] // dont you judge my style choices!
+    unsafe {
+        let ret = (x == X);
+        X = 0;
+        ret
+    }
+}
+
+fn main() {
+    // double-check test infrastructure
+    assert!(check_reset_x(0));
+    unsafe { f(); }
+    assert!(check_reset_x(1));
+    assert!(check_reset_x(0));
+    { g(); }
+    assert!(check_reset_x(1000));
+    assert!(check_reset_x(0));
+    unsafe { f(); g(); g(); }
+    assert!(check_reset_x(2001));
+
+    push_unsafe!( { f(); pop_unsafe!( g() ) } );
+    assert!(check_reset_x(1_001));
+    push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } );
+    assert!(check_reset_x(1_002));
+
+    unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); }
+    assert!(check_reset_x(3));
+    push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } );
+    assert!(check_reset_x(4));
+}
diff --git a/src/test/run-pass/xcrate-static.rs b/src/test/run-pass/xcrate-static.rs
new file mode 100644 (file)
index 0000000..d1f08e7
--- /dev/null
@@ -0,0 +1,17 @@
+// 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.
+
+// aux-build:xcrate-static.rs
+
+extern crate xcrate_static;
+
+fn main() {
+    println!("{}", xcrate_static::FOO);
+}