diff --git a/README.md b/README.md index a7e23d8ac2caa..6cf9577d3330e 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,8 @@ The Rust community congregates in a few places: If you are interested in contributing to the Rust project, please take a look at the [Getting Started][gettingstarted] guide in the [rustc-dev-guide]. +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org + ## License Rust is primarily distributed under the terms of both the MIT license diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index a2c651d1537b5..09c0983bb9d1a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -173,6 +173,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Move, kw::Return, kw::True, + kw::Try, kw::Unsafe, kw::While, kw::Yield, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 0ee8ef55e61bf..97e6b363eff60 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -608,6 +608,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session) { maybe_stage_features(sess, krate); + check_incompatible_features(sess); let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() }; let spans = sess.parse_sess.gated_spans.spans.borrow(); @@ -677,3 +678,36 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { } } } + +fn check_incompatible_features(sess: &Session) { + let features = sess.features_untracked(); + + let declared_features = features + .declared_lang_features + .iter() + .copied() + .map(|(name, span, _)| (name, span)) + .chain(features.declared_lib_features.iter().copied()); + + for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES + .iter() + .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + { + if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { + if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) + { + let spans = vec![f1_span, f2_span]; + sess.struct_span_err( + spans.clone(), + &format!( + "features `{}` and `{}` are incompatible, using them at the same time \ + is not allowed", + f1_name, f2_name + ), + ) + .help("remove one of these features") + .emit(); + } + } + } +} diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs index 64ff6130ddffb..bc3d1ce53bac5 100644 --- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -87,11 +87,8 @@ where } /// Allows searches to terminate early with a value. -#[derive(Clone, Copy, Debug)] -pub enum ControlFlow { - Break(T), - Continue, -} +// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`. +pub type ControlFlow = std::ops::ControlFlow<(), T>; /// The status of a node in the depth-first search. /// @@ -260,12 +257,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Behave as if no edges exist from `source` to `target`. @@ -289,8 +286,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue, + Some(NodeStatus::Visited) => ControlFlow::BREAK, + _ => ControlFlow::CONTINUE, } } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index de4e7a1342431..88c160e93b66a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(incomplete_features)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] #![feature(generators)] diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index e858980738d71..3d7b3da45ccb9 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -605,3 +605,8 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::lazy_normalization_consts, sym::specialization, ]; + +/// Some features are not allowed to be used together at the same time, if +/// the two are present, produce an error +pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = + &[(sym::const_generics, sym::min_const_generics)]; diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 4393368cd4524..15564a59658cb 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -131,7 +131,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::Continue + ControlFlow::CONTINUE } else { ControlFlow::Break(NonRecursive) } @@ -131,7 +131,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue, + | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, } } @@ -144,7 +144,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } } - ControlFlow::Continue + ControlFlow::CONTINUE } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 011ea32d0cfc2..eba7ffae22c4c 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -120,6 +120,9 @@ use crate::raw_vec::RawVec; /// assert_eq!(vec, [0, 0, 0, 0, 0]); /// ``` /// +/// For more information, see +/// [Capacity and Reallocation](#capacity-and-reallocation). +/// /// Use a `Vec` as an efficient stack: /// /// ``` diff --git a/library/alloc/tests/borrow.rs b/library/alloc/tests/borrow.rs index 8bfcf323f674a..57976aa6cdfdf 100644 --- a/library/alloc/tests/borrow.rs +++ b/library/alloc/tests/borrow.rs @@ -45,3 +45,16 @@ fn test_from_cow_path() { let path = Path::new("hello"); test_from_cow!(path: &Path); } + +#[test] +fn cow_const() { + // test that the methods of `Cow` are usable in a const context + + const COW: Cow<'_, str> = Cow::Borrowed("moo"); + + const IS_BORROWED: bool = COW.is_borrowed(); + assert!(IS_BORROWED); + + const IS_OWNED: bool = COW.is_owned(); + assert!(!IS_OWNED); +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index b1513d1b05655..590639d983481 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(allocator_api)] #![feature(box_syntax)] +#![feature(cow_is_borrowed)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 8e66c8a22cec5..53b0d0a271844 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -74,6 +74,42 @@ fn test_zst_capacity() { assert_eq!(Vec::<()>::new().capacity(), usize::MAX); } +#[test] +fn test_indexing() { + let v: Vec = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + let mut x: usize = 0; + assert_eq!(v[x], 10); + assert_eq!(v[x + 1], 20); + x = x + 1; + assert_eq!(v[x], 20); + assert_eq!(v[x - 1], 10); +} + +#[test] +fn test_debug_fmt() { + let vec1: Vec = vec![]; + assert_eq!("[]", format!("{:?}", vec1)); + + let vec2 = vec![0, 1]; + assert_eq!("[0, 1]", format!("{:?}", vec2)); + + let slice: &[isize] = &[4, 5]; + assert_eq!("[4, 5]", format!("{:?}", slice)); +} + +#[test] +fn test_push() { + let mut v = vec![]; + v.push(1); + assert_eq!(v, [1]); + v.push(2); + assert_eq!(v, [1, 2]); + v.push(3); + assert_eq!(v, [1, 2, 3]); +} + #[test] fn test_extend() { let mut v = Vec::new(); @@ -119,6 +155,18 @@ fn test_extend() { assert_eq!(count_x, 1); } +#[test] +fn test_extend_from_slice() { + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; + + let mut v: Vec = a; + + v.extend_from_slice(&b); + + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); +} + #[test] fn test_extend_ref() { let mut v = vec![1, 2]; @@ -134,6 +182,14 @@ fn test_extend_ref() { assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); } +#[test] +fn test_slice_from_ref() { + let values = vec![1, 2, 3, 4, 5]; + let slice = &values[1..3]; + + assert_eq!(slice, [2, 3]); +} + #[test] fn test_slice_from_mut() { let mut values = vec![1, 2, 3, 4, 5]; @@ -345,6 +401,29 @@ fn test_zip_unzip() { assert_eq!((3, 6), (left[2], right[2])); } +#[test] +fn test_cmp() { + let x: &[isize] = &[1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); + + let x: Vec = vec![1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); +} + #[test] fn test_vec_truncate_drop() { static mut DROPS: u32 = 0; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 25951e2f58235..dd9af2d07e770 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -831,7 +831,7 @@ extern "rust-intrinsic" { /// Gets a reference to a static `Location` indicating where it was called. /// /// Consider using [`crate::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index c3f1269401aa9..b411222856edb 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1273,7 +1273,7 @@ where ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::Continue(()), + None => ControlFlow::CONTINUE, } } @@ -1772,7 +1772,7 @@ impl Peekable { self.peeked.get_or_insert_with(|| iter.next()).as_ref() } - /// Consume the next value of this iterator if a condition is true. + /// Consume and return the next value of this iterator if a condition is true. /// /// If `func` returns `true` for the next value of this iterator, consume and return it. /// Otherwise, return `None`. @@ -1812,7 +1812,7 @@ impl Peekable { } } - /// Consume the next item if it is equal to `expected`. + /// Consume and return the next item if it is equal to `expected`. /// /// # Example /// Consume a number if it's equal to 0. @@ -1827,10 +1827,10 @@ impl Peekable { /// assert_eq!(iter.next(), Some(1)); /// ``` #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if_eq(&mut self, expected: &R) -> Option + pub fn next_if_eq(&mut self, expected: &T) -> Option where - R: ?Sized, - I::Item: PartialEq, + T: ?Sized, + I::Item: PartialEq, { self.next_if(|next| next == expected) } diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index f50807116bd09..a025bc8b56049 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -310,7 +310,7 @@ pub trait DoubleEndedIterator: Iterator { mut predicate: impl FnMut(&T) -> bool, ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 46ef12cd938b3..b8a09f822b6da 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -648,11 +648,9 @@ pub trait Iterator { /// Creates an iterator which uses a closure to determine if an element /// should be yielded. /// - /// The closure must return `true` or `false`. `filter()` creates an - /// iterator which calls this closure on each element. If the closure - /// returns `true`, then the element is returned. If the closure returns - /// `false`, it will try again, and call the closure on the next element, - /// seeing if it passes the test. + /// Given an element the closure must return `true` or `false`. The returned + /// iterator will yield only the elements for which the closure returns + /// true. /// /// # Examples /// @@ -719,24 +717,16 @@ pub trait Iterator { /// Creates an iterator that both filters and maps. /// - /// The closure must return an [`Option`]. `filter_map` creates an - /// iterator which calls this closure on each element. If the closure - /// returns [`Some(element)`][`Some`], then that element is returned. If the - /// closure returns [`None`], it will try again, and call the closure on the - /// next element, seeing if it will return [`Some`]. + /// The returned iterator yields only the `value`s for which the supplied + /// closure returns `Some(value)`. /// - /// Why `filter_map` and not just [`filter`] and [`map`]? The key is in this - /// part: + /// `filter_map` can be used to make chains of [`filter`] and [`map`] more + /// concise. The example below shows how a `map().filter().map()` can be + /// shortened to a single call to `filter_map`. /// /// [`filter`]: Iterator::filter /// [`map`]: Iterator::map /// - /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. - /// - /// In other words, it removes the [`Option`] layer automatically. If your - /// mapping is already returning an [`Option`] and you want to skip over - /// [`None`]s, then `filter_map` is much, much nicer to use. - /// /// # Examples /// /// Basic usage: @@ -819,7 +809,7 @@ pub trait Iterator { Enumerate::new(self) } - /// Creates an iterator which can use `peek` to look at the next element of + /// Creates an iterator which can use [`peek`] to look at the next element of /// the iterator without consuming it. /// /// Adds a [`peek`] method to an iterator. See its documentation for @@ -2002,7 +1992,7 @@ pub trait Iterator { /// The same as [`fold()`], but uses the first element in the /// iterator as the initial value, folding every subsequent element into it. - /// If the iterator is empty, return `None`; otherwise, return the result + /// If the iterator is empty, return [`None`]; otherwise, return the result /// of the fold. /// /// [`fold()`]: Iterator::fold @@ -2086,10 +2076,10 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } } - self.try_fold((), check(f)) == ControlFlow::Continue(()) + self.try_fold((), check(f)) == ControlFlow::CONTINUE } /// Tests if any element of the iterator matches a predicate. @@ -2139,11 +2129,11 @@ pub trait Iterator { #[inline] fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } } - self.try_fold((), check(f)) == ControlFlow::Break(()) + self.try_fold((), check(f)) == ControlFlow::BREAK } /// Searches for an element of an iterator that satisfies a predicate. @@ -2201,7 +2191,7 @@ pub trait Iterator { mut predicate: impl FnMut(&T) -> bool, ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -2236,7 +2226,7 @@ pub trait Iterator { ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), - None => ControlFlow::Continue(()), + None => ControlFlow::CONTINUE, } } @@ -2278,7 +2268,7 @@ pub trait Iterator { R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => ControlFlow::Continue(()), + Ok(false) => ControlFlow::CONTINUE, Ok(true) => ControlFlow::Break(Ok(x)), Err(x) => ControlFlow::Break(Err(x)), } @@ -2831,7 +2821,7 @@ pub trait Iterator { Product::product(self) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2853,7 +2843,7 @@ pub trait Iterator { self.cmp_by(other, |x, y| x.cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2905,7 +2895,7 @@ pub trait Iterator { } } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2929,7 +2919,7 @@ pub trait Iterator { self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2990,7 +2980,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another. /// /// # Examples @@ -3009,7 +2999,7 @@ pub trait Iterator { self.eq_by(other, |x, y| x == y) } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another with respect to the specified equality function. /// /// # Examples @@ -3050,7 +3040,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are unequal to those of + /// Determines if the elements of this [`Iterator`] are unequal to those of /// another. /// /// # Examples @@ -3069,7 +3059,7 @@ pub trait Iterator { !self.eq(other) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less than those of another. /// /// # Examples @@ -3090,7 +3080,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Less) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less or equal to those of another. /// /// # Examples @@ -3111,7 +3101,7 @@ pub trait Iterator { matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than those of another. /// /// # Examples @@ -3132,7 +3122,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Greater) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than or equal to those of another. /// /// # Examples diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index 687d423dcb635..b0c7dc1a51875 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -65,3 +65,46 @@ impl ControlFlow { } } } + +impl ControlFlow<(), B> { + /// It's frequently the case that there's no value needed with `Continue`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// let last_used = (1..10).chain(20..25).try_for_each(|x| { + /// partial_sum += x; + /// if partial_sum > 100 { ControlFlow::Break(x) } + /// else { ControlFlow::CONTINUE } + /// }); + /// assert_eq!(last_used.break_value(), Some(22)); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const CONTINUE: Self = ControlFlow::Continue(()); +} + +impl ControlFlow { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// (1..10).chain(20..25).try_for_each(|x| { + /// if partial_sum > 100 { ControlFlow::BREAK } + /// else { partial_sum += x; ControlFlow::CONTINUE } + /// }); + /// assert_eq!(partial_sum, 108); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const BREAK: Self = ControlFlow::Break(()); +} diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 25ee73c626eac..34a974b827158 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -225,7 +225,7 @@ impl<'a> Location<'a> { /// assert_ne!(this_location.column(), another_location.column()); /// ``` #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] #[track_caller] pub const fn caller() -> &'static Location<'static> { crate::intrinsics::caller_location() diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 68977a983aa37..aa9ad395b1840 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -66,7 +66,6 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[allow(unused_attributes)] #[allow_internal_unstable(const_fn_union)] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr` have the same layout. @@ -3358,8 +3357,9 @@ mod private_slice_index { on(T = "str", label = "string indices are ranges of `usize`",), on( all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), - note = "you can use `.chars().nth()` or `.bytes().nth()` -see chapter in The Book " + note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ + for more information, see chapter 8 in The Book: \ + " ), message = "the type `{T}` cannot be indexed by `{Self}`", label = "slice indices are of type `usize` or ranges of `usize`" diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 38eabaaa396e0..cda652c6ea791 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -110,6 +110,7 @@ use self::Ordering::*; use crate::cell::UnsafeCell; use crate::fmt; use crate::intrinsics; +use crate::mem::align_of; use crate::hint::spin_loop; @@ -327,6 +328,27 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -820,6 +842,30 @@ impl AtomicPtr { unsafe { &mut *self.p.get() } } + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + let [] = [(); align_of::() - align_of::<*mut T>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -1104,6 +1150,12 @@ impl From<*mut T> for AtomicPtr { } } +macro_rules! if_not_8_bit { + (u8, $($tt:tt)*) => { "" }; + (i8, $($tt:tt)*) => { "" }; + ($_:ident, $($tt:tt)*) => { $($tt)* }; +} + #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, @@ -1115,7 +1167,8 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $s_int_type:expr, $int_ref:expr, + $(from_mut: cfg($from_mut_cfg:meta),)? + $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, $align:expr, @@ -1226,6 +1279,45 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); } } + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + $(#[cfg($from_mut_cfg)])? + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + let [] = [(); align_of::() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same on all platforms enabled by `$from_mut_cfg` + // as verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } + } + } + doc_comment! { concat!("Consumes the atomic and returns the contained value. @@ -1984,6 +2076,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "i64", "../../../std/primitive.i64.html", "", atomic_min, atomic_max, @@ -2002,6 +2095,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), unstable(feature = "integer_atomics", issue = "32976"), + from_mut: cfg(not(target_arch = "x86")), "u64", "../../../std/primitive.u64.html", "", atomic_umin, atomic_umax, diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 0b97508394789..3244bbc2d670d 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -397,3 +397,14 @@ fn test_is_ascii_align_size_thoroughly() { } } } + +#[test] +fn ascii_const() { + // test that the `is_ascii` methods of `char` and `u8` are usable in a const context + + const CHAR_IS_ASCII: bool = 'a'.is_ascii(); + assert!(CHAR_IS_ASCII); + + const BYTE_IS_ASCII: bool = 97u8.is_ascii(); + assert!(BYTE_IS_ASCII); +} diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index 48aec6d718d3d..825e5e63b59bc 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -195,3 +195,20 @@ fn test_nonzero_from_int_on_err() { assert!(NonZeroI8::try_from(0).is_err()); assert!(NonZeroI32::try_from(0).is_err()); } + +#[test] +fn nonzero_const() { + // test that the methods of `NonZeroX>` are usable in a const context + // Note: only tests NonZero8 + + const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; + + const GET: u8 = NONZERO.get(); + assert_eq!(GET, 5); + + const ZERO: Option = NonZeroU8::new(0); + assert!(ZERO.is_none()); + + const ONE: Option = NonZeroU8::new(1); + assert!(ONE.is_some()); +} diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index a2fba4b4cca95..76a0ae8b9454d 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -809,3 +809,112 @@ fn is_v6() { assert!(!ip.is_ipv4()); assert!(ip.is_ipv6()); } + +#[test] +fn ipv4_const() { + // test that the methods of `Ipv4Addr` are usable in a const context + + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE: bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED: bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment(); + assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!( + IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) + ); + + const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!( + IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) + ); +} + +#[test] +fn ipv6_const() { + // test that the methods of `Ipv6Addr` are usable in a const context + + const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); + + const OCTETS: [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4: Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 1fe27a3460000..83e8853fe7923 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -9,7 +9,6 @@ #![stable(feature = "raw_os", since = "1.1.0")] #[cfg(test)] -#[allow(unused_imports)] mod tests; #[doc(include = "char.md")] diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs index e808faf81d657..e7bb7d7e73e80 100644 --- a/library/std/src/os/raw/tests.rs +++ b/library/std/src/os/raw/tests.rs @@ -1,5 +1,4 @@ use crate::any::TypeId; -use crate::mem; macro_rules! ok { ($($t:ident)*) => {$( diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 73c0a7b403a7b..575882eb459fc 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -159,7 +159,7 @@ pub struct Instant(time::Instant); /// | CloudABI | [clock_time_get (Realtime Clock)] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Realtime Clock)] | -/// | DARWIN | [gettimeofday] | +/// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index e8f52deabd809..9f59936a92d10 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -1,3 +1,7 @@ +// CDB doesn't like how libstd.natvis casts to tuples before this version. +// https://github.com/rust-lang/rust/issues/76352#issuecomment-687640746 +// min-cdb-version: 10.0.18362.1 + // cdb-only // compile-flags:-g diff --git a/src/test/ui/array-slice-vec/slice-2.rs b/src/test/ui/array-slice-vec/slice-2.rs deleted file mode 100644 index 01733f48234f9..0000000000000 --- a/src/test/ui/array-slice-vec/slice-2.rs +++ /dev/null @@ -1,62 +0,0 @@ -// run-pass - -// Test slicing expressions on slices and Vecs. - - -fn main() { - let x: &[isize] = &[1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: Vec = vec![1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: &mut [isize] = &mut [1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } - - let mut x: Vec = vec![1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } -} diff --git a/src/test/ui/array-slice-vec/vec-concat.rs b/src/test/ui/array-slice-vec/vec-concat.rs deleted file mode 100644 index 1f493679b7947..0000000000000 --- a/src/test/ui/array-slice-vec/vec-concat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -use std::vec; - -pub fn main() { - let a: Vec = vec![1, 2, 3, 4, 5]; - let b: Vec = vec![6, 7, 8, 9, 0]; - let mut v: Vec = a; - v.extend_from_slice(&b); - println!("{}", v[9]); - assert_eq!(v[0], 1); - assert_eq!(v[7], 8); - assert_eq!(v[9], 0); -} diff --git a/src/test/ui/array-slice-vec/vec-growth.rs b/src/test/ui/array-slice-vec/vec-growth.rs deleted file mode 100644 index b09f08bb85a82..0000000000000 --- a/src/test/ui/array-slice-vec/vec-growth.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - - - -pub fn main() { - let mut v = vec![1]; - v.push(2); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); -} diff --git a/src/test/ui/array-slice-vec/vec-push.rs b/src/test/ui/array-slice-vec/vec-push.rs deleted file mode 100644 index 466ab3fab1cab..0000000000000 --- a/src/test/ui/array-slice-vec/vec-push.rs +++ /dev/null @@ -1,3 +0,0 @@ -// run-pass - -pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/ui/array-slice-vec/vec-slice.rs b/src/test/ui/array-slice-vec/vec-slice.rs deleted file mode 100644 index 1f090ddd9c97d..0000000000000 --- a/src/test/ui/array-slice-vec/vec-slice.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - -pub fn main() { - let v = vec![1,2,3,4,5]; - let v2 = &v[1..3]; - assert_eq!(v2[0], 2); - assert_eq!(v2[1], 3); -} diff --git a/src/test/ui/array-slice-vec/vec-to_str.rs b/src/test/ui/array-slice-vec/vec-to_str.rs deleted file mode 100644 index a11cfc8e9b5c9..0000000000000 --- a/src/test/ui/array-slice-vec/vec-to_str.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - - -pub fn main() { - assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - - let foo = vec![3, 4]; - let bar: &[isize] = &[4, 5]; - - assert_eq!(format!("{:?}", foo), "[3, 4]"); - assert_eq!(format!("{:?}", bar), "[4, 5]"); -} diff --git a/src/test/ui/array-slice-vec/vec.rs b/src/test/ui/array-slice-vec/vec.rs deleted file mode 100644 index e76c1ab440e6e..0000000000000 --- a/src/test/ui/array-slice-vec/vec.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - - - -pub fn main() { - let v: Vec = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} diff --git a/src/test/ui/const-generics/min-and-full-same-time.rs b/src/test/ui/const-generics/min-and-full-same-time.rs new file mode 100644 index 0000000000000..2365adc3a861f --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.rs @@ -0,0 +1,7 @@ +#![feature(const_generics)] +//~^ ERROR features `const_generics` and `min_const_generics` are incompatible +#![allow(incomplete_features)] +#![feature(min_const_generics)] + + +fn main() {} diff --git a/src/test/ui/const-generics/min-and-full-same-time.stderr b/src/test/ui/const-generics/min-and-full-same-time.stderr new file mode 100644 index 0000000000000..907fec9bbe17a --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.stderr @@ -0,0 +1,13 @@ +error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed + --> $DIR/min-and-full-same-time.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ +... +LL | #![feature(min_const_generics)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const-nonzero.rs b/src/test/ui/consts/const-nonzero.rs deleted file mode 100644 index cf6f8c8d69a26..0000000000000 --- a/src/test/ui/consts/const-nonzero.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - -use std::num::NonZeroU8; - -const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; -const Y: u8 = X.get(); - -const ZERO: Option = NonZeroU8::new(0); -const ONE: Option = NonZeroU8::new(1); - -fn main() { - assert_eq!(Y, 5); - - assert!(ZERO.is_none()); - assert_eq!(ONE.unwrap().get(), 1); -} diff --git a/src/test/ui/consts/cow-is-borrowed.rs b/src/test/ui/consts/cow-is-borrowed.rs deleted file mode 100644 index adebe20f5a255..0000000000000 --- a/src/test/ui/consts/cow-is-borrowed.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -#![feature(cow_is_borrowed)] - -use std::borrow::Cow; - -fn main() { - const COW: Cow = Cow::Borrowed("moo"); - - const IS_BORROWED: bool = COW.is_borrowed(); - assert!(IS_BORROWED); - - const IS_OWNED: bool = COW.is_owned(); - assert!(!IS_OWNED); -} diff --git a/src/test/ui/consts/is_ascii.rs b/src/test/ui/consts/is_ascii.rs deleted file mode 100644 index d8424549f93e6..0000000000000 --- a/src/test/ui/consts/is_ascii.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -static X: bool = 'a'.is_ascii(); -static Y: bool = 'รค'.is_ascii(); - -static BX: bool = b'a'.is_ascii(); -static BY: bool = 192u8.is_ascii(); - -fn main() { - assert!(X); - assert!(!Y); - - assert!(BX); - assert!(!BY); -} diff --git a/src/test/ui/consts/std/net/ipv4.rs b/src/test/ui/consts/std/net/ipv4.rs deleted file mode 100644 index 8c676999ae734..0000000000000 --- a/src/test/ui/consts/std/net/ipv4.rs +++ /dev/null @@ -1,58 +0,0 @@ -// run-pass - -#![feature(ip)] -#![feature(const_ipv4)] - -use std::net::{Ipv4Addr, Ipv6Addr}; - -fn main() { - const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); - - const OCTETS: [u8; 4] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [127, 0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_PRIVATE : bool = IP_ADDRESS.is_private(); - assert!(!IS_PRIVATE); - - const IS_LINK_LOCAL : bool = IP_ADDRESS.is_link_local(); - assert!(!IS_LINK_LOCAL); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_SHARED : bool = IP_ADDRESS.is_shared(); - assert!(!IS_SHARED); - - const IS_IETF_PROTOCOL_ASSIGNMENT : bool = IP_ADDRESS.is_ietf_protocol_assignment(); - assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); - - const IS_BENCHMARKING : bool = IP_ADDRESS.is_benchmarking(); - assert!(!IS_BENCHMARKING); - - const IS_RESERVED : bool = IP_ADDRESS.is_reserved(); - assert!(!IS_RESERVED); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IS_BROADCAST : bool = IP_ADDRESS.is_broadcast(); - assert!(!IS_BROADCAST); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IP_V6_COMPATIBLE : Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); - assert_eq!(IP_V6_COMPATIBLE, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])); - - const IP_V6_MAPPED : Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); - assert_eq!(IP_V6_MAPPED, - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])); -} diff --git a/src/test/ui/consts/std/net/ipv6.rs b/src/test/ui/consts/std/net/ipv6.rs deleted file mode 100644 index e3841c38c2231..0000000000000 --- a/src/test/ui/consts/std/net/ipv6.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -#![feature(ip)] -#![feature(const_ipv6)] - -use std::net::{Ipv4Addr, Ipv6Addr, Ipv6MulticastScope}; - -fn main() { - const IP_ADDRESS : Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); - assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); - - const SEGMENTS : [u16; 8] = IP_ADDRESS.segments(); - assert_eq!(SEGMENTS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 1]); - - const OCTETS : [u8; 16] = IP_ADDRESS.octets(); - assert_eq!(OCTETS, [0 ,0 ,0 ,0 ,0 ,0 ,0, 0 ,0 ,0 ,0 ,0 ,0 ,0, 0, 1]); - - const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); - assert!(!IS_UNSPECIFIED); - - const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); - assert!(IS_LOOPBACK); - - const IS_GLOBAL : bool = IP_ADDRESS.is_global(); - assert!(!IS_GLOBAL); - - const IS_UNIQUE_LOCAL : bool = IP_ADDRESS.is_unique_local(); - assert!(!IS_UNIQUE_LOCAL); - - const IS_UNICAST_LINK_LOCAL_STRICT : bool = IP_ADDRESS.is_unicast_link_local_strict(); - assert!(!IS_UNICAST_LINK_LOCAL_STRICT); - - const IS_UNICAST_LINK_LOCAL : bool = IP_ADDRESS.is_unicast_link_local(); - assert!(!IS_UNICAST_LINK_LOCAL); - - const IS_UNICAST_SITE_LOCAL : bool = IP_ADDRESS.is_unicast_site_local(); - assert!(!IS_UNICAST_SITE_LOCAL); - - const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); - assert!(!IS_DOCUMENTATION); - - const IS_UNICAST_GLOBAL : bool = IP_ADDRESS.is_unicast_global(); - assert!(!IS_UNICAST_GLOBAL); - - const MULTICAST_SCOPE : Option = IP_ADDRESS.multicast_scope(); - assert_eq!(MULTICAST_SCOPE, None); - - const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); - assert!(!IS_MULTICAST); - - const IP_V4 : Option = IP_ADDRESS.to_ipv4(); - assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); -} diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index ef7ce735868cb..f323ba03c012c 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -6,7 +6,7 @@ LL | let _: u8 = s[4]; | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: = note: required because of the requirements on the impl of `Index<{integer}>` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` @@ -17,7 +17,7 @@ LL | let _ = s.get(4); | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:5:29 @@ -27,7 +27,7 @@ LL | let _ = s.get_unchecked(4); | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-idx.rs:6:17 diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index abb9b09cf3871..405542820a394 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -39,7 +39,7 @@ LL | s.get_mut(1); | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:11:25 @@ -49,7 +49,7 @@ LL | s.get_unchecked_mut(1); | = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-mut-idx.rs:13:5 diff --git a/src/test/ui/try-block/try-block-in-return.rs b/src/test/ui/try-block/try-block-in-return.rs new file mode 100644 index 0000000000000..a15bfeef1c12d --- /dev/null +++ b/src/test/ui/try-block/try-block-in-return.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn issue_76271() -> Option { + return try { 4 } +} + +fn main() { + assert_eq!(issue_76271(), Some(4)); +} diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 848bd3a43e890..2f832b53a9039 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -261,6 +261,9 @@ pub struct Config { /// Path to / name of the Microsoft Console Debugger (CDB) executable pub cdb: Option, + /// Version of CDB + pub cdb_version: Option<[u16; 4]>, + /// Path to / name of the GDB executable pub gdb: Option, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0efa668ecc88b..17649dfab3750 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; use tracing::*; use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; -use crate::extract_gdb_version; use crate::util; +use crate::{extract_cdb_version, extract_gdb_version}; #[cfg(test)] mod tests; @@ -105,6 +105,10 @@ impl EarlyProps { props.ignore = true; } + if config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln) { + props.ignore = true; + } + if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) { props.ignore = true; } @@ -131,6 +135,21 @@ impl EarlyProps { return props; + fn ignore_cdb(config: &Config, line: &str) -> bool { + if let Some(actual_version) = config.cdb_version { + if let Some(min_version) = line.strip_prefix("min-cdb-version:").map(str::trim) { + let min_version = extract_cdb_version(min_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", min_version); + }); + + // Ignore if actual version is smaller than the minimum + // required version + return actual_version < min_version; + } + } + false + } + fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { @@ -142,8 +161,8 @@ impl EarlyProps { if start_ver != end_ver { panic!("Expected single GDB version") } - // Ignore if actual version is smaller the minimum required - // version + // Ignore if actual version is smaller than the minimum + // required version return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index adf2fa7fd8ecc..190a9c6221060 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -163,7 +163,7 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); - let cdb = analyze_cdb(matches.opt_str("cdb"), &target); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); let (lldb_version, lldb_native_rust) = matches @@ -216,6 +216,7 @@ pub fn parse_config(args: Vec) -> Config { target, host: opt_str2(matches.opt_str("host")), cdb, + cdb_version, gdb, gdb_version, gdb_native_rust, @@ -773,8 +774,30 @@ fn find_cdb(target: &str) -> Option { } /// Returns Path to CDB -fn analyze_cdb(cdb: Option, target: &str) -> Option { - cdb.map(OsString::from).or_else(|| find_cdb(target)) +fn analyze_cdb(cdb: Option, target: &str) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) } /// Returns (Path to GDB, GDB Version, GDB has Rust Support)