From 8a011b5da2cc289fb7d970492ea4111980676412 Mon Sep 17 00:00:00 2001 From: sharnoff Date: Tue, 22 Sep 2020 19:34:05 +0100 Subject: [PATCH 1/9] minor doc changes, attribute orderings --- library/std/src/collections/hash/map.rs | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 61d71d55d6593..1864b5ccf2bc0 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -554,8 +554,8 @@ impl HashMap { /// 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(&self, k: &Q) -> Option<(&K, &V)> where K: Borrow, @@ -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(&self, k: &Q) -> bool where K: Borrow, @@ -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(&mut self, k: &Q) -> Option<&mut V> where K: Borrow, @@ -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 { 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(&mut self, k: &Q) -> Option where K: Borrow, @@ -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(&mut self, k: &Q) -> Option<(K, V)> where K: Borrow, @@ -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(&mut self, f: F) where F: FnMut(&K, &mut V) -> bool, @@ -1542,7 +1542,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")] @@ -1571,7 +1571,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")] @@ -1609,7 +1609,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")] @@ -2072,7 +2072,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. /// @@ -2090,6 +2089,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(), @@ -2097,7 +2097,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. /// @@ -2114,6 +2113,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 V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -2121,7 +2121,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. @@ -2139,6 +2138,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 V>(self, default: F) -> &'a mut V { match self { Occupied(entry) => entry.into_mut(), @@ -2203,7 +2203,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 /// @@ -2230,7 +2230,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. /// @@ -2247,6 +2246,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(), @@ -2351,7 +2351,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`]. @@ -2523,7 +2523,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 @@ -2545,8 +2545,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 /// From 7f5008c8293a4d1eb3e4557a36a6bfdef34de284 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 30 Sep 2020 17:46:18 +0200 Subject: [PATCH 2/9] Backport LLVM apfloat commit to rustc_apfloat Backports LLVM commit: https://github.com/llvm/llvm-project/commit/e34bd1e0b03d20a506ada156d87e1b3a96d82fa2 Fixes #69532 --- compiler/rustc_apfloat/src/ieee.rs | 12 ++++++++++++ compiler/rustc_apfloat/tests/ieee.rs | 9 +++++++++ src/test/ui/issues/issue-69532.rs | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 src/test/ui/issues/issue-69532.rs diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs index e3d941cad7ae5..aafd6dfb89a25 100644 --- a/compiler/rustc_apfloat/src/ieee.rs +++ b/compiler/rustc_apfloat/src/ieee.rs @@ -1511,6 +1511,18 @@ impl FloatConvert> for IeeeFloat { sig::set_bit(&mut r.sig, T::PRECISION - 1); } + // If we are truncating NaN, it is possible that we shifted out all of the + // set bits in a signalling NaN payload. But NaN must remain NaN, so some + // bit in the significand must be set (otherwise it is Inf). + // This can only happen with sNaN. Set the 1st bit after the quiet bit, + // so that we still have an sNaN. + if r.sig[0] == 0 { + assert!(shift < 0, "Should not lose NaN payload on extend"); + assert!(T::PRECISION >= 3, "Unexpectedly narrow significand"); + assert!(*loses_info, "Missing payload should have set lost info"); + sig::set_bit(&mut r.sig, T::PRECISION - 3); + } + // 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 diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs index 2d8bb7d1e8e03..0f3c99fba9e24 100644 --- a/compiler/rustc_apfloat/tests/ieee.rs +++ b/compiler/rustc_apfloat/tests/ieee.rs @@ -566,6 +566,15 @@ fn fma() { } } +#[test] +fn issue_69532() { + let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128); + let mut loses_info = false; + let r: Single = f.convert(&mut loses_info).value; + assert!(loses_info); + assert!(r.is_nan()); +} + #[test] fn min_num() { let f1 = Double::from_f64(1.0); diff --git a/src/test/ui/issues/issue-69532.rs b/src/test/ui/issues/issue-69532.rs new file mode 100644 index 0000000000000..81007b15074f7 --- /dev/null +++ b/src/test/ui/issues/issue-69532.rs @@ -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()); +} From e41a14412e207aac5f7d686d395bc6a23f643dc9 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 3 Oct 2020 16:13:06 +0100 Subject: [PATCH 3/9] Support vectors with fewer than 8 elements for simd_select_bitmask --- compiler/rustc_codegen_llvm/src/intrinsic.rs | 10 +++++--- .../simd-intrinsic-generic-select.rs | 4 +-- .../simd-intrinsic-generic-select.stderr | 6 ++--- .../ui/simd/simd-intrinsic-generic-select.rs | 25 +++++++++++++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7f5b09eac4f9e..e76e86f56510b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -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())); } diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs index a719b31415055..7d68af49e2868 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.rs @@ -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` diff --git a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr index f68c969d13ee3..a1ef0bb8ee03b 100644 --- a/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr +++ b/src/test/ui/simd-intrinsic/simd-intrinsic-generic-select.stderr @@ -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 diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs index dc9ec5d2760fe..b850cf9750a1f 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs @@ -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); + } } From a58089e097c4f80af0353e843e264ae634db686b Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Fri, 2 Oct 2020 11:47:03 +0200 Subject: [PATCH 4/9] BTreeMap/Set: complete the compile-time test cases --- .../alloc/src/collections/btree/map/tests.rs | 58 ++++++++----- .../alloc/src/collections/btree/set/tests.rs | 87 +++++++++++++++++-- 2 files changed, 118 insertions(+), 27 deletions(-) diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 8018514fa1776..118e173bb16db 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -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 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 vals<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { + fn values_val<'a, 'new>(v: Values<'a, (), &'static str>) -> Values<'a, (), &'new str> { v } } -#[test] #[allow(dead_code)] fn test_sync() { fn map(v: &BTreeMap) -> impl Sync + '_ { @@ -1493,7 +1510,6 @@ fn test_sync() { } } -#[test] #[allow(dead_code)] fn test_send() { fn map(v: BTreeMap) -> impl Send { @@ -1520,7 +1536,7 @@ fn test_send() { v.iter() } - fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { + fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { v.iter_mut() } @@ -1532,7 +1548,7 @@ fn test_send() { v.values() } - fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { + fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { v.values_mut() } @@ -1540,7 +1556,7 @@ fn test_send() { v.range(..) } - fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { + fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { v.range_mut(..) } diff --git a/library/alloc/src/collections/btree/set/tests.rs b/library/alloc/src/collections/btree/set/tests.rs index f4e957e22fe15..9267435728216 100644 --- a/library/alloc/src/collections/btree/set/tests.rs +++ b/library/alloc/src/collections/btree/set/tests.rs @@ -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(v: &BTreeSet) -> impl Sync + '_ { + v + } + + fn iter(v: &BTreeSet) -> impl Sync + '_ { + v.iter() + } + + fn into_iter(v: BTreeSet) -> impl Sync { + v.into_iter() + } + + fn range(v: &BTreeSet) -> impl Sync + '_ { + v.range(..) + } + + fn drain_filter(v: &mut BTreeSet) -> impl Sync + '_ { + v.drain_filter(|_| false) + } + + fn difference(v: &BTreeSet) -> impl Sync + '_ { + v.difference(&v) + } + + fn intersection(v: &BTreeSet) -> impl Sync + '_ { + v.intersection(&v) + } + + fn symmetric_difference(v: &BTreeSet) -> impl Sync + '_ { + v.symmetric_difference(&v) + } + + fn union(v: &BTreeSet) -> impl Sync + '_ { + v.union(&v) + } +} + +#[allow(dead_code)] +fn test_send() { + fn set(v: BTreeSet) -> impl Send { + v + } + + fn iter(v: &BTreeSet) -> impl Send + '_ { + v.iter() + } + + fn into_iter(v: BTreeSet) -> impl Send { + v.into_iter() + } + + fn range(v: &BTreeSet) -> impl Send + '_ { + v.range(..) + } + + fn drain_filter(v: &mut BTreeSet) -> impl Send + '_ { + v.drain_filter(|_| false) + } + + fn difference(v: &BTreeSet) -> impl Send + '_ { + v.difference(&v) + } + + fn intersection(v: &BTreeSet) -> impl Send + '_ { + v.intersection(&v) + } + + fn symmetric_difference(v: &BTreeSet) -> impl Send + '_ { + v.symmetric_difference(&v) + } + + fn union(v: &BTreeSet) -> impl Send + '_ { + v.union(&v) + } } #[test] From 5f76b95e9b5560e1f6784ab3c003e7106ae74d19 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 3 Oct 2020 19:15:27 -0400 Subject: [PATCH 5/9] Change DocFragments from enum variant fields to structs with a nested enum This makes the code a lot easier to work with. It also makes it easier to add new fields without updating each variant and `match` individually. - Name the `Kind` variant after `DocFragmentKind` from `collapse_docs` - Remove unneeded impls --- src/librustdoc/clean/types.rs | 60 ++++++++----------- .../passes/calculate_doc_coverage.rs | 7 ++- src/librustdoc/passes/collapse_docs.rs | 49 ++++----------- src/librustdoc/passes/mod.rs | 12 ++-- src/librustdoc/passes/unindent_comments.rs | 8 +-- 5 files changed, 48 insertions(+), 88 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 223fda84871e9..a5ba037c2d6ee 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -370,32 +370,22 @@ impl> 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 { +pub struct DocFragment { + pub line: usize, + pub span: rustc_span::Span, + pub doc: String, + pub kind: DocFragmentKind, +} + +#[derive(Clone, PartialEq, Eq, Debug, Hash)] +pub enum DocFragmentKind { /// A doc fragment created from a `///` or `//!` doc comment. - SugaredDoc(usize, rustc_span::Span, String), + SugaredDoc, /// A doc fragment created from a "raw" `#[doc=""]` attribute. - RawDoc(usize, rustc_span::Span, String), + RawDoc, /// 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 { - 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, - } - } + 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 diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 671e082556722..4bca3996eb48f 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -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::>().join("\n"), + &i.attrs + .doc_strings + .iter() + .map(|d| d.doc.as_str()) + .collect::>() + .join("\n"), &mut tests, ErrorCodes::No, false, diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index c2185592d1483..be7250f833f00 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -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) { 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 { diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 75a659666673f..f8e395bfb41d9 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -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 { 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, attrs: &clean::Attributes, ) -> Option { - 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; diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index 5604a9c2dc163..a9cf5a87f5493 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -36,13 +36,7 @@ impl clean::Attributes { fn unindent_fragments(docs: &mut Vec) { 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); } } From 59c243331d60e74290102d5450587adf58597dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sun, 4 Oct 2020 00:00:00 +0000 Subject: [PATCH 6/9] Enable RenameReturnPlace MIR optimization on mir-opt-level >= 2 The destination propagation as currently implemented does not supersede the NRVO, e.g., the destination propagation never applies if either local has an address taken, while NRVO might. Additionally, the issue with failing assertions had been already resolved. Continue running both optimizations at mir-opt-level >= 2. --- compiler/rustc_mir/src/transform/nrvo.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs index 1ffb5a87c4762..3673b6a4aa223 100644 --- a/compiler/rustc_mir/src/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -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 => { From d010809c8c0062a4c7a3249254a5193dd1ca15c7 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 3 Oct 2020 22:01:22 +0200 Subject: [PATCH 7/9] Backport another LLVM commit to rustc_apfloat Backports LLVM commit: [APFloat] convert SNaN to QNaN in convert() and raise Invalid signal https://github.com/llvm/llvm-project/commit/149f5b573c79eac0c519ada4d2f7c50e17796cdf SNaN to QNaN conversion also matches what my Intel x86_64 hardware does. --- compiler/rustc_apfloat/src/ieee.rs | 27 ++++++++++----------------- compiler/rustc_apfloat/tests/ieee.rs | 27 +++++++++++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_apfloat/src/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs index aafd6dfb89a25..71bcb8f090d07 100644 --- a/compiler/rustc_apfloat/src/ieee.rs +++ b/compiler/rustc_apfloat/src/ieee.rs @@ -1511,23 +1511,16 @@ impl FloatConvert> for IeeeFloat { sig::set_bit(&mut r.sig, T::PRECISION - 1); } - // If we are truncating NaN, it is possible that we shifted out all of the - // set bits in a signalling NaN payload. But NaN must remain NaN, so some - // bit in the significand must be set (otherwise it is Inf). - // This can only happen with sNaN. Set the 1st bit after the quiet bit, - // so that we still have an sNaN. - if r.sig[0] == 0 { - assert!(shift < 0, "Should not lose NaN payload on extend"); - assert!(T::PRECISION >= 3, "Unexpectedly narrow significand"); - assert!(*loses_info, "Missing payload should have set lost info"); - sig::set_bit(&mut r.sig, T::PRECISION - 3); - } - - // 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; diff --git a/compiler/rustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs index 0f3c99fba9e24..63d925cce9ad7 100644 --- a/compiler/rustc_apfloat/tests/ieee.rs +++ b/compiler/rustc_apfloat/tests/ieee.rs @@ -570,9 +570,11 @@ fn fma() { fn issue_69532() { let f = Double::from_bits(0x7FF0_0000_0000_0001u64 as u128); let mut loses_info = false; - let r: Single = f.convert(&mut loses_info).value; + 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] @@ -1501,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] From adfba2b694b19e4aa6a99289eeda7b48ae402ab8 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 3 Oct 2020 19:52:35 -0700 Subject: [PATCH 8/9] Only use Fira Sans for the first `td` in item lists Fixes an issue where links in the one-line version of an item's docs would be in Fira Sans, while the rest would be in a serifed font. --- src/librustdoc/html/static/rustdoc.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 935b96e51fc3b..3f4bd2886b1b2 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -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; From 17d1cbbbe0dc59509cf0f889d241cf58099076d4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 4 Oct 2020 11:12:56 +0200 Subject: [PATCH 9/9] Move target feature whitelist from cg_llvm to cg_ssa These target features have to be supported or at least emulated by alternative codegen backends anyway as they are used by common crates. By moving this list to cg_ssa, other codegen backends don't have to copy this code. --- compiler/rustc_codegen_llvm/src/attributes.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 150 +----------------- compiler/rustc_codegen_ssa/src/lib.rs | 1 + .../rustc_codegen_ssa/src/target_features.rs | 150 ++++++++++++++++++ 4 files changed, 155 insertions(+), 154 deletions(-) create mode 100644 compiler/rustc_codegen_ssa/src/target_features.rs diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 73c34818446a6..a633ea5e5a9ae 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -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() } }; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 900f2df383a06..d42020047fddd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -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)] = &[ - ("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)] = &[ - ("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)] = &[ - ("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)] = &[ - ("hvx", Some(sym::hexagon_target_feature)), - ("hvx-length128b", Some(sym::hexagon_target_feature)), -]; - -const POWERPC_ALLOWED_FEATURES: &[(&str, Option)] = &[ - ("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)] = - &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))]; - -const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ - ("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)] = &[ - ("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)> { - 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 { .collect() } -pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option)] { - 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 { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index d4f3bf3779784..e34371ef59ac4 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -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 { diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs new file mode 100644 index 0000000000000..4c61e21901bcd --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -0,0 +1,150 @@ +use rustc_session::Session; +use rustc_span::symbol::sym; +use rustc_span::symbol::Symbol; + +const ARM_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("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)] = &[ + ("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)] = &[ + ("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)] = &[ + ("hvx", Some(sym::hexagon_target_feature)), + ("hvx-length128b", Some(sym::hexagon_target_feature)), +]; + +const POWERPC_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("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)] = + &[("fp64", Some(sym::mips_target_feature)), ("msa", Some(sym::mips_target_feature))]; + +const RISCV_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("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)] = &[ + ("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)> { + 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)] { + 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, + _ => &[], + } +}