diff options
87 files changed, 1210 insertions, 222 deletions
diff --git a/Cargo.lock b/Cargo.lock index c066d1b0a5b..7ed327e9f4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,9 +746,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.71" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "163437f05ca8f29d7e9128ea728dedf5eb620e445fbca273641d3a3050305f23" +checksum = "71b72fde1d7792ca3bd654f7c3ea4508f9e4d0c826e24179eabb7fcc97a90bc3" dependencies = [ "cc", "rustc-std-workspace-core", @@ -5509,6 +5509,8 @@ dependencies = [ "pretty_assertions 1.2.1", "regex", "rustc_version", + "serde", + "serde_json", ] [[package]] diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d9d31ab2c89..abf77acb8c7 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2147,7 +2147,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - CastKind::PointerAddress => { + CastKind::PointerExposeAddress => { let ty_from = op.ty(body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 7c59ce354c0..58bec183c94 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -607,7 +607,11 @@ fn codegen_stmt<'tcx>( let operand = codegen_operand(fx, operand); lval.write_cvalue(fx, operand.cast_pointer_to(to_layout)); } - Rvalue::Cast(CastKind::Misc | CastKind::PointerAddress, ref operand, to_ty) => { + Rvalue::Cast( + CastKind::Misc | CastKind::PointerExposeAddress, + ref operand, + to_ty, + ) => { let operand = codegen_operand(fx, operand); let from_ty = operand.layout().ty; let to_ty = fx.monomorphize(to_ty); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index bd88aa33372..6ff8d4aa442 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -181,7 +181,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cast = bx.cx().layout_of(self.monomorphize(mir_cast_ty)); let val = match *kind { - mir::CastKind::PointerAddress => { + mir::CastKind::PointerExposeAddress => { assert!(bx.cx().is_backend_immediate(cast)); let llptr = operand.immediate(); let llcast_ty = bx.cx().immediate_backend_type(cast); diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index af563c1450e..520ae409e6b 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -31,9 +31,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.unsize_into(src, cast_ty, dest)?; } - PointerAddress => { + PointerExposeAddress => { let src = self.read_immediate(src)?; - let res = self.pointer_address_cast(&src, cast_ty)?; + let res = self.pointer_expose_address_cast(&src, cast_ty)?; self.write_immediate(res, dest)?; } @@ -184,7 +184,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into()) } - pub fn pointer_address_cast( + pub fn pointer_expose_address_cast( &mut self, src: &ImmTy<'tcx, M::PointerTag>, cast_ty: Ty<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 977b55a0890..9c032c55fe5 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -441,6 +441,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { msg, }) } + // Ensure we never consider the null pointer dereferencable. + if M::PointerTag::OFFSET_IS_ADDR { + assert_ne!(ptr.addr(), Size::ZERO); + } // Test align. Check this last; if both bounds and alignment are violated // we want the error to be about the bounds. if let Some(align) = align { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 4ef33d62a6b..c07680515f4 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -542,7 +542,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // in the type of any local, which also excludes casts). } - Rvalue::Cast(CastKind::PointerAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { self.check_op(ops::RawPtrToIntCast); } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index ea23bd14d25..cf5d7b6c70a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -502,7 +502,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), // ptr-to-int casts are not possible in consts and thus not promotable - Rvalue::Cast(CastKind::PointerAddress, _, _) => return Err(Unpromotable), + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => return Err(Unpromotable), // int-to-ptr casts are fine, they just use the integer value at pointer type. Rvalue::Cast(_, operand, _) => { diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index f71522d3714..4fda3adb7b8 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -126,9 +126,10 @@ impl<T: Eq + Hash> SsoHashSet<T> { /// Adds a value to the set. /// - /// If the set did not have this value present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have this value present, `false` is returned. + /// - If the set did not previously contain this value, `true` is returned. + /// - If the set already contained this value, `false` is returned. #[inline] pub fn insert(&mut self, elem: T) -> bool { self.map.insert(elem, ()).is_none() diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 3fdc8cf8ac2..e9e7065ec03 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1715,6 +1715,7 @@ impl EmitterWriter { fn emit_suggestion_default( &mut self, + span: &MultiSpan, suggestion: &CodeSuggestion, args: &FluentArgs<'_>, level: &Level, @@ -1766,6 +1767,30 @@ impl EmitterWriter { None, } + if let Some(span) = span.primary_span() { + // Compare the primary span of the diagnostic with the span of the suggestion + // being emitted. If they belong to the same file, we don't *need* to show the + // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're + // telling users to make a change but not clarifying *where*. + let loc = sm.lookup_char_pos(parts[0].span.lo()); + if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() { + buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber); + buffer.append( + row_num - 1, + &format!( + "{}:{}:{}", + sm.filename_for_diagnostics(&loc.file.name), + sm.doctest_offset_line(&loc.file.name, loc.line), + loc.col.0 + 1, + ), + Style::LineAndColumn, + ); + for _ in 0..max_line_num_len { + buffer.prepend(row_num - 1, " ", Style::NoStyle); + } + row_num += 1; + } + } let show_code_change = if has_deletion && !is_multiline { DisplaySuggestion::Diff } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim()) @@ -1787,7 +1812,7 @@ impl EmitterWriter { assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy()); let line_start = sm.lookup_char_pos(parts[0].span.lo()).line; - draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1); + draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1); let mut lines = complete.lines(); if lines.clone().next().is_none() { // Account for a suggestion to completely remove a line(s) with whitespace (#94192). @@ -2046,9 +2071,13 @@ impl EmitterWriter { ) { panic!("failed to emit error: {}", e); } - } else if let Err(e) = - self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len) - { + } else if let Err(e) = self.emit_suggestion_default( + span, + sugg, + args, + &Level::Help, + max_line_num_len, + ) { panic!("failed to emit error: {}", e); }; } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1b63c8d67ca..d9cdca8bcb5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2607,16 +2607,17 @@ static_assert_size!(Rvalue<'_>, 40); impl<'tcx> Rvalue<'tcx> { #[inline] pub fn is_pointer_int_cast(&self) -> bool { - matches!(self, Rvalue::Cast(CastKind::PointerAddress, _, _)) + matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _)) } } #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] pub enum CastKind { Misc, - /// A pointer to address cast. A cast between a pointer and an integer type, - /// or between a function pointer and an integer type. - PointerAddress, + /// An exposing pointer to address cast. A cast between a pointer and an integer type, or + /// between a function pointer and an integer type. + /// See the docs on `expose_addr` for more details. + PointerExposeAddress, Pointer(PointerCast), } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 2b137046c7f..7d08b20631e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cast_ty = CastTy::from_ty(expr.ty); let cast_kind = match (from_ty, cast_ty) { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { - CastKind::PointerAddress + CastKind::PointerExposeAddress } (_, _) => CastKind::Misc, }; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 12302315e90..ee8e4162001 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,8 +1,7 @@ use super::pat::Expected; -use super::ty::{AllowPlus, RecoverQuestionMark}; use super::{ - BlockMode, CommaRecoveryMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, - SemiColonMode, SeqSep, TokenExpectType, TokenType, + BlockMode, CommaRecoveryMode, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, + TokenExpectType, TokenType, }; use crate::lexer::UnmatchedBrace; @@ -1233,26 +1232,14 @@ impl<'a> Parser<'a> { } } - pub(super) fn maybe_report_ambiguous_plus( - &mut self, - allow_plus: AllowPlus, - impl_dyn_multi: bool, - ty: &Ty, - ) { - if matches!(allow_plus, AllowPlus::No) && impl_dyn_multi { + pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) { + if impl_dyn_multi { self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(&ty), span: ty.span }); } } /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it. - pub(super) fn maybe_recover_from_question_mark( - &mut self, - ty: P<Ty>, - recover_question_mark: RecoverQuestionMark, - ) -> P<Ty> { - if let RecoverQuestionMark::No = recover_question_mark { - return ty; - } + pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> { if self.token == token::Question { self.bump(); self.struct_span_err(self.prev_token.span, "invalid `?` in type") @@ -1272,13 +1259,9 @@ impl<'a> Parser<'a> { } } - pub(super) fn maybe_recover_from_bad_type_plus( - &mut self, - allow_plus: AllowPlus, - ty: &Ty, - ) -> PResult<'a, ()> { + pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a, ()> { // Do not add `+` to expected tokens. - if matches!(allow_plus, AllowPlus::No) || !self.token.is_like_plus() { + if !self.token.is_like_plus() { return Ok(()); } @@ -1444,10 +1427,9 @@ impl<'a> Parser<'a> { pub(super) fn maybe_recover_from_bad_qpath<T: RecoverQPath>( &mut self, base: P<T>, - allow_recovery: bool, ) -> PResult<'a, P<T>> { // Do not add `::` to expected tokens. - if allow_recovery && self.token == token::ModSep { + if self.token == token::ModSep { if let Some(ty) = base.to_ty() { return self.maybe_recover_from_bad_qpath_stage_2(ty.span, ty); } @@ -1593,7 +1575,7 @@ impl<'a> Parser<'a> { _ => ExprKind::Await(expr), }; let expr = self.mk_expr(lo.to(sp), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> { @@ -2457,10 +2439,9 @@ impl<'a> Parser<'a> { pub(crate) fn maybe_recover_colon_colon_in_pat_typo( &mut self, mut first_pat: P<Pat>, - ra: RecoverColon, expected: Expected, ) -> P<Pat> { - if RecoverColon::Yes != ra || token::Colon != self.token.kind { + if token::Colon != self.token.kind { return first_pat; } if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) @@ -2594,10 +2575,9 @@ impl<'a> Parser<'a> { pub(crate) fn maybe_recover_unexpected_comma( &mut self, lo: Span, - rc: RecoverComma, rt: CommaRecoveryMode, ) -> PResult<'a, ()> { - if rc == RecoverComma::No || self.token != token::Comma { + if self.token != token::Comma { return Ok(()); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index bb6d892138a..63c7decbb2f 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1417,7 +1417,7 @@ impl<'a> Parser<'a> { match self.parse_opt_lit() { Some(literal) => { let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Lit(literal), attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } None => self.try_macro_suggestion(), } @@ -1444,7 +1444,7 @@ impl<'a> Parser<'a> { ExprKind::Tup(es) }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn parse_array_or_repeat_expr( @@ -1481,7 +1481,7 @@ impl<'a> Parser<'a> { } }; let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } fn parse_path_start_expr(&mut self, attrs: AttrVec) -> PResult<'a, P<Expr>> { @@ -1519,7 +1519,7 @@ impl<'a> Parser<'a> { }; let expr = self.mk_expr(lo.to(hi), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `'label: $expr`. The label is already parsed. @@ -1604,7 +1604,7 @@ impl<'a> Parser<'a> { let lo = self.prev_token.span; let kind = ExprKind::Ret(self.parse_expr_opt()?); let expr = self.mk_expr(lo.to(self.prev_token.span), kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"do" "yeet" expr?`. @@ -1619,7 +1619,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::yeet_expr, span); let expr = self.mk_expr(span, kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten. @@ -1679,7 +1679,7 @@ impl<'a> Parser<'a> { None }; let expr = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Break(label, kind), attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Parse `"yield" expr?`. @@ -1689,7 +1689,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); self.sess.gated_spans.gate(sym::generators, span); let expr = self.mk_expr(span, kind, attrs); - self.maybe_recover_from_bad_qpath(expr, true) + self.maybe_recover_from_bad_qpath(expr) } /// Returns a string literal if the next token is a string literal. diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8019c5fb67c..2ad3f3ec19d 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -100,8 +100,10 @@ impl<'a> Parser<'a> { }; // Parse the first pattern (`p_0`). - let first_pat = self.parse_pat_no_top_alt(expected)?; - self.maybe_recover_unexpected_comma(first_pat.span, rc, rt)?; + let mut first_pat = self.parse_pat_no_top_alt(expected)?; + if rc == RecoverComma::Yes { + self.maybe_recover_unexpected_comma(first_pat.span, rt)?; + } // If the next token is not a `|`, // this is not an or-pattern and we should exit here. @@ -111,7 +113,9 @@ impl<'a> Parser<'a> { // This complicated procedure is done purely for diagnostics UX. // Check if the user wrote `foo:bar` instead of `foo::bar`. - let first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, ra, expected); + if ra == RecoverColon::Yes { + first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected); + } if let Some(leading_vert_span) = leading_vert_span { // If there was a leading vert, treat this as an or-pattern. This improves @@ -139,7 +143,9 @@ impl<'a> Parser<'a> { err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; - self.maybe_recover_unexpected_comma(pat.span, rc, rt)?; + if rc == RecoverComma::Yes { + self.maybe_recover_unexpected_comma(pat.span, rt)?; + } pats.push(pat); } let or_pattern_span = lo.to(self.prev_token.span); @@ -408,7 +414,7 @@ impl<'a> Parser<'a> { }; let pat = self.mk_pat(lo.to(self.prev_token.span), pat); - let pat = self.maybe_recover_from_bad_qpath(pat, true)?; + let pat = self.maybe_recover_from_bad_qpath(pat)?; let pat = self.recover_intersection_pat(pat)?; if !allow_range_pat { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 27a6a487474..7907ec44e98 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -180,7 +180,7 @@ impl<'a> Parser<'a> { } else { // Since none of the above applied, this is an expression statement macro. let e = self.mk_expr(lo.to(hi), ExprKind::MacCall(mac), AttrVec::new()); - let e = self.maybe_recover_from_bad_qpath(e, true)?; + let e = self.maybe_recover_from_bad_qpath(e)?; let e = self.parse_dot_or_call_expr_with(e, lo, attrs.into())?; let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?; StmtKind::Expr(e) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index fb3f5eb3f9f..dee025cfd3c 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -312,13 +312,18 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_token.span); - let ty = self.mk_ty(span, kind); + let mut ty = self.mk_ty(span, kind); // Try to recover from use of `+` with incorrect priority. - self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty); - self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?; - let ty = self.maybe_recover_from_question_mark(ty, recover_question_mark); - self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery) + if matches!(allow_plus, AllowPlus::Yes) { + self.maybe_recover_from_bad_type_plus(&ty)?; + } else { + self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty); + } + if let RecoverQuestionMark::Yes = recover_question_mark { + ty = self.maybe_recover_from_question_mark(ty); + } + if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } } /// Parses either: diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c199cff2038..b1fe418f687 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1839,9 +1839,18 @@ impl<'a> Resolver<'a> { )), ) } else if self.session.edition() == Edition::Edition2015 { - (format!("maybe a missing crate `{}`?", ident), None) + ( + format!("maybe a missing crate `{ident}`?"), + Some(( + vec![], + format!( + "consider adding `extern crate {ident}` to use the `{ident}` crate" + ), + Applicability::MaybeIncorrect, + )), + ) } else { - (format!("could not find `{}` in the crate root", ident), None) + (format!("could not find `{ident}` in the crate root"), None) } } else if i > 0 { let parent = path[i - 1].ident.name; @@ -1852,7 +1861,7 @@ impl<'a> Resolver<'a> { "the list of imported crates".to_owned() } kw::PathRoot | kw::Crate => "the crate root".to_owned(), - _ => format!("`{}`", parent), + _ => format!("`{parent}`"), }; let mut msg = format!("could not find `{}` in {}", ident, parent); diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index a8c8c674d2d..de83a3a5932 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -475,6 +475,10 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } if let Some((suggestions, msg, applicability)) = err.suggestion { + if suggestions.is_empty() { + diag.help(&msg); + continue; + } diag.multipart_suggestion(&msg, suggestions, applicability); } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index a71621a4d52..641b915f373 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -145,15 +145,28 @@ impl<'tcx> ProjectionCandidateSet<'tcx> { } } -/// Takes the place of a +/// States returned from `poly_project_and_unify_type`. Takes the place +/// of the old return type, which was: +/// ```ignore (not-rust) /// Result< /// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, /// MismatchedProjectionTypes<'tcx>, /// > +/// ``` pub(super) enum ProjectAndUnifyResult<'tcx> { + /// The projection bound holds subject to the given obligations. If the + /// projection cannot be normalized because the required trait bound does + /// not hold, this is returned, with `obligations` being a predicate that + /// cannot be proven. Holds(Vec<PredicateObligation<'tcx>>), + /// The projection cannot be normalized due to ambiguity. Resolving some + /// inference variables in the projection may fix this. FailedNormalization, + /// The project cannot be normalized because `poly_project_and_unify_type` + /// is called recursively while normalizing the same projection. Recursive, + // the projection can be normalized, but is not equal to the expected type. + // Returns the type error that arose from the mismatch. MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>), } @@ -163,19 +176,6 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// ``` /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. -/// -/// ## Returns -/// -/// - `Err(_)`: the projection can be normalized, but is not equal to the -/// expected type. -/// - `Ok(Err(InProgress))`: this is called recursively while normalizing -/// the same projection. -/// - `Ok(Ok(None))`: The projection cannot be normalized due to ambiguity -/// (resolving some inference variables in the projection may fix this). -/// - `Ok(Ok(Some(obligations)))`: The projection bound holds subject to -/// the given obligations. If the projection cannot be normalized because -/// the required trait bound doesn't hold this returned with `obligations` -/// being a predicate that cannot be proven. #[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 0379b16334c..2ce2a44d3db 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -81,10 +81,17 @@ pub fn trait_obligations<'a, 'tcx>( body_id: hir::HirId, trait_ref: &ty::TraitRef<'tcx>, span: Span, - item: Option<&'tcx hir::Item<'tcx>>, + item: &'tcx hir::Item<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { - let mut wf = - WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth: 0, item }; + let mut wf = WfPredicates { + infcx, + param_env, + body_id, + span, + out: vec![], + recursion_depth: 0, + item: Some(item), + }; wf.compute_trait_ref(trait_ref, Elaborate::All); debug!(obligations = ?wf.out); wf.normalize() diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 4e54d554c6e..0e198907c8d 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -978,45 +978,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(&mut err); } - if let SelfSource::MethodCall(expr) = source - && let Some((fields, substs)) = self.get_field_candidates(span, actual) - { - let call_expr = - self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); - for candidate_field in fields.iter() { - if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - &|_, field_ty| { - self.lookup_probe( - span, - item_name, - field_ty, - call_expr, - ProbeScope::AllTraits, - ) - .is_ok() - }, - candidate_field, - substs, - vec![], - self.tcx.parent_module(expr.hir_id).to_def_id(), - ) { - let field_path_str = field_path - .iter() - .map(|id| id.name.to_ident_string()) - .collect::<Vec<String>>() - .join("."); - debug!("field_path_str: {:?}", field_path_str); + self.check_for_field_method(&mut err, source, span, actual, item_name); - err.span_suggestion_verbose( - item_name.span.shrink_to_lo(), - "one of the expressions' fields has a method of the same name", - format!("{field_path_str}."), - Applicability::MaybeIncorrect, - ); - } - } - } + self.check_for_unwrap_self(&mut err, source, span, actual, item_name); bound_spans.sort(); bound_spans.dedup(); @@ -1343,6 +1307,145 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + fn check_for_field_method( + &self, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + source: SelfSource<'tcx>, + span: Span, + actual: Ty<'tcx>, + item_name: Ident, + ) { + if let SelfSource::MethodCall(expr) = source + && let Some((fields, substs)) = self.get_field_candidates(span, actual) + { + let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); + for candidate_field in fields.iter() { + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + &|_, field_ty| { + self.lookup_probe( + span, + item_name, + field_ty, + call_expr, + ProbeScope::AllTraits, + ) + .is_ok() + }, + candidate_field, + substs, + vec![], + self.tcx.parent_module(expr.hir_id).to_def_id(), + ) { + let field_path_str = field_path + .iter() + .map(|id| id.name.to_ident_string()) + .collect::<Vec<String>>() + .join("."); + debug!("field_path_str: {:?}", field_path_str); + + err.span_suggestion_verbose( + item_name.span.shrink_to_lo(), + "one of the expressions' fields has a method of the same name", + format!("{field_path_str}."), + Applicability::MaybeIncorrect, + ); + } + } + } + } + + fn check_for_unwrap_self( + &self, + err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + source: SelfSource<'tcx>, + span: Span, + actual: Ty<'tcx>, + item_name: Ident, + ) { + let tcx = self.tcx; + let SelfSource::MethodCall(expr) = source else { return; }; + let call_expr = tcx.hir().expect_expr(tcx.hir().get_parent_node(expr.hir_id)); + + let ty::Adt(kind, substs) = actual.kind() else { return; }; + if !kind.is_enum() { + return; + } + + let matching_variants: Vec<_> = kind + .variants() + .iter() + .flat_map(|variant| { + let [field] = &variant.fields[..] else { return None; }; + let field_ty = field.ty(tcx, substs); + + // Skip `_`, since that'll just lead to ambiguity. + if self.resolve_vars_if_possible(field_ty).is_ty_var() { + return None; + } + + self.lookup_probe(span, item_name, field_ty, call_expr, ProbeScope::AllTraits) + .ok() + .map(|pick| (variant, field, pick)) + }) + .collect(); + + let ret_ty_matches = |diagnostic_item| { + if let Some(ret_ty) = self + .ret_coercion + .as_ref() + .map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty())) + && let ty::Adt(kind, _) = ret_ty.kind() + && tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did()) + { + true + } else { + false + } + }; + + match &matching_variants[..] { + [(_, field, pick)] => { + let self_ty = field.ty(tcx, substs); + err.span_note( + tcx.def_span(pick.item.def_id), + &format!("the method `{item_name}` exists on the type `{self_ty}`"), + ); + let (article, kind, variant, question) = + if Some(kind.did()) == tcx.get_diagnostic_item(sym::Result) { + ("a", "Result", "Err", ret_ty_matches(sym::Result)) + } else if Some(kind.did()) == tcx.get_diagnostic_item(sym::Option) { + ("an", "Option", "None", ret_ty_matches(sym::Option)) + } else { + return; + }; + if question { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "use the `?` operator to extract the `{self_ty}` value, propagating \ + {article} `{kind}::{variant}` value to the caller" + ), + "?".to_owned(), + Applicability::MachineApplicable, + ); + } else { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "consider using `{kind}::expect` to unwrap the `{self_ty}` value, \ + panicking if the value is {article} `{kind}::{variant}`" + ), + ".expect(\"REASON\")".to_owned(), + Applicability::HasPlaceholders, + ); + } + } + // FIXME(compiler-errors): Support suggestions for other matching enum variants + _ => {} + } + } + pub(crate) fn note_unmet_impls_on_type( &self, err: &mut Diagnostic, @@ -1662,13 +1765,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "), (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"), ] { - match self.lookup_probe( - span, - item_name, - *rcvr_ty, - rcvr, - crate::check::method::probe::ProbeScope::AllTraits, - ) { + match self.lookup_probe(span, item_name, *rcvr_ty, rcvr, ProbeScope::AllTraits) { Ok(pick) => { // If the method is defined for the receiver we have, it likely wasn't `use`d. // We point at the method, but we just skip the rest of the check for arbitrary @@ -1700,13 +1797,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"), (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"), ] { - if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe( - span, - item_name, - new_rcvr_t, - rcvr, - crate::check::method::probe::ProbeScope::AllTraits, - ) { + if let Some(new_rcvr_t) = *rcvr_ty + && let Ok(pick) = self.lookup_probe( + span, + item_name, + new_rcvr_t, + rcvr, + ProbeScope::AllTraits, + ) + { debug!("try_alt_rcvr: pick candidate {:?}", pick); let did = Some(pick.item.container.id()); // We don't want to suggest a container type when the missing diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index a6c7573b787..20ef97c085f 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1228,7 +1228,7 @@ fn check_impl<'tcx>( fcx.body_id, &trait_ref, ast_trait_ref.path.span, - Some(item), + item, ); debug!(?obligations); for obligation in obligations { diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index 4b6f80ce57a..7e3fefe4502 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -161,38 +161,23 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< // We've encountered an `AnonConst` in some path, so we need to // figure out which generic parameter it corresponds to and return // the relevant type. - let filtered = path.segments.iter().find_map(|seg| { - seg.args? - .args + let Some((arg_index, segment)) = path.segments.iter().find_map(|seg| { + let args = seg.args?; + args.args + .iter() + .filter(|arg| arg.is_ty_or_const()) + .position(|arg| arg.id() == hir_id) + .map(|index| (index, seg)).or_else(|| args.bindings .iter() - .filter(|arg| arg.is_ty_or_const()) - .position(|arg| arg.id() == hir_id) - .map(|index| (index, seg)) - }); - - // FIXME(associated_const_generics): can we blend this with iteration above? - let (arg_index, segment) = match filtered { - None => { - let binding_filtered = path.segments.iter().find_map(|seg| { - seg.args? - .bindings - .iter() - .filter_map(TypeBinding::opt_const) - .position(|ct| ct.hir_id == hir_id) - .map(|idx| (idx, seg)) - }); - match binding_filtered { - Some(inner) => inner, - None => { - tcx.sess.delay_span_bug( - tcx.def_span(def_id), - "no arg matching AnonConst in path", - ); - return None; - } - } - } - Some(inner) => inner, + .filter_map(TypeBinding::opt_const) + .position(|ct| ct.hir_id == hir_id) + .map(|idx| (idx, seg))) + }) else { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + "no arg matching AnonConst in path", + ); + return None; }; // Try to use the segment resolution if it is valid, otherwise we diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 20ef834eaee..caa629cf4e6 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -770,10 +770,14 @@ impl<T> BTreeSet<T> { /// Adds a value to the set. /// - /// If the set did not have an equal element present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have an equal element present, `false` is returned, and - /// the entry is not updated. See the [module-level documentation] for more. + /// - If the set did not previously contain an equal value, `true` is + /// returned. + /// - If the set already contained an equal value, `false` is returned, and + /// the entry is not updated. + /// + /// See the [module-level documentation] for more. /// /// [module-level documentation]: index.html#insert-and-complex-keys /// diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 45947c4f4a5..33cffa643e4 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2495,6 +2495,7 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> { impl<T, A: Allocator> ops::Deref for Vec<T, A> { type Target = [T]; + #[inline] fn deref(&self) -> &[T] { unsafe { slice::from_raw_parts(self.as_ptr(), self.len) } } @@ -2502,6 +2503,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> { #[stable(feature = "rust1", since = "1.0.0")] impl<T, A: Allocator> ops::DerefMut for Vec<T, A> { + #[inline] fn deref_mut(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) } } diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index df0e7431f1f..a888ced49b3 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -126,7 +126,6 @@ macro_rules! from_str_float_impl { /// ```txt /// Float ::= Sign? ( 'inf' | 'infinity' | 'nan' | Number ) /// Number ::= ( Digit+ | - /// '.' Digit* | /// Digit+ '.' Digit* | /// Digit* '.' Digit+ ) Exp? /// Exp ::= 'e' Sign? Digit+ diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 1aaa274a054..1fbf592c232 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1622,6 +1622,122 @@ impl<T> *mut [T] { metadata(self) } + /// Returns `true` if the raw slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_ptr_len)] + /// + /// let mut a = [1, 2, 3]; + /// let ptr = &mut a as *mut [_]; + /// assert!(!ptr.is_empty()); + /// ``` + #[inline(always)] + #[unstable(feature = "slice_ptr_len", issue = "71146")] + #[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")] + pub const fn is_empty(self) -> bool { + self.len() == 0 + } + + /// Divides one mutable raw slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Safety + /// + /// `mid` must be [in-bounds] of the underlying [allocated object]. + /// Which means `self` must be dereferenceable and span a single allocation + /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these + /// requirements is *[undefined behavior]* even if the resulting pointers are not used. + /// + /// Since `len` being in-bounds it is not a safety invariant of `*mut [T]` the + /// safety requirements of this method are the same as for [`split_at_mut_unchecked`]. + /// The explicit bounds check is only as useful as `len` is correct. + /// + /// [`split_at_mut_unchecked`]: #method.split_at_mut_unchecked + /// [in-bounds]: #method.add + /// [allocated object]: crate::ptr#allocated-object + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(raw_slice_split)] + /// #![feature(slice_ptr_get)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// let ptr = &mut v as *mut [_]; + /// unsafe { + /// let (left, right) = ptr.split_at_mut(2); + /// assert_eq!(&*left, [1, 0]); + /// assert_eq!(&*right, [3, 0, 5, 6]); + /// } + /// ``` + #[inline(always)] + #[track_caller] + #[unstable(feature = "raw_slice_split", issue = "95595")] + pub unsafe fn split_at_mut(self, mid: usize) -> (*mut [T], *mut [T]) { + assert!(mid <= self.len()); + // SAFETY: The assert above is only a safety-net as long as `self.len()` is correct + // The actual safety requirements of this function are the same as for `split_at_mut_unchecked` + unsafe { self.split_at_mut_unchecked(mid) } + } + + /// Divides one mutable raw slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Safety + /// + /// `mid` must be [in-bounds] of the underlying [allocated object]. + /// Which means `self` must be dereferenceable and span a single allocation + /// that is at least `mid * size_of::<T>()` bytes long. Not upholding these + /// requirements is *[undefined behavior]* even if the resulting pointers are not used. + /// + /// [in-bounds]: #method.add + /// [out-of-bounds index]: #method.add + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(raw_slice_split)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let ptr = &mut v as *mut [_]; + /// let (left, right) = ptr.split_at_mut_unchecked(2); + /// assert_eq!(&*left, [1, 0]); + /// assert_eq!(&*right, [3, 0, 5, 6]); + /// (&mut *left)[1] = 2; + /// (&mut *right)[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[inline(always)] + #[unstable(feature = "raw_slice_split", issue = "95595")] + pub unsafe fn split_at_mut_unchecked(self, mid: usize) -> (*mut [T], *mut [T]) { + let len = self.len(); + let ptr = self.as_mut_ptr(); + + // SAFETY: Caller must pass a valid pointer and an index that is in-bounds. + let tail = unsafe { ptr.add(mid) }; + ( + crate::ptr::slice_from_raw_parts_mut(ptr, mid), + crate::ptr::slice_from_raw_parts_mut(tail, len - mid), + ) + } + /// Returns a raw pointer to the slice's buffer. /// /// This is equivalent to casting `self` to `*mut T`, but more type-safe. @@ -1645,9 +1761,10 @@ impl<T> *mut [T] { /// Returns a raw pointer to an element or subslice, without doing bounds /// checking. /// - /// Calling this method with an out-of-bounds index or when `self` is not dereferenceable + /// Calling this method with an [out-of-bounds index] or when `self` is not dereferenceable /// is *[undefined behavior]* even if the resulting pointer is not used. /// + /// [out-of-bounds index]: #method.add /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// /// # Examples diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 95506fc1eb9..229e546e085 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } libc = { version = "0.2.126", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.71" } +compiler_builtins = { version = "0.1.73" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 4ec423eb27f..11ccdd9ea1c 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -896,6 +896,119 @@ where self.base.get_key_value(k) } + /// Attempts to get mutable references to `N` values in the map at once. + /// + /// Returns an array of length `N` with the results of each query. For soundness, at most one + /// mutable reference will be returned to any value. `None` will be returned if any of the + /// keys are duplicates or missing. + /// + /// # Examples + /// + /// ``` + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// + /// // Duplicate keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Athenæum", + /// ]); + /// assert_eq!(got, None); + /// ``` + #[inline] + #[unstable(feature = "map_many_mut", issue = "97601")] + pub fn get_many_mut<Q: ?Sized, const N: usize>(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + where + K: Borrow<Q>, + Q: Hash + Eq, + { + self.base.get_many_mut(ks) + } + + /// Attempts to get mutable references to `N` values in the map at once, without validating that + /// the values are unique. + /// + /// Returns an array of length `N` with the results of each query. `None` will be returned if + /// any of the keys are missing. + /// + /// For a safe alternative see [`get_many_mut`](Self::get_many_mut). + /// + /// # Safety + /// + /// Calling this method with overlapping keys is *[undefined behavior]* even if the resulting + /// references are not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ``` + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Bodleian Library".to_string(), 1602); + /// libraries.insert("Athenæum".to_string(), 1807); + /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); + /// libraries.insert("Library of Congress".to_string(), 1800); + /// + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "Library of Congress", + /// ]); + /// assert_eq!( + /// got, + /// Some([ + /// &mut 1807, + /// &mut 1800, + /// ]), + /// ); + /// + /// // Missing keys result in None + /// let got = libraries.get_many_mut([ + /// "Athenæum", + /// "New York Public Library", + /// ]); + /// assert_eq!(got, None); + /// ``` + #[inline] + #[unstable(feature = "map_many_mut", issue = "97601")] + pub unsafe fn get_many_unchecked_mut<Q: ?Sized, const N: usize>( + &mut self, + ks: [&Q; N], + ) -> Option<[&'_ mut V; N]> + where + K: Borrow<Q>, + Q: Hash + Eq, + { + self.base.get_many_unchecked_mut(ks) + } + /// Returns `true` if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index da0572047ec..19428fe9a23 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -858,9 +858,10 @@ where /// Adds a value to the set. /// - /// If the set did not have this value present, `true` is returned. + /// Returns whether the value was newly inserted. That is: /// - /// If the set did have this value present, `false` is returned. + /// - If the set did not previously contain this value, `true` is returned. + /// - If the set already contained this value, `false` is returned. /// /// # Examples /// diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1e434458dce..4605793d0df 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1667,6 +1667,10 @@ impl Type { matches!(self, Type::Generic(_)) } + pub(crate) fn is_impl_trait(&self) -> bool { + matches!(self, Type::ImplTrait(_)) + } + pub(crate) fn is_primitive(&self) -> bool { self.primitive_type().is_some() } diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs index 2367bde0167..9f26ccc74d1 100644 --- a/src/librustdoc/formats/mod.rs +++ b/src/librustdoc/formats/mod.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::DefId; pub(crate) use renderer::{run_format, FormatRenderer}; use crate::clean::{self, ItemId}; +use cache::Cache; /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. @@ -60,4 +61,28 @@ impl Impl { } } } + + // Returns true if this is an implementation on a "local" type, meaning: + // the type is in the current crate, or the type and the trait are both + // re-exported by the current crate. + pub(crate) fn is_on_local_type(&self, cache: &Cache) -> bool { + let for_type = &self.inner_impl().for_; + if let Some(for_type_did) = for_type.def_id(cache) { + // The "for" type is local if it's in the paths for the current crate. + if cache.paths.contains_key(&for_type_did) { + return true; + } + if let Some(trait_did) = self.trait_did() { + // The "for" type and the trait are from the same crate. That could + // be different from the current crate, for instance when both were + // re-exported from some other crate. But they are local with respect to + // each other. + if for_type_did.krate == trait_did.krate { + return true; + } + } + return false; + }; + true + } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b8d6b340b14..0b801a20995 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2285,9 +2285,7 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean if let Some(implementors) = cache.implementors.get(&it.item_id.expect_def_id()) { let mut res = implementors .iter() - .filter(|i| { - i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d)) - }) + .filter(|i| !i.is_on_local_type(cache)) .filter_map(|i| extract_for_impl_name(&i.impl_item, cx)) .collect::<Vec<_>>(); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index dcf36b5e865..8683e6dfcd9 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -822,9 +822,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean: } } - let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| { - i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d)) - }); + let (local, foreign) = + implementors.iter().partition::<Vec<_>, _>(|i| i.is_on_local_type(cache)); let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter().partition(|i| i.inner_impl().kind.is_auto()); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 25c70f0808c..9f302cc2566 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -226,17 +226,17 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> { Some(path.segments.last().unwrap().name) } // We return an empty name because we don't care about the generic name itself. - clean::Generic(_) => Some(kw::Empty), + clean::Generic(_) | clean::ImplTrait(_) => Some(kw::Empty), clean::Primitive(ref p) => Some(p.as_sym()), - clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_), + clean::BorrowedRef { ref type_, .. } | clean::RawPointer(_, ref type_) => { + get_index_type_name(type_) + } clean::BareFunction(_) | clean::Tuple(_) | clean::Slice(_) | clean::Array(_, _) - | clean::RawPointer(_, _) | clean::QPath { .. } - | clean::Infer - | clean::ImplTrait(_) => None, + | clean::Infer => None, } } @@ -264,10 +264,12 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( mut generics: Vec<TypeWithKind>, cache: &Cache, ) { - let is_full_generic = ty.is_full_generic(); + // generics and impl trait are both identified by their generics, + // rather than a type name itself + let anonymous = ty.is_full_generic() || ty.is_impl_trait(); let generics_empty = generics.is_empty(); - if is_full_generic { + if anonymous { if generics_empty { // This is a type parameter with no trait bounds (for example: `T` in // `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up @@ -318,7 +320,7 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) { return; } - if is_full_generic { + if anonymous { // We remove the name of the full generic because we have no use for it. index_ty.name = Some(String::new()); res.push(TypeWithKind::from((index_ty, ItemType::Generic))); @@ -398,6 +400,23 @@ fn add_generics_and_bounds_as_types<'tcx, 'a>( } insert_ty(res, tcx, arg.clone(), ty_generics, cache); } + } else if let Type::ImplTrait(ref bounds) = *arg { + let mut ty_generics = Vec::new(); + for bound in bounds { + if let Some(path) = bound.get_trait_path() { + let ty = Type::Path { path }; + add_generics_and_bounds_as_types( + self_, + generics, + &ty, + tcx, + recurse + 1, + &mut ty_generics, + cache, + ); + } + } + insert_ty(res, tcx, arg.clone(), ty_generics, cache); } else { // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't. diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index aa7028247be..6ea33d763b1 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -9,7 +9,7 @@ use crate::visit::DocVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::DefId; -use rustc_middle::ty::DefIdTree; +use rustc_middle::ty::{self, DefIdTree}; use rustc_span::symbol::sym; pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass { @@ -81,8 +81,35 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // Do not calculate blanket impl list for docs that are not going to be rendered. // While the `impl` blocks themselves are only in `libcore`, the module with `doc` // attached is directly included in `libstd` as well. + let tcx = cx.tcx; if did.is_local() { - for def_id in prim.impls(cx.tcx) { + for def_id in prim.impls(tcx).filter(|def_id| { + // Avoid including impl blocks with filled-in generics. + // https://github.com/rust-lang/rust/issues/94937 + // + // FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129 + // + // This tactic of using inherent impl blocks for getting + // auto traits and blanket impls is a hack. What we really + // want is to check if `[T]` impls `Send`, which has + // nothing to do with the inherent impl. + // + // Rustdoc currently uses these `impl` block as a source of + // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and + // `Generics`. To avoid relying on the `impl` block, these + // things would need to be created from wholecloth, in a + // form that is valid for use in type inference. + let ty = tcx.type_of(def_id); + match ty.kind() { + ty::Slice(ty) + | ty::Ref(_, ty, _) + | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { + matches!(ty.kind(), ty::Param(..)) + } + ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))), + _ => true, + } + }) { let impls = get_auto_trait_and_blanket_impls(cx, def_id); new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id))); } diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 4fdd4b2b4bb..84d72202d52 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -21,7 +21,7 @@ // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // + literal: Const { ty: &i32, val: Unevaluated(FOO, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - _1 = move _2 as usize (PointerAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 + _1 = move _2 as usize (PointerExposeAddress); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 StorageDead(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:39: 7:40 StorageLive(_4); // scope 1 at $DIR/const_prop_fails_gracefully.rs:8:5: 8:12 diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff index 7eb34ed5469..04724b13ca6 100644 --- a/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.main.ConstProp.diff @@ -17,7 +17,7 @@ // mir::Constant // + span: $DIR/reify_fn_ptr.rs:4:13: 4:17 // + literal: Const { ty: fn() {main}, val: Value(Scalar(<ZST>)) } - _2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 + _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:26 StorageDead(_3); // scope 0 at $DIR/reify_fn_ptr.rs:4:25: 4:26 _1 = move _2 as *const fn() (Misc); // scope 0 at $DIR/reify_fn_ptr.rs:4:13: 4:41 StorageDead(_2); // scope 0 at $DIR/reify_fn_ptr.rs:4:40: 4:41 diff --git a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff index bf32245e300..2331f63ecdd 100644 --- a/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff +++ b/src/test/mir-opt/dead-store-elimination/provenance_soundness.pointer_to_int.DeadStoreElimination.diff @@ -19,12 +19,12 @@ StorageLive(_2); // scope 0 at $DIR/provenance_soundness.rs:8:9: 8:11 StorageLive(_3); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 _3 = _1; // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:15 - _2 = move _3 as usize (PointerAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24 + _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/provenance_soundness.rs:8:14: 8:24 StorageDead(_3); // scope 0 at $DIR/provenance_soundness.rs:8:23: 8:24 StorageLive(_4); // scope 1 at $DIR/provenance_soundness.rs:9:9: 9:11 StorageLive(_5); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 _5 = _1; // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:15 - _4 = move _5 as isize (PointerAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24 + _4 = move _5 as isize (PointerExposeAddress); // scope 1 at $DIR/provenance_soundness.rs:9:14: 9:24 StorageDead(_5); // scope 1 at $DIR/provenance_soundness.rs:9:23: 9:24 _0 = const (); // scope 0 at $DIR/provenance_soundness.rs:7:32: 10:2 StorageDead(_4); // scope 1 at $DIR/provenance_soundness.rs:10:1: 10:2 diff --git a/src/test/rustdoc-js/impl-trait.js b/src/test/rustdoc-js/impl-trait.js new file mode 100644 index 00000000000..8d594bf8aea --- /dev/null +++ b/src/test/rustdoc-js/impl-trait.js @@ -0,0 +1,51 @@ +// ignore-order + +const QUERY = [ + 'Aaaaaaa -> i32', + 'Aaaaaaa -> Aaaaaaa', + 'Aaaaaaa -> usize', + '-> Aaaaaaa', + 'Aaaaaaa', +]; + +const EXPECTED = [ + { + // Aaaaaaa -> i32 + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' }, + ], + }, + { + // Aaaaaaa -> Aaaaaaa + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [], + }, + { + // -> Aaaaaaa + 'others': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'impl_trait', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa + 'others': [ + { 'path': 'impl_trait', 'name': 'Aaaaaaa' }, + ], + 'in_args': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'eeeeeee' }, + ], + 'returned': [ + { 'path': 'impl_trait::Ccccccc', 'name': 'fffffff' }, + { 'path': 'impl_trait::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'impl_trait', 'name': 'bbbbbbb' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/impl-trait.rs b/src/test/rustdoc-js/impl-trait.rs new file mode 100644 index 00000000000..fb8869b46f3 --- /dev/null +++ b/src/test/rustdoc-js/impl-trait.rs @@ -0,0 +1,21 @@ +pub trait Aaaaaaa {} + +impl Aaaaaaa for () {} + +pub fn bbbbbbb() -> impl Aaaaaaa { + () +} + +pub struct Ccccccc {} + +impl Ccccccc { + pub fn ddddddd(&self) -> impl Aaaaaaa { + () + } + pub fn eeeeeee(&self, _x: impl Aaaaaaa) -> i32 { + 0 + } + pub fn fffffff(&self, x: impl Aaaaaaa) -> impl Aaaaaaa { + x + } +} diff --git a/src/test/rustdoc-js/raw-pointer.js b/src/test/rustdoc-js/raw-pointer.js new file mode 100644 index 00000000000..140b955ea71 --- /dev/null +++ b/src/test/rustdoc-js/raw-pointer.js @@ -0,0 +1,55 @@ +// ignore-order + +const QUERY = [ + 'Aaaaaaa -> i32', + 'Aaaaaaa -> Aaaaaaa', + 'Aaaaaaa -> usize', + '-> Aaaaaaa', + 'Aaaaaaa', +]; + +const EXPECTED = [ + { + // Aaaaaaa -> i32 + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' }, + ], + }, + { + // Aaaaaaa -> Aaaaaaa + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + ], + }, + { + // Aaaaaaa -> usize + 'others': [], + }, + { + // -> Aaaaaaa + 'others': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'raw_pointer', 'name': 'bbbbbbb' }, + ], + }, + { + // Aaaaaaa + 'others': [ + { 'path': 'raw_pointer', 'name': 'Aaaaaaa' }, + ], + 'in_args': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'eeeeeee' }, + ], + 'returned': [ + { 'path': 'raw_pointer::Ccccccc', 'name': 'fffffff' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ggggggg' }, + { 'path': 'raw_pointer::Ccccccc', 'name': 'ddddddd' }, + { 'path': 'raw_pointer', 'name': 'bbbbbbb' }, + ], + }, +]; diff --git a/src/test/rustdoc-js/raw-pointer.rs b/src/test/rustdoc-js/raw-pointer.rs new file mode 100644 index 00000000000..b8ace2e0b7d --- /dev/null +++ b/src/test/rustdoc-js/raw-pointer.rs @@ -0,0 +1,24 @@ +use std::ptr; + +pub struct Aaaaaaa {} + +pub fn bbbbbbb() -> *const Aaaaaaa { + ptr::null() +} + +pub struct Ccccccc {} + +impl Ccccccc { + pub fn ddddddd(&self) -> *const Aaaaaaa { + ptr::null() + } + pub fn eeeeeee(&self, _x: *const Aaaaaaa) -> i32 { + 0 + } + pub fn fffffff(&self, x: *const Aaaaaaa) -> *const Aaaaaaa { + x + } + pub fn ggggggg(&self, x: *mut Aaaaaaa) -> *mut Aaaaaaa { + x + } +} diff --git a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr index b60ab6050d7..b54f8200666 100644 --- a/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr +++ b/src/test/rustdoc-ui/intra-doc/unresolved-import-recovery.stderr @@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `unresolved_crate`? | LL | use unresolved_crate::module::Name; | ^^^^^^^^^^^^^^^^ maybe a missing crate `unresolved_crate`? + | + = help: consider adding `extern crate unresolved_crate` to use the `unresolved_crate` crate error: Compilation failed, aborting rustdoc diff --git a/src/test/rustdoc-ui/issue-61732.stderr b/src/test/rustdoc-ui/issue-61732.stderr index 82134224911..38fadaa4435 100644 --- a/src/test/rustdoc-ui/issue-61732.stderr +++ b/src/test/rustdoc-ui/issue-61732.stderr @@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `r#mod`? | LL | pub(in crate::r#mod) fn main() {} | ^^^^^ maybe a missing crate `r#mod`? + | + = help: consider adding `extern crate r#mod` to use the `r#mod` crate error: Compilation failed, aborting rustdoc diff --git a/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs new file mode 100644 index 00000000000..b003fb357d0 --- /dev/null +++ b/src/test/rustdoc/inline_cross/auxiliary/implementors_inline.rs @@ -0,0 +1,18 @@ +pub mod my_trait { + pub trait MyTrait { + fn my_fn(&self) -> Self; + } +} + +pub mod prelude { + #[doc(inline)] + pub use crate::my_trait::MyTrait; +} + +pub struct SomeStruct; + +impl my_trait::MyTrait for SomeStruct { + fn my_fn(&self) -> SomeStruct { + SomeStruct + } +} diff --git a/src/test/rustdoc/inline_cross/implementors-js.rs b/src/test/rustdoc/inline_cross/implementors-js.rs new file mode 100644 index 00000000000..c79f05d8d3c --- /dev/null +++ b/src/test/rustdoc/inline_cross/implementors-js.rs @@ -0,0 +1,25 @@ +// aux-build:implementors_inline.rs +// build-aux-docs +// ignore-cross-compile + +extern crate implementors_inline; + +// @!has implementors/implementors_js/trait.MyTrait.js +// @has implementors/implementors_inline/my_trait/trait.MyTrait.js +// @!has implementors/implementors_inline/prelude/trait.MyTrait.js +// @has implementors_inline/my_trait/trait.MyTrait.html +// @has - '//script/@src' '../../implementors/implementors_inline/my_trait/trait.MyTrait.js' +// @has implementors_js/trait.MyTrait.html +// @has - '//script/@src' '../implementors/implementors_inline/my_trait/trait.MyTrait.js' +/// When re-exporting this trait, the HTML will be inlined, +/// but, vitally, the JavaScript will be located only at the +/// one canonical path. +pub use implementors_inline::prelude::MyTrait; + +pub struct OtherStruct; + +impl MyTrait for OtherStruct { + fn my_fn(&self) -> OtherStruct { + OtherStruct + } +} diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs index ae74fbbc892..24161c3bb48 100644 --- a/src/test/rustdoc/intra-doc/email-address.rs +++ b/src/test/rustdoc/intra-doc/email-address.rs @@ -1,8 +1,10 @@ -#![allow(rustdoc::broken_intra_doc_links)] +#![forbid(rustdoc::broken_intra_doc_links)] //! Email me at <hello@example.com>. //! Email me at <hello-world@example.com>. -//! Email me at <hello@localhost> (this warns but will still become a link). +//! Email me at <hello@localhost>. +//! Email me at <prim@i32>. // @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com' // @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com' // @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost' +// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32' diff --git a/src/test/rustdoc/issue-75588.rs b/src/test/rustdoc/issue-75588.rs index ac97b94fb35..a8cb16ec34c 100644 --- a/src/test/rustdoc/issue-75588.rs +++ b/src/test/rustdoc/issue-75588.rs @@ -13,5 +13,5 @@ extern crate real_gimli; // @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//h3[@class="code-header in-band"]' 'impl Deref for EndianSlice' pub use realcore::Deref; -// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//h3[@class="code-header in-band"]' 'impl Join for Foo' +// @has foo/trait.Join.html '//*[@id="impl-Join"]//h3[@class="code-header in-band"]' 'impl Join for Foo' pub use realcore::Join; diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs new file mode 100644 index 00000000000..b3f511bc1f1 --- /dev/null +++ b/src/test/rustdoc/primitive-slice-auto-trait.rs @@ -0,0 +1,14 @@ +// compile-flags: --crate-type lib --edition 2018 + +#![crate_name = "foo"] +#![feature(rustdoc_internals)] + +// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice' +// @has - '//span[@class="in-band"]' 'Primitive Type slice' +// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!' +// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send' +// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync' +#[doc(primitive = "slice")] +/// this is a test! +mod slice_prim {} diff --git a/src/test/ui/attributes/field-attributes-vis-unresolved.stderr b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr index 41c3cea3021..43976254638 100644 --- a/src/test/ui/attributes/field-attributes-vis-unresolved.stderr +++ b/src/test/ui/attributes/field-attributes-vis-unresolved.stderr @@ -3,12 +3,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistent`? | LL | pub(in nonexistent) field: u8 | ^^^^^^^^^^^ maybe a missing crate `nonexistent`? + | + = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate error[E0433]: failed to resolve: maybe a missing crate `nonexistent`? --> $DIR/field-attributes-vis-unresolved.rs:22:12 | LL | pub(in nonexistent) u8 | ^^^^^^^^^^^ maybe a missing crate `nonexistent`? + | + = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/issue-71546.rs b/src/test/ui/borrowck/issue-71546.rs new file mode 100644 index 00000000000..943f7f86e55 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.rs @@ -0,0 +1,19 @@ +// Regression test for #71546. + +// ignore-compare-mode-nll +// NLL stderr is different from the original one. + +pub fn serialize_as_csv<V>(value: &V) -> Result<String, &str> +where + V: 'static, + for<'a> &'a V: IntoIterator, + for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, +{ + let csv_str: String = value //~ ERROR: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + .into_iter() + .map(|elem| elem.to_string()) + .collect::<String>(); + Ok(csv_str) +} + +fn main() {} diff --git a/src/test/ui/borrowck/issue-71546.stderr b/src/test/ui/borrowck/issue-71546.stderr new file mode 100644 index 00000000000..d479ca8f1d8 --- /dev/null +++ b/src/test/ui/borrowck/issue-71546.stderr @@ -0,0 +1,20 @@ +error[E0310]: the associated type `<&'a V as IntoIterator>::Item` may not live long enough + --> $DIR/issue-71546.rs:12:27 + | +LL | let csv_str: String = value + | ___________________________^ +LL | | .into_iter() +LL | | .map(|elem| elem.to_string()) + | |_____________________________________^ + | + = help: consider adding an explicit lifetime bound `<&'a V as IntoIterator>::Item: 'static`... + = note: ...so that the type `<&'a V as IntoIterator>::Item` will meet its required lifetime bounds... +note: ...that is required by this bound + --> $DIR/issue-71546.rs:10:55 + | +LL | for<'a> <&'a V as IntoIterator>::Item: ToString + 'static, + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index aff51ee9e2f..2eb3fd56783 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -5,6 +5,7 @@ LL | impl Bar for Baz { } | ^^^ type aliases cannot be used as traits | help: you might have meant to use `#![feature(trait_alias)]` instead of a `type` alias + --> $DIR/two_files_data.rs:5:1 | LL | trait Bar = dyn Foo; | diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr index c918651ba62..7390a007742 100644 --- a/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr +++ b/src/test/ui/const-generics/generic_const_exprs/issue-94287.stderr @@ -6,6 +6,7 @@ LL | If<{ FRAC <= 32 }>: True, | = note: the crate this constant originates from uses `#![feature(generic_const_exprs)]` help: consider enabling this feature + --> $DIR/issue-94287.rs:1:1 | LL | #![feature(generic_const_exprs)] | diff --git a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr index 23dad2c16b2..570bbac2b21 100644 --- a/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2015-2018-expansion.stderr @@ -6,6 +6,7 @@ LL | produces_async! {} | = note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info) help: escape `async` to use it as an identifier + --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19 | LL | () => (pub fn r#async() {}) | ++ diff --git a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr index 67f9aa60413..69f275746bd 100644 --- a/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr +++ b/src/test/ui/editions/edition-keywords-2018-2018-expansion.stderr @@ -6,6 +6,7 @@ LL | produces_async! {} | = note: this error originates in the macro `produces_async` (in Nightly builds, run with -Z macro-backtrace for more info) help: escape `async` to use it as an identifier + --> $DIR/auxiliary/edition-kw-macro-2018.rs:7:19 | LL | () => (pub fn r#async() {}) | ++ diff --git a/src/test/ui/error-codes/E0432.stderr b/src/test/ui/error-codes/E0432.stderr index afb031c2252..ed9536f164e 100644 --- a/src/test/ui/error-codes/E0432.stderr +++ b/src/test/ui/error-codes/E0432.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `something` | LL | use something::Foo; | ^^^^^^^^^ maybe a missing crate `something`? + | + = help: consider adding `extern crate something` to use the `something` crate error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr b/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr index 2f4c220ee95..3bae23a4aaa 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_absolute_paths.stderr @@ -3,12 +3,16 @@ error[E0432]: unresolved import `core` | LL | use core::default; | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate error[E0433]: failed to resolve: maybe a missing crate `core`? --> $DIR/feature-gate-extern_absolute_paths.rs:4:19 | LL | let _: u8 = ::core::default::Default(); | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/import3.stderr b/src/test/ui/imports/import3.stderr index 7bb413be59f..ca75c9c18bd 100644 --- a/src/test/ui/imports/import3.stderr +++ b/src/test/ui/imports/import3.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `main` | LL | use main::bar; | ^^^^ maybe a missing crate `main`? + | + = help: consider adding `extern crate main` to use the `main` crate error: aborting due to previous error diff --git a/src/test/ui/imports/issue-1697.stderr b/src/test/ui/imports/issue-1697.stderr index a76fd309914..019ef9ad56a 100644 --- a/src/test/ui/imports/issue-1697.stderr +++ b/src/test/ui/imports/issue-1697.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `unresolved` | LL | use unresolved::*; | ^^^^^^^^^^ maybe a missing crate `unresolved`? + | + = help: consider adding `extern crate unresolved` to use the `unresolved` crate error: aborting due to previous error diff --git a/src/test/ui/imports/issue-33464.stderr b/src/test/ui/imports/issue-33464.stderr index d3bf404c99a..c4e5c555899 100644 --- a/src/test/ui/imports/issue-33464.stderr +++ b/src/test/ui/imports/issue-33464.stderr @@ -3,18 +3,24 @@ error[E0432]: unresolved import `abc` | LL | use abc::one_el; | ^^^ maybe a missing crate `abc`? + | + = help: consider adding `extern crate abc` to use the `abc` crate error[E0432]: unresolved import `abc` --> $DIR/issue-33464.rs:5:5 | LL | use abc::{a, bbb, cccccc}; | ^^^ maybe a missing crate `abc`? + | + = help: consider adding `extern crate abc` to use the `abc` crate error[E0432]: unresolved import `a_very_long_name` --> $DIR/issue-33464.rs:7:5 | LL | use a_very_long_name::{el, el2}; | ^^^^^^^^^^^^^^^^ maybe a missing crate `a_very_long_name`? + | + = help: consider adding `extern crate a_very_long_name` to use the `a_very_long_name` crate error: aborting due to 3 previous errors diff --git a/src/test/ui/imports/issue-36881.stderr b/src/test/ui/imports/issue-36881.stderr index caf9d5d6d62..2e1b468603d 100644 --- a/src/test/ui/imports/issue-36881.stderr +++ b/src/test/ui/imports/issue-36881.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `issue_36881_aux` | LL | use issue_36881_aux::Foo; | ^^^^^^^^^^^^^^^ maybe a missing crate `issue_36881_aux`? + | + = help: consider adding `extern crate issue_36881_aux` to use the `issue_36881_aux` crate error: aborting due to previous error diff --git a/src/test/ui/imports/issue-37887.stderr b/src/test/ui/imports/issue-37887.stderr index 944d544098a..75185cad3b7 100644 --- a/src/test/ui/imports/issue-37887.stderr +++ b/src/test/ui/imports/issue-37887.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `libc` | LL | use libc::*; | ^^^^ maybe a missing crate `libc`? + | + = help: consider adding `extern crate libc` to use the `libc` crate error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/issue-37887.rs:2:5 diff --git a/src/test/ui/imports/issue-53269.stderr b/src/test/ui/imports/issue-53269.stderr index a0e7bf8b61f..29c7556dac4 100644 --- a/src/test/ui/imports/issue-53269.stderr +++ b/src/test/ui/imports/issue-53269.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `nonexistent_module` | LL | use nonexistent_module::mac; | ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`? + | + = help: consider adding `extern crate nonexistent_module` to use the `nonexistent_module` crate error[E0659]: `mac` is ambiguous --> $DIR/issue-53269.rs:8:5 diff --git a/src/test/ui/imports/issue-55457.stderr b/src/test/ui/imports/issue-55457.stderr index 07de3d95902..788fcc830ae 100644 --- a/src/test/ui/imports/issue-55457.stderr +++ b/src/test/ui/imports/issue-55457.stderr @@ -12,6 +12,8 @@ error[E0432]: unresolved import `non_existent` | LL | use non_existent::non_existent; | ^^^^^^^^^^^^ maybe a missing crate `non_existent`? + | + = help: consider adding `extern crate non_existent` to use the `non_existent` crate error: cannot determine resolution for the derive macro `NonExistent` --> $DIR/issue-55457.rs:5:10 diff --git a/src/test/ui/imports/tool-mod-child.stderr b/src/test/ui/imports/tool-mod-child.stderr index efab4f6a74f..6caf15bc724 100644 --- a/src/test/ui/imports/tool-mod-child.stderr +++ b/src/test/ui/imports/tool-mod-child.stderr @@ -3,24 +3,32 @@ error[E0433]: failed to resolve: maybe a missing crate `clippy`? | LL | use clippy::a::b; | ^^^^^^ maybe a missing crate `clippy`? + | + = help: consider adding `extern crate clippy` to use the `clippy` crate error[E0432]: unresolved import `clippy` --> $DIR/tool-mod-child.rs:1:5 | LL | use clippy::a; | ^^^^^^ maybe a missing crate `clippy`? + | + = help: consider adding `extern crate clippy` to use the `clippy` crate error[E0433]: failed to resolve: maybe a missing crate `rustdoc`? --> $DIR/tool-mod-child.rs:5:5 | LL | use rustdoc::a::b; | ^^^^^^^ maybe a missing crate `rustdoc`? + | + = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate error[E0432]: unresolved import `rustdoc` --> $DIR/tool-mod-child.rs:4:5 | LL | use rustdoc::a; | ^^^^^^^ maybe a missing crate `rustdoc`? + | + = help: consider adding `extern crate rustdoc` to use the `rustdoc` crate error: aborting due to 4 previous errors diff --git a/src/test/ui/imports/unresolved-imports-used.stderr b/src/test/ui/imports/unresolved-imports-used.stderr index ddf36089339..73f9d1bfb6c 100644 --- a/src/test/ui/imports/unresolved-imports-used.stderr +++ b/src/test/ui/imports/unresolved-imports-used.stderr @@ -15,24 +15,32 @@ error[E0432]: unresolved import `foo` | LL | use foo::bar; | ^^^ maybe a missing crate `foo`? + | + = help: consider adding `extern crate foo` to use the `foo` crate error[E0432]: unresolved import `baz` --> $DIR/unresolved-imports-used.rs:12:5 | LL | use baz::*; | ^^^ maybe a missing crate `baz`? + | + = help: consider adding `extern crate baz` to use the `baz` crate error[E0432]: unresolved import `foo2` --> $DIR/unresolved-imports-used.rs:14:5 | LL | use foo2::bar2; | ^^^^ maybe a missing crate `foo2`? + | + = help: consider adding `extern crate foo2` to use the `foo2` crate error[E0432]: unresolved import `baz2` --> $DIR/unresolved-imports-used.rs:15:5 | LL | use baz2::*; | ^^^^ maybe a missing crate `baz2`? + | + = help: consider adding `extern crate baz2` to use the `baz2` crate error[E0603]: function `quz` is private --> $DIR/unresolved-imports-used.rs:9:10 diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index 4c11f354494..c6e6ea1e096 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -9,6 +9,7 @@ LL | assert_eq!(a, 0); | = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) help: you might have forgotten to call this function + --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | if !(*left_val() == *right_val) { | ++ diff --git a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr index 247d6b0ed71..54ee45c2867 100644 --- a/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr +++ b/src/test/ui/keyword/extern/keyword-extern-as-identifier-use.stderr @@ -14,6 +14,8 @@ error[E0432]: unresolved import `r#extern` | LL | use extern::foo; | ^^^^^^ maybe a missing crate `r#extern`? + | + = help: consider adding `extern crate r#extern` to use the `r#extern` crate error: aborting due to 2 previous errors diff --git a/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr index 09978b35f7e..0af58bc61f4 100644 --- a/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/methods/method-on-ambiguous-numeric-type.stderr @@ -46,6 +46,7 @@ LL | bar.pow(2); | ^^^ | help: you must specify a type for this binding, like `i32` + --> $DIR/auxiliary/macro-in-other-crate.rs:3:29 | LL | ($ident:ident) => { let $ident: i32 = 42; } | ~~~~~~~~~~~ diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index 5a85aef2b17..c81520c35cd 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `bad`? | LL | pub(in bad::path) mod m1 {} | ^^^ maybe a missing crate `bad`? + | + = help: consider adding `extern crate bad` to use the `bad` crate error[E0742]: visibilities can only be restricted to ancestor modules --> $DIR/test.rs:51:12 diff --git a/src/test/ui/resolve/editions-crate-root-2015.stderr b/src/test/ui/resolve/editions-crate-root-2015.stderr index f8d65fec3d1..00cdd0c58f4 100644 --- a/src/test/ui/resolve/editions-crate-root-2015.stderr +++ b/src/test/ui/resolve/editions-crate-root-2015.stderr @@ -3,12 +3,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistant`? | LL | fn global_inner(_: ::nonexistant::Foo) { | ^^^^^^^^^^^ maybe a missing crate `nonexistant`? + | + = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate error[E0433]: failed to resolve: maybe a missing crate `nonexistant`? --> $DIR/editions-crate-root-2015.rs:7:30 | LL | fn crate_inner(_: crate::nonexistant::Foo) { | ^^^^^^^^^^^ maybe a missing crate `nonexistant`? + | + = help: consider adding `extern crate nonexistant` to use the `nonexistant` crate error[E0412]: cannot find type `nonexistant` in the crate root --> $DIR/editions-crate-root-2015.rs:11:25 diff --git a/src/test/ui/resolve/extern-prelude-fail.stderr b/src/test/ui/resolve/extern-prelude-fail.stderr index a59f4c952bb..a1591914b4d 100644 --- a/src/test/ui/resolve/extern-prelude-fail.stderr +++ b/src/test/ui/resolve/extern-prelude-fail.stderr @@ -3,12 +3,16 @@ error[E0432]: unresolved import `extern_prelude` | LL | use extern_prelude::S; | ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`? + | + = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate error[E0433]: failed to resolve: maybe a missing crate `extern_prelude`? --> $DIR/extern-prelude-fail.rs:8:15 | LL | let s = ::extern_prelude::S; | ^^^^^^^^^^^^^^ maybe a missing crate `extern_prelude`? + | + = help: consider adding `extern crate extern_prelude` to use the `extern_prelude` crate error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-82865.stderr b/src/test/ui/resolve/issue-82865.stderr index 7898c2a360f..730fd6d6026 100644 --- a/src/test/ui/resolve/issue-82865.stderr +++ b/src/test/ui/resolve/issue-82865.stderr @@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `x`? | LL | use x::y::z; | ^ maybe a missing crate `x`? + | + = help: consider adding `extern crate x` to use the `x` crate error[E0599]: no function or associated item named `z` found for struct `Box<_, _>` in the current scope --> $DIR/issue-82865.rs:8:10 diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr index 197ecf0cb00..2ac41b87562 100644 --- a/src/test/ui/resolve/resolve-bad-visibility.stderr +++ b/src/test/ui/resolve/resolve-bad-visibility.stderr @@ -21,12 +21,16 @@ error[E0433]: failed to resolve: maybe a missing crate `nonexistent`? | LL | pub(in nonexistent) struct G; | ^^^^^^^^^^^ maybe a missing crate `nonexistent`? + | + = help: consider adding `extern crate nonexistent` to use the `nonexistent` crate error[E0433]: failed to resolve: maybe a missing crate `too_soon`? --> $DIR/resolve-bad-visibility.rs:8:8 | LL | pub(in too_soon) struct H; | ^^^^^^^^ maybe a missing crate `too_soon`? + | + = help: consider adding `extern crate too_soon` to use the `too_soon` crate error: aborting due to 5 previous errors diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr index f568aa04295..870f4064de4 100644 --- a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr +++ b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr @@ -3,6 +3,8 @@ error[E0433]: failed to resolve: maybe a missing crate `core`? | LL | use core::simd::intrinsics; | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate error[E0432]: unresolved import `std::simd::intrinsics` --> $DIR/portable-intrinsics-arent-exposed.rs:5:5 diff --git a/src/test/ui/suggestions/enum-method-probe.fixed b/src/test/ui/suggestions/enum-method-probe.fixed new file mode 100644 index 00000000000..6499c92bc6f --- /dev/null +++ b/src/test/ui/suggestions/enum-method-probe.fixed @@ -0,0 +1,59 @@ +// compile-flags: --edition=2021 +// run-rustfix + +#![allow(unused)] + +struct Foo; + +impl Foo { + fn get(&self) -> u8 { + 42 + } +} + +fn test_result_in_result() -> Result<(), ()> { + let res: Result<_, ()> = Ok(Foo); + res?.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP use the `?` operator + Ok(()) +} + +async fn async_test_result_in_result() -> Result<(), ()> { + let res: Result<_, ()> = Ok(Foo); + res?.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP use the `?` operator + Ok(()) +} + +fn test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.expect("REASON").get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +async fn async_test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.expect("REASON").get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +fn test_option_in_option() -> Option<()> { + let res: Option<_> = Some(Foo); + res?.get(); + //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~| HELP use the `?` operator + Some(()) +} + +fn test_option_in_unit_return() { + let res: Option<_> = Some(Foo); + res.expect("REASON").get(); + //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` +} + +fn main() {} diff --git a/src/test/ui/suggestions/enum-method-probe.rs b/src/test/ui/suggestions/enum-method-probe.rs new file mode 100644 index 00000000000..18ea8ed8a58 --- /dev/null +++ b/src/test/ui/suggestions/enum-method-probe.rs @@ -0,0 +1,59 @@ +// compile-flags: --edition=2021 +// run-rustfix + +#![allow(unused)] + +struct Foo; + +impl Foo { + fn get(&self) -> u8 { + 42 + } +} + +fn test_result_in_result() -> Result<(), ()> { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP use the `?` operator + Ok(()) +} + +async fn async_test_result_in_result() -> Result<(), ()> { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP use the `?` operator + Ok(()) +} + +fn test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +async fn async_test_result_in_unit_return() { + let res: Result<_, ()> = Ok(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Result` in the current scope + //~| HELP consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` +} + +fn test_option_in_option() -> Option<()> { + let res: Option<_> = Some(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~| HELP use the `?` operator + Some(()) +} + +fn test_option_in_unit_return() { + let res: Option<_> = Some(Foo); + res.get(); + //~^ ERROR no method named `get` found for enum `Option` in the current scope + //~| HELP consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` +} + +fn main() {} diff --git a/src/test/ui/suggestions/enum-method-probe.stderr b/src/test/ui/suggestions/enum-method-probe.stderr new file mode 100644 index 00000000000..6ed14984f47 --- /dev/null +++ b/src/test/ui/suggestions/enum-method-probe.stderr @@ -0,0 +1,99 @@ +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:24:9 + | +LL | res.get(); + | ^^^ method not found in `Result<Foo, ()>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller + | +LL | res?.get(); + | + + +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:39:9 + | +LL | res.get(); + | ^^^ method not found in `Result<Foo, ()>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` + | +LL | res.expect("REASON").get(); + | +++++++++++++++++ + +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:16:9 + | +LL | res.get(); + | ^^^ method not found in `Result<Foo, ()>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: use the `?` operator to extract the `Foo` value, propagating a `Result::Err` value to the caller + | +LL | res?.get(); + | + + +error[E0599]: no method named `get` found for enum `Result` in the current scope + --> $DIR/enum-method-probe.rs:32:9 + | +LL | res.get(); + | ^^^ method not found in `Result<Foo, ()>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: consider using `Result::expect` to unwrap the `Foo` value, panicking if the value is a `Result::Err` + | +LL | res.expect("REASON").get(); + | +++++++++++++++++ + +error[E0599]: no method named `get` found for enum `Option` in the current scope + --> $DIR/enum-method-probe.rs:46:9 + | +LL | res.get(); + | ^^^ method not found in `Option<Foo>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: use the `?` operator to extract the `Foo` value, propagating an `Option::None` value to the caller + | +LL | res?.get(); + | + + +error[E0599]: no method named `get` found for enum `Option` in the current scope + --> $DIR/enum-method-probe.rs:54:9 + | +LL | res.get(); + | ^^^ method not found in `Option<Foo>` + | +note: the method `get` exists on the type `Foo` + --> $DIR/enum-method-probe.rs:9:5 + | +LL | fn get(&self) -> u8 { + | ^^^^^^^^^^^^^^^^^^^ +help: consider using `Option::expect` to unwrap the `Foo` value, panicking if the value is an `Option::None` + | +LL | res.expect("REASON").get(); + | +++++++++++++++++ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/unresolved/unresolved-asterisk-imports.stderr b/src/test/ui/unresolved/unresolved-asterisk-imports.stderr index a789179db65..8df8eab34a7 100644 --- a/src/test/ui/unresolved/unresolved-asterisk-imports.stderr +++ b/src/test/ui/unresolved/unresolved-asterisk-imports.stderr @@ -3,6 +3,8 @@ error[E0432]: unresolved import `not_existing_crate` | LL | use not_existing_crate::*; | ^^^^^^^^^^^^^^^^^^ maybe a missing crate `not_existing_crate`? + | + = help: consider adding `extern crate not_existing_crate` to use the `not_existing_crate` crate error: aborting due to previous error diff --git a/src/test/ui/unresolved/unresolved-import.rs b/src/test/ui/unresolved/unresolved-import.rs index b65c3dfb90b..4125c593c74 100644 --- a/src/test/ui/unresolved/unresolved-import.rs +++ b/src/test/ui/unresolved/unresolved-import.rs @@ -1,5 +1,6 @@ use foo::bar; //~ ERROR unresolved import `foo` [E0432] //~^ maybe a missing crate `foo`? + //~| HELP consider adding `extern crate foo` to use the `foo` crate use bar::Baz as x; //~ ERROR unresolved import `bar::Baz` [E0432] //~| no `Baz` in `bar` diff --git a/src/test/ui/unresolved/unresolved-import.stderr b/src/test/ui/unresolved/unresolved-import.stderr index d4bfea57809..0dd928c8b6f 100644 --- a/src/test/ui/unresolved/unresolved-import.stderr +++ b/src/test/ui/unresolved/unresolved-import.stderr @@ -3,9 +3,11 @@ error[E0432]: unresolved import `foo` | LL | use foo::bar; | ^^^ maybe a missing crate `foo`? + | + = help: consider adding `extern crate foo` to use the `foo` crate error[E0432]: unresolved import `bar::Baz` - --> $DIR/unresolved-import.rs:4:5 + --> $DIR/unresolved-import.rs:5:5 | LL | use bar::Baz as x; | ^^^^^---^^^^^ @@ -14,7 +16,7 @@ LL | use bar::Baz as x; | no `Baz` in `bar` error[E0432]: unresolved import `food::baz` - --> $DIR/unresolved-import.rs:9:5 + --> $DIR/unresolved-import.rs:10:5 | LL | use food::baz; | ^^^^^^--- @@ -23,7 +25,7 @@ LL | use food::baz; | no `baz` in `food` error[E0432]: unresolved import `food::beens` - --> $DIR/unresolved-import.rs:14:12 + --> $DIR/unresolved-import.rs:15:12 | LL | use food::{beens as Foo}; | -----^^^^^^^ @@ -32,13 +34,13 @@ LL | use food::{beens as Foo}; | help: a similar name exists in the module: `beans` error[E0432]: unresolved import `MyEnum` - --> $DIR/unresolved-import.rs:38:9 + --> $DIR/unresolved-import.rs:39:9 | LL | use MyEnum::*; | ^^^^^^ help: a similar path exists: `self::MyEnum` error[E0432]: unresolved import `Enum` - --> $DIR/unresolved-import.rs:48:9 + --> $DIR/unresolved-import.rs:49:9 | LL | use Enum::*; | ^^^^ help: a similar path exists: `self::Enum` diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 39ad1039d9e3e1746177bf5d134af4c164f9552 +Subproject 38472bc19f2f76e245eba54a6e97ee6821b3c1d diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 283b20fc24d..b1c82ac76e8 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -125,7 +125,7 @@ fn check_rvalue<'tcx>( Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => { check_place(tcx, *place, span, body) }, - Rvalue::Cast(CastKind::PointerAddress, _, _) => { + Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => { Err((span, "casting pointers to ints is unstable in const fn".into())) }, Rvalue::Cast(CastKind::Misc, operand, _) => { diff --git a/src/tools/miri b/src/tools/miri -Subproject 065ff89e33b67b3527fcdd56cf8b432e593e32d +Subproject 749efd29565a9b8f47afb441aaacfcc10bc145d |