Auto merge of #101037 - GuillaumeGomez:rollup-opn6kj1, r=GuillaumeGomez

Rollup of 8 pull requests

Successful merges:

 - #95005 (BTree: evaluate static type-related check at compile time)
 - #99742 (Add comments about stdout locking)
 - #100128 (Document that `RawWakerVTable` functions must be thread-safe.)
 - #100956 (Reduce right-side DOM size)
 - #101006 (Fix doc cfg on reexports)
 - #101012 (rustdoc: remove unused CSS for `.variants_table`)
 - #101023 (rustdoc: remove `type="text/css"` from stylesheet links)
 - #101031 (Remove unused build dependency)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2022-08-26 13:05:57 +00:00
commit 42fa8ac723
29 changed files with 363 additions and 103 deletions

View File

@ -1280,7 +1280,6 @@ name = "error_index_generator"
version = "0.0.0"
dependencies = [
"rustdoc",
"walkdir",
]
[[package]]

View File

@ -318,7 +318,7 @@ impl<BorrowType: marker::BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type>
pub fn ascend(
self,
) -> Result<Handle<NodeRef<BorrowType, K, V, marker::Internal>, marker::Edge>, Self> {
assert!(BorrowType::PERMITS_TRAVERSAL);
let _ = BorrowType::TRAVERSAL_PERMIT;
// We need to use raw pointers to nodes because, if BorrowType is marker::ValMut,
// there might be outstanding mutable references to values that we must not invalidate.
let leaf_ptr: *const _ = Self::as_leaf_ptr(&self);
@ -1003,7 +1003,7 @@ impl<BorrowType: marker::BorrowType, K, V>
/// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should
/// both, upon success, do nothing.
pub fn descend(self) -> NodeRef<BorrowType, K, V, marker::LeafOrInternal> {
assert!(BorrowType::PERMITS_TRAVERSAL);
let _ = BorrowType::TRAVERSAL_PERMIT;
// We need to use raw pointers to nodes because, if BorrowType is
// marker::ValMut, there might be outstanding mutable references to
// values that we must not invalidate. There's no worry accessing the
@ -1666,15 +1666,17 @@ pub mod marker {
pub struct ValMut<'a>(PhantomData<&'a mut ()>);
pub trait BorrowType {
// Whether node references of this borrow type allow traversing
// to other nodes in the tree.
const PERMITS_TRAVERSAL: bool = true;
// If node references of this borrow type allow traversing to other
// nodes in the tree, this constant can be evaluated. Thus reading it
// serves as a compile-time assertion.
const TRAVERSAL_PERMIT: () = ();
}
impl BorrowType for Owned {
// Traversal isn't needed, it happens using the result of `borrow_mut`.
// Reject evaluation, because traversal isn't needed. Instead traversal
// happens using the result of `borrow_mut`.
// By disabling traversal, and only creating new references to roots,
// we know that every reference of the `Owned` type is to a root node.
const PERMITS_TRAVERSAL: bool = false;
const TRAVERSAL_PERMIT: () = panic!();
}
impl BorrowType for Dying {}
impl<'a> BorrowType for Immut<'a> {}

View File

@ -71,6 +71,12 @@ impl RawWaker {
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// These functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>)
/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
/// arbitrary threads or invoked by `&` reference. For example, this means that if the
/// `clone` and `drop` functions manage a reference count, they must do so atomically.
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
@ -110,6 +116,12 @@ impl RawWakerVTable {
/// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
/// `wake_by_ref`, and `drop` functions.
///
/// These functions must all be thread-safe (even though [`RawWaker`] is
/// <code>\![Send] + \![Sync]</code>)
/// because [`Waker`] is <code>[Send] + [Sync]</code>, and thus wakers may be moved to
/// arbitrary threads or invoked by `&` reference. For example, this means that if the
/// `clone` and `drop` functions manage a reference count, they must do so atomically.
///
/// # `clone`
///
/// This function will be called when the [`RawWaker`] gets cloned, e.g. when
@ -157,9 +169,9 @@ impl RawWakerVTable {
}
}
/// The `Context` of an asynchronous task.
/// The context of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// Currently, `Context` only serves to provide access to a [`&Waker`](Waker)
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
@ -172,7 +184,7 @@ pub struct Context<'a> {
}
impl<'a> Context<'a> {
/// Create a new `Context` from a `&Waker`.
/// Create a new `Context` from a [`&Waker`](Waker).
#[stable(feature = "futures_api", since = "1.36.0")]
#[must_use]
#[inline]
@ -180,7 +192,7 @@ impl<'a> Context<'a> {
Context { waker, _marker: PhantomData }
}
/// Returns a reference to the `Waker` for the current task.
/// Returns a reference to the [`Waker`] for the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
#[must_use]
#[inline]
@ -202,7 +214,18 @@ impl fmt::Debug for Context<'_> {
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
/// The typical life of a `Waker` is that it is constructed by an executor, wrapped in a
/// [`Context`], then passed to [`Future::poll()`]. Then, if the future chooses to return
/// [`Poll::Pending`], it must also store the waker somehow and call [`Waker::wake()`] when
/// the future should be polled again.
///
/// Implements [`Clone`], [`Send`], and [`Sync`]; therefore, a waker may be invoked
/// from any thread, including ones not in any way managed by the executor. For example,
/// this might be done to wake a future when a blocking function call completes on another
/// thread.
///
/// [`Future::poll()`]: core::future::Future::poll
/// [`Poll::Pending`]: core::task::Poll::Pending
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
@ -219,18 +242,21 @@ unsafe impl Sync for Waker {}
impl Waker {
/// Wake up the task associated with this `Waker`.
///
/// As long as the runtime keeps running and the task is not finished, it is
/// guaranteed that each invocation of `wake` (or `wake_by_ref`) will be followed
/// by at least one `poll` of the task to which this `Waker` belongs. This makes
/// As long as the executor keeps running and the task is not finished, it is
/// guaranteed that each invocation of [`wake()`](Self::wake) (or
/// [`wake_by_ref()`](Self::wake_by_ref)) will be followed by at least one
/// [`poll()`] of the task to which this `Waker` belongs. This makes
/// it possible to temporarily yield to other tasks while running potentially
/// unbounded processing loops.
///
/// Note that the above implies that multiple wake-ups may be coalesced into a
/// single `poll` invocation by the runtime.
/// single [`poll()`] invocation by the runtime.
///
/// Also note that yielding to competing tasks is not guaranteed: it is the
/// executors choice which task to run and the executor may choose to run the
/// current task again.
///
/// [`poll()`]: crate::future::Future::poll
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn wake(self) {
@ -250,8 +276,8 @@ impl Waker {
/// Wake up the task associated with this `Waker` without consuming the `Waker`.
///
/// This is similar to `wake`, but may be slightly less efficient in the case
/// where an owned `Waker` is available. This method should be preferred to
/// This is similar to [`wake()`](Self::wake), but may be slightly less efficient in
/// the case where an owned `Waker` is available. This method should be preferred to
/// calling `waker.clone().wake()`.
#[inline]
#[stable(feature = "futures_api", since = "1.36.0")]
@ -263,7 +289,7 @@ impl Waker {
unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
}
/// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
/// Returns `true` if this `Waker` and another `Waker` would awake the same task.
///
/// This function works on a best-effort basis, and may return false even
/// when the `Waker`s would awaken the same task. However, if this function

View File

@ -27,12 +27,23 @@ macro_rules! panic {
/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted
/// immediately.
///
/// The `print!` macro will lock the standard output on each call. If you call
/// `print!` within a hot loop, this behavior may be the bottleneck of the loop.
/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]:
/// ```
/// use std::io::{stdout, Write};
///
/// let mut lock = stdout().lock();
/// write!(lock, "hello world").unwrap();
/// ```
///
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
/// [flush]: crate::io::Write::flush
/// [`println!`]: crate::println
/// [`eprint!`]: crate::eprint
/// [lock]: crate::io::Stdout
///
/// # Panics
///
@ -75,11 +86,22 @@ macro_rules! print {
/// This macro uses the same syntax as [`format!`], but writes to the standard output instead.
/// See [`std::fmt`] for more information.
///
/// The `println!` macro will lock the standard output on each call. If you call
/// `println!` within a hot loop, this behavior may be the bottleneck of the loop.
/// To avoid this, lock stdout with [`io::stdout().lock()`][lock]:
/// ```
/// use std::io::{stdout, Write};
///
/// let mut lock = stdout().lock();
/// writeln!(lock, "hello world").unwrap();
/// ```
///
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
/// [`std::fmt`]: crate::fmt
/// [`eprintln!`]: crate::eprintln
/// [lock]: crate::io::Stdout
///
/// # Panics
///

View File

@ -300,7 +300,7 @@ pub(crate) fn build_impls(
}
/// `parent_module` refers to the parent of the re-export, not the original item
fn merge_attrs(
pub(crate) fn merge_attrs(
cx: &mut DocContext<'_>,
parent_module: Option<DefId>,
old_attrs: Attrs<'_>,

View File

@ -482,7 +482,7 @@ impl Item {
cx: &mut DocContext<'_>,
cfg: Option<Arc<Cfg>>,
) -> Item {
trace!("name={:?}, def_id={:?}", name, def_id);
trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
// Primitives and Keywords are written in the source code as private modules.
// The modules need to be private so that nobody actually uses them, but the
@ -801,6 +801,31 @@ impl ItemKind {
| KeywordItem => [].iter(),
}
}
/// Returns `true` if this item does not appear inside an impl block.
pub(crate) fn is_non_assoc(&self) -> bool {
matches!(
self,
StructItem(_)
| UnionItem(_)
| EnumItem(_)
| TraitItem(_)
| ModuleItem(_)
| ExternCrateItem { .. }
| FunctionItem(_)
| TypedefItem(_)
| OpaqueTyItem(_)
| StaticItem(_)
| ConstantItem(_)
| TraitAliasItem(_)
| ForeignFunctionItem(_)
| ForeignStaticItem(_)
| ForeignTypeItem
| MacroItem(_)
| ProcMacroItem(_)
| PrimitiveItem(_)
)
}
}
#[derive(Clone, Debug)]

View File

@ -191,12 +191,6 @@ impl StylePath {
}
}
fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
if let Some(l) = cx.src_href(item) {
write!(buf, "<a class=\"srclink\" href=\"{}\">source</a>", l)
}
}
#[derive(Debug, Eq, PartialEq, Hash)]
struct ItemEntry {
url: String,
@ -522,7 +516,14 @@ fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<Strin
(cfg, _) => cfg.as_deref().cloned(),
};
debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
debug!(
"Portability {:?} {:?} (parent: {:?}) - {:?} = {:?}",
item.name,
item.cfg,
parent,
parent.and_then(|p| p.cfg.as_ref()),
cfg
);
Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
}
@ -840,12 +841,13 @@ fn assoc_method(
/// Note that it is possible for an unstable function to be const-stable. In that case, the span
/// will include the const-stable version, but no stable version will be emitted, as a natural
/// consequence of the above rules.
fn render_stability_since_raw(
fn render_stability_since_raw_with_extra(
w: &mut Buffer,
ver: Option<Symbol>,
const_stability: Option<ConstStability>,
containing_ver: Option<Symbol>,
containing_const_ver: Option<Symbol>,
extra_class: &str,
) -> bool {
let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
@ -893,12 +895,30 @@ fn render_stability_since_raw(
}
if !stability.is_empty() {
write!(w, r#"<span class="since" title="{}">{}</span>"#, title, stability);
write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
}
!stability.is_empty()
}
#[inline]
fn render_stability_since_raw(
w: &mut Buffer,
ver: Option<Symbol>,
const_stability: Option<ConstStability>,
containing_ver: Option<Symbol>,
containing_const_ver: Option<Symbol>,
) -> bool {
render_stability_since_raw_with_extra(
w,
ver,
const_stability,
containing_ver,
containing_const_ver,
"",
)
}
fn render_assoc_item(
w: &mut Buffer,
item: &clean::Item,
@ -1681,23 +1701,29 @@ fn render_rightside(
RenderMode::Normal => (item.const_stability(tcx), containing_item.const_stable_since(tcx)),
RenderMode::ForDeref { .. } => (None, None),
};
let src_href = cx.src_href(item);
let has_src_ref = src_href.is_some();
let mut rightside = Buffer::new();
let has_stability = render_stability_since_raw(
let has_stability = render_stability_since_raw_with_extra(
&mut rightside,
item.stable_since(tcx),
const_stability,
containing_item.stable_since(tcx),
const_stable_since,
if has_src_ref { "" } else { " rightside" },
);
let mut srclink = Buffer::empty_from(w);
write_srclink(cx, item, &mut srclink);
if has_stability && !srclink.is_empty() {
rightside.write_str(" · ");
if let Some(l) = src_href {
if has_stability {
write!(rightside, " · <a class=\"srclink\" href=\"{}\">source</a>", l)
} else {
write!(rightside, "<a class=\"srclink rightside\" href=\"{}\">source</a>", l)
}
}
rightside.push_buffer(srclink);
if !rightside.is_empty() {
if has_stability && has_src_ref {
write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
} else {
w.push_buffer(rightside);
}
}

View File

@ -18,7 +18,7 @@ use std::rc::Rc;
use super::{
collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
notable_traits_decl, render_assoc_item, render_assoc_items, render_attributes_in_code,
render_attributes_in_pre, render_impl, render_stability_since_raw, write_srclink,
render_attributes_in_pre, render_impl, render_rightside, render_stability_since_raw,
AssocItemLink, Context, ImplRenderingParameters,
};
use crate::clean;
@ -477,7 +477,7 @@ fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) ->
(cfg, _) => cfg.as_deref().cloned(),
};
debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.cfg, cfg);
debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
if let Some(ref cfg) = cfg {
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
}
@ -709,14 +709,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
}
write!(w, "<div id=\"{}\" class=\"method has-srclink\">", id);
write!(w, "<div class=\"rightside\">");
let has_stability = render_stability_since(w, m, t, cx.tcx());
if has_stability {
w.write_str(" · ");
}
write_srclink(cx, m, w);
write!(w, "</div>");
render_rightside(w, cx, m, t, RenderMode::Normal);
write!(w, "<h4 class=\"code-header\">");
render_assoc_item(
w,
@ -1260,7 +1253,13 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
w.write_str(")");
}
w.write_str("</code>");
render_stability_since(w, variant, it, cx.tcx());
render_stability_since_raw(
w,
variant.stable_since(cx.tcx()),
variant.const_stability(cx.tcx()),
it.stable_since(cx.tcx()),
it.const_stable_since(cx.tcx()),
);
w.write_str("</h3>");
use crate::clean::Variant;
@ -1591,21 +1590,6 @@ where
w.write_str("</code></pre>");
}
fn render_stability_since(
w: &mut Buffer,
item: &clean::Item,
containing_item: &clean::Item,
tcx: TyCtxt<'_>,
) -> bool {
render_stability_since_raw(
w,
item.stable_since(tcx),
item.const_stability(tcx),
containing_item.stable_since(tcx),
containing_item.const_stable_since(tcx),
)
}
fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
let lhss = format!("{}", lhs.inner_impl().print(false, cx));
let rhss = format!("{}", rhs.inner_impl().print(false, cx));

View File

@ -1200,14 +1200,6 @@ so that we can apply CSS-filters to change the arrow color in themes */
float: right;
}
.variants_table {
width: 100%;
}
.variants_table tbody tr td:first-child {
width: 1%; /* make the variant name as small as possible */
}
td.summary-column {
width: 100%;
}

View File

@ -199,7 +199,7 @@ details.rustdoc-toggle > summary::before {
background: none;
}
.rightside,
.rightside:not(a),
.out-of-band {
color: grey;
}

View File

@ -165,7 +165,7 @@ details.rustdoc-toggle > summary::before {
background: none;
}
.rightside,
.rightside:not(a),
.out-of-band {
color: grey;
}

View File

@ -148,7 +148,7 @@ details.rustdoc-toggle > summary::before {
.stab { background: #FFF5D6; border-color: #FFC600; }
.stab.portability > code { background: none; }
.rightside,
.rightside:not(a),
.out-of-band {
color: grey;
}

View File

@ -13,13 +13,13 @@
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
<link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
<link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
<link rel="stylesheet" type="text/css" {# -#}
<link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
id="mainThemeStyle"> {#- -#}
{%- for theme in themes -%}
<link rel="stylesheet" type="text/css" {# -#}
<link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
{%- if theme == "light" -%}
id="themeStyle"
@ -51,7 +51,7 @@
href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
</noscript> {#- -#}
{%- if layout.css_file_extension.is_some() -%}
<link rel="stylesheet" type="text/css" {# -#}
<link rel="stylesheet" {# -#}
href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
{%- endif -%}
{%- if !layout.favicon.is_empty() -%}

View File

@ -2,29 +2,53 @@
use std::sync::Arc;
use crate::clean::cfg::Cfg;
use crate::clean::inline::{load_attrs, merge_attrs};
use crate::clean::{Crate, Item};
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::passes::Pass;
use rustc_hir::def_id::LocalDefId;
pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
name: "propagate-doc-cfg",
run: propagate_doc_cfg,
description: "propagates `#[doc(cfg(...))]` to child items",
};
pub(crate) fn propagate_doc_cfg(cr: Crate, _: &mut DocContext<'_>) -> Crate {
CfgPropagator { parent_cfg: None }.fold_crate(cr)
pub(crate) fn propagate_doc_cfg(cr: Crate, cx: &mut DocContext<'_>) -> Crate {
CfgPropagator { parent_cfg: None, parent: None, cx }.fold_crate(cr)
}
struct CfgPropagator {
struct CfgPropagator<'a, 'tcx> {
parent_cfg: Option<Arc<Cfg>>,
parent: Option<LocalDefId>,
cx: &'a mut DocContext<'tcx>,
}
impl DocFolder for CfgPropagator {
impl<'a, 'tcx> DocFolder for CfgPropagator<'a, 'tcx> {
fn fold_item(&mut self, mut item: Item) -> Option<Item> {
let old_parent_cfg = self.parent_cfg.clone();
if item.kind.is_non_assoc() &&
let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
let hir = self.cx.tcx.hir();
let hir_id = hir.local_def_id_to_hir_id(def_id);
let expected_parent = hir.get_parent_item(hir_id);
// If parents are different, it means that `item` is a reexport and we need to compute
// the actual `cfg` by iterating through its "real" parents.
if self.parent != Some(expected_parent) {
let mut attrs = Vec::new();
for (parent_hir_id, _) in hir.parent_iter(hir_id) {
let def_id = hir.local_def_id(parent_hir_id).to_def_id();
attrs.extend_from_slice(load_attrs(self.cx, def_id));
}
let (_, cfg) =
merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
item.cfg = cfg;
}
}
let new_cfg = match (self.parent_cfg.take(), item.cfg.take()) {
(None, None) => None,
(Some(rc), None) | (None, Some(rc)) => Some(rc),
@ -37,8 +61,15 @@ impl DocFolder for CfgPropagator {
self.parent_cfg = new_cfg.clone();
item.cfg = new_cfg;
let old_parent =
if let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local()) {
self.parent.replace(def_id)
} else {
self.parent.take()
};
let result = self.fold_item_recur(item);
self.parent_cfg = old_parent_cfg;
self.parent = old_parent;
Some(result)
}

View File

@ -1,6 +1,5 @@
// This test is to ensure that the anchors (`§`) have the expected color and position.
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
show-text: true
goto: file://|DOC_PATH|/staged_api/struct.Foo.html
// This is needed to ensure that the text color is computed.
show-text: true
@ -13,10 +12,31 @@ reload:
assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"})
assert-css: (".srclink", {"color": "rgb(56, 115, 173)"})
assert-css: (
".rightside .srclink",
{"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
ALL,
)
compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
move-cursor-to: ".main-heading .srclink"
assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"})
assert-css: (
".main-heading .srclink",
{"color": "rgb(56, 115, 173)", "text-decoration": "underline solid rgb(56, 115, 173)"},
)
move-cursor-to: ".impl-items .rightside .srclink"
assert-css: (
".impl-items .rightside .srclink",
{"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
)
move-cursor-to: ".impl-items .rightside.srclink"
assert-css: (
".impl-items .rightside.srclink",
{"color": "rgb(56, 115, 173)", "text-decoration": "none solid rgb(56, 115, 173)"},
)
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
@ -32,3 +52,103 @@ move-cursor-to: "#impl-HeavilyDocumentedStruct"
assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(0, 0, 0)"})
assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
//
// We do the same checks with the dark theme now.
//
local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
goto: file://|DOC_PATH|/staged_api/struct.Foo.html
assert-css: ("#toggle-all-docs", {"color": "rgb(221, 221, 221)"})
assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(221, 221, 221)"})
assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(45, 191, 184)"})
assert-css: (
".rightside .srclink",
{"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
ALL,
)
compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
move-cursor-to: ".main-heading .srclink"
assert-css: (
".main-heading .srclink",
{"color": "rgb(210, 153, 29)", "text-decoration": "underline solid rgb(210, 153, 29)"},
)
move-cursor-to: ".impl-items .rightside .srclink"
assert-css: (
".impl-items .rightside .srclink",
{"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
)
move-cursor-to: ".impl-items .rightside.srclink"
assert-css: (
".impl-items .rightside.srclink",
{"color": "rgb(210, 153, 29)", "text-decoration": "none solid rgb(210, 153, 29)"},
)
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
assert-css: ("#top-doc-prose-title", {"color": "rgb(221, 221, 221)"})
assert-css: (".sidebar a", {"color": "rgb(253, 191, 53)"})
assert-css: (".in-band a", {"color": "rgb(221, 221, 221)"})
// We move the cursor over the "Implementations" title so the anchor is displayed.
move-cursor-to: "h2#implementations"
assert-css: ("h2#implementations a.anchor", {"color": "rgb(221, 221, 221)"})
// Same thing with the impl block title.
move-cursor-to: "#impl-HeavilyDocumentedStruct"
assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(221, 221, 221)"})
assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
//
// We do the same checks with the ayu theme now.
//
local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"}
goto: file://|DOC_PATH|/staged_api/struct.Foo.html
assert-css: ("#toggle-all-docs", {"color": "rgb(197, 197, 197)"})
assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(255, 255, 255)"})
assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(255, 160, 165)"})
assert-css: (
".rightside .srclink",
{"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
ALL,
)
compare-elements-css: (".rightside .srclink", ".rightside.srclink", ["color", "text-decoration"])
compare-elements-css: (".main-heading .srclink", ".rightside.srclink", ["color", "text-decoration"])
move-cursor-to: ".main-heading .srclink"
assert-css: (
".main-heading .srclink",
{"color": "rgb(57, 175, 215)", "text-decoration": "underline solid rgb(57, 175, 215)"},
)
move-cursor-to: ".impl-items .rightside .srclink"
assert-css: (
".impl-items .rightside .srclink",
{"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
)
move-cursor-to: ".impl-items .rightside.srclink"
assert-css: (
".impl-items .rightside.srclink",
{"color": "rgb(57, 175, 215)", "text-decoration": "none solid rgb(57, 175, 215)"},
)
goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
assert-css: ("#top-doc-prose-title", {"color": "rgb(255, 255, 255)"})
assert-css: (".sidebar a", {"color": "rgb(83, 177, 219)"})
assert-css: (".in-band a", {"color": "rgb(255, 255, 255)"})
// We move the cursor over the "Implementations" title so the anchor is displayed.
move-cursor-to: "h2#implementations"
assert-css: ("h2#implementations a.anchor", {"color": "rgb(197, 197, 197)"})
// Same thing with the impl block title.
move-cursor-to: "#impl-HeavilyDocumentedStruct"
assert-css: ("#impl-HeavilyDocumentedStruct a.anchor", {"color": "rgb(197, 197, 197)"})
assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})

View File

@ -247,12 +247,12 @@ assert-css: (
local-storage: {"rustdoc-theme": "light"}
goto: file://|DOC_PATH|/staged_api/struct.Foo.html
assert-css: (".since", {"color": "rgb(128, 128, 128)"})
assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
local-storage: {"rustdoc-theme": "dark"}
reload:
assert-css: (".since", {"color": "rgb(128, 128, 128)"})
assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)
local-storage: {"rustdoc-theme": "ayu"}
reload:
assert-css: (".since", {"color": "rgb(128, 128, 128)"})
assert-css: (".since", {"color": "rgb(128, 128, 128)"}, ALL)

View File

@ -7,5 +7,6 @@ edition = "2021"
path = "lib.rs"
[features]
default = ["some_feature"]
default = ["some_feature", "some_other_feature"]
some_feature = []
some_other_feature = []

View File

@ -7,4 +7,6 @@ pub struct Foo {}
impl Foo {
#[stable(feature = "some_feature", since = "1.3.5")]
pub fn bar() {}
#[stable(feature = "some_other_feature", since = "1.3.6")]
pub fn yo() {}
}

View File

@ -1 +1 @@
<div id="associatedconstant.YOLO" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#16">source</a></div><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div>
<div id="associatedconstant.YOLO" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#16">source</a><h4 class="code-header">const <a href="#associatedconstant.YOLO" class="constant">YOLO</a>: <a class="primitive" href="{{channel}}/std/primitive.u32.html">u32</a></h4></div>

View File

@ -1 +1 @@
<section id="associatedconstant.X" class="associatedconstant has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#42">source</a></span><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>
<section id="associatedconstant.X" class="associatedconstant has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#42">source</a><h4 class="code-header">pub const <a href="#associatedconstant.X" class="constant">X</a>: <a class="primitive" href="{{channel}}/std/primitive.i32.html">i32</a> = 0i32</h4></section>

View File

@ -1 +1 @@
<section id="method.new" class="method has-srclink"><span class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#48">source</a></span><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -&gt; Self</h4></section>
<section id="method.new" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#48">source</a><h4 class="code-header">pub fn <a href="#method.new" class="fnname">new</a>() -&gt; Self</h4></section>

View File

@ -1 +1 @@
<div id="method.bar" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#23">source</a></div><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div>
<div id="method.bar" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#23">source</a><h4 class="code-header">fn <a href="#method.bar" class="fnname">bar</a>()</h4></div>

View File

@ -1 +1 @@
<div id="tymethod.foo" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#20">source</a></div><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div>
<div id="tymethod.foo" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#20">source</a><h4 class="code-header">fn <a href="#tymethod.foo" class="fnname">foo</a>()</h4></div>

View File

@ -1 +1 @@
<div id="associatedtype.T" class="method has-srclink"><div class="rightside"><a class="srclink" href="../src/foo/anchors.rs.html#13">source</a></div><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div>
<div id="associatedtype.T" class="method has-srclink"><a class="srclink rightside" href="../src/foo/anchors.rs.html#13">source</a><h4 class="code-header">type <a href="#associatedtype.T" class="associatedtype">T</a></h4></div>

View File

@ -0,0 +1,33 @@
#![feature(doc_cfg)]
#![feature(no_core)]
#![crate_name = "foo"]
#![no_core]
// @has 'foo/index.html'
// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar'
// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar'
#[doc(cfg(feature = "foobar"))]
mod imp_priv {
// @has 'foo/struct.BarPriv.html'
// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'Available on crate feature foobar only.'
pub struct BarPriv {}
impl BarPriv {
pub fn test() {}
}
}
#[doc(cfg(feature = "foobar"))]
pub use crate::imp_priv::*;
pub mod bar {
// @has 'foo/bar/struct.Bar.html'
// @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
// 'Available on crate feature bar only.'
#[doc(cfg(feature = "bar"))]
pub struct Bar;
}
#[doc(cfg(feature = "bar"))]
pub use bar::Bar;

View File

@ -2,5 +2,5 @@
// This test ensures that the [src] link is present on traits items.
// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink"]' "source"
// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink rightside"]' "source"
pub use std::iter::Iterator;

View File

@ -6,7 +6,7 @@
// @has - '//*[@id="impl-Sync-for-Unsized"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
// @!has - '//*[@id="impl-Sync-for-Unsized"]//a[@class="srclink"]' 'source'
// @has - '//*[@id="impl-Any-for-Unsized"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink"]' 'source'
// @has - '//*[@id="impl-Any-for-Unsized"]//a[@class="srclink rightside"]' 'source'
pub struct Unsized {
data: [u8],
}

View File

@ -16,7 +16,7 @@ pub fn foo() {}
pub struct Bar;
impl Bar {
// @has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0'
// @has - '//*[@id="method.bar"]/*[@class="since rightside"]' '2.0'
// @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
#[stable(feature = "foobar", since = "2.0")]
pub fn bar() {}

View File

@ -6,9 +6,6 @@ edition = "2021"
[dependencies]
rustdoc = { path = "../../librustdoc" }
[build-dependencies]
walkdir = "2"
[[bin]]
name = "error_index_generator"
path = "main.rs"