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.
This commit is contained in:
parent
c9b03c24ec
commit
4e25765aa2
@ -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)
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -64,6 +64,7 @@ impl ItemType {
|
||||
clean::MacroItem(..) => ItemType::Macro,
|
||||
clean::PrimitiveItem(..) => ItemType::Primitive,
|
||||
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
|
||||
clean::DefaultImplItem(..) => ItemType::Impl,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(..) => {}
|
||||
|
@ -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);
|
||||
}
|
||||
|
5
src/test/run-make/rustdoc-default-impl/Makefile
Normal file
5
src/test/run-make/rustdoc-default-impl/Makefile
Normal file
@ -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)
|
17
src/test/run-make/rustdoc-default-impl/bar.rs
Normal file
17
src/test/run-make/rustdoc-default-impl/bar.rs
Normal file
@ -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>() {
|
||||
}
|
||||
|
33
src/test/run-make/rustdoc-default-impl/foo.rs
Normal file
33
src/test/run-make/rustdoc-default-impl/foo.rs
Normal file
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user