about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-06-28 05:28:32 -0700
committerbors <bors@rust-lang.org>2013-06-28 05:28:32 -0700
commit811e045c609f8f6bc53faeec817e9ba7aeadf056 (patch)
tree2e11e915a59d73825ea43122162cfdd5070f9d82
parent887ae82382ff4fad401a6539356245d2a05d6b4f (diff)
parent3fbea161075aa21a217bd794e3f5cac7085e94ec (diff)
downloadrust-811e045c609f8f6bc53faeec817e9ba7aeadf056.tar.gz
rust-811e045c609f8f6bc53faeec817e9ba7aeadf056.zip
auto merge of #7426 : thestinger/rust/zero-size-noncopyable, r=catamorphism
4885918 r=huonw
42a63fc r=thestinger
7ec5a08 r=catamorphism
fb1e5f1 r=thestinger
659cd55 r=cmr
-rw-r--r--RELEASES.txt1
-rw-r--r--doc/rustpkg.md10
-rw-r--r--doc/tutorial-container.md207
-rw-r--r--doc/tutorial.md127
-rw-r--r--man/rustc.169
-rw-r--r--mk/docs.mk10
-rw-r--r--src/libextra/ebml.rs8
-rw-r--r--src/libextra/rc.rs2
-rw-r--r--src/librustc/middle/ty.rs2
-rw-r--r--src/libstd/libc.rs1
-rw-r--r--src/libstd/option.rs2
-rw-r--r--src/libstd/unstable/atomics.rs2
-rw-r--r--src/libstd/util.rs54
-rw-r--r--src/test/run-pass/attr-no-drop-flag-size.rs2
14 files changed, 302 insertions, 195 deletions
diff --git a/RELEASES.txt b/RELEASES.txt
index dbee53f8e30..9ac4d650b43 100644
--- a/RELEASES.txt
+++ b/RELEASES.txt
@@ -101,6 +101,7 @@ Version 0.7 (July 2013)
         dynamic borrowcheck failures for debugging.
       * rustdoc has a nicer stylesheet.
       * Various improvements to rustdoc.
+      * Improvements to rustpkg (see the detailed release notes)
 
    * Other
       * More and improved library documentation.
diff --git a/doc/rustpkg.md b/doc/rustpkg.md
index b12bce5a0af..506fc2ad15a 100644
--- a/doc/rustpkg.md
+++ b/doc/rustpkg.md
@@ -95,12 +95,22 @@ When building a package that is in a `git` repository,
 When building a package that is not under version control,
 or that has no tags, `rustpkg` assumes the intended version is 0.1.
 
+# Dependencies
+
+rustpkg infers dependencies from `extern mod` directives.
+Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library.
+(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.)
+
 # Custom build scripts
 
 A file called `pkg.rs` at the root level in a workspace is called a *package script*.
 If a package script exists, rustpkg executes it to build the package
 rather than inferring crates as described previously.
 
+Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build.
+`rustpkg::api` contains functions to build, install, or clean libraries and executables
+in the way rustpkg normally would without custom build logic.
+
 # Command reference
 
 ## build
diff --git a/doc/tutorial-container.md b/doc/tutorial-container.md
new file mode 100644
index 00000000000..66bd0b9c131
--- /dev/null
+++ b/doc/tutorial-container.md
@@ -0,0 +1,207 @@
+% Containers and iterators
+
+# Containers
+
+The container traits are defined in the `std::container` module.
+
+## Unique and managed vectors
+
+Vectors have `O(1)` indexing and removal from the end, along with `O(1)`
+amortized insertion. Vectors are the most common container in Rust, and are
+flexible enough to fit many use cases.
+
+Vectors can also be sorted and used as efficient lookup tables with the
+`std::vec::bsearch` function, if all the elements are inserted at one time and
+deletions are unnecessary.
+
+## Maps and sets
+
+Maps are collections of unique keys with corresponding values, and sets are
+just unique keys without a corresponding value. The `Map` and `Set` traits in
+`std::container` define the basic interface.
+
+The standard library provides three owned map/set types:
+
+* `std::hashmap::HashMap` and `std::hashmap::HashSet`, requiring the keys to
+  implement `Eq` and `Hash`
+* `std::trie::TrieMap` and `std::trie::TrieSet`, requiring the keys to be `uint`
+* `extra::treemap::TreeMap` and `extra::treemap::TreeSet`, requiring the keys
+  to implement `TotalOrd`
+
+These maps do not use managed pointers so they can be sent between tasks as
+long as the key and value types are sendable. Neither the key or value type has
+to be copyable.
+
+The `TrieMap` and `TreeMap` maps are ordered, while `HashMap` uses an arbitrary
+order.
+
+Each `HashMap` instance has a random 128-bit key to use with a keyed hash,
+making the order of a set of keys in a given hash table randomized. Rust
+provides a [SipHash](https://131002.net/siphash/) implementation for any type
+implementing the `IterBytes` trait.
+
+## Double-ended queues
+
+The `extra::deque` module implements a double-ended queue with `O(1)` amortized
+inserts and removals from both ends of the container. It also has `O(1)`
+indexing like a vector. The contained elements are not required to be copyable,
+and the queue will be sendable if the contained type is sendable.
+
+## Priority queues
+
+The `extra::priority_queue` module implements a queue ordered by a key.  The
+contained elements are not required to be copyable, and the queue will be
+sendable if the contained type is sendable.
+
+Insertions have `O(log n)` time complexity and checking or popping the largest
+element is `O(1)`. Converting a vector to a priority queue can be done
+in-place, and has `O(n)` complexity. A priority queue can also be converted to
+a sorted vector in-place, allowing it to be used for an `O(n log n)` in-place
+heapsort.
+
+# Iterators
+
+## Iteration protocol
+
+The iteration protocol is defined by the `Iterator` trait in the
+`std::iterator` module. The minimal implementation of the trait is a `next`
+method, yielding the next element from an iterator object:
+
+~~~
+/// An infinite stream of zeroes
+struct ZeroStream;
+
+impl Iterator<int> for ZeroStream {
+    fn next(&mut self) -> Option<int> {
+        Some(0)
+    }
+}
+~~~~
+
+Reaching the end of the iterator is signalled by returning `None` instead of
+`Some(item)`:
+
+~~~
+/// A stream of N zeroes
+struct ZeroStream {
+    priv remaining: uint
+}
+
+impl ZeroStream {
+    fn new(n: uint) -> ZeroStream {
+        ZeroStream { remaining: n }
+    }
+}
+
+impl Iterator<int> for ZeroStream {
+    fn next(&mut self) -> Option<int> {
+        if self.remaining == 0 {
+            None
+        } else {
+            self.remaining -= 1;
+            Some(0)
+        }
+    }
+}
+~~~
+
+## Container iterators
+
+Containers implement iteration over the contained elements by returning an
+iterator object. For example, vectors have four iterators available:
+
+* `vector.iter()`, for immutable references to the elements
+* `vector.mut_iter()`, for mutable references to the elements
+* `vector.rev_iter()`, for immutable references to the elements in reverse order
+* `vector.mut_rev_iter()`, for mutable references to the elements in reverse order
+
+### Freezing
+
+Unlike most other languages with external iterators, Rust has no *iterator
+invalidation*. As long an iterator is still in scope, the compiler will prevent
+modification of the container through another handle.
+
+~~~
+let mut xs = [1, 2, 3];
+{
+    let _it = xs.iter();
+
+    // the vector is frozen for this scope, the compiler will statically
+    // prevent modification
+}
+// the vector becomes unfrozen again at the end of the scope
+~~~
+
+These semantics are due to most container iterators being implemented with `&`
+and `&mut`.
+
+## Iterator adaptors
+
+The `IteratorUtil` trait implements common algorithms as methods extending
+every `Iterator` implementation. For example, the `fold` method will accumulate
+the items yielded by an `Iterator` into a single value:
+
+~~~
+let xs = [1, 9, 2, 3, 14, 12];
+let result = xs.iter().fold(0, |accumulator, item| accumulator - *item);
+assert_eq!(result, -41);
+~~~
+
+Some adaptors return an adaptor object implementing the `Iterator` trait itself:
+
+~~~
+let xs = [1, 9, 2, 3, 14, 12];
+let ys = [5, 2, 1, 8];
+let sum = xs.iter().chain_(ys.iter()).fold(0, |a, b| a + *b);
+assert_eq!(sum, 57);
+~~~
+
+Note that some adaptors like the `chain_` method above use a trailing
+underscore to work around an issue with method resolve. The underscores will be
+dropped when they become unnecessary.
+
+## For loops
+
+The `for` loop syntax is currently in transition, and will switch from the old
+closure-based iteration protocol to iterator objects. For now, the `advance`
+adaptor is required as a compatibility shim to use iterators with for loops.
+
+~~~
+let xs = [2, 3, 5, 7, 11, 13, 17];
+
+// print out all the elements in the vector
+for xs.iter().advance |x| {
+    println(x.to_str())
+}
+
+// print out all but the first 3 elements in the vector
+for xs.iter().skip(3).advance |x| {
+    println(x.to_str())
+}
+~~~
+
+For loops are *often* used with a temporary iterator object, as above. They can
+also advance the state of an iterator in a mutable location:
+
+~~~
+let xs = [1, 2, 3, 4, 5];
+let ys = ["foo", "bar", "baz", "foobar"];
+
+// create an iterator yielding tuples of elements from both vectors
+let mut it = xs.iter().zip(ys.iter());
+
+// print out the pairs of elements up to (&3, &"baz")
+for it.advance |(x, y)| {
+    println(fmt!("%d %s", *x, *y));
+
+    if *x == 3 {
+        break;
+    }
+}
+
+// yield and print the last pair from the iterator
+println(fmt!("last: %?", it.next()));
+
+// the iterator is now fully consumed
+assert!(it.next().is_none());
+~~~
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 0701d61351c..fc0f7b74a7a 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -1607,132 +1607,6 @@ do spawn {
 If you want to see the output of `debug!` statements, you will need to turn on `debug!` logging.
 To enable `debug!` logging, set the RUST_LOG environment variable to the name of your crate, which, for a file named `foo.rs`, will be `foo` (e.g., with bash, `export RUST_LOG=foo`).
 
-## For loops
-
-> ***Note:*** The closure-based protocol used `for` loop is on the way out. The `for` loop will
-> use iterator objects in the future instead.
-
-The most common way to express iteration in Rust is with a `for`
-loop. Like `do`, `for` is a nice syntax for describing control flow
-with closures.  Additionally, within a `for` loop, `break`, `loop`,
-and `return` work just as they do with `while` and `loop`.
-
-Consider again our `each` function, this time improved to return
-immediately when the iteratee returns `false`:
-
-~~~~
-fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool {
-   let mut n = 0;
-   while n < v.len() {
-       if !op(&v[n]) {
-           return false;
-       }
-       n += 1;
-   }
-   return true;
-}
-~~~~
-
-And using this function to iterate over a vector:
-
-~~~~
-# fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool {
-#    let mut n = 0;
-#    while n < v.len() {
-#        if !op(&v[n]) {
-#            return false;
-#        }
-#        n += 1;
-#    }
-#    return true;
-# }
-each([2, 4, 8, 5, 16], |n| {
-    if *n % 2 != 0 {
-        println("found odd number!");
-        false
-    } else { true }
-});
-~~~~
-
-With `for`, functions like `each` can be treated more
-like built-in looping structures. When calling `each`
-in a `for` loop, instead of returning `false` to break
-out of the loop, you just write `break`. To skip ahead
-to the next iteration, write `loop`.
-
-~~~~
-# fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool {
-#    let mut n = 0;
-#    while n < v.len() {
-#        if !op(&v[n]) {
-#            return false;
-#        }
-#        n += 1;
-#    }
-#    return true;
-# }
-for each([2, 4, 8, 5, 16]) |n| {
-    if *n % 2 != 0 {
-        println("found odd number!");
-        break;
-    }
-}
-~~~~
-
-As an added bonus, you can use the `return` keyword, which is not
-normally allowed in closures, in a block that appears as the body of a
-`for` loop: the meaning of `return` in such a block is to return from
-the enclosing function, not just the loop body.
-
-~~~~
-# fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool {
-#    let mut n = 0;
-#    while n < v.len() {
-#        if !op(&v[n]) {
-#            return false;
-#        }
-#        n += 1;
-#    }
-#    return true;
-# }
-fn contains(v: &[int], elt: int) -> bool {
-    for each(v) |x| {
-        if (*x == elt) { return true; }
-    }
-    false
-}
-~~~~
-
-Notice that, because `each` passes each value by borrowed pointer,
-the iteratee needs to dereference it before using it.
-In these situations it can be convenient to lean on Rust's
-argument patterns to bind `x` to the actual value, not the pointer.
-
-~~~~
-# fn each(v: &[int], op: &fn(v: &int) -> bool) -> bool {
-#    let mut n = 0;
-#    while n < v.len() {
-#        if !op(&v[n]) {
-#            return false;
-#        }
-#        n += 1;
-#    }
-#    return true;
-# }
-# fn contains(v: &[int], elt: int) -> bool {
-    for each(v) |&x| {
-        if (x == elt) { return true; }
-    }
-#    false
-# }
-~~~~
-
-`for` syntax only works with stack closures.
-
-> ***Note:*** This is, essentially, a special loop protocol:
-> the keywords `break`, `loop`, and `return` work, in varying degree,
-> with `while`, `loop`, `do`, and `for` constructs.
-
 # Methods
 
 Methods are like functions except that they always begin with a special argument,
@@ -2653,6 +2527,7 @@ tutorials on individual topics.
 * [Tasks and communication][tasks]
 * [Macros][macros]
 * [The foreign function interface][ffi]
+* [Containers and iterators](tutorial-container.html)
 
 There is further documentation on the [wiki].
 
diff --git a/man/rustc.1 b/man/rustc.1
index 9ed98c14294..4e76749f707 100644
--- a/man/rustc.1
+++ b/man/rustc.1
@@ -1,4 +1,4 @@
-.TH RUSTC "1" "February 2013" "rustc 0.6" "User Commands"
+.TH RUSTC "1" "July 2013" "rustc 0.7" "User Commands"
 .SH NAME
 rustc \- rust compiler
 .SH SYNOPSIS
@@ -33,6 +33,12 @@ Add a directory to the library search path
 \fB\-\-lib\fR
 Compile a library crate
 .TP
+\fB\-\-linker\fR LINKER
+Program to use for linking instead of the default
+.TP
+\fB\-\-link-args\fR FLAGS
+A space-separated list of flags passed to the linker
+.TP
 \fB\-\-ls\fR
 List the symbols defined by a library crate
 .TP
@@ -48,6 +54,11 @@ Write output to <filename>
 \fB\-\-opt\-level\fR LEVEL
 Optimize with possible levels 0-3
 .TP
+\fB\-\-passes\fR NAMES
+Comma- or space-separated list of optimization passes. Overrides
+the default passes for the optimization level. A value of 'list'
+will list the available passes.
+.TP
 \fB\-\-out\-dir\fR DIR
 Write output to compiler-chosen filename in <dir>
 .TP
@@ -77,6 +88,12 @@ Target triple cpu-manufacturer-kernel[-os] to compile for (see
 http://sources.redhat.com/autobook/autobook/autobook_17.html
 for detail)
 .TP
+\fB\-\-target-feature\fR TRIPLE
+Target-specific attributes (see llc -mattr=help for detail)
+.TP
+\fB\-\-android-cross-path\fR PATH
+The path to the Android NDK
+.TP
 \fB\-W\fR help
 Print 'lint' options and default settings
 .TP
@@ -94,56 +111,6 @@ Set lint forbidden
 .TP
 \fB\-Z\fR FLAG
 Set internal debugging options. Use "-Z help" to print available options.
-
-Available debug flags are:
-.RS
-.IP \[bu]
-\fBverbose\fR - in general, enable more debug printouts
-.IP \[bu]
-\fBtime\-passes\fR - measure time of each rustc pass
-.IP \[bu]
-\fBcount\-llvm\-insns\fR - count where LLVM instrs originate
-.IP \[bu]
-\fBtime\-llvm\-passes\fR - measure time of each LLVM pass
-.IP \[bu]
-\fBtrans\-stats\fR - gather trans statistics
-.IP \[bu]
-\fBno\-asm\-comments\fR - omit comments when using \fI\-S\fR
-.IP \[bu]
-\fBno\-verify\fR - skip LLVM verification
-.IP \[bu]
-\fBtrace\fR - emit trace logs
-.IP \[bu]
-\fBcoherence\fR - perform coherence checking
-.IP \[bu]
-\fBborrowck\-stats\fR - gather borrowck statistics
-.IP \[bu]
-\fBborrowck\-note\-pure\fR - note where purity is req'd
-.IP \[bu]
-\fBborrowck\-note\-loan\fR - note where loans are req'd
-.IP \[bu]
-\fBno\-landing\-pads\fR - omit landing pads for unwinding
-.IP \[bu]
-\fBdebug\-llvm\fR - enable debug output from LLVM
-.IP \[bu]
-\fBcount\-type\-sizes\fR - count the sizes of aggregate types
-.IP \[bu]
-\fBmeta\-stats\fR - gather metadata statistics
-.IP \[bu]
-\fBno\-opt\fR - do not optimize, even if \fI\-O\fR is passed
-.IP \[bu]
-\fBno\-monomorphic\-collapse\fR - do not collapse template instantiations
-.IP \[bu]
-\fBgc\fR - Garbage collect shared data (experimental)
-.IP \[bu]
-\fBjit\fR - Execute using JIT (experimental)
-.IP \[bu]
-\fBextra\-debug\-info\fR - Extra debugging info (experimental)
-.IP \[bu]
-\fBdebug\-info\fR - Produce debug info (experimental)
-.IP \[bu]
-\fBstatic\fR - Use or produce static libraries or binaries (experimental)
-.RE
 .TP
 \fB\-v\fR, \fB\-\-version\fR
 Print version info and exit
diff --git a/mk/docs.mk b/mk/docs.mk
index 8470da7c07b..f11a3d24b8d 100644
--- a/mk/docs.mk
+++ b/mk/docs.mk
@@ -99,6 +99,16 @@ doc/tutorial-macros.html: tutorial-macros.md doc/version_info.html \
 	   --include-before-body=doc/version_info.html \
            --output=$@
 
+DOCS += doc/tutorial-container.html
+doc/tutorial-container.html: tutorial-container.md doc/version_info.html doc/rust.css
+	@$(call E, pandoc: $@)
+	$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
+          $(CFG_PANDOC) --standalone --toc \
+           --section-divs --number-sections \
+           --from=markdown --to=html --css=rust.css \
+	   --include-before-body=doc/version_info.html \
+           --output=$@
+
 DOCS += doc/tutorial-ffi.html
 doc/tutorial-ffi.html: tutorial-ffi.md doc/version_info.html doc/rust.css
 	@$(call E, pandoc: $@)
diff --git a/src/libextra/ebml.rs b/src/libextra/ebml.rs
index 92a027100da..dd3ba639c05 100644
--- a/src/libextra/ebml.rs
+++ b/src/libextra/ebml.rs
@@ -82,8 +82,14 @@ pub mod reader {
     use core::cast::transmute;
     use core::int;
     use core::io;
-    use core::ptr::offset;
     use core::str;
+
+    #[cfg(target_arch = "x86")]
+    #[cfg(target_arch = "x86_64")]
+    use core::ptr::offset;
+
+    #[cfg(target_arch = "x86")]
+    #[cfg(target_arch = "x86_64")]
     use core::unstable::intrinsics::bswap32;
 
     // ebml reading
diff --git a/src/libextra/rc.rs b/src/libextra/rc.rs
index 8ef58a188d9..5b1451387e7 100644
--- a/src/libextra/rc.rs
+++ b/src/libextra/rc.rs
@@ -36,6 +36,7 @@ struct RcBox<T> {
 
 /// Immutable reference counted pointer type
 #[non_owned]
+#[unsafe_no_drop_flag]
 pub struct Rc<T> {
     priv ptr: *mut RcBox<T>,
 }
@@ -168,6 +169,7 @@ struct RcMutBox<T> {
 /// Mutable reference counted pointer type
 #[non_owned]
 #[mutable]
+#[unsafe_no_drop_flag]
 pub struct RcMut<T> {
     priv ptr: *mut RcMutBox<T>,
 }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index b53359abed4..29d81f37da7 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -3904,7 +3904,7 @@ impl DtorKind {
 pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind {
     match cx.destructor_for_type.find(&struct_id) {
         Some(&method_def_id) => {
-            let flag = !has_attr(cx, struct_id, "no_drop_flag");
+            let flag = !has_attr(cx, struct_id, "unsafe_no_drop_flag");
 
             TraitDtor(method_def_id, flag)
         }
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 3c2ae93b656..41b78afded1 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -349,7 +349,6 @@ pub mod types {
                 use libc::types::os::arch::c95::{c_uchar, c_uint, c_ulong, time_t};
                 use libc::types::os::arch::c99::{c_longlong, c_ulonglong};
                 use libc::types::os::arch::posix88::{uid_t, gid_t, ino_t};
-                use libc::types::os::arch::posix88::{uid_t};
 
                 pub type nlink_t = u16;
                 pub type blksize_t = u32;
diff --git a/src/libstd/option.rs b/src/libstd/option.rs
index f3ea81f1ae5..12ae2abd4a1 100644
--- a/src/libstd/option.rs
+++ b/src/libstd/option.rs
@@ -447,7 +447,7 @@ fn test_option_dance() {
 }
 #[test] #[should_fail] #[ignore(cfg(windows))]
 fn test_option_too_much_dance() {
-    let mut y = Some(util::NonCopyable::new());
+    let mut y = Some(util::NonCopyable);
     let _y2 = y.swap_unwrap();
     let _y3 = y.swap_unwrap();
 }
diff --git a/src/libstd/unstable/atomics.rs b/src/libstd/unstable/atomics.rs
index 45eced9846c..1e5ac305df3 100644
--- a/src/libstd/unstable/atomics.rs
+++ b/src/libstd/unstable/atomics.rs
@@ -62,7 +62,7 @@ pub struct AtomicPtr<T> {
 /**
  * An owned atomic pointer. Ensures that only a single reference to the data is held at any time.
  */
-#[no_drop_flag]
+#[unsafe_no_drop_flag]
 pub struct AtomicOption<T> {
     priv p: *mut c_void
 }
diff --git a/src/libstd/util.rs b/src/libstd/util.rs
index 6eddae17ce6..fd29d7dc14b 100644
--- a/src/libstd/util.rs
+++ b/src/libstd/util.rs
@@ -75,18 +75,14 @@ pub fn replace<T>(dest: &mut T, mut src: T) -> T {
 }
 
 /// A non-copyable dummy type.
+#[deriving(Eq, TotalEq, Ord, TotalOrd)]
+#[unsafe_no_drop_flag]
 pub struct NonCopyable;
 
-impl NonCopyable {
-    /// Creates a dummy non-copyable structure and returns it for use.
-    pub fn new() -> NonCopyable { NonCopyable }
-}
-
 impl Drop for NonCopyable {
     fn drop(&self) { }
 }
 
-
 /// A type with no inhabitants
 pub enum Void { }
 
@@ -130,39 +126,73 @@ pub fn unreachable() -> ! {
 
 #[cfg(test)]
 mod tests {
+    use super::*;
     use option::{None, Some};
-    use util::{Void, NonCopyable, id, replace, swap};
     use either::{Either, Left, Right};
+    use sys::size_of;
+    use kinds::Drop;
 
     #[test]
-    pub fn identity_crisis() {
+    fn identity_crisis() {
         // Writing a test for the identity function. How did it come to this?
         let x = ~[(5, false)];
         //FIXME #3387 assert!(x.eq(id(copy x)));
         let y = copy x;
         assert!(x.eq(&id(y)));
     }
+
     #[test]
-    pub fn test_swap() {
+    fn test_swap() {
         let mut x = 31337;
         let mut y = 42;
         swap(&mut x, &mut y);
         assert_eq!(x, 42);
         assert_eq!(y, 31337);
     }
+
     #[test]
-    pub fn test_replace() {
-        let mut x = Some(NonCopyable::new());
+    fn test_replace() {
+        let mut x = Some(NonCopyable);
         let y = replace(&mut x, None);
         assert!(x.is_none());
         assert!(y.is_some());
     }
+
     #[test]
-    pub fn test_uninhabited() {
+    fn test_uninhabited() {
         let could_only_be_coin : Either <Void, ()> = Right (());
         match could_only_be_coin {
             Right (coin) => coin,
             Left (is_void) => is_void.uninhabited ()
         }
     }
+
+    #[test]
+    fn test_noncopyable() {
+        assert_eq!(size_of::<NonCopyable>(), 0);
+
+        // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct
+
+        // NOTE: uncomment after snapshot, will not parse yet
+        //static mut did_run: bool = false;
+
+        struct Foo { five: int }
+
+        impl Drop for Foo {
+            fn drop(&self) {
+                assert_eq!(self.five, 5);
+                // NOTE: uncomment after snapshot, will not parse yet
+                //unsafe {
+                    //did_run = true;
+                //}
+            }
+        }
+
+        {
+            let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
+        }
+
+        // NOTE: uncomment after snapshot, will not parse yet
+        //unsafe { assert_eq!(did_run, true); }
+    }
 }
diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs
index 00a7955d834..87c476d781e 100644
--- a/src/test/run-pass/attr-no-drop-flag-size.rs
+++ b/src/test/run-pass/attr-no-drop-flag-size.rs
@@ -10,7 +10,7 @@
 
 use std::sys::size_of;
 
-#[no_drop_flag]
+#[unsafe_no_drop_flag]
 struct Test<T> {
     a: T
 }