diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index e0903e4324124..dff22855629a8 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -60,18 +60,13 @@ pub trait WithStartNode: DirectedGraph { } pub trait ControlFlowGraph: - DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes + DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes { // convenient trait } impl ControlFlowGraph for T where - T: DirectedGraph - + WithStartNode - + WithPredecessors - + WithStartNode - + WithSuccessors - + WithNumNodes + T: DirectedGraph + WithStartNode + WithPredecessors + WithSuccessors + WithNumNodes { } diff --git a/compiler/rustc_error_codes/src/error_codes/E0530.md b/compiler/rustc_error_codes/src/error_codes/E0530.md index 502f674fc1d21..60fa711cbed36 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0530.md +++ b/compiler/rustc_error_codes/src/error_codes/E0530.md @@ -1,32 +1,57 @@ A binding shadowed something it shouldn't. -Erroneous code example: +A match arm or a variable has a name that is already used by +something else, e.g. + +* struct name +* enum variant +* static +* associated constant + +This error may also happen when an enum variant *with fields* is used +in a pattern, but without its fields. + +```compile_fail +enum Enum { + WithField(i32) +} + +use Enum::*; +match WithField(1) { + WithField => {} // error: missing (_) +} +``` + +Match bindings cannot shadow statics: ```compile_fail,E0530 static TEST: i32 = 0; -let r: (i32, i32) = (0, 0); +let r = 123; match r { - TEST => {} // error: match bindings cannot shadow statics + TEST => {} // error: name of a static } ``` -To fix this error, just change the binding's name in order to avoid shadowing -one of the following: +Fixed examples: -* struct name -* struct/enum variant -* static -* const -* associated const +``` +static TEST: i32 = 0; -Fixed example: +let r = 123; +match r { + some_value => {} // ok! +} +``` + +or ``` -static TEST: i32 = 0; +const TEST: i32 = 0; // const, not static -let r: (i32, i32) = (0, 0); +let r = 123; match r { - something => {} // ok! + TEST => {} // const is ok! + other_values => {} } ``` diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0c64fe6ea60a9..1b4e6b4e38177 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -55,7 +55,8 @@ pub(super) fn mangle( let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate); - let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false } + let mut printer = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false }; + printer .print_def_path( def_id, if let ty::InstanceDef::DropGlue(_, _) = instance.def { @@ -198,7 +199,7 @@ struct SymbolPrinter<'tcx> { // `PrettyPrinter` aka pretty printing of e.g. types in paths, // symbol names should have their own printing machinery. -impl Printer<'tcx> for SymbolPrinter<'tcx> { +impl Printer<'tcx> for &mut SymbolPrinter<'tcx> { type Error = fmt::Error; type Path = Self; @@ -242,7 +243,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { Ok(self) } - fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result { + fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result { // only print integers if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val { if ct.ty.is_integral() { @@ -253,7 +254,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { Ok(self) } - fn path_crate(mut self, cnum: CrateNum) -> Result { + fn path_crate(self, cnum: CrateNum) -> Result { self.write_str(&self.tcx.crate_name(cnum).as_str())?; Ok(self) } @@ -344,7 +345,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { } } -impl PrettyPrinter<'tcx> for SymbolPrinter<'tcx> { +impl PrettyPrinter<'tcx> for &mut SymbolPrinter<'tcx> { fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool { false } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 3f713ce3c3914..ac07cc1f03439 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -245,9 +245,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let ObligationCauseCode::WellFormed(Some(wf_loc)) = root_obligation.cause.code.peel_derives() { - if let Some(cause) = - self.tcx.diagnostic_hir_wf_check((obligation.predicate, wf_loc.clone())) - { + if let Some(cause) = self.tcx.diagnostic_hir_wf_check(( + tcx.erase_regions(obligation.predicate), + wf_loc.clone(), + )) { obligation.cause = cause; span = obligation.cause.span; } diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 831b573e1568a..a536285651102 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -1313,15 +1313,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - let no_accessible_remaining_fields = remaining_fields - .iter() - .find(|(_, (_, field))| { - field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) - }) - .is_none(); + let inaccessible_remaining_fields = remaining_fields.iter().any(|(_, (_, field))| { + !field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + }); - if no_accessible_remaining_fields { - self.report_no_accessible_fields(adt_ty, span); + if inaccessible_remaining_fields { + self.report_inaccessible_fields(adt_ty, span); } else { self.report_missing_fields(adt_ty, span, remaining_fields); } @@ -1398,7 +1395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .emit(); } - /// Report an error for a struct field expression when there are no visible fields. + /// Report an error for a struct field expression when there are invisible fields. /// /// ```text /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields @@ -1409,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// error: aborting due to previous error /// ``` - fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { + fn report_inaccessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { self.tcx.sess.span_err( span, &format!( diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 77586ce48529c..c7a7462668aa5 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1695,8 +1695,8 @@ fn print_disambiguation_help( source_map: &source_map::SourceMap, ) { let mut applicability = Applicability::MachineApplicable; - let sugg_args = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { - format!( + let (span, sugg) = if let (ty::AssocKind::Fn, Some(args)) = (kind, args) { + let args = format!( "({}{})", if rcvr_ty.is_region_ptr() { if rcvr_ty.is_mutable_ptr() { "&mut " } else { "&" } @@ -1710,12 +1710,12 @@ fn print_disambiguation_help( })) .collect::>() .join(", "), - ) + ); + (span, format!("{}::{}{}", trait_name, item_name, args)) } else { - String::new() + (span.with_hi(item_name.span.lo()), format!("{}::", trait_name)) }; - let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); - err.span_suggestion( + err.span_suggestion_verbose( span, &format!( "disambiguate the {} for {}", diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index db77d155a2bae..dae574bb7bf0f 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1250,15 +1250,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - let no_accessible_unmentioned_fields = !unmentioned_fields.iter().any(|(field, _)| { - field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) - }); + let accessible_unmentioned_fields: Vec<_> = unmentioned_fields + .iter() + .copied() + .filter(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }) + .collect(); - if no_accessible_unmentioned_fields { + if accessible_unmentioned_fields.is_empty() { unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); } else { - unmentioned_err = - Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields)); + unmentioned_err = Some(self.error_unmentioned_fields( + pat, + &accessible_unmentioned_fields, + accessible_unmentioned_fields.len() != unmentioned_fields.len(), + &fields, + )); } } match (inexistent_fields_err, unmentioned_err) { @@ -1583,17 +1591,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &Pat<'_>, unmentioned_fields: &[(&ty::FieldDef, Ident)], + have_inaccessible_fields: bool, fields: &'tcx [hir::PatField<'tcx>], ) -> DiagnosticBuilder<'tcx> { + let inaccessible = if have_inaccessible_fields { " and inaccessible fields" } else { "" }; let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`", unmentioned_fields[0].1) + format!("field `{}`{}", unmentioned_fields[0].1, inaccessible) } else { let fields = unmentioned_fields .iter() .map(|(_, name)| format!("`{}`", name)) .collect::>() .join(", "); - format!("fields {}", fields) + format!("fields {}{}", fields, inaccessible) }; let mut err = struct_span_err!( self.tcx.sess, @@ -1624,17 +1634,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion( sp, &format!( - "include the missing field{} in the pattern", + "include the missing field{} in the pattern{}", if len == 1 { "" } else { "s" }, + if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" } ), format!( - "{}{}{}", + "{}{}{}{}", prefix, unmentioned_fields .iter() .map(|(_, name)| name.to_string()) .collect::>() .join(", "), + if have_inaccessible_fields { ", .." } else { "" }, postfix, ), Applicability::MachineApplicable, diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 96b3fa9aa0143..b9483d6f98760 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -190,8 +190,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // Try to use the segment resolution if it is valid, otherwise we // default to the path resolution. let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res); + use def::CtorOf; let generics = match res { - Res::Def(DefKind::Ctor(..), def_id) => { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of( + tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(), + ), + Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => { tcx.generics_of(tcx.parent(def_id).unwrap()) } // Other `DefKind`s don't have generics and would ICE when calling @@ -200,7 +204,6 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< DefKind::Struct | DefKind::Union | DefKind::Enum - | DefKind::Variant | DefKind::Trait | DefKind::OpaqueTy | DefKind::TyAlias diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index 1d3a12962145e..75ef873abc965 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -45,7 +45,8 @@ impl_float_to_int!(f64 => u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); macro_rules! impl_from { ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] - impl From<$Small> for $Large { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const From<$Small> for $Large { // Rustdocs on the impl block show a "[+] show undocumented items" toggle. // Rustdocs on functions do not. #[doc = $doc] @@ -172,7 +173,8 @@ impl_from! { f32, f64, #[stable(feature = "lossless_float_conv", since = "1.6.0" macro_rules! try_from_unbounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -190,7 +192,8 @@ macro_rules! try_from_unbounded { macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -212,7 +215,8 @@ macro_rules! try_from_lower_bounded { macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source @@ -234,7 +238,8 @@ macro_rules! try_from_upper_bounded { macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( #[stable(feature = "try_from", since = "1.34.0")] - impl TryFrom<$source> for $target { + #[rustc_const_unstable(feature = "const_num_from_num", issue = "87852")] + impl const TryFrom<$source> for $target { type Error = TryFromIntError; /// Try to create the target number type from a source diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 222ef34b6aa8a..37c3f8d4c16ab 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -99,6 +99,7 @@ #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_swap)] +#![feature(const_trait_impl)] #![feature(const_type_id)] #![feature(const_type_name)] #![feature(const_unreachable_unchecked)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index d4e9c384f9302..3f9f04606b36a 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1399,6 +1399,33 @@ impl Option { } } +impl Option<(T, U)> { + /// Unzips an option containing a tuple of two options + /// + /// If `self` is `Some((a, b))` this method returns `(Some(a), Some(b))`. + /// Otherwise, `(None, None)` is returned. + /// + /// # Examples + /// + /// ``` + /// #![feature(unzip_option)] + /// + /// let x = Some((1, "hi")); + /// let y = None::<(u8, u32)>; + /// + /// assert_eq!(x.unzip(), (Some(1), Some("hi"))); + /// assert_eq!(y.unzip(), (None, None)); + /// ``` + #[inline] + #[unstable(feature = "unzip_option", issue = "87800", reason = "recently added")] + pub const fn unzip(self) -> (Option, Option) { + match self { + Some((a, b)) => (Some(a), Some(b)), + None => (None, None), + } + } +} + impl Option<&T> { /// Maps an `Option<&T>` to an `Option` by copying the contents of the /// option. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index c7756a503c3e9..13f483f19b770 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,6 +13,8 @@ #![feature(const_ptr_read)] #![feature(const_ptr_write)] #![feature(const_ptr_offset)] +#![feature(const_trait_impl)] +#![feature(const_num_from_num)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -66,6 +68,7 @@ #![feature(slice_group_by)] #![feature(trusted_random_access)] #![feature(unsize)] +#![feature(unzip_option)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; diff --git a/library/core/tests/num/const_from.rs b/library/core/tests/num/const_from.rs new file mode 100644 index 0000000000000..aca18ef39de1a --- /dev/null +++ b/library/core/tests/num/const_from.rs @@ -0,0 +1,25 @@ +#[test] +fn from() { + use core::convert::TryFrom; + use core::num::TryFromIntError; + + // From + const FROM: i64 = i64::from(1i32); + assert_eq!(FROM, 1i64); + + // From int to float + const FROM_F64: f64 = f64::from(42u8); + assert_eq!(FROM_F64, 42f64); + + // Upper bounded + const U8_FROM_U16: Result = u8::try_from(1u16); + assert_eq!(U8_FROM_U16, Ok(1u8)); + + // Both bounded + const I8_FROM_I16: Result = i8::try_from(1i16); + assert_eq!(I8_FROM_I16, Ok(1i8)); + + // Lower bounded + const I16_FROM_U16: Result = i16::try_from(1u16); + assert_eq!(I16_FROM_U16, Ok(1i16)); +} diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 76e838cf6bfbd..37b5e9127d5b0 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -27,6 +27,8 @@ mod u64; mod u8; mod bignum; + +mod const_from; mod dec2flt; mod flt2dec; mod int_log; diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 88ea15a3b33fa..cd8fdebe36a05 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -399,7 +399,7 @@ fn test_unwrap_drop() { } #[test] -pub fn option_ext() { +fn option_ext() { let thing = "{{ f }}"; let f = thing.find("{{"); @@ -407,3 +407,35 @@ pub fn option_ext() { println!("None!"); } } + +#[test] +fn zip_options() { + let x = Some(10); + let y = Some("foo"); + let z: Option = None; + + assert_eq!(x.zip(y), Some((10, "foo"))); + assert_eq!(x.zip(z), None); + assert_eq!(z.zip(x), None); +} + +#[test] +fn unzip_options() { + let x = Some((10, "foo")); + let y = None::<(bool, i32)>; + + assert_eq!(x.unzip(), (Some(10), Some("foo"))); + assert_eq!(y.unzip(), (None, None)); +} + +#[test] +fn zip_unzip_roundtrip() { + let x = Some(10); + let y = Some("foo"); + + let z = x.zip(y); + assert_eq!(z, Some((10, "foo"))); + + let a = z.unzip(); + assert_eq!(a, (x, y)); +} diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 240b894057c3e..43e2af3eb18d2 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -739,6 +739,10 @@ fn test_array_windows_count() { let v3: &[i32] = &[]; let c3 = v3.array_windows::<2>(); assert_eq!(c3.count(), 0); + + let v4: &[()] = &[(); usize::MAX]; + let c4 = v4.array_windows::<1>(); + assert_eq!(c4.count(), usize::MAX); } #[test] @@ -1050,6 +1054,10 @@ fn test_windows_count() { let v3: &[i32] = &[]; let c3 = v3.windows(2); assert_eq!(c3.count(), 0); + + let v4 = &[(); usize::MAX]; + let c4 = v4.windows(1); + assert_eq!(c4.count(), usize::MAX); } #[test] diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 36e1d502019b7..f44df845bf4dd 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -28,7 +28,7 @@ //! When the main thread of a Rust program terminates, the entire program shuts //! down, even if other threads are still running. However, this module provides //! convenient facilities for automatically waiting for the termination of a -//! child thread (i.e., join). +//! thread (i.e., join). //! //! ## Spawning a thread //! @@ -42,38 +42,43 @@ //! }); //! ``` //! -//! In this example, the spawned thread is "detached" from the current -//! thread. This means that it can outlive its parent (the thread that spawned -//! it), unless this parent is the main thread. +//! In this example, the spawned thread is "detached," which means that there is +//! no way for the program to learn when the spawned thread completes or otherwise +//! terminates. //! -//! The parent thread can also wait on the completion of the child -//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides -//! a `join` method for waiting: +//! To learn when a thread completes, it is necessary to capture the [`JoinHandle`] +//! object that is returned by the call to [`spawn`], which provides +//! a `join` method that allows the caller to wait for the completion of the +//! spawned thread: //! //! ```rust //! use std::thread; //! -//! let child = thread::spawn(move || { +//! let thread_join_handle = thread::spawn(move || { //! // some work here //! }); //! // some work here -//! let res = child.join(); +//! let res = thread_join_handle.join(); //! ``` //! //! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final -//! value produced by the child thread, or [`Err`] of the value given to -//! a call to [`panic!`] if the child panicked. +//! value produced by the spawned thread, or [`Err`] of the value given to +//! a call to [`panic!`] if the thread panicked. +//! +//! Note that there is no parent/child relationship between a thread that spawns a +//! new thread and the thread being spawned. In particular, the spawned thread may or +//! may not outlive the spawning thread, unless the spawning thread is the main thread. //! //! ## Configuring threads //! //! A new thread can be configured before it is spawned via the [`Builder`] type, -//! which currently allows you to set the name and stack size for the child thread: +//! which currently allows you to set the name and stack size for the thread: //! //! ```rust //! # #![allow(unused_must_use)] //! use std::thread; //! -//! thread::Builder::new().name("child1".to_string()).spawn(move || { +//! thread::Builder::new().name("thread1".to_string()).spawn(move || { //! println!("Hello, world!"); //! }); //! ``` @@ -344,7 +349,7 @@ impl Builder { /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on - /// termination of the child thread, including recovering its panics. + /// termination of the spawned thread, including recovering its panics. /// /// For a more complete documentation see [`thread::spawn`][`spawn`]. /// @@ -389,7 +394,7 @@ impl Builder { /// The spawned thread may outlive the caller (unless the caller thread /// is the main thread; the whole process is terminated when the main /// thread finishes). The join handle can be used to block on - /// termination of the child thread, including recovering its panics. + /// termination of the spawned thread, including recovering its panics. /// /// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`], /// except for the relaxed lifetime bounds, which render it unsafe. @@ -516,15 +521,16 @@ impl Builder { /// Spawns a new thread, returning a [`JoinHandle`] for it. /// -/// The join handle will implicitly *detach* the child thread upon being -/// dropped. In this case, the child thread may outlive the parent (unless -/// the parent thread is the main thread; the whole process is terminated when -/// the main thread finishes). Additionally, the join handle provides a [`join`] -/// method that can be used to join the child thread. If the child thread -/// panics, [`join`] will return an [`Err`] containing the argument given to -/// [`panic!`]. +/// The join handle provides a [`join`] method that can be used to join the spawned +/// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing +/// the argument given to [`panic!`]. +/// +/// If the join handle is dropped, the spawned thread will implicitly be *detached*. +/// In this case, the spawned thread may no longer be joined. +/// (It is the responsibility of the program to either eventually join threads it +/// creates or detach them; otherwise, a resource leak will result.) /// -/// This will create a thread using default parameters of [`Builder`], if you +/// This call will create a thread using default parameters of [`Builder`], if you /// want to specify the stack size or the name of the thread, use this API /// instead. /// @@ -533,8 +539,8 @@ impl Builder { /// /// - The `'static` constraint means that the closure and its return value /// must have a lifetime of the whole program execution. The reason for this -/// is that threads can `detach` and outlive the lifetime they have been -/// created in. +/// is that threads can outlive the lifetime they have been created in. +/// /// Indeed if the thread, and by extension its return value, can outlive their /// caller, we need to make sure that they will be valid afterwards, and since /// we *can't* know when it will return we need to have them valid as long as @@ -1236,10 +1242,10 @@ impl fmt::Debug for Thread { #[stable(feature = "rust1", since = "1.0.0")] pub type Result = crate::result::Result>; -// This packet is used to communicate the return value between the child thread -// and the parent thread. Memory is shared through the `Arc` within and there's +// This packet is used to communicate the return value between the spawned thread +// and the rest of the program. Memory is shared through the `Arc` within and there's // no need for a mutex here because synchronization happens with `join()` (the -// parent thread never reads this packet until the child has exited). +// caller will never read this packet until the thread has exited). // // This packet itself is then stored into a `JoinInner` which in turns is placed // in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to @@ -1303,7 +1309,7 @@ impl JoinInner { /// }).unwrap(); /// ``` /// -/// Child being detached and outliving its parent: +/// A thread being detached and outliving the thread that spawned it: /// /// ```no_run /// use std::thread; @@ -1361,12 +1367,15 @@ impl JoinHandle { /// Waits for the associated thread to finish. /// + /// This function will return immediately if the associated thread has already finished. + /// /// In terms of [atomic memory orderings], the completion of the associated /// thread synchronizes with this function returning. In other words, all - /// operations performed by that thread are ordered before all + /// operations performed by that thread [happen + /// before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) all /// operations that happen after `join` returns. /// - /// If the child thread panics, [`Err`] is returned with the parameter given + /// If the associated thread panics, [`Err`] is returned with the parameter given /// to [`panic!`]. /// /// [`Err`]: crate::result::Result::Err diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index b5d20a6a4cd81..5718a18393f9c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -115,6 +115,7 @@ The `std` column in the table below has the following meanings: target | std | notes -------|:---:|------- `aarch64-apple-ios` | ✓ | ARM64 iOS +[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64 `aarch64-fuchsia` | ✓ | ARM64 Fuchsia `aarch64-linux-android` | ✓ | ARM64 Android `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat @@ -165,7 +166,6 @@ target | std | notes `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI `x86_64-apple-ios` | ✓ | 64-bit x86 iOS -[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | | Apple iOS Simulator on ARM64 `x86_64-fortanix-unknown-sgx` | ✓ | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | 64-bit Fuchsia `x86_64-linux-android` | ✓ | 64-bit x86 Android diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index cb7b85655b5a8..70900a0bab942 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -297,9 +297,14 @@ we can add the `#[macro_use]` attribute. Second, we’ll need to add our own ## Attributes -There are a few annotations that are useful to help `rustdoc` do the right +Code blocks can be annotated with attributes that help `rustdoc` do the right thing when testing your code: +The `ignore` attribute tells Rust to ignore your code. This is almost never +what you want as it's the most generic. Instead, consider annotating it +with `text` if it's not code or using `#`s to get a working example that +only shows the part you care about. + ```rust /// ```ignore /// fn foo() { @@ -307,10 +312,8 @@ thing when testing your code: # fn foo() {} ``` -The `ignore` directive tells Rust to ignore your code. This is almost never -what you want, as it's the most generic. Instead, consider annotating it -with `text` if it's not code, or using `#`s to get a working example that -only shows the part you care about. +`should_panic` tells `rustdoc` that the code should compile correctly but +panic during execution. If the code doesn't panic, the test will fail. ```rust /// ```should_panic @@ -319,8 +322,10 @@ only shows the part you care about. # fn foo() {} ``` -`should_panic` tells `rustdoc` that the code should compile correctly, but -not actually pass as a test. +The `no_run` attribute will compile your code but not run it. This is +important for examples such as "Here's how to retrieve a web page," +which you would want to ensure compiles, but might be run in a test +environment that has no network access. ```rust /// ```no_run @@ -331,24 +336,24 @@ not actually pass as a test. # fn foo() {} ``` -The `no_run` attribute will compile your code, but not run it. This is -important for examples such as "Here's how to retrieve a web page," -which you would want to ensure compiles, but might be run in a test -environment that has no network access. +`compile_fail` tells `rustdoc` that the compilation should fail. If it +compiles, then the test will fail. However, please note that code failing +with the current Rust release may work in a future release, as new features +are added. -```text +```rust /// ```compile_fail /// let x = 5; /// x += 2; // shouldn't compile! /// ``` +# fn foo() {} ``` -`compile_fail` tells `rustdoc` that the compilation should fail. If it -compiles, then the test will fail. However please note that code failing -with the current Rust release may work in a future release, as new features -are added. +`edition2018` tells `rustdoc` that the code sample should be compiled using +the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile +the code with the 2015 edition. -```text +```rust /// Only runs on the 2018 edition. /// /// ```edition2018 @@ -358,12 +363,9 @@ are added. /// + "3".parse::()? /// }; /// ``` +# fn foo() {} ``` -`edition2018` tells `rustdoc` that the code sample should be compiled using -the 2018 edition of Rust. Similarly, you can specify `edition2015` to compile -the code with the 2015 edition. - ## Syntax reference The *exact* syntax for code blocks, including the edge cases, can be found @@ -385,7 +387,7 @@ section. However, it's preferable to use fenced code blocks over indented code blocks. Not only are fenced code blocks considered more idiomatic for Rust code, -but there is no way to use directives such as `ignore` or `should_panic` with +but there is no way to use attributes such as `ignore` or `should_panic` with indented code blocks. ### Include items only when collecting doctests diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index 849924ea5501e..8dd7b2b3edc40 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -37,7 +37,7 @@ h4 { .docblock code { color: #ffb454; } -h3 > code, h4 > code, h5 > code { +.code-header { color: #e6e1cf; } pre > code { diff --git a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr index c5e32afbbce40..fc94ef2ff8872 100644 --- a/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-consts/associated-const-ambiguity-report.stderr @@ -17,11 +17,11 @@ LL | const ID: i32 = 3; help: disambiguate the associated constant for candidate #1 | LL | const X: i32 = Foo::ID; - | ^^^^^^^ + | ^^^^^ help: disambiguate the associated constant for candidate #2 | LL | const X: i32 = Bar::ID; - | ^^^^^^^ + | ^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/enum-variants.rs b/src/test/ui/const-generics/enum-variants.rs new file mode 100644 index 0000000000000..5c6c4a8efac15 --- /dev/null +++ b/src/test/ui/const-generics/enum-variants.rs @@ -0,0 +1,24 @@ +// check-pass +enum Foo { + Variant, + Variant2(), + Variant3{}, +} + +struct Bar; +struct Bar2(); +struct Bar3 {} + +fn main() { + let _ = Foo::Variant::<1>; + let _ = Foo::Variant2::<1>(); + let _ = Foo::Variant3::<1>{}; + + let _ = Foo::<1>::Variant; + let _ = Foo::<1>::Variant2(); + let _ = Foo::<1>::Variant3{}; + + let _ = Bar::<1>; + let _ = Bar2::<1>(); + let _ = Bar3::<1>{}; +} diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index 471512ca8f72c..55119857d8f83 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -17,11 +17,11 @@ LL | fn foo() {} help: disambiguate the associated function for candidate #1 | LL | Trait1::foo() - | ^^^^^^^^^^^ + | ^^^^^^^^ help: disambiguate the associated function for candidate #2 | LL | Trait2::foo() - | ^^^^^^^^^^^ + | ^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr index 11c8cfdcf66a5..33cf76d777bb6 100644 --- a/src/test/ui/issues/issue-18446.stderr +++ b/src/test/ui/issues/issue-18446.stderr @@ -2,10 +2,7 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-18446.rs:18:7 | LL | x.foo(); - | --^^^-- - | | | - | | multiple `foo` found - | help: disambiguate the associated function for candidate #2: `T::foo(&x)` + | ^^^ multiple `foo` found | note: candidate #1 is defined in an impl for the type `(dyn T + 'a)` --> $DIR/issue-18446.rs:9:5 @@ -17,6 +14,10 @@ note: candidate #2 is defined in the trait `T` | LL | fn foo(&self); | ^^^^^^^^^^^^^^ +help: disambiguate the associated function for candidate #2 + | +LL | T::foo(&x); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 85b3964788590..7bfb8baa0c643 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -17,11 +17,11 @@ LL | fn foo() {} help: disambiguate the associated function for candidate #1 | LL | A::foo(); - | ^^^^^^ + | ^^^ help: disambiguate the associated function for candidate #2 | LL | B::foo(); - | ^^^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 16a1ac6d71814..f789441378fe4 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -61,10 +61,7 @@ error[E0599]: no method named `is_str` found for type parameter `T` in the curre --> $DIR/issue-7575.rs:70:7 | LL | t.is_str() - | --^^^^^^-- - | | | - | | this is an associated function, not a method - | help: disambiguate the associated function for the candidate: `ManyImplTrait::is_str(t)` + | ^^^^^^ this is an associated function, not a method | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: the candidate is defined in the trait `ManyImplTrait` @@ -73,6 +70,10 @@ note: the candidate is defined in the trait `ManyImplTrait` LL | fn is_str() -> bool { | ^^^^^^^^^^^^^^^^^^^ = help: items from traits can only be used if the type parameter is bounded by the trait +help: disambiguate the associated function for the candidate + | +LL | ManyImplTrait::is_str(t) + | error: aborting due to 3 previous errors diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs new file mode 100644 index 0000000000000..3176144133760 --- /dev/null +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.rs @@ -0,0 +1,11 @@ +pub mod foo { + pub struct Foo { + pub you_can_use_this_field: bool, + you_cant_use_this_field: bool, + } +} + +fn main() { + foo::Foo {}; + //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields +} diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr new file mode 100644 index 0000000000000..81b73c00e8600 --- /dev/null +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-literal.stderr @@ -0,0 +1,8 @@ +error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + --> $DIR/issue-87872-missing-inaccessible-field-literal.rs:9:5 + | +LL | foo::Foo {}; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs new file mode 100644 index 0000000000000..d28e17559d879 --- /dev/null +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs @@ -0,0 +1,11 @@ +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo {} = foo::Foo::default(); + //~^ ERROR pattern does not mention field `visible` and inaccessible fields +} diff --git a/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr new file mode 100644 index 0000000000000..51b8e39b101a3 --- /dev/null +++ b/src/test/ui/typeck/issue-87872-missing-inaccessible-field-pattern.stderr @@ -0,0 +1,18 @@ +error[E0027]: pattern does not mention field `visible` and inaccessible fields + --> $DIR/issue-87872-missing-inaccessible-field-pattern.rs:9:9 + | +LL | let foo::Foo {} = foo::Foo::default(); + | ^^^^^^^^^^^ missing field `visible` and inaccessible fields + | +help: include the missing field in the pattern and ignore the inaccessible fields + | +LL | let foo::Foo { visible, .. } = foo::Foo::default(); + | ^^^^^^^^^^^^^^^ +help: if you don't care about this missing field, you can explicitly ignore it + | +LL | let foo::Foo { .. } = foo::Foo::default(); + | ^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/wf/hir-wf-check-erase-regions.rs b/src/test/ui/wf/hir-wf-check-erase-regions.rs new file mode 100644 index 0000000000000..bb398e5698a80 --- /dev/null +++ b/src/test/ui/wf/hir-wf-check-erase-regions.rs @@ -0,0 +1,14 @@ +// Regression test for #87549. +// compile-flags: -C incremental=tmp/wf/hir-wf-check-erase-regions + +pub struct Table([Option; N]); + +impl<'a, T, const N: usize> IntoIterator for &'a Table { + type IntoIter = std::iter::Flatten>; //~ ERROR `&T` is not an iterator + type Item = &'a T; + + fn into_iter(self) -> Self::IntoIter { //~ ERROR `&T` is not an iterator + unimplemented!() + } +} +fn main() {} diff --git a/src/test/ui/wf/hir-wf-check-erase-regions.stderr b/src/test/ui/wf/hir-wf-check-erase-regions.stderr new file mode 100644 index 0000000000000..a704754e82a92 --- /dev/null +++ b/src/test/ui/wf/hir-wf-check-erase-regions.stderr @@ -0,0 +1,31 @@ +error[E0277]: `&T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:7:5 + | +LL | type IntoIter = std::iter::Flatten>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&T` is not an iterator + | + ::: $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL + | +LL | pub struct Flatten> { + | ------------ required by this bound in `Flatten` + | + = help: the trait `Iterator` is not implemented for `&T` + = note: required because of the requirements on the impl of `IntoIterator` for `&T` + +error[E0277]: `&T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:10:27 + | +LL | fn into_iter(self) -> Self::IntoIter { + | ^^^^^^^^^^^^^^ `&T` is not an iterator + | + ::: $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL + | +LL | pub struct Flatten> { + | ------------ required by this bound in `Flatten` + | + = help: the trait `Iterator` is not implemented for `&T` + = note: required because of the requirements on the impl of `IntoIterator` for `&T` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`.