diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9eb54c2cc0044..e90ee5c285f2f 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1212,7 +1212,7 @@ impl Initializer { /// /// [`write`]: Self::write /// [`flush`]: Self::flush -/// [`std::io`]: index.html +/// [`std::io`]: self /// /// # Examples /// @@ -1590,8 +1590,6 @@ pub trait Seek { /// # Errors /// /// Seeking to a negative offset is considered an error. - /// - /// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start #[stable(feature = "rust1", since = "1.0.0")] fn seek(&mut self, pos: SeekFrom) -> Result; @@ -1678,8 +1676,6 @@ pub trait Seek { /// Enumeration of possible methods to seek within an I/O object. /// /// It is used by the [`Seek`] trait. -/// -/// [`Seek`]: trait.Seek.html #[derive(Copy, PartialEq, Eq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum SeekFrom { @@ -1759,11 +1755,9 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) -> R /// For example, [`File`] implements [`Read`], but not `BufRead`. /// [`BufReader`] to the rescue! /// -/// [`BufReader`]: struct.BufReader.html /// [`File`]: crate::fs::File /// [`read_line`]: Self::read_line /// [`lines`]: Self::lines -/// [`Read`]: trait.Read.html /// /// ```no_run /// use std::io::{self, BufReader}; @@ -1869,7 +1863,6 @@ pub trait BufRead: Read { /// present in `buf` and its length will have been adjusted appropriately. /// /// [`fill_buf`]: Self::fill_buf - /// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted /// /// # Examples /// @@ -1877,8 +1870,6 @@ pub trait BufRead: Read { /// this example, we use [`Cursor`] to read all the bytes in a byte slice /// in hyphen delimited segments: /// - /// [`Cursor`]: struct.Cursor.html - /// /// ``` /// use std::io::{self, BufRead}; /// @@ -1940,8 +1931,6 @@ pub trait BufRead: Read { /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In /// this example, we use [`Cursor`] to read all the lines in a byte slice: /// - /// [`Cursor`]: struct.Cursor.html - /// /// ``` /// use std::io::{self, BufRead}; /// @@ -1996,8 +1985,6 @@ pub trait BufRead: Read { /// this example, we use [`Cursor`] to iterate over all hyphen delimited /// segments in a byte slice /// - /// [`Cursor`]: struct.Cursor.html - /// /// ``` /// use std::io::{self, BufRead}; /// @@ -2046,8 +2033,6 @@ pub trait BufRead: Read { /// # Errors /// /// Each line of the iterator has the same error semantics as [`BufRead::read_line`]. - /// - /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line #[stable(feature = "rust1", since = "1.0.0")] fn lines(self) -> Lines where @@ -2062,7 +2047,7 @@ pub trait BufRead: Read { /// This struct is generally created by calling [`chain`] on a reader. /// Please see the documentation of [`chain`] for more details. /// -/// [`chain`]: trait.Read.html#method.chain +/// [`chain`]: Read::chain #[stable(feature = "rust1", since = "1.0.0")] pub struct Chain { first: T, @@ -2204,7 +2189,7 @@ impl BufRead for Chain { /// This struct is generally created by calling [`take`] on a reader. /// Please see the documentation of [`take`] for more details. /// -/// [`take`]: trait.Read.html#method.take +/// [`take`]: Read::take #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Take { @@ -2403,7 +2388,7 @@ impl BufRead for Take { /// This struct is generally created by calling [`bytes`] on a reader. /// Please see the documentation of [`bytes`] for more details. /// -/// [`bytes`]: trait.Read.html#method.bytes +/// [`bytes`]: Read::bytes #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Bytes { @@ -2433,7 +2418,7 @@ impl Iterator for Bytes { /// This struct is generally created by calling [`split`] on a `BufRead`. /// Please see the documentation of [`split`] for more details. /// -/// [`split`]: trait.BufRead.html#method.split +/// [`split`]: BufRead::split #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Split { @@ -2465,7 +2450,7 @@ impl Iterator for Split { /// This struct is generally created by calling [`lines`] on a `BufRead`. /// Please see the documentation of [`lines`] for more details. /// -/// [`lines`]: trait.BufRead.html#method.lines +/// [`lines`]: BufRead::lines #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Lines { diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f0487e0dff148..1144a13b52c30 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -22,7 +22,7 @@ //! * [`std::*` modules](#modules) //! * [Primitive types](#primitives) //! * [Standard macros](#macros) -//! * [The Rust Prelude](prelude/index.html) +//! * [The Rust Prelude] //! //! If this is your first time, the documentation for the standard library is //! written to be casually perused. Clicking on interesting things should @@ -63,8 +63,8 @@ //! So for example there is a [page for the primitive type //! `i32`](primitive.i32.html) that lists all the methods that can be called on //! 32-bit integers (very useful), and there is a [page for the module -//! `std::i32`](i32/index.html) that documents the constant values [`MIN`] and -//! [`MAX`](i32/constant.MAX.html) (rarely useful). +//! `std::i32`] that documents the constant values [`MIN`] and [`MAX`] (rarely +//! useful). //! //! Note the documentation for the primitives [`str`] and [`[T]`][slice] (also //! called 'slice'). Many method calls on [`String`] and [`Vec`] are actually @@ -152,48 +152,35 @@ //! contains further primitive shared memory types, including [`atomic`] and //! [`mpsc`], which contains the channel types for message passing. //! -//! [I/O]: io/index.html -//! [`MIN`]: i32/constant.MIN.html -//! [TCP]: net/struct.TcpStream.html -//! [The Rust Prelude]: prelude/index.html -//! [UDP]: net/struct.UdpSocket.html -//! [`Arc`]: sync/struct.Arc.html -//! [owned slice]: boxed/index.html -//! [`Cell`]: cell/struct.Cell.html -//! [`FromStr`]: str/trait.FromStr.html -//! [`HashMap`]: collections/struct.HashMap.html -//! [`Iterator`]: iter/trait.Iterator.html -//! [`Mutex`]: sync/struct.Mutex.html -//! [`Option`]: option/enum.Option.html -//! [`Rc`]: rc/struct.Rc.html -//! [`RefCell`]: cell/struct.RefCell.html -//! [`Result`]: result/enum.Result.html -//! [`String`]: string/struct.String.html -//! [`Vec`]: vec/struct.Vec.html -//! [array]: primitive.array.html -//! [slice]: primitive.slice.html -//! [`atomic`]: sync/atomic/index.html -//! [`collections`]: collections/index.html +//! [I/O]: io +//! [`MIN`]: i32::MIN +//! [`MAX`]: i32::MAX +//! [page for the module `std::i32`]: crate::i32 +//! [TCP]: net::TcpStream +//! [The Rust Prelude]: prelude +//! [UDP]: net::UdpSocket +//! [`Arc`]: sync::Arc +//! [owned slice]: boxed +//! [`Cell`]: cell::Cell +//! [`FromStr`]: str::FromStr +//! [`HashMap`]: collections::HashMap +//! [`Mutex`]: sync::Mutex +//! [`Option`]: option::Option +//! [`Rc`]: rc::Rc +//! [`RefCell`]: cell::RefCell +//! [`Result`]: result::Result +//! [`Vec`]: vec::Vec +//! [`atomic`]: sync::atomic //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for -//! [`format!`]: macro.format.html -//! [`fs`]: fs/index.html -//! [`io`]: io/index.html -//! [`iter`]: iter/index.html -//! [`mpsc`]: sync/mpsc/index.html -//! [`net`]: net/index.html -//! [`option`]: option/index.html -//! [`result`]: result/index.html -//! [`std::cmp`]: cmp/index.html -//! [`std::slice`]: slice/index.html -//! [`str`]: primitive.str.html -//! [`sync`]: sync/index.html -//! [`thread`]: thread/index.html +//! [`mpsc`]: sync::mpsc +//! [`std::cmp`]: cmp +//! [`std::slice`]: slice //! [`use std::env`]: env/index.html //! [`use`]: ../book/ch07-02-defining-modules-to-control-scope-and-privacy.html //! [crates.io]: https://crates.io //! [deref-coercions]: ../book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods -//! [files]: fs/struct.File.html -//! [multithreading]: thread/index.html +//! [files]: fs::File +//! [multithreading]: thread //! [other]: #what-is-in-the-standard-library-documentation //! [primitive types]: ../book/ch03-02-data-types.html //! [rust-discord]: https://discord.gg/rust-lang diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index f9c96b7c3d4b3..0d2aca6bbc3eb 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -768,7 +768,8 @@ mod prim_tuple {} /// /// This type can represent a wide range of decimal numbers, like `3.5`, `27`, /// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types -/// (like `i32`), floating point types can represent non-integer numbers, too. +/// (such as `i32`), floating point types can represent non-integer numbers, +/// too. /// /// However, being able to represent this wide range of numbers comes at the /// cost of precision: floats can only represent some of the real numbers and @@ -779,15 +780,12 @@ mod prim_tuple {} /// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will /// print `0.2`. /// -/// The precision is better for numbers near 0 and worse for large numbers. For -/// example, above 224, not even all integers are representable. -/// /// Additionally, `f32` can represent a couple of special values: /// /// - `-0`: this is just due to how floats are encoded. It is semantically /// equivalent to `0` and `-0.0 == 0.0` results in `true`. /// - [∞](#associatedconstant.INFINITY) and -/// [-∞](#associatedconstant.NEG_INFINITY): these result from calculations +/// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations /// like `1.0 / 0.0`. /// - [NaN (not a number)](#associatedconstant.NAN): this value results from /// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 6782d845bb056..8408756f1b3be 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -46,6 +46,7 @@ pub struct DirEntry { pub struct OpenOptions { read: bool, write: bool, + append: bool, dirflags: wasi::Lookupflags, fdflags: wasi::Fdflags, oflags: wasi::Oflags, @@ -270,8 +271,9 @@ impl OpenOptions { } } - pub fn append(&mut self, set: bool) { - self.fdflag(wasi::FDFLAGS_APPEND, set); + pub fn append(&mut self, append: bool) { + self.append = append; + self.fdflag(wasi::FDFLAGS_APPEND, append); } pub fn dsync(&mut self, set: bool) { @@ -321,7 +323,7 @@ impl OpenOptions { base |= wasi::RIGHTS_FD_READ; base |= wasi::RIGHTS_FD_READDIR; } - if self.write { + if self.write || self.append { base |= wasi::RIGHTS_FD_WRITE; base |= wasi::RIGHTS_FD_DATASYNC; base |= wasi::RIGHTS_FD_ALLOCATE; diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 969c442884df2..02161ecb4c8d2 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -359,9 +359,7 @@ impl Add for Instant { /// # Panics /// /// This function may panic if the resulting point in time cannot be represented by the - /// underlying data structure. See [`checked_add`] for a version without panic. - /// - /// [`checked_add`]: Instant::checked_add + /// underlying data structure. See [`Instant::checked_add`] for a version without panic. fn add(self, other: Duration) -> Instant { self.checked_add(other).expect("overflow when adding duration to instant") } @@ -525,9 +523,7 @@ impl Add for SystemTime { /// # Panics /// /// This function may panic if the resulting point in time cannot be represented by the - /// underlying data structure. See [`checked_add`] for a version without panic. - /// - /// [`checked_add`]: SystemTime::checked_add + /// underlying data structure. See [`SystemTime::checked_add`] for a version without panic. fn add(self, dur: Duration) -> SystemTime { self.checked_add(dur).expect("overflow when adding duration to instant") } diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 244377dfa1d2c..3c2a063cf2481 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -777,7 +777,7 @@ fn validate_generic_param_order<'a>( if sess.features_untracked().const_generics { ", then consts and types" } else if sess.features_untracked().min_const_generics { - ", then consts, then types" + ", then types, then consts" } else { ", then types" }, diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 54271d3dd0491..1a5794d113366 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -975,7 +975,6 @@ pub unsafe fn with_llvm_pmb( (llvm::CodeGenOptLevel::Default, ..) => { llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225); } - (llvm::CodeGenOptLevel::Other, ..) => bug!("CodeGenOptLevel::Other selected"), } f(builder); diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index eb7dc827f9391..f094ad868947f 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -337,9 +337,6 @@ impl AtomicOrdering { #[derive(Copy, Clone)] #[repr(C)] pub enum SynchronizationScope { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, SingleThread, CrossThread, } @@ -347,7 +344,6 @@ pub enum SynchronizationScope { impl SynchronizationScope { pub fn from_generic(sc: rustc_codegen_ssa::common::SynchronizationScope) -> Self { match sc { - rustc_codegen_ssa::common::SynchronizationScope::Other => SynchronizationScope::Other, rustc_codegen_ssa::common::SynchronizationScope::SingleThread => { SynchronizationScope::SingleThread } @@ -362,9 +358,6 @@ impl SynchronizationScope { #[derive(Copy, Clone)] #[repr(C)] pub enum FileType { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, AssemblyFile, ObjectFile, } @@ -391,9 +384,6 @@ pub enum MetadataType { #[derive(Copy, Clone)] #[repr(C)] pub enum AsmDialect { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, Att, Intel, } @@ -411,9 +401,6 @@ impl AsmDialect { #[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum CodeGenOptLevel { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, None, Less, Default, @@ -513,9 +500,6 @@ pub enum DiagnosticLevel { #[derive(Copy, Clone)] #[repr(C)] pub enum ArchiveKind { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, K_GNU, K_BSD, K_DARWIN, diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index 432b2f3bdc3c1..e04ed531bbff2 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -72,9 +72,6 @@ pub enum AtomicOrdering { } pub enum SynchronizationScope { - // FIXME: figure out if this variant is needed at all. - #[allow(dead_code)] - Other, SingleThread, CrossThread, } diff --git a/src/librustc_error_codes/error_codes/E0751.md b/src/librustc_error_codes/error_codes/E0751.md index 809b888d92ac3..8794f7868f302 100644 --- a/src/librustc_error_codes/error_codes/E0751.md +++ b/src/librustc_error_codes/error_codes/E0751.md @@ -5,8 +5,8 @@ Erroneous code example: ```compile_fail,E0751 trait MyTrait {} impl MyTrait for i32 { } -impl !MyTrait for i32 { } +impl !MyTrait for i32 { } // error! ``` -Negative implementations are a promise that the trait will never be -implemented for the given types. +Negative implementations are a promise that the trait will never be implemented +for the given types. Therefore, both cannot exists at the same time. diff --git a/src/librustc_resolve/late/diagnostics.rs b/src/librustc_resolve/late/diagnostics.rs index f0ea325d2ab74..a7d3697405751 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/src/librustc_resolve/late/diagnostics.rs @@ -16,8 +16,8 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::config::nightly_options; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span}; +use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, Span, DUMMY_SP}; use log::debug; @@ -33,6 +33,7 @@ enum AssocSuggestion { crate enum MissingLifetimeSpot<'tcx> { Generics(&'tcx hir::Generics<'tcx>), HigherRanked { span: Span, span_type: ForLifetimeSpanType }, + Static, } crate enum ForLifetimeSpanType { @@ -1195,6 +1196,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { https://doc.rust-lang.org/nomicon/hrtb.html", ); } + _ => {} } } if nightly_options::is_nightly_build() @@ -1253,7 +1255,8 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { err: &mut DiagnosticBuilder<'_>, span: Span, count: usize, - lifetime_names: &FxHashSet, + lifetime_names: &FxHashSet, + lifetime_spans: Vec, params: &[ElisionFailureInfo], ) { let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok(); @@ -1267,11 +1270,60 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ), ); - let suggest_existing = |err: &mut DiagnosticBuilder<'_>, sugg| { + let suggest_existing = |err: &mut DiagnosticBuilder<'_>, + name: &str, + formatter: &dyn Fn(&str) -> String| { + if let Some(MissingLifetimeSpot::HigherRanked { span: for_span, span_type }) = + self.missing_named_lifetime_spots.iter().rev().next() + { + // When we have `struct S<'a>(&'a dyn Fn(&X) -> &X);` we want to not only suggest + // using `'a`, but also introduce the concept of HRLTs by suggesting + // `struct S<'a>(&'a dyn for<'b> Fn(&X) -> &'b X);`. (#72404) + let mut introduce_suggestion = vec![]; + + let a_to_z_repeat_n = |n| { + (b'a'..=b'z').map(move |c| { + let mut s = '\''.to_string(); + s.extend(std::iter::repeat(char::from(c)).take(n)); + s + }) + }; + + // If all single char lifetime names are present, we wrap around and double the chars. + let lt_name = (1..) + .flat_map(a_to_z_repeat_n) + .find(|lt| !lifetime_names.contains(&Symbol::intern(<))) + .unwrap(); + let msg = format!( + "consider making the {} lifetime-generic with a new `{}` lifetime", + span_type.descr(), + lt_name, + ); + err.note( + "for more information on higher-ranked polymorphism, visit \ + https://doc.rust-lang.org/nomicon/hrtb.html", + ); + let for_sugg = span_type.suggestion(<_name); + for param in params { + if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) { + if snippet.starts_with('&') && !snippet.starts_with("&'") { + introduce_suggestion + .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); + } else if snippet.starts_with("&'_ ") { + introduce_suggestion + .push((param.span, format!("&{} {}", lt_name, &snippet[4..]))); + } + } + } + introduce_suggestion.push((*for_span, for_sugg.to_string())); + introduce_suggestion.push((span, formatter(<_name))); + err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); + } + err.span_suggestion_verbose( span, &format!("consider using the `{}` lifetime", lifetime_names.iter().next().unwrap()), - sugg, + formatter(name), Applicability::MaybeIncorrect, ); }; @@ -1282,6 +1334,15 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { let should_break; introduce_suggestion.push(match missing { MissingLifetimeSpot::Generics(generics) => { + if generics.span == DUMMY_SP { + // Account for malformed generics in the HIR. This shouldn't happen, + // but if we make a mistake elsewhere, mainly by keeping something in + // `missing_named_lifetime_spots` that we shouldn't, like associated + // `const`s or making a mistake in the AST lowering we would provide + // non-sensical suggestions. Guard against that by skipping these. + // (#74264) + continue; + } msg = "consider introducing a named lifetime parameter".to_string(); should_break = true; if let Some(param) = generics.params.iter().find(|p| match p.kind { @@ -1308,6 +1369,42 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { ); (*span, span_type.suggestion("'a")) } + MissingLifetimeSpot::Static => { + let (span, sugg) = match snippet.as_deref() { + Some("&") => (span.shrink_to_hi(), "'static ".to_owned()), + Some("'_") => (span, "'static".to_owned()), + Some(snippet) if !snippet.ends_with('>') => { + if snippet == "" { + ( + span, + std::iter::repeat("'static") + .take(count) + .collect::>() + .join(", "), + ) + } else { + ( + span.shrink_to_hi(), + format!( + "<{}>", + std::iter::repeat("'static") + .take(count) + .collect::>() + .join(", ") + ), + ) + } + } + _ => continue, + }; + err.span_suggestion_verbose( + span, + "consider using the `'static` lifetime", + sugg.to_string(), + Applicability::MaybeIncorrect, + ); + continue; + } }); for param in params { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(param.span) { @@ -1328,19 +1425,19 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } }; - match (lifetime_names.len(), lifetime_names.iter().next(), snippet.as_deref()) { - (1, Some(name), Some("&")) => { - suggest_existing(err, format!("&{} ", name)); + let lifetime_names: Vec<_> = lifetime_names.into_iter().collect(); + match (&lifetime_names[..], snippet.as_deref()) { + ([name], Some("&")) => { + suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name)); } - (1, Some(name), Some("'_")) => { - suggest_existing(err, name.to_string()); + ([name], Some("'_")) => { + suggest_existing(err, &name.as_str()[..], &|n| n.to_string()); } - (1, Some(name), Some("")) => { - suggest_existing(err, format!("{}, ", name).repeat(count)); + ([name], Some("")) => { + suggest_existing(err, &name.as_str()[..], &|n| format!("{}, ", n).repeat(count)); } - (1, Some(name), Some(snippet)) if !snippet.ends_with('>') => { - suggest_existing( - err, + ([name], Some(snippet)) if !snippet.ends_with('>') => { + let f = |name: &str| { format!( "{}<{}>", snippet, @@ -1348,21 +1445,37 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { .take(count) .collect::>() .join(", ") - ), - ); + ) + }; + suggest_existing(err, &name.as_str()[..], &f); } - (0, _, Some("&")) if count == 1 => { + ([], Some("&")) if count == 1 => { suggest_new(err, "&'a "); } - (0, _, Some("'_")) if count == 1 => { + ([], Some("'_")) if count == 1 => { suggest_new(err, "'a"); } - (0, _, Some(snippet)) if !snippet.ends_with('>') && count == 1 => { - suggest_new(err, &format!("{}<'a>", snippet)); + ([], Some(snippet)) if !snippet.ends_with('>') => { + if snippet == "" { + // This happens when we have `type Bar<'a> = Foo` where we point at the space + // before `T`. We will suggest `type Bar<'a> = Foo<'a, T>`. + suggest_new( + err, + &std::iter::repeat("'a, ").take(count).collect::>().join(""), + ); + } else { + suggest_new( + err, + &format!( + "{}<{}>", + snippet, + std::iter::repeat("'a").take(count).collect::>().join(", ") + ), + ); + } } - (n, ..) if n > 1 => { - let spans: Vec = lifetime_names.iter().map(|lt| lt.span).collect(); - err.span_note(spans, "these named lifetimes are available to use"); + (lts, ..) if lts.len() > 1 => { + err.span_note(lifetime_spans, "these named lifetimes are available to use"); if Some("") == snippet.as_deref() { // This happens when we have `Foo` where we point at the space before `T`, // but this can be confusing so we give a suggestion with placeholders. diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 0b881b089deaa..2046419d984d0 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -711,9 +711,9 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) { use self::hir::TraitItemKind::*; - self.missing_named_lifetime_spots.push((&trait_item.generics).into()); match trait_item.kind { Fn(ref sig, _) => { + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(trait_item.hir_id)), @@ -721,8 +721,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { &trait_item.generics, |this| intravisit::walk_trait_item(this, trait_item), ); + self.missing_named_lifetime_spots.pop(); } Type(bounds, ref ty) => { + self.missing_named_lifetime_spots.push((&trait_item.generics).into()); let generics = &trait_item.generics; let mut index = self.next_early_index(); debug!("visit_ty: index = {}", index); @@ -757,31 +759,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); } }); + self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(trait_item.generics.params.is_empty()); + self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_trait_item(self, trait_item); + self.missing_named_lifetime_spots.pop(); } } - self.missing_named_lifetime_spots.pop(); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) { use self::hir::ImplItemKind::*; - self.missing_named_lifetime_spots.push((&impl_item.generics).into()); match impl_item.kind { Fn(ref sig, _) => { + self.missing_named_lifetime_spots.push((&impl_item.generics).into()); let tcx = self.tcx; self.visit_early_late( Some(tcx.hir().get_parent_item(impl_item.hir_id)), &sig.decl, &impl_item.generics, |this| intravisit::walk_impl_item(this, impl_item), - ) + ); + self.missing_named_lifetime_spots.pop(); } TyAlias(ref ty) => { let generics = &impl_item.generics; + self.missing_named_lifetime_spots.push(generics.into()); let mut index = self.next_early_index(); let mut non_lifetime_count = 0; debug!("visit_ty: index = {}", index); @@ -810,14 +816,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_generics(generics); this.visit_ty(ty); }); + self.missing_named_lifetime_spots.pop(); } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); + self.missing_named_lifetime_spots.push(MissingLifetimeSpot::Static); intravisit::walk_impl_item(self, impl_item); + self.missing_named_lifetime_spots.pop(); } } - self.missing_named_lifetime_spots.pop(); } fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { @@ -2315,6 +2323,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut late_depth = 0; let mut scope = self.scope; let mut lifetime_names = FxHashSet::default(); + let mut lifetime_spans = vec![]; let error = loop { match *scope { // Do not assign any resolution, it will be inferred. @@ -2326,7 +2335,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // collect named lifetimes for suggestions for name in lifetimes.keys() { if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); + lifetime_names.insert(name.name); + lifetime_spans.push(name.span); } } late_depth += 1; @@ -2344,12 +2354,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Elide::Exact(l) => l.shifted(late_depth), Elide::Error(ref e) => { - if let Scope::Binder { ref lifetimes, .. } = s { - // collect named lifetimes for suggestions - for name in lifetimes.keys() { - if let hir::ParamName::Plain(name) = name { - lifetime_names.insert(*name); + let mut scope = s; + loop { + match scope { + Scope::Binder { ref lifetimes, s, .. } => { + // Collect named lifetimes for suggestions. + for name in lifetimes.keys() { + if let hir::ParamName::Plain(name) = name { + lifetime_names.insert(name.name); + lifetime_spans.push(name.span); + } + } + scope = s; + } + Scope::ObjectLifetimeDefault { ref s, .. } + | Scope::Elision { ref s, .. } => { + scope = s; } + _ => break, } } break Some(e); @@ -2373,7 +2395,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { if let Some(params) = error { // If there's no lifetime available, suggest `'static`. if self.report_elision_failure(&mut err, params) && lifetime_names.is_empty() { - lifetime_names.insert(Ident::with_dummy_span(kw::StaticLifetime)); + lifetime_names.insert(kw::StaticLifetime); } } self.add_missing_lifetime_specifiers_label( @@ -2381,6 +2403,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { span, lifetime_refs.len(), &lifetime_names, + lifetime_spans, error.map(|p| &p[..]).unwrap_or(&[]), ); err.emit(); diff --git a/src/librustc_serialize/collection_impls.rs b/src/librustc_serialize/collection_impls.rs index c602de37b14f7..49b8094abd0eb 100644 --- a/src/librustc_serialize/collection_impls.rs +++ b/src/librustc_serialize/collection_impls.rs @@ -86,11 +86,9 @@ where { fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self { + for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; e.emit_map_elt_val(i, |e| val.encode(e))?; - i += 1; } Ok(()) }) @@ -121,10 +119,8 @@ where { fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self { + for (i, e) in self.iter().enumerate() { s.emit_seq_elt(i, |s| e.encode(s))?; - i += 1; } Ok(()) }) @@ -154,11 +150,9 @@ where { fn encode(&self, e: &mut E) -> Result<(), E::Error> { e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self { + for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; e.emit_map_elt_val(i, |e| val.encode(e))?; - i += 1; } Ok(()) }) @@ -192,10 +186,8 @@ where { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self { + for (i, e) in self.iter().enumerate() { s.emit_seq_elt(i, |s| e.encode(s))?; - i += 1; } Ok(()) }) @@ -227,11 +219,9 @@ where { fn encode(&self, e: &mut E) -> Result<(), E::Error> { e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self { + for (i, (key, val)) in self.iter().enumerate() { e.emit_map_elt_key(i, |e| key.encode(e))?; e.emit_map_elt_val(i, |e| val.encode(e))?; - i += 1; } Ok(()) }) @@ -265,10 +255,8 @@ where { fn encode(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self { + for (i, e) in self.iter().enumerate() { s.emit_seq_elt(i, |s| e.encode(s))?; - i += 1; } Ok(()) }) diff --git a/src/librustc_serialize/json.rs b/src/librustc_serialize/json.rs index 820ebdc9baa52..ab7f6975325bc 100644 --- a/src/librustc_serialize/json.rs +++ b/src/librustc_serialize/json.rs @@ -78,19 +78,17 @@ //! data_vector: Vec, //! } //! -//! fn main() { -//! let object = TestStruct { -//! data_int: 1, -//! data_str: "homura".to_string(), -//! data_vector: vec![2,3,4,5], -//! }; +//! let object = TestStruct { +//! data_int: 1, +//! data_str: "homura".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; //! -//! // Serialize using `json::encode` -//! let encoded = json::encode(&object).unwrap(); +//! // Serialize using `json::encode` +//! let encoded = json::encode(&object).unwrap(); //! -//! // Deserialize using `json::decode` -//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap(); -//! } +//! // Deserialize using `json::decode` +//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap(); //! ``` //! //! ## Using the `ToJson` trait @@ -125,16 +123,14 @@ //! val: Json, //! } //! -//! fn main() { -//! let num = ComplexNum { a: 0.0001, b: 12.539 }; -//! let data: String = json::encode(&ComplexNumRecord{ -//! uid: 1, -//! dsc: "test".to_string(), -//! val: num.to_json(), -//! }).unwrap(); -//! println!("data: {}", data); -//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"}; -//! } +//! let num = ComplexNum { a: 0.0001, b: 12.539 }; +//! let data: String = json::encode(&ComplexNumRecord{ +//! uid: 1, +//! dsc: "test".to_string(), +//! val: num.to_json(), +//! }).unwrap(); +//! println!("data: {}", data); +//! // data: {"uid":1,"dsc":"test","val":"0.0001+12.539i"}; //! ``` //! //! ### Verbose example of `ToJson` usage @@ -164,19 +160,17 @@ //! } //! } //! -//! fn main() { -//! // Serialize using `ToJson` -//! let input_data = TestStruct { -//! data_int: 1, -//! data_str: "madoka".to_string(), -//! data_vector: vec![2,3,4,5], -//! }; -//! let json_obj: Json = input_data.to_json(); -//! let json_str: String = json_obj.to_string(); +//! // Serialize using `ToJson` +//! let input_data = TestStruct { +//! data_int: 1, +//! data_str: "madoka".to_string(), +//! data_vector: vec![2,3,4,5], +//! }; +//! let json_obj: Json = input_data.to_json(); +//! let json_str: String = json_obj.to_string(); //! -//! // Deserialize like before -//! let decoded: TestStruct = json::decode(&json_str).unwrap(); -//! } +//! // Deserialize like before +//! let decoded: TestStruct = json::decode(&json_str).unwrap(); //! ``` use self::DecoderError::*; @@ -1269,34 +1263,22 @@ impl Json { /// Returns `true` if the Json value is a `Number`. pub fn is_number(&self) -> bool { - match *self { - Json::I64(_) | Json::U64(_) | Json::F64(_) => true, - _ => false, - } + matches!(*self, Json::I64(_) | Json::U64(_) | Json::F64(_)) } /// Returns `true` if the Json value is a `i64`. pub fn is_i64(&self) -> bool { - match *self { - Json::I64(_) => true, - _ => false, - } + matches!(*self, Json::I64(_)) } /// Returns `true` if the Json value is a `u64`. pub fn is_u64(&self) -> bool { - match *self { - Json::U64(_) => true, - _ => false, - } + matches!(*self, Json::U64(_)) } /// Returns `true` if the Json value is a `f64`. pub fn is_f64(&self) -> bool { - match *self { - Json::F64(_) => true, - _ => false, - } + matches!(*self, Json::F64(_)) } /// If the Json value is a number, returns or cast it to a `i64`; @@ -1416,6 +1398,7 @@ enum ParserState { /// structure of the JSON stream. /// /// An example is `foo.bar[3].x`. +#[derive(Default)] pub struct Stack { stack: Vec, str_buffer: Vec, @@ -1442,7 +1425,7 @@ enum InternalStackElement { impl Stack { pub fn new() -> Stack { - Stack { stack: Vec::new(), str_buffer: Vec::new() } + Self::default() } /// Returns The number of elements in the Stack. @@ -1547,10 +1530,7 @@ impl Stack { // Used by Parser to test whether the top-most element is an index. fn last_is_index(&self) -> bool { - match self.stack.last() { - Some(InternalIndex(_)) => true, - _ => false, - } + matches!(self.stack.last(), Some(InternalIndex(_))) } // Used by Parser to increment the index of the top-most element. diff --git a/src/librustc_serialize/opaque.rs b/src/librustc_serialize/opaque.rs index 39f3abb75271b..fa4423e261d1c 100644 --- a/src/librustc_serialize/opaque.rs +++ b/src/librustc_serialize/opaque.rs @@ -118,13 +118,13 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_f64(&mut self, v: f64) -> EncodeResult { - let as_u64: u64 = unsafe { ::std::mem::transmute(v) }; + let as_u64: u64 = v.to_bits(); self.emit_u64(as_u64) } #[inline] fn emit_f32(&mut self, v: f32) -> EncodeResult { - let as_u32: u32 = unsafe { ::std::mem::transmute(v) }; + let as_u32: u32 = v.to_bits(); self.emit_u32(as_u32) } diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 93704638f8351..9ce614fda5752 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -35,7 +35,6 @@ struct RustArchiveIterator { }; enum class LLVMRustArchiveKind { - Other, GNU, BSD, DARWIN, diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 41b14714842fd..76fe5e7f769f7 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -311,7 +311,6 @@ static Optional fromRust(LLVMRustCodeModel Model) { } enum class LLVMRustCodeGenOptLevel { - Other, None, Less, Default, @@ -597,7 +596,6 @@ extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) { } enum class LLVMRustFileType { - Other, AssemblyFile, ObjectFile, }; diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 667bf4a2ded37..9d90b0dfe0702 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -366,7 +366,6 @@ LLVMRustBuildAtomicCmpXchg(LLVMBuilderRef B, LLVMValueRef Target, } enum class LLVMRustSynchronizationScope { - Other, SingleThread, CrossThread, }; @@ -389,7 +388,6 @@ LLVMRustBuildAtomicFence(LLVMBuilderRef B, LLVMAtomicOrdering Order, } enum class LLVMRustAsmDialect { - Other, Att, Intel, }; diff --git a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr index 00f44129cc8b7..6c68cc7bc61aa 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-binding-only.elision.stderr @@ -5,6 +5,11 @@ LL | fn elision &i32>() { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'a` lifetime + | +LL | fn elision Fn() -> &'a i32>() { + | ^^^^^^^ ^^^ help: consider using the `'static` lifetime | LL | fn elision &'static i32>() { diff --git a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr index a5242707c7105..93d2f8e7911f0 100644 --- a/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr +++ b/src/test/ui/associated-types/bound-lifetime-in-return-only.elision.stderr @@ -5,6 +5,11 @@ LL | fn elision(_: fn() -> &i32) { | ^ expected named lifetime parameter | = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the type lifetime-generic with a new `'a` lifetime + | +LL | fn elision(_: for<'a> fn() -> &'a i32) { + | ^^^^^^^ ^^^ help: consider using the `'static` lifetime | LL | fn elision(_: fn() -> &'static i32) { diff --git a/src/test/ui/const-generics/defaults/needs-feature.min.stderr b/src/test/ui/const-generics/defaults/needs-feature.min.stderr index d57190ea3bbab..7058327fdce15 100644 --- a/src/test/ui/const-generics/defaults/needs-feature.min.stderr +++ b/src/test/ui/const-generics/defaults/needs-feature.min.stderr @@ -2,7 +2,7 @@ error: type parameters must be declared prior to const parameters --> $DIR/needs-feature.rs:10:26 | LL | struct A(T); - | -----------------^----- help: reorder the parameters: lifetimes, then consts, then types: `` + | -----------------^----- help: reorder the parameters: lifetimes, then types, then consts: `` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0106.stderr b/src/test/ui/error-codes/E0106.stderr index a23bcbfd71a56..ac70e887626ab 100644 --- a/src/test/ui/error-codes/E0106.stderr +++ b/src/test/ui/error-codes/E0106.stderr @@ -51,6 +51,15 @@ error[E0106]: missing lifetime specifiers | LL | buzz: Buzz, | ^^^^ expected 2 lifetime parameters + | +help: consider introducing a named lifetime parameter + | +LL | struct Quux<'a> { +LL | baz: Baz, +LL | +LL | +LL | buzz: Buzz<'a, 'a>, + | error: aborting due to 5 previous errors diff --git a/src/test/ui/issues/issue-74739.rs b/src/test/ui/issues/issue-74739.rs new file mode 100644 index 0000000000000..03622358ae1cd --- /dev/null +++ b/src/test/ui/issues/issue-74739.rs @@ -0,0 +1,14 @@ +// compile-flags: -O +// run-pass + +struct Foo { + x: i32, +} + +pub fn main() { + let mut foo = Foo { x: 42 }; + let x = &mut foo.x; + *x = 13; + let y = foo; + assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug +} diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index da3056eac9009..d260addef4813 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -6,8 +6,8 @@ LL | type Item = IteratorChunk; | help: consider introducing a named lifetime parameter | -LL | type Item<'a> = IteratorChunk<<'a>T, S>; - | ^^^^ ^^^^ +LL | type Item<'a> = IteratorChunk<'a, T, S>; + | ^^^^ ^^^ error: `impl` item signature doesn't match `trait` item signature --> $DIR/issue-74918-missing-lifetime.rs:11:5 diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs new file mode 100644 index 0000000000000..38332627f4c87 --- /dev/null +++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.rs @@ -0,0 +1,16 @@ +trait ZstAssert: Sized { + const A: &str = ""; //~ ERROR missing lifetime specifier + const B: S = S { s: &() }; //~ ERROR missing lifetime specifier + const C: &'_ str = ""; //~ ERROR missing lifetime specifier + const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier +} + +struct S<'a> { + s: &'a (), +} +struct T<'a, 'b> { + a: &'a (), + b: &'b (), +} + +fn main() {} diff --git a/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr new file mode 100644 index 0000000000000..b20778ce20817 --- /dev/null +++ b/src/test/ui/suggestions/missing-lifetime-in-assoc-const-type.stderr @@ -0,0 +1,73 @@ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-assoc-const-type.rs:2:14 + | +LL | const A: &str = ""; + | ^ expected named lifetime parameter + | +help: consider using the `'static` lifetime + | +LL | const A: &'static str = ""; + | ^^^^^^^ +help: consider introducing a named lifetime parameter + | +LL | trait ZstAssert<'a>: Sized { +LL | const A: &'a str = ""; + | + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14 + | +LL | const B: S = S { s: &() }; + | ^ expected named lifetime parameter + | +help: consider using the `'static` lifetime + | +LL | const B: S<'static> = S { s: &() }; + | ^^^^^^^^^ +help: consider introducing a named lifetime parameter + | +LL | trait ZstAssert<'a>: Sized { +LL | const A: &str = ""; +LL | const B: S<'a> = S { s: &() }; + | + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15 + | +LL | const C: &'_ str = ""; + | ^^ expected named lifetime parameter + | +help: consider using the `'static` lifetime + | +LL | const C: &'static str = ""; + | ^^^^^^^ +help: consider introducing a named lifetime parameter + | +LL | trait ZstAssert<'a>: Sized { +LL | const A: &str = ""; +LL | const B: S = S { s: &() }; +LL | const C: &'a str = ""; + | + +error[E0106]: missing lifetime specifiers + --> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14 + | +LL | const D: T = T { a: &(), b: &() }; + | ^ expected 2 lifetime parameters + | +help: consider using the `'static` lifetime + | +LL | const D: T<'static, 'static> = T { a: &(), b: &() }; + | ^^^^^^^^^^^^^^^^^^ +help: consider introducing a named lifetime parameter + | +LL | trait ZstAssert<'a>: Sized { +LL | const A: &str = ""; +LL | const B: S = S { s: &() }; +LL | const C: &'_ str = ""; +LL | const D: T<'a, 'a> = T { a: &(), b: &() }; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.rs b/src/test/ui/suggestions/missing-lt-for-hrtb.rs new file mode 100644 index 0000000000000..a90a90122ad19 --- /dev/null +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.rs @@ -0,0 +1,15 @@ +struct X<'a>(&'a ()); +struct S<'a>(&'a dyn Fn(&X) -> &X); +//~^ ERROR missing lifetime specifier +//~| ERROR missing lifetime specifier +struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); +//~^ ERROR missing lifetime specifier +//~| ERROR missing lifetime specifier + +fn main() { + let x = S(&|x| { + println!("hi"); + x + }); + x.0(&X(&())); +} diff --git a/src/test/ui/suggestions/missing-lt-for-hrtb.stderr b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr new file mode 100644 index 0000000000000..2cb63500e48b9 --- /dev/null +++ b/src/test/ui/suggestions/missing-lt-for-hrtb.stderr @@ -0,0 +1,63 @@ +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:2:32 + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &'b X); + | ^^^^^^^ ^^^^^ ^^^ +help: consider using the `'a` lifetime + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &'a X); + | ^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:2:33 + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'b` lifetime + | +LL | struct S<'a>(&'a dyn for<'b> Fn(&'b X) -> &X<'b>); + | ^^^^^^^ ^^^^^ ^^^^^ +help: consider using the `'a` lifetime + | +LL | struct S<'a>(&'a dyn Fn(&X) -> &X<'a>); + | ^^^^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:5:40 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from +note: these named lifetimes are available to use + --> $DIR/missing-lt-for-hrtb.rs:5:10 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | ^^ ^^ + +error[E0106]: missing lifetime specifier + --> $DIR/missing-lt-for-hrtb.rs:5:41 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | -- ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but the signature does not say which one of argument 1's 2 lifetimes it is borrowed from +note: these named lifetimes are available to use + --> $DIR/missing-lt-for-hrtb.rs:5:10 + | +LL | struct V<'a>(&'a dyn for<'b> Fn(&X) -> &X); + | ^^ ^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0106`.