Auto merge of #77527 - jonas-schievink:rollup-szgq5he, r=jonas-schievink

Rollup of 8 pull requests

Successful merges:

 - #77072 (Minor `hash_map` doc adjustments + item attribute orderings)
 - #77368 (Backport LLVM apfloat commit to rustc_apfloat)
 - #77445 (BTreeMap: complete the compile-time test_variance test case)
 - #77504 (Support vectors with fewer than 8 elements for simd_select_bitmask)
 - #77513 (Change DocFragments from enum variant fields to structs with a nested enum)
 - #77518 (Only use Fira Sans for the first `td` in item lists)
 - #77521 (Move target feature whitelist from cg_llvm to cg_ssa)
 - #77525 (Enable RenameReturnPlace MIR optimization on mir-opt-level >= 2)

Failed merges:

r? `@ghost`
This commit is contained in:
bors 2020-10-04 13:49:36 +00:00
commit a835b483fe
21 changed files with 440 additions and 320 deletions

View File

@ -1511,11 +1511,16 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
sig::set_bit(&mut r.sig, T::PRECISION - 1); sig::set_bit(&mut r.sig, T::PRECISION - 1);
} }
// gcc forces the Quiet bit on, which means (float)(double)(float_sNan) // Convert of sNaN creates qNaN and raises an exception (invalid op).
// does not give you back the same bits. This is dubious, and we // This also guarantees that a sNaN does not become Inf on a truncation
// don't currently do it. You're really supposed to get // that loses all payload bits.
// an invalid operation signal at runtime, but nobody does that. if self.is_signaling() {
status = Status::OK; // Quiet signaling NaN.
sig::set_bit(&mut r.sig, T::QNAN_BIT);
status = Status::INVALID_OP;
} else {
status = Status::OK;
}
} else { } else {
*loses_info = false; *loses_info = false;
status = Status::OK; status = Status::OK;

View File

@ -566,6 +566,17 @@ fn fma() {
} }
} }
#[test]
fn issue_69532() {
let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128);
let mut loses_info = false;
let sta = f.convert(&mut loses_info);
let r: Single = sta.value;
assert!(loses_info);
assert!(r.is_nan());
assert_eq!(sta.status, Status::INVALID_OP);
}
#[test] #[test]
fn min_num() { fn min_num() {
let f1 = Double::from_f64(1.0); let f1 = Double::from_f64(1.0);
@ -1492,27 +1503,32 @@ fn convert() {
assert_eq!(4294967295.0, test.to_f64()); assert_eq!(4294967295.0, test.to_f64());
assert!(!loses_info); assert!(!loses_info);
let test = Single::snan(None);
let x87_snan = X87DoubleExtended::snan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_snan));
assert!(!loses_info);
let test = Single::qnan(None); let test = Single::qnan(None);
let x87_qnan = X87DoubleExtended::qnan(None); let x87_qnan = X87DoubleExtended::qnan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value; let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_qnan)); assert!(test.bitwise_eq(x87_qnan));
assert!(!loses_info); assert!(!loses_info);
let test = X87DoubleExtended::snan(None); let test = Single::snan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value; let sta = test.convert(&mut loses_info);
assert!(test.bitwise_eq(x87_snan)); let test: X87DoubleExtended = sta.value;
assert!(test.is_nan());
assert!(!test.is_signaling());
assert!(!loses_info); assert!(!loses_info);
assert_eq!(sta.status, Status::INVALID_OP);
let test = X87DoubleExtended::qnan(None); let test = X87DoubleExtended::qnan(None);
let test: X87DoubleExtended = test.convert(&mut loses_info).value; let test: X87DoubleExtended = test.convert(&mut loses_info).value;
assert!(test.bitwise_eq(x87_qnan)); assert!(test.bitwise_eq(x87_qnan));
assert!(!loses_info); assert!(!loses_info);
let test = X87DoubleExtended::snan(None);
let sta = test.convert(&mut loses_info);
let test: X87DoubleExtended = sta.value;
assert!(test.is_nan());
assert!(!test.is_signaling());
assert!(!loses_info);
assert_eq!(sta.status, Status::INVALID_OP);
} }
#[test] #[test]

View File

@ -349,17 +349,15 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
} }
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features};
providers.supported_target_features = |tcx, cnum| { providers.supported_target_features = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE); assert_eq!(cnum, LOCAL_CRATE);
if tcx.sess.opts.actually_rustdoc { if tcx.sess.opts.actually_rustdoc {
// rustdoc needs to be able to document functions that use all the features, so // rustdoc needs to be able to document functions that use all the features, so
// provide them all. // provide them all.
llvm_util::all_known_features().map(|(a, b)| (a.to_string(), b)).collect() all_known_features().map(|(a, b)| (a.to_string(), b)).collect()
} else { } else {
llvm_util::supported_target_features(tcx.sess) supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
.iter()
.map(|&(a, b)| (a.to_string(), b))
.collect()
} }
}; };

View File

@ -793,14 +793,18 @@ fn generic_simd_intrinsic(
require_simd!(arg_tys[1], "argument"); require_simd!(arg_tys[1], "argument");
let v_len = arg_tys[1].simd_size(tcx); let v_len = arg_tys[1].simd_size(tcx);
require!( require!(
m_len == v_len, // Allow masks for vectors with fewer than 8 elements to be
// represented with a u8 or i8.
m_len == v_len || (m_len == 8 && v_len < 8),
"mismatched lengths: mask length `{}` != other vector length `{}`", "mismatched lengths: mask length `{}` != other vector length `{}`",
m_len, m_len,
v_len v_len
); );
let i1 = bx.type_i1(); let i1 = bx.type_i1();
let i1xn = bx.type_vector(i1, m_len); let im = bx.type_ix(v_len);
let m_i1s = bx.bitcast(args[0].immediate(), i1xn); let i1xn = bx.type_vector(i1, v_len);
let m_im = bx.trunc(args[0].immediate(), im);
let m_i1s = bx.bitcast(m_im, i1xn);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
} }

View File

@ -1,12 +1,12 @@
use crate::back::write::create_informational_target_machine; use crate::back::write::create_informational_target_machine;
use crate::llvm; use crate::llvm;
use libc::c_int; use libc::c_int;
use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_feature::UnstableFeatures; use rustc_feature::UnstableFeatures;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_session::config::PrintRequest; use rustc_session::config::PrintRequest;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy}; use rustc_target::spec::{MergeFunctions, PanicStrategy};
use std::ffi::CString; use std::ffi::CString;
@ -139,140 +139,6 @@ pub fn time_trace_profiler_finish(file_name: &str) {
// WARNING: the features after applying `to_llvm_feature` must be known // WARNING: the features after applying `to_llvm_feature` must be known
// to LLVM or the feature detection code will walk past the end of the feature // to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes. // array, leading to crashes.
const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("aclass", Some(sym::arm_target_feature)),
("mclass", Some(sym::arm_target_feature)),
("rclass", Some(sym::arm_target_feature)),
("dsp", Some(sym::arm_target_feature)),
("neon", Some(sym::arm_target_feature)),
("crc", Some(sym::arm_target_feature)),
("crypto", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
("v6t2", Some(sym::arm_target_feature)),
("v7", Some(sym::arm_target_feature)),
("v8", Some(sym::arm_target_feature)),
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
// This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled per-function using #[instruction_set], not
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("fp", Some(sym::aarch64_target_feature)),
("neon", Some(sym::aarch64_target_feature)),
("sve", Some(sym::aarch64_target_feature)),
("crc", Some(sym::aarch64_target_feature)),
("crypto", Some(sym::aarch64_target_feature)),
("ras", Some(sym::aarch64_target_feature)),
("lse", Some(sym::aarch64_target_feature)),
("rdm", Some(sym::aarch64_target_feature)),
("fp16", Some(sym::aarch64_target_feature)),
("rcpc", Some(sym::aarch64_target_feature)),
("dotprod", Some(sym::aarch64_target_feature)),
("tme", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("adx", Some(sym::adx_target_feature)),
("aes", None),
("avx", None),
("avx2", None),
("avx512bw", Some(sym::avx512_target_feature)),
("avx512cd", Some(sym::avx512_target_feature)),
("avx512dq", Some(sym::avx512_target_feature)),
("avx512er", Some(sym::avx512_target_feature)),
("avx512f", Some(sym::avx512_target_feature)),
("avx512ifma", Some(sym::avx512_target_feature)),
("avx512pf", Some(sym::avx512_target_feature)),
("avx512vbmi", Some(sym::avx512_target_feature)),
("avx512vl", Some(sym::avx512_target_feature)),
("avx512vpopcntdq", Some(sym::avx512_target_feature)),
("bmi1", None),
("bmi2", None),
("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
("f16c", Some(sym::f16c_target_feature)),
("fma", None),
("fxsr", None),
("lzcnt", None),
("movbe", Some(sym::movbe_target_feature)),
("pclmulqdq", None),
("popcnt", None),
("rdrand", None),
("rdseed", None),
("rtm", Some(sym::rtm_target_feature)),
("sha", None),
("sse", None),
("sse2", None),
("sse3", None),
("sse4.1", None),
("sse4.2", None),
("sse4a", Some(sym::sse4a_target_feature)),
("ssse3", None),
("tbm", Some(sym::tbm_target_feature)),
("xsave", None),
("xsavec", None),
("xsaveopt", None),
("xsaves", None),
];
const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("hvx", Some(sym::hexagon_target_feature)),
("hvx-length128b", Some(sym::hexagon_target_feature)),
];
const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("altivec", Some(sym::powerpc_target_feature)),
("power8-altivec", Some(sym::powerpc_target_feature)),
("power9-altivec", Some(sym::powerpc_target_feature)),
("power8-vector", Some(sym::powerpc_target_feature)),
("power9-vector", Some(sym::powerpc_target_feature)),
("vsx", Some(sym::powerpc_target_feature)),
];
const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
&[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("m", Some(sym::riscv_target_feature)),
("a", Some(sym::riscv_target_feature)),
("c", Some(sym::riscv_target_feature)),
("f", Some(sym::riscv_target_feature)),
("d", Some(sym::riscv_target_feature)),
("e", Some(sym::riscv_target_feature)),
];
const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("simd128", Some(sym::wasm_target_feature)),
("atomics", Some(sym::wasm_target_feature)),
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
std::iter::empty()
.chain(ARM_ALLOWED_FEATURES.iter())
.chain(AARCH64_ALLOWED_FEATURES.iter())
.chain(X86_ALLOWED_FEATURES.iter())
.chain(HEXAGON_ALLOWED_FEATURES.iter())
.chain(POWERPC_ALLOWED_FEATURES.iter())
.chain(MIPS_ALLOWED_FEATURES.iter())
.chain(RISCV_ALLOWED_FEATURES.iter())
.chain(WASM_ALLOWED_FEATURES.iter())
.cloned()
}
pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch }; let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch };
match (arch, s) { match (arch, s) {
@ -306,20 +172,6 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
.collect() .collect()
} }
pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
match &*sess.target.target.arch {
"arm" => ARM_ALLOWED_FEATURES,
"aarch64" => AARCH64_ALLOWED_FEATURES,
"x86" | "x86_64" => X86_ALLOWED_FEATURES,
"hexagon" => HEXAGON_ALLOWED_FEATURES,
"mips" | "mips64" => MIPS_ALLOWED_FEATURES,
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
"wasm32" => WASM_ALLOWED_FEATURES,
_ => &[],
}
}
pub fn print_version() { pub fn print_version() {
// Can be called without initializing LLVM // Can be called without initializing LLVM
unsafe { unsafe {

View File

@ -42,6 +42,7 @@ pub mod glue;
pub mod meth; pub mod meth;
pub mod mir; pub mod mir;
pub mod mono_item; pub mod mono_item;
pub mod target_features;
pub mod traits; pub mod traits;
pub struct ModuleCodegen<M> { pub struct ModuleCodegen<M> {

View File

@ -0,0 +1,150 @@
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::symbol::Symbol;
const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("aclass", Some(sym::arm_target_feature)),
("mclass", Some(sym::arm_target_feature)),
("rclass", Some(sym::arm_target_feature)),
("dsp", Some(sym::arm_target_feature)),
("neon", Some(sym::arm_target_feature)),
("crc", Some(sym::arm_target_feature)),
("crypto", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
("v6t2", Some(sym::arm_target_feature)),
("v7", Some(sym::arm_target_feature)),
("v8", Some(sym::arm_target_feature)),
("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)),
("vfp4", Some(sym::arm_target_feature)),
// This is needed for inline assembly, but shouldn't be stabilized as-is
// since it should be enabled per-function using #[instruction_set], not
// #[target_feature].
("thumb-mode", Some(sym::arm_target_feature)),
];
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("fp", Some(sym::aarch64_target_feature)),
("neon", Some(sym::aarch64_target_feature)),
("sve", Some(sym::aarch64_target_feature)),
("crc", Some(sym::aarch64_target_feature)),
("crypto", Some(sym::aarch64_target_feature)),
("ras", Some(sym::aarch64_target_feature)),
("lse", Some(sym::aarch64_target_feature)),
("rdm", Some(sym::aarch64_target_feature)),
("fp16", Some(sym::aarch64_target_feature)),
("rcpc", Some(sym::aarch64_target_feature)),
("dotprod", Some(sym::aarch64_target_feature)),
("tme", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("adx", Some(sym::adx_target_feature)),
("aes", None),
("avx", None),
("avx2", None),
("avx512bw", Some(sym::avx512_target_feature)),
("avx512cd", Some(sym::avx512_target_feature)),
("avx512dq", Some(sym::avx512_target_feature)),
("avx512er", Some(sym::avx512_target_feature)),
("avx512f", Some(sym::avx512_target_feature)),
("avx512ifma", Some(sym::avx512_target_feature)),
("avx512pf", Some(sym::avx512_target_feature)),
("avx512vbmi", Some(sym::avx512_target_feature)),
("avx512vl", Some(sym::avx512_target_feature)),
("avx512vpopcntdq", Some(sym::avx512_target_feature)),
("bmi1", None),
("bmi2", None),
("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
("f16c", Some(sym::f16c_target_feature)),
("fma", None),
("fxsr", None),
("lzcnt", None),
("movbe", Some(sym::movbe_target_feature)),
("pclmulqdq", None),
("popcnt", None),
("rdrand", None),
("rdseed", None),
("rtm", Some(sym::rtm_target_feature)),
("sha", None),
("sse", None),
("sse2", None),
("sse3", None),
("sse4.1", None),
("sse4.2", None),
("sse4a", Some(sym::sse4a_target_feature)),
("ssse3", None),
("tbm", Some(sym::tbm_target_feature)),
("xsave", None),
("xsavec", None),
("xsaveopt", None),
("xsaves", None),
];
const HEXAGON_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("hvx", Some(sym::hexagon_target_feature)),
("hvx-length128b", Some(sym::hexagon_target_feature)),
];
const POWERPC_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("altivec", Some(sym::powerpc_target_feature)),
("power8-altivec", Some(sym::powerpc_target_feature)),
("power9-altivec", Some(sym::powerpc_target_feature)),
("power8-vector", Some(sym::powerpc_target_feature)),
("power9-vector", Some(sym::powerpc_target_feature)),
("vsx", Some(sym::powerpc_target_feature)),
];
const MIPS_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] =
&[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))];
const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("m", Some(sym::riscv_target_feature)),
("a", Some(sym::riscv_target_feature)),
("c", Some(sym::riscv_target_feature)),
("f", Some(sym::riscv_target_feature)),
("d", Some(sym::riscv_target_feature)),
("e", Some(sym::riscv_target_feature)),
];
const WASM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("simd128", Some(sym::wasm_target_feature)),
("atomics", Some(sym::wasm_target_feature)),
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
];
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented.
///
/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol>)> {
std::iter::empty()
.chain(ARM_ALLOWED_FEATURES.iter())
.chain(AARCH64_ALLOWED_FEATURES.iter())
.chain(X86_ALLOWED_FEATURES.iter())
.chain(HEXAGON_ALLOWED_FEATURES.iter())
.chain(POWERPC_ALLOWED_FEATURES.iter())
.chain(MIPS_ALLOWED_FEATURES.iter())
.chain(RISCV_ALLOWED_FEATURES.iter())
.chain(WASM_ALLOWED_FEATURES.iter())
.cloned()
}
pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] {
match &*sess.target.target.arch {
"arm" => ARM_ALLOWED_FEATURES,
"aarch64" => AARCH64_ALLOWED_FEATURES,
"x86" | "x86_64" => X86_ALLOWED_FEATURES,
"hexagon" => HEXAGON_ALLOWED_FEATURES,
"mips" | "mips64" => MIPS_ALLOWED_FEATURES,
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
"wasm32" => WASM_ALLOWED_FEATURES,
_ => &[],
}
}

View File

@ -36,12 +36,6 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
return; return;
} }
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
// The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and
// fails some asserts).
return;
}
let returned_local = match local_eligible_for_nrvo(body) { let returned_local = match local_eligible_for_nrvo(body) {
Some(l) => l, Some(l) => l,
None => { None => {

View File

@ -1,12 +1,10 @@
use super::super::{navigate::Position, node, DeterministicRng};
use super::Entry::{Occupied, Vacant};
use super::*;
use crate::boxed::Box; use crate::boxed::Box;
use crate::collections::btree::navigate::Position;
use crate::collections::btree::node;
use crate::collections::btree_map::Entry::{Occupied, Vacant};
use crate::collections::BTreeMap;
use crate::fmt::Debug; use crate::fmt::Debug;
use crate::rc::Rc; use crate::rc::Rc;
use crate::string::String; use crate::string::{String, ToString};
use crate::string::ToString;
use crate::vec::Vec; use crate::vec::Vec;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::iter::FromIterator; use std::iter::FromIterator;
@ -16,19 +14,17 @@ use std::ops::RangeBounds;
use std::panic::{catch_unwind, AssertUnwindSafe}; use std::panic::{catch_unwind, AssertUnwindSafe};
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use super::super::DeterministicRng;
// Capacity of a tree with a single level, // Capacity of a tree with a single level,
// i.e. a tree who's root is a leaf node at height 0. // i.e., a tree who's root is a leaf node at height 0.
const NODE_CAPACITY: usize = node::CAPACITY; const NODE_CAPACITY: usize = node::CAPACITY;
// Minimum number of elements to insert, to guarantee a tree with 2 levels, // Minimum number of elements to insert, to guarantee a tree with 2 levels,
// i.e. a tree who's root is an internal node at height 1, with edges to leaf nodes. // i.e., a tree who's root is an internal node at height 1, with edges to leaf nodes.
// It's not the minimum size: removing an element from such a tree does not always reduce height. // It's not the minimum size: removing an element from such a tree does not always reduce height.
const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1; const MIN_INSERTS_HEIGHT_1: usize = NODE_CAPACITY + 1;
// Minimum number of elements to insert in ascending order, to guarantee a tree with 3 levels, // Minimum number of elements to insert in ascending order, to guarantee a tree with 3 levels,
// i.e. a tree who's root is an internal node at height 2, with edges to more internal nodes. // i.e., a tree who's root is an internal node at height 2, with edges to more internal nodes.
// It's not the minimum size: removing an element from such a tree does not always reduce height. // It's not the minimum size: removing an element from such a tree does not always reduce height.
const MIN_INSERTS_HEIGHT_2: usize = 89; const MIN_INSERTS_HEIGHT_2: usize = 89;
@ -1386,44 +1382,65 @@ fn test_clone_from() {
} }
} }
#[test]
#[allow(dead_code)] #[allow(dead_code)]
fn test_variance() { fn test_variance() {
use std::collections::btree_map::{IntoIter, Iter, Keys, Range, Values};
fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> { fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> {
v v
} }
fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> { fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> {
v v
} }
fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> { fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> {
v v
} }
fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> { fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> {
v v
} }
fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> { fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> {
v v
} }
fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> { fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> {
v v
} }
fn into_keys_key<'new>(v: IntoKeys<&'static str, ()>) -> IntoKeys<&'new str, ()> {
v
}
fn into_keys_val<'new>(v: IntoKeys<(), &'static str>) -> IntoKeys<(), &'new str> {
v
}
fn into_values_key<'new>(v: IntoValues<&'static str, ()>) -> IntoValues<&'new str, ()> {
v
}
fn into_values_val<'new>(v: IntoValues<(), &'static str>) -> IntoValues<(), &'new str> {
v
}
fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> { fn range_key<'a, 'new>(v: Range<'a, &'static str, ()>) -> Range<'a, &'new str, ()> {
v v
} }
fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> { fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> {
v v
} }
fn keys<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
fn keys_key<'a, 'new>(v: Keys<'a, &'static str, ()>) -> Keys<'a, &'new str, ()> {
v v
} }
fn vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { fn keys_val<'a, 'new>(v: Keys<'a, (), &'static str>) -> Keys<'a, (), &'new str> {
v
}
fn values_key<'a, 'new>(v: Values<'a, &'static str, ()>) -> Values<'a, &'new str, ()> {
v
}
fn values_val<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> {
v v
} }
} }
#[test]
#[allow(dead_code)] #[allow(dead_code)]
fn test_sync() { fn test_sync() {
fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ { fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
@ -1493,7 +1510,6 @@ fn test_sync() {
} }
} }
#[test]
#[allow(dead_code)] #[allow(dead_code)]
fn test_send() { fn test_send() {
fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send { fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
@ -1520,7 +1536,7 @@ fn test_send() {
v.iter() v.iter()
} }
fn iter_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ { fn iter_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
v.iter_mut() v.iter_mut()
} }
@ -1532,7 +1548,7 @@ fn test_send() {
v.values() v.values()
} }
fn values_mut<T: Send + Sync>(v: &mut BTreeMap<T, T>) -> impl Send + '_ { fn values_mut<T: Send>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
v.values_mut() v.values_mut()
} }
@ -1540,7 +1556,7 @@ fn test_send() {
v.range(..) v.range(..)
} }
fn range_mut<T: Send + Sync + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ { fn range_mut<T: Send + Ord>(v: &mut BTreeMap<T, T>) -> impl Send + '_ {
v.range_mut(..) v.range_mut(..)
} }

View File

@ -1,11 +1,10 @@
use crate::collections::BTreeSet; use super::super::DeterministicRng;
use super::*;
use crate::vec::Vec; use crate::vec::Vec;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::panic::{catch_unwind, AssertUnwindSafe}; use std::panic::{catch_unwind, AssertUnwindSafe};
use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::atomic::{AtomicU32, Ordering};
use super::super::DeterministicRng;
#[test] #[test]
fn test_clone_eq() { fn test_clone_eq() {
let mut m = BTreeSet::new(); let mut m = BTreeSet::new();
@ -528,11 +527,8 @@ fn test_recovery() {
assert_eq!(s.iter().next(), None); assert_eq!(s.iter().next(), None);
} }
#[test]
#[allow(dead_code)] #[allow(dead_code)]
fn test_variance() { fn test_variance() {
use std::collections::btree_set::{IntoIter, Iter, Range};
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
v v
} }
@ -545,6 +541,85 @@ fn test_variance() {
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
v v
} }
// not applied to Difference, Intersection, SymmetricDifference, Union
}
#[allow(dead_code)]
fn test_sync() {
fn set<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
v
}
fn iter<T: Sync>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.iter()
}
fn into_iter<T: Sync>(v: BTreeSet<T>) -> impl Sync {
v.into_iter()
}
fn range<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.range(..)
}
fn drain_filter<T: Sync + Ord>(v: &mut BTreeSet<T>) -> impl Sync + '_ {
v.drain_filter(|_| false)
}
fn difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.difference(&v)
}
fn intersection<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.intersection(&v)
}
fn symmetric_difference<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.symmetric_difference(&v)
}
fn union<T: Sync + Ord>(v: &BTreeSet<T>) -> impl Sync + '_ {
v.union(&v)
}
}
#[allow(dead_code)]
fn test_send() {
fn set<T: Send>(v: BTreeSet<T>) -> impl Send {
v
}
fn iter<T: Send + Sync>(v: &BTreeSet<T>) -> impl Send + '_ {
v.iter()
}
fn into_iter<T: Send>(v: BTreeSet<T>) -> impl Send {
v.into_iter()
}
fn range<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
v.range(..)
}
fn drain_filter<T: Send + Ord>(v: &mut BTreeSet<T>) -> impl Send + '_ {
v.drain_filter(|_| false)
}
fn difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
v.difference(&v)
}
fn intersection<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
v.intersection(&v)
}
fn symmetric_difference<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
v.symmetric_difference(&v)
}
fn union<T: Send + Sync + Ord>(v: &BTreeSet<T>) -> impl Send + '_ {
v.union(&v)
}
} }
#[test] #[test]

View File

@ -554,8 +554,8 @@ impl<K, V, S> HashMap<K, V, S> {
/// a.clear(); /// a.clear();
/// assert!(a.is_empty()); /// assert!(a.is_empty());
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.base.clear(); self.base.clear();
} }
@ -746,8 +746,8 @@ where
/// assert_eq!(map.get_key_value(&1), Some((&1, &"a"))); /// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
/// assert_eq!(map.get_key_value(&2), None); /// assert_eq!(map.get_key_value(&2), None);
/// ``` /// ```
#[stable(feature = "map_get_key_value", since = "1.40.0")]
#[inline] #[inline]
#[stable(feature = "map_get_key_value", since = "1.40.0")]
pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)> pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
where where
K: Borrow<Q>, K: Borrow<Q>,
@ -772,8 +772,8 @@ where
/// assert_eq!(map.contains_key(&1), true); /// assert_eq!(map.contains_key(&1), true);
/// assert_eq!(map.contains_key(&2), false); /// assert_eq!(map.contains_key(&2), false);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where where
K: Borrow<Q>, K: Borrow<Q>,
@ -800,8 +800,8 @@ where
/// } /// }
/// assert_eq!(map[&1], "b"); /// assert_eq!(map[&1], "b");
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V> pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
where where
K: Borrow<Q>, K: Borrow<Q>,
@ -834,8 +834,8 @@ where
/// assert_eq!(map.insert(37, "c"), Some("b")); /// assert_eq!(map.insert(37, "c"), Some("b"));
/// assert_eq!(map[&37], "c"); /// assert_eq!(map[&37], "c");
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn insert(&mut self, k: K, v: V) -> Option<V> { pub fn insert(&mut self, k: K, v: V) -> Option<V> {
self.base.insert(k, v) self.base.insert(k, v)
} }
@ -857,8 +857,8 @@ where
/// assert_eq!(map.remove(&1), Some("a")); /// assert_eq!(map.remove(&1), Some("a"));
/// assert_eq!(map.remove(&1), None); /// assert_eq!(map.remove(&1), None);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V> pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
where where
K: Borrow<Q>, K: Borrow<Q>,
@ -886,8 +886,8 @@ where
/// assert_eq!(map.remove(&1), None); /// assert_eq!(map.remove(&1), None);
/// # } /// # }
/// ``` /// ```
#[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
#[inline] #[inline]
#[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)> pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
where where
K: Borrow<Q>, K: Borrow<Q>,
@ -909,8 +909,8 @@ where
/// map.retain(|&k, _| k % 2 == 0); /// map.retain(|&k, _| k % 2 == 0);
/// assert_eq!(map.len(), 4); /// assert_eq!(map.len(), 4);
/// ``` /// ```
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
#[inline] #[inline]
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
pub fn retain<F>(&mut self, f: F) pub fn retain<F>(&mut self, f: F)
where where
F: FnMut(&K, &mut V) -> bool, F: FnMut(&K, &mut V) -> bool,
@ -1647,7 +1647,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
self.base.get() self.base.get()
} }
/// Converts the OccupiedEntry into a mutable reference to the value in the entry /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
/// with a lifetime bound to the map itself. /// with a lifetime bound to the map itself.
#[inline] #[inline]
#[unstable(feature = "hash_raw_entry", issue = "56167")] #[unstable(feature = "hash_raw_entry", issue = "56167")]
@ -1676,7 +1676,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
self.base.get_key_value_mut() self.base.get_key_value_mut()
} }
/// Converts the OccupiedEntry into a mutable reference to the key and value in the entry /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry
/// with a lifetime bound to the map itself. /// with a lifetime bound to the map itself.
#[inline] #[inline]
#[unstable(feature = "hash_raw_entry", issue = "56167")] #[unstable(feature = "hash_raw_entry", issue = "56167")]
@ -1714,7 +1714,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
} }
impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
/// Sets the value of the entry with the VacantEntry's key, /// Sets the value of the entry with the `VacantEntry`'s key,
/// and returns a mutable reference to it. /// and returns a mutable reference to it.
#[inline] #[inline]
#[unstable(feature = "hash_raw_entry", issue = "56167")] #[unstable(feature = "hash_raw_entry", issue = "56167")]
@ -2173,7 +2173,6 @@ where
} }
impl<'a, K, V> Entry<'a, K, V> { impl<'a, K, V> Entry<'a, K, V> {
#[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the default if empty, and returns /// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry. /// a mutable reference to the value in the entry.
/// ///
@ -2191,6 +2190,7 @@ impl<'a, K, V> Entry<'a, K, V> {
/// assert_eq!(map["poneyland"], 6); /// assert_eq!(map["poneyland"], 6);
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn or_insert(self, default: V) -> &'a mut V { pub fn or_insert(self, default: V) -> &'a mut V {
match self { match self {
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
@ -2198,7 +2198,6 @@ impl<'a, K, V> Entry<'a, K, V> {
} }
} }
#[stable(feature = "rust1", since = "1.0.0")]
/// Ensures a value is in the entry by inserting the result of the default function if empty, /// Ensures a value is in the entry by inserting the result of the default function if empty,
/// and returns a mutable reference to the value in the entry. /// and returns a mutable reference to the value in the entry.
/// ///
@ -2215,6 +2214,7 @@ impl<'a, K, V> Entry<'a, K, V> {
/// assert_eq!(map["poneyland"], "hoho".to_string()); /// assert_eq!(map["poneyland"], "hoho".to_string());
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
match self { match self {
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
@ -2222,7 +2222,6 @@ impl<'a, K, V> Entry<'a, K, V> {
} }
} }
#[unstable(feature = "or_insert_with_key", issue = "71024")]
/// Ensures a value is in the entry by inserting, if empty, the result of the default function, /// Ensures a value is in the entry by inserting, if empty, the result of the default function,
/// which takes the key as its argument, and returns a mutable reference to the value in the /// which takes the key as its argument, and returns a mutable reference to the value in the
/// entry. /// entry.
@ -2240,6 +2239,7 @@ impl<'a, K, V> Entry<'a, K, V> {
/// assert_eq!(map["poneyland"], 9); /// assert_eq!(map["poneyland"], 9);
/// ``` /// ```
#[inline] #[inline]
#[unstable(feature = "or_insert_with_key", issue = "71024")]
pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V { pub fn or_insert_with_key<F: FnOnce(&K) -> V>(self, default: F) -> &'a mut V {
match self { match self {
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
@ -2304,7 +2304,7 @@ impl<'a, K, V> Entry<'a, K, V> {
} }
} }
/// Sets the value of the entry, and returns an OccupiedEntry. /// Sets the value of the entry, and returns an `OccupiedEntry`.
/// ///
/// # Examples /// # Examples
/// ///
@ -2331,7 +2331,6 @@ impl<'a, K, V> Entry<'a, K, V> {
} }
impl<'a, K, V: Default> Entry<'a, K, V> { impl<'a, K, V: Default> Entry<'a, K, V> {
#[stable(feature = "entry_or_default", since = "1.28.0")]
/// Ensures a value is in the entry by inserting the default value if empty, /// Ensures a value is in the entry by inserting the default value if empty,
/// and returns a mutable reference to the value in the entry. /// and returns a mutable reference to the value in the entry.
/// ///
@ -2348,6 +2347,7 @@ impl<'a, K, V: Default> Entry<'a, K, V> {
/// # } /// # }
/// ``` /// ```
#[inline] #[inline]
#[stable(feature = "entry_or_default", since = "1.28.0")]
pub fn or_default(self) -> &'a mut V { pub fn or_default(self) -> &'a mut V {
match self { match self {
Occupied(entry) => entry.into_mut(), Occupied(entry) => entry.into_mut(),
@ -2452,7 +2452,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
self.base.get_mut() self.base.get_mut()
} }
/// Converts the OccupiedEntry into a mutable reference to the value in the entry /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry
/// with a lifetime bound to the map itself. /// with a lifetime bound to the map itself.
/// ///
/// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
@ -2624,7 +2624,7 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
self.base.into_key() self.base.into_key()
} }
/// Sets the value of the entry with the VacantEntry's key, /// Sets the value of the entry with the `VacantEntry`'s key,
/// and returns a mutable reference to it. /// and returns a mutable reference to it.
/// ///
/// # Examples /// # Examples
@ -2646,8 +2646,8 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
self.base.insert(value) self.base.insert(value)
} }
/// Sets the value of the entry with the VacantEntry's key, /// Sets the value of the entry with the `VacantEntry`'s key,
/// and returns an OccupiedEntry. /// and returns an `OccupiedEntry`.
/// ///
/// # Examples /// # Examples
/// ///

View File

@ -370,32 +370,22 @@ impl<I: IntoIterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
/// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are /// information can be given when a doctest fails. Sugared doc comments and "raw" doc comments are
/// kept separate because of issue #42760. /// kept separate because of issue #42760.
#[derive(Clone, PartialEq, Eq, Debug, Hash)] #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub enum DocFragment { pub struct DocFragment {
/// A doc fragment created from a `///` or `//!` doc comment. pub line: usize,
SugaredDoc(usize, rustc_span::Span, String), pub span: rustc_span::Span,
/// A doc fragment created from a "raw" `#[doc=""]` attribute. pub doc: String,
RawDoc(usize, rustc_span::Span, String), pub kind: DocFragmentKind,
/// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
/// given filename and the file contents.
Include(usize, rustc_span::Span, String, String),
} }
impl DocFragment { #[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub fn as_str(&self) -> &str { pub enum DocFragmentKind {
match *self { /// A doc fragment created from a `///` or `//!` doc comment.
DocFragment::SugaredDoc(_, _, ref s) => &s[..], SugaredDoc,
DocFragment::RawDoc(_, _, ref s) => &s[..], /// A doc fragment created from a "raw" `#[doc=""]` attribute.
DocFragment::Include(_, _, _, ref s) => &s[..], RawDoc,
} /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
} /// given filename and the file contents.
Include { filename: String },
pub fn span(&self) -> rustc_span::Span {
match *self {
DocFragment::SugaredDoc(_, span, _)
| DocFragment::RawDoc(_, span, _)
| DocFragment::Include(_, span, _, _) => span,
}
}
} }
impl<'a> FromIterator<&'a DocFragment> for String { impl<'a> FromIterator<&'a DocFragment> for String {
@ -407,12 +397,7 @@ impl<'a> FromIterator<&'a DocFragment> for String {
if !acc.is_empty() { if !acc.is_empty() {
acc.push('\n'); acc.push('\n');
} }
match *frag { acc.push_str(&frag.doc);
DocFragment::SugaredDoc(_, _, ref docs)
| DocFragment::RawDoc(_, _, ref docs)
| DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs),
}
acc acc
}) })
} }
@ -547,15 +532,15 @@ impl Attributes {
.filter_map(|attr| { .filter_map(|attr| {
if let Some(value) = attr.doc_str() { if let Some(value) = attr.doc_str() {
let value = beautify_doc_string(value); let value = beautify_doc_string(value);
let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() { let kind = if attr.is_doc_comment() {
DocFragment::SugaredDoc DocFragmentKind::SugaredDoc
} else { } else {
DocFragment::RawDoc DocFragmentKind::RawDoc
}; };
let line = doc_line; let line = doc_line;
doc_line += value.lines().count(); doc_line += value.lines().count();
doc_strings.push(mk_fragment(line, attr.span, value)); doc_strings.push(DocFragment { line, span: attr.span, doc: value, kind });
if sp.is_none() { if sp.is_none() {
sp = Some(attr.span); sp = Some(attr.span);
@ -575,9 +560,12 @@ impl Attributes {
{ {
let line = doc_line; let line = doc_line;
doc_line += contents.lines().count(); doc_line += contents.lines().count();
doc_strings.push(DocFragment::Include( doc_strings.push(DocFragment {
line, attr.span, filename, contents, line,
)); span: attr.span,
doc: contents,
kind: DocFragmentKind::Include { filename },
});
} }
} }
} }
@ -621,7 +609,7 @@ impl Attributes {
/// Finds the `doc` attribute as a NameValue and returns the corresponding /// Finds the `doc` attribute as a NameValue and returns the corresponding
/// value found. /// value found.
pub fn doc_value(&self) -> Option<&str> { pub fn doc_value(&self) -> Option<&str> {
self.doc_strings.first().map(|s| s.as_str()) self.doc_strings.first().map(|s| s.doc.as_str())
} }
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined /// Finds all `doc` attributes as NameValues and returns their corresponding values, joined

View File

@ -120,7 +120,7 @@ h3.impl, h3.method, h3.type {
} }
h1, h2, h3, h4, h1, h2, h3, h4,
.sidebar, a.source, .search-input, .content table :not(code)>a, .sidebar, a.source, .search-input, .content table td:first-child > a,
.collapse-toggle, div.item-list .out-of-band, .collapse-toggle, div.item-list .out-of-band,
#source-sidebar, #sidebar-toggle { #source-sidebar, #sidebar-toggle {
font-family: "Fira Sans", sans-serif; font-family: "Fira Sans", sans-serif;

View File

@ -232,7 +232,12 @@ impl fold::DocFolder for CoverageCalculator {
let mut tests = Tests { found_tests: 0 }; let mut tests = Tests { found_tests: 0 };
find_testable_code( find_testable_code(
&i.attrs.doc_strings.iter().map(|d| d.as_str()).collect::<Vec<_>>().join("\n"), &i.attrs
.doc_strings
.iter()
.map(|d| d.doc.as_str())
.collect::<Vec<_>>()
.join("\n"),
&mut tests, &mut tests,
ErrorCodes::No, ErrorCodes::No,
false, false,

View File

@ -1,4 +1,4 @@
use crate::clean::{self, DocFragment, Item}; use crate::clean::{self, DocFragment, DocFragmentKind, Item};
use crate::core::DocContext; use crate::core::DocContext;
use crate::fold; use crate::fold;
use crate::fold::DocFolder; use crate::fold::DocFolder;
@ -12,23 +12,6 @@ pub const COLLAPSE_DOCS: Pass = Pass {
description: "concatenates all document attributes into one document attribute", description: "concatenates all document attributes into one document attribute",
}; };
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum DocFragmentKind {
Sugared,
Raw,
Include,
}
impl DocFragment {
fn kind(&self) -> DocFragmentKind {
match *self {
DocFragment::SugaredDoc(..) => DocFragmentKind::Sugared,
DocFragment::RawDoc(..) => DocFragmentKind::Raw,
DocFragment::Include(..) => DocFragmentKind::Include,
}
}
}
pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate { pub fn collapse_docs(krate: clean::Crate, _: &DocContext<'_>) -> clean::Crate {
let mut krate = Collapser.fold_crate(krate); let mut krate = Collapser.fold_crate(krate);
krate.collapsed = true; krate.collapsed = true;
@ -50,30 +33,22 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
for frag in take(doc_strings) { for frag in take(doc_strings) {
if let Some(mut curr_frag) = last_frag.take() { if let Some(mut curr_frag) = last_frag.take() {
let curr_kind = curr_frag.kind(); let curr_kind = &curr_frag.kind;
let new_kind = frag.kind(); let new_kind = &frag.kind;
if curr_kind == DocFragmentKind::Include || curr_kind != new_kind { if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
match curr_frag { if *curr_kind == DocFragmentKind::SugaredDoc
DocFragment::SugaredDoc(_, _, ref mut doc_string) || *curr_kind == DocFragmentKind::RawDoc
| DocFragment::RawDoc(_, _, ref mut doc_string) => { {
// add a newline for extra padding between segments // add a newline for extra padding between segments
doc_string.push('\n'); curr_frag.doc.push('\n');
}
_ => {}
} }
docs.push(curr_frag); docs.push(curr_frag);
last_frag = Some(frag); last_frag = Some(frag);
} else { } else {
match curr_frag { curr_frag.doc.push('\n');
DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string) curr_frag.doc.push_str(&frag.doc);
| DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => { curr_frag.span = curr_frag.span.to(frag.span);
doc_string.push('\n');
doc_string.push_str(frag.as_str());
*span = span.to(frag.span());
}
_ => unreachable!(),
}
last_frag = Some(curr_frag); last_frag = Some(curr_frag);
} }
} else { } else {

View File

@ -8,7 +8,7 @@ use std::mem;
use std::ops::Range; use std::ops::Range;
use self::Condition::*; use self::Condition::*;
use crate::clean::{self, GetDefId, Item}; use crate::clean::{self, DocFragmentKind, GetDefId, Item};
use crate::core::DocContext; use crate::core::DocContext;
use crate::fold::{DocFolder, StripItem}; use crate::fold::{DocFolder, StripItem};
@ -314,11 +314,11 @@ crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> {
if attrs.doc_strings.is_empty() { if attrs.doc_strings.is_empty() {
return None; return None;
} }
let start = attrs.doc_strings[0].span(); let start = attrs.doc_strings[0].span;
if start == DUMMY_SP { if start == DUMMY_SP {
return None; return None;
} }
let end = attrs.doc_strings.last().expect("no doc strings provided").span(); let end = attrs.doc_strings.last().expect("no doc strings provided").span;
Some(start.to(end)) Some(start.to(end))
} }
@ -333,10 +333,8 @@ crate fn source_span_for_markdown_range(
md_range: &Range<usize>, md_range: &Range<usize>,
attrs: &clean::Attributes, attrs: &clean::Attributes,
) -> Option<Span> { ) -> Option<Span> {
let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag { let is_all_sugared_doc =
clean::DocFragment::SugaredDoc(..) => true, attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
_ => false,
});
if !is_all_sugared_doc { if !is_all_sugared_doc {
return None; return None;

View File

@ -36,13 +36,7 @@ impl clean::Attributes {
fn unindent_fragments(docs: &mut Vec<DocFragment>) { fn unindent_fragments(docs: &mut Vec<DocFragment>) {
for fragment in docs { for fragment in docs {
match *fragment { fragment.doc = unindent(&fragment.doc);
DocFragment::SugaredDoc(_, _, ref mut doc_string)
| DocFragment::RawDoc(_, _, ref mut doc_string)
| DocFragment::Include(_, _, _, ref mut doc_string) => {
*doc_string = unindent(doc_string)
}
}
} }
} }

View File

@ -0,0 +1,24 @@
// run-pass
#![feature(const_fn_transmute)]
const fn make_nans() -> (f64, f64, f32, f32) {
let nan1: f64 = unsafe { std::mem::transmute(0x7FF0_0001_0000_0001u64) };
let nan2: f64 = unsafe { std::mem::transmute(0x7FF0_0000_0000_0001u64) };
let nan1_32 = nan1 as f32;
let nan2_32 = nan2 as f32;
(nan1, nan2, nan1_32, nan2_32)
}
static NANS: (f64, f64, f32, f32) = make_nans();
fn main() {
let (nan1, nan2, nan1_32, nan2_32) = NANS;
assert!(nan1.is_nan());
assert!(nan2.is_nan());
assert!(nan1_32.is_nan());
assert!(nan2_32.is_nan());
}

View File

@ -49,8 +49,8 @@ fn main() {
simd_select(m4, 0u32, 1u32); simd_select(m4, 0u32, 1u32);
//~^ ERROR found non-SIMD `u32` //~^ ERROR found non-SIMD `u32`
simd_select_bitmask(0u8, x, x); simd_select_bitmask(0u16, x, x);
//~^ ERROR mask length `8` != other vector length `4` //~^ ERROR mask length `16` != other vector length `4`
// //
simd_select_bitmask(0u8, 1u32, 2u32); simd_select_bitmask(0u8, 1u32, 2u32);
//~^ ERROR found non-SIMD `u32` //~^ ERROR found non-SIMD `u32`

View File

@ -22,11 +22,11 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD
LL | simd_select(m4, 0u32, 1u32); LL | simd_select(m4, 0u32, 1u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `8` != other vector length `4` error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: mismatched lengths: mask length `16` != other vector length `4`
--> $DIR/simd-intrinsic-generic-select.rs:52:9 --> $DIR/simd-intrinsic-generic-select.rs:52:9
| |
LL | simd_select_bitmask(0u8, x, x); LL | simd_select_bitmask(0u16, x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
--> $DIR/simd-intrinsic-generic-select.rs:55:9 --> $DIR/simd-intrinsic-generic-select.rs:55:9

View File

@ -167,4 +167,29 @@ fn main() {
let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7); let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
assert_eq!(r, e); assert_eq!(r, e);
} }
unsafe {
let a = u32x4(0, 1, 2, 3);
let b = u32x4(4, 5, 6, 7);
let r: u32x4 = simd_select_bitmask(0u8, a, b);
let e = b;
assert_eq!(r, e);
let r: u32x4 = simd_select_bitmask(0xfu8, a, b);
let e = a;
assert_eq!(r, e);
let r: u32x4 = simd_select_bitmask(0b0101u8, a, b);
let e = u32x4(0, 5, 2, 7);
assert_eq!(r, e);
let r: u32x4 = simd_select_bitmask(0b1010u8, a, b);
let e = u32x4(4, 1, 6, 3);
assert_eq!(r, e);
let r: u32x4 = simd_select_bitmask(0b1100u8, a, b);
let e = u32x4(4, 5, 2, 3);
assert_eq!(r, e);
}
} }