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:
commit
a835b483fe
|
@ -1511,11 +1511,16 @@ impl<S: Semantics, T: Semantics> FloatConvert<IeeeFloat<T>> for IeeeFloat<S> {
|
|||
sig::set_bit(&mut r.sig, T::PRECISION - 1);
|
||||
}
|
||||
|
||||
// gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
|
||||
// does not give you back the same bits. This is dubious, and we
|
||||
// don't currently do it. You're really supposed to get
|
||||
// an invalid operation signal at runtime, but nobody does that.
|
||||
// Convert of sNaN creates qNaN and raises an exception (invalid op).
|
||||
// This also guarantees that a sNaN does not become Inf on a truncation
|
||||
// that loses all payload bits.
|
||||
if self.is_signaling() {
|
||||
// Quiet signaling NaN.
|
||||
sig::set_bit(&mut r.sig, T::QNAN_BIT);
|
||||
status = Status::INVALID_OP;
|
||||
} else {
|
||||
status = Status::OK;
|
||||
}
|
||||
} else {
|
||||
*loses_info = false;
|
||||
status = Status::OK;
|
||||
|
|
|
@ -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]
|
||||
fn min_num() {
|
||||
let f1 = Double::from_f64(1.0);
|
||||
|
@ -1492,27 +1503,32 @@ fn convert() {
|
|||
assert_eq!(4294967295.0, test.to_f64());
|
||||
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 x87_qnan = X87DoubleExtended::qnan(None);
|
||||
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
|
||||
assert!(test.bitwise_eq(x87_qnan));
|
||||
assert!(!loses_info);
|
||||
|
||||
let test = X87DoubleExtended::snan(None);
|
||||
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
|
||||
assert!(test.bitwise_eq(x87_snan));
|
||||
let test = Single::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);
|
||||
|
||||
let test = X87DoubleExtended::qnan(None);
|
||||
let test: X87DoubleExtended = test.convert(&mut loses_info).value;
|
||||
assert!(test.bitwise_eq(x87_qnan));
|
||||
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]
|
||||
|
|
|
@ -349,17 +349,15 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty::
|
|||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features};
|
||||
providers.supported_target_features = |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// 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 {
|
||||
llvm_util::supported_target_features(tcx.sess)
|
||||
.iter()
|
||||
.map(|&(a, b)| (a.to_string(), b))
|
||||
.collect()
|
||||
supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -793,14 +793,18 @@ fn generic_simd_intrinsic(
|
|||
require_simd!(arg_tys[1], "argument");
|
||||
let v_len = arg_tys[1].simd_size(tcx);
|
||||
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 `{}`",
|
||||
m_len,
|
||||
v_len
|
||||
);
|
||||
let i1 = bx.type_i1();
|
||||
let i1xn = bx.type_vector(i1, m_len);
|
||||
let m_i1s = bx.bitcast(args[0].immediate(), i1xn);
|
||||
let im = bx.type_ix(v_len);
|
||||
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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::llvm;
|
||||
use libc::c_int;
|
||||
use rustc_codegen_ssa::target_features::supported_target_features;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::config::PrintRequest;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy};
|
||||
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
|
||||
// to LLVM or the feature detection code will walk past the end of the feature
|
||||
// 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 {
|
||||
let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch };
|
||||
match (arch, s) {
|
||||
|
@ -306,20 +172,6 @@ pub fn target_features(sess: &Session) -> Vec<Symbol> {
|
|||
.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() {
|
||||
// Can be called without initializing LLVM
|
||||
unsafe {
|
||||
|
|
|
@ -42,6 +42,7 @@ pub mod glue;
|
|||
pub mod meth;
|
||||
pub mod mir;
|
||||
pub mod mono_item;
|
||||
pub mod target_features;
|
||||
pub mod traits;
|
||||
|
||||
pub struct ModuleCodegen<M> {
|
||||
|
|
|
@ -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,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
|
@ -36,12 +36,6 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
|
|||
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) {
|
||||
Some(l) => l,
|
||||
None => {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
use super::super::{navigate::Position, node, DeterministicRng};
|
||||
use super::Entry::{Occupied, Vacant};
|
||||
use super::*;
|
||||
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::rc::Rc;
|
||||
use crate::string::String;
|
||||
use crate::string::ToString;
|
||||
use crate::string::{String, ToString};
|
||||
use crate::vec::Vec;
|
||||
use std::convert::TryFrom;
|
||||
use std::iter::FromIterator;
|
||||
|
@ -16,19 +14,17 @@ use std::ops::RangeBounds;
|
|||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use super::super::DeterministicRng;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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.
|
||||
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,
|
||||
// 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.
|
||||
const MIN_INSERTS_HEIGHT_2: usize = 89;
|
||||
|
||||
|
@ -1386,44 +1382,65 @@ fn test_clone_from() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_variance() {
|
||||
use std::collections::btree_map::{IntoIter, Iter, Keys, Range, Values};
|
||||
|
||||
fn map_key<'new>(v: BTreeMap<&'static str, ()>) -> BTreeMap<&'new str, ()> {
|
||||
v
|
||||
}
|
||||
fn map_val<'new>(v: BTreeMap<(), &'static str>) -> BTreeMap<(), &'new str> {
|
||||
v
|
||||
}
|
||||
|
||||
fn iter_key<'a, 'new>(v: Iter<'a, &'static str, ()>) -> Iter<'a, &'new str, ()> {
|
||||
v
|
||||
}
|
||||
fn iter_val<'a, 'new>(v: Iter<'a, (), &'static str>) -> Iter<'a, (), &'new str> {
|
||||
v
|
||||
}
|
||||
|
||||
fn into_iter_key<'new>(v: IntoIter<&'static str, ()>) -> IntoIter<&'new str, ()> {
|
||||
v
|
||||
}
|
||||
fn into_iter_val<'new>(v: IntoIter<(), &'static str>) -> IntoIter<(), &'new str> {
|
||||
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, ()> {
|
||||
v
|
||||
}
|
||||
fn range_val<'a, 'new>(v: Range<'a, (), &'static str>) -> Range<'a, (), &'new str> {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_sync() {
|
||||
fn map<T: Sync>(v: &BTreeMap<T, T>) -> impl Sync + '_ {
|
||||
|
@ -1493,7 +1510,6 @@ fn test_sync() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_send() {
|
||||
fn map<T: Send>(v: BTreeMap<T, T>) -> impl Send {
|
||||
|
@ -1520,7 +1536,7 @@ fn test_send() {
|
|||
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()
|
||||
}
|
||||
|
||||
|
@ -1532,7 +1548,7 @@ fn test_send() {
|
|||
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()
|
||||
}
|
||||
|
||||
|
@ -1540,7 +1556,7 @@ fn test_send() {
|
|||
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(..)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
use crate::collections::BTreeSet;
|
||||
use super::super::DeterministicRng;
|
||||
use super::*;
|
||||
use crate::vec::Vec;
|
||||
use std::iter::FromIterator;
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use super::super::DeterministicRng;
|
||||
|
||||
#[test]
|
||||
fn test_clone_eq() {
|
||||
let mut m = BTreeSet::new();
|
||||
|
@ -528,11 +527,8 @@ fn test_recovery() {
|
|||
assert_eq!(s.iter().next(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(dead_code)]
|
||||
fn test_variance() {
|
||||
use std::collections::btree_set::{IntoIter, Iter, Range};
|
||||
|
||||
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
|
||||
v
|
||||
}
|
||||
|
@ -545,6 +541,85 @@ fn test_variance() {
|
|||
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
|
||||
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]
|
||||
|
|
|
@ -554,8 +554,8 @@ impl<K, V, S> HashMap<K, V, S> {
|
|||
/// a.clear();
|
||||
/// assert!(a.is_empty());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn clear(&mut self) {
|
||||
self.base.clear();
|
||||
}
|
||||
|
@ -746,8 +746,8 @@ where
|
|||
/// assert_eq!(map.get_key_value(&1), Some((&1, &"a")));
|
||||
/// assert_eq!(map.get_key_value(&2), None);
|
||||
/// ```
|
||||
#[stable(feature = "map_get_key_value", since = "1.40.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "map_get_key_value", since = "1.40.0")]
|
||||
pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -772,8 +772,8 @@ where
|
|||
/// assert_eq!(map.contains_key(&1), true);
|
||||
/// assert_eq!(map.contains_key(&2), false);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -800,8 +800,8 @@ where
|
|||
/// }
|
||||
/// assert_eq!(map[&1], "b");
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -834,8 +834,8 @@ where
|
|||
/// assert_eq!(map.insert(37, "c"), Some("b"));
|
||||
/// assert_eq!(map[&37], "c");
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
|
||||
self.base.insert(k, v)
|
||||
}
|
||||
|
@ -857,8 +857,8 @@ where
|
|||
/// assert_eq!(map.remove(&1), Some("a"));
|
||||
/// assert_eq!(map.remove(&1), None);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -886,8 +886,8 @@ where
|
|||
/// assert_eq!(map.remove(&1), None);
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
|
||||
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
|
@ -909,8 +909,8 @@ where
|
|||
/// map.retain(|&k, _| k % 2 == 0);
|
||||
/// assert_eq!(map.len(), 4);
|
||||
/// ```
|
||||
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
|
||||
#[inline]
|
||||
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
|
||||
pub fn retain<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&K, &mut V) -> bool,
|
||||
|
@ -1647,7 +1647,7 @@ impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
|
|||
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.
|
||||
#[inline]
|
||||
#[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()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[inline]
|
||||
#[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> {
|
||||
/// 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.
|
||||
#[inline]
|
||||
#[unstable(feature = "hash_raw_entry", issue = "56167")]
|
||||
|
@ -2173,7 +2173,6 @@ where
|
|||
}
|
||||
|
||||
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
|
||||
/// 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);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
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,
|
||||
/// 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());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
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,
|
||||
/// which takes the key as its argument, and returns a mutable reference to the value in the
|
||||
/// entry.
|
||||
|
@ -2240,6 +2239,7 @@ impl<'a, K, V> Entry<'a, K, V> {
|
|||
/// assert_eq!(map["poneyland"], 9);
|
||||
/// ```
|
||||
#[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 {
|
||||
match self {
|
||||
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
|
||||
///
|
||||
|
@ -2331,7 +2331,6 @@ impl<'a, K, V> 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,
|
||||
/// 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]
|
||||
#[stable(feature = "entry_or_default", since = "1.28.0")]
|
||||
pub fn or_default(self) -> &'a mut V {
|
||||
match self {
|
||||
Occupied(entry) => entry.into_mut(),
|
||||
|
@ -2452,7 +2452,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
|
|||
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.
|
||||
///
|
||||
/// 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()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -2646,8 +2646,8 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
|
|||
self.base.insert(value)
|
||||
}
|
||||
|
||||
/// Sets the value of the entry with the VacantEntry's key,
|
||||
/// and returns an OccupiedEntry.
|
||||
/// Sets the value of the entry with the `VacantEntry`'s key,
|
||||
/// and returns an `OccupiedEntry`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -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
|
||||
/// kept separate because of issue #42760.
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum DocFragment {
|
||||
/// A doc fragment created from a `///` or `//!` doc comment.
|
||||
SugaredDoc(usize, rustc_span::Span, String),
|
||||
/// A doc fragment created from a "raw" `#[doc=""]` attribute.
|
||||
RawDoc(usize, rustc_span::Span, String),
|
||||
/// 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),
|
||||
pub struct DocFragment {
|
||||
pub line: usize,
|
||||
pub span: rustc_span::Span,
|
||||
pub doc: String,
|
||||
pub kind: DocFragmentKind,
|
||||
}
|
||||
|
||||
impl DocFragment {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match *self {
|
||||
DocFragment::SugaredDoc(_, _, ref s) => &s[..],
|
||||
DocFragment::RawDoc(_, _, ref s) => &s[..],
|
||||
DocFragment::Include(_, _, _, ref s) => &s[..],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn span(&self) -> rustc_span::Span {
|
||||
match *self {
|
||||
DocFragment::SugaredDoc(_, span, _)
|
||||
| DocFragment::RawDoc(_, span, _)
|
||||
| DocFragment::Include(_, span, _, _) => span,
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum DocFragmentKind {
|
||||
/// A doc fragment created from a `///` or `//!` doc comment.
|
||||
SugaredDoc,
|
||||
/// A doc fragment created from a "raw" `#[doc=""]` attribute.
|
||||
RawDoc,
|
||||
/// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the
|
||||
/// given filename and the file contents.
|
||||
Include { filename: String },
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<&'a DocFragment> for String {
|
||||
|
@ -407,12 +397,7 @@ impl<'a> FromIterator<&'a DocFragment> for String {
|
|||
if !acc.is_empty() {
|
||||
acc.push('\n');
|
||||
}
|
||||
match *frag {
|
||||
DocFragment::SugaredDoc(_, _, ref docs)
|
||||
| DocFragment::RawDoc(_, _, ref docs)
|
||||
| DocFragment::Include(_, _, _, ref docs) => acc.push_str(docs),
|
||||
}
|
||||
|
||||
acc.push_str(&frag.doc);
|
||||
acc
|
||||
})
|
||||
}
|
||||
|
@ -547,15 +532,15 @@ impl Attributes {
|
|||
.filter_map(|attr| {
|
||||
if let Some(value) = attr.doc_str() {
|
||||
let value = beautify_doc_string(value);
|
||||
let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() {
|
||||
DocFragment::SugaredDoc
|
||||
let kind = if attr.is_doc_comment() {
|
||||
DocFragmentKind::SugaredDoc
|
||||
} else {
|
||||
DocFragment::RawDoc
|
||||
DocFragmentKind::RawDoc
|
||||
};
|
||||
|
||||
let line = doc_line;
|
||||
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() {
|
||||
sp = Some(attr.span);
|
||||
|
@ -575,9 +560,12 @@ impl Attributes {
|
|||
{
|
||||
let line = doc_line;
|
||||
doc_line += contents.lines().count();
|
||||
doc_strings.push(DocFragment::Include(
|
||||
line, attr.span, filename, contents,
|
||||
));
|
||||
doc_strings.push(DocFragment {
|
||||
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
|
||||
/// value found.
|
||||
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
|
||||
|
|
|
@ -120,7 +120,7 @@ h3.impl, h3.method, h3.type {
|
|||
}
|
||||
|
||||
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,
|
||||
#source-sidebar, #sidebar-toggle {
|
||||
font-family: "Fira Sans", sans-serif;
|
||||
|
|
|
@ -232,7 +232,12 @@ impl fold::DocFolder for CoverageCalculator {
|
|||
let mut tests = Tests { found_tests: 0 };
|
||||
|
||||
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,
|
||||
ErrorCodes::No,
|
||||
false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::clean::{self, DocFragment, Item};
|
||||
use crate::clean::{self, DocFragment, DocFragmentKind, Item};
|
||||
use crate::core::DocContext;
|
||||
use crate::fold;
|
||||
use crate::fold::DocFolder;
|
||||
|
@ -12,23 +12,6 @@ pub const COLLAPSE_DOCS: Pass = Pass {
|
|||
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 {
|
||||
let mut krate = Collapser.fold_crate(krate);
|
||||
krate.collapsed = true;
|
||||
|
@ -50,30 +33,22 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) {
|
|||
|
||||
for frag in take(doc_strings) {
|
||||
if let Some(mut curr_frag) = last_frag.take() {
|
||||
let curr_kind = curr_frag.kind();
|
||||
let new_kind = frag.kind();
|
||||
let curr_kind = &curr_frag.kind;
|
||||
let new_kind = &frag.kind;
|
||||
|
||||
if curr_kind == DocFragmentKind::Include || curr_kind != new_kind {
|
||||
match curr_frag {
|
||||
DocFragment::SugaredDoc(_, _, ref mut doc_string)
|
||||
| DocFragment::RawDoc(_, _, ref mut doc_string) => {
|
||||
if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind {
|
||||
if *curr_kind == DocFragmentKind::SugaredDoc
|
||||
|| *curr_kind == DocFragmentKind::RawDoc
|
||||
{
|
||||
// add a newline for extra padding between segments
|
||||
doc_string.push('\n');
|
||||
}
|
||||
_ => {}
|
||||
curr_frag.doc.push('\n');
|
||||
}
|
||||
docs.push(curr_frag);
|
||||
last_frag = Some(frag);
|
||||
} else {
|
||||
match curr_frag {
|
||||
DocFragment::SugaredDoc(_, ref mut span, ref mut doc_string)
|
||||
| DocFragment::RawDoc(_, ref mut span, ref mut doc_string) => {
|
||||
doc_string.push('\n');
|
||||
doc_string.push_str(frag.as_str());
|
||||
*span = span.to(frag.span());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
curr_frag.doc.push('\n');
|
||||
curr_frag.doc.push_str(&frag.doc);
|
||||
curr_frag.span = curr_frag.span.to(frag.span);
|
||||
last_frag = Some(curr_frag);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::mem;
|
|||
use std::ops::Range;
|
||||
|
||||
use self::Condition::*;
|
||||
use crate::clean::{self, GetDefId, Item};
|
||||
use crate::clean::{self, DocFragmentKind, GetDefId, Item};
|
||||
use crate::core::DocContext;
|
||||
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() {
|
||||
return None;
|
||||
}
|
||||
let start = attrs.doc_strings[0].span();
|
||||
let start = attrs.doc_strings[0].span;
|
||||
if start == DUMMY_SP {
|
||||
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))
|
||||
}
|
||||
|
||||
|
@ -333,10 +333,8 @@ crate fn source_span_for_markdown_range(
|
|||
md_range: &Range<usize>,
|
||||
attrs: &clean::Attributes,
|
||||
) -> Option<Span> {
|
||||
let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag {
|
||||
clean::DocFragment::SugaredDoc(..) => true,
|
||||
_ => false,
|
||||
});
|
||||
let is_all_sugared_doc =
|
||||
attrs.doc_strings.iter().all(|frag| frag.kind == DocFragmentKind::SugaredDoc);
|
||||
|
||||
if !is_all_sugared_doc {
|
||||
return None;
|
||||
|
|
|
@ -36,13 +36,7 @@ impl clean::Attributes {
|
|||
|
||||
fn unindent_fragments(docs: &mut Vec<DocFragment>) {
|
||||
for fragment in docs {
|
||||
match *fragment {
|
||||
DocFragment::SugaredDoc(_, _, ref mut doc_string)
|
||||
| DocFragment::RawDoc(_, _, ref mut doc_string)
|
||||
| DocFragment::Include(_, _, _, ref mut doc_string) => {
|
||||
*doc_string = unindent(doc_string)
|
||||
}
|
||||
}
|
||||
fragment.doc = unindent(&fragment.doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -49,8 +49,8 @@ fn main() {
|
|||
simd_select(m4, 0u32, 1u32);
|
||||
//~^ ERROR found non-SIMD `u32`
|
||||
|
||||
simd_select_bitmask(0u8, x, x);
|
||||
//~^ ERROR mask length `8` != other vector length `4`
|
||||
simd_select_bitmask(0u16, x, x);
|
||||
//~^ ERROR mask length `16` != other vector length `4`
|
||||
//
|
||||
simd_select_bitmask(0u8, 1u32, 2u32);
|
||||
//~^ ERROR found non-SIMD `u32`
|
||||
|
|
|
@ -22,11 +22,11 @@ error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD
|
|||
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
|
||||
|
|
||||
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`
|
||||
--> $DIR/simd-intrinsic-generic-select.rs:55:9
|
||||
|
|
|
@ -167,4 +167,29 @@ fn main() {
|
|||
let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue