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);
}
// 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.
status = Status::OK;
// 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;

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]
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]

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) {
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()
}
};

View File

@ -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()));
}

View File

@ -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 {

View File

@ -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> {

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;
}
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 => {

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::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(..)
}

View File

@ -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]

View File

@ -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
///

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
/// 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

View File

@ -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;

View File

@ -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,

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::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) => {
// add a newline for extra padding between segments
doc_string.push('\n');
}
_ => {}
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
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 {

View File

@ -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;

View File

@ -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);
}
}

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);
//~^ 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`

View File

@ -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

View File

@ -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);
}
}