about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-02-19 02:11:48 -0800
committerbors <bors@rust-lang.org>2014-02-19 02:11:48 -0800
commitc4afcf44d2c70b2c176bdf283082a7bdd4be5826 (patch)
treed9678297bc030da543bdf174489418bf418d554c /src
parent9f68f793d444285e5d7f00f57b5635ece43613b3 (diff)
parent429ef870f67b02664b6ac35b08f3b36b71e8bd00 (diff)
downloadrust-c4afcf44d2c70b2c176bdf283082a7bdd4be5826.tar.gz
rust-c4afcf44d2c70b2c176bdf283082a7bdd4be5826.zip
auto merge of #12339 : alexcrichton/rust/rustdoc-fixes, r=sfackler
Commits have the details
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/clean.rs31
-rw-r--r--src/librustdoc/doctree.rs9
-rw-r--r--src/librustdoc/html/render.rs92
-rw-r--r--src/librustdoc/html/static/main.css2
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/passes.rs4
-rw-r--r--src/librustdoc/visit_ast.rs9
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/macros.rs177
-rw-r--r--src/test/run-make/rustdoc-json/Makefile4
-rw-r--r--src/test/run-make/rustdoc-json/foo.rs25
11 files changed, 314 insertions, 43 deletions
diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs
index 22f9d2f9843..586323358c2 100644
--- a/src/librustdoc/clean.rs
+++ b/src/librustdoc/clean.rs
@@ -25,7 +25,6 @@ use rustc::metadata::csearch;
 use rustc::metadata::decoder;
 
 use std;
-use std::hashmap::HashMap;
 
 use doctree;
 use visit_ast;
@@ -68,7 +67,7 @@ impl<T: Clean<U>, U> Clean<~[U]> for syntax::opt_vec::OptVec<T> {
 pub struct Crate {
     name: ~str,
     module: Option<Item>,
-    externs: HashMap<ast::CrateNum, ExternalCrate>,
+    externs: ~[(ast::CrateNum, ExternalCrate)],
 }
 
 impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
@@ -76,9 +75,9 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
         use syntax::attr::find_crateid;
         let cx = local_data::get(super::ctxtkey, |x| *x.unwrap());
 
-        let mut externs = HashMap::new();
+        let mut externs = ~[];
         cx.sess.cstore.iter_crate_data(|n, meta| {
-            externs.insert(n, meta.clean());
+            externs.push((n, meta.clean()));
         });
 
         Crate {
@@ -181,6 +180,7 @@ pub enum ItemEnum {
     VariantItem(Variant),
     ForeignFunctionItem(Function),
     ForeignStaticItem(Static),
+    MacroItem(Macro),
 }
 
 #[deriving(Clone, Encodable, Decodable)]
@@ -206,7 +206,8 @@ impl Clean<Item> for doctree::Module {
                        self.fns.clean(), self.foreigns.clean().concat_vec(),
                        self.mods.clean(), self.typedefs.clean(),
                        self.statics.clean(), self.traits.clean(),
-                       self.impls.clean(), self.view_items.clean()].concat_vec()
+                       self.impls.clean(), self.view_items.clean(),
+                       self.macros.clean()].concat_vec()
             })
         }
     }
@@ -1263,3 +1264,23 @@ fn resolve_def(id: ast::NodeId) -> Option<ast::DefId> {
         None => None
     }
 }
+
+#[deriving(Clone, Encodable, Decodable)]
+pub struct Macro {
+    source: ~str,
+}
+
+impl Clean<Item> for doctree::Macro {
+    fn clean(&self) -> Item {
+        Item {
+            name: Some(self.name.clean()),
+            attrs: self.attrs.clean(),
+            source: self.where.clean(),
+            visibility: ast::Public.clean(),
+            id: self.id,
+            inner: MacroItem(Macro {
+                source: self.where.to_src(),
+            }),
+        }
+    }
+}
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index f1bd3a62e01..03186c16733 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -32,6 +32,7 @@ pub struct Module {
     impls: ~[Impl],
     foreigns: ~[ast::ForeignMod],
     view_items: ~[ast::ViewItem],
+    macros: ~[Macro],
 }
 
 impl Module {
@@ -52,6 +53,7 @@ impl Module {
             impls      : ~[],
             view_items : ~[],
             foreigns   : ~[],
+            macros     : ~[],
         }
     }
 }
@@ -157,6 +159,13 @@ pub struct Impl {
     id: ast::NodeId,
 }
 
+pub struct Macro {
+    name: Ident,
+    id: ast::NodeId,
+    attrs: ~[ast::Attribute],
+    where: Span,
+}
+
 pub fn struct_type_from_def(sd: &ast::StructDef) -> StructType {
     if sd.ctor_id.is_some() {
         // We are in a tuple-struct
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 11f80155085..649d5f592c5 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -157,6 +157,7 @@ pub struct Cache {
     priv parent_stack: ~[ast::NodeId],
     priv search_index: ~[IndexItem],
     priv privmod: bool,
+    priv public_items: HashSet<ast::NodeId>,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -231,18 +232,23 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
     }
 
     // Crawl the crate to build various caches used for the output
-    let mut cache = Cache {
-        impls: HashMap::new(),
-        typarams: HashMap::new(),
-        paths: HashMap::new(),
-        traits: HashMap::new(),
-        implementors: HashMap::new(),
-        stack: ~[],
-        parent_stack: ~[],
-        search_index: ~[],
-        extern_locations: HashMap::new(),
-        privmod: false,
-    };
+    let mut cache = local_data::get(::analysiskey, |analysis| {
+        let public_items = analysis.map(|a| a.public_items.clone());
+        let public_items = public_items.unwrap_or(HashSet::new());
+        Cache {
+            impls: HashMap::new(),
+            typarams: HashMap::new(),
+            paths: HashMap::new(),
+            traits: HashMap::new(),
+            implementors: HashMap::new(),
+            stack: ~[],
+            parent_stack: ~[],
+            search_index: ~[],
+            extern_locations: HashMap::new(),
+            privmod: false,
+            public_items: public_items,
+        }
+    });
     cache.stack.push(krate.name.clone());
     krate = cache.fold_crate(krate);
 
@@ -305,7 +311,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
         krate = folder.fold_crate(krate);
     }
 
-    for (&n, e) in krate.externs.iter() {
+    for &(n, ref e) in krate.externs.iter() {
         cache.extern_locations.insert(n, extern_location(e, &cx.dst));
     }
 
@@ -565,8 +571,24 @@ impl DocFolder for Cache {
             clean::StructItem(..) | clean::EnumItem(..) |
             clean::TypedefItem(..) | clean::TraitItem(..) |
             clean::FunctionItem(..) | clean::ModuleItem(..) |
-            clean::ForeignFunctionItem(..) | clean::VariantItem(..) => {
-                self.paths.insert(item.id, (self.stack.clone(), shortty(&item)));
+            clean::ForeignFunctionItem(..) => {
+                // Reexported items mean that the same id can show up twice in
+                // the rustdoc ast that we're looking at. We know, however, that
+                // a reexported item doesn't show up in the `public_items` map,
+                // so we can skip inserting into the paths map if there was
+                // already an entry present and we're not a public item.
+                if !self.paths.contains_key(&item.id) ||
+                   self.public_items.contains(&item.id) {
+                    self.paths.insert(item.id,
+                                      (self.stack.clone(), shortty(&item)));
+                }
+            }
+            // link variants to their parent enum because pages aren't emitted
+            // for each variant
+            clean::VariantItem(..) => {
+                let mut stack = self.stack.clone();
+                stack.pop();
+                self.paths.insert(item.id, (stack, "enum"));
             }
             _ => {}
         }
@@ -791,6 +813,7 @@ fn shortty(item: &clean::Item) -> &'static str {
         clean::VariantItem(..)         => "variant",
         clean::ForeignFunctionItem(..) => "ffi",
         clean::ForeignStaticItem(..)   => "ffs",
+        clean::MacroItem(..)           => "macro",
     }
 }
 
@@ -869,6 +892,7 @@ impl<'a> fmt::Show for Item<'a> {
             clean::StructItem(ref s) => item_struct(fmt.buf, self.item, s),
             clean::EnumItem(ref e) => item_enum(fmt.buf, self.item, e),
             clean::TypedefItem(ref t) => item_typedef(fmt.buf, self.item, t),
+            clean::MacroItem(ref m) => item_macro(fmt.buf, self.item, m),
             _ => Ok(())
         }
     }
@@ -937,6 +961,8 @@ fn item_module(w: &mut Writer, cx: &Context,
             (_, &clean::ViewItemItem(..)) => Greater,
             (&clean::ModuleItem(..), _) => Less,
             (_, &clean::ModuleItem(..)) => Greater,
+            (&clean::MacroItem(..), _) => Less,
+            (_, &clean::MacroItem(..)) => Greater,
             (&clean::StructItem(..), _) => Less,
             (_, &clean::StructItem(..)) => Greater,
             (&clean::EnumItem(..), _) => Less,
@@ -987,6 +1013,7 @@ fn item_module(w: &mut Writer, cx: &Context,
                 clean::VariantItem(..)         => "Variants",
                 clean::ForeignFunctionItem(..) => "Foreign Functions",
                 clean::ForeignStaticItem(..)   => "Foreign Statics",
+                clean::MacroItem(..)           => "Macros",
             }));
         }
 
@@ -1099,7 +1126,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         if_ok!(write!(w, "\\{\n"));
         for m in required.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, ";\n"));
         }
         if required.len() > 0 && provided.len() > 0 {
@@ -1107,7 +1134,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         }
         for m in provided.iter() {
             if_ok!(write!(w, "    "));
-            if_ok!(render_method(w, m.item(), true));
+            if_ok!(render_method(w, m.item()));
             if_ok!(write!(w, " \\{ ... \\}\n"));
         }
         if_ok!(write!(w, "\\}"));
@@ -1121,7 +1148,7 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
         if_ok!(write!(w, "<h3 id='{}.{}' class='method'><code>",
                       shortty(m.item()),
                       *m.item().name.get_ref()));
-        if_ok!(render_method(w, m.item(), false));
+        if_ok!(render_method(w, m.item()));
         if_ok!(write!(w, "</code></h3>"));
         if_ok!(document(w, m.item()));
         Ok(())
@@ -1176,16 +1203,12 @@ fn item_trait(w: &mut Writer, it: &clean::Item,
     })
 }
 
-fn render_method(w: &mut Writer, meth: &clean::Item,
-                 withlink: bool) -> fmt::Result {
+fn render_method(w: &mut Writer, meth: &clean::Item) -> fmt::Result {
     fn fun(w: &mut Writer, it: &clean::Item, purity: ast::Purity,
-           g: &clean::Generics, selfty: &clean::SelfTy, d: &clean::FnDecl,
-           withlink: bool) -> fmt::Result {
-        write!(w, "{}fn {withlink, select,
-                            true{<a href='\\#{ty}.{name}'
-                                    class='fnname'>{name}</a>}
-                            other{<span class='fnname'>{name}</span>}
-                        }{generics}{decl}",
+           g: &clean::Generics, selfty: &clean::SelfTy,
+           d: &clean::FnDecl) -> fmt::Result {
+        write!(w, "{}fn <a href='\\#{ty}.{name}' class='fnname'>{name}</a>\
+                   {generics}{decl}",
                match purity {
                    ast::UnsafeFn => "unsafe ",
                    _ => "",
@@ -1193,15 +1216,14 @@ fn render_method(w: &mut Writer, meth: &clean::Item,
                ty = shortty(it),
                name = it.name.get_ref().as_slice(),
                generics = *g,
-               decl = Method(selfty, d),
-               withlink = if withlink {"true"} else {"false"})
+               decl = Method(selfty, d))
     }
     match meth.inner {
         clean::TyMethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         clean::MethodItem(ref m) => {
-            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl, withlink)
+            fun(w, meth, m.purity, &m.generics, &m.self_, &m.decl)
         }
         _ => unreachable!()
     }
@@ -1432,7 +1454,7 @@ fn render_impl(w: &mut Writer, i: &clean::Impl,
     fn docmeth(w: &mut Writer, item: &clean::Item) -> io::IoResult<bool> {
         if_ok!(write!(w, "<h4 id='method.{}' class='method'><code>",
                       *item.name.get_ref()));
-        if_ok!(render_method(w, item, false));
+        if_ok!(render_method(w, item));
         if_ok!(write!(w, "</code></h4>\n"));
         match item.doc_value() {
             Some(s) => {
@@ -1609,3 +1631,9 @@ impl<'a> fmt::Show for Source<'a> {
         Ok(())
     }
 }
+
+fn item_macro(w: &mut Writer, it: &clean::Item,
+              t: &clean::Macro) -> fmt::Result {
+    if_ok!(write!(w, "<pre class='macro'>{}</pre>", t.source));
+    document(w, it)
+}
diff --git a/src/librustdoc/html/static/main.css b/src/librustdoc/html/static/main.css
index e0f4a9c167d..8e1876bad03 100644
--- a/src/librustdoc/html/static/main.css
+++ b/src/librustdoc/html/static/main.css
@@ -301,3 +301,5 @@ a {
 .stability.Stable { border-color: #AEC516; color: #7c8b10; }
 .stability.Frozen { border-color: #009431; color: #007726; }
 .stability.Locked { border-color: #0084B6; color: #00668c; }
+
+:target { background: #FDFFD3; }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 2c4d553a39f..4194f5e4729 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -344,7 +344,7 @@ fn json_output(krate: clean::Crate, res: ~[plugins::PluginJson],
     };
     let crate_json = match json::from_str(crate_json_str) {
         Ok(j) => j,
-        Err(_) => fail!("Rust generated JSON is invalid??")
+        Err(e) => fail!("Rust generated JSON is invalid: {:?}", e)
     };
 
     json.insert(~"crate", crate_json);
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 6ebaf6eece8..2b8f01cfac8 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -150,8 +150,8 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             }
             clean::ImplItem(..) => {}
 
-            // tymethods have no control over privacy
-            clean::TyMethodItem(..) => {}
+            // tymethods/macros have no control over privacy
+            clean::MacroItem(..) | clean::TyMethodItem(..) => {}
         }
 
         let fastreturn = match i.inner {
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 5bf1aa3e91a..ef02d734567 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -280,7 +280,14 @@ impl<'a> RustdocVisitor<'a> {
             ast::ItemForeignMod(ref fm) => {
                 om.foreigns.push(fm.clone());
             }
-            _ => (),
+            ast::ItemMac(ref _m) => {
+                om.macros.push(Macro {
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    name: item.ident,
+                    where: item.span,
+                })
+            }
         }
     }
 }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 4452482b7e8..d3ddd9ae783 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -77,7 +77,7 @@
 #[cfg(test)] pub use ops = realstd::ops;
 #[cfg(test)] pub use cmp = realstd::cmp;
 
-mod macros;
+pub mod macros;
 
 mod rtdeps;
 
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 14ae7c9900c..34b33003786 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -7,8 +7,29 @@
 // <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.
+
+//! Standard library macros
+//!
+//! This modules contains a set of macros which are exported from the standard
+//! library. Each macro is available for use when linking against the standard
+//! library.
+
 #[macro_escape];
 
+/// The standard logging macro
+///
+/// This macro will generically log over a provided level (of type u32) with a
+/// format!-based argument list. See documentation in `std::fmt` for details on
+/// how to use the syntax, and documentation in `std::logging` for info about
+/// logging macros.
+///
+/// # Example
+///
+/// ```
+/// log!(::std::logging::DEBUG, "this is a debug message");
+/// log!(::std::logging::WARN, "this is a warning {}", "message");
+/// log!(6, "this is a custom logging level: {level}", level=6);
+/// ```
 #[macro_export]
 macro_rules! log(
     ($lvl:expr, $($arg:tt)+) => ({
@@ -21,26 +42,73 @@ macro_rules! log(
     })
 )
 
+/// A convenience macro for logging at the error log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let error = 3;
+/// error!("the build has failed with error code: {}", error);
+/// ```
 #[macro_export]
 macro_rules! error(
     ($($arg:tt)*) => (log!(1u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the warning log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let code = 3;
+/// warn!("you may like to know that a process exited with: {}", code);
+/// ```
 #[macro_export]
 macro_rules! warn(
     ($($arg:tt)*) => (log!(2u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the info log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// # let ret = 3;
+/// info!("this function is about to return: {}", ret);
+/// ```
 #[macro_export]
 macro_rules! info(
     ($($arg:tt)*) => (log!(3u32, $($arg)*))
 )
 
+/// A convenience macro for logging at the debug log level. See `std::logging`
+/// for more information. about logging.
+///
+/// # Example
+///
+/// ```
+/// debug!("x = {x}, y = {y}", x=10, y=20);
+/// ```
 #[macro_export]
 macro_rules! debug(
     ($($arg:tt)*) => (if cfg!(not(ndebug)) { log!(4u32, $($arg)*) })
 )
 
+/// A macro to test whether a log level is enabled for the current module.
+///
+/// # Example
+///
+/// ```
+/// # struct Point { x: int, y: int }
+/// # fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } }
+/// if log_enabled!(std::logging::DEBUG) {
+///     let x = some_expensive_computation();
+///     debug!("x.x = {}, x.y = {}", x.x, x.y);
+/// }
+/// ```
 #[macro_export]
 macro_rules! log_enabled(
     ($lvl:expr) => ({
@@ -49,6 +117,25 @@ macro_rules! log_enabled(
     })
 )
 
+/// The entry point for failure of rust tasks.
+///
+/// This macro is used to inject failure into a rust task, causing the task to
+/// unwind and fail entirely. Each task's failure can be reaped as the `~Any`
+/// type, and the single-argument form of the `fail!` macro will be the value
+/// which is transmitted.
+///
+/// The multi-argument form of this macro fails with a string and has the
+/// `format!` sytnax for building a string.
+///
+/// # Example
+///
+/// ```should_fail
+/// # #[allow(unreachable_code)];
+/// fail!();
+/// fail!("this is a terrible mistake!");
+/// fail!(4); // fail with the value of 4 to be collected elsewhere
+/// fail!("this is a {} {message}", "fancy", message = "message");
+/// ```
 #[macro_export]
 macro_rules! fail(
     () => (
@@ -70,6 +157,26 @@ macro_rules! fail(
     });
 )
 
+/// Ensure that a boolean expression is `true` at runtime.
+///
+/// This will invoke the `fail!` macro if the provided expression cannot be
+/// evaluated to `true` at runtime.
+///
+/// # Example
+///
+/// ```
+/// // the failure message for these assertions is the stringified value of the
+/// // expression given.
+/// assert!(true);
+/// # fn some_computation() -> bool { true }
+/// assert!(some_computation());
+///
+/// // assert with a custom message
+/// # let x = true;
+/// assert!(x, "x wasn't true!");
+/// # let a = 3; let b = 27;
+/// assert!(a + b == 30, "a = {}, b = {}", a, b);
+/// ```
 #[macro_export]
 macro_rules! assert(
     ($cond:expr) => (
@@ -89,6 +196,18 @@ macro_rules! assert(
     );
 )
 
+/// Asserts that two expressions are equal to each other, testing equality in
+/// both directions.
+///
+/// On failure, this macro will print the values of the expressions.
+///
+/// # Example
+///
+/// ```
+/// let a = 3;
+/// let b = 1 + 2;
+/// assert_eq!(a, b);
+/// ```
 #[macro_export]
 macro_rules! assert_eq(
     ($given:expr , $expected:expr) => ({
@@ -110,13 +229,15 @@ macro_rules! assert_eq(
 /// # Example
 ///
 /// ~~~rust
+/// struct Item { weight: uint }
+///
 /// fn choose_weighted_item(v: &[Item]) -> Item {
 ///     assert!(!v.is_empty());
 ///     let mut so_far = 0u;
 ///     for item in v.iter() {
 ///         so_far += item.weight;
 ///         if so_far > 100 {
-///             return item;
+///             return *item;
 ///         }
 ///     }
 ///     // The above loop always returns, so we must hint to the
@@ -136,6 +257,16 @@ macro_rules! unimplemented(
     () => (fail!("not yet implemented"))
 )
 
+/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// format!("test");
+/// format!("hello {}", "world!");
+/// format!("x = {}, y = {y}", 10, y = 30);
+/// ```
 #[macro_export]
 macro_rules! format(
     ($($arg:tt)*) => (
@@ -143,6 +274,19 @@ macro_rules! format(
     )
 )
 
+/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`.
+/// See `std::fmt` for more information.
+///
+/// # Example
+///
+/// ```
+/// # #[allow(unused_must_use)];
+/// use std::io::MemWriter;
+///
+/// let mut w = MemWriter::new();
+/// write!(&mut w, "test");
+/// write!(&mut w, "formatted {}", "arguments");
+/// ```
 #[macro_export]
 macro_rules! write(
     ($dst:expr, $($arg:tt)*) => ({
@@ -151,6 +295,8 @@ macro_rules! write(
     })
 )
 
+/// Equivalent to the `write!` macro, except that a newline is appended after
+/// the message is written.
 #[macro_export]
 macro_rules! writeln(
     ($dst:expr, $($arg:tt)*) => ({
@@ -159,16 +305,42 @@ macro_rules! writeln(
     })
 )
 
+/// Equivalent to the `println!` macro except that a newline is not printed at
+/// the end of the message.
 #[macro_export]
 macro_rules! print(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*))
 )
 
+/// Macro for printing to a task's stdout handle.
+///
+/// Each task can override its stdout handle via `std::io::stdio::set_stdout`.
+/// The syntax of this macro is the same as that used for `format!`. For more
+/// information, see `std::fmt` and `std::io::stdio`.
+///
+/// # Example
+///
+/// ```
+/// println!("hello there!");
+/// println!("format {} arguments", "some");
+/// ```
 #[macro_export]
 macro_rules! println(
     ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*))
 )
 
+/// Declare a task-local key with a specific type.
+///
+/// # Example
+///
+/// ```
+/// use std::local_data;
+///
+/// local_data_key!(my_integer: int)
+///
+/// local_data::set(my_integer, 2);
+/// local_data::get(my_integer, |val| println!("{}", val.map(|i| *i)));
+/// ```
 #[macro_export]
 macro_rules! local_data_key(
     ($name:ident: $ty:ty) => (
@@ -179,6 +351,9 @@ macro_rules! local_data_key(
     );
 )
 
+/// Helper macro for unwrapping `Result` values while returning early with an
+/// error if the value of the expression is `Err`. For more information, see
+/// `std::io`.
 #[macro_export]
 macro_rules! if_ok(
     ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
diff --git a/src/test/run-make/rustdoc-json/Makefile b/src/test/run-make/rustdoc-json/Makefile
new file mode 100644
index 00000000000..5e6ab4b790e
--- /dev/null
+++ b/src/test/run-make/rustdoc-json/Makefile
@@ -0,0 +1,4 @@
+-include ../tools.mk
+all:
+	$(RUSTDOC) -w json -o $(TMPDIR)/doc.json foo.rs
+	$(RUSTDOC) -o $(TMPDIR)/doc $(TMPDIR)/doc.json
diff --git a/src/test/run-make/rustdoc-json/foo.rs b/src/test/run-make/rustdoc-json/foo.rs
new file mode 100644
index 00000000000..818ec1e5eb7
--- /dev/null
+++ b/src/test/run-make/rustdoc-json/foo.rs
@@ -0,0 +1,25 @@
+// Copyright 2014 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.
+
+#[crate_id = "foo#0.1"];
+
+//! Very docs
+
+pub mod bar {
+
+    /// So correct
+    pub mod baz {
+        /// Much detail
+        pub fn baz() { }
+    }
+
+    /// *wow*
+    pub trait Doge { }
+}