[rust] Add rust_bench_test and rust_doc_test rules and improve usability of rust_test rule.

* Add rust_bench_test rule to run benchmark tests
* Add rust_doc_test rule to run Rust documentation tests.
* Enable rust_test and rust_bench_test to depend directly on a rust_library target.
* Rename rust_docs rule to rust_doc for consistency.

RELNOTES: [rust] Add rust_bench_test and rust_doc_test rules and improve usability of rust_test tule.

--
MOS_MIGRATED_REVID=104648497
diff --git a/WORKSPACE b/WORKSPACE
index b3aebe8..f9d107a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -47,6 +47,7 @@
     url = "https://static.rust-lang.org/dist/rust-1.3.0-x86_64-unknown-linux-gnu.tar.gz",
     sha256 = "fa755b6331ff7554e6e8545ee20af7897b0adc65f471dd24ae8a467a944755b4",
     build_file = "tools/build_rules/rust/rust.BUILD",
+    strip_prefix = "rust-1.3.0-x86_64-unknown-linux-gnu",
 )
 
 new_http_archive(
@@ -54,6 +55,7 @@
     url = "https://static.rust-lang.org/dist/rust-1.3.0-x86_64-apple-darwin.tar.gz",
     sha256 = "bfeac876e22cc5fe63a250644ce1a6f3892c13a5461131a881419bd06fcb2011",
     build_file = "tools/build_rules/rust/rust.BUILD",
+    strip_prefix = "rust-1.3.0-x86_64-apple-darwin",
 )
 
 # In order to run the Android integration tests, uncomment these rules, point
diff --git a/examples/rust/fibonacci/BUILD b/examples/rust/fibonacci/BUILD
new file mode 100644
index 0000000..a29e212
--- /dev/null
+++ b/examples/rust/fibonacci/BUILD
@@ -0,0 +1,36 @@
+package(default_visibility = ["//visibility:public"])
+
+load(
+    "/tools/build_rules/rust/rust",
+    "rust_library",
+    "rust_test",
+    "rust_bench_test",
+    "rust_doc",
+    "rust_doc_test",
+)
+
+rust_library(
+    name = "fibonacci",
+    srcs = ["src/lib.rs"],
+)
+
+rust_test(
+    name = "fibonacci_test",
+    deps = [":fibonacci"],
+)
+
+rust_bench_test(
+    name = "fibonacci_bench",
+    srcs = ["benches/fibonacci_bench.rs"],
+    deps = [":fibonacci"],
+)
+
+rust_doc(
+    name = "fibonacci_doc",
+    dep = ":fibonacci",
+)
+
+rust_doc_test(
+    name = "fibonacci_doc_test",
+    dep = ":fibonacci",
+)
diff --git a/examples/rust/fibonacci/benches/fibonacci_bench.rs b/examples/rust/fibonacci/benches/fibonacci_bench.rs
new file mode 100644
index 0000000..80aa1a8
--- /dev/null
+++ b/examples/rust/fibonacci/benches/fibonacci_bench.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#![feature(test)]
+
+extern crate test;
+extern crate fibonacci;
+
+use test::Bencher;
+
+#[bench]
+fn bench_fibonacci(b: &mut Bencher) {
+    b.iter(|| fibonacci::fibonacci(40));
+}
diff --git a/examples/rust/fibonacci/src/lib.rs b/examples/rust/fibonacci/src/lib.rs
new file mode 100644
index 0000000..d8ae6e3
--- /dev/null
+++ b/examples/rust/fibonacci/src/lib.rs
@@ -0,0 +1,48 @@
+// Copyright 2015 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/// Returns the nth Fibonacci number.
+///
+/// # Examples
+///
+/// ```
+/// fibonacci::fibonacci(5)
+/// ```
+pub fn fibonacci(n: u64) -> u64 {
+    if n < 2 {
+        return n;
+    }
+    let mut n1: u64 = 0;
+    let mut n2: u64 = 1;
+    for _ in 1..n {
+        let sum = n1 + n2;
+        n1 = n2;
+        n2 = sum;
+    }
+    n2
+}
+
+#[cfg(test)]
+mod test {
+    use super::fibonacci;
+
+    #[test]
+    fn test_fibonacci() {
+        let numbers : Vec<u64> =
+            vec![0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144];
+        for (i, number) in numbers.iter().enumerate() {
+            assert_eq!(*number, fibonacci(i as u64));
+        }
+    }
+}
diff --git a/examples/rust/hello_lib/BUILD b/examples/rust/hello_lib/BUILD
index a075f8b..90941e6 100644
--- a/examples/rust/hello_lib/BUILD
+++ b/examples/rust/hello_lib/BUILD
@@ -1,6 +1,12 @@
 package(default_visibility = ["//visibility:public"])
 
-load("/tools/build_rules/rust/rust", "rust_library", "rust_docs", "rust_test")
+load(
+    "/tools/build_rules/rust/rust",
+    "rust_library",
+    "rust_test",
+    "rust_doc",
+    "rust_doc_test",
+)
 
 rust_library(
     name = "hello_lib",
@@ -10,13 +16,23 @@
     ],
 )
 
-rust_docs(
-    name = "hello_lib_docs",
-    dep = ":hello_lib",
+rust_test(
+    name = "hello_lib_test",
+    deps = [":hello_lib"],
 )
 
 rust_test(
-    name = "greeting",
+    name = "greeting_test",
     srcs = ["tests/greeting.rs"],
     deps = [":hello_lib"],
 )
+
+rust_doc(
+    name = "hello_lib_doc",
+    dep = ":hello_lib",
+)
+
+rust_doc_test(
+    name = "hello_lib_doc_test",
+    dep = ":hello_lib",
+)
diff --git a/examples/rust/hello_lib/src/greeter.rs b/examples/rust/hello_lib/src/greeter.rs
index 2a7d715..bf332e4 100644
--- a/examples/rust/hello_lib/src/greeter.rs
+++ b/examples/rust/hello_lib/src/greeter.rs
@@ -60,3 +60,14 @@
         println!("{} {}", &self.greeting, thing);
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::Greeter;
+
+    #[test]
+    fn test_greeting() {
+        let hello = Greeter::new("Hi");
+        assert_eq!("Hi Rust", hello.greeting("Rust"));
+    }
+}
diff --git a/examples/rust/hello_world/BUILD b/examples/rust/hello_world/BUILD
index ccd87f1..1f53656 100644
--- a/examples/rust/hello_world/BUILD
+++ b/examples/rust/hello_world/BUILD
@@ -1,6 +1,6 @@
 package(default_visibility = ["//visibility:public"])
 
-load("/tools/build_rules/rust/rust", "rust_binary", "rust_docs")
+load("/tools/build_rules/rust/rust", "rust_binary", "rust_doc")
 
 rust_binary(
     name = "hello_world",
@@ -8,7 +8,7 @@
     deps = ["//examples/rust/hello_lib"],
 )
 
-rust_docs(
-    name = "hello_world_docs",
+rust_doc(
+    name = "hello_world_doc",
     dep = ":hello_world",
 )
diff --git a/tools/build_rules/rust/README.md b/tools/build_rules/rust/README.md
index 536c10f..a040ad3 100644
--- a/tools/build_rules/rust/README.md
+++ b/tools/build_rules/rust/README.md
@@ -1,18 +1,16 @@
 # Rust Rules for Bazel
 
+* [`rust_library`](#rust_library)
+* [`rust_binary`](#rust_binary)
+* [`rust_test`](#rust_test)
+* [`rust_bench_test`](#rust_bench_test)
+* [`rust_doc`](#rust_doc)
+* [`rust_doc_test`](#rust_doc_test)
+
 ## Overview
 
 These build rules are used for building [Rust][rust] projects with Bazel.
 
-* [Setup](#setup)
-* [Basic Example](#basic-example)
-* [Build Rule Reference](#reference)
-  * [`rust_library`](#reference-rust_library)
-  * [`rust_binary`](#reference-rust_binary)
-  * [`rust_test`](#reference-rust_test)
-  * [`rust_docs`](#reference-rust_docs)
-* [Roadmap](#roadmap)
-
 [rust]: http://www.rust-lang.org/
 
 <a name="setup"></a>
@@ -21,8 +19,121 @@
 To use the Rust rules, simply copy the contents of `rust.WORKSPACE` to your
 `WORKSPACE` file.
 
-<a name="basic-example"></a>
-## Basic Example
+<a name="roadmap"></a>
+## Roadmap
+
+* Add `rust_toolchain` rule to make it easy to use a custom Rust toolchain.
+* Add tool for taking `Cargo.toml` and generating a `WORKSPACE` file with
+  workspace rules for pulling external dependencies.
+* Improve expressiveness of features and support for [Cargo's feature
+  groups](http://doc.crates.io/manifest.html#the-[features]-section).
+* Add `cargo_crate` workspace rule for pulling crates from
+  [Cargo](https://crates.io/).
+
+<a name="rust_library"></a>
+## rust_library
+
+```python
+rust_library(name, srcs, deps, data, crate_features, rustc_flags)
+```
+
+<table>
+  <thead>
+    <tr>
+      <th>Attribute</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>name</code></td>
+      <td>
+        <code>Name, required</code>
+        <p>A unique name for this rule.</p>
+        <p>
+          This name will also be used as the name of the library crate built by
+          this rule.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>srcs</code></td>
+      <td>
+        <code>List of labels, required</code>
+        <p>List of Rust <code>.rs</code> source files used to build the
+        library.</p>
+        <p>
+          If <code>srcs</code> contains more than one file, then there must be
+          a file either named <code>lib.rs</code>. Otherwise,
+          <code>crate_root</code> must be set to the source file that is the
+          root of the crate to be passed to <code>rustc</code> to build this
+          crate.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>crate_root</code></td>
+      <td>
+        <code>Label, optional</code>
+        <p>
+          The file that will be passed to <code>rustc</code> to be used for
+          building this crate.
+        </p>
+        <p>
+          If <code>crate_root</code> is not set, then this rule will look for
+          a <code>lib.rs</code> file or the single file in <code>srcs</code>
+          if <code>srcs</code> contains only one file.
+        </p>
+      </td>
+    </td>
+    <tr>
+      <td><code>deps</code></td>
+      <td>
+        <code>List of labels, optional</code>
+        <p>List of other libraries to be linked to this library target.</p>
+        <p>
+          These can be either other <code>rust_library</code> targets or
+          <code>cc_library</code> targets if linking a native library.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>data</code></td>
+      <td>
+        <code>List of labels, optional</code>
+        <p>List of files used by this rule at runtime.</p>
+        <p>
+          This attribute can be used to specify any data files that are embedded
+          into the library, such as via the
+          <a href="https://doc.rust-lang.org/std/macro.include_str!.html target="_blank"><code>include_str!</code></a>
+          macro.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>crate_features</code></td>
+      <td>
+        <code>List of strings, optional</code>
+        <p>List of features to enable for this crate.</p>
+        <p>
+          Features are defined in the code using the
+          <code>#[cfg(feature = "foo")]</code> configuration option. The
+          features listed here will be passed to <code>rustc</code> with
+          <code>--cfg feature="${feature_name}"</code> flags.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>rustc_flags</code></td>
+      <td>
+        <code>List of strings, optional</code>
+        <p>List of compiler flags passed to <code>rustc</code>.</p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Example
 
 Suppose you have the following directory structure for a simple Rust library
 crate:
@@ -88,155 +199,13 @@
 INFO: Elapsed time: 1.245s, Critical Path: 1.01s
 ```
 
-Now, let's add a binary crate that uses the `hello_lib` library. The directory
-structure now looks like the following:
+<a name="rust_binary"></a>
+## rust_binary
 
 ```
-[workspace]/
-    WORKSPACE
-    hello_lib/
-        BUILD
-        src/
-            greeter.rs
-            lib.rs
-    hello_world/
-        BUILD
-        src/
-            main.rs
+rust_binary(name, srcs, deps, data, crate_features, rustc_flags)
 ```
 
-`hello_world/src/main.rs`:
-
-```rust
-extern crate hello_lib;
-
-use hello_lib::greeter;
-
-fn main() {
-    let hello = greeter::Greeter::new("Hello");
-    hello.greet("world");
-}
-```
-
-`hello_world/BUILD`:
-
-```python
-load("/tools/build_rules/rust/rust", "rust_binary")
-
-rust_binary(
-    name = "hello_world",
-    srcs = ["src/main.rs"],
-    deps = ["//hello_lib"],
-)
-```
-
-Build and run `hello_world`:
-
-```
-$ bazel run //hello_world
-INFO: Found 1 target...
-Target //examples/rust/hello_world:hello_world up-to-date:
-  bazel-bin/examples/rust/hello_world/hello_world
-INFO: Elapsed time: 1.308s, Critical Path: 1.22s
-
-INFO: Running command line: bazel-bin/examples/rust/hello_world/hello_world
-Hello world
-```
-
-<a name="reference"></a>
-## Build Rule Reference
-
-<a name="reference-rust_library"></a>
-### `rust_library`
-
-`rust_library(name, srcs, deps, data, crate_features, rustc_flags)`
-
-<table>
-  <thead>
-    <tr>
-      <th>Attribute</th>
-      <th>Description</th>
-    </tr>
-  </thead>
-  <tbody>
-    <tr>
-      <td><code>name</code></td>
-      <td>
-        <code>Name, required</code>
-        <p>A unique name for this rule.</p>
-        <p>
-          This name will also be used as the name of the library crate built by
-          this rule.
-        </p>
-      </td>
-    </tr>
-    <tr>
-      <td><code>srcs</code></td>
-      <td>
-        <code>List of labels, required</code>
-        <p>List of Rust <code>.rs</code> source files used to build the
-        library.</p>
-        <p>
-          There must be a file either named <code>lib.rs</code> or with a name
-          matching the name of this crate. For example, if the name of a given
-          rule is <code>foo</code>, then there must be a file named
-          <code>lib.rs</code> or <code>foo.rs</code> in <code>srcs</code>.
-          This file will be passed to <code>rustc</code> as the crate root.
-        </p>
-      </td>
-    </tr>
-    <tr>
-      <td><code>deps</code></td>
-      <td>
-        <code>List of labels, optional</code>
-        <p>List of other libraries to be linked to this library target.</p>
-        <p>
-          These can be either other <code>rust_library</code> targets or
-          <code>cc_library</code> targets if linking a native library.
-        </p>
-      </td>
-    </tr>
-    <tr>
-      <td><code>data</code></td>
-      <td>
-        <code>List of labels, optional</code>
-        <p>List of files used by this rule at runtime.</p>
-        <p>
-          This attribute can be used to specify any data files that are embedded
-          into the library, such as via the
-          <a href="https://doc.rust-lang.org/std/macro.include_str!.html target="_blank"><code>include_str!</code></a>
-          macro.
-        </p>
-      </td>
-    </tr>
-    <tr>
-      <td><code>crate_features</code></td>
-      <td>
-        <code>List of strings, optional</code>
-        <p>List of features to enable for this crate.</p>
-        <p>
-          Features are defined in the code using the
-          <code>#[cfg(feature = "foo")]</code> configuration option. The
-          features listed here will be passed to <code>rustc</code> with
-          <code>--cfg feature="${feature_name}"</code> flags.
-        </p>
-      </td>
-    </tr>
-    <tr>
-      <td><code>rustc_flags</code></td>
-      <td>
-        <code>List of strings, optional</code>
-        <p>List of compiler flags passed to <code>rustc</code>.</p>
-      </td>
-    </tr>
-  </tbody>
-</table>
-
-<a name="reference-rust_binary"></a>
-### `rust_binary`
-
-`rust_binary(name, srcs, deps, data, crate_features, rustc_flags)`
-
 <table>
   <thead>
     <tr>
@@ -263,16 +232,30 @@
         <p>List of Rust <code>.rs</code> source files used to build the
         binary.</p>
         <p>
-          There must be a file either named <code>main.rs</code> or with a name
-          matching the name of this crate that contains the <code>main</code>
-          function. For example, if the name of a given
-          rule is <code>foo</code>, then there must be a file named
-          <code>main.rs</code> or <code>foo.rs</code> in <code>srcs</code>.
-          This file will be passed to <code>rustc</code> as the crate root.
+          If <code>srcs</code> contains more than one file, then there must be
+          a file either named <code>main.rs</code>. Otherwise,
+          <code>crate_root</code> must be set to the source file that is the
+          root of the crate to be passed to <code>rustc</code> to build this
+          crate.
         </p>
       </td>
     </tr>
     <tr>
+      <td><code>crate_root</code></td>
+      <td>
+        <code>Label, optional</code>
+        <p>
+          The file that will be passed to <code>rustc</code> to be used for
+          building this crate.
+        </p>
+        <p>
+          If <code>crate_root</code> is not set, then this rule will look for
+          a <code>main.rs</code> file or the single file in <code>srcs</code>
+          if <code>srcs</code> contains only one file.
+        </p>
+      </td>
+    </td>
+    <tr>
       <td><code>deps</code></td>
       <td>
         <code>List of labels, optional</code>
@@ -318,8 +301,94 @@
   </tbody>
 </table>
 
-<a name="reference-rust_test"></a>
-### `rust_test`
+### Example
+
+Suppose you have the following directory structure for a Rust project with a
+library crate, `hello_lib`, and a binary crate, `hello_world` that uses the
+`hello_lib` library:
+
+```
+[workspace]/
+    WORKSPACE
+    hello_lib/
+        BUILD
+        src/
+            lib.rs
+    hello_world/
+        BUILD
+        src/
+            main.rs
+```
+
+`hello_lib/src/lib.rs`:
+
+```rust
+pub struct Greeter {
+    greeting: String,
+}
+
+impl Greeter {
+    pub fn new(greeting: &str) -> Greeter {
+        Greeter { greeting: greeting.to_string(), }
+    }
+
+    pub fn greet(&self, thing: &str) {
+        println!("{} {}", &self.greeting, thing);
+    }
+}
+```
+
+`hello_lib/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library")
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["src/lib.rs"],
+)
+```
+
+`hello_world/src/main.rs`:
+
+```rust
+extern crate hello_lib;
+
+fn main() {
+    let hello = hello_lib::Greeter::new("Hello");
+    hello.greet("world");
+}
+```
+
+`hello_world/BUILD`:
+
+```python
+load("/tools/build_rules/rust/rust", "rust_binary")
+
+rust_binary(
+    name = "hello_world",
+    srcs = ["src/main.rs"],
+    deps = ["//hello_lib"],
+)
+```
+
+Build and run `hello_world`:
+
+```
+$ bazel run //hello_world
+INFO: Found 1 target...
+Target //examples/rust/hello_world:hello_world up-to-date:
+  bazel-bin/examples/rust/hello_world/hello_world
+INFO: Elapsed time: 1.308s, Critical Path: 1.22s
+
+INFO: Running command line: bazel-bin/examples/rust/hello_world/hello_world
+Hello world
+```
+
+<a name="rust_test"></a>
+## rust_test
 
 ```python
 rust_test(name, srcs, deps, data, crate_features, rustc_flags)
@@ -351,15 +420,30 @@
         <p>List of Rust <code>.rs</code> source files used to build the
         library.</p>
         <p>
-          There must be a file either with a name matching the name of this
-          test. For example, if the name of a <code>rust_test</code> rule is
-          <code>foo</code>, then there must be a file named <code>foo.rs</code>
-          in <code>srcs</code>.  This file will be passed to <code>rustc</code>
-          as the crate root.
+          If <code>srcs</code> contains more than one file, then there must be
+          a file either named <code>lib.rs</code>. Otherwise,
+          <code>crate_root</code> must be set to the source file that is the
+          root of the crate to be passed to <code>rustc</code> to build this
+          crate.
         </p>
       </td>
     </tr>
     <tr>
+      <td><code>crate_root</code></td>
+      <td>
+        <code>Label, optional</code>
+        <p>
+          The file that will be passed to <code>rustc</code> to be used for
+          building this crate.
+        </p>
+        <p>
+          If <code>crate_root</code> is not set, then this rule will look for
+          a <code>lib.rs</code> file or the single file in <code>srcs</code>
+          if <code>srcs</code> contains only one file.
+        </p>
+      </td>
+    </td>
+    <tr>
       <td><code>deps</code></td>
       <td>
         <code>List of labels, optional</code>
@@ -405,11 +489,319 @@
   </tbody>
 </table>
 
-<a name="reference-rust_docs"></a>
-### `rust_docs`
+### Example
+
+Suppose you have the following directory structure for a Rust library crate
+with unit test code in the library sources:
+
+```
+[workspace]/
+    WORKSPACE
+    hello_lib/
+        BUILD
+        src/
+            lib.rs
+```
+
+`hello_lib/src/lib.rs`:
+
+```rust
+pub struct Greeter {
+    greeting: String,
+}
+
+impl Greeter {
+    pub fn new(greeting: &str) -> Greeter {
+        Greeter { greeting: greeting.to_string(), }
+    }
+
+    pub fn greet(&self, thing: &str) {
+        println!("{} {}", &self.greeting, thing);
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::Greeter;
+
+    #[test]
+    fn test_greeting() {
+        let hello = Greeter::new("Hi");
+        assert_eq!("Hi Rust", hello.greeting("Rust"));
+    }
+}
+```
+
+To build and run the tests, simply add a `rust_test` rule with no `srcs` and
+only depends on the `hello_lib` `rust_library` target:
+
+`hello_lib/BUILD`:
 
 ```python
-rust_docs(name, dep, markdown_css, html_in_header, html_before_content, html_after_content)
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_test")
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["src/lib.rs"],
+)
+
+rust_test(
+    name = "hello_lib_test",
+    deps = [":hello_lib"],
+)
+```
+
+Run the test with `bazel build //hello_lib:hello_lib_test`.
+
+### Example: `test` directory
+
+Integration tests that live in the [`tests` directory][int-tests], they are
+essentially built as separate crates. Suppose you have the following directory
+structure where `greeting.rs` is an integration test for the `hello_lib`
+library crate:
+
+[int-tests]: http://doc.rust-lang.org/book/testing.html#the-tests-directory
+
+```
+[workspace]/
+    WORKSPACE
+    hello_lib/
+        BUILD
+        src/
+            lib.rs
+        tests/
+            greeting.rs
+```
+
+`hello_lib/tests/greeting.rs`:
+
+```rust
+extern crate hello_lib;
+
+use hello_lib;
+
+#[test]
+fn test_greeting() {
+    let hello = greeter::Greeter::new("Hello");
+    assert_eq!("Hello world", hello.greeting("world"));
+}
+```
+
+To build the `greeting.rs` integration test, simply add a `rust_test` target
+with `greeting.rs` in `srcs` and a dependency on the `hello_lib` target:
+
+`hello_lib/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_test")
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["src/lib.rs"],
+)
+
+rust_test(
+    name = "greeting_test",
+    srcs = ["tests/greeting.rs"],
+    deps = [":hello_lib"],
+)
+```
+
+Run the test with `bazel build //hello_lib:hello_lib_test`.
+
+<a name="rust_bench_test"></a>
+## rust_bench_test
+
+```python
+rust_bench_test(name, srcs, deps, data, crate_features, rustc_flags)
+```
+
+**Warning**: This rule is currently experimental. [Rust Benchmark
+tests][rust-bench] require the `Bencher` interface in the unstable `libtest`
+crate, which is behind the `test` unstable feature gate. As a result, using
+this rule would require using a nightly binary release of Rust. A
+`rust_toolchain` rule will be added in the [near future](#roadmap) to make it
+easy to use a custom Rust toolchain, such as a nightly release.
+
+[rust-bench]: https://doc.rust-lang.org/book/benchmark-tests.html
+
+<table>
+  <thead>
+    <tr>
+      <th>Attribute</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>name</code></td>
+      <td>
+        <code>Name, required</code>
+        <p>A unique name for this rule.</p>
+        <p>
+          This name will also be used as the name of the binary test crate
+          built by this rule.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>srcs</code></td>
+      <td>
+        <code>List of labels, required</code>
+        <p>List of Rust <code>.rs</code> source files used to build the
+        library.</p>
+        <p>
+          If <code>srcs</code> contains more than one file, then there must be
+          a file either named <code>lib.rs</code>. Otherwise,
+          <code>crate_root</code> must be set to the source file that is the
+          root of the crate to be passed to <code>rustc</code> to build this
+          crate.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>crate_root</code></td>
+      <td>
+        <code>Label, optional</code>
+        <p>
+          The file that will be passed to <code>rustc</code> to be used for
+          building this crate.
+        </p>
+        <p>
+          If <code>crate_root</code> is not set, then this rule will look for
+          a <code>lib.rs</code> file or the single file in <code>srcs</code>
+          if <code>srcs</code> contains only one file.
+        </p>
+      </td>
+    </td>
+    <tr>
+      <td><code>deps</code></td>
+      <td>
+        <code>List of labels, optional</code>
+        <p>List of other libraries to be linked to this test target.</p>
+        <p>
+          These must be <code>rust_library</code> targets.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>data</code></td>
+      <td>
+        <code>List of labels, optional</code>
+        <p>List of files used by this rule at runtime.</p>
+        <p>
+          This attribute can be used to specify any data files that are embedded
+          into the library, such as via the
+          <a href="https://doc.rust-lang.org/std/macro.include_str!.html target="_blank"><code>include_str!</code></a>
+          macro.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>crate_features</code></td>
+      <td>
+        <code>List of strings, optional</code>
+        <p>List of features to enable for this crate.</p>
+        <p>
+          Features are defined in the code using the
+          <code>#[cfg(feature = "foo")]</code> configuration option. The
+          features listed here will be passed to <code>rustc</code> with
+          <code>--cfg feature="${feature_name}"</code> flags.
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>rustc_flags</code></td>
+      <td>
+        <code>List of strings, optional</code>
+        <p>List of compiler flags passed to <code>rustc</code>.</p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a Rust project with a
+library crate, `fibonacci` with benchmarks under the `benches/` directory:
+
+```
+[workspace]/
+    WORKSPACE
+    fibonacci/
+        BUILD
+        src/
+            lib.rs
+        benches/
+            fibonacci_bench.rs
+```
+
+`fibonacci/src/lib.rs`:
+
+```rust
+pub fn fibonacci(n: u64) -> u64 {
+    if n < 2 {
+        return n;
+    }
+    let mut n1: u64 = 0;
+    let mut n2: u64 = 1;
+    for _ in 1..n {
+        let sum = n1 + n2;
+        n1 = n2;
+        n2 = sum;
+    }
+    n2
+}
+```
+
+`fibonacci/benches/fibonacci_bench.rs`:
+
+```rust
+#![feature(test)]
+
+extern crate test;
+extern crate fibonacci;
+
+use test::Bencher;
+
+#[bench]
+fn bench_fibonacci(b: &mut Bencher) {
+    b.iter(|| fibonacci::fibonacci(40));
+}
+```
+
+To build the benchmark test, simply add a `rust_bench_test` target:
+
+`fibonacci/BUILD`:
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_bench_test")
+
+rust_library(
+    name = "fibonacci",
+    srcs = ["src/lib.rs"],
+)
+
+rust_bench_test(
+    name = "fibonacci_bench",
+    srcs = ["benches/fibonacci_bench.rs"],
+    deps = [":fibonacci"],
+)
+```
+
+Run the benchmark test using: `bazel build //fibonacci:fibonacci_bench`.
+
+<a name="rust_doc"></a>
+## rust_doc
+
+```python
+rust_doc(name, dep, markdown_css, html_in_header, html_before_content, html_after_content)
 ```
 
 <table>
@@ -433,7 +825,7 @@
         <code>Label, required</code>
         <p>The label of the target to generate code documentation for.</p>
         <p>
-          <code>rust_docs</code> can generate HTML code documentation for the
+          <code>rust_doc</code> can generate HTML code documentation for the
           source files of <code>rust_library</code> or <code>rust_binary</code>
           targets.
         </p>
@@ -473,20 +865,113 @@
   </tbody>
 </table>
 
-<a name="#roadmap"></a>
-## Roadmap
+### Example
 
-### Near-term roadmap
+Suppose you have the following directory structure for a Rust library crate:
 
-* Enable `rust_test` to depend solely on a `rust_library` since many projects
-  intermix `#[test]` methods in implementation source.
-* Improve documentation with more detailed examples.
+```
+[workspace]/
+    WORKSPACE
+    hello_lib/
+        BUILD
+        src/
+            lib.rs
+```
 
-### Longer-term roadmap
+To build [`rustdoc`][rustdoc] documentation for the `hello_lib` crate, define
+a `rust_doc` rule that depends on the the `hello_lib` `rust_library` target:
 
-* Add tool for taking `Cargo.toml` and generating a `WORKSPACE` file with
-  workspace rules for pulling external dependencies.
-* Improve expressiveness of features and support for [Cargo's feature
-  groups](http://doc.crates.io/manifest.html#the-[features]-section).
-* Add `cargo_crate` workspace rule for pulling crates from
-  [Cargo](https://crates.io/).
+[rustdoc]: https://doc.rust-lang.org/book/documentation.html
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_doc")
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["src/lib.rs"],
+)
+
+rust_doc(
+    name = "hello_lib_doc",
+    dep = ":hello_lib",
+)
+```
+
+Running `bazel build //hello_lib:hello_lib_doc` will build a zip file containing
+the documentation for the `hello_lib` library crate generated by `rustdoc`.
+
+<a name="rust_doc_test"></a>
+### `rust_doc_test`
+
+```python
+rust_doc_test(name, dep)
+```
+
+<table>
+  <thead>
+    <tr>
+      <th>Attribute</th>
+      <th>Description</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td><code>name</code></td>
+      <td>
+        <code>Name, required</code>
+        <p>A unique name for this rule.</p>
+      </td>
+    </tr>
+    <tr>
+      <td><code>dep</code></td>
+      <td>
+        <code>Label, required</code>
+        <p>The label of the target to run documentation tests for.</p>
+        <p>
+          <code>rust_doc_test</code> can run documentation tests for the
+          source files of <code>rust_library</code> or <code>rust_binary</code>
+          targets.
+        </p>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+### Example
+
+Suppose you have the following directory structure for a Rust library crate:
+
+```
+[workspace]/
+    WORKSPACE
+    hello_lib/
+        BUILD
+        src/
+            lib.rs
+```
+
+To run [documentation tests][doc-test] for the `hello_lib` crate, define a
+`rust_doc_test` target that depends on the `hello_lib` `rust_library` target:
+
+[doc-test]: https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
+
+```python
+package(default_visibility = ["//visibility:public"])
+
+load("/tools/build_rules/rust/rust", "rust_library", "rust_doc_test")
+
+rust_library(
+    name = "hello_lib",
+    srcs = ["src/lib.rs"],
+)
+
+rust_doc_test(
+    name = "hello_lib_doc_test",
+    dep = ":hello_lib",
+)
+```
+
+Running `bazel test //hello_lib:hello_lib_doc_test` will run all documentation
+tests for the `hello_lib` library crate.
diff --git a/tools/build_rules/rust/rust.BUILD b/tools/build_rules/rust/rust.BUILD
index 576f8b8..8a0e469 100644
--- a/tools/build_rules/rust/rust.BUILD
+++ b/tools/build_rules/rust/rust.BUILD
@@ -1,7 +1,3 @@
-RUST_VERSION = "1.3.0"
-LINUX_BASE_DIR = "rust-%s-x86_64-unknown-linux-gnu/" % RUST_VERSION
-DARWIN_BASE_DIR = "rust-%s-x86_64-apple-darwin/" % RUST_VERSION
-
 config_setting(
     name = "darwin",
     values = {"host_cpu": "darwin"},
@@ -15,8 +11,8 @@
 filegroup(
     name = "rustc",
     srcs = select({
-        ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustc"],
-        ":k8": [LINUX_BASE_DIR + "rustc/bin/rustc"],
+        ":darwin": ["rustc/bin/rustc"],
+        ":k8": ["rustc/bin/rustc"],
     }),
     visibility = ["//visibility:public"],
 )
@@ -24,8 +20,8 @@
 filegroup(
     name = "rustc_lib",
     srcs = select({
-        ":darwin": glob([DARWIN_BASE_DIR + "rustc/lib/*.dylib"]),
-        ":k8": glob([LINUX_BASE_DIR + "rustc/lib/*.so"]),
+        ":darwin": glob(["rustc/lib/*.dylib"]),
+        ":k8": glob(["rustc/lib/*.so"]),
     }),
     visibility = ["//visibility:public"],
 )
@@ -33,8 +29,8 @@
 filegroup(
     name = "rustdoc",
     srcs = select({
-        ":darwin": [DARWIN_BASE_DIR + "rustc/bin/rustdoc"],
-        ":k8": [LINUX_BASE_DIR + "rustc/bin/rustdoc"],
+        ":darwin": ["rustc/bin/rustdoc"],
+        ":k8": ["rustc/bin/rustdoc"],
     }),
     visibility = ["//visibility:public"],
 )
@@ -43,14 +39,14 @@
     name = "rustlib",
     srcs = select({
         ":darwin": glob([
-            DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.rlib",
-            DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.dylib",
-            DARWIN_BASE_DIR + "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.a",
+            "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.rlib",
+            "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.dylib",
+            "rustc/lib/rustlib/x86_64-apple-darwin/lib/*.a",
         ]),
         ":k8": glob([
-            LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib",
-            LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so",
-            LINUX_BASE_DIR + "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.a",
+            "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib",
+            "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so",
+            "rustc/lib/rustlib/x86_64-unknown-linux-gnu/lib/*.a",
         ]),
     }),
     visibility = ["//visibility:public"],
diff --git a/tools/build_rules/rust/rust.bzl b/tools/build_rules/rust/rust.bzl
index 69a54b1..5dc3c0b 100644
--- a/tools/build_rules/rust/rust.bzl
+++ b/tools/build_rules/rust/rust.bzl
@@ -17,7 +17,9 @@
 RUST_FILETYPE = FileType([".rs"])
 A_FILETYPE = FileType([".a"])
 
-# Used by rust_docs
+LIBRARY_CRATE_TYPES = ["lib", "rlib", "dylib", "staticlib"]
+
+# Used by rust_doc
 HTML_MD_FILETYPE = FileType([".html", ".md"])
 CSS_FILETYPE = FileType([".css"])
 
@@ -143,8 +145,8 @@
       rustlib_path = ctx.files._rustlib[0].dirname,
       rustdoc_path = ctx.file._rustdoc.path)
 
-def _build_rustc_command(ctx, crate_type, src, output_dir, depinfo,
-                         extra_flags=[]):
+def _build_rustc_command(ctx, crate_name, crate_type, src, output_dir,
+                         depinfo, rust_flags=[]):
   """Builds the rustc command.
 
   Constructs the rustc command used to build the current target.
@@ -152,11 +154,10 @@
   Args:
     ctx: The ctx object for the current target.
     crate_type: The type of crate to build ("lib" or "bin")
-    src: The path to the crate root source file ("lib.rs" or "main.rs")
+    src: The File object for crate root source file ("lib.rs" or "main.rs")
     output_dir: The output directory for the target.
     depinfo: Struct containing information about dependencies as returned by
         _setup_deps
-    extra_flags: Additional command line flags.
 
   Return:
     String containing the rustc command.
@@ -180,42 +181,61 @@
   # Construct features flags
   features_flags = _get_features_flags(ctx.attr.crate_features)
 
-  return " ".join([
-      "set -e;",
-      " ".join(depinfo.setup_cmd),
-      "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
-      "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
-      toolchain.rustc_path,
-      src,
-      "--crate-name %s" % ctx.label.name,
-      "--crate-type %s" % crate_type,
-      "-C opt-level=3",
-      "--codegen ar=%s" % ar,
-      "--codegen linker=%s" % cc,
-      "-L all=%s" % toolchain.rustlib_path,
-      " ".join(extra_flags),
-      " ".join(features_flags),
-      "--out-dir %s" % output_dir,
-      "--emit=dep-info,link",
-      " ".join(depinfo.search_flags),
-      " ".join(depinfo.link_flags),
-      " ".join(ctx.attr.rustc_flags),
-  ])
+  return " ".join(
+      ["set -e;"] +
+      depinfo.setup_cmd +
+      [
+          "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+          "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+          toolchain.rustc_path,
+          src.path,
+          "--crate-name %s" % crate_name,
+          "--crate-type %s" % crate_type,
+          "-C opt-level=3",
+          "--codegen ar=%s" % ar,
+          "--codegen linker=%s" % cc,
+          "-L all=%s" % toolchain.rustlib_path,
+          "--out-dir %s" % output_dir,
+          "--emit=dep-info,link",
+      ] +
+      features_flags +
+      rust_flags +
+      depinfo.search_flags +
+      depinfo.link_flags +
+      ctx.attr.rustc_flags)
 
 def _find_crate_root_src(srcs, file_names=["lib.rs"]):
   """Finds the source file for the crate root."""
+  if len(srcs) == 1:
+    return srcs[0]
   for src in srcs:
     if src.basename in file_names:
-      return src.path
+      return src
   fail("No %s source file found." % " or ".join(file_names), "srcs")
 
+def _crate_root_src(ctx, file_names=["lib.rs"]):
+  if ctx.file.crate_root == None:
+    return _find_crate_root_src(ctx.files.srcs, file_names)
+  else:
+    return ctx.file.crate_root
+
 def _rust_library_impl(ctx):
   """
   Implementation for rust_library Skylark rule.
   """
 
   # Find lib.rs
-  lib_rs = _find_crate_root_src(ctx.files.srcs)
+  lib_rs = _crate_root_src(ctx)
+
+  # Validate crate_type
+  crate_type = ""
+  if ctx.attr.crate_type != "":
+    if ctx.attr.crate_type not in LIBRARY_CRATE_TYPES:
+      fail("Invalid crate_type for rust_library. Allowed crate types are: %s"
+           % " ".join(LIBRARY_CRATE_TYPES), "crate_type")
+    crate_type += ctx.attr.crate_type
+  else:
+    crate_type += "lib"
 
   # Output library
   rust_lib = ctx.outputs.rust_lib
@@ -230,7 +250,8 @@
   # Build rustc command
   cmd = _build_rustc_command(
       ctx = ctx,
-      crate_type = "lib",
+      crate_name = ctx.label.name,
+      crate_type = crate_type,
       src = lib_rs,
       output_dir = output_dir,
       depinfo = depinfo)
@@ -240,6 +261,7 @@
       ctx.files.srcs +
       ctx.files.data +
       depinfo.libs +
+      depinfo.transitive_libs +
       [ctx.file._rustc] +
       ctx.files._rustc_lib +
       ctx.files._rustlib)
@@ -255,16 +277,18 @@
 
   return struct(
       files = set([rust_lib]),
+      crate_type = crate_type,
+      crate_root = lib_rs,
       rust_srcs = ctx.files.srcs,
       rust_deps = ctx.attr.deps,
       transitive_libs = depinfo.transitive_libs,
       rust_lib = rust_lib)
 
-def _rust_binary_impl_common(ctx, extra_flags = []):
+def _rust_binary_impl(ctx):
   """Implementation for rust_binary Skylark rule."""
 
   # Find main.rs.
-  main_rs = _find_crate_root_src(ctx.files.srcs, ["main.rs"])
+  main_rs = _crate_root_src(ctx, ["main.rs"])
 
   # Output binary
   rust_binary = ctx.outputs.executable
@@ -278,17 +302,18 @@
 
   # Build rustc command.
   cmd = _build_rustc_command(ctx = ctx,
+                             crate_name = ctx.label.name,
                              crate_type = "bin",
                              src = main_rs,
                              output_dir = output_dir,
-                             depinfo = depinfo,
-                             extra_flags = extra_flags)
+                             depinfo = depinfo)
 
   # Compile action.
   compile_inputs = (
       ctx.files.srcs +
       ctx.files.data +
       depinfo.libs +
+      depinfo.transitive_libs +
       [ctx.file._rustc] +
       ctx.files._rustc_lib +
       ctx.files._rustlib)
@@ -303,19 +328,89 @@
                           % (ctx.label.name, len(ctx.files.srcs))))
 
   return struct(rust_srcs = ctx.files.srcs,
+                crate_root = main_rs,
                 rust_deps = ctx.attr.deps)
 
-def _rust_binary_impl(ctx):
+def _rust_test_common(ctx, test_binary):
+  """Builds a Rust test binary.
+
+  Args:
+      ctx: The ctx object for the current target.
+      test_binary: The File object for the test binary.
   """
-  Implementation for rust_binary Skylark rule.
-  """
-  return _rust_binary_impl_common(ctx)
+  output_dir = test_binary.dirname
+
+  if len(ctx.attr.deps) == 1 and len(ctx.files.srcs) == 0:
+    # Target has a single dependency but no srcs. Build the test binary using
+    # the dependency's srcs.
+    dep = ctx.attr.deps[0]
+    crate_type = dep.crate_type if hasattr(dep, "crate_type") else "bin"
+    target = struct(name = dep.label.name,
+                    srcs = dep.rust_srcs,
+                    deps = dep.rust_deps,
+                    crate_root = dep.crate_root,
+                    crate_type = crate_type)
+  else:
+    # Target is a standalone crate. Build the test binary as its own crate.
+    target = struct(name = ctx.label.name,
+                    srcs = ctx.files.srcs,
+                    deps = ctx.attr.deps,
+                    crate_root = _crate_root_src(ctx),
+                    crate_type = "lib")
+
+  # Get information about dependencies
+  depinfo = _setup_deps(target.deps,
+                        target.name,
+                        output_dir,
+                        is_library=False)
+
+  cmd = _build_rustc_command(ctx = ctx,
+                             crate_name = test_binary.basename,
+                             crate_type = target.crate_type,
+                             src = target.crate_root,
+                             output_dir = output_dir,
+                             depinfo = depinfo,
+                             rust_flags = ["--test"])
+
+  compile_inputs = (target.srcs +
+                    depinfo.libs +
+                    depinfo.transitive_libs +
+                    [ctx.file._rustc] +
+                    ctx.files._rustc_lib +
+                    ctx.files._rustlib)
+
+  ctx.action(
+      inputs = compile_inputs,
+      outputs = [test_binary],
+      mnemonic = "RustcTest",
+      command = cmd,
+      use_default_shell_env = True,
+      progress_message = ("Compiling Rust test %s (%d files)"
+                          % (ctx.label.name, len(target.srcs))))
 
 def _rust_test_impl(ctx):
   """
-  Implementation for rust_test and rust_bench_test Skylark rules.
+  Implementation for rust_test Skylark rule.
   """
-  return _rust_binary_impl_common(ctx, ["--test"])
+  _rust_test_common(ctx, ctx.outputs.executable)
+
+def _rust_bench_test_impl(ctx):
+  """Implementation for the rust_bench_test Skylark rule."""
+  rust_bench_test = ctx.outputs.executable
+  test_binary = ctx.new_file(ctx.configuration.bin_dir,
+                             "%s_bin" % rust_bench_test.basename)
+  _rust_test_common(ctx, test_binary)
+
+  ctx.file_action(
+      output = rust_bench_test,
+      content = " ".join([
+          "#!/bin/bash\n",
+          "set -e\n",
+          "%s --bench\n" % test_binary.short_path]),
+      executable = True)
+
+  runfiles = ctx.runfiles(files = [test_binary], collect_data = True)
+  return struct(runfiles = runfiles)
 
 def _build_rustdoc_flags(ctx):
   """Collects the rustdoc flags."""
@@ -331,19 +426,21 @@
     doc_flags += ["--html-after-content %s"]
   return doc_flags
 
-def _rust_docs_impl(ctx):
-  """Implementation of the rust_docs rule."""
+def _rust_doc_impl(ctx):
+  """Implementation of the rust_doc rule."""
   rust_doc_zip = ctx.outputs.rust_doc_zip
 
   # Gather attributes about the rust_library target to generated rustdocs for.
   target = struct(name = ctx.attr.dep.label.name,
                   srcs = ctx.attr.dep.rust_srcs,
-                  deps = ctx.attr.dep.rust_deps)
+                  deps = ctx.attr.dep.rust_deps,
+                  crate_root = ctx.attr.dep.crate_root)
 
   # Find lib.rs
-  lib_rs = _find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+  lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+            if target.crate_root == None else target.crate_root)
 
-  # Dependencies
+  # Get information about dependencies
   output_dir = rust_doc_zip.dirname
   depinfo = _setup_deps(target.deps,
                         target.name,
@@ -364,7 +461,7 @@
           "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
           "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
           toolchain.rustdoc_path,
-          lib_rs,
+          lib_rs.path,
           "--crate-name %s" % target.name,
           "-L all=%s" % toolchain.rustlib_path,
           "-o %s" % docs_dir,
@@ -399,8 +496,60 @@
       progress_message = ("Generating rustdoc for %s (%d files)"
                           % (target.name, len(target.srcs))))
 
+def _rust_doc_test_impl(ctx):
+  """Implementation for the rust_doc_test rule."""
+  rust_doc_test = ctx.outputs.executable
+
+  # Gather attributes about the rust_library target to generated rustdocs for.
+  target = struct(name = ctx.attr.dep.label.name,
+                  srcs = ctx.attr.dep.rust_srcs,
+                  deps = ctx.attr.dep.rust_deps,
+                  crate_root = ctx.attr.dep.crate_root)
+
+  # Find lib.rs
+  lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"])
+            if target.crate_root == None else target.crate_root)
+
+  # Get information about dependencies
+  depinfo = _setup_deps(target.deps,
+                        target.name,
+                        working_dir=".",
+                        is_library=False)
+
+  # Construct rustdoc test command, which will be written to a shell script
+  # to be executed to run the test.
+  toolchain = _rust_toolchain(ctx)
+  doc_test_cmd = " ".join(
+      ["#!/bin/bash\n"] +
+      ["set -e\n"] +
+      depinfo.setup_cmd +
+      [
+          "LD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+          "DYLD_LIBRARY_PATH=%s" % toolchain.rustc_lib_path,
+          toolchain.rustdoc_path,
+          lib_rs.path,
+      ] +
+      depinfo.search_flags +
+      depinfo.link_flags)
+
+  ctx.file_action(output = rust_doc_test,
+                  content = doc_test_cmd,
+                  executable = True)
+
+  doc_test_inputs = (target.srcs +
+                     depinfo.libs +
+                     depinfo.transitive_libs +
+                     [ctx.file._rustdoc] +
+                     ctx.files._rustc_lib +
+                     ctx.files._rustlib)
+
+  runfiles = ctx.runfiles(files = doc_test_inputs, collect_data = True)
+  return struct(runfiles = runfiles)
+
 _rust_common_attrs = {
     "srcs": attr.label_list(allow_files = RUST_FILETYPE),
+    "crate_root": attr.label(allow_files = RUST_FILETYPE,
+                             single_file = True),
     "data": attr.label_list(allow_files = True, cfg = DATA_CFG),
     "deps": attr.label_list(),
     "crate_features": attr.string_list(),
@@ -421,9 +570,13 @@
         single_file = True),
 }
 
+_rust_library_attrs = _rust_common_attrs + {
+    "crate_type": attr.string(),
+}
+
 rust_library = rule(
     _rust_library_impl,
-    attrs = _rust_common_attrs + _rust_toolchain_attrs,
+    attrs = _rust_library_attrs + _rust_toolchain_attrs,
     outputs = {
         "rust_lib": "lib%{name}.rlib",
     },
@@ -446,25 +599,35 @@
 )
 
 rust_bench_test = rule(
-    _rust_test_impl,
+    _rust_bench_test_impl,
     executable = True,
     attrs = _rust_common_attrs + _rust_toolchain_attrs,
     test = True,
     fragments = ["cpp"],
 )
 
-_rust_doc_attrs = {
+_rust_doc_common_attrs = {
     "dep": attr.label(mandatory = True),
+}
+
+_rust_doc_attrs = _rust_doc_common_attrs + {
     "markdown_css": attr.label_list(allow_files = CSS_FILETYPE),
     "html_in_header": attr.label(allow_files = HTML_MD_FILETYPE),
     "html_before_content": attr.label(allow_files = HTML_MD_FILETYPE),
     "html_after_content": attr.label(allow_files = HTML_MD_FILETYPE),
 }
 
-rust_docs = rule(
-    _rust_docs_impl,
+rust_doc = rule(
+    _rust_doc_impl,
     attrs = _rust_doc_attrs + _rust_toolchain_attrs,
     outputs = {
         "rust_doc_zip": "%{name}-docs.zip",
     },
 )
+
+rust_doc_test = rule(
+    _rust_doc_test_impl,
+    attrs = _rust_doc_common_attrs + _rust_toolchain_attrs,
+    executable = True,
+    test = True,
+)