mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #136943 - GuillaumeGomez:rollup-amtd3mq, r=GuillaumeGomez
Rollup of 10 pull requests Successful merges: - #136758 (tests: `-Copt-level=3` instead of `-O` in assembly tests) - #136761 (tests: `-Copt-level=3` instead of `-O` in codegen tests) - #136784 (Nuke `Buffer` abstraction from `librustdoc`, take 2 💣) - #136838 (Check whole `Unsize` predicate for escaping bound vars) - #136848 (add docs and ut for bootstrap util cache) - #136871 (dev-guide: Link to `t-lang` procedures for new features) - #136890 (Change swap_nonoverlapping from lang to library UB) - #136901 (compiler: give `ExternAbi` truly stable `Hash` and `Ord`) - #136907 (compiler: Make middle errors `pub(crate)` and bury the dead code) - #136916 (use cc archiver as default in `cc2ar`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
+1
-2
@@ -3409,7 +3409,6 @@ dependencies = [
|
||||
"rustc_parse",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
@@ -4423,6 +4422,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"parking_lot",
|
||||
"rustc-rayon-core",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
@@ -4434,7 +4434,6 @@ dependencies = [
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use ExternAbi as Abi;
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
|
||||
#[derive(HashStable_Generic, Encodable, Decodable)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
|
||||
pub enum ExternAbi {
|
||||
// Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
|
||||
// hashing tests. These are used in many places, so giving them stable values reduces test
|
||||
@@ -68,7 +73,124 @@ pub enum ExternAbi {
|
||||
RiscvInterruptS,
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
macro_rules! abi_impls {
|
||||
($e_name:ident = {
|
||||
$($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
|
||||
}) => {
|
||||
impl $e_name {
|
||||
pub const ALL_VARIANTS: &[Self] = &[
|
||||
$($e_name::$variant $({ unwind: $uw })*,)*
|
||||
];
|
||||
pub const fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
$($e_name::$variant $( { unwind: $uw } )* => $tok,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::core::str::FromStr for $e_name {
|
||||
type Err = AbiFromStrErr;
|
||||
fn from_str(s: &str) -> Result<$e_name, Self::Err> {
|
||||
match s {
|
||||
$($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
|
||||
_ => Err(AbiFromStrErr::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AbiFromStrErr {
|
||||
Unknown,
|
||||
}
|
||||
|
||||
abi_impls! {
|
||||
ExternAbi = {
|
||||
C { unwind: false } =><= "C",
|
||||
CCmseNonSecureCall =><= "C-cmse-nonsecure-call",
|
||||
CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry",
|
||||
C { unwind: true } =><= "C-unwind",
|
||||
Rust =><= "Rust",
|
||||
Aapcs { unwind: false } =><= "aapcs",
|
||||
Aapcs { unwind: true } =><= "aapcs-unwind",
|
||||
AvrInterrupt =><= "avr-interrupt",
|
||||
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
|
||||
Cdecl { unwind: false } =><= "cdecl",
|
||||
Cdecl { unwind: true } =><= "cdecl-unwind",
|
||||
EfiApi =><= "efiapi",
|
||||
Fastcall { unwind: false } =><= "fastcall",
|
||||
Fastcall { unwind: true } =><= "fastcall-unwind",
|
||||
GpuKernel =><= "gpu-kernel",
|
||||
Msp430Interrupt =><= "msp430-interrupt",
|
||||
PtxKernel =><= "ptx-kernel",
|
||||
RiscvInterruptM =><= "riscv-interrupt-m",
|
||||
RiscvInterruptS =><= "riscv-interrupt-s",
|
||||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustIntrinsic =><= "rust-intrinsic",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
System { unwind: true } =><= "system-unwind",
|
||||
SysV64 { unwind: false } =><= "sysv64",
|
||||
SysV64 { unwind: true } =><= "sysv64-unwind",
|
||||
Thiscall { unwind: false } =><= "thiscall",
|
||||
Thiscall { unwind: true } =><= "thiscall-unwind",
|
||||
Unadjusted =><= "unadjusted",
|
||||
Vectorcall { unwind: false } =><= "vectorcall",
|
||||
Vectorcall { unwind: true } =><= "vectorcall-unwind",
|
||||
Win64 { unwind: false } =><= "win64",
|
||||
Win64 { unwind: true } =><= "win64-unwind",
|
||||
X86Interrupt =><= "x86-interrupt",
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for ExternAbi {
|
||||
fn cmp(&self, rhs: &Self) -> Ordering {
|
||||
self.as_str().cmp(rhs.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for ExternAbi {
|
||||
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(rhs))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ExternAbi {
|
||||
fn eq(&self, rhs: &Self) -> bool {
|
||||
self.cmp(rhs) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ExternAbi {}
|
||||
|
||||
impl Hash for ExternAbi {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state);
|
||||
// double-assurance of a prefix breaker
|
||||
u32::from_be_bytes(*b"ABI\0").hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl<C> HashStable<C> for ExternAbi {
|
||||
#[inline]
|
||||
fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
|
||||
Hash::hash(self, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
impl StableOrd for ExternAbi {
|
||||
const CAN_USE_UNSTABLE_SORT: bool = true;
|
||||
|
||||
// because each ABI is hashed like a string, there is no possible instability
|
||||
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
|
||||
}
|
||||
|
||||
impl ExternAbi {
|
||||
pub fn supports_varargs(self) -> bool {
|
||||
// * C and Cdecl obviously support varargs.
|
||||
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
|
||||
@@ -92,144 +214,21 @@ pub fn supports_varargs(self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AbiData {
|
||||
pub abi: Abi,
|
||||
|
||||
/// Name of this ABI as we like it called.
|
||||
pub name: &'static str,
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const AbiDatas: &[AbiData] = &[
|
||||
AbiData { abi: Abi::Rust, name: "Rust" },
|
||||
AbiData { abi: Abi::C { unwind: false }, name: "C" },
|
||||
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
|
||||
AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
|
||||
AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
|
||||
AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
|
||||
AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
|
||||
AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
|
||||
AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
|
||||
AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
|
||||
AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
|
||||
AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
|
||||
AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
|
||||
AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
|
||||
AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
|
||||
AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
|
||||
AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
|
||||
AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
|
||||
AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
|
||||
AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
|
||||
AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
|
||||
AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
|
||||
AbiData { abi: Abi::GpuKernel, name: "gpu-kernel" },
|
||||
AbiData { abi: Abi::EfiApi, name: "efiapi" },
|
||||
AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
|
||||
AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
|
||||
AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
|
||||
AbiData { abi: Abi::CCmseNonSecureEntry, name: "C-cmse-nonsecure-entry" },
|
||||
AbiData { abi: Abi::System { unwind: false }, name: "system" },
|
||||
AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
|
||||
AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
|
||||
AbiData { abi: Abi::RustCall, name: "rust-call" },
|
||||
AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
|
||||
AbiData { abi: Abi::RustCold, name: "rust-cold" },
|
||||
AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" },
|
||||
AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" },
|
||||
];
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct AbiUnsupported {}
|
||||
/// Returns the ABI with the given name (if any).
|
||||
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
|
||||
AbiDatas
|
||||
.iter()
|
||||
.find(|abi_data| name == abi_data.name)
|
||||
.map(|&x| x.abi)
|
||||
.ok_or_else(|| AbiUnsupported {})
|
||||
}
|
||||
|
||||
pub fn all_names() -> Vec<&'static str> {
|
||||
AbiDatas.iter().map(|d| d.name).collect()
|
||||
ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
|
||||
}
|
||||
|
||||
impl Abi {
|
||||
impl ExternAbi {
|
||||
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
|
||||
pub const FALLBACK: Abi = Abi::C { unwind: false };
|
||||
|
||||
#[inline]
|
||||
pub fn index(self) -> usize {
|
||||
// N.B., this ordering MUST match the AbiDatas array above.
|
||||
// (This is ensured by the test indices_are_correct().)
|
||||
use Abi::*;
|
||||
let i = match self {
|
||||
// Cross-platform ABIs
|
||||
Rust => 0,
|
||||
C { unwind: false } => 1,
|
||||
C { unwind: true } => 2,
|
||||
// Platform-specific ABIs
|
||||
Cdecl { unwind: false } => 3,
|
||||
Cdecl { unwind: true } => 4,
|
||||
Stdcall { unwind: false } => 5,
|
||||
Stdcall { unwind: true } => 6,
|
||||
Fastcall { unwind: false } => 7,
|
||||
Fastcall { unwind: true } => 8,
|
||||
Vectorcall { unwind: false } => 9,
|
||||
Vectorcall { unwind: true } => 10,
|
||||
Thiscall { unwind: false } => 11,
|
||||
Thiscall { unwind: true } => 12,
|
||||
Aapcs { unwind: false } => 13,
|
||||
Aapcs { unwind: true } => 14,
|
||||
Win64 { unwind: false } => 15,
|
||||
Win64 { unwind: true } => 16,
|
||||
SysV64 { unwind: false } => 17,
|
||||
SysV64 { unwind: true } => 18,
|
||||
PtxKernel => 19,
|
||||
Msp430Interrupt => 20,
|
||||
X86Interrupt => 21,
|
||||
GpuKernel => 22,
|
||||
EfiApi => 23,
|
||||
AvrInterrupt => 24,
|
||||
AvrNonBlockingInterrupt => 25,
|
||||
CCmseNonSecureCall => 26,
|
||||
CCmseNonSecureEntry => 27,
|
||||
// Cross-platform ABIs
|
||||
System { unwind: false } => 28,
|
||||
System { unwind: true } => 29,
|
||||
RustIntrinsic => 30,
|
||||
RustCall => 31,
|
||||
Unadjusted => 32,
|
||||
RustCold => 33,
|
||||
RiscvInterruptM => 34,
|
||||
RiscvInterruptS => 35,
|
||||
};
|
||||
debug_assert!(
|
||||
AbiDatas
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, AbiData { abi, .. })| *abi == self)
|
||||
.map(|(index, _)| index)
|
||||
.expect("abi variant has associated data")
|
||||
== i,
|
||||
"Abi index did not match `AbiDatas` ordering"
|
||||
);
|
||||
i
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn data(self) -> &'static AbiData {
|
||||
&AbiDatas[self.index()]
|
||||
}
|
||||
|
||||
pub fn name(self) -> &'static str {
|
||||
self.data().name
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Abi {
|
||||
impl fmt::Display for ExternAbi {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "\"{}\"", self.name())
|
||||
write!(f, "\"{}\"", self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[test]
|
||||
fn lookup_Rust() {
|
||||
let abi = lookup("Rust");
|
||||
assert!(abi.is_ok() && abi.unwrap().data().name == "Rust");
|
||||
let abi = ExternAbi::from_str("Rust");
|
||||
assert!(abi.is_ok() && abi.unwrap().as_str() == "Rust");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_cdecl() {
|
||||
let abi = lookup("cdecl");
|
||||
assert!(abi.is_ok() && abi.unwrap().data().name == "cdecl");
|
||||
let abi = ExternAbi::from_str("cdecl");
|
||||
assert!(abi.is_ok() && abi.unwrap().as_str() == "cdecl");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lookup_baz() {
|
||||
let abi = lookup("baz");
|
||||
assert_matches!(abi, Err(AbiUnsupported {}));
|
||||
let abi = ExternAbi::from_str("baz");
|
||||
assert_matches!(abi, Err(AbiFromStrErr::Unknown));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn indices_are_correct() {
|
||||
for (i, abi_data) in AbiDatas.iter().enumerate() {
|
||||
assert_eq!(i, abi_data.abi.index());
|
||||
}
|
||||
fn guarantee_lexicographic_ordering() {
|
||||
let abis = ExternAbi::ALL_VARIANTS;
|
||||
let mut sorted_abis = abis.to_vec();
|
||||
sorted_abis.sort_unstable();
|
||||
assert_eq!(abis, sorted_abis);
|
||||
}
|
||||
|
||||
@@ -52,21 +52,17 @@
|
||||
use rustc_data_structures::stable_hasher::StableOrd;
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::HashStable_Generic;
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_Generic, Encodable_Generic};
|
||||
use rustc_macros::{Decodable_Generic, Encodable_Generic, HashStable_Generic};
|
||||
|
||||
mod callconv;
|
||||
mod layout;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
mod extern_abi;
|
||||
|
||||
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use extern_abi::{AbiDatas, AbiUnsupported, ExternAbi, all_names, lookup};
|
||||
pub use extern_abi::{ExternAbi, all_names};
|
||||
#[cfg(feature = "nightly")]
|
||||
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
|
||||
pub use layout::{LayoutCalculator, LayoutCalculatorError};
|
||||
|
||||
@@ -1475,7 +1475,7 @@ pub(super) fn lower_fn_header(
|
||||
|
||||
pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi {
|
||||
let ast::StrLit { symbol_unescaped, span, .. } = abi_str;
|
||||
let extern_abi = rustc_abi::lookup(symbol_unescaped.as_str()).unwrap_or_else(|_| {
|
||||
let extern_abi = symbol_unescaped.as_str().parse().unwrap_or_else(|_| {
|
||||
self.error_on_invalid_abi(abi_str);
|
||||
ExternAbi::Rust
|
||||
});
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
|
||||
rustc_abi::AbiDatas
|
||||
.iter()
|
||||
.filter(|data| extern_abi_enabled(features, span, data.abi).is_ok())
|
||||
.map(|d| d.name)
|
||||
ExternAbi::ALL_VARIANTS
|
||||
.into_iter()
|
||||
.filter(|abi| extern_abi_enabled(features, span, **abi).is_ok())
|
||||
.map(|abi| abi.as_str())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -54,17 +54,12 @@ enum GateReason {
|
||||
impl fmt::Display for UnstableAbi {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { abi, .. } = self;
|
||||
let name = abi.to_string();
|
||||
let name = name.trim_matches('"');
|
||||
match self.explain {
|
||||
GateReason::Experimental => {
|
||||
write!(f, r#"the extern "{name}" ABI is experimental and subject to change"#)
|
||||
write!(f, "the extern {abi} ABI is experimental and subject to change")
|
||||
}
|
||||
GateReason::ImplDetail => {
|
||||
write!(
|
||||
f,
|
||||
r#"the extern "{name}" ABI is an implementation detail and perma-unstable"#
|
||||
)
|
||||
write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,5 @@ rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_parse = { path = "../rustc_parse" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
||||
@@ -747,8 +747,7 @@ fn print_crate_info(
|
||||
}
|
||||
}
|
||||
CallingConventions => {
|
||||
let mut calling_conventions = rustc_abi::all_names();
|
||||
calling_conventions.sort_unstable();
|
||||
let calling_conventions = rustc_abi::all_names();
|
||||
println_info!("{}", calling_conventions.join("\n"));
|
||||
}
|
||||
RelocationModels
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
/// instead of implementing everything in `rustc_middle`.
|
||||
pub trait HashStableContext:
|
||||
rustc_ast::HashStableContext + rustc_target::HashStableContext
|
||||
{
|
||||
pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {
|
||||
fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
middle_adjust_for_foreign_abi_error =
|
||||
target architecture {$arch} does not support `extern {$abi}` ABI
|
||||
|
||||
middle_assert_async_resume_after_panic = `async fn` resumed after panicking
|
||||
|
||||
middle_assert_async_resume_after_return = `async fn` resumed after completion
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_drop_check_overflow, code = E0320)]
|
||||
#[note]
|
||||
pub struct DropCheckOverflow<'tcx> {
|
||||
pub(crate) struct DropCheckOverflow<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
@@ -20,14 +20,14 @@ pub struct DropCheckOverflow<'tcx> {
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_failed_writing_file)]
|
||||
pub struct FailedWritingFile<'a> {
|
||||
pub(crate) struct FailedWritingFile<'a> {
|
||||
pub path: &'a Path,
|
||||
pub error: io::Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_opaque_hidden_type_mismatch)]
|
||||
pub struct OpaqueHiddenTypeMismatch<'tcx> {
|
||||
pub(crate) struct OpaqueHiddenTypeMismatch<'tcx> {
|
||||
pub self_ty: Ty<'tcx>,
|
||||
pub other_ty: Ty<'tcx>,
|
||||
#[primary_span]
|
||||
@@ -37,12 +37,14 @@ pub struct OpaqueHiddenTypeMismatch<'tcx> {
|
||||
pub sub: TypeMismatchReason,
|
||||
}
|
||||
|
||||
// FIXME(autodiff): I should get used somewhere
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_unsupported_union)]
|
||||
pub struct UnsupportedUnion {
|
||||
pub ty_name: String,
|
||||
}
|
||||
|
||||
// FIXME(autodiff): I should get used somewhere
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_autodiff_unsafe_inner_const_ref)]
|
||||
pub struct AutodiffUnsafeInnerConstRef {
|
||||
@@ -67,7 +69,7 @@ pub enum TypeMismatchReason {
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_limit_invalid)]
|
||||
pub struct LimitInvalid<'a> {
|
||||
pub(crate) struct LimitInvalid<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
@@ -78,14 +80,14 @@ pub struct LimitInvalid<'a> {
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_recursion_limit_reached)]
|
||||
#[help]
|
||||
pub struct RecursionLimitReached<'tcx> {
|
||||
pub(crate) struct RecursionLimitReached<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub suggested_limit: rustc_session::Limit,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_const_eval_non_int)]
|
||||
pub struct ConstEvalNonIntError {
|
||||
pub(crate) struct ConstEvalNonIntError {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
@@ -159,27 +161,17 @@ pub enum LayoutError<'tcx> {
|
||||
ReferencesError,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_adjust_for_foreign_abi_error)]
|
||||
pub struct UnsupportedFnAbi {
|
||||
pub arch: Symbol,
|
||||
pub abi: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_erroneous_constant)]
|
||||
pub struct ErroneousConstant {
|
||||
pub(crate) struct ErroneousConstant {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
/// Used by `rustc_const_eval`
|
||||
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(middle_type_length_limit)]
|
||||
#[help(middle_consider_type_length_limit)]
|
||||
pub struct TypeLengthLimit {
|
||||
pub(crate) struct TypeLengthLimit {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub shrunk: String,
|
||||
|
||||
@@ -7,6 +7,7 @@ edition = "2021"
|
||||
# tidy-alphabetical-start
|
||||
parking_lot = "0.12"
|
||||
rustc-rayon-core = { version = "0.5.0" }
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
@@ -18,7 +19,6 @@ rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
rustc_target = { path = "../rustc_target" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
thin-vec = "0.2.12"
|
||||
tracing = "0.1"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
use crate::ich::StableHashingContext;
|
||||
|
||||
impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
|
||||
impl<'ctx> rustc_abi::HashStableContext for StableHashingContext<'ctx> {}
|
||||
impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {}
|
||||
|
||||
impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
|
||||
|
||||
@@ -480,7 +480,7 @@ fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> {
|
||||
ExternAbi::C { unwind: false } => cx.push("KC"),
|
||||
abi => {
|
||||
cx.push("K");
|
||||
let name = abi.name();
|
||||
let name = abi.as_str();
|
||||
if name.contains('-') {
|
||||
cx.push_ident(&name.replace('-', "_"));
|
||||
} else {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use rustc_abi::HashStableContext;
|
||||
use rustc_abi::HashStableContext;
|
||||
|
||||
/// The name of rustc's own place to organize libraries.
|
||||
///
|
||||
|
||||
@@ -920,11 +920,12 @@ fn assemble_candidates_for_unsizing(
|
||||
// T: Trait
|
||||
// so it seems ok if we (conservatively) fail to accept that `Unsize`
|
||||
// obligation above. Should be possible to extend this in the future.
|
||||
let Some(source) = obligation.self_ty().no_bound_vars() else {
|
||||
let Some(trait_pred) = obligation.predicate.no_bound_vars() else {
|
||||
// Don't add any candidates if there are bound regions.
|
||||
return;
|
||||
};
|
||||
let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
|
||||
let source = trait_pred.self_ty();
|
||||
let target = trait_pred.trait_ref.args.type_at(1);
|
||||
|
||||
debug!(?source, ?target, "assemble_candidates_for_unsizing");
|
||||
|
||||
|
||||
@@ -1070,7 +1070,7 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
||||
#[rustc_diagnostic_item = "ptr_swap_nonoverlapping"]
|
||||
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
ub_checks::assert_unsafe_precondition!(
|
||||
check_language_ub,
|
||||
check_library_ub,
|
||||
"ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
|
||||
and the specified memory ranges do not overlap",
|
||||
(
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
//! This module helps you efficiently store and retrieve values using interning.
|
||||
//!
|
||||
//! Interning is a neat trick that keeps only one copy of identical values, saving memory
|
||||
//! and making comparisons super fast. Here, we provide the `Interned<T>` struct and the `Internable` trait
|
||||
//! to make interning easy for different data types.
|
||||
//!
|
||||
//! The `Interner` struct handles caching for common types like `String`, `PathBuf`, and `Vec<String>`,
|
||||
//! while the `Cache` struct acts as a write-once storage for linking computation steps with their results.
|
||||
//!
|
||||
//! # Thread Safety
|
||||
//!
|
||||
//! We use `Mutex` to make sure interning and retrieval are thread-safe. But keep in mind—once a value is
|
||||
//! interned, it sticks around for the entire lifetime of the program.
|
||||
|
||||
use std::any::{Any, TypeId};
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
@@ -12,6 +26,9 @@
|
||||
|
||||
use crate::core::builder::Step;
|
||||
|
||||
/// Represents an interned value of type `T`, allowing for efficient comparisons and retrieval.
|
||||
///
|
||||
/// This struct stores a unique index referencing the interned value within an internal cache.
|
||||
pub struct Interned<T>(usize, PhantomData<*const T>);
|
||||
|
||||
impl<T: Internable + Default> Default for Interned<T> {
|
||||
@@ -111,6 +128,10 @@ fn cmp(&self, other: &Self) -> Ordering {
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure for managing the interning of values of type `T`.
|
||||
///
|
||||
/// `TyIntern<T>` maintains a mapping between values and their interned representations,
|
||||
/// ensuring that duplicate values are not stored multiple times.
|
||||
struct TyIntern<T: Clone + Eq> {
|
||||
items: Vec<T>,
|
||||
set: HashMap<T, Interned<T>>,
|
||||
@@ -123,6 +144,9 @@ fn default() -> Self {
|
||||
}
|
||||
|
||||
impl<T: Hash + Clone + Eq> TyIntern<T> {
|
||||
/// Interns a borrowed value, ensuring it is stored uniquely.
|
||||
///
|
||||
/// If the value has been previously interned, the same `Interned<T>` instance is returned.
|
||||
fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
|
||||
where
|
||||
B: Eq + Hash + ToOwned<Owned = T> + ?Sized,
|
||||
@@ -138,6 +162,9 @@ fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
|
||||
interned
|
||||
}
|
||||
|
||||
/// Interns an owned value, storing it uniquely.
|
||||
///
|
||||
/// If the value has been previously interned, the existing `Interned<T>` is returned.
|
||||
fn intern(&mut self, item: T) -> Interned<T> {
|
||||
if let Some(i) = self.set.get(&item) {
|
||||
return *i;
|
||||
@@ -148,11 +175,16 @@ fn intern(&mut self, item: T) -> Interned<T> {
|
||||
interned
|
||||
}
|
||||
|
||||
/// Retrieves a reference to the interned value associated with the given `Interned<T>` instance.
|
||||
fn get(&self, i: Interned<T>) -> &T {
|
||||
&self.items[i.0]
|
||||
}
|
||||
}
|
||||
|
||||
/// A global interner for managing interned values of common types.
|
||||
///
|
||||
/// This structure maintains caches for `String`, `PathBuf`, and `Vec<String>`, ensuring efficient storage
|
||||
/// and retrieval of frequently used values.
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
strs: Mutex<TyIntern<String>>,
|
||||
@@ -160,6 +192,10 @@ pub struct Interner {
|
||||
lists: Mutex<TyIntern<Vec<String>>>,
|
||||
}
|
||||
|
||||
/// Defines the behavior required for a type to be internable.
|
||||
///
|
||||
/// Types implementing this trait must provide access to a static cache and define an `intern` method
|
||||
/// that ensures values are stored uniquely.
|
||||
trait Internable: Clone + Eq + Hash + 'static {
|
||||
fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
|
||||
|
||||
@@ -187,11 +223,15 @@ fn intern_cache() -> &'static Mutex<TyIntern<Self>> {
|
||||
}
|
||||
|
||||
impl Interner {
|
||||
/// Interns a string reference, ensuring it is stored uniquely.
|
||||
///
|
||||
/// If the string has been previously interned, the same `Interned<String>` instance is returned.
|
||||
pub fn intern_str(&self, s: &str) -> Interned<String> {
|
||||
self.strs.lock().unwrap().intern_borrow(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// A global instance of `Interner` that caches common interned values.
|
||||
pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
|
||||
|
||||
/// This is essentially a `HashMap` which allows storing any type in its input and
|
||||
@@ -209,10 +249,12 @@ pub struct Cache(
|
||||
);
|
||||
|
||||
impl Cache {
|
||||
/// Creates a new empty cache.
|
||||
pub fn new() -> Cache {
|
||||
Cache(RefCell::new(HashMap::new()))
|
||||
}
|
||||
|
||||
/// Stores the result of a computation step in the cache.
|
||||
pub fn put<S: Step>(&self, step: S, value: S::Output) {
|
||||
let mut cache = self.0.borrow_mut();
|
||||
let type_id = TypeId::of::<S>();
|
||||
@@ -225,6 +267,7 @@ pub fn put<S: Step>(&self, step: S, value: S::Output) {
|
||||
stepcache.insert(step, value);
|
||||
}
|
||||
|
||||
/// Retrieves a cached result for the given step, if available.
|
||||
pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
|
||||
let mut cache = self.0.borrow_mut();
|
||||
let type_id = TypeId::of::<S>();
|
||||
@@ -255,3 +298,6 @@ pub fn contains<S: Step>(&self) -> bool {
|
||||
self.0.borrow().contains_key(&TypeId::of::<S>())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::utils::cache::{INTERNER, Internable, TyIntern};
|
||||
|
||||
#[test]
|
||||
fn test_string_interning() {
|
||||
let s1 = INTERNER.intern_str("Hello");
|
||||
let s2 = INTERNER.intern_str("Hello");
|
||||
let s3 = INTERNER.intern_str("world");
|
||||
|
||||
assert_eq!(s1, s2, "Same strings should be interned to the same instance");
|
||||
assert_ne!(s1, s3, "Different strings should have different interned values");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_interning() {
|
||||
let p1 = PathBuf::from("/tmp/file").intern();
|
||||
let p2 = PathBuf::from("/tmp/file").intern();
|
||||
let p3 = PathBuf::from("/tmp/other").intern();
|
||||
|
||||
assert_eq!(p1, p2);
|
||||
assert_ne!(p1, p3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec_interning() {
|
||||
let v1 = vec!["a".to_string(), "b".to_string()].intern();
|
||||
let v2 = vec!["a".to_string(), "b".to_string()].intern();
|
||||
let v3 = vec!["c".to_string()].intern();
|
||||
|
||||
assert_eq!(v1, v2);
|
||||
assert_ne!(v1, v3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_interned_equality() {
|
||||
let s1 = INTERNER.intern_str("test");
|
||||
let s2 = INTERNER.intern_str("test");
|
||||
|
||||
assert_eq!(s1, s2);
|
||||
assert_eq!(s1, "test");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ty_intern_intern_borrow() {
|
||||
let mut interner = TyIntern::default();
|
||||
let s1 = interner.intern_borrow("borrowed");
|
||||
let s2 = interner.intern("borrowed".to_string());
|
||||
|
||||
assert_eq!(s1, s2);
|
||||
assert_eq!(interner.get(s1), "borrowed");
|
||||
}
|
||||
@@ -29,11 +29,8 @@
|
||||
use crate::utils::exec::{BootstrapCommand, command};
|
||||
use crate::{Build, CLang, GitRepo};
|
||||
|
||||
// The `cc` crate doesn't provide a way to obtain a path to the detected archiver,
|
||||
// so use some simplified logic here. First we respect the environment variable `AR`, then
|
||||
// try to infer the archiver path from the C compiler path.
|
||||
// In the future this logic should be replaced by calling into the `cc` crate.
|
||||
fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
|
||||
/// FIXME(onur-ozkan): This logic should be replaced by calling into the `cc` crate.
|
||||
fn cc2ar(cc: &Path, target: TargetSelection, default_ar: PathBuf) -> Option<PathBuf> {
|
||||
if let Some(ar) = env::var_os(format!("AR_{}", target.triple.replace('-', "_"))) {
|
||||
Some(PathBuf::from(ar))
|
||||
} else if let Some(ar) = env::var_os("AR") {
|
||||
@@ -57,16 +54,7 @@ fn cc2ar(cc: &Path, target: TargetSelection) -> Option<PathBuf> {
|
||||
} else if target.contains("android") || target.contains("-wasi") {
|
||||
Some(cc.parent().unwrap().join(PathBuf::from("llvm-ar")))
|
||||
} else {
|
||||
let parent = cc.parent().unwrap();
|
||||
let file = cc.file_name().unwrap().to_str().unwrap();
|
||||
for suffix in &["gcc", "cc", "clang"] {
|
||||
if let Some(idx) = file.rfind(suffix) {
|
||||
let mut file = file[..idx].to_owned();
|
||||
file.push_str("ar");
|
||||
return Some(parent.join(&file));
|
||||
}
|
||||
}
|
||||
Some(parent.join(file))
|
||||
Some(default_ar)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +126,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
|
||||
let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) {
|
||||
ar
|
||||
} else {
|
||||
cc2ar(compiler.path(), target)
|
||||
cc2ar(compiler.path(), target, PathBuf::from(cfg.get_archiver().get_program()))
|
||||
};
|
||||
|
||||
build.cc.borrow_mut().insert(target, compiler.clone());
|
||||
|
||||
@@ -9,7 +9,11 @@ smoothly.
|
||||
**NOTE: this section is for *language* features, not *library* features,
|
||||
which use [a different process].**
|
||||
|
||||
See also [the Rust Language Design Team's procedures][lang-propose] for
|
||||
proposing changes to the language.
|
||||
|
||||
[a different process]: ./stability.md
|
||||
[lang-propose]: https://lang-team.rust-lang.org/how_to/propose.html
|
||||
|
||||
## The @rfcbot FCP process
|
||||
|
||||
|
||||
@@ -37,113 +37,8 @@
|
||||
use crate::joined::Joined as _;
|
||||
use crate::passes::collect_intra_doc_links::UrlFragment;
|
||||
|
||||
pub(crate) trait Print {
|
||||
fn print(self, buffer: &mut Buffer);
|
||||
}
|
||||
|
||||
impl<F> Print for F
|
||||
where
|
||||
F: FnOnce(&mut Buffer),
|
||||
{
|
||||
fn print(self, buffer: &mut Buffer) {
|
||||
(self)(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
impl Print for String {
|
||||
fn print(self, buffer: &mut Buffer) {
|
||||
buffer.write_str(&self);
|
||||
}
|
||||
}
|
||||
|
||||
impl Print for &'_ str {
|
||||
fn print(self, buffer: &mut Buffer) {
|
||||
buffer.write_str(self);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Buffer {
|
||||
for_html: bool,
|
||||
buffer: String,
|
||||
}
|
||||
|
||||
impl core::fmt::Write for Buffer {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||
self.buffer.write_str(s)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
self.buffer.write_char(c)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
|
||||
self.buffer.write_fmt(args)
|
||||
}
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub(crate) fn empty_from(v: &Buffer) -> Buffer {
|
||||
Buffer { for_html: v.for_html, buffer: String::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn html() -> Buffer {
|
||||
Buffer { for_html: true, buffer: String::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn new() -> Buffer {
|
||||
Buffer { for_html: false, buffer: String::new() }
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.buffer.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> String {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
pub(crate) fn push(&mut self, c: char) {
|
||||
self.buffer.push(c);
|
||||
}
|
||||
|
||||
pub(crate) fn push_str(&mut self, s: &str) {
|
||||
self.buffer.push_str(s);
|
||||
}
|
||||
|
||||
pub(crate) fn push_buffer(&mut self, other: Buffer) {
|
||||
self.buffer.push_str(&other.buffer);
|
||||
}
|
||||
|
||||
// Intended for consumption by write! and writeln! (std::fmt) but without
|
||||
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
|
||||
// import).
|
||||
pub(crate) fn write_str(&mut self, s: &str) {
|
||||
self.buffer.push_str(s);
|
||||
}
|
||||
|
||||
// Intended for consumption by write! and writeln! (std::fmt) but without
|
||||
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
|
||||
// import).
|
||||
pub(crate) fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
|
||||
self.buffer.write_fmt(v).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn to_display<T: Print>(mut self, t: T) -> String {
|
||||
t.print(&mut self);
|
||||
self.into_inner()
|
||||
}
|
||||
|
||||
pub(crate) fn reserve(&mut self, additional: usize) {
|
||||
self.buffer.reserve(additional)
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.buffer.len()
|
||||
}
|
||||
pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) {
|
||||
s.write_fmt(f).unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>(
|
||||
@@ -772,7 +667,7 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
|
||||
else {
|
||||
return String::new();
|
||||
};
|
||||
let mut buf = Buffer::new();
|
||||
let mut buf = String::new();
|
||||
let fqp = if *shortty == ItemType::Primitive {
|
||||
// primitives are documented in a crate, but not actually part of it
|
||||
&fqp[fqp.len() - 1..]
|
||||
@@ -780,19 +675,19 @@ pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Cont
|
||||
fqp
|
||||
};
|
||||
if let &Some(UrlFragment::Item(id)) = fragment {
|
||||
write!(buf, "{} ", cx.tcx().def_descr(id));
|
||||
write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id)));
|
||||
for component in fqp {
|
||||
write!(buf, "{component}::");
|
||||
write_str(&mut buf, format_args!("{component}::"));
|
||||
}
|
||||
write!(buf, "{}", cx.tcx().item_name(id));
|
||||
write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id)));
|
||||
} else if !fqp.is_empty() {
|
||||
let mut fqp_it = fqp.iter();
|
||||
write!(buf, "{shortty} {}", fqp_it.next().unwrap());
|
||||
write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap()));
|
||||
for component in fqp_it {
|
||||
write!(buf, "::{component}");
|
||||
write_str(&mut buf, format_args!("::{component}"));
|
||||
}
|
||||
}
|
||||
buf.into_inner()
|
||||
buf
|
||||
}
|
||||
|
||||
/// Used to render a [`clean::Path`].
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::{BytePos, DUMMY_SP, Span};
|
||||
|
||||
use super::format::{self, Buffer};
|
||||
use super::format::{self, write_str};
|
||||
use crate::clean::PrimitiveType;
|
||||
use crate::html::escape::EscapeBodyText;
|
||||
use crate::html::render::{Context, LinkFromSrc};
|
||||
@@ -48,7 +48,7 @@ pub(crate) enum Tooltip {
|
||||
/// Highlights `src` as an inline example, returning the HTML output.
|
||||
pub(crate) fn render_example_with_highlighting(
|
||||
src: &str,
|
||||
out: &mut Buffer,
|
||||
out: &mut String,
|
||||
tooltip: Tooltip,
|
||||
playground_button: Option<&str>,
|
||||
extra_classes: &[String],
|
||||
@@ -59,61 +59,69 @@ pub(crate) fn render_example_with_highlighting(
|
||||
}
|
||||
|
||||
fn write_header(
|
||||
out: &mut Buffer,
|
||||
out: &mut String,
|
||||
class: &str,
|
||||
extra_content: Option<Buffer>,
|
||||
extra_content: Option<&str>,
|
||||
tooltip: Tooltip,
|
||||
extra_classes: &[String],
|
||||
) {
|
||||
write!(
|
||||
write_str(
|
||||
out,
|
||||
"<div class=\"example-wrap{}\">",
|
||||
match tooltip {
|
||||
Tooltip::Ignore => " ignore",
|
||||
Tooltip::CompileFail => " compile_fail",
|
||||
Tooltip::ShouldPanic => " should_panic",
|
||||
Tooltip::Edition(_) => " edition",
|
||||
Tooltip::None => "",
|
||||
},
|
||||
format_args!(
|
||||
"<div class=\"example-wrap{}\">",
|
||||
match tooltip {
|
||||
Tooltip::Ignore => " ignore",
|
||||
Tooltip::CompileFail => " compile_fail",
|
||||
Tooltip::ShouldPanic => " should_panic",
|
||||
Tooltip::Edition(_) => " edition",
|
||||
Tooltip::None => "",
|
||||
}
|
||||
),
|
||||
);
|
||||
|
||||
if tooltip != Tooltip::None {
|
||||
let edition_code;
|
||||
write!(
|
||||
write_str(
|
||||
out,
|
||||
"<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
|
||||
match tooltip {
|
||||
Tooltip::Ignore => "This example is not tested",
|
||||
Tooltip::CompileFail => "This example deliberately fails to compile",
|
||||
Tooltip::ShouldPanic => "This example panics",
|
||||
Tooltip::Edition(edition) => {
|
||||
edition_code = format!("This example runs with edition {edition}");
|
||||
&edition_code
|
||||
format_args!(
|
||||
"<a href=\"#\" class=\"tooltip\" title=\"{}\">ⓘ</a>",
|
||||
match tooltip {
|
||||
Tooltip::Ignore => "This example is not tested",
|
||||
Tooltip::CompileFail => "This example deliberately fails to compile",
|
||||
Tooltip::ShouldPanic => "This example panics",
|
||||
Tooltip::Edition(edition) => {
|
||||
edition_code = format!("This example runs with edition {edition}");
|
||||
&edition_code
|
||||
}
|
||||
Tooltip::None => unreachable!(),
|
||||
}
|
||||
Tooltip::None => unreachable!(),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(extra) = extra_content {
|
||||
out.push_buffer(extra);
|
||||
out.push_str(&extra);
|
||||
}
|
||||
if class.is_empty() {
|
||||
write!(
|
||||
write_str(
|
||||
out,
|
||||
"<pre class=\"rust{}{}\">",
|
||||
if extra_classes.is_empty() { "" } else { " " },
|
||||
extra_classes.join(" "),
|
||||
format_args!(
|
||||
"<pre class=\"rust{}{}\">",
|
||||
if extra_classes.is_empty() { "" } else { " " },
|
||||
extra_classes.join(" ")
|
||||
),
|
||||
);
|
||||
} else {
|
||||
write!(
|
||||
write_str(
|
||||
out,
|
||||
"<pre class=\"rust {class}{}{}\">",
|
||||
if extra_classes.is_empty() { "" } else { " " },
|
||||
extra_classes.join(" "),
|
||||
format_args!(
|
||||
"<pre class=\"rust {class}{}{}\">",
|
||||
if extra_classes.is_empty() { "" } else { " " },
|
||||
extra_classes.join(" ")
|
||||
),
|
||||
);
|
||||
}
|
||||
write!(out, "<code>");
|
||||
write_str(out, format_args!("<code>"));
|
||||
}
|
||||
|
||||
/// Check if two `Class` can be merged together. In the following rules, "unclassified" means `None`
|
||||
@@ -398,8 +406,8 @@ pub(super) fn write_code(
|
||||
});
|
||||
}
|
||||
|
||||
fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
|
||||
writeln!(out, "</code></pre>{}</div>", playground_button.unwrap_or_default());
|
||||
fn write_footer(out: &mut String, playground_button: Option<&str>) {
|
||||
write_str(out, format_args_nl!("</code></pre>{}</div>", playground_button.unwrap_or_default()));
|
||||
}
|
||||
|
||||
/// How a span of text is classified. Mostly corresponds to token kinds.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
|
||||
use super::{DecorationInfo, write_code};
|
||||
use crate::html::format::Buffer;
|
||||
|
||||
const STYLE: &str = r#"
|
||||
<style>
|
||||
@@ -22,9 +21,9 @@ fn test_html_highlighting() {
|
||||
create_default_session_globals_then(|| {
|
||||
let src = include_str!("fixtures/sample.rs");
|
||||
let html = {
|
||||
let mut out = Buffer::new();
|
||||
let mut out = String::new();
|
||||
write_code(&mut out, src, None, None, None);
|
||||
format!("{STYLE}<pre><code>{}</code></pre>\n", out.into_inner())
|
||||
format!("{STYLE}<pre><code>{out}</code></pre>\n")
|
||||
};
|
||||
expect_file!["fixtures/sample.html"].assert_eq(&html);
|
||||
});
|
||||
@@ -36,9 +35,9 @@ fn test_dos_backline() {
|
||||
let src = "pub fn foo() {\r\n\
|
||||
println!(\"foo\");\r\n\
|
||||
}\r\n";
|
||||
let mut html = Buffer::new();
|
||||
let mut html = String::new();
|
||||
write_code(&mut html, src, None, None, None);
|
||||
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
|
||||
expect_file!["fixtures/dos_line.html"].assert_eq(&html);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -50,9 +49,9 @@ fn test_keyword_highlight() {
|
||||
let x = super::b::foo;
|
||||
let y = Self::whatever;";
|
||||
|
||||
let mut html = Buffer::new();
|
||||
let mut html = String::new();
|
||||
write_code(&mut html, src, None, None, None);
|
||||
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
|
||||
expect_file!["fixtures/highlight.html"].assert_eq(&html);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -60,9 +59,9 @@ fn test_keyword_highlight() {
|
||||
fn test_union_highlighting() {
|
||||
create_default_session_globals_then(|| {
|
||||
let src = include_str!("fixtures/union.rs");
|
||||
let mut html = Buffer::new();
|
||||
let mut html = String::new();
|
||||
write_code(&mut html, src, None, None, None);
|
||||
expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
|
||||
expect_file!["fixtures/union.html"].assert_eq(&html);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -77,8 +76,8 @@ fn test_decorations() {
|
||||
decorations.insert("example", vec![(0, 10), (11, 21)]);
|
||||
decorations.insert("example2", vec![(22, 32)]);
|
||||
|
||||
let mut html = Buffer::new();
|
||||
let mut html = String::new();
|
||||
write_code(&mut html, src, None, Some(&DecorationInfo(decorations)), None);
|
||||
expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
|
||||
expect_file!["fixtures/decorations.html"].assert_eq(&html);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::fmt::{self, Display};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use rinja::Template;
|
||||
@@ -5,7 +6,6 @@
|
||||
|
||||
use super::static_files::{STATIC_FILES, StaticFiles};
|
||||
use crate::externalfiles::ExternalHtml;
|
||||
use crate::html::format::{Buffer, Print};
|
||||
use crate::html::render::{StylePath, ensure_trailing_slash};
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -71,7 +71,24 @@ struct PageLayout<'a> {
|
||||
|
||||
pub(crate) use crate::html::render::sidebar::filters;
|
||||
|
||||
pub(crate) fn render<T: Print, S: Print>(
|
||||
/// Implements [`Display`] for a function that accepts a mutable reference to a [`String`], and (optionally) writes to it.
|
||||
///
|
||||
/// The wrapped function will receive an empty string, and can modify it,
|
||||
/// and the `Display` implementation will write the contents of the string after the function has finished.
|
||||
pub(crate) struct BufDisplay<F>(pub F);
|
||||
|
||||
impl<F> Display for BufDisplay<F>
|
||||
where
|
||||
F: Fn(&mut String),
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut buf = String::new();
|
||||
self.0(&mut buf);
|
||||
f.write_str(&buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn render<T: Display, S: Display>(
|
||||
layout: &Layout,
|
||||
page: &Page<'_>,
|
||||
sidebar: S,
|
||||
@@ -98,8 +115,8 @@ pub(crate) fn render<T: Print, S: Print>(
|
||||
let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
|
||||
themes.sort();
|
||||
|
||||
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
|
||||
let sidebar = Buffer::html().to_display(sidebar);
|
||||
let content = t.to_string(); // Note: This must happen before making the sidebar.
|
||||
let sidebar = sidebar.to_string();
|
||||
PageLayout {
|
||||
static_root_path,
|
||||
page,
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
use crate::doctest;
|
||||
use crate::doctest::GlobalTestOptions;
|
||||
use crate::html::escape::{Escape, EscapeBodyText};
|
||||
use crate::html::format::Buffer;
|
||||
use crate::html::highlight;
|
||||
use crate::html::length_limit::HtmlWithLimit;
|
||||
use crate::html::render::small_url_encode;
|
||||
@@ -329,7 +328,7 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
|
||||
// insert newline to clearly separate it from the
|
||||
// previous block so we can shorten the html output
|
||||
let mut s = Buffer::new();
|
||||
let mut s = String::new();
|
||||
s.push('\n');
|
||||
|
||||
highlight::render_example_with_highlighting(
|
||||
@@ -339,7 +338,7 @@ fn next(&mut self) -> Option<Self::Item> {
|
||||
playground_button.as_deref(),
|
||||
&added_classes,
|
||||
);
|
||||
Some(Event::Html(s.into_inner().into()))
|
||||
Some(Event::Html(s.into()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::mpsc::{Receiver, channel};
|
||||
use std::{fmt, io};
|
||||
|
||||
use rinja::Template;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
@@ -26,11 +26,12 @@
|
||||
use crate::formats::cache::Cache;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{Buffer, join_with_double_colon};
|
||||
use crate::html::format::join_with_double_colon;
|
||||
use crate::html::layout::{self, BufDisplay};
|
||||
use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
|
||||
use crate::html::render::write_shared::write_shared;
|
||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||
use crate::html::{layout, sources, static_files};
|
||||
use crate::html::{sources, static_files};
|
||||
use crate::scrape_examples::AllCallLocations;
|
||||
use crate::{DOC_RUST_LANG_ORG_VERSION, try_err};
|
||||
|
||||
@@ -235,7 +236,7 @@ fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String {
|
||||
};
|
||||
|
||||
if !render_redirect_pages {
|
||||
let mut page_buffer = Buffer::html();
|
||||
let mut page_buffer = String::new();
|
||||
print_item(self, it, &mut page_buffer);
|
||||
let page = layout::Page {
|
||||
css_class: tyname_s,
|
||||
@@ -249,8 +250,10 @@ fn render_item(&mut self, it: &clean::Item, is_module: bool) -> String {
|
||||
layout::render(
|
||||
&self.shared.layout,
|
||||
&page,
|
||||
|buf: &mut _| print_sidebar(self, it, buf),
|
||||
move |buf: &mut Buffer| buf.push_buffer(page_buffer),
|
||||
BufDisplay(|buf: &mut String| {
|
||||
print_sidebar(self, it, buf);
|
||||
}),
|
||||
page_buffer,
|
||||
&self.shared.style_files,
|
||||
)
|
||||
} else {
|
||||
@@ -627,7 +630,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
rust_logo: has_doc_flag(self.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
|
||||
};
|
||||
let all = shared.all.replace(AllTypes::new());
|
||||
let mut sidebar = Buffer::html();
|
||||
let mut sidebar = String::new();
|
||||
|
||||
// all.html is not customizable, so a blank id map is fine
|
||||
let blocks = sidebar_module_like(all.item_sections(), &mut IdMap::new(), ModuleLike::Crate);
|
||||
@@ -646,8 +649,10 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
let v = layout::render(
|
||||
&shared.layout,
|
||||
&page,
|
||||
sidebar.into_inner(),
|
||||
|buf: &mut Buffer| all.print(buf),
|
||||
sidebar,
|
||||
BufDisplay(|buf: &mut String| {
|
||||
all.print(buf);
|
||||
}),
|
||||
&shared.style_files,
|
||||
);
|
||||
shared.fs.write(final_file, v)?;
|
||||
@@ -665,7 +670,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
&shared.layout,
|
||||
&page,
|
||||
sidebar,
|
||||
|buf: &mut Buffer| {
|
||||
fmt::from_fn(|buf| {
|
||||
write!(
|
||||
buf,
|
||||
"<div class=\"main-heading\">\
|
||||
@@ -684,7 +689,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
<script defer src=\"{static_root_path}{settings_js}\"></script>",
|
||||
static_root_path = page.get_static_root_path(),
|
||||
settings_js = static_files::STATIC_FILES.settings_js,
|
||||
);
|
||||
)?;
|
||||
// Pre-load all theme CSS files, so that switching feels seamless.
|
||||
//
|
||||
// When loading settings.html as a popover, the equivalent HTML is
|
||||
@@ -697,10 +702,11 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
as=\"style\">",
|
||||
root_path = page.static_root_path.unwrap_or(""),
|
||||
suffix = page.resource_suffix,
|
||||
);
|
||||
)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(())
|
||||
}),
|
||||
&shared.style_files,
|
||||
);
|
||||
shared.fs.write(settings_file, v)?;
|
||||
@@ -716,25 +722,22 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
||||
&shared.layout,
|
||||
&page,
|
||||
sidebar,
|
||||
|buf: &mut Buffer| {
|
||||
write!(
|
||||
buf,
|
||||
"<div class=\"main-heading\">\
|
||||
<h1>Rustdoc help</h1>\
|
||||
<span class=\"out-of-band\">\
|
||||
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
||||
Back\
|
||||
</a>\
|
||||
</span>\
|
||||
</div>\
|
||||
<noscript>\
|
||||
<section>\
|
||||
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
|
||||
<p>For more information, browse the <a href=\"{DOC_RUST_LANG_ORG_VERSION}/rustdoc/\">rustdoc handbook</a>.</p>\
|
||||
</section>\
|
||||
</noscript>",
|
||||
)
|
||||
},
|
||||
format_args!(
|
||||
"<div class=\"main-heading\">\
|
||||
<h1>Rustdoc help</h1>\
|
||||
<span class=\"out-of-band\">\
|
||||
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
||||
Back\
|
||||
</a>\
|
||||
</span>\
|
||||
</div>\
|
||||
<noscript>\
|
||||
<section>\
|
||||
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
|
||||
<p>For more information, browse the <a href=\"{DOC_RUST_LANG_ORG_VERSION}/rustdoc/\">rustdoc handbook</a>.</p>\
|
||||
</section>\
|
||||
</noscript>",
|
||||
),
|
||||
&shared.style_files,
|
||||
);
|
||||
shared.fs.write(help_file, v)?;
|
||||
|
||||
+207
-159
@@ -69,9 +69,9 @@
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
Buffer, Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
|
||||
Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space,
|
||||
print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause,
|
||||
visibility_print_with_space,
|
||||
visibility_print_with_space, write_str,
|
||||
};
|
||||
use crate::html::markdown::{
|
||||
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
||||
@@ -436,27 +436,29 @@ fn item_sections(&self) -> FxHashSet<ItemSection> {
|
||||
sections
|
||||
}
|
||||
|
||||
fn print(self, f: &mut Buffer) {
|
||||
fn print_entries(f: &mut Buffer, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
|
||||
fn print(&self, f: &mut String) {
|
||||
fn print_entries(f: &mut String, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
|
||||
if !e.is_empty() {
|
||||
let mut e: Vec<&ItemEntry> = e.iter().collect();
|
||||
e.sort();
|
||||
write!(
|
||||
write_str(
|
||||
f,
|
||||
"<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
|
||||
id = kind.id(),
|
||||
title = kind.name(),
|
||||
format_args!(
|
||||
"<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
|
||||
id = kind.id(),
|
||||
title = kind.name(),
|
||||
),
|
||||
);
|
||||
|
||||
for s in e.iter() {
|
||||
write!(f, "<li>{}</li>", s.print());
|
||||
write_str(f, format_args!("<li>{}</li>", s.print()));
|
||||
}
|
||||
|
||||
f.write_str("</ul>");
|
||||
f.push_str("</ul>");
|
||||
}
|
||||
}
|
||||
|
||||
f.write_str("<h1>List of all items</h1>");
|
||||
f.push_str("<h1>List of all items</h1>");
|
||||
// Note: print_entries does not escape the title, because we know the current set of titles
|
||||
// doesn't require escaping.
|
||||
print_entries(f, &self.structs, ItemSection::Structs);
|
||||
@@ -761,7 +763,7 @@ pub(crate) fn render_impls(
|
||||
let did = i.trait_did().unwrap();
|
||||
let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
|
||||
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
|
||||
let mut buffer = Buffer::new();
|
||||
let mut buffer = String::new();
|
||||
render_impl(
|
||||
&mut buffer,
|
||||
cx,
|
||||
@@ -778,7 +780,7 @@ pub(crate) fn render_impls(
|
||||
toggle_open_by_default,
|
||||
},
|
||||
);
|
||||
buffer.into_inner()
|
||||
buffer
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
rendered_impls.sort();
|
||||
@@ -847,7 +849,7 @@ enum AssocConstValue<'a> {
|
||||
}
|
||||
|
||||
fn assoc_const(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
it: &clean::Item,
|
||||
generics: &clean::Generics,
|
||||
ty: &clean::Type,
|
||||
@@ -857,15 +859,17 @@ fn assoc_const(
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
let tcx = cx.tcx();
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
|
||||
indent = " ".repeat(indent),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
ty = ty.print(cx),
|
||||
format_args!(
|
||||
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
|
||||
indent = " ".repeat(indent),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
ty = ty.print(cx),
|
||||
),
|
||||
);
|
||||
if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
|
||||
// FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
|
||||
@@ -879,14 +883,14 @@ fn assoc_const(
|
||||
AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
|
||||
AssocConstValue::None => unreachable!(),
|
||||
} {
|
||||
write!(w, " = {}", Escape(&repr));
|
||||
write_str(w, format_args!(" = {}", Escape(&repr)));
|
||||
}
|
||||
}
|
||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||
write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
|
||||
}
|
||||
|
||||
fn assoc_type(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
it: &clean::Item,
|
||||
generics: &clean::Generics,
|
||||
bounds: &[clean::GenericBound],
|
||||
@@ -895,27 +899,29 @@ fn assoc_type(
|
||||
indent: usize,
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
|
||||
indent = " ".repeat(indent),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
format_args!(
|
||||
"{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
|
||||
indent = " ".repeat(indent),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
),
|
||||
);
|
||||
if !bounds.is_empty() {
|
||||
write!(w, ": {}", print_generic_bounds(bounds, cx))
|
||||
write_str(w, format_args!(": {}", print_generic_bounds(bounds, cx)));
|
||||
}
|
||||
// Render the default before the where-clause which aligns with the new recommended style. See #89122.
|
||||
if let Some(default) = default {
|
||||
write!(w, " = {}", default.print(cx))
|
||||
write_str(w, format_args!(" = {}", default.print(cx)));
|
||||
}
|
||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||
write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline)));
|
||||
}
|
||||
|
||||
fn assoc_method(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
meth: &clean::Item,
|
||||
g: &clean::Generics,
|
||||
d: &clean::FnDecl,
|
||||
@@ -961,30 +967,32 @@ fn assoc_method(
|
||||
let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
|
||||
header_len += 4;
|
||||
let indent_str = " ";
|
||||
write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx));
|
||||
write_str(w, format_args!("{}", render_attributes_in_pre(meth, indent_str, cx)));
|
||||
(4, indent_str, Ending::NoNewline)
|
||||
} else {
|
||||
render_attributes_in_code(w, meth, cx);
|
||||
(0, "", Ending::Newline)
|
||||
};
|
||||
w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
|
||||
format_args!(
|
||||
"{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
|
||||
<a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
|
||||
indent = indent_str,
|
||||
vis = vis,
|
||||
defaultness = defaultness,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
safety = safety,
|
||||
abi = abi,
|
||||
href = href,
|
||||
name = name,
|
||||
generics = g.print(cx),
|
||||
decl = d.full_print(header_len, indent, cx),
|
||||
notable_traits = notable_traits.unwrap_or_default(),
|
||||
where_clause = print_where_clause(g, cx, indent, end_newline),
|
||||
indent = indent_str,
|
||||
vis = vis,
|
||||
defaultness = defaultness,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
safety = safety,
|
||||
abi = abi,
|
||||
href = href,
|
||||
name = name,
|
||||
generics = g.print(cx),
|
||||
decl = d.full_print(header_len, indent, cx),
|
||||
notable_traits = notable_traits.unwrap_or_default(),
|
||||
where_clause = print_where_clause(g, cx, indent, end_newline),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1003,7 +1011,7 @@ fn assoc_method(
|
||||
/// 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_with_extra(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
stable_version: Option<StableSince>,
|
||||
const_stability: Option<ConstStability>,
|
||||
extra_class: &str,
|
||||
@@ -1058,7 +1066,10 @@ fn render_stability_since_raw_with_extra(
|
||||
}
|
||||
|
||||
if !stability.is_empty() {
|
||||
write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#);
|
||||
write_str(
|
||||
w,
|
||||
format_args!(r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#),
|
||||
);
|
||||
}
|
||||
|
||||
!stability.is_empty()
|
||||
@@ -1074,7 +1085,7 @@ fn since_to_string(since: &StableSince) -> Option<String> {
|
||||
|
||||
#[inline]
|
||||
fn render_stability_since_raw(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
ver: Option<StableSince>,
|
||||
const_stability: Option<ConstStability>,
|
||||
) -> bool {
|
||||
@@ -1082,7 +1093,7 @@ fn render_stability_since_raw(
|
||||
}
|
||||
|
||||
fn render_assoc_item(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
item: &clean::Item,
|
||||
link: AssocItemLink<'_>,
|
||||
parent: ItemType,
|
||||
@@ -1222,9 +1233,11 @@ pub(crate) fn render_all_impls(
|
||||
synthetic: &[&Impl],
|
||||
blanket_impl: &[&Impl],
|
||||
) {
|
||||
let mut impls = Buffer::html();
|
||||
render_impls(cx, &mut impls, concrete, containing_item, true);
|
||||
let impls = impls.into_inner();
|
||||
let impls = {
|
||||
let mut buf = String::new();
|
||||
render_impls(cx, &mut buf, concrete, containing_item, true);
|
||||
buf
|
||||
};
|
||||
if !impls.is_empty() {
|
||||
write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations");
|
||||
write!(w, "<div id=\"trait-implementations-list\">{impls}</div>").unwrap();
|
||||
@@ -1277,7 +1290,7 @@ fn render_assoc_items_inner(
|
||||
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
|
||||
if !non_trait.is_empty() {
|
||||
let mut close_tags = <Vec<&str>>::with_capacity(1);
|
||||
let mut tmp_buf = Buffer::html();
|
||||
let mut tmp_buf = String::new();
|
||||
let (render_mode, id, class_html) = match what {
|
||||
AssocItemRender::All => {
|
||||
write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations");
|
||||
@@ -1287,7 +1300,7 @@ fn render_assoc_items_inner(
|
||||
let id =
|
||||
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
|
||||
let derived_id = cx.derive_id(&id);
|
||||
tmp_buf.write_str("<details class=\"toggle big-toggle\" open><summary>");
|
||||
tmp_buf.push_str("<details class=\"toggle big-toggle\" open><summary>");
|
||||
close_tags.push("</details>");
|
||||
write_impl_section_heading(
|
||||
&mut tmp_buf,
|
||||
@@ -1298,14 +1311,14 @@ fn render_assoc_items_inner(
|
||||
),
|
||||
&id,
|
||||
);
|
||||
tmp_buf.write_str("</summary>");
|
||||
tmp_buf.push_str("</summary>");
|
||||
if let Some(def_id) = type_.def_id(cx.cache()) {
|
||||
cx.deref_id_map.borrow_mut().insert(def_id, id);
|
||||
}
|
||||
(RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
|
||||
}
|
||||
};
|
||||
let mut impls_buf = Buffer::html();
|
||||
let mut impls_buf = String::new();
|
||||
for i in &non_trait {
|
||||
render_impl(
|
||||
&mut impls_buf,
|
||||
@@ -1325,13 +1338,7 @@ fn render_assoc_items_inner(
|
||||
);
|
||||
}
|
||||
if !impls_buf.is_empty() {
|
||||
write!(
|
||||
w,
|
||||
"{}<div id=\"{id}\"{class_html}>{}</div>",
|
||||
tmp_buf.into_inner(),
|
||||
impls_buf.into_inner()
|
||||
)
|
||||
.unwrap();
|
||||
write!(w, "{tmp_buf}<div id=\"{id}\"{class_html}>{impls_buf}</div>").unwrap();
|
||||
for tag in close_tags.into_iter().rev() {
|
||||
w.write_str(tag).unwrap();
|
||||
}
|
||||
@@ -1485,7 +1492,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
|
||||
}
|
||||
|
||||
fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
|
||||
let mut out = Buffer::html();
|
||||
let mut out = String::new();
|
||||
|
||||
let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
|
||||
|
||||
@@ -1507,15 +1514,20 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
|
||||
|
||||
if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) {
|
||||
if out.is_empty() {
|
||||
write!(
|
||||
write_str(
|
||||
&mut out,
|
||||
"<h3>Notable traits for <code>{}</code></h3>\
|
||||
<pre><code>",
|
||||
impl_.for_.print(cx)
|
||||
format_args!(
|
||||
"<h3>Notable traits for <code>{}</code></h3>\
|
||||
<pre><code>",
|
||||
impl_.for_.print(cx)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
write!(&mut out, "<div class=\"where\">{}</div>", impl_.print(false, cx));
|
||||
write_str(
|
||||
&mut out,
|
||||
format_args!("<div class=\"where\">{}</div>", impl_.print(false, cx)),
|
||||
);
|
||||
for it in &impl_.items {
|
||||
if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
|
||||
out.push_str("<div class=\"where\"> ");
|
||||
@@ -1538,10 +1550,10 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
|
||||
}
|
||||
}
|
||||
if out.is_empty() {
|
||||
out.write_str("</code></pre>");
|
||||
out.push_str("</code></pre>");
|
||||
}
|
||||
|
||||
(format!("{:#}", ty.print(cx)), out.into_inner())
|
||||
(format!("{:#}", ty.print(cx)), out)
|
||||
}
|
||||
|
||||
pub(crate) fn notable_traits_json<'a>(
|
||||
@@ -1577,7 +1589,7 @@ struct ImplRenderingParameters {
|
||||
}
|
||||
|
||||
fn render_impl(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
i: &Impl,
|
||||
parent: &clean::Item,
|
||||
@@ -1598,8 +1610,8 @@ fn render_impl(
|
||||
// `containing_item` is used for rendering stability info. If the parent is a trait impl,
|
||||
// `containing_item` will the grandparent, since trait impls can't have stability attached.
|
||||
fn doc_impl_item(
|
||||
boring: &mut Buffer,
|
||||
interesting: &mut Buffer,
|
||||
boring: &mut String,
|
||||
interesting: &mut String,
|
||||
cx: &Context<'_>,
|
||||
item: &clean::Item,
|
||||
parent: &clean::Item,
|
||||
@@ -1622,8 +1634,8 @@ fn doc_impl_item(
|
||||
|
||||
let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
|
||||
|
||||
let mut doc_buffer = Buffer::empty_from(boring);
|
||||
let mut info_buffer = Buffer::empty_from(boring);
|
||||
let mut doc_buffer = String::new();
|
||||
let mut info_buffer = String::new();
|
||||
let mut short_documented = true;
|
||||
|
||||
if render_method_item {
|
||||
@@ -1638,25 +1650,26 @@ fn doc_impl_item(
|
||||
document_item_info(cx, it, Some(parent))
|
||||
.render_into(&mut info_buffer)
|
||||
.unwrap();
|
||||
write!(
|
||||
write_str(
|
||||
&mut doc_buffer,
|
||||
"{}",
|
||||
document_full(item, cx, HeadingOffset::H5)
|
||||
format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
|
||||
);
|
||||
short_documented = false;
|
||||
} else {
|
||||
// In case the item isn't documented,
|
||||
// provide short documentation from the trait.
|
||||
write!(
|
||||
write_str(
|
||||
&mut doc_buffer,
|
||||
"{}",
|
||||
document_short(
|
||||
it,
|
||||
cx,
|
||||
link,
|
||||
parent,
|
||||
rendering_params.show_def_docs,
|
||||
)
|
||||
format_args!(
|
||||
"{}",
|
||||
document_short(
|
||||
it,
|
||||
cx,
|
||||
link,
|
||||
parent,
|
||||
rendering_params.show_def_docs,
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1665,15 +1678,20 @@ fn doc_impl_item(
|
||||
.render_into(&mut info_buffer)
|
||||
.unwrap();
|
||||
if rendering_params.show_def_docs {
|
||||
write!(&mut doc_buffer, "{}", document_full(item, cx, HeadingOffset::H5));
|
||||
write_str(
|
||||
&mut doc_buffer,
|
||||
format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
|
||||
);
|
||||
short_documented = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write!(
|
||||
write_str(
|
||||
&mut doc_buffer,
|
||||
"{}",
|
||||
document_short(item, cx, link, parent, rendering_params.show_def_docs)
|
||||
format_args!(
|
||||
"{}",
|
||||
document_short(item, cx, link, parent, rendering_params.show_def_docs)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1682,7 +1700,10 @@ fn doc_impl_item(
|
||||
let toggled = !doc_buffer.is_empty();
|
||||
if toggled {
|
||||
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
|
||||
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
|
||||
);
|
||||
}
|
||||
match &item.kind {
|
||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
|
||||
@@ -1697,13 +1718,16 @@ fn doc_impl_item(
|
||||
.find(|item| item.name.map(|n| n == *name).unwrap_or(false))
|
||||
})
|
||||
.map(|item| format!("{}.{name}", item.type_()));
|
||||
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
|
||||
);
|
||||
render_rightside(w, cx, item, render_mode);
|
||||
if trait_.is_some() {
|
||||
// Anchors are only used on trait impls.
|
||||
write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
|
||||
write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
|
||||
}
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
w.push_str("<h4 class=\"code-header\">");
|
||||
render_assoc_item(
|
||||
w,
|
||||
item,
|
||||
@@ -1712,19 +1736,22 @@ fn doc_impl_item(
|
||||
cx,
|
||||
render_mode,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
}
|
||||
}
|
||||
clean::RequiredAssocConstItem(ref generics, ref ty) => {
|
||||
let source_id = format!("{item_type}.{name}");
|
||||
let id = cx.derive_id(&source_id);
|
||||
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
|
||||
);
|
||||
render_rightside(w, cx, item, render_mode);
|
||||
if trait_.is_some() {
|
||||
// Anchors are only used on trait impls.
|
||||
write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
|
||||
write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
|
||||
}
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
w.push_str("<h4 class=\"code-header\">");
|
||||
assoc_const(
|
||||
w,
|
||||
item,
|
||||
@@ -1735,18 +1762,21 @@ fn doc_impl_item(
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
}
|
||||
clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
|
||||
let source_id = format!("{item_type}.{name}");
|
||||
let id = cx.derive_id(&source_id);
|
||||
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
|
||||
);
|
||||
render_rightside(w, cx, item, render_mode);
|
||||
if trait_.is_some() {
|
||||
// Anchors are only used on trait impls.
|
||||
write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
|
||||
write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
|
||||
}
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
w.push_str("<h4 class=\"code-header\">");
|
||||
assoc_const(
|
||||
w,
|
||||
item,
|
||||
@@ -1761,18 +1791,21 @@ fn doc_impl_item(
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
}
|
||||
clean::RequiredAssocTypeItem(ref generics, ref bounds) => {
|
||||
let source_id = format!("{item_type}.{name}");
|
||||
let id = cx.derive_id(&source_id);
|
||||
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
|
||||
);
|
||||
render_rightside(w, cx, item, render_mode);
|
||||
if trait_.is_some() {
|
||||
// Anchors are only used on trait impls.
|
||||
write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
|
||||
write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
|
||||
}
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
w.push_str("<h4 class=\"code-header\">");
|
||||
assoc_type(
|
||||
w,
|
||||
item,
|
||||
@@ -1783,18 +1816,21 @@ fn doc_impl_item(
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
}
|
||||
clean::AssocTypeItem(tydef, _bounds) => {
|
||||
let source_id = format!("{item_type}.{name}");
|
||||
let id = cx.derive_id(&source_id);
|
||||
write!(w, "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">"),
|
||||
);
|
||||
render_rightside(w, cx, item, render_mode);
|
||||
if trait_.is_some() {
|
||||
// Anchors are only used on trait impls.
|
||||
write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>");
|
||||
write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
|
||||
}
|
||||
w.write_str("<h4 class=\"code-header\">");
|
||||
w.push_str("<h4 class=\"code-header\">");
|
||||
assoc_type(
|
||||
w,
|
||||
item,
|
||||
@@ -1805,22 +1841,22 @@ fn doc_impl_item(
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
}
|
||||
clean::StrippedItem(..) => return,
|
||||
_ => panic!("can't make docs for trait item with name {:?}", item.name),
|
||||
}
|
||||
|
||||
w.push_buffer(info_buffer);
|
||||
w.push_str(&info_buffer);
|
||||
if toggled {
|
||||
w.write_str("</summary>");
|
||||
w.push_buffer(doc_buffer);
|
||||
w.push_str("</summary>");
|
||||
w.push_str(&doc_buffer);
|
||||
w.push_str("</details>");
|
||||
}
|
||||
}
|
||||
|
||||
let mut impl_items = Buffer::empty_from(w);
|
||||
let mut default_impl_items = Buffer::empty_from(w);
|
||||
let mut impl_items = String::new();
|
||||
let mut default_impl_items = String::new();
|
||||
let impl_ = i.inner_impl();
|
||||
|
||||
// Impl items are grouped by kinds:
|
||||
@@ -1894,8 +1930,8 @@ fn doc_impl_item(
|
||||
}
|
||||
|
||||
fn render_default_items(
|
||||
boring: &mut Buffer,
|
||||
interesting: &mut Buffer,
|
||||
boring: &mut String,
|
||||
interesting: &mut String,
|
||||
cx: &Context<'_>,
|
||||
t: &clean::Trait,
|
||||
i: &clean::Impl,
|
||||
@@ -1960,11 +1996,13 @@ fn render_default_items(
|
||||
let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
|
||||
if toggled {
|
||||
close_tags.push("</details>");
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<details class=\"toggle implementors-toggle\"{}>\
|
||||
<summary>",
|
||||
if rendering_params.toggle_open_by_default { " open" } else { "" }
|
||||
format_args!(
|
||||
"<details class=\"toggle implementors-toggle\"{}>\
|
||||
<summary>",
|
||||
if rendering_params.toggle_open_by_default { " open" } else { "" }
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1995,38 +2033,38 @@ fn render_default_items(
|
||||
&before_dox,
|
||||
);
|
||||
if toggled {
|
||||
w.write_str("</summary>");
|
||||
w.push_str("</summary>");
|
||||
}
|
||||
|
||||
if before_dox.is_some() {
|
||||
if trait_.is_none() && impl_.items.is_empty() {
|
||||
w.write_str(
|
||||
w.push_str(
|
||||
"<div class=\"item-info\">\
|
||||
<div class=\"stab empty-impl\">This impl block contains no items.</div>\
|
||||
</div>",
|
||||
);
|
||||
}
|
||||
if let Some(after_dox) = after_dox {
|
||||
write!(w, "<div class=\"docblock\">{after_dox}</div>");
|
||||
write_str(w, format_args!("<div class=\"docblock\">{after_dox}</div>"));
|
||||
}
|
||||
}
|
||||
if !default_impl_items.is_empty() || !impl_items.is_empty() {
|
||||
w.write_str("<div class=\"impl-items\">");
|
||||
w.push_str("<div class=\"impl-items\">");
|
||||
close_tags.push("</div>");
|
||||
}
|
||||
}
|
||||
if !default_impl_items.is_empty() || !impl_items.is_empty() {
|
||||
w.push_buffer(default_impl_items);
|
||||
w.push_buffer(impl_items);
|
||||
w.push_str(&default_impl_items);
|
||||
w.push_str(&impl_items);
|
||||
}
|
||||
for tag in close_tags.into_iter().rev() {
|
||||
w.write_str(tag);
|
||||
w.push_str(tag);
|
||||
}
|
||||
}
|
||||
|
||||
// Render the items that appear on the right side of methods, impls, and
|
||||
// associated types. For example "1.0.0 (const: 1.39.0) · source".
|
||||
fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) {
|
||||
fn render_rightside(w: &mut String, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) {
|
||||
let tcx = cx.tcx();
|
||||
|
||||
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
|
||||
@@ -2038,7 +2076,7 @@ fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render
|
||||
let src_href = cx.src_href(item);
|
||||
let has_src_ref = src_href.is_some();
|
||||
|
||||
let mut rightside = Buffer::new();
|
||||
let mut rightside = String::new();
|
||||
let has_stability = render_stability_since_raw_with_extra(
|
||||
&mut rightside,
|
||||
item.stable_since(tcx),
|
||||
@@ -2047,20 +2085,26 @@ fn render_rightside(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, render
|
||||
);
|
||||
if let Some(link) = src_href {
|
||||
if has_stability {
|
||||
write!(rightside, " · <a class=\"src\" href=\"{link}\">Source</a>")
|
||||
write_str(
|
||||
&mut rightside,
|
||||
format_args!(" · <a class=\"src\" href=\"{link}\">Source</a>"),
|
||||
);
|
||||
} else {
|
||||
write!(rightside, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
|
||||
write_str(
|
||||
&mut rightside,
|
||||
format_args!("<a class=\"src rightside\" href=\"{link}\">Source</a>"),
|
||||
);
|
||||
}
|
||||
}
|
||||
if has_stability && has_src_ref {
|
||||
write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
|
||||
write_str(w, format_args!("<span class=\"rightside\">{rightside}</span>"));
|
||||
} else {
|
||||
w.push_buffer(rightside);
|
||||
w.push_str(&rightside);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn render_impl_summary(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
i: &Impl,
|
||||
parent: &clean::Item,
|
||||
@@ -2078,20 +2122,22 @@ pub(crate) fn render_impl_summary(
|
||||
} else {
|
||||
format!(" data-aliases=\"{}\"", aliases.join(","))
|
||||
};
|
||||
write!(w, "<section id=\"{id}\" class=\"impl\"{aliases}>");
|
||||
write_str(w, format_args!("<section id=\"{id}\" class=\"impl\"{aliases}>"));
|
||||
render_rightside(w, cx, &i.impl_item, RenderMode::Normal);
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<a href=\"#{id}\" class=\"anchor\">§</a>\
|
||||
<h3 class=\"code-header\">"
|
||||
format_args!(
|
||||
"<a href=\"#{id}\" class=\"anchor\">§</a>\
|
||||
<h3 class=\"code-header\">"
|
||||
),
|
||||
);
|
||||
|
||||
if let Some(use_absolute) = use_absolute {
|
||||
write!(w, "{}", inner_impl.print(use_absolute, cx));
|
||||
write_str(w, format_args!("{}", inner_impl.print(use_absolute, cx)));
|
||||
if show_def_docs {
|
||||
for it in &inner_impl.items {
|
||||
if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
|
||||
w.write_str("<div class=\"where\"> ");
|
||||
w.push_str("<div class=\"where\"> ");
|
||||
assoc_type(
|
||||
w,
|
||||
it,
|
||||
@@ -2102,30 +2148,32 @@ pub(crate) fn render_impl_summary(
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str(";</div>");
|
||||
w.push_str(";</div>");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
write!(w, "{}", inner_impl.print(false, cx));
|
||||
write_str(w, format_args!("{}", inner_impl.print(false, cx)));
|
||||
}
|
||||
w.write_str("</h3>");
|
||||
w.push_str("</h3>");
|
||||
|
||||
let is_trait = inner_impl.trait_.is_some();
|
||||
if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<span class=\"item-info\">\
|
||||
format_args!(
|
||||
"<span class=\"item-info\">\
|
||||
<div class=\"stab portability\">{portability}</div>\
|
||||
</span>",
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(doc) = doc {
|
||||
write!(w, "<div class=\"docblock\">{doc}</div>");
|
||||
write_str(w, format_args!("<div class=\"docblock\">{doc}</div>"));
|
||||
}
|
||||
|
||||
w.write_str("</section>");
|
||||
w.push_str("</section>");
|
||||
}
|
||||
|
||||
pub(crate) fn small_url_encode(s: String) -> String {
|
||||
@@ -2577,7 +2625,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean
|
||||
cx,
|
||||
&cx.root_path(),
|
||||
&highlight::DecorationInfo(decoration_info),
|
||||
sources::SourceContext::Embedded(sources::ScrapedInfo {
|
||||
&sources::SourceContext::Embedded(sources::ScrapedInfo {
|
||||
needs_expansion,
|
||||
offset: line_min,
|
||||
name: &call_data.display_name,
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::escape::{Escape, EscapeBodyTextWithWbr};
|
||||
use crate::html::format::{
|
||||
Buffer, Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
|
||||
print_constness_with_space, print_where_clause, visibility_print_with_space,
|
||||
Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space,
|
||||
print_constness_with_space, print_where_clause, visibility_print_with_space, write_str,
|
||||
};
|
||||
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
||||
use crate::html::render::{document_full, document_item_info};
|
||||
@@ -165,16 +165,16 @@ struct ItemVars<'a> {
|
||||
|
||||
/// Calls `print_where_clause` and returns `true` if a `where` clause was generated.
|
||||
fn print_where_clause_and_check<'a, 'tcx: 'a>(
|
||||
buffer: &mut Buffer,
|
||||
buffer: &mut String,
|
||||
gens: &'a clean::Generics,
|
||||
cx: &'a Context<'tcx>,
|
||||
) -> bool {
|
||||
let len_before = buffer.len();
|
||||
write!(buffer, "{}", print_where_clause(gens, cx, 0, Ending::Newline));
|
||||
write_str(buffer, format_args!("{}", print_where_clause(gens, cx, 0, Ending::Newline)));
|
||||
len_before != buffer.len()
|
||||
}
|
||||
|
||||
pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
|
||||
pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut String) {
|
||||
debug_assert!(!item.is_stripped());
|
||||
let typ = match item.kind {
|
||||
clean::ModuleItem(_) => {
|
||||
@@ -207,13 +207,15 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let mut stability_since_raw = Buffer::new();
|
||||
render_stability_since_raw(
|
||||
&mut stability_since_raw,
|
||||
item.stable_since(cx.tcx()),
|
||||
item.const_stability(cx.tcx()),
|
||||
);
|
||||
let stability_since_raw: String = stability_since_raw.into_inner();
|
||||
let stability_since_raw = {
|
||||
let mut buf = String::new();
|
||||
render_stability_since_raw(
|
||||
&mut buf,
|
||||
item.stable_since(cx.tcx()),
|
||||
item.const_stability(cx.tcx()),
|
||||
);
|
||||
buf
|
||||
};
|
||||
|
||||
// Write source tag
|
||||
//
|
||||
@@ -278,10 +280,12 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer)
|
||||
// Render notable-traits.js used for all methods in this module.
|
||||
let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut();
|
||||
if !types_with_notable_traits.is_empty() {
|
||||
write!(
|
||||
write_str(
|
||||
buf,
|
||||
r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
|
||||
notable_traits_json(types_with_notable_traits.iter(), cx)
|
||||
format_args!(
|
||||
r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
|
||||
notable_traits_json(types_with_notable_traits.iter(), cx)
|
||||
),
|
||||
);
|
||||
types_with_notable_traits.clear();
|
||||
}
|
||||
@@ -311,8 +315,8 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display {
|
||||
fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>);
|
||||
}
|
||||
|
||||
fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
|
||||
write!(w, "{}", document(cx, item, None, HeadingOffset::H2));
|
||||
fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
|
||||
write_str(w, format_args!("{}", document(cx, item, None, HeadingOffset::H2)));
|
||||
|
||||
let mut not_stripped_items =
|
||||
items.iter().filter(|i| !i.is_stripped()).enumerate().collect::<Vec<_>>();
|
||||
@@ -398,7 +402,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
|
||||
let my_section = item_ty_to_section(myitem.type_());
|
||||
if Some(my_section) != last_section {
|
||||
if last_section.is_some() {
|
||||
w.write_str(ITEM_TABLE_CLOSE);
|
||||
w.push_str(ITEM_TABLE_CLOSE);
|
||||
}
|
||||
last_section = Some(my_section);
|
||||
let section_id = my_section.id();
|
||||
@@ -412,21 +416,29 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
|
||||
use crate::html::format::anchor;
|
||||
|
||||
match *src {
|
||||
Some(src) => write!(
|
||||
w,
|
||||
"<dt><code>{}extern crate {} as {};",
|
||||
visibility_print_with_space(myitem, cx),
|
||||
anchor(myitem.item_id.expect_def_id(), src, cx),
|
||||
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
|
||||
),
|
||||
None => write!(
|
||||
w,
|
||||
"<dt><code>{}extern crate {};",
|
||||
visibility_print_with_space(myitem, cx),
|
||||
anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
|
||||
),
|
||||
Some(src) => {
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"<dt><code>{}extern crate {} as {};",
|
||||
visibility_print_with_space(myitem, cx),
|
||||
anchor(myitem.item_id.expect_def_id(), src, cx),
|
||||
EscapeBodyTextWithWbr(myitem.name.unwrap().as_str())
|
||||
),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"<dt><code>{}extern crate {};",
|
||||
visibility_print_with_space(myitem, cx),
|
||||
anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
w.write_str("</code></dt>");
|
||||
w.push_str("</code></dt>");
|
||||
}
|
||||
|
||||
clean::ImportItem(ref import) => {
|
||||
@@ -440,13 +452,15 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
|
||||
}
|
||||
clean::ImportKind::Glob => String::new(),
|
||||
};
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<dt{id}>\
|
||||
<code>{vis}{imp}</code>{stab_tags}\
|
||||
</dt>",
|
||||
vis = visibility_print_with_space(myitem, cx),
|
||||
imp = import.print(cx),
|
||||
format_args!(
|
||||
"<dt{id}>\
|
||||
<code>{vis}{imp}</code>{stab_tags}\
|
||||
</dt>",
|
||||
vis = visibility_print_with_space(myitem, cx),
|
||||
imp = import.print(cx)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -484,33 +498,35 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
|
||||
MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string();
|
||||
let (docs_before, docs_after) =
|
||||
if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") };
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<dt>\
|
||||
<a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
|
||||
{visibility_and_hidden}\
|
||||
{unsafety_flag}\
|
||||
{stab_tags}\
|
||||
</dt>\
|
||||
{docs_before}{docs}{docs_after}",
|
||||
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
|
||||
visibility_and_hidden = visibility_and_hidden,
|
||||
stab_tags = extra_info_tags(tcx, myitem, item, None),
|
||||
class = myitem.type_(),
|
||||
unsafety_flag = unsafety_flag,
|
||||
href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
|
||||
title = [myitem.type_().to_string(), full_path(cx, myitem)]
|
||||
.iter()
|
||||
.filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
|
||||
.collect::<Vec<_>>()
|
||||
.join(" "),
|
||||
format_args!(
|
||||
"<dt>\
|
||||
<a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
|
||||
{visibility_and_hidden}\
|
||||
{unsafety_flag}\
|
||||
{stab_tags}\
|
||||
</dt>\
|
||||
{docs_before}{docs}{docs_after}",
|
||||
name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()),
|
||||
visibility_and_hidden = visibility_and_hidden,
|
||||
stab_tags = extra_info_tags(tcx, myitem, item, None),
|
||||
class = myitem.type_(),
|
||||
unsafety_flag = unsafety_flag,
|
||||
href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
|
||||
title = [myitem.type_().to_string(), full_path(cx, myitem)]
|
||||
.iter()
|
||||
.filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
|
||||
.collect::<Vec<_>>()
|
||||
.join(" "),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if last_section.is_some() {
|
||||
w.write_str(ITEM_TABLE_CLOSE);
|
||||
w.push_str(ITEM_TABLE_CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,7 +588,7 @@ fn tag_html<'a>(class: &'a str, title: &'a str, contents: &'a str) -> impl Displ
|
||||
})
|
||||
}
|
||||
|
||||
fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
|
||||
fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) {
|
||||
let tcx = cx.tcx();
|
||||
let header = it.fn_header(tcx).expect("printing a function which isn't a function");
|
||||
debug!(
|
||||
@@ -607,27 +623,29 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
|
||||
|
||||
wrap_item(w, |w| {
|
||||
w.reserve(header_len);
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
|
||||
format_args!(
|
||||
"{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
|
||||
{name}{generics}{decl}{notable_traits}{where_clause}",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
safety = safety,
|
||||
abi = abi,
|
||||
name = name,
|
||||
generics = f.generics.print(cx),
|
||||
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
|
||||
decl = f.decl.full_print(header_len, 0, cx),
|
||||
notable_traits = notable_traits.unwrap_or_default(),
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility,
|
||||
constness = constness,
|
||||
asyncness = asyncness,
|
||||
safety = safety,
|
||||
abi = abi,
|
||||
name = name,
|
||||
generics = f.generics.print(cx),
|
||||
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
|
||||
decl = f.decl.full_print(header_len, 0, cx),
|
||||
notable_traits = notable_traits.unwrap_or_default(),
|
||||
),
|
||||
);
|
||||
});
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
}
|
||||
|
||||
fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
|
||||
fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
|
||||
let tcx = cx.tcx();
|
||||
let bounds = bounds(&t.bounds, false, cx);
|
||||
let required_types =
|
||||
@@ -645,28 +663,33 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
|
||||
// Output the trait definition
|
||||
wrap_item(w, |mut w| {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
safety = t.safety(tcx).print_with_space(),
|
||||
is_auto = if t.is_auto(tcx) { "auto " } else { "" },
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
format_args!(
|
||||
"{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
safety = t.safety(tcx).print_with_space(),
|
||||
is_auto = if t.is_auto(tcx) { "auto " } else { "" },
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
),
|
||||
);
|
||||
|
||||
if !t.generics.where_predicates.is_empty() {
|
||||
write!(w, "{}", print_where_clause(&t.generics, cx, 0, Ending::Newline));
|
||||
write_str(
|
||||
w,
|
||||
format_args!("{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)),
|
||||
);
|
||||
} else {
|
||||
w.write_str(" ");
|
||||
w.push_str(" ");
|
||||
}
|
||||
|
||||
if t.items.is_empty() {
|
||||
w.write_str("{ }");
|
||||
w.push_str("{ }");
|
||||
} else {
|
||||
// FIXME: we should be using a derived_id for the Anchors here
|
||||
w.write_str("{\n");
|
||||
w.push_str("{\n");
|
||||
let mut toggle = false;
|
||||
|
||||
// If there are too many associated types, hide _everything_
|
||||
@@ -687,7 +710,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
w.push_str(";\n");
|
||||
}
|
||||
}
|
||||
// If there are too many associated constants, hide everything after them
|
||||
@@ -707,7 +730,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
);
|
||||
}
|
||||
if count_types != 0 && (count_consts != 0 || count_methods != 0) {
|
||||
w.write_str("\n");
|
||||
w.push_str("\n");
|
||||
}
|
||||
for consts in [&required_consts, &provided_consts] {
|
||||
for c in consts {
|
||||
@@ -719,7 +742,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
w.push_str(";\n");
|
||||
}
|
||||
}
|
||||
if !toggle && should_hide_fields(count_methods) {
|
||||
@@ -727,11 +750,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
toggle_open(&mut w, format_args!("{count_methods} methods"));
|
||||
}
|
||||
if count_consts != 0 && count_methods != 0 {
|
||||
w.write_str("\n");
|
||||
w.push_str("\n");
|
||||
}
|
||||
|
||||
if !required_methods.is_empty() {
|
||||
writeln!(w, " // Required method{}", pluralize(required_methods.len()));
|
||||
write_str(
|
||||
w,
|
||||
format_args_nl!(" // Required method{}", pluralize(required_methods.len())),
|
||||
);
|
||||
}
|
||||
for (pos, m) in required_methods.iter().enumerate() {
|
||||
render_assoc_item(
|
||||
@@ -742,18 +768,21 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str(";\n");
|
||||
w.push_str(";\n");
|
||||
|
||||
if pos < required_methods.len() - 1 {
|
||||
w.write_str("<span class=\"item-spacer\"></span>");
|
||||
w.push_str("<span class=\"item-spacer\"></span>");
|
||||
}
|
||||
}
|
||||
if !required_methods.is_empty() && !provided_methods.is_empty() {
|
||||
w.write_str("\n");
|
||||
w.push_str("\n");
|
||||
}
|
||||
|
||||
if !provided_methods.is_empty() {
|
||||
writeln!(w, " // Provided method{}", pluralize(provided_methods.len()));
|
||||
write_str(
|
||||
w,
|
||||
format_args_nl!(" // Provided method{}", pluralize(provided_methods.len())),
|
||||
);
|
||||
}
|
||||
for (pos, m) in provided_methods.iter().enumerate() {
|
||||
render_assoc_item(
|
||||
@@ -765,39 +794,42 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
|
||||
RenderMode::Normal,
|
||||
);
|
||||
|
||||
w.write_str(" { ... }\n");
|
||||
w.push_str(" { ... }\n");
|
||||
|
||||
if pos < provided_methods.len() - 1 {
|
||||
w.write_str("<span class=\"item-spacer\"></span>");
|
||||
w.push_str("<span class=\"item-spacer\"></span>");
|
||||
}
|
||||
}
|
||||
if toggle {
|
||||
toggle_close(&mut w);
|
||||
}
|
||||
w.write_str("}");
|
||||
w.push_str("}");
|
||||
}
|
||||
});
|
||||
|
||||
// Trait documentation
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
|
||||
fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
|
||||
fn trait_item(w: &mut String, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
|
||||
let name = m.name.unwrap();
|
||||
info!("Documenting {name} on {ty_name:?}", ty_name = t.name);
|
||||
let item_type = m.type_();
|
||||
let id = cx.derive_id(format!("{item_type}.{name}"));
|
||||
|
||||
let mut content = Buffer::empty_from(w);
|
||||
write!(content, "{}", document_full(m, cx, HeadingOffset::H5));
|
||||
let mut content = String::new();
|
||||
write_str(&mut content, format_args!("{}", document_full(m, cx, HeadingOffset::H5)));
|
||||
|
||||
let toggled = !content.is_empty();
|
||||
if toggled {
|
||||
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
|
||||
write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>");
|
||||
write_str(
|
||||
w,
|
||||
format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
|
||||
);
|
||||
}
|
||||
write!(w, "<section id=\"{id}\" class=\"method\">");
|
||||
write_str(w, format_args!("<section id=\"{id}\" class=\"method\">"));
|
||||
render_rightside(w, cx, m, RenderMode::Normal);
|
||||
write!(w, "<h4 class=\"code-header\">");
|
||||
write_str(w, format_args!("<h4 class=\"code-header\">"));
|
||||
render_assoc_item(
|
||||
w,
|
||||
m,
|
||||
@@ -806,12 +838,12 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
cx,
|
||||
RenderMode::Normal,
|
||||
);
|
||||
w.write_str("</h4></section>");
|
||||
w.push_str("</h4></section>");
|
||||
document_item_info(cx, m, Some(t)).render_into(w).unwrap();
|
||||
if toggled {
|
||||
write!(w, "</summary>");
|
||||
w.push_buffer(content);
|
||||
write!(w, "</details>");
|
||||
write_str(w, format_args!("</summary>"));
|
||||
w.push_str(&content);
|
||||
write_str(w, format_args!("</details>"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -826,7 +858,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for t in required_consts {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
if !provided_consts.is_empty() {
|
||||
write_section_heading(
|
||||
@@ -839,7 +871,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for t in provided_consts {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
|
||||
if !required_types.is_empty() {
|
||||
@@ -853,7 +885,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for t in required_types {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
if !provided_types.is_empty() {
|
||||
write_section_heading(
|
||||
@@ -866,7 +898,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for t in provided_types {
|
||||
trait_item(w, cx, t, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
|
||||
// Output the documentation for each function individually
|
||||
@@ -880,17 +912,19 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
);
|
||||
|
||||
if let Some(list) = must_implement_one_of_functions.as_deref() {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
|
||||
list.iter().join("`, `")
|
||||
format_args!(
|
||||
"<div class=\"stab must_implement\">At least one of the `{}` methods is required.</div>",
|
||||
list.iter().join("`, `")
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for m in required_methods {
|
||||
trait_item(w, cx, m, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
if !provided_methods.is_empty() {
|
||||
write_section_heading(
|
||||
@@ -903,11 +937,17 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for m in provided_methods {
|
||||
trait_item(w, cx, m, it);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
|
||||
// If there are methods directly on this trait object, render them here.
|
||||
write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All));
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"{}",
|
||||
render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)
|
||||
),
|
||||
);
|
||||
|
||||
let mut extern_crates = FxIndexSet::default();
|
||||
|
||||
@@ -997,7 +1037,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
for implementor in concrete {
|
||||
render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
|
||||
if t.is_auto(tcx) {
|
||||
write_section_heading(
|
||||
@@ -1020,7 +1060,7 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
),
|
||||
);
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
} else {
|
||||
// even without any implementations to write in, we still want the heading and list, so the
|
||||
@@ -1136,10 +1176,12 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
|
||||
.join(",");
|
||||
let (extern_before, extern_after) =
|
||||
if extern_crates.is_empty() { ("", "") } else { (" data-ignore-extern-crates=\"", "\"") };
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>",
|
||||
src = js_src_path.finish(),
|
||||
format_args!(
|
||||
"<script src=\"{src}\"{extern_before}{extern_crates}{extern_after} async></script>",
|
||||
src = js_src_path.finish()
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1171,21 +1213,23 @@ fn item_trait_alias(
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
|
||||
fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) {
|
||||
wrap_item(w, |w| {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
type_ = t.type_.print(cx),
|
||||
format_args!(
|
||||
"{attrs}{vis}type {name}{generics}{where_clause} = {type_};",
|
||||
attrs = render_attributes_in_pre(it, "", cx),
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = t.generics.print(cx),
|
||||
where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline),
|
||||
type_ = t.type_.print(cx),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
|
||||
if let Some(inner_type) = &t.inner_type {
|
||||
write_section_heading(w, "Aliased Type", "aliased-type", None, "");
|
||||
@@ -1201,7 +1245,7 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
|
||||
let variants_count = variants_iter().count();
|
||||
let has_stripped_entries = variants_len != variants_count;
|
||||
|
||||
write!(w, "enum {}{}", it.name.unwrap(), t.generics.print(cx));
|
||||
write_str(w, format_args!("enum {}{}", it.name.unwrap(), t.generics.print(cx)));
|
||||
render_enum_fields(
|
||||
w,
|
||||
cx,
|
||||
@@ -1220,7 +1264,10 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
|
||||
let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
|
||||
let has_stripped_fields = fields.len() != fields_count;
|
||||
|
||||
write!(w, "union {}{}", it.name.unwrap(), t.generics.print(cx));
|
||||
write_str(
|
||||
w,
|
||||
format_args!("union {}{}", it.name.unwrap(), t.generics.print(cx)),
|
||||
);
|
||||
render_struct_fields(
|
||||
w,
|
||||
Some(&t.generics),
|
||||
@@ -1239,7 +1286,10 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
|
||||
let fields_count = fields.iter().filter(|i| !i.is_stripped()).count();
|
||||
let has_stripped_fields = fields.len() != fields_count;
|
||||
|
||||
write!(w, "struct {}{}", it.name.unwrap(), t.generics.print(cx));
|
||||
write_str(
|
||||
w,
|
||||
format_args!("struct {}{}", it.name.unwrap(), t.generics.print(cx)),
|
||||
);
|
||||
render_struct_fields(
|
||||
w,
|
||||
Some(&t.generics),
|
||||
@@ -1261,8 +1311,8 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
|
||||
// won't be visible anywhere in the docs. It would be nice to also show
|
||||
// associated items from the aliased type (see discussion in #32077), but
|
||||
// we need #14072 to make sense of the generics.
|
||||
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
|
||||
write!(w, "{}", document_type_layout(cx, def_id));
|
||||
write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
|
||||
write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
|
||||
|
||||
// [RUSTDOCIMPL] type.impl
|
||||
//
|
||||
@@ -1352,15 +1402,17 @@ fn item_type_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean
|
||||
js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied());
|
||||
js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap()));
|
||||
let self_path = self_fqp.iter().map(Symbol::as_str).collect::<Vec<&str>>().join("::");
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
|
||||
src = js_src_path.finish(),
|
||||
format_args!(
|
||||
"<script src=\"{src}\" data-self-path=\"{self_path}\" async></script>",
|
||||
src = js_src_path.finish()
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
|
||||
fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
|
||||
item_template!(
|
||||
#[template(path = "item_union.html")]
|
||||
struct ItemUnion<'a, 'cx> {
|
||||
@@ -1445,16 +1497,18 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
|
||||
})
|
||||
}
|
||||
|
||||
fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
|
||||
fn item_enum(w: &mut String, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) {
|
||||
let count_variants = e.variants().count();
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{}enum {}{}",
|
||||
visibility_print_with_space(it, cx),
|
||||
it.name.unwrap(),
|
||||
e.generics.print(cx),
|
||||
format_args!(
|
||||
"{}enum {}{}",
|
||||
visibility_print_with_space(it, cx),
|
||||
it.name.unwrap(),
|
||||
e.generics.print(cx),
|
||||
),
|
||||
);
|
||||
|
||||
render_enum_fields(
|
||||
@@ -1469,14 +1523,14 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
|
||||
);
|
||||
});
|
||||
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
|
||||
if count_variants != 0 {
|
||||
item_variants(w, cx, it, &e.variants, it.def_id().unwrap());
|
||||
}
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
|
||||
write!(w, "{}", document_type_layout(cx, def_id));
|
||||
write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
|
||||
write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
|
||||
}
|
||||
|
||||
/// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at
|
||||
@@ -1505,7 +1559,7 @@ fn should_show_enum_discriminant(
|
||||
}
|
||||
|
||||
fn display_c_like_variant(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
item: &clean::Item,
|
||||
variant: &clean::Variant,
|
||||
@@ -1515,22 +1569,22 @@ fn display_c_like_variant(
|
||||
) {
|
||||
let name = item.name.unwrap();
|
||||
if let Some(ref value) = variant.discriminant {
|
||||
write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true));
|
||||
write_str(w, format_args!("{} = {}", name.as_str(), value.value(cx.tcx(), true)));
|
||||
} else if should_show_enum_discriminant {
|
||||
let adt_def = cx.tcx().adt_def(enum_def_id);
|
||||
let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
|
||||
if discr.ty.is_signed() {
|
||||
write!(w, "{} = {}", name.as_str(), discr.val as i128);
|
||||
write_str(w, format_args!("{} = {}", name.as_str(), discr.val as i128));
|
||||
} else {
|
||||
write!(w, "{} = {}", name.as_str(), discr.val);
|
||||
write_str(w, format_args!("{} = {}", name.as_str(), discr.val));
|
||||
}
|
||||
} else {
|
||||
w.write_str(name.as_str());
|
||||
w.push_str(name.as_str());
|
||||
}
|
||||
}
|
||||
|
||||
fn render_enum_fields(
|
||||
mut w: &mut Buffer,
|
||||
mut w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
g: Option<&clean::Generics>,
|
||||
variants: &IndexVec<VariantIdx, clean::Item>,
|
||||
@@ -1542,14 +1596,14 @@ fn render_enum_fields(
|
||||
let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants);
|
||||
if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) {
|
||||
// If there wasn't a `where` clause, we add a whitespace.
|
||||
w.write_str(" ");
|
||||
w.push_str(" ");
|
||||
}
|
||||
|
||||
let variants_stripped = has_stripped_entries;
|
||||
if count_variants == 0 && !variants_stripped {
|
||||
w.write_str("{}");
|
||||
w.push_str("{}");
|
||||
} else {
|
||||
w.write_str("{\n");
|
||||
w.push_str("{\n");
|
||||
let toggle = should_hide_fields(count_variants);
|
||||
if toggle {
|
||||
toggle_open(&mut w, format_args!("{count_variants} variants"));
|
||||
@@ -1559,7 +1613,7 @@ fn render_enum_fields(
|
||||
if v.is_stripped() {
|
||||
continue;
|
||||
}
|
||||
w.write_str(TAB);
|
||||
w.push_str(TAB);
|
||||
match v.kind {
|
||||
clean::VariantItem(ref var) => match var.kind {
|
||||
clean::VariantKind::CLike => display_c_like_variant(
|
||||
@@ -1572,7 +1626,14 @@ fn render_enum_fields(
|
||||
enum_def_id,
|
||||
),
|
||||
clean::VariantKind::Tuple(ref s) => {
|
||||
write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s));
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"{}({})",
|
||||
v.name.unwrap(),
|
||||
print_tuple_struct_fields(cx, s)
|
||||
),
|
||||
);
|
||||
}
|
||||
clean::VariantKind::Struct(ref s) => {
|
||||
render_struct(w, v, None, None, &s.fields, TAB, false, cx);
|
||||
@@ -1580,21 +1641,21 @@ fn render_enum_fields(
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
w.write_str(",\n");
|
||||
w.push_str(",\n");
|
||||
}
|
||||
|
||||
if variants_stripped && !is_non_exhaustive {
|
||||
w.write_str(" <span class=\"comment\">// some variants omitted</span>\n");
|
||||
w.push_str(" <span class=\"comment\">// some variants omitted</span>\n");
|
||||
}
|
||||
if toggle {
|
||||
toggle_close(&mut w);
|
||||
}
|
||||
w.write_str("}");
|
||||
w.push_str("}");
|
||||
}
|
||||
}
|
||||
|
||||
fn item_variants(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
it: &clean::Item,
|
||||
variants: &IndexVec<VariantIdx, clean::Item>,
|
||||
@@ -1615,10 +1676,12 @@ fn item_variants(
|
||||
continue;
|
||||
}
|
||||
let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<section id=\"{id}\" class=\"variant\">\
|
||||
<a href=\"#{id}\" class=\"anchor\">§</a>",
|
||||
format_args!(
|
||||
"<section id=\"{id}\" class=\"variant\">\
|
||||
<a href=\"#{id}\" class=\"anchor\">§</a>"
|
||||
),
|
||||
);
|
||||
render_stability_since_raw_with_extra(
|
||||
w,
|
||||
@@ -1626,7 +1689,7 @@ fn item_variants(
|
||||
variant.const_stability(tcx),
|
||||
" rightside",
|
||||
);
|
||||
w.write_str("<h3 class=\"code-header\">");
|
||||
w.push_str("<h3 class=\"code-header\">");
|
||||
if let clean::VariantItem(ref var) = variant.kind
|
||||
&& let clean::VariantKind::CLike = var.kind
|
||||
{
|
||||
@@ -1640,17 +1703,17 @@ fn item_variants(
|
||||
enum_def_id,
|
||||
);
|
||||
} else {
|
||||
w.write_str(variant.name.unwrap().as_str());
|
||||
w.push_str(variant.name.unwrap().as_str());
|
||||
}
|
||||
|
||||
let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() };
|
||||
|
||||
if let clean::VariantKind::Tuple(ref s) = variant_data.kind {
|
||||
write!(w, "({})", print_tuple_struct_fields(cx, s));
|
||||
write_str(w, format_args!("({})", print_tuple_struct_fields(cx, s)));
|
||||
}
|
||||
w.write_str("</h3></section>");
|
||||
w.push_str("</h3></section>");
|
||||
|
||||
write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4));
|
||||
write_str(w, format_args!("{}", document(cx, variant, Some(it), HeadingOffset::H4)));
|
||||
|
||||
let heading_and_fields = match &variant_data.kind {
|
||||
clean::VariantKind::Struct(s) => {
|
||||
@@ -1676,12 +1739,14 @@ fn item_variants(
|
||||
if let Some((heading, fields)) = heading_and_fields {
|
||||
let variant_id =
|
||||
cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<div class=\"sub-variant\" id=\"{variant_id}\">\
|
||||
<h4>{heading}</h4>\
|
||||
{}",
|
||||
document_non_exhaustive(variant)
|
||||
format_args!(
|
||||
"<div class=\"sub-variant\" id=\"{variant_id}\">\
|
||||
<h4>{heading}</h4>\
|
||||
{}",
|
||||
document_non_exhaustive(variant)
|
||||
),
|
||||
);
|
||||
for field in fields {
|
||||
match field.kind {
|
||||
@@ -1692,40 +1757,44 @@ fn item_variants(
|
||||
variant.name.unwrap(),
|
||||
field.name.unwrap()
|
||||
));
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<div class=\"sub-variant-field\">\
|
||||
<span id=\"{id}\" class=\"section-header\">\
|
||||
<a href=\"#{id}\" class=\"anchor field\">§</a>\
|
||||
<code>{f}: {t}</code>\
|
||||
</span>",
|
||||
f = field.name.unwrap(),
|
||||
t = ty.print(cx),
|
||||
format_args!(
|
||||
"<div class=\"sub-variant-field\">\
|
||||
<span id=\"{id}\" class=\"section-header\">\
|
||||
<a href=\"#{id}\" class=\"anchor field\">§</a>\
|
||||
<code>{f}: {t}</code>\
|
||||
</span>",
|
||||
f = field.name.unwrap(),
|
||||
t = ty.print(cx),
|
||||
),
|
||||
);
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{}</div>",
|
||||
document(cx, field, Some(variant), HeadingOffset::H5)
|
||||
format_args!(
|
||||
"{}</div>",
|
||||
document(cx, field, Some(variant), HeadingOffset::H5),
|
||||
),
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
w.write_str("</div>");
|
||||
w.push_str("</div>");
|
||||
}
|
||||
}
|
||||
write!(w, "</div>");
|
||||
write_str(w, format_args!("</div>"));
|
||||
}
|
||||
|
||||
fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
|
||||
fn item_macro(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) {
|
||||
wrap_item(w, |w| {
|
||||
// FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
|
||||
if !t.macro_rules {
|
||||
write!(w, "{}", visibility_print_with_space(it, cx));
|
||||
write_str(w, format_args!("{}", visibility_print_with_space(it, cx)));
|
||||
}
|
||||
write!(w, "{}", Escape(&t.source));
|
||||
write_str(w, format_args!("{}", Escape(&t.source)));
|
||||
});
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
}
|
||||
|
||||
fn item_proc_macro(
|
||||
@@ -1779,7 +1848,7 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) {
|
||||
}
|
||||
|
||||
fn item_constant(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
it: &clean::Item,
|
||||
generics: &clean::Generics,
|
||||
@@ -1790,14 +1859,16 @@ fn item_constant(
|
||||
let tcx = cx.tcx();
|
||||
render_attributes_in_code(w, it, cx);
|
||||
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{vis}const {name}{generics}: {typ}{where_clause}",
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = generics.print(cx),
|
||||
typ = ty.print(cx),
|
||||
where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline),
|
||||
format_args!(
|
||||
"{vis}const {name}{generics}: {typ}{where_clause}",
|
||||
vis = visibility_print_with_space(it, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = generics.print(cx),
|
||||
typ = ty.print(cx),
|
||||
where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline)
|
||||
),
|
||||
);
|
||||
|
||||
// FIXME: The code below now prints
|
||||
@@ -1813,9 +1884,9 @@ fn item_constant(
|
||||
let is_literal = c.is_literal(tcx);
|
||||
let expr = c.expr(tcx);
|
||||
if value.is_some() || is_literal {
|
||||
write!(w, " = {expr};", expr = Escape(&expr));
|
||||
write_str(w, format_args!(" = {expr};", expr = Escape(&expr)));
|
||||
} else {
|
||||
w.write_str(";");
|
||||
w.push_str(";");
|
||||
}
|
||||
|
||||
if !is_literal {
|
||||
@@ -1826,32 +1897,32 @@ fn item_constant(
|
||||
if value_lowercase != expr_lowercase
|
||||
&& value_lowercase.trim_end_matches("i32") != expr_lowercase
|
||||
{
|
||||
write!(w, " // {value}", value = Escape(value));
|
||||
write_str(w, format_args!(" // {value}", value = Escape(value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
}
|
||||
|
||||
fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
|
||||
fn item_struct(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
|
||||
wrap_item(w, |w| {
|
||||
render_attributes_in_code(w, it, cx);
|
||||
render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx);
|
||||
});
|
||||
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2));
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
|
||||
item_fields(w, cx, it, &s.fields, s.ctor_kind);
|
||||
|
||||
let def_id = it.item_id.expect_def_id();
|
||||
write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All));
|
||||
write!(w, "{}", document_type_layout(cx, def_id));
|
||||
write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)));
|
||||
write_str(w, format_args!("{}", document_type_layout(cx, def_id)));
|
||||
}
|
||||
|
||||
fn item_fields(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
cx: &Context<'_>,
|
||||
it: &clean::Item,
|
||||
fields: &[clean::Item],
|
||||
@@ -1876,16 +1947,18 @@ fn item_fields(
|
||||
let field_name =
|
||||
field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string());
|
||||
let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField));
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"<span id=\"{id}\" class=\"{item_type} section-header\">\
|
||||
<a href=\"#{id}\" class=\"anchor field\">§</a>\
|
||||
<code>{field_name}: {ty}</code>\
|
||||
</span>",
|
||||
item_type = ItemType::StructField,
|
||||
ty = ty.print(cx)
|
||||
format_args!(
|
||||
"<span id=\"{id}\" class=\"{item_type} section-header\">\
|
||||
<a href=\"#{id}\" class=\"anchor field\">§</a>\
|
||||
<code>{field_name}: {ty}</code>\
|
||||
</span>",
|
||||
item_type = ItemType::StructField,
|
||||
ty = ty.print(cx)
|
||||
),
|
||||
);
|
||||
write!(w, "{}", document(cx, field, Some(it), HeadingOffset::H3));
|
||||
write_str(w, format_args!("{}", document(cx, field, Some(it), HeadingOffset::H3)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1933,8 +2006,8 @@ fn item_foreign_type(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
|
||||
write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
|
||||
fn item_keyword(w: &mut String, cx: &Context<'_>, it: &clean::Item) {
|
||||
write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2)));
|
||||
}
|
||||
|
||||
/// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
|
||||
@@ -2108,7 +2181,7 @@ fn render_implementor(
|
||||
cx: &Context<'_>,
|
||||
implementor: &Impl,
|
||||
trait_: &clean::Item,
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
implementor_dups: &FxHashMap<Symbol, (DefId, bool)>,
|
||||
aliases: &[String],
|
||||
) {
|
||||
@@ -2152,10 +2225,9 @@ fn render_union<'a, 'cx: 'a>(
|
||||
|
||||
let where_displayed = g
|
||||
.map(|g| {
|
||||
let mut buf = Buffer::html();
|
||||
write!(buf, "{}", g.print(cx));
|
||||
let mut buf = g.print(cx).to_string();
|
||||
let where_displayed = print_where_clause_and_check(&mut buf, g, cx);
|
||||
write!(f, "{buf}", buf = buf.into_inner()).unwrap();
|
||||
f.write_str(&buf).unwrap();
|
||||
where_displayed
|
||||
})
|
||||
.unwrap_or(false);
|
||||
@@ -2197,7 +2269,7 @@ fn render_union<'a, 'cx: 'a>(
|
||||
}
|
||||
|
||||
fn render_struct(
|
||||
w: &mut Buffer,
|
||||
w: &mut String,
|
||||
it: &clean::Item,
|
||||
g: Option<&clean::Generics>,
|
||||
ty: Option<CtorKind>,
|
||||
@@ -2206,15 +2278,17 @@ fn render_struct(
|
||||
structhead: bool,
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"{}{}{}",
|
||||
visibility_print_with_space(it, cx),
|
||||
if structhead { "struct " } else { "" },
|
||||
it.name.unwrap()
|
||||
format_args!(
|
||||
"{}{}{}",
|
||||
visibility_print_with_space(it, cx),
|
||||
if structhead { "struct " } else { "" },
|
||||
it.name.unwrap()
|
||||
),
|
||||
);
|
||||
if let Some(g) = g {
|
||||
write!(w, "{}", g.print(cx))
|
||||
write_str(w, format_args!("{}", g.print(cx)));
|
||||
}
|
||||
render_struct_fields(
|
||||
w,
|
||||
@@ -2229,7 +2303,7 @@ fn render_struct(
|
||||
}
|
||||
|
||||
fn render_struct_fields(
|
||||
mut w: &mut Buffer,
|
||||
mut w: &mut String,
|
||||
g: Option<&clean::Generics>,
|
||||
ty: Option<CtorKind>,
|
||||
fields: &[clean::Item],
|
||||
@@ -2245,9 +2319,9 @@ fn render_struct_fields(
|
||||
|
||||
// If there wasn't a `where` clause, we add a whitespace.
|
||||
if !where_displayed {
|
||||
w.write_str(" {");
|
||||
w.push_str(" {");
|
||||
} else {
|
||||
w.write_str("{");
|
||||
w.push_str("{");
|
||||
}
|
||||
let count_fields =
|
||||
fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count();
|
||||
@@ -2258,66 +2332,82 @@ fn render_struct_fields(
|
||||
}
|
||||
for field in fields {
|
||||
if let clean::StructFieldItem(ref ty) = field.kind {
|
||||
write!(
|
||||
write_str(
|
||||
w,
|
||||
"\n{tab} {vis}{name}: {ty},",
|
||||
vis = visibility_print_with_space(field, cx),
|
||||
name = field.name.unwrap(),
|
||||
ty = ty.print(cx),
|
||||
format_args!(
|
||||
"\n{tab} {vis}{name}: {ty},",
|
||||
vis = visibility_print_with_space(field, cx),
|
||||
name = field.name.unwrap(),
|
||||
ty = ty.print(cx)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if has_visible_fields {
|
||||
if has_stripped_entries {
|
||||
write!(w, "\n{tab} <span class=\"comment\">/* private fields */</span>");
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"\n{tab} <span class=\"comment\">/* private fields */</span>"
|
||||
),
|
||||
);
|
||||
}
|
||||
write!(w, "\n{tab}");
|
||||
write_str(w, format_args!("\n{tab}"));
|
||||
} else if has_stripped_entries {
|
||||
write!(w, " <span class=\"comment\">/* private fields */</span> ");
|
||||
write_str(w, format_args!(" <span class=\"comment\">/* private fields */</span> "));
|
||||
}
|
||||
if toggle {
|
||||
toggle_close(&mut w);
|
||||
}
|
||||
w.write_str("}");
|
||||
w.push_str("}");
|
||||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
w.write_str("(");
|
||||
w.push_str("(");
|
||||
if !fields.is_empty()
|
||||
&& fields.iter().all(|field| {
|
||||
matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
|
||||
})
|
||||
{
|
||||
write!(w, "<span class=\"comment\">/* private fields */</span>");
|
||||
write_str(w, format_args!("<span class=\"comment\">/* private fields */</span>"));
|
||||
} else {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
w.write_str(", ");
|
||||
w.push_str(", ");
|
||||
}
|
||||
match field.kind {
|
||||
clean::StrippedItem(box clean::StructFieldItem(..)) => write!(w, "_"),
|
||||
clean::StrippedItem(box clean::StructFieldItem(..)) => {
|
||||
write_str(w, format_args!("_"));
|
||||
}
|
||||
clean::StructFieldItem(ref ty) => {
|
||||
write!(w, "{}{}", visibility_print_with_space(field, cx), ty.print(cx),)
|
||||
write_str(
|
||||
w,
|
||||
format_args!(
|
||||
"{}{}",
|
||||
visibility_print_with_space(field, cx),
|
||||
ty.print(cx)
|
||||
),
|
||||
);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
w.write_str(")");
|
||||
w.push_str(")");
|
||||
if let Some(g) = g {
|
||||
write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
|
||||
write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
|
||||
}
|
||||
// We only want a ";" when we are displaying a tuple struct, not a variant tuple struct.
|
||||
if structhead {
|
||||
w.write_str(";");
|
||||
w.push_str(";");
|
||||
}
|
||||
}
|
||||
Some(CtorKind::Const) => {
|
||||
// Needed for PhantomData.
|
||||
if let Some(g) = g {
|
||||
write!(w, "{}", print_where_clause(g, cx, 0, Ending::NoNewline));
|
||||
write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline)));
|
||||
}
|
||||
w.write_str(";");
|
||||
w.push_str(";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
use crate::clean;
|
||||
use crate::formats::Impl;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::format::Buffer;
|
||||
use crate::html::markdown::{IdMap, MarkdownWithToc};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -114,7 +113,7 @@ pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>>
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
|
||||
pub(super) fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut String) {
|
||||
let mut ids = IdMap::new();
|
||||
let mut blocks: Vec<LinkBlock<'_>> = docblock_toc(cx, it, &mut ids).into_iter().collect();
|
||||
let deref_id_map = cx.deref_id_map.borrow();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::AllTypes;
|
||||
use super::print_item::compare_names;
|
||||
use super::{AllTypes, Buffer};
|
||||
|
||||
#[test]
|
||||
fn test_compare_names() {
|
||||
@@ -47,8 +47,8 @@ fn test_all_types_prints_header_once() {
|
||||
// Regression test for #82477
|
||||
let all_types = AllTypes::new();
|
||||
|
||||
let mut buffer = Buffer::new();
|
||||
let mut buffer = String::new();
|
||||
all_types.print(&mut buffer);
|
||||
|
||||
assert_eq!(1, buffer.into_inner().matches("List of all items").count());
|
||||
assert_eq!(1, buffer.matches("List of all items").count());
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
use crate::error::Error;
|
||||
use crate::formats::Impl;
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::html::format::Buffer;
|
||||
use crate::html::layout;
|
||||
use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
|
||||
use crate::html::render::search_index::{SerializedSearchIndex, build_index};
|
||||
@@ -622,7 +621,6 @@ fn get(
|
||||
// to make that functionality work here, it needs to be called with
|
||||
// each type alias, and if it gives a different result, split the impl
|
||||
for &(type_alias_fqp, type_alias_item) in type_aliases {
|
||||
let mut buf = Buffer::html();
|
||||
cx.id_map.borrow_mut().clear();
|
||||
cx.deref_id_map.borrow_mut().clear();
|
||||
let target_did = impl_
|
||||
@@ -638,23 +636,26 @@ fn get(
|
||||
} else {
|
||||
AssocItemLink::Anchor(None)
|
||||
};
|
||||
super::render_impl(
|
||||
&mut buf,
|
||||
cx,
|
||||
impl_,
|
||||
type_alias_item,
|
||||
assoc_link,
|
||||
RenderMode::Normal,
|
||||
None,
|
||||
&[],
|
||||
ImplRenderingParameters {
|
||||
show_def_docs: true,
|
||||
show_default_items: true,
|
||||
show_non_assoc_items: true,
|
||||
toggle_open_by_default: true,
|
||||
},
|
||||
);
|
||||
let text = buf.into_inner();
|
||||
let text = {
|
||||
let mut buf = String::new();
|
||||
super::render_impl(
|
||||
&mut buf,
|
||||
cx,
|
||||
impl_,
|
||||
type_alias_item,
|
||||
assoc_link,
|
||||
RenderMode::Normal,
|
||||
None,
|
||||
&[],
|
||||
ImplRenderingParameters {
|
||||
show_def_docs: true,
|
||||
show_default_items: true,
|
||||
show_non_assoc_items: true,
|
||||
toggle_open_by_default: true,
|
||||
},
|
||||
);
|
||||
buf
|
||||
};
|
||||
let type_alias_fqp = (*type_alias_fqp).iter().join("::");
|
||||
if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) {
|
||||
ret.last_mut()
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, sym};
|
||||
use tracing::info;
|
||||
|
||||
use super::highlight;
|
||||
use super::layout::{self, BufDisplay};
|
||||
use super::render::Context;
|
||||
use crate::clean;
|
||||
use crate::clean::utils::has_doc_flag;
|
||||
use crate::docfs::PathError;
|
||||
use crate::error::Error;
|
||||
use crate::html::render::Context;
|
||||
use crate::html::{highlight, layout};
|
||||
use crate::visit::DocVisitor;
|
||||
|
||||
pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
|
||||
@@ -237,11 +238,12 @@ fn emit_source(
|
||||
resource_suffix: &shared.resource_suffix,
|
||||
rust_logo: has_doc_flag(self.cx.tcx(), LOCAL_CRATE.as_def_id(), sym::rust_logo),
|
||||
};
|
||||
let source_context = SourceContext::Standalone { file_path };
|
||||
let v = layout::render(
|
||||
&shared.layout,
|
||||
&page,
|
||||
"",
|
||||
|buf: &mut _| {
|
||||
BufDisplay(|buf: &mut String| {
|
||||
print_src(
|
||||
buf,
|
||||
contents,
|
||||
@@ -249,9 +251,9 @@ fn emit_source(
|
||||
self.cx,
|
||||
&root_path,
|
||||
&highlight::DecorationInfo::default(),
|
||||
SourceContext::Standalone { file_path },
|
||||
)
|
||||
},
|
||||
&source_context,
|
||||
);
|
||||
}),
|
||||
&shared.style_files,
|
||||
);
|
||||
shared.fs.write(cur, v)?;
|
||||
@@ -301,7 +303,7 @@ pub(crate) struct ScrapedInfo<'a> {
|
||||
#[derive(Template)]
|
||||
#[template(path = "scraped_source.html")]
|
||||
struct ScrapedSource<'a, Code: std::fmt::Display> {
|
||||
info: ScrapedInfo<'a>,
|
||||
info: &'a ScrapedInfo<'a>,
|
||||
code_html: Code,
|
||||
max_nb_digits: u32,
|
||||
}
|
||||
@@ -328,7 +330,7 @@ pub(crate) fn print_src(
|
||||
context: &Context<'_>,
|
||||
root_path: &str,
|
||||
decoration_info: &highlight::DecorationInfo,
|
||||
source_context: SourceContext<'_>,
|
||||
source_context: &SourceContext<'_>,
|
||||
) {
|
||||
let mut lines = s.lines().count();
|
||||
let line_info = if let SourceContext::Embedded(ref info) = source_context {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#![feature(box_patterns)]
|
||||
#![feature(debug_closure_helpers)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(format_args_nl)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//! This is a regression test for <https://github.com/rust-lang/miri/issues/4188>: The precondition
|
||||
//! check in `ptr::swap_nonoverlapping` was incorrectly disabled in Miri.
|
||||
//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();"
|
||||
//@normalize-stderr-test: "\| +\^+" -> "| ^"
|
||||
//@normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
|
||||
//@normalize-stderr-test: "\n +at [^\n]+" -> ""
|
||||
//@error-in-other-file: aborted execution
|
||||
|
||||
fn main() {
|
||||
let mut data = 0usize;
|
||||
let ptr = std::ptr::addr_of_mut!(data);
|
||||
unsafe {
|
||||
std::ptr::swap_nonoverlapping(ptr, ptr, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
thread 'main' panicked at RUSTLIB/core/src/panicking.rs:LL:CC:
|
||||
unsafe precondition(s) violated: ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap
|
||||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect
|
||||
thread caused non-unwinding panic. aborting.
|
||||
error: abnormal termination: the program aborted execution
|
||||
--> RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
|
||||
|
|
||||
LL | ABORT();
|
||||
| ^ the program aborted execution
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `std::sys::pal::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/pal/PLATFORM/mod.rs:LL:CC
|
||||
= note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC
|
||||
= note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC
|
||||
= note: inside `std::sys::backtrace::__rust_end_short_backtrace::<{closure@std::panicking::begin_panic_handler::{closure#0}}, !>` at RUSTLIB/std/src/sys/backtrace.rs:LL:CC
|
||||
= note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC
|
||||
= note: inside `core::panicking::panic_nounwind` at RUSTLIB/core/src/panicking.rs:LL:CC
|
||||
= note: inside `std::ptr::swap_nonoverlapping::precondition_check` at RUSTLIB/core/src/ub_checks.rs:LL:CC
|
||||
= note: inside `std::ptr::swap_nonoverlapping::<usize>` at RUSTLIB/core/src/ub_checks.rs:LL:CC
|
||||
note: inside `main`
|
||||
--> tests/fail/ptr_swap_nonoverlapping.rs:LL:CC
|
||||
|
|
||||
LL | std::ptr::swap_nonoverlapping(ptr, ptr, 1);
|
||||
| ^
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
//@ compile-flags: -Copt-level=3 -C panic=abort
|
||||
//@ compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
//@ needs-llvm-components: aarch64
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $reg:ident $code:literal) => {
|
||||
// -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0
|
||||
// -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $func() -> i32 {
|
||||
let y;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@ needs-llvm-components: aarch64
|
||||
//@ only-aarch64
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
//@ compile-flags: -Copt-level=3 -C panic=abort
|
||||
//@ compile-flags: --target armv7-unknown-linux-gnueabihf
|
||||
//@ compile-flags: -C target-feature=+neon
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
@@ -21,7 +21,7 @@ impl Copy for f32x4 {}
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $modifier:literal $reg:ident $ty:ident $mov:literal) => {
|
||||
// -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0
|
||||
// -Copt-level=3 and extern "C" guarantee that the selected register is always r0/s0/d0/q0
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $func() -> $ty {
|
||||
let y;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//@ add-core-stubs
|
||||
//@ revisions: x86_64 i686
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -C panic=abort
|
||||
//@ compile-flags: -Copt-level=3 -C panic=abort
|
||||
//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[x86_64] needs-llvm-components: x86
|
||||
//@[i686] compile-flags: --target i686-unknown-linux-gnu
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
macro_rules! check {
|
||||
($func:ident $modifier:literal $reg:ident $mov:literal) => {
|
||||
// -O and extern "C" guarantee that the selected register is always ax/xmm0
|
||||
// -Copt-level=3 and extern "C" guarantee that the selected register is always ax/xmm0
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn $func() -> i32 {
|
||||
let y;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ assembly-output: emit-asm
|
||||
// # zen3 previously exhibited odd vectorization
|
||||
//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver3 -O
|
||||
//@ compile-flags: --crate-type=lib -Ctarget-cpu=znver3 -Copt-level=3
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Regression test for #106269
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ only-x86_64-unknown-linux-gnu
|
||||
//@ compile-flags: -C panic=unwind -C force-unwind-tables=n -O
|
||||
//@ compile-flags: -C panic=unwind -C force-unwind-tables=n -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ revisions: elfv1-be elfv2-be elfv2-le aix
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@[elfv1-be] compile-flags: --target powerpc64-unknown-linux-gnu
|
||||
//@[elfv1-be] needs-llvm-components: powerpc
|
||||
//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ revisions: enable-backchain disable-backchain
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O --crate-type=lib --target=s390x-unknown-linux-gnu
|
||||
//@ compile-flags: -Copt-level=3 --crate-type=lib --target=s390x-unknown-linux-gnu
|
||||
//@ needs-llvm-components: systemz
|
||||
//@[enable-backchain] compile-flags: -Ctarget-feature=+backchain
|
||||
//@[disable-backchain] compile-flags: -Ctarget-feature=-backchain
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//@ revisions: z10 z10_vector z13 z13_no_vector
|
||||
// ignore-tidy-linelength
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector
|
||||
//@[z10] needs-llvm-components: systemz
|
||||
//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu
|
||||
//@ [aarch64] needs-llvm-components: aarch64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
|
||||
//@ [x86-avx512] needs-llvm-components: x86
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
|
||||
//@ [x86-avx512] needs-llvm-components: x86
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu
|
||||
//@ [aarch64] needs-llvm-components: aarch64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
|
||||
//@ [x86-avx512] needs-llvm-components: x86
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//@ [x86-avx512] compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bw,+avx512dq
|
||||
//@ [x86-avx512] needs-llvm-components: x86
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//@ [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu
|
||||
//@ [aarch64] needs-llvm-components: aarch64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C panic=abort
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C panic=abort
|
||||
|
||||
#![feature(no_core, lang_items, repr_simd, intrinsics)]
|
||||
#![no_core]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//@ revisions: x86_64 aarch64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3
|
||||
|
||||
//@[aarch64] only-aarch64
|
||||
//@[x86_64] only-x86_64
|
||||
//@[x86_64] compile-flags: -Ctarget-feature=+sse3
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//@ [WIN] only-windows
|
||||
//@ [LIN] only-linux
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ only-x86
|
||||
// FIXME(#114479): LLVM miscompiles loading and storing `f32` and `f64` when SSE is disabled.
|
||||
// There's no compiletest directive to ignore a test on i586 only, so just always explicitly enable
|
||||
// SSE2.
|
||||
// Use the same target CPU as `i686` so that LLVM orders the instructions in the same order.
|
||||
//@ compile-flags: -Ctarget-feature=+sse2 -Ctarget-cpu=pentium4
|
||||
// Force frame pointers to make ASM more consistent between targets
|
||||
//@ compile-flags: -O -C force-frame-pointers
|
||||
//@ compile-flags: -C force-frame-pointers
|
||||
// At opt-level=3, LLVM can merge two movss into one movsd, and we aren't testing for that.
|
||||
//@ compile-flags: -Copt-level=2
|
||||
//@ filecheck-flags: --implicit-check-not fld --implicit-check-not fst
|
||||
//@ revisions: normal win
|
||||
//@[normal] ignore-windows
|
||||
//@[win] only-windows
|
||||
//@ revisions: linux win
|
||||
//@ add-core-stubs
|
||||
//@[linux] needs-llvm-components: x86
|
||||
//@[win] needs-llvm-components: x86
|
||||
//@[linux] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[win] compile-flags: --target i686-pc-windows-msvc
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(f16, f128)]
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// Tests that returning `f32` and `f64` with the "Rust" ABI on 32-bit x86 doesn't use the x87
|
||||
// floating point stack, as loading and storing `f32`s and `f64`s to and from the x87 stack quietens
|
||||
@@ -190,8 +199,8 @@ pub unsafe fn call_f64_f64(x: &mut (f64, f64)) {
|
||||
}
|
||||
// CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
|
||||
// CHECK: calll {{()|_}}get_f64_f64
|
||||
// normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// normal-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// linux-NEXT: movsd [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// win: movsd (%esp), %[[VAL1:.*]]
|
||||
// win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
|
||||
// CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
|
||||
@@ -207,12 +216,12 @@ pub unsafe fn call_f32_f64(x: &mut (f32, f64)) {
|
||||
}
|
||||
// CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
|
||||
// CHECK: calll {{()|_}}get_f32_f64
|
||||
// normal: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// normal-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
|
||||
// linux: movss [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
|
||||
// win: movss (%esp), %[[VAL1:.*]]
|
||||
// win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
|
||||
// CHECK-NEXT: movss %[[VAL1]], (%[[PTR]])
|
||||
// normal-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
|
||||
// linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
|
||||
// win-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
|
||||
*x = get_f32_f64();
|
||||
}
|
||||
@@ -225,8 +234,8 @@ pub unsafe fn call_f64_f32(x: &mut (f64, f32)) {
|
||||
}
|
||||
// CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
|
||||
// CHECK: calll {{()|_}}get_f64_f32
|
||||
// normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// normal-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// linux-NEXT: movss [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// win: movsd (%esp), %[[VAL1:.*]]
|
||||
// win-NEXT: movss 8(%esp), %[[VAL2:.*]]
|
||||
// CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
|
||||
@@ -257,8 +266,8 @@ pub unsafe fn call_f64_other(x: &mut (f64, usize)) {
|
||||
}
|
||||
// CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
|
||||
// CHECK: calll {{()|_}}get_f64_other
|
||||
// normal: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// normal-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// linux: movsd [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// linux-NEXT: movl [[#%d,OFFSET+8]](%ebp), %[[VAL2:.*]]
|
||||
// win: movsd (%esp), %[[VAL1:.*]]
|
||||
// win-NEXT: movl 8(%esp), %[[VAL2:.*]]
|
||||
// CHECK-NEXT: movsd %[[VAL1]], (%[[PTR]])
|
||||
@@ -289,12 +298,12 @@ pub unsafe fn call_other_f64(x: &mut (usize, f64)) {
|
||||
}
|
||||
// CHECK: movl {{.*}}(%ebp), %[[PTR:.*]]
|
||||
// CHECK: calll {{()|_}}get_other_f64
|
||||
// normal: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// normal-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
|
||||
// linux: movl [[#%d,OFFSET:]](%ebp), %[[VAL1:.*]]
|
||||
// linux-NEXT: movsd [[#%d,OFFSET+4]](%ebp), %[[VAL2:.*]]
|
||||
// win: movl (%esp), %[[VAL1:.*]]
|
||||
// win-NEXT: movsd 8(%esp), %[[VAL2:.*]]
|
||||
// CHECK-NEXT: movl %[[VAL1]], (%[[PTR]])
|
||||
// normal-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
|
||||
// linux-NEXT: movsd %[[VAL2]], 4(%[[PTR]])
|
||||
// win-NEXT: movsd %[[VAL2]], 8(%[[PTR]])
|
||||
*x = get_other_f64();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
//@ ignore-apple (manipulates rsp too)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//@ only-x86_64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O -C target-cpu=x86-64-v4
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C target-cpu=x86-64-v4
|
||||
//@ compile-flags: -C llvm-args=-x86-asm-syntax=intel
|
||||
//@ revisions: llvm-pre-20 llvm-20
|
||||
//@ [llvm-20] min-llvm-version: 20
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
//@ assembly-output: emit-asm
|
||||
// Set the base cpu explicitly, in case the default has been changed.
|
||||
//@ compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel -C target-cpu=x86-64
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3 -C llvm-args=-x86-asm-syntax=intel -C target-cpu=x86-64
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
//@ revisions: unset keep thunk-extern keep-thunk-extern thunk-extern-keep
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ [keep] compile-flags: -Zfunction-return=keep
|
||||
//@ [thunk-extern] compile-flags: -Zfunction-return=thunk-extern
|
||||
//@ [keep-thunk-extern] compile-flags: -Zfunction-return=keep -Zfunction-return=thunk-extern
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
//@ revisions: unset set
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ [set] compile-flags: -Zno-jump-tables
|
||||
//@ only-x86_64
|
||||
//@ ignore-sgx
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//@ [LIN] only-linux
|
||||
//@ only-x86_64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --crate-type=lib -O
|
||||
//@ compile-flags: --crate-type=lib -Copt-level=3
|
||||
|
||||
use std::arch::x86_64::__m128;
|
||||
use std::mem::swap;
|
||||
@@ -12,42 +12,42 @@
|
||||
#[no_mangle]
|
||||
pub fn swap_i32(x: &mut i32, y: &mut i32) {
|
||||
// CHECK: movl (%[[ARG1:.+]]), %[[T1:.+]]
|
||||
// CHECK: movl (%[[ARG2:.+]]), %[[T2:.+]]
|
||||
// CHECK: movl %[[T2]], (%[[ARG1]])
|
||||
// CHECK: movl %[[T1]], (%[[ARG2]])
|
||||
// CHECK: retq
|
||||
// CHECK-NEXT: movl (%[[ARG2:.+]]), %[[T2:.+]]
|
||||
// CHECK-DAG: movl %[[T2]], (%[[ARG1]])
|
||||
// CHECK-DAG: movl %[[T1]], (%[[ARG2]])
|
||||
// CHECK-NEXT: retq
|
||||
swap(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: swap_pair:
|
||||
#[no_mangle]
|
||||
pub fn swap_pair(x: &mut (i32, u32), y: &mut (i32, u32)) {
|
||||
// CHECK: movq (%[[ARG1]]), %[[T1:.+]]
|
||||
// CHECK: movq (%[[ARG2]]), %[[T2:.+]]
|
||||
// CHECK: movq %[[T2]], (%[[ARG1]])
|
||||
// CHECK: movq %[[T1]], (%[[ARG2]])
|
||||
// CHECK: retq
|
||||
// CHECK: movq (%[[ARG1:r..?]]), %[[T1:.+]]
|
||||
// CHECK-NEXT: movq (%[[ARG2:r..?]]), %[[T2:.+]]
|
||||
// CHECK-DAG: movq %[[T2]], (%[[ARG1]])
|
||||
// CHECK-DAG: movq %[[T1]], (%[[ARG2]])
|
||||
// CHECK-NEXT: retq
|
||||
swap(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: swap_str:
|
||||
#[no_mangle]
|
||||
pub fn swap_str<'a>(x: &mut &'a str, y: &mut &'a str) {
|
||||
// CHECK: movups (%[[ARG1]]), %[[T1:xmm.]]
|
||||
// CHECK: movups (%[[ARG2]]), %[[T2:xmm.]]
|
||||
// CHECK: movups %[[T2]], (%[[ARG1]])
|
||||
// CHECK: movups %[[T1]], (%[[ARG2]])
|
||||
// CHECK: retq
|
||||
// CHECK: movups (%[[ARG1:r..?]]), %[[T1:xmm.]]
|
||||
// CHECK-NEXT: movups (%[[ARG2:r..?]]), %[[T2:xmm.]]
|
||||
// CHECK-DAG: movups %[[T2]], (%[[ARG1]])
|
||||
// CHECK-DAG: movups %[[T1]], (%[[ARG2]])
|
||||
// CHECK-NEXT: retq
|
||||
swap(x, y)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: swap_simd:
|
||||
#[no_mangle]
|
||||
pub fn swap_simd(x: &mut __m128, y: &mut __m128) {
|
||||
// CHECK: movaps (%[[ARG1]]), %[[T1:xmm.]]
|
||||
// CHECK: movaps (%[[ARG2]]), %[[T2:xmm.]]
|
||||
// CHECK: movaps %[[T2]], (%[[ARG1]])
|
||||
// CHECK: movaps %[[T1]], (%[[ARG2]])
|
||||
// CHECK: retq
|
||||
// CHECK: movaps (%[[ARG1:r..?]]), %[[T1:xmm.]]
|
||||
// CHECK-NEXT: movaps (%[[ARG2:r..?]]), %[[T2:xmm.]]
|
||||
// CHECK-DAG: movaps %[[T2]], (%[[ARG1]])
|
||||
// CHECK-DAG: movaps %[[T1]], (%[[ARG2]])
|
||||
// CHECK-NEXT: retq
|
||||
swap(x, y)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -O
|
||||
//@ only-windows
|
||||
//@ only-x86_64
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ compile-flags: --target x86_64-pc-windows-msvc
|
||||
//@ needs-llvm-components: x86
|
||||
//@ add-core-stubs
|
||||
|
||||
#![feature(f16, f128)]
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: second_f16
|
||||
// CHECK: movaps %xmm1, %xmm0
|
||||
// CHECK-NEXT: retq
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
//@ revisions:x86_64 i686 aarch64-apple aarch64-windows aarch64-linux arm riscv
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -C no-prepopulate-passes
|
||||
//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
//@ only-x86_64
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(array_repeat)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generation of atomic operations.
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::sync::atomic::AtomicI32;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// ensures that we do not have such a round-trip for AtomicPtr::swap, because LLVM supports pointer
|
||||
// arguments to `atomicrmw xchg`.
|
||||
|
||||
//@ compile-flags: -O -Cno-prepopulate-passes
|
||||
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
|
||||
#![crate_type = "lib"]
|
||||
#![feature(strict_provenance_atomic_ptr)]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort
|
||||
//@ compile-flags: -Copt-level=3 --target=avr-unknown-gnu-atmega328 --crate-type=rlib -C panic=abort
|
||||
//@ needs-llvm-components: avr
|
||||
|
||||
// This test validates that function pointers can be stored in global variables
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ ignore-std-debug-assertions
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// Make sure no bounds checks are emitted when slicing or indexing
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Checks that range metadata gets emitted on calls to functions returning a
|
||||
// scalar value.
|
||||
|
||||
//@ compile-flags: -O -C no-prepopulate-passes
|
||||
//@ compile-flags: -Copt-level=3 -C no-prepopulate-passes
|
||||
//@ max-llvm-major-version: 18
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// This tests that LLVM can optimize based on the niches in the source or
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// ignore-tidy-linelength
|
||||
//@ revisions:aarch64 loongarch64 powerpc64 sparc64 x86_64
|
||||
//@ min-llvm-version: 19
|
||||
//@ compile-flags: -O -Cno-prepopulate-passes -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error
|
||||
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes -Zlint-llvm-ir -Cllvm-args=-lint-abort-on-error
|
||||
|
||||
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@[aarch64] needs-llvm-components: arm
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
// On x86 the closure is inlined in foo() producing something like
|
||||
// define i32 @foo() [...] {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Checks that these functions are branchless.
|
||||
//
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Z merge-functions=disabled
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(unchecked_shifts)]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//@ revisions: DEBUGINFO NODEBUGINFO
|
||||
//@ compile-flags: -Zunsound-mir-opts
|
||||
// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
|
||||
//@ compile-flags: -O -Cno-prepopulate-passes
|
||||
//@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
|
||||
//@ [DEBUGINFO] compile-flags: -Cdebuginfo=full
|
||||
|
||||
// From https://github.com/rust-lang/rust/issues/128081.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(core_intrinsics)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ aux-build:always.rs
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Zcross-crate-inline-threshold=always
|
||||
//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=always
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Zcross-crate-inline-threshold=never
|
||||
//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=never
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O -Zcross-crate-inline-threshold=yes
|
||||
//@ compile-flags: -Copt-level=3 -Zcross-crate-inline-threshold=yes
|
||||
//@ aux-build:leaf.rs
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//@ compile-flags: -O
|
||||
//@ compile-flags: -Copt-level=3
|
||||
//@ aux-build:never.rs
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user