diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 302713a21db9e..32104e6f00d44 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -200,6 +200,11 @@ pub trait Emitter { true } + /// Checks if we can use colors in the current output stream. + fn supports_color(&self) -> bool { + false + } + fn source_map(&self) -> Option<&Lrc>; /// Formats the substitutions of the primary_span @@ -504,6 +509,10 @@ impl Emitter for EmitterWriter { fn should_show_explain(&self) -> bool { !self.short_message } + + fn supports_color(&self) -> bool { + self.dst.supports_color() + } } /// An emitter that does nothing when emitting a diagnostic. @@ -2057,6 +2066,14 @@ impl Destination { Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)), } } + + fn supports_color(&self) -> bool { + match *self { + Self::Terminal(ref stream) => stream.supports_color(), + Self::Buffered(ref buffer) => buffer.buffer().supports_color(), + Self::Raw(_, supports_color) => supports_color, + } + } } impl<'a> WritableDst<'a> { diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 0a4f88dedbb07..3427c83a18f2a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -23,6 +23,8 @@ extern "Rust" { // (the code expanding that attribute macro generates those functions), or to call // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. + // The rustc fork of LLVM also special-cases these function names to be able to optimize them + // like `malloc`, `realloc`, and `free`, respectively. #[rustc_allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index 8f0cd3be4066e..e9d595e65e2b2 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,4 +1,4 @@ -use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo}; +use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; // Test the Range structs and syntax. @@ -59,6 +59,12 @@ fn test_range_inclusive() { assert_eq!(r.next(), None); } +#[test] +fn test_range_to_inclusive() { + // Not much to test. + let _ = RangeToInclusive { end: 42 }; +} + #[test] fn test_range_is_empty() { assert!(!(0.0..10.0).is_empty()); @@ -151,3 +157,43 @@ fn test_range_syntax_in_return_statement() { } // Not much to test. } + +#[test] +fn range_structural_match() { + // test that all range types can be structurally matched upon + + const RANGE: Range = 0..1000; + match RANGE { + RANGE => {} + _ => unreachable!(), + } + + const RANGE_FROM: RangeFrom = 0..; + match RANGE_FROM { + RANGE_FROM => {} + _ => unreachable!(), + } + + const RANGE_FULL: RangeFull = ..; + match RANGE_FULL { + RANGE_FULL => {} + } + + const RANGE_INCLUSIVE: RangeInclusive = 0..=999; + match RANGE_INCLUSIVE { + RANGE_INCLUSIVE => {} + _ => unreachable!(), + } + + const RANGE_TO: RangeTo = ..1000; + match RANGE_TO { + RANGE_TO => {} + _ => unreachable!(), + } + + const RANGE_TO_INCLUSIVE: RangeToInclusive = ..=999; + match RANGE_TO_INCLUSIVE { + RANGE_TO_INCLUSIVE => {} + _ => unreachable!(), + } +} diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 5e40e6b151d30..4128ffd7a1af4 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,13 +1,13 @@ use rustc_ast as ast; use rustc_data_structures::sync::Lrc; -use rustc_errors::ErrorReported; +use rustc_errors::{ColorConfig, ErrorReported}; use rustc_hir as hir; use rustc_hir::intravisit; use rustc_hir::{HirId, CRATE_HIR_ID}; use rustc_interface::interface; use rustc_middle::hir::map::Map; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, CrateType}; +use rustc_session::config::{self, CrateType, ErrorOutputType}; use rustc_session::{lint, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::source_map::SourceMap; @@ -248,7 +248,8 @@ fn run_test( outdir: DirState, path: PathBuf, ) -> Result<(), TestFailure> { - let (test, line_offset) = make_test(test, Some(cratename), as_test_harness, opts, edition); + let (test, line_offset, supports_color) = + make_test(test, Some(cratename), as_test_harness, opts, edition); let output_file = outdir.path().join("rust_out"); @@ -293,6 +294,20 @@ fn run_test( path.to_str().expect("target path must be valid unicode").to_string() } }); + if let ErrorOutputType::HumanReadable(kind) = options.error_format { + let (_, color_config) = kind.unzip(); + match color_config { + ColorConfig::Never => { + compiler.arg("--color").arg("never"); + } + ColorConfig::Always => { + compiler.arg("--color").arg("always"); + } + ColorConfig::Auto => { + compiler.arg("--color").arg(if supports_color { "always" } else { "never" }); + } + } + } compiler.arg("-"); compiler.stdin(Stdio::piped()); @@ -320,7 +335,10 @@ fn run_test( (true, false) => {} (false, true) => { if !error_codes.is_empty() { - error_codes.retain(|err| !out.contains(&format!("error[{}]: ", err))); + // We used to check if the output contained "error[{}]: " but since we added the + // colored output, we can't anymore because of the color escape characters before + // the ":". + error_codes.retain(|err| !out.contains(&format!("error[{}]", err))); if !error_codes.is_empty() { return Err(TestFailure::MissingErrorCodes(error_codes)); @@ -362,18 +380,19 @@ fn run_test( } /// Transforms a test into code that can be compiled into a Rust binary, and returns the number of -/// lines before the test code begins. +/// lines before the test code begins as well as if the output stream supports colors or not. pub fn make_test( s: &str, cratename: Option<&str>, dont_insert_main: bool, opts: &TestOptions, edition: Edition, -) -> (String, usize) { +) -> (String, usize, bool) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); let mut line_offset = 0; let mut prog = String::new(); + let mut supports_color = false; if opts.attrs.is_empty() && !opts.display_warnings { // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some @@ -399,7 +418,7 @@ pub fn make_test( // crate already is included. let result = rustc_driver::catch_fatal_errors(|| { rustc_span::with_session_globals(edition, || { - use rustc_errors::emitter::EmitterWriter; + use rustc_errors::emitter::{Emitter, EmitterWriter}; use rustc_errors::Handler; use rustc_parse::maybe_new_parser_from_source_str; use rustc_session::parse::ParseSess; @@ -411,8 +430,13 @@ pub fn make_test( // Any errors in parsing should also appear when the doctest is compiled for real, so just // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + supports_color = + EmitterWriter::stderr(ColorConfig::Auto, None, false, false, Some(80), false) + .supports_color(); + let emitter = EmitterWriter::new(box io::sink(), None, false, false, false, None, false); + // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, sm); @@ -482,7 +506,7 @@ pub fn make_test( Err(ErrorReported) => { // If the parser panicked due to a fatal error, pass the test code through unchanged. // The error will be reported during compilation. - return (s.to_owned(), 0); + return (s.to_owned(), 0, false); } }; @@ -532,7 +556,7 @@ pub fn make_test( debug!("final doctest:\n{}", prog); - (prog, line_offset) + (prog, line_offset, supports_color) } // FIXME(aburka): use a real parser to deal with multiline attributes diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a96186a95e16b..a024e9c72a43e 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -11,8 +11,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -26,8 +26,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -44,8 +44,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); } #[test] @@ -61,8 +61,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -79,8 +79,8 @@ use std::*; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -98,8 +98,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -115,8 +115,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -134,8 +134,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); // Adding more will also bump the returned line offset. opts.attrs.push("feature(hella_dope)".to_string()); @@ -147,8 +147,8 @@ use asdf::qwop; assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 4)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 4)); } #[test] @@ -164,8 +164,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -180,8 +180,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -196,8 +196,8 @@ fn main() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); } #[test] @@ -210,8 +210,8 @@ assert_eq!(2+2, 4);"; //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);" .to_string(); - let output = make_test(input, None, true, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, true, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -224,8 +224,8 @@ fn make_test_display_warnings() { assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } #[test] @@ -242,8 +242,8 @@ assert_eq!(2+2, 4); }" .to_string(); - let output = make_test(input, None, false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 2)); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 2)); let input = "extern crate hella_qwop; assert_eq!(asdf::foo, 4);"; @@ -256,8 +256,8 @@ assert_eq!(asdf::foo, 4); }" .to_string(); - let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 3)); + let (output, len, _) = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 3)); } #[test] @@ -274,6 +274,6 @@ test_wrapper! { }" .to_string(); - let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); - assert_eq!(output, (expected, 1)); + let (output, len, _) = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); + assert_eq!((output, len), (expected, 1)); } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 4769edc50ff07..b5fe593dc0105 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -46,7 +46,9 @@ fn write_header(out: &mut String, class: Option<&str>) { } fn write_code(out: &mut String, src: &str) { - Classifier::new(src).highlight(&mut |highlight| { + // This replace allows to fix how the code source with DOS backline characters is displayed. + let src = src.replace("\r\n", "\n"); + Classifier::new(&src).highlight(&mut |highlight| { match highlight { Highlight::Token { text, class } => string(out, Escape(text), class), Highlight::EnterSpan { class } => enter_span(out, class), diff --git a/src/librustdoc/html/highlight/fixtures/dos_line.html b/src/librustdoc/html/highlight/fixtures/dos_line.html new file mode 100644 index 0000000000000..4400f85681d8a --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/dos_line.html @@ -0,0 +1,3 @@ +pub fn foo() { +println!("foo"); +} diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index c79471b1fae6b..f57f52d6f0875 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,17 +1,6 @@ use super::write_code; use expect_test::expect_file; -#[test] -fn test_html_highlighting() { - let src = include_str!("fixtures/sample.rs"); - let html = { - let mut out = String::new(); - write_code(&mut out, src); - format!("{}
{}
\n", STYLE, out) - }; - expect_file!["fixtures/sample.html"].assert_eq(&html); -} - const STYLE: &str = r#" "#; + +#[test] +fn test_html_highlighting() { + let src = include_str!("fixtures/sample.rs"); + let html = { + let mut out = String::new(); + write_code(&mut out, src); + format!("{}
{}
\n", STYLE, out) + }; + expect_file!["fixtures/sample.html"].assert_eq(&html); +} + +#[test] +fn test_dos_backline() { + let src = "pub fn foo() {\r\n\ + println!(\"foo\");\r\n\ +}\r\n"; + let mut html = String::new(); + write_code(&mut html, src); + expect_file!["fixtures/dos_line.html"].assert_eq(&html); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ca8b811681cc9..cec4e334395e0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -243,7 +243,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .collect::>>() .join("\n"); let krate = krate.as_ref().map(|s| &**s); - let (test, _) = doctest::make_test(&test, krate, false, &Default::default(), edition); + let (test, _, _) = + doctest::make_test(&test, krate, false, &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index eebb07f0476c0..fc0ce4b1f0979 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2251,6 +2251,22 @@ fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { tags } +fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option { + let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + debug!( + "Portability {:?} - {:?} = {:?}", + item.attrs.cfg, + parent.and_then(|p| p.attrs.cfg.as_ref()), + cfg + ); + + Some(format!("
{}
", cfg?.render_long_html())) +} + /// Render the stability and/or deprecation warning that is displayed at the top of the item's /// documentation. fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec { @@ -2328,19 +2344,8 @@ fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item stability.push(format!("
{}
", message)); } - let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { - (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), - (cfg, _) => cfg.as_deref().cloned(), - }; - - debug!( - "Portability {:?} - {:?} = {:?}", - item.attrs.cfg, - parent.and_then(|p| p.attrs.cfg.as_ref()), - cfg - ); - if let Some(cfg) = cfg { - stability.push(format!("
{}
", cfg.render_long_html())); + if let Some(portability) = portability(item, parent) { + stability.push(portability); } stability @@ -2431,6 +2436,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func fn render_implementor( cx: &Context, implementor: &Impl, + parent: &clean::Item, w: &mut Buffer, implementor_dups: &FxHashMap<&str, (DefId, bool)>, aliases: &[String], @@ -2450,7 +2456,7 @@ fn render_implementor( w, cx, implementor, - None, + parent, AssocItemLink::Anchor(None), RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), @@ -2480,7 +2486,7 @@ fn render_impls( &mut buffer, cx, i, - Some(containing_item), + containing_item, assoc_link, RenderMode::Normal, containing_item.stable_since().as_deref(), @@ -2727,7 +2733,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, cx, &implementor, - None, + it, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since().as_deref(), @@ -2749,7 +2755,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, "
", ); for implementor in concrete { - render_implementor(cx, implementor, w, &implementor_dups, &[], cache); + render_implementor(cx, implementor, it, w, &implementor_dups, &[], cache); } write_loading_content(w, "
"); @@ -2764,6 +2770,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, render_implementor( cx, implementor, + it, w, &implementor_dups, &collect_paths_for_type(implementor.inner_impl().for_.clone()), @@ -3430,7 +3437,7 @@ fn render_assoc_items( w, cx, i, - Some(containing_item), + containing_item, AssocItemLink::Anchor(None), render_mode, containing_item.stable_since().as_deref(), @@ -3622,7 +3629,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, i: &Impl, - parent: Option<&clean::Item>, + parent: &clean::Item, link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, @@ -3635,6 +3642,9 @@ fn render_impl( aliases: &[String], cache: &Cache, ) { + let traits = &cache.traits; + let trait_ = i.trait_did().map(|did| &traits[&did]); + if render_mode == RenderMode::Normal { let id = cx.derive_id(match i.inner_impl().trait_ { Some(ref t) => { @@ -3687,6 +3697,13 @@ fn render_impl( ); } write!(w, ""); + + if trait_.is_some() { + if let Some(portability) = portability(&i.impl_item, Some(parent)) { + write!(w, "
{}
", portability); + } + } + if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!( @@ -3709,7 +3726,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, item: &clean::Item, - parent: Option<&clean::Item>, + parent: &clean::Item, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, @@ -3794,7 +3811,7 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden, parent); + document_stability(w, cx, it, is_hidden, Some(parent)); if item.doc_value().is_some() { document_full(w, item, cx, "", is_hidden); } else if show_def_docs { @@ -3804,13 +3821,13 @@ fn render_impl( } } } else { - document_stability(w, cx, item, is_hidden, parent); + document_stability(w, cx, item, is_hidden, Some(parent)); if show_def_docs { document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden, parent); + document_stability(w, cx, item, is_hidden, Some(parent)); if show_def_docs { document_short(w, item, link, "", is_hidden); } @@ -3818,16 +3835,13 @@ fn render_impl( } } - let traits = &cache.traits; - let trait_ = i.trait_did().map(|did| &traits[&did]); - write!(w, "
"); for trait_item in &i.inner_impl().items { doc_impl_item( w, cx, trait_item, - parent, + if trait_.is_some() { &i.impl_item } else { parent }, link, render_mode, false, @@ -3843,7 +3857,7 @@ fn render_impl( cx: &Context, t: &clean::Trait, i: &clean::Impl, - parent: Option<&clean::Item>, + parent: &clean::Item, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, @@ -3884,7 +3898,7 @@ fn render_impl( cx, t, &i.inner_impl(), - parent, + &i.impl_item, render_mode, outer_version, show_def_docs, diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index cbf15cd0b6e4a..b8377dc15696d 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2439,12 +2439,13 @@ function defocusSearchBar() { var func = function(e) { var next = e.nextElementSibling; + if (next && hasClass(next, "stability")) { + next = next.nextElementSibling; + } if (!next) { return; } - if (hasClass(next, "docblock") === true || - (hasClass(next, "stability") === true && - hasClass(next.nextElementSibling, "docblock") === true)) { + if (hasClass(next, "docblock")) { var newToggle = toggle.cloneNode(true); insertAfter(newToggle, e.childNodes[e.childNodes.length - 1]); if (hideMethodDocs === true && hasClass(e, "method") === true) { @@ -2455,6 +2456,9 @@ function defocusSearchBar() { var funcImpl = function(e) { var next = e.nextElementSibling; + if (next && hasClass(next, "stability")) { + next = next.nextElementSibling; + } if (next && hasClass(next, "docblock")) { next = next.nextElementSibling; } diff --git a/src/test/rustdoc/doc-cfg-traits.rs b/src/test/rustdoc/doc-cfg-traits.rs new file mode 100644 index 0000000000000..13407b2c791fe --- /dev/null +++ b/src/test/rustdoc/doc-cfg-traits.rs @@ -0,0 +1,124 @@ +#![crate_name = "myrmecophagous"] +#![feature(doc_cfg, associated_type_defaults)] + +// @has 'myrmecophagous/index.html' +// @count - '//*[@class="stab portability"]' 2 +// @matches - '//*[@class="stab portability"]' '^jurisconsult$' +// @matches - '//*[@class="stab portability"]' '^quarter$' + +pub trait Lea {} + +// @has 'myrmecophagous/trait.Vortoscope.html' +// @count - '//*[@class="stab portability"]' 6 +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// @matches - '//*[@class="stab portability"]' 'crate feature lea' +// @matches - '//*[@class="stab portability"]' 'crate feature unit' +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +pub trait Vortoscope { + type Batology = (); + + #[doc(cfg(feature = "zibib"))] + type Zibib = (); + + const YAHRZEIT: () = (); + + #[doc(cfg(feature = "poriform"))] + const PORIFORM: () = (); + + fn javanais() {} + + #[doc(cfg(feature = "ethopoeia"))] + fn ethopoeia() {} +} + +#[doc(cfg(feature = "lea"))] +impl Vortoscope for T {} + +#[doc(cfg(feature = "unit"))] +impl Vortoscope for () {} + +// @has 'myrmecophagous/trait.Jurisconsult.html' +// @count - '//*[@class="stab portability"]' 7 +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// @matches - '//*[@class="stab portability"]' 'crate feature lea' +// @matches - '//*[@class="stab portability"]' 'crate feature unit' +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +#[doc(cfg(feature = "jurisconsult"))] +pub trait Jurisconsult { + type Urbanist = (); + + #[doc(cfg(feature = "lithomancy"))] + type Lithomancy = (); + + const UNIFILAR: () = (); + + #[doc(cfg(feature = "boodle"))] + const BOODLE: () = (); + + fn mersion() {} + + #[doc(cfg(feature = "mistetch"))] + fn mistetch() {} +} + +#[doc(cfg(feature = "lea"))] +impl Jurisconsult for T {} + +#[doc(cfg(feature = "unit"))] +impl Jurisconsult for () {} + +// @has 'myrmecophagous/struct.Ultimogeniture.html' +// @count - '//*[@class="stab portability"]' 8 +// +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// +// @matches - '//*[@class="stab portability"]' 'crate feature copy' +#[derive(Clone)] +pub struct Ultimogeniture; + +impl Vortoscope for Ultimogeniture {} + +#[doc(cfg(feature = "jurisconsult"))] +impl Jurisconsult for Ultimogeniture {} + +#[doc(cfg(feature = "copy"))] +impl Copy for Ultimogeniture {} + +// @has 'myrmecophagous/struct.Quarter.html' +// @count - '//*[@class="stab portability"]' 9 +// @matches - '//*[@class="stab portability"]' 'crate feature quarter' +// +// @matches - '//*[@class="stab portability"]' 'crate feature zibib' +// @matches - '//*[@class="stab portability"]' 'crate feature poriform' +// @matches - '//*[@class="stab portability"]' 'crate feature ethopoeia' +// +// @matches - '//*[@class="stab portability"]' 'crate feature jurisconsult' +// @matches - '//*[@class="stab portability"]' 'crate feature lithomancy' +// @matches - '//*[@class="stab portability"]' 'crate feature boodle' +// @matches - '//*[@class="stab portability"]' 'crate feature mistetch' +// +// @matches - '//*[@class="stab portability"]' 'crate feature copy' +#[doc(cfg(feature = "quarter"))] +#[derive(Clone)] +pub struct Quarter; + +#[doc(cfg(feature = "quarter"))] +impl Vortoscope for Quarter {} + +#[doc(cfg(all(feature = "jurisconsult", feature = "quarter")))] +impl Jurisconsult for Quarter {} + +#[doc(cfg(all(feature = "copy", feature = "quarter")))] +impl Copy for Quarter {}