about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-03-12 19:15:52 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-03-12 21:01:49 -0700
commit4e25765aa2b973a4dda1f61dd8b5f167752e74ef (patch)
tree6dae72860b4b9a61240a4e9e9814a905c2398c4e
parentc9b03c24ec346e6405883032094f47805ef9c43e (diff)
downloadrust-4e25765aa2b973a4dda1f61dd8b5f167752e74ef.tar.gz
rust-4e25765aa2b973a4dda1f61dd8b5f167752e74ef.zip
rustdoc: Fix ICE with cross-crate default impls
This adds a special code path for impls which are listed as default impls to
ensure that they're loaded correctly.
-rw-r--r--src/librustc/metadata/csearch.rs5
-rw-r--r--src/librustc/metadata/decoder.rs7
-rw-r--r--src/librustdoc/clean/inline.rs41
-rw-r--r--src/librustdoc/clean/mod.rs27
-rw-r--r--src/librustdoc/doctree.rs2
-rw-r--r--src/librustdoc/html/item_type.rs1
-rw-r--r--src/librustdoc/passes.rs2
-rw-r--r--src/librustdoc/visit_ast.rs4
-rw-r--r--src/test/run-make/rustdoc-default-impl/Makefile5
-rw-r--r--src/test/run-make/rustdoc-default-impl/bar.rs17
-rw-r--r--src/test/run-make/rustdoc-default-impl/foo.rs33
11 files changed, 130 insertions, 14 deletions
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index ed5783c8dba..ca8ae83ab80 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -411,3 +411,8 @@ pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: ast::DefId) ->
     let cdata = cstore.get_crate_data(trait_def_id.krate);
     decoder::is_defaulted_trait(&*cdata, trait_def_id.node)
 }
+
+pub fn is_default_impl(cstore: &cstore::CStore, impl_did: ast::DefId) -> bool {
+    let cdata = cstore.get_crate_data(impl_did.krate);
+    decoder::is_default_impl(&*cdata, impl_did.node)
+}
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index dbbc17c018a..c0bad80ab59 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -1537,13 +1537,18 @@ pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool {
     }
 }
 
-pub fn is_defaulted_trait<'tcx>(cdata: Cmd, trait_id: ast::NodeId) -> bool {
+pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
     let trait_doc = lookup_item(trait_id, cdata.data());
     assert!(item_family(trait_doc) == Family::Trait);
     let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
     reader::doc_as_u8(defaulted_doc) != 0
 }
 
+pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool {
+    let impl_doc = lookup_item(impl_id, cdata.data());
+    item_family(impl_doc) == Family::DefaultImpl
+}
+
 pub fn get_imported_filemaps(metadata: &[u8]) -> Vec<codemap::FileMap> {
     let crate_doc = rbml::Doc::new(metadata);
     let cm_doc = reader::get_doc(crate_doc, tag_codemap);
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9f7b68f38fa..aa17bf20d74 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -259,26 +259,43 @@ fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
     impls.into_iter().filter_map(|a| a).collect()
 }
 
-fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
+fn build_impl(cx: &DocContext,
+              tcx: &ty::ctxt,
               did: ast::DefId) -> Option<clean::Item> {
     if !cx.inlined.borrow_mut().as_mut().unwrap().insert(did) {
         return None
     }
 
+    let attrs = load_attrs(cx, tcx, did);
     let associated_trait = csearch::get_impl_trait(tcx, did);
-    // If this is an impl for a #[doc(hidden)] trait, be sure to not inline it.
-    match associated_trait {
-        Some(ref t) => {
-            let trait_attrs = load_attrs(cx, tcx, t.def_id);
-            if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
-                return None
-            }
+    if let Some(ref t) = associated_trait {
+        // If this is an impl for a #[doc(hidden)] trait, be sure to not inline
+        let trait_attrs = load_attrs(cx, tcx, t.def_id);
+        if trait_attrs.iter().any(|a| is_doc_hidden(a)) {
+            return None
         }
-        None => {}
     }
 
-    let attrs = load_attrs(cx, tcx, did);
-    let ty = ty::lookup_item_type(tcx, did);
+    // If this is a defaulted impl, then bail out early here
+    if csearch::is_default_impl(&tcx.sess.cstore, did) {
+        return Some(clean::Item {
+            inner: clean::DefaultImplItem(clean::DefaultImpl {
+                // FIXME: this should be decoded
+                unsafety: ast::Unsafety::Normal,
+                trait_: match associated_trait.as_ref().unwrap().clean(cx) {
+                    clean::TraitBound(polyt, _) => polyt.trait_,
+                    clean::RegionBound(..) => unreachable!(),
+                },
+            }),
+            source: clean::Span::empty(),
+            name: None,
+            attrs: attrs,
+            visibility: Some(ast::Inherited),
+            stability: stability::lookup(tcx, did).clean(cx),
+            def_id: did,
+        });
+    }
+
     let predicates = ty::lookup_predicates(tcx, did);
     let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did)
             .iter()
@@ -330,8 +347,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
         }
     }).collect();
     let polarity = csearch::get_impl_polarity(tcx, did);
+    let ty = ty::lookup_item_type(tcx, did);
     return Some(clean::Item {
         inner: clean::ImplItem(clean::Impl {
+            unsafety: ast::Unsafety::Normal, // FIXME: this should be decoded
             derived: clean::detect_derived(&attrs),
             trait_: associated_trait.clean(cx).map(|bound| {
                 match bound {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e91e95961c5..421549f8b7e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -337,6 +337,7 @@ pub enum ItemEnum {
     MacroItem(Macro),
     PrimitiveItem(PrimitiveType),
     AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
+    DefaultImplItem(DefaultImpl),
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -367,6 +368,7 @@ impl Clean<Item> for doctree::Module {
         items.extend(self.traits.iter().map(|x| x.clean(cx)));
         items.extend(self.impls.iter().map(|x| x.clean(cx)));
         items.extend(self.macros.iter().map(|x| x.clean(cx)));
+        items.extend(self.def_traits.iter().map(|x| x.clean(cx)));
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
@@ -2079,6 +2081,7 @@ impl Clean<ImplPolarity> for ast::ImplPolarity {
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct Impl {
+    pub unsafety: ast::Unsafety,
     pub generics: Generics,
     pub trait_: Option<Type>,
     pub for_: Type,
@@ -2101,6 +2104,7 @@ impl Clean<Item> for doctree::Impl {
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             inner: ImplItem(Impl {
+                unsafety: self.unsafety,
                 generics: self.generics.clean(cx),
                 trait_: self.trait_.clean(cx),
                 for_: self.for_.clean(cx),
@@ -2112,6 +2116,29 @@ impl Clean<Item> for doctree::Impl {
     }
 }
 
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
+pub struct DefaultImpl {
+    pub unsafety: ast::Unsafety,
+    pub trait_: Type,
+}
+
+impl Clean<Item> for doctree::DefaultImpl {
+    fn clean(&self, cx: &DocContext) -> Item {
+        Item {
+            name: None,
+            attrs: self.attrs.clean(cx),
+            source: self.whence.clean(cx),
+            def_id: ast_util::local_def(self.id),
+            visibility: Some(ast::Public),
+            stability: None,
+            inner: DefaultImplItem(DefaultImpl {
+                unsafety: self.unsafety,
+                trait_: self.trait_.clean(cx),
+            }),
+        }
+    }
+}
+
 impl Clean<Item> for doctree::ExternCrate {
     fn clean(&self, cx: &DocContext) -> Item {
         Item {
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index 5a4deaa2e72..c6d8b9428c5 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -202,6 +202,8 @@ pub struct DefaultImpl {
     pub unsafety: ast::Unsafety,
     pub trait_: ast::TraitRef,
     pub id: ast::NodeId,
+    pub attrs: Vec<ast::Attribute>,
+    pub whence: Span,
 }
 
 pub struct Macro {
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index 356be2ffeb0..1d63f01be52 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -64,6 +64,7 @@ impl ItemType {
             clean::MacroItem(..)           => ItemType::Macro,
             clean::PrimitiveItem(..)       => ItemType::Primitive,
             clean::AssociatedTypeItem(..)  => ItemType::AssociatedType,
+            clean::DefaultImplItem(..)     => ItemType::Impl,
         }
     }
 
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 722f14fa6d4..953b442bb3c 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -176,7 +176,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
                     return None;
                 }
             }
-            clean::ImplItem(..) => {}
+            clean::DefaultImplItem(..) | clean::ImplItem(..) => {}
 
             // tymethods/macros have no control over privacy
             clean::MacroItem(..) | clean::TyMethodItem(..) => {}
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 3e998166397..d53954b29b5 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -362,7 +362,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 let i = DefaultImpl {
                     unsafety: unsafety,
                     trait_: trait_ref.clone(),
-                    id: item.id
+                    id: item.id,
+                    attrs: item.attrs.clone(),
+                    whence: item.span,
                 };
                 om.def_traits.push(i);
             }
diff --git a/src/test/run-make/rustdoc-default-impl/Makefile b/src/test/run-make/rustdoc-default-impl/Makefile
new file mode 100644
index 00000000000..338cf9d2053
--- /dev/null
+++ b/src/test/run-make/rustdoc-default-impl/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+all: foo.rs bar.rs
+	$(RUSTC) foo.rs --crate-type lib
+	$(HOST_RPATH_ENV) $(RUSTDOC) -w html -o $(TMPDIR)/doc bar.rs -L $(TMPDIR)
diff --git a/src/test/run-make/rustdoc-default-impl/bar.rs b/src/test/run-make/rustdoc-default-impl/bar.rs
new file mode 100644
index 00000000000..c9fae80d858
--- /dev/null
+++ b/src/test/run-make/rustdoc-default-impl/bar.rs
@@ -0,0 +1,17 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
+
+pub use foo::bar;
+
+pub fn wut<T: bar::Bar>() {
+}
+
diff --git a/src/test/run-make/rustdoc-default-impl/foo.rs b/src/test/run-make/rustdoc-default-impl/foo.rs
new file mode 100644
index 00000000000..08f3bd10e74
--- /dev/null
+++ b/src/test/run-make/rustdoc-default-impl/foo.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod bar {
+    use std::marker;
+
+    pub trait Bar: marker::MarkerTrait + 'static {}
+
+    impl Bar for .. {}
+
+    pub trait Foo {
+        fn foo(&self) {}
+    }
+
+    impl Foo {
+        pub fn test<T: Bar>(&self) {}
+    }
+
+    pub struct TypeId;
+
+    impl TypeId {
+        pub fn of<T: Bar + ?Sized>() -> TypeId {
+            panic!()
+        }
+    }
+}