diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1ca0715606181..c85d6f454321e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1415,6 +1415,9 @@ impl<'a> State<'a> { } fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { + if let ast::Parens::Yes = t.parens { + self.popen(); + } self.print_formal_generic_params(&t.bound_generic_params); let ast::TraitBoundModifiers { constness, asyncness, polarity } = t.modifiers; @@ -1437,7 +1440,10 @@ impl<'a> State<'a> { } } - self.print_trait_ref(&t.trait_ref) + self.print_trait_ref(&t.trait_ref); + if let ast::Parens::Yes = t.parens { + self.pclose(); + } } fn print_stmt(&mut self, st: &ast::Stmt) { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index f0fc2a5b5e939..f8ccc8594e333 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,4 +1,4 @@ -use rustc_abi::Align; +use rustc_abi::{Align, Size}; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_hir::attrs::{IntType, ReprAttr}; @@ -229,7 +229,7 @@ fn parse_repr_align( return None; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => Some(match align_kind { AlignKind::Packed => ReprAttr::ReprPacked(literal), AlignKind::Align => ReprAttr::ReprAlign(literal), @@ -248,23 +248,35 @@ fn parse_repr_align( } } -fn parse_alignment(node: &LitKind) -> Result { - if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { - // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first - if literal.get().is_power_of_two() { - // Only possible error is larger than 2^29 - literal - .get() - .try_into() - .ok() - .and_then(|v| Align::from_bytes(v).ok()) - .ok_or("larger than 2^29") - } else { - Err("not a power of two") - } - } else { - Err("not an unsuffixed integer") +fn parse_alignment( + node: &LitKind, + cx: &AcceptContext<'_, '_, S>, +) -> Result { + let LitKind::Int(literal, LitIntType::Unsuffixed) = node else { + return Err("not an unsuffixed integer".to_string()); + }; + + // `Align::from_bytes` accepts 0 as a valid input, + // so we check if its a power of two first + if !literal.get().is_power_of_two() { + return Err("not a power of two".to_string()); + } + // lit must be < 2^29 + let align = literal + .get() + .try_into() + .ok() + .and_then(|a| Align::from_bytes(a).ok()) + .ok_or("larger than 2^29".to_string())?; + + // alignment must not be larger than the pointer width (`isize::MAX`) + let max = Size::from_bits(cx.sess.target.pointer_width).signed_int_max() as u64; + if align.bytes() > max { + return Err(format!( + "alignment larger than `isize::MAX` bytes ({max} for the current target)" + )); } + Ok(align) } /// Parse #[align(N)]. @@ -294,7 +306,7 @@ impl RustcAlignParser { return; }; - match parse_alignment(&lit.kind) { + match parse_alignment(&lit.kind, cx) { Ok(literal) => self.0 = Ord::max(self.0, Some((literal, cx.attr_span))), Err(message) => { cx.emit_err(session_diagnostics::InvalidAlignmentValue { diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 987c0cb04c84d..7c2044ec235a7 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -227,12 +227,12 @@ pub(crate) struct InvalidReprAlignNeedArg { #[derive(Diagnostic)] #[diag("invalid `repr({$repr_arg})` attribute: {$error_part}", code = E0589)] -pub(crate) struct InvalidReprGeneric<'a> { +pub(crate) struct InvalidReprGeneric { #[primary_span] pub span: Span, pub repr_arg: String, - pub error_part: &'a str, + pub error_part: String, } #[derive(Diagnostic)] @@ -479,7 +479,7 @@ pub(crate) struct InvalidTarget { pub(crate) struct InvalidAlignmentValue { #[primary_span] pub span: Span, - pub error_part: &'static str, + pub error_part: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 738e3330254b7..cbc05acef5647 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -8,7 +8,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::move_paths::{LookupResult, MovePathIndex}; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, ExpnKind, MacroKind, Span}; +use rustc_span::{BytePos, ExpnKind, MacroKind, Span, sym}; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; @@ -700,14 +700,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { binds_to.sort(); binds_to.dedup(); - self.add_move_error_details(err, &binds_to); + self.add_move_error_details(err, &binds_to, &[]); } } GroupedMoveError::MovesFromValue { mut binds_to, .. } => { binds_to.sort(); binds_to.dedup(); - self.add_move_error_suggestions(err, &binds_to); - self.add_move_error_details(err, &binds_to); + let desugar_spans = self.add_move_error_suggestions(err, &binds_to); + self.add_move_error_details(err, &binds_to, &desugar_spans); } // No binding. Nothing to suggest. GroupedMoveError::OtherIllegalMove { ref original_path, use_spans, .. } => { @@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) { + fn add_move_error_suggestions(&self, err: &mut Diag<'_>, binds_to: &[Local]) -> Vec { /// A HIR visitor to associate each binding with a `&` or `&mut` that could be removed to /// make it bind by reference instead (if possible) struct BindingFinder<'tcx> { @@ -843,6 +843,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ref_pat_for_binding: Vec<(Span, Option<&'tcx hir::Pat<'tcx>>)>, /// Output: ref patterns that can't be removed straightforwardly cannot_remove: FxHashSet, + /// Output: binding spans from destructuring assignment desugaring + desugar_binding_spans: Vec, } impl<'tcx> Visitor<'tcx> for BindingFinder<'tcx> { type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; @@ -883,16 +885,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } if let hir::PatKind::Binding(_, _, ident, _) = p.kind { - // the spans in `binding_spans` encompass both the ident and binding mode - if let Some(&bind_sp) = - self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) - { - self.ref_pat_for_binding.push((bind_sp, self.ref_pat)); + // Skip synthetic bindings from destructuring assignment desugaring + // These have name `lhs` and their parent is a `LetStmt` with + // `LocalSource::AssignDesugar` + let dominated_by_desugar_assign = ident.name == sym::lhs + && self.tcx.hir_parent_iter(p.hir_id).any(|(_, node)| { + matches!( + node, + hir::Node::LetStmt(&hir::LetStmt { + source: hir::LocalSource::AssignDesugar, + .. + }) + ) + }); + + if dominated_by_desugar_assign { + if let Some(&bind_sp) = + self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) + { + self.desugar_binding_spans.push(bind_sp); + } } else { - // we've encountered a binding that we're not reporting a move error for. - // we don't want to change its type, so don't remove the surrounding `&`. - if let Some(ref_pat) = self.ref_pat { - self.cannot_remove.insert(ref_pat.hir_id); + // the spans in `binding_spans` encompass both the ident and binding mode + if let Some(&bind_sp) = + self.binding_spans.iter().find(|bind_sp| bind_sp.contains(ident.span)) + { + self.ref_pat_for_binding.push((bind_sp, self.ref_pat)); + } else { + // we've encountered a binding that we're not reporting a move error for. + // we don't want to change its type, so don't remove the surrounding `&`. + if let Some(ref_pat) = self.ref_pat { + self.cannot_remove.insert(ref_pat.hir_id); + } } } } @@ -913,10 +937,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { binding_spans.push(bind_to.source_info.span); } } - let Some(pat_span) = pat_span else { return }; + let Some(pat_span) = pat_span else { return Vec::new() }; let tcx = self.infcx.tcx; - let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return }; + let Some(body) = tcx.hir_maybe_body_owned_by(self.mir_def_id()) else { return Vec::new() }; let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); let mut finder = BindingFinder { typeck_results, @@ -928,6 +952,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { has_adjustments: false, ref_pat_for_binding: Vec::new(), cannot_remove: FxHashSet::default(), + desugar_binding_spans: Vec::new(), }; finder.visit_body(body); @@ -952,9 +977,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { for (span, msg, suggestion) in suggestions { err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable); } + finder.desugar_binding_spans } - fn add_move_error_details(&self, err: &mut Diag<'_>, binds_to: &[Local]) { + fn add_move_error_details( + &self, + err: &mut Diag<'_>, + binds_to: &[Local], + desugar_spans: &[Span], + ) { for (j, local) in binds_to.iter().enumerate() { let bind_to = &self.body.local_decls[*local]; let binding_span = bind_to.source_info.span; @@ -968,7 +999,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if binds_to.len() == 1 { let place_desc = self.local_name(*local).map(|sym| format!("`{sym}`")); - if let Some(expr) = self.find_expr(binding_span) { + if !desugar_spans.contains(&binding_span) + && let Some(expr) = self.find_expr(binding_span) + { + // The binding_span doesn't correspond to a let binding desugaring + // and is an expression where calling `.clone()` would be valid. let local_place: PlaceRef<'tcx> = (*local).into(); self.suggest_cloning(err, local_place, bind_to.ty, expr, None); } diff --git a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch index 6a0244cfde3fb..340f6cc9b0e7c 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-sysroot_tests-disable-f16-math.patch @@ -19,7 +19,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1557,7 +1557,7 @@ fn s_nan() -> Float { name: exp, attrs: { @@ -28,7 +28,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1578,7 +1578,7 @@ fn s_nan() -> Float { name: exp2, attrs: { @@ -37,7 +37,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1598,7 +1598,7 @@ fn s_nan() -> Float { name: ln, attrs: { @@ -46,7 +46,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1620,7 +1620,7 @@ fn s_nan() -> Float { name: log, attrs: { @@ -55,7 +55,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1645,7 +1645,7 @@ fn s_nan() -> Float { name: log2, attrs: { @@ -64,7 +64,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1668,7 +1668,7 @@ fn s_nan() -> Float { name: log10, attrs: { @@ -73,7 +73,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1692,7 +1692,7 @@ fn s_nan() -> Float { name: asinh, attrs: { @@ -82,7 +82,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1725,7 +1725,7 @@ fn s_nan() -> Float { name: acosh, attrs: { @@ -91,7 +91,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1753,7 +1753,7 @@ fn s_nan() -> Float { name: atanh, attrs: { @@ -100,7 +100,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1779,7 +1779,7 @@ fn s_nan() -> Float { name: gamma, attrs: { @@ -109,7 +109,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -1814,7 +1814,7 @@ fn s_nan() -> Float { name: ln_gamma, attrs: { @@ -118,7 +118,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { @@ -2027,7 +2027,7 @@ fn s_nan() -> Float { attrs: { // FIXME(f16_f128): add math tests when available @@ -127,7 +127,7 @@ index c61961f8584..d7b4fa20322 100644 + f16: #[cfg(false)], // FIXME(rust-lang/rustc_codegen_cranelift#1622) f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { -- 2.50.1 diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 1ceb01337b118..b8a8bb3ad419d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -5,6 +5,7 @@ use rustc_hir::attrs::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{self as hir, Attribute, find_attr}; +use rustc_macros::Diagnostic; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs, }; @@ -385,6 +386,17 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code } } +#[derive(Diagnostic)] +#[diag("non-default `sanitize` will have no effect after inlining")] +struct SanitizeOnInline { + #[note("inlining requested here")] + inline_span: Span, +} + +#[derive(Diagnostic)] +#[diag("the async executor can run blocking code, without realtime sanitizer catching it")] +struct AsyncBlocking; + fn check_result( tcx: TyCtxt<'_>, did: LocalDefId, @@ -425,10 +437,12 @@ fn check_result( (interesting_spans.sanitize, interesting_spans.inline) { let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, sanitize_span, |lint| { - lint.primary_message("non-default `sanitize` will have no effect after inlining"); - lint.span_note(inline_span, "inlining requested here"); - }) + tcx.emit_node_span_lint( + lint::builtin::INLINE_NO_SANITIZE, + hir_id, + sanitize_span, + SanitizeOnInline { inline_span }, + ) } // warn for nonblocking async functions, blocks and closures. @@ -445,13 +459,11 @@ fn check_result( != rustc_hir::ClosureKind::Closure)) { let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::RTSAN_NONBLOCKING_ASYNC, hir_id, sanitize_span, - |lint| { - lint.primary_message(r#"the async executor can run blocking code, without realtime sanitizer catching it"#); - } + AsyncBlocking, ); } diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index b771addb8df55..4323debd80149 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -413,7 +413,7 @@ fn valtree_into_mplace<'tcx>( Some(variant_idx), ) } - _ => (place.clone(), branches, None), + _ => (place.clone(), branches.as_slice(), None), }; debug!(?place_adjusted, ?branches); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index cfc697b521fc5..a093fede8c198 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -106,6 +106,7 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError { pub trait Diagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> { /// Write out as a diagnostic out of `DiagCtxt`. #[must_use] + #[track_caller] fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G>; } @@ -139,7 +140,7 @@ where } #[derive(Clone, Debug, Encodable, Decodable)] -pub(crate) struct DiagLocation { +pub struct DiagLocation { file: Cow<'static, str>, line: u32, col: u32, @@ -147,7 +148,7 @@ pub(crate) struct DiagLocation { impl DiagLocation { #[track_caller] - fn caller() -> Self { + pub fn caller() -> Self { let loc = panic::Location::caller(); DiagLocation { file: loc.file().into(), line: loc.line(), col: loc.column() } } @@ -248,7 +249,7 @@ pub struct DiagInner { pub long_ty_path: Option, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. - pub(crate) emitted_at: DiagLocation, + pub emitted_at: DiagLocation, } impl DiagInner { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 7fc3e4a45d0ab..c881339564570 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -37,8 +37,8 @@ pub use anstyle::{ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ - BugAbort, Diag, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, FatalAbort, - StringPart, Subdiag, Subdiagnostic, + BugAbort, Diag, DiagInner, DiagLocation, DiagStyledString, Diagnostic, EmissionGuarantee, + FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 94988f3c92750..f3d234afef05e 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -4,7 +4,7 @@ use std::ops::ControlFlow; use rustc_abi::{ExternAbi, FieldIdx, ScalableElt}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; -use rustc_errors::{EmissionGuarantee, MultiSpan}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan}; use rustc_hir as hir; use rustc_hir::attrs::ReprAttr::ReprPacked; use rustc_hir::def::{CtorKind, DefKind}; @@ -12,6 +12,7 @@ use rustc_hir::{LangItem, Node, find_attr, intravisit}; use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc}; use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS}; +use rustc_macros::Diagnostic; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; @@ -53,6 +54,22 @@ fn add_abi_diag_help(abi: ExternAbi, diag: &mut Diag<'_, T } pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { + struct UnsupportedCallingConventions { + abi: ExternAbi, + } + + impl<'a> Diagnostic<'a, ()> for UnsupportedCallingConventions { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { abi } = self; + let mut lint = Diag::new( + dcx, + level, + format!("{abi} is not a supported ABI for the current target"), + ); + add_abi_diag_help(abi, &mut lint); + lint + } + } // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this // currently only guards function imports, function definitions, and function pointer types. // Functions in trait declarations can still use "deprecated" ABIs without any warning. @@ -64,12 +81,12 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering")); } AbiMapping::Deprecated(..) => { - tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.primary_message(format!( - "{abi} is not a supported ABI for the current target" - )); - add_abi_diag_help(abi, lint); - }); + tcx.emit_node_span_lint( + UNSUPPORTED_CALLING_CONVENTIONS, + hir_id, + span, + UnsupportedCallingConventions { abi }, + ); } } } @@ -174,6 +191,11 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b /// Check that a `static` is inhabited. fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { + #[derive(Diagnostic)] + #[diag("static of uninhabited type")] + #[note("uninhabited statics cannot be initialized, and any access would be an immediate error")] + struct StaticOfUninhabitedType; + // Make sure statics are inhabited. // Other parts of the compiler assume that there are no uninhabited places. In principle it // would be enough to check this for `extern` statics, as statics with an initializer will @@ -204,15 +226,11 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { } }; if layout.is_uninhabited() { - tcx.node_span_lint( + tcx.emit_node_span_lint( UNINHABITED_STATIC, tcx.local_def_id_to_hir_id(def_id), span, - |lint| { - lint.primary_message("static of uninhabited type"); - lint - .note("uninhabited statics cannot be initialized, and any access would be an immediate error"); - }, + StaticOfUninhabitedType, ); } } @@ -1637,6 +1655,39 @@ pub(super) fn check_packed_inner( } pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) { + struct ZeroSizedFieldReprTransparentIncompatibility<'tcx> { + unsuited: UnsuitedInfo<'tcx>, + } + + impl<'a, 'tcx> Diagnostic<'a, ()> for ZeroSizedFieldReprTransparentIncompatibility<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { unsuited } = self; + let (title, note) = match unsuited.reason { + UnsuitedReason::NonExhaustive => ( + "external non-exhaustive types", + "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.", + ), + UnsuitedReason::PrivateField => ( + "external types with private fields", + "contains private fields, so it could become non-zero-sized in the future.", + ), + UnsuitedReason::ReprC => ( + "`repr(C)` types", + "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", + ), + }; + Diag::new( + dcx, + level, + format!("zero-sized fields in `repr(transparent)` cannot contain {title}"), + ) + .with_note(format!( + "this field contains `{field_ty}`, which {note}", + field_ty = unsuited.ty, + )) + } + } + if !adt.repr().transparent() { return; } @@ -1747,29 +1798,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts. // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst. if non_trivial_count > 0 || prev_unsuited_1zst { - tcx.node_span_lint( + tcx.emit_node_span_lint( REPR_TRANSPARENT_NON_ZST_FIELDS, tcx.local_def_id_to_hir_id(adt.did().expect_local()), field.span, - |lint| { - let title = match unsuited.reason { - UnsuitedReason::NonExhaustive => "external non-exhaustive types", - UnsuitedReason::PrivateField => "external types with private fields", - UnsuitedReason::ReprC => "`repr(C)` types", - }; - lint.primary_message( - format!("zero-sized fields in `repr(transparent)` cannot contain {title}"), - ); - let note = match unsuited.reason { - UnsuitedReason::NonExhaustive => "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.", - UnsuitedReason::PrivateField => "contains private fields, so it could become non-zero-sized in the future.", - UnsuitedReason::ReprC => "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.", - }; - lint.note(format!( - "this field contains `{field_ty}`, which {note}", - field_ty = unsuited.ty, - )); - }, + ZeroSizedFieldReprTransparentIncompatibility { unsuited }, ); } else { prev_unsuited_1zst = true; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 61e6133306066..458bb6ddd2117 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -77,7 +77,7 @@ use std::num::NonZero; pub use check::{check_abi, check_custom_abi}; use rustc_abi::VariantIdx; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; +use rustc_errors::{ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 3fb33c741c9dc..7302913cc1ae7 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -1,10 +1,28 @@ use rustc_data_structures::unord::{ExtendUnord, UnordSet}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::ty::TyCtxt; use rustc_session::lint; +use rustc_span::Span; use tracing::debug; +struct UnusedImport<'tcx> { + tcx: TyCtxt<'tcx>, + span: Span, +} + +impl<'a, 'tcx> Diagnostic<'a, ()> for UnusedImport<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { tcx, span } = self; + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + Diag::new(dcx, level, format!("unused import: `{snippet}`")) + } else { + Diag::new(dcx, level, "unused import") + } + } +} + pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { let mut used_trait_imports = UnordSet::::default(); @@ -31,12 +49,11 @@ pub(super) fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { continue; } let (path, _) = item.expect_use(); - tcx.node_span_lint(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { - lint.primary_message(format!("unused import: `{snippet}`")); - } else { - lint.primary_message("unused import"); - } - }); + tcx.emit_node_span_lint( + lint::builtin::UNUSED_IMPORTS, + item.hir_id(), + path.span, + UnusedImport { tcx, span: path.span }, + ); } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f4c7234cd8f83..6850e67aff1a7 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -22,7 +22,9 @@ use rustc_abi::{ExternAbi, Size}; use rustc_ast::Recovered; use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, E0228, ErrorGuaranteed, StashKey}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, E0228, ErrorGuaranteed, Level, StashKey, +}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; @@ -610,6 +612,19 @@ pub(super) fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { } pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) { + struct ReprCIssue { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for ReprCIssue { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + .with_note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C") + .with_help("use `repr($int_ty)` instead to explicitly set the size of this enum") + } + } + let def = tcx.adt_def(def_id); let repr_type = def.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); @@ -659,15 +674,11 @@ pub(super) fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: LocalDefId) { } else { "`repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int`" }; - tcx.node_span_lint( + tcx.emit_node_span_lint( rustc_session::lint::builtin::REPR_C_ENUMS_LARGER_THAN_INT, tcx.local_def_id_to_hir_id(def_id), span, - |d| { - d.primary_message(msg) - .note("`repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C") - .help("use `repr($int_ty)` instead to explicitly set the size of this enum"); - } + ReprCIssue { msg }, ); } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index b4c264c3a2364..e1ec57aea9217 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -1,6 +1,7 @@ use std::ops::ControlFlow; use rustc_data_structures::assert_matches; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor, VisitorExt}; @@ -17,6 +18,17 @@ use crate::middle::resolve_bound_vars as rbv; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; + struct GenericParametersForbiddenHere { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for GenericParametersForbiddenHere { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + } + } + // For an RPITIT, synthesize generics which are equal to the opaque's generics // and parent fn's generics compressed into one list. if let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = @@ -269,13 +281,11 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { match param_default_policy.expect("no policy for generic param default") { ParamDefaultPolicy::Allowed => {} ParamDefaultPolicy::FutureCompatForbidden => { - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, - |lint| { - lint.primary_message(MESSAGE); - }, + GenericParametersForbiddenHere { msg: MESSAGE }, ); } ParamDefaultPolicy::Forbidden => { diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 777610402893b..c3d8865817830 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -438,6 +438,11 @@ fn const_evaluatable_predicates_of<'tcx>( return; } + // Skip type consts as mGCA doesn't support evaluatable clauses. + if self.tcx.is_type_const(uv.def) { + return; + } + let span = self.tcx.def_span(uv.def); self.preds.insert((ty::ClauseKind::ConstEvaluatable(c).upcast(self.tcx), span)); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 7b8e09943df71..8397ff61a3b3c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -2,11 +2,12 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, StashKey, + Suggestions, struct_span_code_err, }; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::{self as hir, HirId, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ @@ -523,6 +524,30 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_id: hir::HirId, hir_bounds: &[hir::PolyTraitRef<'tcx>], ) -> Option { + struct TraitObjectWithoutDyn<'a, 'tcx> { + span: Span, + hir_id: HirId, + sugg: Vec<(Span, String)>, + this: &'a dyn HirTyLowerer<'tcx>, + } + + impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for TraitObjectWithoutDyn<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { span, hir_id, sugg, this } = self; + let mut lint = + Diag::new(dcx, level, "trait objects without an explicit `dyn` are deprecated"); + if span.can_be_used_for_suggestions() { + lint.multipart_suggestion( + "if this is a dyn-compatible trait, use `dyn`", + sugg, + Applicability::MachineApplicable, + ); + } + this.maybe_suggest_blanket_trait_impl(span, hir_id, &mut lint); + lint + } + } + let tcx = self.tcx(); let [poly_trait_ref, ..] = hir_bounds else { return None }; @@ -606,17 +631,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } Some(diag.emit()) } else { - tcx.node_span_lint(BARE_TRAIT_OBJECTS, hir_id, span, |lint| { - lint.primary_message("trait objects without an explicit `dyn` are deprecated"); - if span.can_be_used_for_suggestions() { - lint.multipart_suggestion( - "if this is a dyn-compatible trait, use `dyn`", - sugg, - Applicability::MachineApplicable, - ); - } - self.maybe_suggest_blanket_trait_impl(span, hir_id, lint); - }); + tcx.emit_node_span_lint( + BARE_TRAIT_OBJECTS, + hir_id, + span, + TraitObjectWithoutDyn { span, hir_id, sugg, this: self }, + ); None } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index ff0a5a8df0faf..0ca57cb50cf25 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -1,6 +1,9 @@ use rustc_ast::ast::ParamKindOrd; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, struct_span_code_err}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, + struct_span_code_err, +}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, GenericArg}; @@ -625,6 +628,17 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( args: &hir::GenericArgs<'_>, position: GenericArgPosition, ) -> ExplicitLateBound { + struct LifetimeArgsIssue { + msg: &'static str, + } + + impl<'a> Diagnostic<'a, ()> for LifetimeArgsIssue { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { msg } = self; + Diag::new(dcx, level, msg) + } + } + let param_counts = def.own_counts(); if let Some(span_late) = def.has_late_bound_regions @@ -644,13 +658,11 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes( } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note); - cx.tcx().node_span_lint( + cx.tcx().emit_node_span_lint( LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, - |lint| { - lint.primary_message(msg); - }, + LifetimeArgsIssue { msg }, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 25911d3e9e462..3a41ef47ac526 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -27,7 +27,8 @@ use rustc_data_structures::assert_matches; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, FatalError, Level, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -1481,6 +1482,54 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, mode: LowerTypeRelativePathMode, ) -> Result, ErrorGuaranteed> { + struct AmbiguousAssocItem<'tcx> { + variant_def_id: DefId, + item_def_id: DefId, + span: Span, + segment_ident: Ident, + bound_def_id: DefId, + self_ty: Ty<'tcx>, + tcx: TyCtxt<'tcx>, + mode: LowerTypeRelativePathMode, + } + + impl<'a, 'tcx> Diagnostic<'a, ()> for AmbiguousAssocItem<'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { + variant_def_id, + item_def_id, + span, + segment_ident, + bound_def_id, + self_ty, + tcx, + mode, + } = self; + let mut lint = Diag::new(dcx, level, "ambiguous associated item"); + + let mut could_refer_to = |kind: DefKind, def_id, also| { + let note_msg = format!( + "`{}` could{} refer to the {} defined here", + segment_ident, + also, + tcx.def_kind_descr(kind, def_id) + ); + lint.span_note(tcx.def_span(def_id), note_msg); + }; + + could_refer_to(DefKind::Variant, variant_def_id, ""); + could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also"); + + lint.span_suggestion( + span, + "use fully-qualified syntax", + format!("<{} as {}>::{}", self_ty, tcx.item_name(bound_def_id), segment_ident), + Applicability::MachineApplicable, + ); + lint + } + } + debug!(%self_ty, ?segment.ident); let tcx = self.tcx(); @@ -1556,33 +1605,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let (item_def_id, args) = self.lower_assoc_item_path(span, item_def_id, segment, bound)?; if let Some(variant_def_id) = variant_def_id { - tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, qpath_hir_id, span, |lint| { - lint.primary_message("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - segment.ident, - also, - tcx.def_kind_descr(kind, def_id) - ); - lint.span_note(tcx.def_span(def_id), note_msg); - }; - - could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(mode.def_kind_for_diagnostics(), item_def_id, " also"); - - lint.span_suggestion( + tcx.emit_node_span_lint( + AMBIGUOUS_ASSOCIATED_ITEMS, + qpath_hir_id, + span, + AmbiguousAssocItem { + variant_def_id, + item_def_id, span, - "use fully-qualified syntax", - format!( - "<{} as {}>::{}", - self_ty, - tcx.item_name(bound.def_id()), - segment.ident - ), - Applicability::MachineApplicable, - ); - }); + segment_ident: segment.ident, + bound_def_id: bound.def_id(), + self_ty, + tcx, + mode, + }, + ); } Ok(TypeRelativePath::AssocItem(item_def_id, args)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index d2152b763a8e2..c24d1127d5a62 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -3,7 +3,9 @@ use std::slice; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{ + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, +}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; @@ -80,6 +82,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. pub(crate) fn warn_if_unreachable(&self, id: HirId, span: Span, kind: &str) { + struct UnreachableItem<'a, 'b> { + kind: &'a str, + span: Span, + orig_span: Span, + custom_note: Option<&'b str>, + } + + impl<'a, 'b, 'c> Diagnostic<'a, ()> for UnreachableItem<'b, 'c> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { kind, span, orig_span, custom_note } = self; + let msg = format!("unreachable {kind}"); + Diag::new(dcx, level, msg.clone()).with_span_label(span, msg).with_span_label( + orig_span, + custom_note.map(|c| c.to_owned()).unwrap_or_else(|| { + "any code following this expression is unreachable".to_owned() + }), + ) + } + } + let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() else { return; }; @@ -102,14 +124,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - let msg = format!("unreachable {kind}"); - self.tcx().node_span_lint(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - lint.primary_message(msg.clone()); - lint.span_label(span, msg).span_label( - orig_span, - custom_note.unwrap_or("any code following this expression is unreachable"), - ); - }) + self.tcx().emit_node_span_lint( + lint::builtin::UNREACHABLE_CODE, + id, + span, + UnreachableItem { kind, span, orig_span, custom_note }, + ); } /// Resolves type and const variables in `t` if possible. Unlike the infcx diff --git a/compiler/rustc_hir_typeck/src/inline_asm.rs b/compiler/rustc_hir_typeck/src/inline_asm.rs index 7c1655f8201d7..f2b746ac96b10 100644 --- a/compiler/rustc_hir_typeck/src/inline_asm.rs +++ b/compiler/rustc_hir_typeck/src/inline_asm.rs @@ -1,6 +1,7 @@ use rustc_abi::FieldIdx; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_middle::bug; @@ -168,6 +169,40 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { is_input: bool, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option)>, ) -> Option { + struct FormattingSubRegisterArg<'a> { + expr_span: Span, + idx: usize, + suggested_modifier: char, + suggested_result: &'a str, + suggested_size: u16, + default_modifier: char, + default_result: &'a str, + default_size: u16, + } + + impl<'a, 'b> Diagnostic<'a, ()> for FormattingSubRegisterArg<'b> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { + expr_span, + idx, + suggested_modifier, + suggested_result, + suggested_size, + default_modifier, + default_result, + default_size, + } = self; + Diag::new(dcx, level, "formatting may not be suitable for sub-register argument") + .with_span_label(expr_span, "for this argument") + .with_help(format!( + "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", + )) + .with_help(format!( + "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", + )) + } + } + let ty = self.expr_ty(expr); if ty.has_non_region_infer() { bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); @@ -362,19 +397,19 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { result: default_result, size: default_size, } = reg_class.default_modifier(asm_arch).unwrap(); - self.tcx().node_span_lint( + self.tcx().emit_node_span_lint( lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, - |lint| { - lint.primary_message("formatting may not be suitable for sub-register argument"); - lint.span_label(expr.span, "for this argument"); - lint.help(format!( - "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}` (for {suggested_size}-bit values)", - )); - lint.help(format!( - "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}` (for {default_size}-bit values)", - )); + FormattingSubRegisterArg { + expr_span: expr.span, + idx, + suggested_modifier, + suggested_result, + suggested_size, + default_modifier, + default_result, + default_size, }, ); } diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 38413cca633c9..d846f4433dc70 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -3,19 +3,157 @@ use std::fmt::Write; use hir::def_id::DefId; use hir::{HirId, ItemKind}; use rustc_ast::join_path_idents; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir as hir; use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER}; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::{RUST_2021_PRELUDE_COLLISIONS, RUST_2024_PRELUDE_COLLISIONS}; -use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, kw, sym}; +use rustc_span::{Ident, STDLIB_STABLE_CRATES, Span, Symbol, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use tracing::debug; use crate::FnCtxt; use crate::method::probe::{self, Pick}; +struct AmbiguousTraitMethodCall<'a, 'b, 'tcx> { + segment_name: Symbol, + self_expr_span: Span, + pick: &'a Pick<'tcx>, + tcx: TyCtxt<'tcx>, + edition: &'b str, +} + +impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitMethodCall<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { segment_name, self_expr_span, pick, tcx, edition } = self; + let mut lint = Diag::new( + dcx, + level, + format!("trait method `{}` will become ambiguous in Rust {edition}", segment_name), + ); + let derefs = "*".repeat(pick.autoderefs); + + let autoref = match pick.autoref_or_ptr_adjustment { + Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => mutbl.ref_prefix_str(), + Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", + Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { + hir::Mutability::Mut => "Pin<&mut ", + hir::Mutability::Not => "Pin<&", + }, + }; + if let Ok(self_expr) = tcx.sess.source_map().span_to_snippet(self_expr_span) { + let mut self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}{self_expr} as *const _") + } else { + format!("{autoref}{derefs}{self_expr}") + }; + + if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = + pick.autoref_or_ptr_adjustment + { + self_adjusted.push('>'); + } + + lint.span_suggestion( + self_expr_span, + "disambiguate the method call", + format!("({self_adjusted})"), + Applicability::MachineApplicable, + ); + } else { + let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = + pick.autoref_or_ptr_adjustment + { + format!("{derefs}(...) as *const _") + } else { + format!("{autoref}{derefs}...") + }; + lint.span_help( + self_expr_span, + format!("disambiguate the method call with `({self_adjusted})`",), + ); + } + lint + } +} + +struct AmbiguousTraitMethod<'a, 'b, 'tcx, 'pcx, 'fnctx> { + segment: &'a hir::PathSegment<'pcx>, + call_expr: &'tcx hir::Expr<'tcx>, + self_expr: &'tcx hir::Expr<'tcx>, + pick: &'a Pick<'tcx>, + args: &'tcx [hir::Expr<'tcx>], + edition: &'b str, + span: Span, + this: &'a FnCtxt<'fnctx, 'tcx>, +} + +impl<'a, 'b, 'c, 'tcx, 'pcx, 'fnctx> Diagnostic<'a, ()> + for AmbiguousTraitMethod<'b, 'c, 'tcx, 'pcx, 'fnctx> +{ + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { segment, call_expr, self_expr, pick, args, edition, span, this } = self; + let mut lint = Diag::new( + dcx, + level, + format!( + "trait method `{}` will become ambiguous in Rust {edition}", + segment.ident.name + ), + ); + + let sp = call_expr.span; + let trait_name = + this.trait_path_or_bare_name(span, call_expr.hir_id, pick.item.container_id(this.tcx)); + + let (self_adjusted, precise) = this.adjust_expr(pick, self_expr, sp); + if precise { + let args = args.iter().fold(String::new(), |mut string, arg| { + let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); + write!(string, ", {}", this.sess().source_map().span_to_snippet(span).unwrap()) + .unwrap(); + string + }); + + lint.span_suggestion( + sp, + "disambiguate the associated function", + format!( + "{}::{}{}({}{})", + trait_name, + segment.ident.name, + if let Some(args) = segment.args.as_ref().and_then(|args| this + .sess() + .source_map() + .span_to_snippet(args.span_ext) + .ok()) + { + // Keep turbofish. + format!("::{args}") + } else { + String::new() + }, + self_adjusted, + args, + ), + Applicability::MachineApplicable, + ); + } else { + lint.span_help( + sp, + format!( + "disambiguate the associated function with `{}::{}(...)`", + trait_name, segment.ident, + ), + ); + } + lint + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(super) fn lint_edition_dependent_dot_call( &self, @@ -101,133 +239,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Inherent impls only require not relying on autoref and autoderef in order to // ensure that the trait implementation won't be used - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( prelude_or_array_lint, self_expr.hir_id, self_expr.span, - |lint| { - lint.primary_message(format!( - "trait method `{}` will become ambiguous in Rust {edition}", - segment.ident.name - )); - - let sp = self_expr.span; - - let derefs = "*".repeat(pick.autoderefs); - - let autoref = match pick.autoref_or_ptr_adjustment { - Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, .. }) => { - mutbl.ref_prefix_str() - } - Some(probe::AutorefOrPtrAdjustment::ToConstPtr) | None => "", - Some(probe::AutorefOrPtrAdjustment::ReborrowPin(mutbl)) => match mutbl { - hir::Mutability::Mut => "Pin<&mut ", - hir::Mutability::Not => "Pin<&", - }, - }; - if let Ok(self_expr) = self.sess().source_map().span_to_snippet(self_expr.span) - { - let mut self_adjusted = - if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = - pick.autoref_or_ptr_adjustment - { - format!("{derefs}{self_expr} as *const _") - } else { - format!("{autoref}{derefs}{self_expr}") - }; - - if let Some(probe::AutorefOrPtrAdjustment::ReborrowPin(_)) = - pick.autoref_or_ptr_adjustment - { - self_adjusted.push('>'); - } - - lint.span_suggestion( - sp, - "disambiguate the method call", - format!("({self_adjusted})"), - Applicability::MachineApplicable, - ); - } else { - let self_adjusted = if let Some(probe::AutorefOrPtrAdjustment::ToConstPtr) = - pick.autoref_or_ptr_adjustment - { - format!("{derefs}(...) as *const _") - } else { - format!("{autoref}{derefs}...") - }; - lint.span_help( - sp, - format!("disambiguate the method call with `({self_adjusted})`",), - ); - } + AmbiguousTraitMethodCall { + segment_name: segment.ident.name, + self_expr_span: self_expr.span, + pick, + tcx: self.tcx, + edition, }, ); } else { // trait implementations require full disambiguation to not clash with the new prelude // additions (i.e. convert from dot-call to fully-qualified call) - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( prelude_or_array_lint, call_expr.hir_id, call_expr.span, - |lint| { - lint.primary_message(format!( - "trait method `{}` will become ambiguous in Rust {edition}", - segment.ident.name - )); - - let sp = call_expr.span; - let trait_name = self.trait_path_or_bare_name( - span, - call_expr.hir_id, - pick.item.container_id(self.tcx), - ); - - let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); - if precise { - let args = args.iter().fold(String::new(), |mut string, arg| { - let span = arg.span.find_ancestor_inside(sp).unwrap_or_default(); - write!( - string, - ", {}", - self.sess().source_map().span_to_snippet(span).unwrap() - ) - .unwrap(); - string - }); - - lint.span_suggestion( - sp, - "disambiguate the associated function", - format!( - "{}::{}{}({}{})", - trait_name, - segment.ident.name, - if let Some(args) = segment.args.as_ref().and_then(|args| self - .sess() - .source_map() - .span_to_snippet(args.span_ext) - .ok()) - { - // Keep turbofish. - format!("::{args}") - } else { - String::new() - }, - self_adjusted, - args, - ), - Applicability::MachineApplicable, - ); - } else { - lint.span_help( - sp, - format!( - "disambiguate the associated function with `{}::{}(...)`", - trait_name, segment.ident, - ), - ); - } + AmbiguousTraitMethod { + segment, + call_expr, + self_expr, + pick, + args, + edition, + span, + this: self, }, ); } @@ -242,6 +281,88 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_id: hir::HirId, pick: &Pick<'tcx>, ) { + struct AmbiguousTraitAssocFunc<'a, 'fnctx, 'tcx> { + method_name: Symbol, + this: &'a FnCtxt<'fnctx, 'tcx>, + pick: &'a Pick<'tcx>, + span: Span, + expr_id: hir::HirId, + self_ty_span: Span, + self_ty: Ty<'tcx>, + } + + impl<'a, 'b, 'fnctx, 'tcx> Diagnostic<'a, ()> for AmbiguousTraitAssocFunc<'b, 'fnctx, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { method_name, this, pick, span, expr_id, self_ty_span, self_ty } = self; + let mut lint = Diag::new( + dcx, + level, + format!( + "trait-associated function `{}` will become ambiguous in Rust 2021", + method_name + ), + ); + + // "type" refers to either a type or, more likely, a trait from which + // the associated function or method is from. + let container_id = pick.item.container_id(this.tcx); + let trait_path = this.trait_path_or_bare_name(span, expr_id, container_id); + let trait_generics = this.tcx.generics_of(container_id); + + let trait_name = + if trait_generics.own_params.len() <= trait_generics.has_self as usize { + trait_path + } else { + let counts = trait_generics.own_counts(); + format!( + "{}<{}>", + trait_path, + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain(std::iter::repeat("_").take( + counts.types + counts.consts - trait_generics.has_self as usize + )) + .collect::>() + .join(", ") + ) + }; + + let mut self_ty_name = self_ty_span + .find_ancestor_inside(span) + .and_then(|span| this.sess().source_map().span_to_snippet(span).ok()) + .unwrap_or_else(|| self_ty.to_string()); + + // Get the number of generics the self type has (if an Adt) unless we can determine that + // the user has written the self type with generics already which we (naively) do by looking + // for a "<" in `self_ty_name`. + if !self_ty_name.contains('<') { + if let ty::Adt(def, _) = self_ty.kind() { + let generics = this.tcx.generics_of(def.did()); + if !generics.is_own_empty() { + let counts = generics.own_counts(); + self_ty_name += &format!( + "<{}>", + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain( + std::iter::repeat("_").take(counts.types + counts.consts) + ) + .collect::>() + .join(", ") + ); + } + } + } + lint.span_suggestion( + span, + "disambiguate the associated function", + format!("<{} as {}>::{}", self_ty_name, trait_name, method_name), + Applicability::MachineApplicable, + ); + lint + } + } + // Rust 2021 and later is already using the new prelude if span.at_least_rust_2021() { return; @@ -278,67 +399,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - self.tcx.node_span_lint(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| { - lint.primary_message(format!( - "trait-associated function `{}` will become ambiguous in Rust 2021", - method_name.name - )); - - // "type" refers to either a type or, more likely, a trait from which - // the associated function or method is from. - let container_id = pick.item.container_id(self.tcx); - let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); - let trait_generics = self.tcx.generics_of(container_id); - - let trait_name = - if trait_generics.own_params.len() <= trait_generics.has_self as usize { - trait_path - } else { - let counts = trait_generics.own_counts(); - format!( - "{}<{}>", - trait_path, - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take( - counts.types + counts.consts - trait_generics.has_self as usize - )) - .collect::>() - .join(", ") - ) - }; - - let mut self_ty_name = self_ty_span - .find_ancestor_inside(span) - .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) - .unwrap_or_else(|| self_ty.to_string()); - - // Get the number of generics the self type has (if an Adt) unless we can determine that - // the user has written the self type with generics already which we (naively) do by looking - // for a "<" in `self_ty_name`. - if !self_ty_name.contains('<') { - if let ty::Adt(def, _) = self_ty.kind() { - let generics = self.tcx.generics_of(def.did()); - if !generics.is_own_empty() { - let counts = generics.own_counts(); - self_ty_name += &format!( - "<{}>", - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take(counts.types + counts.consts)) - .collect::>() - .join(", ") - ); - } - } - } - lint.span_suggestion( + self.tcx.emit_node_span_lint( + RUST_2021_PRELUDE_COLLISIONS, + expr_id, + span, + AmbiguousTraitAssocFunc { + method_name: method_name.name, + this: self, + pick, span, - "disambiguate the associated function", - format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), - Applicability::MachineApplicable, - ); - }); + expr_id, + self_ty_span, + self_ty, + }, + ); } fn trait_path_or_bare_name( diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b6162f2556d36..8d92ee03ff472 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -5,13 +5,14 @@ use std::ops::Deref; use rustc_data_structures::debug_assert_matches; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::def::DefKind; use rustc_hir::{self as hir, ExprKind, HirId, Node, find_attr}; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, query}; +use rustc_macros::Diagnostic; use rustc_middle::middle::stability; use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, simplify_type}; @@ -389,6 +390,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where OP: FnOnce(ProbeContext<'_, 'tcx>) -> Result>, { + #[derive(Diagnostic)] + #[diag("type annotations needed")] + struct MissingTypeAnnot; + let mut orig_values = OriginalQueryValues::default(); let predefined_opaques_in_body = if self.next_trait_solver() { self.tcx.mk_predefined_opaques_in_body_from_iter( @@ -471,13 +476,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( lint::builtin::TYVAR_BEHIND_RAW_POINTER, scope_expr_id, span, - |lint| { - lint.primary_message("type annotations needed"); - }, + MissingTypeAnnot, ); } else { // Ended up encountering a type variable when doing autoderef, @@ -1823,47 +1826,68 @@ impl<'tcx> Pick<'tcx> { span: Span, scope_expr_id: HirId, ) { - if self.unstable_candidates.is_empty() { - return; + struct ItemMaybeBeAddedToStd<'a, 'tcx> { + this: &'a Pick<'tcx>, + tcx: TyCtxt<'tcx>, + span: Span, } - let def_kind = self.item.as_def_kind(); - tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| { - lint.primary_message(format!( - "{} {} with this name may be added to the standard library in the future", - tcx.def_kind_descr_article(def_kind, self.item.def_id), - tcx.def_kind_descr(def_kind, self.item.def_id), - )); - - match (self.item.kind, self.item.container) { - (ty::AssocKind::Fn { .. }, _) => { - // FIXME: This should be a `span_suggestion` instead of `help` - // However `self.span` only - // highlights the method name, so we can't use it. Also consider reusing - // the code from `report_method_error()`. - lint.help(format!( - "call with fully qualified syntax `{}(...)` to keep using the current \ - method", - tcx.def_path_str(self.item.def_id), - )); - } - (ty::AssocKind::Const { name, .. }, ty::AssocContainer::Trait) => { - let def_id = self.item.container_id(tcx); - lint.span_suggestion( - span, - "use the fully qualified path to the associated const", - format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name), - Applicability::MachineApplicable, - ); + + impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for ItemMaybeBeAddedToStd<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { this, tcx, span } = self; + let def_kind = this.item.as_def_kind(); + let mut lint = Diag::new( + dcx, + level, + format!( + "{} {} with this name may be added to the standard library in the future", + tcx.def_kind_descr_article(def_kind, this.item.def_id), + tcx.def_kind_descr(def_kind, this.item.def_id), + ), + ); + + match (this.item.kind, this.item.container) { + (ty::AssocKind::Fn { .. }, _) => { + // FIXME: This should be a `span_suggestion` instead of `help` + // However `this.span` only + // highlights the method name, so we can't use it. Also consider reusing + // the code from `report_method_error()`. + lint.help(format!( + "call with fully qualified syntax `{}(...)` to keep using the current \ + method", + tcx.def_path_str(this.item.def_id), + )); + } + (ty::AssocKind::Const { name, .. }, ty::AssocContainer::Trait) => { + let def_id = this.item.container_id(tcx); + lint.span_suggestion( + span, + "use the fully qualified path to the associated const", + format!("<{} as {}>::{}", this.self_ty, tcx.def_path_str(def_id), name), + Applicability::MachineApplicable, + ); + } + _ => {} } - _ => {} + tcx.disabled_nightly_features( + &mut lint, + this.unstable_candidates.iter().map(|(candidate, feature)| { + (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) + }), + ); + lint } - tcx.disabled_nightly_features( - lint, - self.unstable_candidates.iter().map(|(candidate, feature)| { - (format!(" `{}`", tcx.def_path_str(candidate.item.def_id)), *feature) - }), - ); - }); + } + + if self.unstable_candidates.is_empty() { + return; + } + tcx.emit_node_span_lint( + lint::builtin::UNSTABLE_NAME_COLLISIONS, + scope_expr_id, + span, + ItemMaybeBeAddedToStd { this: self, tcx, span }, + ); } } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index ea4edb3ccf3cd..527ac5627237d 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -7,7 +7,8 @@ use rustc_data_structures::assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, + Applicability, Diag, DiagCtxtHandle, Diagnostic, ErrorGuaranteed, Level, MultiSpan, pluralize, + struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -2436,10 +2437,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); if let Some(field) = fields.last() { + let tail_span = field.span.shrink_to_hi().to(pat.span.shrink_to_hi()); + let comma_hi_offset = + self.tcx.sess.source_map().span_to_snippet(tail_span).ok().and_then(|snippet| { + let trimmed = snippet.trim_start(); + trimmed.starts_with(',').then(|| (snippet.len() - trimmed.len() + 1) as u32) + }); err.span_suggestion_verbose( - field.span.shrink_to_hi(), + if let Some(comma_hi_offset) = comma_hi_offset { + tail_span.with_hi(tail_span.lo() + BytePos(comma_hi_offset)).shrink_to_hi() + } else { + field.span.shrink_to_hi() + }, "ignore the inaccessible and unused fields", - ", ..", + if comma_hi_offset.is_some() { " .." } else { ", .." }, Applicability::MachineApplicable, ); } else { @@ -2471,6 +2482,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &[(&ty::FieldDef, Ident)], ty: Ty<'tcx>, ) { + struct FieldsNotListed<'a, 'b, 'tcx> { + pat_span: Span, + unmentioned_fields: &'a [(&'b ty::FieldDef, Ident)], + joined_patterns: String, + ty: Ty<'tcx>, + } + + impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for FieldsNotListed<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { pat_span, unmentioned_fields, joined_patterns, ty } = self; + Diag::new(dcx, level, "some fields are not explicitly listed") + .with_span_label(pat_span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)) + .with_help( + "ensure that all fields are mentioned explicitly by adding the suggested fields", + ) + .with_note(format!( + "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", + )) + } + } + fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String { const LIMIT: usize = 3; match witnesses { @@ -2495,16 +2527,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &unmentioned_fields.iter().map(|(_, i)| i).collect::>(), ); - self.tcx.node_span_lint(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |lint| { - lint.primary_message("some fields are not explicitly listed"); - lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); - lint.help( - "ensure that all fields are mentioned explicitly by adding the suggested fields", - ); - lint.note(format!( - "the pattern is of type `{ty}` and the `non_exhaustive_omitted_patterns` attribute was found", - )); - }); + self.tcx.emit_node_span_lint( + NON_EXHAUSTIVE_OMITTED_PATTERNS, + pat.hir_id, + pat.span, + FieldsNotListed { pat_span: pat.span, unmentioned_fields, joined_patterns, ty }, + ); } /// Returns a diagnostic reporting a struct pattern which does not mention some fields. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 1f680ca5b09a7..df02974d2fb2d 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -35,7 +35,7 @@ use std::iter; use rustc_abi::FIRST_VARIANT; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::unord::{ExtendUnord, UnordSet}; -use rustc_errors::{Applicability, MultiSpan}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, HirId, find_attr}; @@ -964,165 +964,216 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { capture_clause: hir::CaptureBy, span: Span, ) { - let (need_migrations, reasons) = self.compute_2229_migrations( - closure_def_id, - span, - capture_clause, - self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), - ); + struct MigrationLint<'a, 'b, 'tcx> { + closure_def_id: LocalDefId, + this: &'a FnCtxt<'b, 'tcx>, + body_id: hir::BodyId, + need_migrations: Vec, + migration_message: String, + } - if !need_migrations.is_empty() { - let (migration_string, migrated_variables_concat) = - migration_suggestion_for_2229(self.tcx, &need_migrations); + impl<'a, 'b, 'c, 'tcx> Diagnostic<'a, ()> for MigrationLint<'b, 'c, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { closure_def_id, this, body_id, need_migrations, migration_message } = + self; + let mut lint = Diag::new(dcx, level, migration_message); + + let (migration_string, migrated_variables_concat) = + migration_suggestion_for_2229(this.tcx, &need_migrations); + + let closure_hir_id = this.tcx.local_def_id_to_hir_id(closure_def_id); + let closure_head_span = this.tcx.def_span(closure_def_id); + + for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { + // Labels all the usage of the captured variable and why they are responsible + // for migration being needed + for lint_note in diagnostics_info.iter() { + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { + source_expr: Some(capture_expr_id), + var_name: captured_name, + } => { + let cause_span = this.tcx.hir_span(*capture_expr_id); + lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + this.tcx.hir_name(*var_hir_id), + captured_name, + )); + } + UpvarMigrationInfo::CapturingNothing { use_span } => { + lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + this.tcx.hir_name(*var_hir_id), + )); + } + + _ => {} + } + + // Add a label pointing to where a captured variable affected by drop order + // is dropped + if lint_note.reason.drop_order { + let drop_location_span = drop_location_span(this.tcx, closure_hir_id); - let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); - let closure_head_span = self.tcx.def_span(closure_def_id); - self.tcx.node_span_lint( - lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, - closure_hir_id, - closure_head_span, - |lint| { - lint.primary_message(reasons.migration_message()); - - for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { - // Labels all the usage of the captured variable and why they are responsible - // for migration being needed - for lint_note in diagnostics_info.iter() { match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { - let cause_span = self.tcx.hir_span(*capture_expr_id); - lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir_name(*var_hir_id), + UpvarMigrationInfo::CapturingPrecise { + var_name: captured_name, + .. + } => { + lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", + this.tcx.hir_name(*var_hir_id), captured_name, )); } - UpvarMigrationInfo::CapturingNothing { use_span } => { - lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", - self.tcx.hir_name(*var_hir_id), + UpvarMigrationInfo::CapturingNothing { use_span: _ } => { + lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + v = this.tcx.hir_name(*var_hir_id), )); } - - _ => { } } + } - // Add a label pointing to where a captured variable affected by drop order - // is dropped - if lint_note.reason.drop_order { - let drop_location_span = drop_location_span(self.tcx, closure_hir_id); - - match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir_name(*var_hir_id), - captured_name, - )); - } - UpvarMigrationInfo::CapturingNothing { use_span: _ } => { - lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", - v = self.tcx.hir_name(*var_hir_id), - )); - } + // Add a label explaining why a closure no longer implements a trait + for &missing_trait in &lint_note.reason.auto_traits { + // not capturing something anymore cannot cause a trait to fail to be implemented: + match &lint_note.captures_info { + UpvarMigrationInfo::CapturingPrecise { + var_name: captured_name, + .. + } => { + let var_name = this.tcx.hir_name(*var_hir_id); + lint.span_label( + closure_head_span, + format!( + "\ + in Rust 2018, this closure implements {missing_trait} \ + as `{var_name}` implements {missing_trait}, but in Rust 2021, \ + this closure will no longer implement {missing_trait} \ + because `{var_name}` is not fully captured \ + and `{captured_name}` does not implement {missing_trait}" + ), + ); } - } - // Add a label explaining why a closure no longer implements a trait - for &missing_trait in &lint_note.reason.auto_traits { - // not capturing something anymore cannot cause a trait to fail to be implemented: - match &lint_note.captures_info { - UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - let var_name = self.tcx.hir_name(*var_hir_id); - lint.span_label(closure_head_span, format!("\ - in Rust 2018, this closure implements {missing_trait} \ - as `{var_name}` implements {missing_trait}, but in Rust 2021, \ - this closure will no longer implement {missing_trait} \ - because `{var_name}` is not fully captured \ - and `{captured_name}` does not implement {missing_trait}")); - } - - // Cannot happen: if we don't capture a variable, we impl strictly more traits - UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"), - } + // Cannot happen: if we don't capture a variable, we impl strictly more traits + UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!( + *use_span, + "missing trait from not capturing something" + ), } } } + } - let diagnostic_msg = format!( - "add a dummy let to cause {migrated_variables_concat} to be fully captured" - ); + let diagnostic_msg = format!( + "add a dummy let to cause {migrated_variables_concat} to be fully captured" + ); - let closure_span = self.tcx.hir_span_with_body(closure_hir_id); - let mut closure_body_span = { - // If the body was entirely expanded from a macro - // invocation, i.e. the body is not contained inside the - // closure span, then we walk up the expansion until we - // find the span before the expansion. - let s = self.tcx.hir_span_with_body(body_id.hir_id); - s.find_ancestor_inside(closure_span).unwrap_or(s) - }; + let closure_span = this.tcx.hir_span_with_body(closure_hir_id); + let mut closure_body_span = { + // If the body was entirely expanded from a macro + // invocation, i.e. the body is not contained inside the + // closure span, then we walk up the expansion until we + // find the span before the expansion. + let s = this.tcx.hir_span_with_body(body_id.hir_id); + s.find_ancestor_inside(closure_span).unwrap_or(s) + }; - if let Ok(mut s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { - if s.starts_with('$') { - // Looks like a macro fragment. Try to find the real block. - if let hir::Node::Expr(&hir::Expr { - kind: hir::ExprKind::Block(block, ..), .. - }) = self.tcx.hir_node(body_id.hir_id) { - // If the body is a block (with `{..}`), we use the span of that block. - // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. - // Since we know it's a block, we know we can insert the `let _ = ..` without - // breaking the macro syntax. - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(block.span) { - closure_body_span = block.span; - s = snippet; - } + if let Ok(mut s) = this.tcx.sess.source_map().span_to_snippet(closure_body_span) { + if s.starts_with('$') { + // Looks like a macro fragment. Try to find the real block. + if let hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Block(block, ..), + .. + }) = this.tcx.hir_node(body_id.hir_id) + { + // If the body is a block (with `{..}`), we use the span of that block. + // E.g. with a `|| $body` expanded from a `m!({ .. })`, we use `{ .. }`, and not `$body`. + // Since we know it's a block, we know we can insert the `let _ = ..` without + // breaking the macro syntax. + if let Ok(snippet) = + this.tcx.sess.source_map().span_to_snippet(block.span) + { + closure_body_span = block.span; + s = snippet; } } + } - let mut lines = s.lines(); - let line1 = lines.next().unwrap_or_default(); - - if line1.trim_end() == "{" { - // This is a multi-line closure with just a `{` on the first line, - // so we put the `let` on its own line. - // We take the indentation from the next non-empty line. - let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); - let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; - lint.span_suggestion( - closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(), - diagnostic_msg, - format!("\n{indent}{migration_string};"), - Applicability::MachineApplicable, - ); - } else if line1.starts_with('{') { - // This is a closure with its body wrapped in - // braces, but with more than just the opening - // brace on the first line. We put the `let` - // directly after the `{`. - lint.span_suggestion( - closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(), - diagnostic_msg, - format!(" {migration_string};"), - Applicability::MachineApplicable, - ); - } else { - // This is a closure without braces around the body. - // We add braces to add the `let` before the body. - lint.multipart_suggestion( - diagnostic_msg, - vec![ - (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")), - (closure_body_span.shrink_to_hi(), " }".to_string()), - ], - Applicability::MachineApplicable - ); - } - } else { + let mut lines = s.lines(); + let line1 = lines.next().unwrap_or_default(); + + if line1.trim_end() == "{" { + // This is a multi-line closure with just a `{` on the first line, + // so we put the `let` on its own line. + // We take the indentation from the next non-empty line. + let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); + let indent = + line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; lint.span_suggestion( - closure_span, + closure_body_span + .with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())) + .shrink_to_lo(), diagnostic_msg, - migration_string, - Applicability::HasPlaceholders + format!("\n{indent}{migration_string};"), + Applicability::MachineApplicable, + ); + } else if line1.starts_with('{') { + // This is a closure with its body wrapped in + // braces, but with more than just the opening + // brace on the first line. We put the `let` + // directly after the `{`. + lint.span_suggestion( + closure_body_span + .with_lo(closure_body_span.lo() + BytePos(1)) + .shrink_to_lo(), + diagnostic_msg, + format!(" {migration_string};"), + Applicability::MachineApplicable, + ); + } else { + // This is a closure without braces around the body. + // We add braces to add the `let` before the body. + lint.multipart_suggestion( + diagnostic_msg, + vec![ + ( + closure_body_span.shrink_to_lo(), + format!("{{ {migration_string}; "), + ), + (closure_body_span.shrink_to_hi(), " }".to_string()), + ], + Applicability::MachineApplicable, ); } + } else { + lint.span_suggestion( + closure_span, + diagnostic_msg, + migration_string, + Applicability::HasPlaceholders, + ); + } + lint + } + } + + let (need_migrations, reasons) = self.compute_2229_migrations( + closure_def_id, + span, + capture_clause, + self.typeck_results.borrow().closure_min_captures.get(&closure_def_id), + ); + + if !need_migrations.is_empty() { + self.tcx.emit_node_span_lint( + lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, + self.tcx.local_def_id_to_hir_id(closure_def_id), + self.tcx.def_span(closure_def_id), + MigrationLint { + this: self, + migration_message: reasons.migration_message(), + closure_def_id, + body_id, + need_migrations, }, ); } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 5cd5c95f1ec14..98f087892a398 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Diag, Diagnostic, LintBuffer, MultiSpan}; +use rustc_errors::{Diagnostic, LintBuffer, MultiSpan}; use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -509,19 +509,6 @@ pub struct EarlyContext<'a> { pub trait LintContext { fn sess(&self) -> &Session; - // FIXME: These methods should not take an Into -- instead, callers should need to - // set the span in their `decorate` function (preferably using set_span). - /// Emit a lint at the appropriate level, with an optional associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ); - // FIXME: These methods should not take an Into -- instead, callers should need to // set the span in their `decorate` function (preferably using set_span). /// Emit a lint at the appropriate level, with an optional associated span. @@ -537,6 +524,7 @@ pub trait LintContext { /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`, /// typically generated by `#[derive(Diagnostic)]`). + #[track_caller] fn emit_span_lint>( &self, lint: &'static Lint, @@ -546,32 +534,12 @@ pub trait LintContext { self.opt_span_diag_lint(lint, Some(span), decorator); } - /// Emit a lint at the appropriate level, with an associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - #[track_caller] - fn span_lint>( - &self, - lint: &'static Lint, - span: S, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - self.opt_span_lint(lint, Some(span), decorate); - } - /// Emit a lint from a lint struct (some type that implements `Diagnostic`, typically /// generated by `#[derive(Diagnostic)]`). fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) { self.opt_span_diag_lint(lint, None as Option, decorator); } - /// Emit a lint at the appropriate level, with no associated span. - /// - /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature - fn lint(&self, lint: &'static Lint, decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>)) { - self.opt_span_lint(lint, None as Option, decorate); - } - /// This returns the lint level for the given lint at the current location. fn get_lint_level(&self, lint: &'static Lint) -> LevelAndSource; @@ -625,20 +593,6 @@ impl<'tcx> LintContext for LateContext<'tcx> { self.tcx.sess } - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let hir_id = self.last_node_with_lint_attrs; - - match span { - Some(s) => self.tcx.node_span_lint(lint, hir_id, s, decorate), - None => self.tcx.node_lint(lint, hir_id, decorate), - } - } - fn opt_span_diag_lint>( &self, lint: &'static Lint, @@ -664,15 +618,6 @@ impl LintContext for EarlyContext<'_> { self.builder.sess() } - fn opt_span_lint>( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - self.builder.opt_span_lint(lint, span.map(|s| s.into()), decorate) - } - fn opt_span_diag_lint>( &self, lint: &'static Lint, diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a134b623d7bd4..8b7a8c9ed5d87 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -2,7 +2,7 @@ use rustc_ast::attr::AttributeExt; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{Diag, Diagnostic, MultiSpan, msg}; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, MultiSpan, msg}; use rustc_feature::{Features, GateIssue}; use rustc_hir::HirId; use rustc_hir::intravisit::{self, Visitor}; @@ -11,7 +11,7 @@ use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::lint::{ LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, diag_lint_level, - lint_level, reveal_actual_level, + reveal_actual_level, }; use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; @@ -948,22 +948,45 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { return true; }; - if self.lint_added_lints { - let lint = builtin::UNKNOWN_LINTS; - let level = self.lint_level(builtin::UNKNOWN_LINTS); - lint_level(self.sess, lint, level, Some(span.into()), |lint| { - lint.primary_message(msg!("unknown lint: `{$name}`")); - lint.arg("name", lint_id.lint.name_lower()); - lint.note(msg!("the `{$name}` lint is unstable")); + struct UnknownLint<'a> { + sess: &'a Session, + lint_id: LintId, + feature: Symbol, + lint_from_cli: bool, + } + + impl<'a, 'b> Diagnostic<'a, ()> for UnknownLint<'b> { + fn into_diag( + self, + dcx: DiagCtxtHandle<'a>, + level: rustc_errors::Level, + ) -> Diag<'a, ()> { + let Self { sess, lint_id, feature, lint_from_cli } = self; + let mut lint = Diag::new(dcx, level, msg!("unknown lint: `{$name}`")) + .with_arg("name", lint_id.lint.name_lower()) + .with_note(msg!("the `{$name}` lint is unstable")); rustc_session::parse::add_feature_diagnostics_for_issue( - lint, - &self.sess, + &mut lint, + sess, feature, GateIssue::Language, lint_from_cli, None, ); - }); + lint + } + } + + if self.lint_added_lints { + let lint = builtin::UNKNOWN_LINTS; + let level = self.lint_level(builtin::UNKNOWN_LINTS); + diag_lint_level( + self.sess, + lint, + level, + Some(span.into()), + UnknownLint { sess: &self.sess, lint_id, feature, lint_from_cli }, + ); } false @@ -974,19 +997,6 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { self.provider.get_lint_level(lint, self.sess) } - /// Used to emit a lint-related diagnostic based on the current state of - /// this lint context. - #[track_caller] - pub(crate) fn opt_span_lint( - &self, - lint: &'static Lint, - span: Option, - decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), - ) { - let level = self.lint_level(lint); - lint_level(self.sess, lint, level, span, decorate) - } - /// Used to emit a lint-related diagnostic based on the current state of /// this lint context. #[track_caller] diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index bb04da96140a6..7f137d5bf0603 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -1,5 +1,6 @@ use rustc_ast as ast; -use rustc_errors::{Applicability, msg}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, msg}; +use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::{bug, ty}; @@ -85,49 +86,26 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { } } -fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Lit(lit) = &arg.kind { - if let ast::LitKind::Str(sym, _) = lit.node { - // The argument is a string literal. - check_panic_str(cx, f, arg, sym.as_str()); - return; - } - } - - // The argument is *not* a string literal. - - let (span, panic, symbol) = panic_call(cx, f); - - if span.in_external_macro(cx.sess().source_map()) { - // Nothing that can be done about it in the current crate. - return; - } - - // Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the - // case of `panic!(some_macro!())` or `unreachable!(some_macro!())`. - // We don't use source_callsite(), because this `panic!(..)` might itself - // be expanded from another macro, in which case we want to stop at that - // expansion. - let mut arg_span = arg.span; - let mut arg_macro = None; - while !span.contains(arg_span) { - let ctxt = arg_span.ctxt(); - if ctxt.is_root() { - break; - } - let expn = ctxt.outer_expn_data(); - arg_macro = expn.macro_def_id; - arg_span = expn.call_site; - } +struct PanicMessageNotLiteral<'a, 'tcx> { + arg_span: Span, + symbol: Symbol, + span: Span, + arg_macro: Option, + cx: &'a LateContext<'tcx>, + arg: &'tcx hir::Expr<'tcx>, + panic: Option, +} - cx.span_lint(NON_FMT_PANICS, arg_span, |lint| { - lint.primary_message(msg!("panic message is not a string literal")); - lint.arg("name", symbol); - lint.note(msg!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021")); - lint.note(msg!("for more information, see ")); +impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for PanicMessageNotLiteral<'b, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { arg_span, symbol, span, arg_macro, cx, arg, panic } = self; + let mut lint = Diag::new(dcx, level, "panic message is not a string literal") + .with_arg("name", symbol) + .with_note(msg!("this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021")) + .with_note("for more information, see "); if !is_arg_inside_call(arg_span, span) { // No clue where this argument is coming from. - return; + return lint; } if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) { // A case of `panic!(format!(..))`. @@ -215,7 +193,50 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc } } } - }); + lint + } +} + +fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) { + if let hir::ExprKind::Lit(lit) = &arg.kind { + if let ast::LitKind::Str(sym, _) = lit.node { + // The argument is a string literal. + check_panic_str(cx, f, arg, sym.as_str()); + return; + } + } + + // The argument is *not* a string literal. + + let (span, panic, symbol) = panic_call(cx, f); + + if span.in_external_macro(cx.sess().source_map()) { + // Nothing that can be done about it in the current crate. + return; + } + + // Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the + // case of `panic!(some_macro!())` or `unreachable!(some_macro!())`. + // We don't use source_callsite(), because this `panic!(..)` might itself + // be expanded from another macro, in which case we want to stop at that + // expansion. + let mut arg_span = arg.span; + let mut arg_macro = None; + while !span.contains(arg_span) { + let ctxt = arg_span.ctxt(); + if ctxt.is_root() { + break; + } + let expn = ctxt.outer_expn_data(); + arg_macro = expn.macro_def_id; + arg_span = expn.call_site; + } + + cx.emit_span_lint( + NON_FMT_PANICS, + arg_span, + PanicMessageNotLiteral { arg_span, symbol, span, arg_macro, cx, arg, panic }, + ); } fn check_panic_str<'tcx>( diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d00ef84725071..640e6f9838510 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,7 +92,6 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_hir::attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] valtree: rustc_middle::ty::ValTreeKind>, [] stable_order_of_exportable_impls: rustc_data_structures::fx::FxIndexMap, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 223b47c9044be..eb1628762ffe8 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,7 +2,7 @@ use std::cmp; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sorted_map::SortedMap; -use rustc_errors::{Diag, Diagnostic, MultiSpan}; +use rustc_errors::{Diag, DiagLocation, Diagnostic, MultiSpan}; use rustc_hir::{HirId, ItemLocalId}; use rustc_lint_defs::EditionFcw; use rustc_macros::{Decodable, Encodable, HashStable}; @@ -602,6 +602,9 @@ pub fn diag_lint_level<'a, D: Diagnostic<'a, ()> + 'a>( } else { Diag::new(sess.dcx(), err_level, "") }; + // FIXME: Find a nicer way to expose the `DiagLocation` + err.emitted_at = DiagLocation::caller(); + if let Some(span) = span && err.span.primary_span().is_none() { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 5f78f414a742a..d1987f51f6e01 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -13,6 +13,7 @@ use std::marker::{DiscriminantKind, PointeeSized}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; +use rustc_middle::ty::Const; use rustc_serialize::{Decodable, Encodable}; use rustc_span::source_map::Spanned; use rustc_span::{Span, SpanDecoder, SpanEncoder}; @@ -497,6 +498,7 @@ impl_decodable_via_ref! { &'tcx ty::List>, &'tcx ty::List>, &'tcx ty::ListWithCachedTypeInfo>, + &'tcx ty::List>, } #[macro_export] diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 994f7d17c5c41..50242613b3e7f 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -31,12 +31,6 @@ impl<'tcx> ty::ValTreeKind> { // recurses through pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind>>); -impl<'tcx> rustc_type_ir::inherent::ValTree> for ValTree<'tcx> { - fn kind(&self) -> &ty::ValTreeKind> { - &self - } -} - impl<'tcx> ValTree<'tcx> { /// Returns the zero-sized valtree: `Branch([])`. pub fn zst(tcx: TyCtxt<'tcx>) -> Self { @@ -44,7 +38,7 @@ impl<'tcx> ValTree<'tcx> { } pub fn is_zst(self) -> bool { - matches!(*self, ty::ValTreeKind::Branch(box [])) + matches!(*self, ty::ValTreeKind::Branch(consts) if consts.is_empty()) } pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self { @@ -58,7 +52,9 @@ impl<'tcx> ValTree<'tcx> { tcx: TyCtxt<'tcx>, branches: impl IntoIterator>, ) -> Self { - tcx.intern_valtree(ty::ValTreeKind::Branch(branches.into_iter().collect())) + tcx.intern_valtree(ty::ValTreeKind::Branch( + tcx.mk_const_list_from_iter(branches.into_iter()), + )) } pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self { @@ -81,6 +77,14 @@ impl fmt::Debug for ValTree<'_> { } } +impl<'tcx> rustc_type_ir::inherent::IntoKind for ty::ValTree<'tcx> { + type Kind = ty::ValTreeKind>; + + fn kind(self) -> Self::Kind { + *self.0 + } +} + /// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed /// because the value contains something of type `ty` that is not valtree-compatible. /// The caller can then show an appropriate error; the query does not have the diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 68819445a06c4..8f94fc921563d 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -564,7 +564,7 @@ impl<'tcx> CommonConsts<'tcx> { )) }; - let valtree_zst = mk_valtree(ty::ValTreeKind::Branch(Box::default())); + let valtree_zst = mk_valtree(ty::ValTreeKind::Branch(List::empty())); let valtree_true = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::TRUE)); let valtree_false = mk_valtree(ty::ValTreeKind::Leaf(ty::ScalarInt::FALSE)); diff --git a/compiler/rustc_middle/src/ty/context/impl_interner.rs b/compiler/rustc_middle/src/ty/context/impl_interner.rs index a6b3f29d7ec23..af7da06ff4798 100644 --- a/compiler/rustc_middle/src/ty/context/impl_interner.rs +++ b/compiler/rustc_middle/src/ty/context/impl_interner.rs @@ -95,6 +95,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Safety = hir::Safety; type Abi = ExternAbi; type Const = ty::Const<'tcx>; + type Consts = &'tcx List; type ParamConst = ty::ParamConst; type ValueConst = ty::Value<'tcx>; diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index a34244096d20c..8b8fe522842a4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1930,7 +1930,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Otherwise, print the array separated by commas (or if it's a tuple) (ty::ValTreeKind::Branch(fields), ty::Array(..) | ty::Tuple(..)) => { - let fields_iter = fields.iter().copied(); + let fields_iter = fields.iter(); match *cv.ty.kind() { ty::Array(..) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9a2f1e8a13a1a..04985dd3acde5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -797,4 +797,5 @@ list_fold! { &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, &'tcx ty::List> : mk_outlives, + &'tcx ty::List> : mk_const_list, } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d04322c320b4c..38055471e83a8 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2941,12 +2941,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match pat.ctor() { Constructor::Variant(variant_index) => { - let ValTreeKind::Branch(box [actual_variant_idx]) = *valtree else { + let ValTreeKind::Branch(branch) = *valtree else { bug!("malformed valtree for an enum") }; - - let ValTreeKind::Leaf(actual_variant_idx) = *actual_variant_idx.to_value().valtree - else { + if branch.len() != 1 { + bug!("malformed valtree for an enum") + }; + let ValTreeKind::Leaf(actual_variant_idx) = **branch[0].to_value().valtree else { bug!("malformed valtree for an enum") }; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 02deff6474080..c5eeb8b1aa856 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -806,6 +806,10 @@ impl<'tcx> ThirBuildCx<'tcx> { lit: ScalarInt::try_from_uint(val, Size::from_bits(32)).unwrap(), user_ty: None, }; + let mk_usize_kind = |val: u64| ExprKind::NonHirLiteral { + lit: ScalarInt::try_from_target_usize(val, tcx).unwrap(), + user_ty: None, + }; let mk_call = |thir: &mut Thir<'tcx>, ty: Ty<'tcx>, variant: VariantIdx, field: FieldIdx| { let fun_ty = @@ -842,7 +846,7 @@ impl<'tcx> ThirBuildCx<'tcx> { }); } - expr.unwrap_or(mk_u32_kind(0)) + expr.unwrap_or_else(|| mk_usize_kind(0)) } hir::ExprKind::ConstBlock(ref anon_const) => { diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 3e2f10df20b8f..3b77505229a30 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -9,7 +9,7 @@ use std::cell::Cell; use std::collections::hash_map::Entry; use std::slice; -use rustc_abi::{Align, ExternAbi, Size}; +use rustc_abi::ExternAbi; use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::{AttributeParser, Late}; use rustc_data_structures::fx::FxHashMap; @@ -190,8 +190,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { &Attribute::Parsed(AttributeKind::RustcPubTransparent(attr_span)) => { self.check_rustc_pub_transparent(attr_span, span, attrs) } - Attribute::Parsed(AttributeKind::RustcAlign { align, span: attr_span }) => { - self.check_align(*align, *attr_span) + Attribute::Parsed(AttributeKind::RustcAlign {..}) => { + } Attribute::Parsed(AttributeKind::Naked(..)) => { self.check_naked(hir_id, target) @@ -1335,31 +1335,27 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } } - ReprAttr::ReprAlign(align) => { - match target { - Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlign { - span: *repr_span, - item: target.plural_name(), - }); - } - Target::Static if self.tcx.features().static_align() => { - self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { - span: *repr_span, - item: target.plural_name(), - }); - } - _ => { - self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: *repr_span, - span, - }); - } + ReprAttr::ReprAlign(..) => match target { + Target::Struct | Target::Union | Target::Enum => {} + Target::Fn | Target::Method(_) if self.tcx.features().fn_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlign { + span: *repr_span, + item: target.plural_name(), + }); } - - self.check_align(*align, *repr_span); - } + Target::Static if self.tcx.features().static_align() => { + self.dcx().emit_err(errors::ReprAlignShouldBeAlignStatic { + span: *repr_span, + item: target.plural_name(), + }); + } + _ => { + self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { + hint_span: *repr_span, + span, + }); + } + }, ReprAttr::ReprPacked(_) => { if target != Target::Struct && target != Target::Union { self.dcx().emit_err(errors::AttrApplication::StructUnion { @@ -1475,25 +1471,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align(&self, align: Align, span: Span) { - if align.bytes() > 2_u64.pow(29) { - // for values greater than 2^29, a different error will be emitted, make sure that happens - self.dcx().span_delayed_bug( - span, - "alignment greater than 2^29 should be errored on elsewhere", - ); - } else { - // only do this check when <= 2^29 to prevent duplicate errors: - // alignment greater than 2^29 not supported - // alignment is too large for the current target - - let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; - if align.bytes() > max { - self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max }); - } - } - } - /// Outputs an error for attributes that can only be applied to macros, such as /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`. /// (Allows proc_macro functions) diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 8073cb257b032..bd3fd6935e8f3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -236,15 +236,6 @@ pub(crate) struct ReprConflicting { pub hint_spans: Vec, } -#[derive(Diagnostic)] -#[diag("alignment must not be greater than `isize::MAX` bytes", code = E0589)] -#[note("`isize::MAX` is {$size} for the current target")] -pub(crate) struct InvalidReprAlignForTarget { - #[primary_span] - pub span: Span, - pub size: u64, -} - #[derive(Diagnostic)] #[diag("conflicting representation hints", code = E0566)] pub(crate) struct ReprConflictingLint; diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 52f86be310fb9..4a0a99ea27640 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1016,17 +1016,20 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::ConstEvaluatable(c), - )); - let cause = self.cause(ObligationCauseCode::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - tcx, - cause, - self.recursion_depth, - self.param_env, - predicate, - )); + // Skip type consts as mGCA doesn't support evaluatable clauses + if !tcx.is_type_const(uv.def) { + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstEvaluatable(c), + )); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + tcx, + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } if matches!(tcx.def_kind(uv.def), DefKind::AssocConst { .. }) && tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false }) diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 1c39f31469b1c..49fb94c830e24 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -140,7 +140,7 @@ impl HashStable for InferConst { /// /// `ValTree` does not have this problem with representation, as it only contains integers or /// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s). -#[derive_where(Clone, Debug, Hash, Eq, PartialEq; I: Interner)] +#[derive_where(Clone, Copy, Debug, Hash, Eq, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -159,8 +159,7 @@ pub enum ValTreeKind { /// the fields of the variant. /// /// ZST types are represented as an empty slice. - // FIXME(mgca): Use a `List` here instead of a boxed slice - Branch(Box<[I::Const]>), + Branch(I::Consts), } impl ValTreeKind { @@ -177,9 +176,9 @@ impl ValTreeKind { /// Converts to a `ValTreeKind::Branch` value, `panic`'ing /// if this valtree is some other kind. #[inline] - pub fn to_branch(&self) -> &[I::Const] { + pub fn to_branch(&self) -> I::Consts { match self { - ValTreeKind::Branch(branch) => &**branch, + ValTreeKind::Branch(branch) => *branch, ValTreeKind::Leaf(..) => panic!("expected branch, got {:?}", self), } } @@ -193,9 +192,9 @@ impl ValTreeKind { } /// Attempts to convert to a `ValTreeKind::Branch` value. - pub fn try_to_branch(&self) -> Option<&[I::Const]> { + pub fn try_to_branch(&self) -> Option { match self { - ValTreeKind::Branch(branch) => Some(&**branch), + ValTreeKind::Branch(branch) => Some(*branch), ValTreeKind::Leaf(_) => None, } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 8b057e5866cd9..7e905da0785f8 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -482,8 +482,8 @@ impl FlagComputation { match cv.valtree().kind() { ty::ValTreeKind::Leaf(_) => (), ty::ValTreeKind::Branch(cts) => { - for ct in cts { - self.add_const(*ct); + for ct in cts.iter() { + self.add_const(ct); } } } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 8256ea7ed312e..116fd100bf0a9 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -294,12 +294,6 @@ pub trait ValueConst>: Copy + Debug + Hash + Eq { fn valtree(self) -> I::ValTree; } -// FIXME(mgca): This trait can be removed once we're not using a `Box` in `Branch` -pub trait ValTree>: Copy + Debug + Hash + Eq { - // This isnt' `IntoKind` because then we can't return a reference - fn kind(&self) -> &ty::ValTreeKind; -} - pub trait ExprConst>: Copy + Debug + Hash + Eq + Relate { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 8f446cdfba6d5..e77e7af071b90 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -150,10 +150,11 @@ pub trait Interner: // Kinds of consts type Const: Const; + type Consts: Copy + Debug + Hash + Eq + SliceLike + Default; type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type ValueConst: ValueConst; type ExprConst: ExprConst; - type ValTree: ValTree; + type ValTree: Copy + Debug + Hash + Eq + IntoKind>; type ScalarInt: Copy + Debug + Hash + Eq; // Kinds of regions diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 3610605462ba9..d33c6036dadd8 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -577,9 +577,9 @@ pub fn structurally_relate_consts>( if branches_a.len() == branches_b.len() => { branches_a - .into_iter() - .zip(branches_b) - .all(|(a, b)| relation.relate(*a, *b).is_ok()) + .iter() + .zip(branches_b.iter()) + .all(|(a, b)| relation.relate(a, b).is_ok()) } _ => false, } diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index b729cdf8458d7..3e39528dfbf43 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -218,31 +218,28 @@ const fn lim_for_ty(_x: T) -> T { // We have runtime ("rt") and const versions of these macros. /// Verify that floats are within a tolerance of each other. -macro_rules! assert_approx_eq_rt { - ($a:expr, $b:expr) => {{ assert_approx_eq_rt!($a, $b, $crate::floats::lim_for_ty($a)) }}; +macro_rules! assert_approx_eq { + ($a:expr, $b:expr $(,)?) => {{ assert_approx_eq!($a, $b, $crate::floats::lim_for_ty($a)) }}; ($a:expr, $b:expr, $lim:expr) => {{ let (a, b) = (&$a, &$b); let diff = (*a - *b).abs(); - assert!( + core::panic::const_assert!( diff <= $lim, + "actual value is not approximately equal to expected value", "{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})", - lim = $lim + // We rely on the `Float` type being brought in scope by the macros below. + a: Float = *a, + b: Float = *b, + diff: Float = diff, + lim: Float = $lim, ); }}; } -macro_rules! assert_approx_eq_const { - ($a:expr, $b:expr) => {{ assert_approx_eq_const!($a, $b, $crate::floats::lim_for_ty($a)) }}; - ($a:expr, $b:expr, $lim:expr) => {{ - let (a, b) = (&$a, &$b); - let diff = (*a - *b).abs(); - assert!(diff <= $lim); - }}; -} /// Verify that floats have the same bitwise representation. Used to avoid the default `0.0 == -0.0` /// behavior, as well as to ensure exact NaN bitpatterns. -macro_rules! assert_biteq_rt { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ +macro_rules! assert_biteq { + ($left:expr, $right:expr $(,)?) => {{ let l = $left; let r = $right; @@ -252,63 +249,21 @@ macro_rules! assert_biteq_rt { // Hack to get the width from a value let bits = (l.to_bits() - l.to_bits()).leading_zeros(); - assert!( + core::panic::const_assert!( l.to_bits() == r.to_bits(), - "{msg}{nl}l: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", - msg = format_args!($($tt)*), - nl = $msg_sep, - lb = l.to_bits(), - rb = r.to_bits(), - width = ((bits / 4) + 2) as usize, + "actual value and expected value are not bit-equal", + "actual value and expected value are not bit-equal\n\ + l: {l:?} ({lb:#0width$x})\nr: {r:?} ({rb:#0width$x})", + // We rely on the `Float` type being brought in scope by the macros below. + l: Float = l, + r: Float = r, + lb: ::Int = l.to_bits(), + rb: ::Int = r.to_bits(), + width: usize = ((bits / 4) + 2) as usize, ); - - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert_eq!(l, r); - } - }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_rt!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq_rt!(@inner $left, $right, "", "") - }; -} -macro_rules! assert_biteq_const { - (@inner $left:expr, $right:expr, $msg_sep:literal, $($tt:tt)*) => {{ - let l = $left; - let r = $right; - - // Hack to coerce left and right to the same type - let mut _eq_ty = l; - _eq_ty = r; - - assert!(l.to_bits() == r.to_bits()); - - if !l.is_nan() && !r.is_nan() { - // Also check that standard equality holds, since most tests use `assert_biteq` rather - // than `assert_eq`. - assert!(l == r); - } }}; - ($left:expr, $right:expr , $($tt:tt)*) => { - assert_biteq_const!(@inner $left, $right, "\n", $($tt)*) - }; - ($left:expr, $right:expr $(,)?) => { - assert_biteq_const!(@inner $left, $right, "", "") - }; } -// Use the runtime version by default. -// This way, they can be shadowed by the const versions. -pub(crate) use {assert_approx_eq_rt as assert_approx_eq, assert_biteq_rt as assert_biteq}; - -// Also make the const version available for re-exports. -#[rustfmt::skip] -pub(crate) use assert_biteq_const; -pub(crate) use assert_approx_eq_const; - /// Generate float tests for all our float types, for compile-time and run-time behavior. /// /// By default all tests run for all float types. Configuration can be applied via `attrs`. @@ -341,7 +296,7 @@ macro_rules! float_test { $(f128: #[ $($f128_meta:meta),+ ] ,)? $(const f128: #[ $($f128_const_meta:meta),+ ] ,)? }, - test<$fty:ident> $test:block + test $test:block ) => { mod $name { use super::*; @@ -351,9 +306,9 @@ macro_rules! float_test { fn test_f16() { #[allow(unused_imports)] use core::f16::consts; - type $fty = f16; + type Float = f16; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -362,9 +317,9 @@ macro_rules! float_test { fn test_f32() { #[allow(unused_imports)] use core::f32::consts; - type $fty = f32; + type Float = f32; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -373,9 +328,9 @@ macro_rules! float_test { fn test_f64() { #[allow(unused_imports)] use core::f64::consts; - type $fty = f64; + type Float = f64; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } @@ -384,35 +339,24 @@ macro_rules! float_test { fn test_f128() { #[allow(unused_imports)] use core::f128::consts; - type $fty = f128; + type Float = f128; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } $test } $( $( #[$const_meta] )+ )? mod const_ { - #[allow(unused)] - use super::TestableFloat; - #[allow(unused)] - use std::num::FpCategory as Fp; - #[allow(unused)] - use std::ops::{Add, Div, Mul, Rem, Sub}; - // Shadow the runtime versions of the macro with const-compatible versions. - #[allow(unused)] - use $crate::floats::{ - assert_approx_eq_const as assert_approx_eq, - assert_biteq_const as assert_biteq, - }; + use super::*; #[test] $( $( #[$f16_const_meta] )+ )? fn test_f16() { #[allow(unused_imports)] use core::f16::consts; - type $fty = f16; + type Float = f16; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -421,9 +365,9 @@ macro_rules! float_test { fn test_f32() { #[allow(unused_imports)] use core::f32::consts; - type $fty = f32; + type Float = f32; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -432,9 +376,9 @@ macro_rules! float_test { fn test_f64() { #[allow(unused_imports)] use core::f64::consts; - type $fty = f64; + type Float = f64; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } @@ -443,9 +387,9 @@ macro_rules! float_test { fn test_f128() { #[allow(unused_imports)] use core::f128::consts; - type $fty = f128; + type Float = f128; #[allow(unused)] - const fn flt (x: $fty) -> $fty { x } + const fn flt (x: Float) -> Float { x } const { $test } } } @@ -459,7 +403,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let two: Float = 2.0; let ten: Float = 10.0; assert_biteq!(ten.add(two), ten + two); @@ -477,7 +421,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { let two: Float = 2.0; let ten: Float = 10.0; assert_biteq!(ten.rem(two), ten % two); @@ -490,7 +434,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; assert!(nan.is_nan()); assert!(!nan.is_infinite()); @@ -510,7 +454,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let inf: Float = Float::INFINITY; assert!(inf.is_infinite()); assert!(!inf.is_finite()); @@ -528,7 +472,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let neg_inf: Float = Float::NEG_INFINITY; assert!(neg_inf.is_infinite()); assert!(!neg_inf.is_finite()); @@ -546,7 +490,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(0.0, Float::ZERO); assert!(!Float::ZERO.is_infinite()); assert!(Float::ZERO.is_finite()); @@ -564,7 +508,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let neg_zero: Float = -0.0; assert!(0.0 == neg_zero); assert_biteq!(-0.0, neg_zero); @@ -584,7 +528,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(1.0, Float::ONE); assert!(!Float::ONE.is_infinite()); assert!(Float::ONE.is_finite()); @@ -602,7 +546,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -623,7 +567,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -644,7 +588,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -665,7 +609,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -686,7 +630,7 @@ float_test! { attrs: { f16: #[cfg(any(miri, target_has_reliable_f16))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -708,7 +652,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).min(0.0), 0.0); assert_biteq!(flt(-0.0).min(-0.0), -0.0); assert_biteq!(flt(9.0).min(9.0), 9.0); @@ -738,7 +682,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).max(0.0), 0.0); assert_biteq!(flt(-0.0).max(-0.0), -0.0); assert_biteq!(flt(9.0).max(9.0), 9.0); @@ -769,7 +713,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).minimum(0.0), 0.0); assert_biteq!(flt(-0.0).minimum(0.0), -0.0); assert_biteq!(flt(-0.0).minimum(-0.0), -0.0); @@ -800,7 +744,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).maximum(0.0), 0.0); assert_biteq!(flt(-0.0).maximum(0.0), 0.0); assert_biteq!(flt(-0.0).maximum(-0.0), -0.0); @@ -832,7 +776,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.5).midpoint(0.5), 0.5); assert_biteq!(flt(0.5).midpoint(2.5), 1.5); assert_biteq!(flt(3.0).midpoint(4.0), 3.5); @@ -885,7 +829,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { // test if large differences in magnitude are still correctly computed. // NOTE: that because of how small x and y are, x + y can never overflow // so (x + y) / 2.0 is always correct @@ -915,7 +859,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(Float::INFINITY.abs(), Float::INFINITY); assert_biteq!(Float::ONE.abs(), Float::ONE); assert_biteq!(Float::ZERO.abs(), Float::ZERO); @@ -933,7 +877,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).copysign(-2.0), -1.0); assert_biteq!(flt(-1.0).copysign(2.0), 1.0); assert_biteq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); @@ -948,7 +892,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert!(Float::INFINITY.rem_euclid(42.0).is_nan()); assert_biteq!(flt(42.0).rem_euclid(Float::INFINITY), 42.0); assert!(flt(42.0).rem_euclid(Float::NAN).is_nan()); @@ -965,7 +909,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(42.0).div_euclid(Float::INFINITY), 0.0); assert!(flt(42.0).div_euclid(Float::NAN).is_nan()); assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); @@ -980,7 +924,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).floor(), 1.0); assert_biteq!(flt(1.3).floor(), 1.0); assert_biteq!(flt(1.5).floor(), 1.0); @@ -1009,7 +953,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).ceil(), 1.0); assert_biteq!(flt(1.3).ceil(), 2.0); assert_biteq!(flt(1.5).ceil(), 2.0); @@ -1038,7 +982,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(2.5).round(), 3.0); assert_biteq!(flt(1.0).round(), 1.0); assert_biteq!(flt(1.3).round(), 1.0); @@ -1068,7 +1012,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(2.5).round_ties_even(), 2.0); assert_biteq!(flt(1.0).round_ties_even(), 1.0); assert_biteq!(flt(1.3).round_ties_even(), 1.0); @@ -1098,7 +1042,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).trunc(), 1.0); assert_biteq!(flt(1.3).trunc(), 1.0); assert_biteq!(flt(1.5).trunc(), 1.0); @@ -1127,7 +1071,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).fract(), 0.0); assert_approx_eq!(flt(1.3).fract(), 0.3); // rounding differs between float types assert_biteq!(flt(1.5).fract(), 0.5); @@ -1158,7 +1102,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(Float::INFINITY.signum(), Float::ONE); assert_biteq!(Float::ONE.signum(), Float::ONE); assert_biteq!(Float::ZERO.signum(), Float::ONE); @@ -1176,7 +1120,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert!(Float::INFINITY.is_sign_positive()); assert!(Float::ONE.is_sign_positive()); assert!(Float::ZERO.is_sign_positive()); @@ -1195,7 +1139,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert!(!Float::INFINITY.is_sign_negative()); assert!(!Float::ONE.is_sign_negative()); assert!(!Float::ZERO.is_sign_negative()); @@ -1214,7 +1158,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::NEG_INFINITY.next_up(), Float::MIN); assert_biteq!(Float::MIN.next_up(), -Float::MAX_DOWN); assert_biteq!((-Float::ONE - Float::EPSILON).next_up(), -Float::ONE); @@ -1245,7 +1189,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::NEG_INFINITY.next_down(), Float::NEG_INFINITY); assert_biteq!(Float::MIN.next_down(), Float::NEG_INFINITY); assert_biteq!((-Float::MAX_DOWN).next_down(), Float::MIN); @@ -1278,7 +1222,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { assert!(Float::NAN.sqrt().is_nan()); assert!(Float::NEG_INFINITY.sqrt().is_nan()); assert!((-Float::ONE).sqrt().is_nan()); @@ -1298,7 +1242,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(3.0, 1.0); } } @@ -1312,7 +1256,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(Float::NAN, 1.0); } } @@ -1326,7 +1270,7 @@ float_test! { f64: #[should_panic], f128: #[should_panic, cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let _ = Float::ONE.clamp(3.0, Float::NAN); } } @@ -1337,7 +1281,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { use core::cmp::Ordering; const fn quiet_bit_mask() -> ::Int { @@ -1442,7 +1386,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { use core::cmp::Ordering; fn quiet_bit_mask() -> ::Int { @@ -1498,7 +1442,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16_math))], f128: #[cfg(any(miri, target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1522,7 +1466,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1543,7 +1487,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1566,7 +1510,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(1.0, flt(0.0).exp()); assert_approx_eq!(consts::E, flt(1.0).exp(), Float::EXP_APPROX); assert_approx_eq!(148.41315910257660342111558004055227962348775, flt(5.0).exp(), Float::EXP_APPROX); @@ -1587,7 +1531,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(32.0, flt(5.0).exp2(), Float::EXP_APPROX); assert_biteq!(1.0, flt(0.0).exp2()); @@ -1607,7 +1551,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1629,7 +1573,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1654,7 +1598,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1677,7 +1621,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1701,7 +1645,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).asinh(), 0.0); assert_biteq!(flt(-0.0).asinh(), -0.0); @@ -1734,7 +1678,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(1.0).acosh(), 0.0); assert!(flt(0.999).acosh().is_nan()); @@ -1762,7 +1706,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_biteq!(flt(0.0).atanh(), 0.0); assert_biteq!(flt(-0.0).atanh(), -0.0); @@ -1788,7 +1732,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(flt(1.0).gamma(), 1.0, Float::GAMMA_APPROX); assert_approx_eq!(flt(2.0).gamma(), 1.0, Float::GAMMA_APPROX); assert_approx_eq!(flt(3.0).gamma(), 2.0, Float::GAMMA_APPROX); @@ -1823,7 +1767,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { assert_approx_eq!(flt(1.0).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX); assert_eq!(flt(1.0).ln_gamma().1, 1); assert_approx_eq!(flt(2.0).ln_gamma().0, 0.0, Float::LNGAMMA_APPROX); @@ -1841,7 +1785,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let pi: Float = consts::PI; let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; @@ -1862,7 +1806,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let pi: Float = consts::PI; let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; @@ -1883,7 +1827,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let a: Float = flt(123.0); let b: Float = flt(456.0); @@ -1907,7 +1851,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(flt(1.0), Float::RAW_1); assert_biteq!(flt(12.5), Float::RAW_12_DOT_5); assert_biteq!(flt(1337.0), Float::RAW_1337); @@ -1937,7 +1881,7 @@ float_test! { f64: #[cfg_attr(all(target_os = "windows", target_env = "gnu", not(target_abi = "llvm")), ignore)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { let nan: Float = Float::NAN; let inf: Float = Float::INFINITY; let neg_inf: Float = Float::NEG_INFINITY; @@ -1959,7 +1903,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(false), Float::ZERO); assert_biteq!(Float::from(true), Float::ONE); @@ -1980,7 +1924,7 @@ float_test! { const f16: #[cfg(false)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(u16::MIN), Float::ZERO); assert_biteq!(Float::from(42_u16), 42.0); assert_biteq!(Float::from(u16::MAX), 65535.0); @@ -1999,7 +1943,7 @@ float_test! { const f32: #[cfg(false)], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { assert_biteq!(Float::from(u32::MIN), Float::ZERO); assert_biteq!(Float::from(42_u32), 42.0); assert_biteq!(Float::from(u32::MAX), 4294967295.0); @@ -2016,7 +1960,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { // The maximum integer that converts to a unique floating point // value. const MAX_EXACT_INTEGER: ::SInt = Float::MAX_EXACT_INTEGER; @@ -2058,7 +2002,7 @@ float_test! { f16: #[cfg(any(miri, target_has_reliable_f16))], f128: #[cfg(any(miri, target_has_reliable_f128))], }, - test { + test { // The minimum integer that converts to a unique floating point // value. const MIN_EXACT_INTEGER: ::SInt = Float::MIN_EXACT_INTEGER; @@ -2105,7 +2049,7 @@ float_test! { // f64: #[cfg(false)], // f128: #[cfg(any(miri, target_has_reliable_f128))], // }, -// test { +// test { // assert_biteq!(Float::from(u64::MIN), Float::ZERO); // assert_biteq!(Float::from(42_u64), 42.0); // assert_biteq!(Float::from(u64::MAX), 18446744073709551615.0); @@ -2123,7 +2067,7 @@ float_test! { f16: #[cfg(all(not(miri), target_has_reliable_f16_math))], f128: #[cfg(all(not(miri), target_has_reliable_f128_math))], }, - test { + test { let pi: Float = consts::PI; assert_approx_eq!(consts::FRAC_PI_2, pi / 2.0); assert_approx_eq!(consts::FRAC_PI_3, pi / 3.0, Float::APPROX); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 5e303a3c6b790..d04b9a2d6e136 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -90,11 +90,13 @@ #![feature(nonzero_from_str_radix)] #![feature(numfmt)] #![feature(one_sided_range)] +#![feature(panic_internals)] #![feature(pattern)] #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(result_option_map_or_default)] +#![feature(rustc_attrs)] #![feature(signed_bigint_helpers)] #![feature(slice_from_ptr_range)] #![feature(slice_index_methods)] diff --git a/library/std/src/sys/sync/once/mod.rs b/library/std/src/sys/sync/once/mod.rs index aeea884b9f617..5796c6d207dba 100644 --- a/library/std/src/sys/sync/once/mod.rs +++ b/library/std/src/sys/sync/once/mod.rs @@ -12,7 +12,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "motor", target_os = "openbsd", diff --git a/library/std/src/sys/sync/thread_parking/mod.rs b/library/std/src/sys/sync/thread_parking/mod.rs index 74b5b72b19a75..9d5a0a996b115 100644 --- a/library/std/src/sys/sync/thread_parking/mod.rs +++ b/library/std/src/sys/sync/thread_parking/mod.rs @@ -3,7 +3,7 @@ cfg_select! { all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", - all(target_arch = "wasm32", target_feature = "atomics"), + all(target_family = "wasm", target_feature = "atomics"), target_os = "freebsd", target_os = "openbsd", target_os = "dragonfly", diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index db7c7b69cba94..105e41ca45f63 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -696,7 +696,7 @@ def download_toolchain(self): for download_info in tarballs_download_info: download_component(download_info) - # Unpack the tarballs in parallle. + # Unpack the tarballs in parallel. # In Python 2.7, Pool cannot be used as a context manager. pool_size = min(len(tarballs_download_info), get_cpus()) if self.verbose: diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 81b06ea0c539b..c0d02aaa6ee88 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -8,7 +8,7 @@ //! Thank you! //! ~The `INTERNAL_METADATA_COLLECTOR` lint -use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan}; +use rustc_errors::{Applicability, Diag, Diagnostic, DiagCtxtHandle, DiagMessage, Level, MultiSpan}; #[cfg(debug_assertions)] use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions}; use rustc_hir::HirId; @@ -240,15 +240,27 @@ where M: Into, F: FnOnce(&mut Diag<'_, ()>), { + struct ClippyDiag)>(F); + + impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for ClippyDiag { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut lint = Diag::new(dcx, level, ""); + (self.0)(&mut lint); + lint + } + } + + let sp = sp.into(); #[expect(clippy::disallowed_methods)] - cx.span_lint(lint, sp, |diag| { + cx.emit_span_lint(lint, sp.clone(), ClippyDiag(|diag: &mut Diag<'_, ()>| { diag.primary_message(msg); + diag.span(sp); f(diag); docs_link(diag, lint); #[cfg(debug_assertions)] validate_diag(diag); - }); + })); } /// Like [`span_lint`], but emits the lint at the node identified by the given `HirId`. diff --git a/src/tools/rust-analyzer/.codecov.yml b/src/tools/rust-analyzer/.codecov.yml new file mode 100644 index 0000000000000..68eacb7d08cbb --- /dev/null +++ b/src/tools/rust-analyzer/.codecov.yml @@ -0,0 +1,10 @@ +coverage: + range: 40...60 + status: + patch: off + project: + default: + informational: true + +# Don't leave comments on PRs +comment: false diff --git a/src/tools/rust-analyzer/.github/workflows/coverage.yaml b/src/tools/rust-analyzer/.github/workflows/coverage.yaml new file mode 100644 index 0000000000000..bd4edba747ca1 --- /dev/null +++ b/src/tools/rust-analyzer/.github/workflows/coverage.yaml @@ -0,0 +1,44 @@ +name: Coverage + +on: [pull_request, push] + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CI: 1 + RUST_BACKTRACE: short + RUSTUP_MAX_RETRIES: 10 + +jobs: + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust toolchain + run: | + rustup update --no-self-update nightly + rustup default nightly + rustup component add --toolchain nightly rust-src rustc-dev rustfmt + # We also install a nightly rustfmt, because we use `--file-lines` in + # a test. + rustup toolchain install nightly --profile minimal --component rustfmt + + rustup toolchain install nightly --component llvm-tools-preview + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Install nextest + uses: taiki-e/install-action@nextest + + - name: Generate code coverage + run: cargo llvm-cov --workspace --lcov --output-path lcov.info + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v5 + with: + files: lcov.info + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + verbose: true diff --git a/src/tools/rust-analyzer/AGENTS.md b/src/tools/rust-analyzer/AGENTS.md new file mode 120000 index 0000000000000..681311eb9cf45 --- /dev/null +++ b/src/tools/rust-analyzer/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/src/tools/rust-analyzer/CLAUDE.md b/src/tools/rust-analyzer/CLAUDE.md new file mode 100644 index 0000000000000..e8f699d92813a --- /dev/null +++ b/src/tools/rust-analyzer/CLAUDE.md @@ -0,0 +1,40 @@ +**Reminder: All AI usage must be disclosed in commit messages, see +CONTRIBUTING.md for more details.** + +## Build Commands + +```bash +cargo build # Build all crates +cargo test # Run all tests +cargo test -p # Run tests for a specific crate (e.g., cargo test -p hir-ty) +cargo lint # Run clippy on all targets +cargo xtask codegen # Run code generation +cargo xtask tidy # Run tidy checks +UPDATE_EXPECT=1 cargo test # Update test expectations (snapshot tests) +RUN_SLOW_TESTS=1 cargo test # Run heavy/slow tests +``` + +## Key Architectural Invariants + +- Typing in a function body never invalidates global derived data +- Parser/syntax tree is built per-file to enable parallel parsing +- The server is stateless (HTTP-like); context must be re-created from request parameters +- Cancellation uses salsa's cancellation mechanism; computations panic with a `Cancelled` payload + +### Code Generation + +Generated code is committed to the repo. Grammar and AST are generated from `ungrammar`. Run `cargo test -p xtask` after adding inline parser tests (`// test test_name` comments). + +## Testing + +Tests are snapshot-based using `expect-test`. Test fixtures use a mini-language: +- `$0` marks cursor position +- `// ^^^^` labels attach to the line above +- `//- minicore: sized, fn` includes parts of minicore (minimal core library) +- `//- /path/to/file.rs crate:name deps:dep1,dep2` declares files/crates + +## Style Notes + +- Use `stdx::never!` and `stdx::always!` instead of `assert!` for recoverable invariants +- Use `T![fn]` macro instead of `SyntaxKind::FN_KW` +- Use keyword name mangling over underscore prefixing for identifiers: `crate` → `krate`, `fn` → `func`, `struct` → `strukt`, `type` → `ty` diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9db4dd7cb1a3a..f31dda4a107bc 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -2635,7 +2635,7 @@ dependencies = [ [[package]] name = "smol_str" -version = "0.3.5" +version = "0.3.6" dependencies = [ "arbitrary", "borsh", diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index ccd001df69b41..cb5eed1b8b6cd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -234,7 +234,7 @@ impl Visibility { if mod_.krate(db) == krate { Some(Visibility::Module(mod_, exp)) } else { None } } (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => { - if mod_a.krate(db) != mod_b.krate(db) { + if mod_a == mod_b { // Most module visibilities are `pub(self)`, and assuming no errors // this will be the common and thus fast path. return Some(Visibility::Module( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index ae8eef2bbb5d9..949b22b0adaa6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -5,10 +5,7 @@ use std::borrow::Cow; use base_db::AnchoredPath; use cfg::CfgExpr; use either::Either; -use intern::{ - Symbol, - sym, -}; +use intern::{Symbol, sym}; use itertools::Itertools; use mbe::{DelimiterKind, expect_fragment}; use span::{Edition, FileId, Span}; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 16e7d51e8734f..45b181eff8f0a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -658,7 +658,7 @@ impl<'db> InferenceContext<'_, 'db> { } } if let RecordSpread::Expr(expr) = *spread { - self.infer_expr(expr, &Expectation::has_type(ty), ExprIsRead::Yes); + self.infer_expr_coerce_never(expr, &Expectation::has_type(ty), ExprIsRead::Yes); } ty } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs index c79c828cd4420..95d63ffb508f6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/op.rs @@ -178,9 +178,9 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // trait matching creating lifetime constraints that are too strict. // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. - let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::No); + let lhs_ty = self.infer_expr_no_expect(lhs_expr, ExprIsRead::Yes); let fresh_var = self.table.next_ty_var(); - self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::No) + self.demand_coerce(lhs_expr, lhs_ty, fresh_var, AllowTwoPhase::No, ExprIsRead::Yes) } }; let lhs_ty = self.table.resolve_vars_with_obligations(lhs_ty); @@ -200,7 +200,7 @@ impl<'a, 'db> InferenceContext<'a, 'db> { // see `NB` above let rhs_ty = - self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::No); + self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty_var), ExprIsRead::Yes); let rhs_ty = self.table.resolve_vars_with_obligations(rhs_ty); let return_ty = match result { @@ -320,7 +320,11 @@ impl<'a, 'db> InferenceContext<'a, 'db> { if let Some((rhs_expr, rhs_ty)) = opt_rhs && rhs_ty.is_ty_var() { - self.infer_expr_coerce(rhs_expr, &Expectation::HasType(rhs_ty), ExprIsRead::No); + self.infer_expr_coerce( + rhs_expr, + &Expectation::HasType(rhs_ty), + ExprIsRead::Yes, + ); } // Construct an obligation `self_ty : Trait` diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index a0945c3bdce66..c49e943437933 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -40,8 +40,7 @@ use rustc_hash::FxHashSet; use rustc_type_ir::{ AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, - TyKind, - TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, + TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; use smallvec::SmallVec; @@ -1681,10 +1680,16 @@ impl SupertraitsInfo { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -enum TypeParamAssocTypeShorthandError { - AssocTypeNotFound, - AmbiguousAssocType, +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +enum AssocTypeShorthandResolution { + Resolved(StoredEarlyBinder<(TypeAliasId, StoredGenericArgs)>), + Ambiguous { + /// If one resolution belongs to a sub-trait and one to a supertrait, this contains + /// the sub-trait's resolution. This can be `None` if there is no trait inheritance + /// relationship between the resolutions. + sub_trait_resolution: Option>, + }, + NotFound, Cycle, } @@ -1708,7 +1713,7 @@ fn resolve_type_param_assoc_type_shorthand( def: GenericDefId, param: TypeParamId, assoc_name: Name, -) -> Result, TypeParamAssocTypeShorthandError> { +) -> AssocTypeShorthandResolution { let generics = generics(db, def); let resolver = def.resolver(db); let mut ctx = TyLoweringContext::new( @@ -1719,13 +1724,13 @@ fn resolve_type_param_assoc_type_shorthand( LifetimeElisionKind::AnonymousReportError, ); let interner = ctx.interner; - let mut result = None; let param_ty = Ty::new_param( interner, param, generics.type_or_const_param_idx(param.into()).unwrap() as u32, ); + let mut this_trait_resolution = None; if let GenericDefId::TraitId(containing_trait) = param.parent() && param.local_id() == GenericParams::SELF_PARAM_ID_IN_SELF { @@ -1734,10 +1739,11 @@ fn resolve_type_param_assoc_type_shorthand( containing_trait.trait_items(db).associated_type_by_name(&assoc_name) { let args = GenericArgs::identity_for_item(interner, containing_trait.into()); - result = Some(StoredEarlyBinder::bind((assoc_type, args.store()))); + this_trait_resolution = Some(StoredEarlyBinder::bind((assoc_type, args.store()))); } } + let mut supertraits_resolution = None; for maybe_parent_generics in std::iter::successors(Some(&generics), |generics| generics.parent_generics()) { @@ -1783,34 +1789,53 @@ fn resolve_type_param_assoc_type_shorthand( TypeParamId::trait_self(bounded_trait), assoc_name.clone(), ); - let lookup_on_bounded_trait = match lookup_on_bounded_trait { - Ok(it) => it, - Err( - err @ (TypeParamAssocTypeShorthandError::AmbiguousAssocType - | TypeParamAssocTypeShorthandError::Cycle), - ) => return Err(*err), - Err(TypeParamAssocTypeShorthandError::AssocTypeNotFound) => { + let assoc_type_and_args = match &lookup_on_bounded_trait { + AssocTypeShorthandResolution::Resolved(trait_ref) => trait_ref, + AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(trait_ref), + } => trait_ref, + AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None } => { + return AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: this_trait_resolution, + }; + } + AssocTypeShorthandResolution::NotFound => { never!("we checked that the trait defines this assoc type"); continue; } + AssocTypeShorthandResolution::Cycle => return AssocTypeShorthandResolution::Cycle, }; - let (assoc_type, args) = lookup_on_bounded_trait - .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) - .skip_binder(); - let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); - let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); - // If we already have a result, this is an ambiguity - unless this is the same result, then we are fine - // (e.g. rustc allows to write the same bound twice without ambiguity). - if let Some(existing_result) = result - && existing_result != current_result - { - return Err(TypeParamAssocTypeShorthandError::AmbiguousAssocType); + if let Some(this_trait_resolution) = this_trait_resolution { + return AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(this_trait_resolution), + }; + } else if supertraits_resolution.is_some() { + return AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: None }; + } else { + let (assoc_type, args) = assoc_type_and_args + .get_with(|(assoc_type, args)| (*assoc_type, args.as_ref())) + .skip_binder(); + let args = EarlyBinder::bind(args).instantiate(interner, bounded_trait_ref.args); + let current_result = StoredEarlyBinder::bind((assoc_type, args.store())); + supertraits_resolution = Some(match lookup_on_bounded_trait { + AssocTypeShorthandResolution::Resolved(_) => { + AssocTypeShorthandResolution::Resolved(current_result) + } + AssocTypeShorthandResolution::Ambiguous { .. } => { + AssocTypeShorthandResolution::Ambiguous { + sub_trait_resolution: Some(current_result), + } + } + AssocTypeShorthandResolution::NotFound + | AssocTypeShorthandResolution::Cycle => unreachable!(), + }); } - result = Some(current_result); } } - result.ok_or(TypeParamAssocTypeShorthandError::AssocTypeNotFound) + supertraits_resolution + .or_else(|| this_trait_resolution.map(AssocTypeShorthandResolution::Resolved)) + .unwrap_or(AssocTypeShorthandResolution::NotFound) } fn resolve_type_param_assoc_type_shorthand_cycle_result( @@ -1819,8 +1844,8 @@ fn resolve_type_param_assoc_type_shorthand_cycle_result( _def: GenericDefId, _param: TypeParamId, _assoc_name: Name, -) -> Result, TypeParamAssocTypeShorthandError> { - Err(TypeParamAssocTypeShorthandError::Cycle) +) -> AssocTypeShorthandResolution { + AssocTypeShorthandResolution::Cycle } #[inline] @@ -2468,7 +2493,7 @@ fn fn_sig_for_struct_constructor( let inputs_and_output = Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { - abi: FnAbi::RustCall, + abi: FnAbi::Rust, c_variadic: false, safety: Safety::Safe, inputs_and_output, @@ -2487,7 +2512,7 @@ fn fn_sig_for_enum_variant_constructor( let inputs_and_output = Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { - abi: FnAbi::RustCall, + abi: FnAbi::Rust, c_variadic: false, safety: Safety::Safe, inputs_and_output, @@ -2569,19 +2594,22 @@ pub(crate) fn associated_ty_item_bounds<'db>( EarlyBinder::bind(BoundExistentialPredicates::new_from_slice(&bounds)) } -pub(crate) fn associated_type_by_name_including_super_traits<'db>( +pub(crate) fn associated_type_by_name_including_super_traits_allow_ambiguity<'db>( db: &'db dyn HirDatabase, trait_ref: TraitRef<'db>, name: Name, ) -> Option<(TypeAliasId, GenericArgs<'db>)> { - let assoc_type = resolve_type_param_assoc_type_shorthand( - db, - trait_ref.def_id.0.into(), - TypeParamId::trait_self(trait_ref.def_id.0), - name.clone(), - ) - .as_ref() - .ok()?; + let (AssocTypeShorthandResolution::Resolved(assoc_type) + | AssocTypeShorthandResolution::Ambiguous { sub_trait_resolution: Some(assoc_type) }) = + resolve_type_param_assoc_type_shorthand( + db, + trait_ref.def_id.0.into(), + TypeParamId::trait_self(trait_ref.def_id.0), + name.clone(), + ) + else { + return None; + }; let (assoc_type, trait_args) = assoc_type .get_with(|(assoc_type, trait_args)| (*assoc_type, trait_args.as_ref())) .skip_binder(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs index d47d696259d54..79f29d370f5cd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs @@ -30,7 +30,10 @@ use crate::{ consteval::{unknown_const, unknown_const_as_generic}, db::HirDatabase, generics::{Generics, generics}, - lower::{GenericPredicateSource, LifetimeElisionKind, PathDiagnosticCallbackData}, + lower::{ + AssocTypeShorthandResolution, GenericPredicateSource, LifetimeElisionKind, + PathDiagnosticCallbackData, + }, next_solver::{ Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs, Predicate, ProjectionPredicate, Region, TraitRef, Ty, @@ -38,8 +41,8 @@ use crate::{ }; use super::{ - ImplTraitLoweringMode, TyLoweringContext, associated_type_by_name_including_super_traits, - const_param_ty_query, ty_query, + ImplTraitLoweringMode, TyLoweringContext, + associated_type_by_name_including_super_traits_allow_ambiguity, const_param_ty_query, ty_query, }; type CallbackData<'a> = @@ -482,12 +485,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed); let (assoc_type, trait_args) = match res { Some(TypeNs::GenericParam(param)) => { - let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( - db, - def, - param, - assoc_name.clone(), - ) else { + let AssocTypeShorthandResolution::Resolved(assoc_type) = + super::resolve_type_param_assoc_type_shorthand( + db, + def, + param, + assoc_name.clone(), + ) + else { return error_ty(); }; assoc_type @@ -500,12 +505,14 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }; let impl_trait = impl_trait.instantiate_identity(); // Searching for `Self::Assoc` in `impl Trait for Type` is like searching for `Self::Assoc` in `Trait`. - let Ok(assoc_type) = super::resolve_type_param_assoc_type_shorthand( - db, - impl_trait.def_id.0.into(), - TypeParamId::trait_self(impl_trait.def_id.0), - assoc_name.clone(), - ) else { + let AssocTypeShorthandResolution::Resolved(assoc_type) = + super::resolve_type_param_assoc_type_shorthand( + db, + impl_trait.def_id.0.into(), + TypeParamId::trait_self(impl_trait.def_id.0), + assoc_name.clone(), + ) + else { return error_ty(); }; let (assoc_type, trait_args) = assoc_type @@ -869,7 +876,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let interner = self.ctx.interner; self.current_or_prev_segment.args_and_bindings.map(|args_and_bindings| { args_and_bindings.bindings.iter().enumerate().flat_map(move |(binding_idx, binding)| { - let found = associated_type_by_name_including_super_traits( + let found = associated_type_by_name_including_super_traits_allow_ambiguity( self.ctx.db, trait_ref, binding.name.clone(), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs index 80d1ea4aa4d00..1813abab86e7b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/next_solver/abi.rs @@ -62,7 +62,6 @@ impl<'db> rustc_type_ir::inherent::Abi> for FnAbi { } fn is_rust(self) -> bool { - // TODO: rustc does not consider `RustCall` to be true here, but Chalk does - matches!(self, FnAbi::Rust | FnAbi::RustCall) + matches!(self, FnAbi::Rust) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs index e4e7b4cc38859..993293bb56857 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs @@ -802,6 +802,37 @@ fn foo() { ); } +#[test] +fn binop_rhs_never_place_diverges() { + check_no_mismatches( + r#" +//- minicore: sized, add +fn foo() -> i32 { + unsafe { + let p: *mut ! = 0 as _; + let mut x: i32 = 0; + x += *p; + } +} +"#, + ); +} + +#[test] +fn binop_lhs_never_place_diverges() { + check_no_mismatches( + r#" +//- minicore: sized, add +fn foo() { + unsafe { + let p: *mut ! = 0 as _; + *p += 1; + } +} +"#, + ); +} + #[test] fn never_place_isnt_diverging() { check_infer_with_mismatches( @@ -855,3 +886,18 @@ fn foo() { "#]], ); } + +#[test] +fn never_coercion_in_struct_update_syntax() { + check_no_mismatches( + r#" +struct Struct { + field: i32, +} + +fn example() -> Struct { + Struct { ..loop {} } +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 658c304aac012..1939db0ef5a76 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -2795,3 +2795,23 @@ fn foo() { "#]], ); } + +#[test] +fn regression_21742() { + check_no_mismatches( + r#" +pub trait IntoIterator { + type Item; +} + +pub trait Collection: IntoIterator::Item> { + type Item; + fn contains(&self, item: &::Item); +} + +fn contains_0>(points: &S) { + points.contains(&0) +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index cdf7b40003b5b..74e9a8dac0e79 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -2217,6 +2217,40 @@ fn test() { ); } +#[test] +fn tuple_struct_constructor_as_fn_trait() { + check_types( + r#" +//- minicore: fn +struct S(u32, u64); + +fn takes_fn S>(f: F) -> S { f(1, 2) } + +fn test() { + takes_fn(S); + //^^^^^^^^^^^ S +} +"#, + ); +} + +#[test] +fn enum_variant_constructor_as_fn_trait() { + check_types( + r#" +//- minicore: fn +enum E { A(u32) } + +fn takes_fn E>(f: F) -> E { f(1) } + +fn test() { + takes_fn(E::A); + //^^^^^^^^^^^^^^ E +} +"#, + ); +} + #[test] fn fn_item_fn_trait() { check_types( diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 9dbee16dae6b7..11d79e2d7bf85 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -5952,7 +5952,16 @@ impl<'db> Type<'db> { ) -> R { let module = resolver.module(); let interner = DbInterner::new_with(db, module.krate(db)); - let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis); + // Most IDE operations want to operate in PostAnalysis mode, revealing opaques. This makes + // for a nicer IDE experience. However, method resolution is always done on real code (either + // existing code or code to be inserted), and there using PostAnalysis is dangerous - we may + // suggest invalid methods. So we're using the TypingMode of the body we're in. + let typing_mode = if let Some(body_owner) = resolver.body_owner() { + TypingMode::analysis_in_body(interner, body_owner.into()) + } else { + TypingMode::non_body_analysis() + }; + let infcx = interner.infer_ctxt().build(typing_mode); let unstable_features = MethodResolutionUnstableFeatures::from_def_map(resolver.top_level_def_map()); let environment = param_env_from_resolver(db, resolver); @@ -6149,6 +6158,13 @@ impl<'db> Type<'db> { Some(adt.into()) } + /// Holes in the args can come from lifetime/const params. + pub fn as_adt_with_args(&self) -> Option<(Adt, Vec>>)> { + let (adt, args) = self.ty.as_adt()?; + let args = args.iter().map(|arg| Some(self.derived(arg.ty()?))).collect(); + Some((adt.into(), args)) + } + pub fn as_builtin(&self) -> Option { self.ty.as_builtin().map(|inner| BuiltinType { inner }) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 4bc757da44174..1cf3b98160820 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -1819,6 +1819,28 @@ impl<'db> SemanticsImpl<'db> { self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr) } + /// The type that the associated `try` block, closure or function expects. + pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option> { + self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| { + if let Some(try_block) = ast::BlockExpr::cast(parent.clone()) + && try_block.try_block_modifier().is_some() + { + Some(self.type_of_expr(&try_block.into())?.original) + } else if let Some(closure) = ast::ClosureExpr::cast(parent.clone()) { + Some( + self.type_of_expr(&closure.into())? + .original + .as_callable(self.db)? + .return_type(), + ) + } else if let Some(function) = ast::Fn::cast(parent) { + Some(self.to_def(&function)?.ret_type(self.db)) + } else { + None + } + }) + } + // This does not resolve the method call to the correct trait impl! // We should probably fix that. pub fn resolve_method_call_as_callable( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 10c3ff0e4d2be..c0ce057d7798d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -44,8 +44,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) let arm_list_range = ctx.sema.original_range_opt(match_arm_list.syntax())?; if cursor_at_trivial_match_arm_list(ctx, &match_expr, &match_arm_list).is_none() { - let arm_list_range = ctx.sema.original_range(match_arm_list.syntax()).range; - let cursor_in_range = arm_list_range.contains_range(ctx.selection_trimmed()); + let cursor_in_range = arm_list_range.range.contains_range(ctx.selection_trimmed()); if cursor_in_range { cov_mark::hit!(not_applicable_outside_of_range_right); return None; @@ -348,8 +347,8 @@ fn cursor_at_trivial_match_arm_list( // $0 // } if let Some(last_arm) = match_arm_list.arms().last() { - let last_arm_range = last_arm.syntax().text_range(); - let match_expr_range = match_expr.syntax().text_range(); + let last_arm_range = ctx.sema.original_range_opt(last_arm.syntax())?.range; + let match_expr_range = ctx.sema.original_range_opt(match_expr.syntax())?.range; if last_arm_range.end() <= ctx.offset() && ctx.offset() < match_expr_range.end() { cov_mark::hit!(add_missing_match_arms_end_of_last_arm); return Some(()); @@ -1612,6 +1611,38 @@ fn foo(t: Test) { Test::B => ${2:todo!()}, Test::C => ${3:todo!()},$0 }); +}"#, + ); + + check_assist( + add_missing_match_arms, + r#" +macro_rules! m { ($expr:expr) => {$expr}} +enum Test { + A, + B, + C, +} + +fn foo(t: Test) { + m!(match t { + Test::A => (), + $0}); +}"#, + r#" +macro_rules! m { ($expr:expr) => {$expr}} +enum Test { + A, + B, + C, +} + +fn foo(t: Test) { + m!(match t { + Test::A=>(), + Test::B => ${1:todo!()}, + Test::C => ${2:todo!()},$0 + }); }"#, ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index bb5d11221087e..4c4cee1d7811f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -1,15 +1,19 @@ -use hir::HasVisibility; +use hir::{HasVisibility, Semantics}; use ide_db::{ - FxHashMap, FxHashSet, + FxHashMap, FxHashSet, RootDatabase, assists::AssistId, defs::Definition, helpers::mod_path_to_ast, search::{FileReference, SearchScope}, }; use itertools::Itertools; -use syntax::ast::{HasName, syntax_factory::SyntaxFactory}; use syntax::syntax_editor::SyntaxEditor; use syntax::{AstNode, Edition, SmolStr, SyntaxNode, ToSmolStr, ast}; +use syntax::{ + SyntaxToken, + ast::{HasName, edit::IndentLevel, syntax_factory::SyntaxFactory}, + syntax_editor::Position, +}; use crate::{ assist_context::{AssistContext, Assists, SourceChangeBuilder}, @@ -44,33 +48,90 @@ use crate::{ // } // ``` pub(crate) fn destructure_struct_binding(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let ident_pat = ctx.find_node_at_offset::()?; - let data = collect_data(ident_pat, ctx)?; + let target = ctx.find_node_at_offset::()?; + let data = collect_data(target, ctx)?; acc.add( AssistId::refactor_rewrite("destructure_struct_binding"), "Destructure struct binding", - data.ident_pat.syntax().text_range(), + data.target.syntax().text_range(), |edit| destructure_struct_binding_impl(ctx, edit, &data), ); Some(()) } +enum Target { + IdentPat(ast::IdentPat), + SelfParam { param: ast::SelfParam, insert_after: SyntaxToken }, +} + +impl Target { + fn ty<'db>(&self, sema: &Semantics<'db, RootDatabase>) -> Option> { + match self { + Target::IdentPat(pat) => sema.type_of_binding_in_pat(pat), + Target::SelfParam { param, .. } => sema.type_of_self(param), + } + } + + fn is_ref(&self) -> bool { + match self { + Target::IdentPat(ident_pat) => ident_pat.ref_token().is_some(), + Target::SelfParam { .. } => false, + } + } + + fn is_mut(&self) -> bool { + match self { + Target::IdentPat(ident_pat) => ident_pat.mut_token().is_some(), + Target::SelfParam { param, .. } => { + param.mut_token().is_some() && param.amp_token().is_none() + } + } + } +} + +impl HasName for Target {} + +impl AstNode for Target { + fn cast(node: SyntaxNode) -> Option { + if ast::IdentPat::can_cast(node.kind()) { + ast::IdentPat::cast(node).map(Self::IdentPat) + } else { + let param = ast::SelfParam::cast(node)?; + let param_list = param.syntax().parent().and_then(ast::ParamList::cast)?; + let block = param_list.syntax().parent()?.children().find_map(ast::BlockExpr::cast)?; + let insert_after = block.stmt_list()?.l_curly_token()?; + Some(Self::SelfParam { param, insert_after }) + } + } + + fn can_cast(kind: syntax::SyntaxKind) -> bool { + ast::IdentPat::can_cast(kind) || ast::SelfParam::can_cast(kind) + } + + fn syntax(&self) -> &SyntaxNode { + match self { + Target::IdentPat(ident_pat) => ident_pat.syntax(), + Target::SelfParam { param, .. } => param.syntax(), + } + } +} + fn destructure_struct_binding_impl( ctx: &AssistContext<'_>, builder: &mut SourceChangeBuilder, data: &StructEditData, ) { let field_names = generate_field_names(ctx, data); - let mut editor = builder.make_editor(data.ident_pat.syntax()); + let mut editor = builder.make_editor(data.target.syntax()); destructure_pat(ctx, &mut editor, data, &field_names); update_usages(ctx, &mut editor, data, &field_names.into_iter().collect()); builder.add_file_edits(ctx.vfs_file_id(), editor); } struct StructEditData { - ident_pat: ast::IdentPat, + target: Target, name: ast::Name, kind: hir::StructKind, struct_def_path: hir::ModPath, @@ -83,11 +144,44 @@ struct StructEditData { edition: Edition, } -fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option { - let ty = ctx.sema.type_of_binding_in_pat(&ident_pat)?; +impl StructEditData { + fn apply_to_destruct( + &self, + new_pat: ast::Pat, + editor: &mut SyntaxEditor, + make: &SyntaxFactory, + ) { + match &self.target { + Target::IdentPat(pat) => { + // If the binding is nested inside a record, we need to wrap the new + // destructured pattern in a non-shorthand record field + if self.need_record_field_name { + let new_pat = + make.record_pat_field(make.name_ref(&self.name.to_string()), new_pat); + editor.replace(pat.syntax(), new_pat.syntax()) + } else { + editor.replace(pat.syntax(), new_pat.syntax()) + } + } + Target::SelfParam { insert_after, .. } => { + let indent = IndentLevel::from_token(insert_after) + 1; + let newline = make.whitespace(&format!("\n{indent}")); + let initializer = make.expr_path(make.ident_path("self")); + let let_stmt = make.let_stmt(new_pat, None, Some(initializer)); + editor.insert_all( + Position::after(insert_after), + vec![newline.into(), let_stmt.syntax().clone().into()], + ); + } + } + } +} + +fn collect_data(target: Target, ctx: &AssistContext<'_>) -> Option { + let ty = target.ty(&ctx.sema)?; let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None }; - let module = ctx.sema.scope(ident_pat.syntax())?.module(); + let module = ctx.sema.scope(target.syntax())?.module(); let cfg = ctx.config.find_path_config(ctx.sema.is_nightly(module.krate(ctx.db()))); let struct_def = hir::ModuleDef::from(struct_type); let kind = struct_type.kind(ctx.db()); @@ -116,15 +210,17 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option ctx.sema.to_def(pat), + Target::SelfParam { param, .. } => ctx.sema.to_def(param), + }; + let usages = def .and_then(|def| { Definition::Local(def) .usages(&ctx.sema) @@ -136,11 +232,11 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option) -> Option, - ident_pat: &ast::IdentPat, + target: &Target, usages: &[FileReference], ) -> Option> { fn last_usage(usages: &[FileReference]) -> Option { @@ -165,7 +261,7 @@ fn get_names_in_scope( // If available, find names visible to the last usage of the binding // else, find names visible to the binding itself let last_usage = last_usage(usages); - let node = last_usage.as_ref().unwrap_or(ident_pat.syntax()); + let node = last_usage.as_ref().unwrap_or(target.syntax()); let scope = ctx.sema.scope(node)?; let mut names = FxHashSet::default(); @@ -183,12 +279,9 @@ fn destructure_pat( data: &StructEditData, field_names: &[(SmolStr, SmolStr)], ) { - let ident_pat = &data.ident_pat; - let name = &data.name; - let struct_path = mod_path_to_ast(&data.struct_def_path, data.edition); - let is_ref = ident_pat.ref_token().is_some(); - let is_mut = ident_pat.mut_token().is_some(); + let is_ref = data.target.is_ref(); + let is_mut = data.target.is_mut(); let make = SyntaxFactory::with_mappings(); let new_pat = match data.kind { @@ -221,16 +314,8 @@ fn destructure_pat( hir::StructKind::Unit => make.path_pat(struct_path), }; - // If the binding is nested inside a record, we need to wrap the new - // destructured pattern in a non-shorthand record field - let destructured_pat = if data.need_record_field_name { - make.record_pat_field(make.name_ref(&name.to_string()), new_pat).syntax().clone() - } else { - new_pat.syntax().clone() - }; - + data.apply_to_destruct(new_pat, editor, &make); editor.add_mappings(make.finish_with_mappings()); - editor.replace(data.ident_pat.syntax(), destructured_pat); } fn generate_field_names(ctx: &AssistContext<'_>, data: &StructEditData) -> Vec<(SmolStr, SmolStr)> { @@ -698,6 +783,84 @@ mod tests { ) } + #[test] + fn mut_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(mut $0self) { + self.bar = 5; + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(mut self) { + let Foo { mut bar, mut baz } = self; + bar = 5; + } + } + "#, + ) + } + + #[test] + fn ref_mut_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&mut $0self) { + self.bar = 5; + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&mut self) { + let Foo { bar, baz } = self; + *bar = 5; + } + } + "#, + ) + } + + #[test] + fn ref_self_param() { + check_assist( + destructure_struct_binding, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&$0self) -> &i32 { + &self.bar + } + } + "#, + r#" + struct Foo { bar: i32, baz: i32 } + + impl Foo { + fn foo(&self) -> &i32 { + let Foo { bar, baz } = self; + bar + } + } + "#, + ) + } + #[test] fn ref_not_add_parenthesis_and_deref_record() { check_assist( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index b8dc59f87dee7..d51a3a26a3c7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -164,6 +164,7 @@ enum RefType { Mutable, } struct TupleData { + // FIXME: After removing ted, it may be possible to reuse destructure_struct_binding::Target ident_pat: IdentPat, ref_type: Option, field_names: Vec, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index fdc5a0fbda359..b4c347ff36a7c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -567,7 +567,8 @@ fn main() { match 92 { x => if true && true - && true { + && true + { { false } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index dcadb5368d525..8ff30fce5b5d4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -972,7 +972,8 @@ fn main() { fn main() { if true { match path.strip_prefix(root_path) - .and(x) { + .and(x) + { Ok(rel_path) => { let rel_path = RelativePathBuf::from_path(rel_path) .ok()?; @@ -1012,7 +1013,8 @@ fn main() { fn main() { if true { match path.strip_prefix(root_path) - .and(x) { + .and(x) + { Ok(rel_path) => { Foo { x: 1 @@ -1046,7 +1048,8 @@ fn main() { fn main() { if true { match true - && false { + && false + { true => foo(), false => (), } @@ -1925,7 +1928,8 @@ fn main() { fn main() { if true { if let Ok(rel_path) = path.strip_prefix(root_path) - .and(x) { + .and(x) + { Foo { x: 2 } @@ -1965,7 +1969,8 @@ fn main() { fn main() { if true { if let Ok(rel_path) = path.strip_prefix(root_path) - .and(x) { + .and(x) + { let rel_path = RelativePathBuf::from_path(rel_path) .ok()?; Some((*id, rel_path)) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index a58592b1365b8..ea53aef40c2e7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -16,7 +16,7 @@ use itertools::Itertools; use stdx::never; use syntax::{ SmolStr, - SyntaxKind::{BLOCK_EXPR, EXPR_STMT, STMT_LIST}, + SyntaxKind::{EXPR_STMT, STMT_LIST}, T, TextRange, TextSize, ToSmolStr, ast::{self, AstNode, AstToken}, format_smolstr, match_ast, @@ -52,6 +52,7 @@ pub(crate) fn complete_postfix( _ => return, }; let expr_ctx = &dot_access.ctx; + let receiver_accessor = receiver_accessor(dot_receiver); let receiver_text = get_receiver_text(&ctx.sema, dot_receiver, receiver_is_ambiguous_float_literal); @@ -90,7 +91,7 @@ pub(crate) fn complete_postfix( // The rest of the postfix completions create an expression that moves an argument, // so it's better to consider references now to avoid breaking the compilation - let (dot_receiver_including_refs, prefix) = include_references(dot_receiver); + let (dot_receiver_including_refs, prefix) = include_references(&receiver_accessor); let mut receiver_text = receiver_text; receiver_text.insert_str(0, &prefix); let postfix_snippet = @@ -111,13 +112,8 @@ pub(crate) fn complete_postfix( .add_to(acc, ctx.db); let try_enum = TryEnum::from_ty(&ctx.sema, receiver_ty); - let mut is_in_cond = false; - if let Some(parent) = dot_receiver_including_refs.syntax().parent() - && let Some(second_ancestor) = parent.parent() - { - if let Some(parent_expr) = ast::Expr::cast(parent) { - is_in_cond = is_in_condition(&parent_expr); - } + let is_in_cond = is_in_condition(&dot_receiver_including_refs); + if let Some(parent) = dot_receiver_including_refs.syntax().parent() { let placeholder = suggest_receiver_name(dot_receiver, "0", &ctx.sema); match &try_enum { Some(try_enum) if is_in_cond => match try_enum { @@ -154,13 +150,13 @@ pub(crate) fn complete_postfix( postfix_snippet("let", "let", &format!("let $1 = {receiver_text}")) .add_to(acc, ctx.db); } - _ if matches!(second_ancestor.kind(), STMT_LIST | EXPR_STMT | BLOCK_EXPR) => { + _ if matches!(parent.kind(), STMT_LIST | EXPR_STMT) => { postfix_snippet("let", "let", &format!("let $0 = {receiver_text};")) .add_to(acc, ctx.db); postfix_snippet("letm", "let mut", &format!("let mut $0 = {receiver_text};")) .add_to(acc, ctx.db); } - _ if ast::MatchArm::can_cast(second_ancestor.kind()) => { + _ if ast::MatchArm::can_cast(parent.kind()) => { postfix_snippet( "let", "let", @@ -305,7 +301,7 @@ pub(crate) fn complete_postfix( postfix_snippet("const", "const {}", &const_completion_string).add_to(acc, ctx.db); } - if let ast::Expr::Literal(literal) = dot_receiver_including_refs.clone() + if let ast::Expr::Literal(literal) = dot_receiver.clone() && let Some(literal_text) = ast::String::cast(literal.token()) { add_format_like_completions(acc, ctx, &dot_receiver_including_refs, cap, &literal_text); @@ -392,14 +388,22 @@ fn escape_snippet_bits(text: &mut String) { stdx::replace(text, '$', "\\$"); } +fn receiver_accessor(receiver: &ast::Expr) -> ast::Expr { + receiver + .syntax() + .parent() + .and_then(ast::Expr::cast) + .filter(|it| { + matches!( + it, + ast::Expr::FieldExpr(_) | ast::Expr::MethodCallExpr(_) | ast::Expr::CallExpr(_) + ) + }) + .unwrap_or_else(|| receiver.clone()) +} + fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) { let mut resulting_element = initial_element.clone(); - - while let Some(field_expr) = resulting_element.syntax().parent().and_then(ast::FieldExpr::cast) - { - resulting_element = ast::Expr::from(field_expr); - } - let mut prefix = String::new(); let mut found_ref_or_deref = false; @@ -898,6 +902,30 @@ fn main() { bar => bar.$0 } } +"#, + expect![[r#" + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); + check( + r#" +fn main() { + match 2 { + bar => &bar.l$0 + } +} "#, expect![[r#" sn box Box::new(expr) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 5fef8c44deb12..8e50ef10eca65 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -3659,3 +3659,38 @@ fn main() { "#]], ); } + +#[test] +fn rpitit_with_reference() { + check( + r#" +trait Foo { + fn foo(&self); +} + +trait Bar { + fn bar(&self) -> &impl Foo; +} + +fn baz(v: impl Bar) { + v.bar().$0 +} + "#, + expect![[r#" + me foo() (as Foo) fn(&self) + sn box Box::new(expr) + sn call function(expr) + sn const const {} + sn dbg dbg!(expr) + sn dbgr dbg!(&expr) + sn deref *expr + sn let let + sn letm let mut + sn match match expr {} + sn ref &expr + sn refm &mut expr + sn return return expr + sn unsafe unsafe {} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 3c3ac9d3bbe61..3890bcad7fc61 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -95,6 +95,13 @@ pub(crate) fn goto_definition( continue; } + let parent = token.value.parent()?; + + if let Some(question_mark_conversion) = goto_question_mark_conversions(sema, &parent) { + navs.extend(def_to_nav(sema, question_mark_conversion.into())); + continue; + } + if let Some(token) = ast::String::cast(token.value.clone()) && let Some(original_token) = ast::String::cast(original_token.clone()) && let Some((analysis, fixture_analysis)) = @@ -113,8 +120,6 @@ pub(crate) fn goto_definition( }); } - let parent = token.value.parent()?; - let token_file_id = token.file_id; if let Some(token) = ast::String::cast(token.value.clone()) && let Some(x) = @@ -149,6 +154,45 @@ pub(crate) fn goto_definition( Some(RangeInfo::new(original_token.text_range(), navs)) } +/// When the `?` operator is used on `Result`, go to the `From` impl if it exists as this provides more value. +fn goto_question_mark_conversions( + sema: &Semantics<'_, RootDatabase>, + node: &SyntaxNode, +) -> Option { + let node = ast::TryExpr::cast(node.clone())?; + let try_expr_ty = sema.type_of_expr(&node.expr()?)?.adjusted(); + + let fd = FamousDefs(sema, try_expr_ty.krate(sema.db)); + let result_enum = fd.core_result_Result()?.into(); + + let (try_expr_ty_adt, try_expr_ty_args) = try_expr_ty.as_adt_with_args()?; + if try_expr_ty_adt != result_enum { + // FIXME: Support `Poll`. + return None; + } + let original_err_ty = try_expr_ty_args.get(1)?.clone()?; + + let returned_ty = sema.try_expr_returned_type(&node)?; + let (returned_adt, returned_ty_args) = returned_ty.as_adt_with_args()?; + if returned_adt != result_enum { + return None; + } + let returned_err_ty = returned_ty_args.get(1)?.clone()?; + + if returned_err_ty.could_unify_with_deeply(sema.db, &original_err_ty) { + return None; + } + + let from_trait = fd.core_convert_From()?; + let from_fn = from_trait.function(sema.db, sym::from)?; + sema.resolve_trait_impl_method( + returned_err_ty.clone(), + from_trait, + from_fn, + [returned_err_ty, original_err_ty], + ) +} + // If the token is into(), try_into(), search the definition of From, TryFrom. fn find_definition_for_known_blanket_dual_impls( sema: &Semantics<'_, RootDatabase>, @@ -4034,4 +4078,25 @@ where "#, ) } + + #[test] + fn question_mark_on_result_goes_to_conversion() { + check( + r#" +//- minicore: try, result, from + +struct Foo; +struct Bar; +impl From for Bar { + fn from(_: Foo) -> Bar { Bar } + // ^^^^ +} + +fn foo() -> Result<(), Bar> { + Err(Foo)?$0; + Ok(()) +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs index 9c7f109a626c3..9ce88484f781f 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_config_file.rs @@ -164,7 +164,7 @@ pub(crate) fn make_lockfile_copy( major: 1, minor: 95, patch: 0, - pre: semver::Prerelease::new("nightly").unwrap(), + pre: semver::Prerelease::new("beta").unwrap(), build: semver::BuildMetadata::EMPTY, }; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 98d759aef2093..f5d1d009a579b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -644,7 +644,8 @@ pub fn expr_await(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("{expr}.await")) } pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { - expr_from_text(&format!("match {expr} {match_arm_list}")) + let ws = block_whitespace(&expr); + expr_from_text(&format!("match {expr}{ws}{match_arm_list}")) } pub fn expr_if( condition: ast::Expr, @@ -656,14 +657,17 @@ pub fn expr_if( Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), None => String::new(), }; - expr_from_text(&format!("if {condition} {then_branch} {else_branch}")) + let ws = block_whitespace(&condition); + expr_from_text(&format!("if {condition}{ws}{then_branch} {else_branch}")) } pub fn expr_for_loop(pat: ast::Pat, expr: ast::Expr, block: ast::BlockExpr) -> ast::ForExpr { - expr_from_text(&format!("for {pat} in {expr} {block}")) + let ws = block_whitespace(&expr); + expr_from_text(&format!("for {pat} in {expr}{ws}{block}")) } pub fn expr_while_loop(condition: ast::Expr, block: ast::BlockExpr) -> ast::WhileExpr { - expr_from_text(&format!("while {condition} {block}")) + let ws = block_whitespace(&condition); + expr_from_text(&format!("while {condition}{ws}{block}")) } pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { @@ -723,6 +727,9 @@ pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::BinExpr { fn expr_from_text + AstNode>(text: &str) -> E { ast_from_text(&format!("const C: () = {text};")) } +fn block_whitespace(after: &impl AstNode) -> &'static str { + if after.syntax().text().contains_char('\n') { "\n" } else { " " } +} pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { ast_from_text(&format!("const _: () = while let {pattern} = {expr} {{}};")) } @@ -880,8 +887,9 @@ pub fn ref_pat(pat: ast::Pat) -> ast::RefPat { pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) -> ast::MatchArm { let comma_str = if expr.is_block_like() { "" } else { "," }; + let ws = guard.as_ref().filter(|_| expr.is_block_like()).map_or(" ", block_whitespace); return match guard { - Some(guard) => from_text(&format!("{pat} {guard} => {expr}{comma_str}")), + Some(guard) => from_text(&format!("{pat} {guard} =>{ws}{expr}{comma_str}")), None => from_text(&format!("{pat} => {expr}{comma_str}")), }; @@ -890,19 +898,6 @@ pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) } } -pub fn match_arm_with_guard( - pats: impl IntoIterator, - guard: ast::Expr, - expr: ast::Expr, -) -> ast::MatchArm { - let pats_str = pats.into_iter().join(" | "); - return from_text(&format!("{pats_str} if {guard} => {expr}")); - - fn from_text(text: &str) -> ast::MatchArm { - ast_from_text(&format!("fn f() {{ match () {{{text}}} }}")) - } -} - pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard { return from_text(&format!("if {condition}")); diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index d3fbea2336b0b..be0bdc8d55bbf 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -749,9 +749,9 @@ } }, "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -810,9 +810,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -934,29 +934,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1851,9 +1828,9 @@ } }, "node_modules/@vscode/vsce/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3463,9 +3440,9 @@ } }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -3907,17 +3884,40 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/glob/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4895,13 +4895,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6840,9 +6840,9 @@ } }, "node_modules/vscode-languageclient/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs index c216864bee8c2..84748bbca8d77 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs @@ -18,6 +18,12 @@ impl Default for ReqQueue { } } +impl ReqQueue { + pub fn has_pending(&self) -> bool { + self.incoming.has_pending() || self.outgoing.has_pending() + } +} + #[derive(Debug)] pub struct Incoming { pending: HashMap, @@ -51,6 +57,10 @@ impl Incoming { pub fn is_completed(&self, id: &RequestId) -> bool { !self.pending.contains_key(id) } + + pub fn has_pending(&self) -> bool { + !self.pending.is_empty() + } } impl Outgoing { @@ -64,4 +74,8 @@ impl Outgoing { pub fn complete(&mut self, id: RequestId) -> Option { self.pending.remove(&id) } + + pub fn has_pending(&self) -> bool { + !self.pending.is_empty() + } } diff --git a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md index 4aa25fa13446f..6327275d07dcb 100644 --- a/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md +++ b/src/tools/rust-analyzer/lib/smol_str/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## 0.3.6 - 2026-03-04 +- Fix the `borsh` feature. + ## 0.3.5 - 2026-01-08 - Optimise `SmolStr::clone` 4-5x speedup inline, 0.5x heap (slow down). diff --git a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml index 4e7844b49e195..22068fe8418b4 100644 --- a/src/tools/rust-analyzer/lib/smol_str/Cargo.toml +++ b/src/tools/rust-analyzer/lib/smol_str/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smol_str" -version = "0.3.5" +version = "0.3.6" description = "small-string optimized string type with O(1) clone" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/smol_str" diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index b6e1b2bc55df4..7c89bcb9ab045 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -c78a29473a68f07012904af11c92ecffa68fcc75 +f8704be04fe1150527fc2cf21dd44327f0fe87fb diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml index ac4efd0a24bcb..5fd97f52d8c2c 100644 --- a/src/tools/rust-analyzer/triagebot.toml +++ b/src/tools/rust-analyzer/triagebot.toml @@ -24,4 +24,5 @@ labels = ["has-merge-commits", "S-waiting-on-author"] [transfer] # Canonicalize issue numbers to avoid closing the wrong issue when upstreaming this subtree -[canonicalize-issue-links] +[issue-links] +check-commits = "uncanonicalized" diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs index 205072a6ce0cf..564d9cc24efe8 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar/ast_src.rs @@ -189,9 +189,9 @@ pub(crate) fn generate_kind_src( } } }); - PUNCT.iter().zip(used_puncts).filter(|(_, used)| !used).for_each(|((punct, _), _)| { + if let Some(punct) = PUNCT.iter().zip(used_puncts).find(|(_, used)| !used) { panic!("Punctuation {punct:?} is not used in grammar"); - }); + } keywords.extend(RESERVED.iter().copied()); keywords.sort(); keywords.dedup(); diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 51b73351fe6a5..d34706a2ba5cd 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -1553,7 +1553,10 @@ pub(crate) fn can_be_overflowed_expr( } // Handle always block-like expressions - ast::ExprKind::Gen(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true, + ast::ExprKind::Gen(..) + | ast::ExprKind::Block(..) + | ast::ExprKind::Closure(..) + | ast::ExprKind::TryBlock(..) => true, // Handle `[]` and `{}`-like expressions ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => { diff --git a/src/tools/rustfmt/tests/source/try_block.rs b/src/tools/rustfmt/tests/source/try_block.rs index e324a13317584..62f0492f96620 100644 --- a/src/tools/rustfmt/tests/source/try_block.rs +++ b/src/tools/rustfmt/tests/source/try_block.rs @@ -27,5 +27,13 @@ fn baz() -> Option { let x: Option = try { baz()?; baz()?; baz()?; 7 }; + let _ = overflowed_expr( + x, + try { + foo()?; + bar()?; + }, + ); + return None; } diff --git a/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs b/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs index 7a1135cfbc764..056bedafef6cb 100644 --- a/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs +++ b/src/tools/rustfmt/tests/source/try_blocks_heterogeneous.rs @@ -35,5 +35,15 @@ fn baz() -> Option { let x = try bikeshed Foo {}; + let x = try bikeshed Result {}; + + let _ = overflowed_expr( + x, + try bikeshed Option<_> { + foo()?; + bar()?; + }, + ); + return None; } diff --git a/src/tools/rustfmt/tests/target/try_block.rs b/src/tools/rustfmt/tests/target/try_block.rs index 61da123b735d8..f9d9909f524fe 100644 --- a/src/tools/rustfmt/tests/target/try_block.rs +++ b/src/tools/rustfmt/tests/target/try_block.rs @@ -26,5 +26,10 @@ fn baz() -> Option { 7 }; + let _ = overflowed_expr(x, try { + foo()?; + bar()?; + }); + return None; } diff --git a/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs b/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs index 018d53ed35e41..ce0a3cf704bbf 100644 --- a/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs +++ b/src/tools/rustfmt/tests/target/try_blocks_heterogeneous.rs @@ -37,5 +37,16 @@ fn baz() -> Option { let x = try bikeshed Foo {}; + let x = try bikeshed Result< + VeryVeryVeryVeryVeryLongTypeForSuccess, + VeryVeryVeryVeryVeryLongTypeForFailure, + > { + }; + + let _ = overflowed_expr(x, try bikeshed Option<_> { + foo()?; + bar()?; + }); + return None; } diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index e2f106e565439..5973f63bbae9e 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -39,7 +39,7 @@ // Const generic parameter //@ gdb-command:info functions -q function_names::const_generic_fn.* //@ gdb-check:[...]static fn function_names::const_generic_fn_bool(); -//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ffa3db4ca1d52dce}>(); +//@ gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#6dd80cc0c950c171}>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); //@ gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); diff --git a/tests/pretty/paren-trait-bound.rs b/tests/pretty/paren-trait-bound.rs new file mode 100644 index 0000000000000..98e75308abfe8 --- /dev/null +++ b/tests/pretty/paren-trait-bound.rs @@ -0,0 +1,11 @@ +//@ pp-exact + +trait Dummy {} + +// Without parens, `+ Send` would bind to `dyn Dummy` instead of the outer `dyn`. +fn f1(_: Box Box) + Send>) {} + +// Without parens, `+ Send + Sync` would bind to `dyn Dummy` instead of the outer `impl`. +fn f2(_: impl (FnMut(&mut u8) -> &mut dyn Dummy) + Send + Sync) {} + +fn main() {} diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index 00cc31170b74f..6add008aa60fa 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -162,9 +162,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -173,9 +173,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -183,9 +183,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -193,9 +193,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 25 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 23bdcc2272950..ab345f9e42e96 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -144,9 +144,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -155,9 +155,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -165,9 +165,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -175,9 +175,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 22 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index ef1f1b53cdc56..e2ca35d6a50e2 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -156,9 +156,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -177,9 +177,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 24 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index ef1f1b53cdc56..e2ca35d6a50e2 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -156,9 +156,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -177,9 +177,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 24 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 0c338849ae9d8..41842eecbd020 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -138,9 +138,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "cdecl" is not a supported ABI for the current target @@ -149,9 +149,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -159,9 +159,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -169,9 +169,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 21 previous errors; 4 warnings emitted diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 07c4eb691fe97..79938f04c5996 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -106,9 +106,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default warning: "stdcall" is not a supported ABI for the current target @@ -117,9 +117,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "stdcall-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:92:1 @@ -127,9 +127,9 @@ warning: "stdcall-unwind" is not a supported ABI for the current target LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:100:17 @@ -137,9 +137,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:105:1 @@ -147,9 +147,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "cdecl-unwind" is not a supported ABI for the current target --> $DIR/unsupported.rs:108:1 @@ -157,9 +157,9 @@ warning: "cdecl-unwind" is not a supported ABI for the current target LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C-unwind"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C-unwind"` instead warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:137:1 @@ -167,9 +167,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead warning: "stdcall" is not a supported ABI for the current target --> $DIR/unsupported.rs:78:1 @@ -177,9 +177,9 @@ warning: "stdcall" is not a supported ABI for the current target LL | extern "stdcall" fn stdcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: "cdecl" is not a supported ABI for the current target --> $DIR/unsupported.rs:97:1 @@ -187,9 +187,9 @@ warning: "cdecl" is not a supported ABI for the current target LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: use `extern "C"` instead = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: use `extern "C"` instead error: aborting due to 17 previous errors; 9 warnings emitted diff --git a/tests/ui/const-generics/type-const-ice-issue-151631.rs b/tests/ui/const-generics/type-const-ice-issue-151631.rs new file mode 100644 index 0000000000000..53c6d0c6dd6d4 --- /dev/null +++ b/tests/ui/const-generics/type-const-ice-issue-151631.rs @@ -0,0 +1,18 @@ +// issue: +//@ compile-flags: -Znext-solver +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait SuperTrait {} +trait Trait: SuperTrait { + type const K: u32; +} +impl Trait for () { //~ ERROR: the trait bound `(): SuperTrait` is not satisfied + type const K: u32 = const { 1 }; +} + +fn check(_: impl Trait) {} + +fn main() { + check(()); //~ ERROR: the trait bound `(): SuperTrait` is not satisfied +} diff --git a/tests/ui/const-generics/type-const-ice-issue-151631.stderr b/tests/ui/const-generics/type-const-ice-issue-151631.stderr new file mode 100644 index 0000000000000..6f287293e27cf --- /dev/null +++ b/tests/ui/const-generics/type-const-ice-issue-151631.stderr @@ -0,0 +1,37 @@ +error[E0277]: the trait bound `(): SuperTrait` is not satisfied + --> $DIR/type-const-ice-issue-151631.rs:10:16 + | +LL | impl Trait for () { + | ^^ the trait `SuperTrait` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/type-const-ice-issue-151631.rs:6:1 + | +LL | trait SuperTrait {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/type-const-ice-issue-151631.rs:7:14 + | +LL | trait Trait: SuperTrait { + | ^^^^^^^^^^ required by this bound in `Trait` + +error[E0277]: the trait bound `(): SuperTrait` is not satisfied + --> $DIR/type-const-ice-issue-151631.rs:17:5 + | +LL | check(()); + | ^^^^^^^^^ the trait `SuperTrait` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/type-const-ice-issue-151631.rs:6:1 + | +LL | trait SuperTrait {} + | ^^^^^^^^^^^^^^^^ +note: required by a bound in `Trait` + --> $DIR/type-const-ice-issue-151631.rs:7:14 + | +LL | trait Trait: SuperTrait { + | ^^^^^^^^^^ required by this bound in `Trait` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr index c33d5b003042e..e8fdfc3d6136e 100644 --- a/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr +++ b/tests/ui/consts/const-eval/const_panic_stability.e2018.stderr @@ -4,9 +4,9 @@ warning: panic message is not a string literal LL | panic!({ "foo" }); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr b/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr index e2517ab342f45..2b8326018bc93 100644 --- a/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr +++ b/tests/ui/enum-discriminant/repr-c-big-discriminant1.ptr64.stderr @@ -4,10 +4,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = 9223372036854775807, // i64::MAX | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 note: the lint level is defined here --> $DIR/repr-c-big-discriminant1.rs:8:9 | @@ -20,10 +20,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = -2147483649, // i32::MIN-1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `unsigned int`, and a previous discriminant does not fit into C `int` --> $DIR/repr-c-big-discriminant1.rs:36:5 @@ -31,10 +31,10 @@ error: `repr(C)` enum discriminant does not fit into C `unsigned int`, and a pre LL | B = -1, | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `int`, and a previous discriminant does not fit into C `unsigned int` --> $DIR/repr-c-big-discriminant1.rs:43:5 @@ -42,10 +42,10 @@ error: `repr(C)` enum discriminant does not fit into C `int`, and a previous dis LL | A = 2147483648, // i32::MAX+1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigned int` --> $DIR/repr-c-big-discriminant1.rs:53:5 @@ -53,10 +53,10 @@ error: `repr(C)` enum discriminant does not fit into C `int` nor into C `unsigne LL | A = I64_MAX as isize, | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 error: aborting due to 5 previous errors diff --git a/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr b/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr index 8cd978ccb2fb1..ebf14059b314d 100644 --- a/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr +++ b/tests/ui/enum-discriminant/repr-c-big-discriminant2.ptr64.stderr @@ -4,10 +4,10 @@ error: `repr(C)` enum discriminant does not fit into C `int`, and a previous dis LL | B, // +1 | ^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #124403 = note: `repr(C)` enums with big discriminants are non-portable, and their size in Rust might not match their size in C = help: use `repr($int_ty)` instead to explicitly set the size of this enum + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #124403 note: the lint level is defined here --> $DIR/repr-c-big-discriminant2.rs:8:9 | diff --git a/tests/ui/imports/ambiguous-panic-pick-core.stderr b/tests/ui/imports/ambiguous-panic-pick-core.stderr index 0a43c83934acc..5c4c881f6bc73 100644 --- a/tests/ui/imports/ambiguous-panic-pick-core.stderr +++ b/tests/ui/imports/ambiguous-panic-pick-core.stderr @@ -24,9 +24,9 @@ warning: panic message is not a string literal LL | panic!(&std::string::String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/imports/ambiguous-panic-pick-std.stderr b/tests/ui/imports/ambiguous-panic-pick-std.stderr index 53e51afe051c2..8938450d1c579 100644 --- a/tests/ui/imports/ambiguous-panic-pick-std.stderr +++ b/tests/ui/imports/ambiguous-panic-pick-std.stderr @@ -24,9 +24,9 @@ warning: panic message is not a string literal LL | panic!(std::string::String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see = note: `#[warn(non_fmt_panics)]` (part of `#[warn(rust_2021_compatibility)]`) on by default help: add a "{}" format string to `Display` the message | diff --git a/tests/ui/inference/inference_unstable.stderr b/tests/ui/inference/inference_unstable.stderr index 0072175d51403..b547293052a2a 100644 --- a/tests/ui/inference/inference_unstable.stderr +++ b/tests/ui/inference/inference_unstable.stderr @@ -4,9 +4,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_flatten(), 1); | ^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_flatten(...)` to keep using the current method = note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_flatten` | @@ -19,9 +19,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_by_value_vs_by_ref(), 1); | ^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_value_vs_by_ref(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_value_vs_by_ref(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_value_vs_by_ref` | LL + #![feature(ipu_flatten)] @@ -33,9 +33,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!('x'.ipu_by_ref_vs_by_ref_mut(), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_ref_vs_by_ref_mut(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_ref_vs_by_ref_mut(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_ref_vs_by_ref_mut` | LL + #![feature(ipu_flatten)] @@ -47,9 +47,9 @@ warning: a method with this name may be added to the standard library in the fut LL | assert_eq!((&mut 'x' as *mut char).ipu_by_mut_ptr_vs_by_const_ptr(), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_mut_ptr_vs_by_const_ptr(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `inference_unstable_itertools::IpuItertools::ipu_by_mut_ptr_vs_by_const_ptr(...)` to keep using the current method help: add `#![feature(ipu_flatten)]` to the crate attributes to enable `inference_unstable_iterator::IpuIterator::ipu_by_mut_ptr_vs_by_const_ptr` | LL + #![feature(ipu_flatten)] diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index 5a574636245d3..9d945eb23491c 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr @@ -9,9 +9,9 @@ LL | | LL | | } | |_^ | + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #137018 - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` = note: `#[warn(unsupported_calling_conventions)]` (part of `#[warn(future_incompatible)]`) on by default error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr index ff1e54f5dea30..8f234c6216065 100644 --- a/tests/ui/lint/future-incompatible-lint-group.stderr +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -14,8 +14,6 @@ error: ambiguous associated item LL | fn foo() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57644 note: `V` could refer to the variant defined here --> $DIR/future-incompatible-lint-group.rs:8:10 | @@ -26,6 +24,8 @@ note: `V` could also refer to the associated type defined here | LL | type V; | ^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57644 note: the lint level is defined here --> $DIR/future-incompatible-lint-group.rs:6:9 | diff --git a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr index ef23f3ca6c919..82eacf901d25d 100644 --- a/tests/ui/lint/improper-ctypes/lint-ctypes.stderr +++ b/tests/ui/lint/improper-ctypes/lint-ctypes.stderr @@ -218,7 +218,7 @@ warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct TransparentCustomZst(i32, ZeroSize); | ^^^^^^^^ | + = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. diff --git a/tests/ui/lint/improper-ctypes/lint-fn.stderr b/tests/ui/lint/improper-ctypes/lint-fn.stderr index a0d1ab232c6ad..45681cc9f1122 100644 --- a/tests/ui/lint/improper-ctypes/lint-fn.stderr +++ b/tests/ui/lint/improper-ctypes/lint-fn.stderr @@ -169,7 +169,7 @@ warning: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct TransparentCustomZst(i32, ZeroSize); | ^^^^^^^^ | + = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ZeroSize`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. diff --git a/tests/ui/macros/non-fmt-panic.stderr b/tests/ui/macros/non-fmt-panic.stderr index 9cadaf3fbe388..959fcf6bfcf61 100644 --- a/tests/ui/macros/non-fmt-panic.stderr +++ b/tests/ui/macros/non-fmt-panic.stderr @@ -78,9 +78,9 @@ warning: panic message is not a string literal LL | assert!(false, S); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", S); @@ -92,9 +92,9 @@ warning: panic message is not a string literal LL | assert!(false, 123); | ^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", 123); @@ -106,9 +106,9 @@ warning: panic message is not a string literal LL | assert!(false, Some(123)); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | assert!(false, "{:?}", Some(123)); @@ -133,9 +133,9 @@ warning: panic message is not a string literal LL | panic!(C); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", C); @@ -147,9 +147,9 @@ warning: panic message is not a string literal LL | panic!(S); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", S); @@ -161,9 +161,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); @@ -175,9 +175,9 @@ warning: panic message is not a string literal LL | unreachable!(S); | ^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", S); @@ -189,9 +189,9 @@ warning: panic message is not a string literal LL | std::panic!(123); | ^^^ | - = note: for more information, see = note: this usage of `std::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | std::panic!("{}", 123); @@ -208,9 +208,9 @@ warning: panic message is not a string literal LL | core::panic!(&*"abc"); | ^^^^^^^ | - = note: for more information, see = note: this usage of `core::panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | core::panic!("{}", &*"abc"); @@ -222,9 +222,9 @@ warning: panic message is not a string literal LL | panic!(Some(123)); | ^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `Option` | LL | panic!("{:?}", Some(123)); @@ -280,9 +280,9 @@ warning: panic message is not a string literal LL | panic!(a!()); | ^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", a!()); @@ -299,9 +299,9 @@ warning: panic message is not a string literal LL | unreachable!(a!()); | ^^^^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | unreachable!("{}", a!()); @@ -313,10 +313,10 @@ warning: panic message is not a string literal LL | panic!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `panic!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - panic!(format!("{}", 1)); @@ -329,10 +329,10 @@ warning: panic message is not a string literal LL | unreachable!(format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `unreachable!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `unreachable!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - unreachable!(format!("{}", 1)); @@ -345,10 +345,10 @@ warning: panic message is not a string literal LL | assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `assert!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - assert!(false, format!("{}", 1)); @@ -361,10 +361,10 @@ warning: panic message is not a string literal LL | debug_assert!(false, format!("{}", 1)); | ^^^^^^^^^^^^^^^^ | - = note: for more information, see = note: this usage of `debug_assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see = note: the `debug_assert!()` macro supports formatting, so there's no need for the `format!()` macro here + = note: for more information, see help: remove the `format!(..)` macro call | LL - debug_assert!(false, format!("{}", 1)); @@ -377,9 +377,9 @@ warning: panic message is not a string literal LL | panic![123]; | ^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!["{}", 123]; @@ -396,9 +396,9 @@ warning: panic message is not a string literal LL | panic!{123}; | ^^^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!{"{}", 123}; @@ -415,9 +415,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: use std::panic::panic_any instead | LL - panic!(v); @@ -430,9 +430,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see warning: panic message is not a string literal --> $DIR/non-fmt-panic.rs:84:12 @@ -440,9 +440,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | panic!("{:?}", v); @@ -459,9 +459,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{:?}" format string to use the `Debug` implementation of `T` | LL | assert!(false, "{:?}", v); @@ -473,9 +473,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); @@ -492,9 +492,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); @@ -506,9 +506,9 @@ warning: panic message is not a string literal LL | panic!(v); | ^ | - = note: for more information, see = note: this usage of `panic!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | panic!("{}", v); @@ -525,9 +525,9 @@ warning: panic message is not a string literal LL | assert!(false, v); | ^ | - = note: for more information, see = note: this usage of `assert!()` is deprecated; it will be a hard error in Rust 2021 = note: for more information, see + = note: for more information, see help: add a "{}" format string to `Display` the message | LL | assert!(false, "{}", v); diff --git a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs new file mode 100644 index 0000000000000..23d5d4c9e1096 --- /dev/null +++ b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.rs @@ -0,0 +1,14 @@ +// Regression test for #152694 +// Verify that we don't emit invalid suggestions (adding `ref` or `clone()`) +// when a destructuring assignment involves a type that implements `Drop`. + +struct Thing(String); + +impl Drop for Thing { + fn drop(&mut self) {} +} + +fn main() { + Thing(*&mut String::new()) = Thing(String::new()); + //~^ ERROR cannot move out of type `Thing`, which implements the `Drop` trait +} diff --git a/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr new file mode 100644 index 0000000000000..c2bc85ee6beee --- /dev/null +++ b/tests/ui/moves/invalid-suggestions-destructuring-assignment-drop.stderr @@ -0,0 +1,12 @@ +error[E0509]: cannot move out of type `Thing`, which implements the `Drop` trait + --> $DIR/invalid-suggestions-destructuring-assignment-drop.rs:12:34 + | +LL | Thing(*&mut String::new()) = Thing(String::new()); + | ------------------- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here + | | + | data moved here + | move occurs because the place has type `String`, which does not implement the `Copy` trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0509`. diff --git a/tests/ui/offset-of/offset-of-error-recovery.rs b/tests/ui/offset-of/offset-of-error-recovery.rs new file mode 100644 index 0000000000000..659140877cd14 --- /dev/null +++ b/tests/ui/offset-of/offset-of-error-recovery.rs @@ -0,0 +1,14 @@ +use std::mem::offset_of; + +struct S { + x: (), +} + +impl S { + fn a() { + offset_of!(Self, Self::x); + //~^ ERROR offset_of expects dot-separated field and variant names + } +} + +fn main() {} diff --git a/tests/ui/offset-of/offset-of-error-recovery.stderr b/tests/ui/offset-of/offset-of-error-recovery.stderr new file mode 100644 index 0000000000000..fce3616c213ec --- /dev/null +++ b/tests/ui/offset-of/offset-of-error-recovery.stderr @@ -0,0 +1,8 @@ +error: offset_of expects dot-separated field and variant names + --> $DIR/offset-of-error-recovery.rs:9:26 + | +LL | offset_of!(Self, Self::x); + | ^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed new file mode 100644 index 0000000000000..6a73475f202f4 --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.fixed @@ -0,0 +1,23 @@ +#![allow(dead_code)] +#![allow(unused)] +//@ run-rustfix + +mod m { + pub(crate) struct S { + pub(crate) visible: u64, + hidden: u64, + } + + impl S { + pub(crate) fn new() -> Self { + loop {} + } + } +} + +fn main() { + let m::S { + //~^ ERROR pattern requires `..` due to inaccessible fields + visible, .. + } = m::S::new(); +} diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs new file mode 100644 index 0000000000000..1a4fed68381a1 --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.rs @@ -0,0 +1,23 @@ +#![allow(dead_code)] +#![allow(unused)] +//@ run-rustfix + +mod m { + pub(crate) struct S { + pub(crate) visible: u64, + hidden: u64, + } + + impl S { + pub(crate) fn new() -> Self { + loop {} + } + } +} + +fn main() { + let m::S { + //~^ ERROR pattern requires `..` due to inaccessible fields + visible, + } = m::S::new(); +} diff --git a/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr new file mode 100644 index 0000000000000..4eacdecc6810c --- /dev/null +++ b/tests/ui/privacy/inaccessible-private-fields-trailing-comma-149787.stderr @@ -0,0 +1,17 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/inaccessible-private-fields-trailing-comma-149787.rs:19:9 + | +LL | let m::S { + | _________^ +LL | | +LL | | visible, +LL | | } = m::S::new(); + | |_____^ + | +help: ignore the inaccessible and unused fields + | +LL | visible, .. + | ++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr index ac5493bf7e59c..0a575e5f5829d 100644 --- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr +++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr @@ -4,9 +4,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T5(Sized, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -19,9 +19,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:54:23 @@ -29,9 +29,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` | ^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:59:22 @@ -39,9 +39,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T7(Sized, NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:64:22 @@ -49,9 +49,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T8(Sized, NonExhaustiveVariant); | ^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:69:22 @@ -59,9 +59,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:74:23 @@ -69,9 +69,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T10(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:79:23 @@ -79,9 +79,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T11(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:84:23 @@ -89,9 +89,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T12(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:89:23 @@ -99,9 +99,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T13(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:94:23 @@ -109,9 +109,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:99:23 @@ -119,9 +119,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T15(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:104:23 @@ -129,9 +129,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T16(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:109:16 @@ -139,9 +139,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T17(NonExhaustive, Sized); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:114:31 @@ -149,9 +149,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T18(NonExhaustive, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external types with private fields --> $DIR/repr-transparent-non-exhaustive.rs:119:31 @@ -159,9 +159,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T19(NonExhaustive, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types --> $DIR/repr-transparent-non-exhaustive.rs:124:32 @@ -169,9 +169,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T19Flipped(Private, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. error: aborting due to 17 previous errors @@ -182,9 +182,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T5(Sized, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -198,9 +198,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -214,9 +214,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` | ^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -230,9 +230,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T7(Sized, NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -246,9 +246,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T8(Sized, NonExhaustiveVariant); | ^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -262,9 +262,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -278,9 +278,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T10(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -294,9 +294,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T11(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -310,9 +310,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T12(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -326,9 +326,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T13(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -342,9 +342,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -358,9 +358,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T15(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -374,9 +374,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T16(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -390,9 +390,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T17(NonExhaustive, Sized); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -406,9 +406,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T18(NonExhaustive, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -422,9 +422,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external types wi LL | pub struct T19(NonExhaustive, Private); | ^^^^^^^ | + = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `Private`, which contains private fields, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | @@ -438,9 +438,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exha LL | pub struct T19Flipped(Private, NonExhaustive); | ^^^^^^^^^^^^^ | + = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future. note: the lint level is defined here --> $DIR/repr-transparent-non-exhaustive.rs:1:9 | diff --git a/tests/ui/repr/repr-transparent-repr-c.stderr b/tests/ui/repr/repr-transparent-repr-c.stderr index 5724845afdc1e..2a670fed80704 100644 --- a/tests/ui/repr/repr-transparent-repr-c.stderr +++ b/tests/ui/repr/repr-transparent-repr-c.stderr @@ -4,9 +4,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T5(Sized, ReprC1Zst); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -19,9 +19,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T6(ReprC1Zst, Sized); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types --> $DIR/repr-transparent-repr-c.rs:28:15 @@ -29,9 +29,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type | ^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. error: aborting due to 3 previous errors @@ -42,9 +42,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T5(Sized, ReprC1Zst); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -58,9 +58,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T6(ReprC1Zst, Sized); | ^^^^^^^^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | @@ -74,9 +74,9 @@ error: zero-sized fields in `repr(transparent)` cannot contain `repr(C)` types LL | pub struct T7(T1, Sized); // still wrong, even when the repr(C) is hidden inside another type | ^^ | + = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #78586 - = note: this field contains `ReprC1Zst`, which is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets. note: the lint level is defined here --> $DIR/repr-transparent-repr-c.rs:1:9 | diff --git a/tests/ui/repr/repr_align_greater_usize.msp430.stderr b/tests/ui/repr/repr_align_greater_usize.msp430.stderr index a7b06acb6752b..4fcd33d50d749 100644 --- a/tests/ui/repr/repr_align_greater_usize.msp430.stderr +++ b/tests/ui/repr/repr_align_greater_usize.msp430.stderr @@ -1,18 +1,14 @@ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:23:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:23:14 | LL | #[repr(align(32768))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ -error[E0589]: alignment must not be greater than `isize::MAX` bytes - --> $DIR/repr_align_greater_usize.rs:26:8 +error[E0589]: invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) + --> $DIR/repr_align_greater_usize.rs:26:14 | LL | #[repr(align(65536))] - | ^^^^^^^^^^^^ - | - = note: `isize::MAX` is 32767 for the current target + | ^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/repr/repr_align_greater_usize.rs b/tests/ui/repr/repr_align_greater_usize.rs index 52a4d23b1eca2..7df1fbe762661 100644 --- a/tests/ui/repr/repr_align_greater_usize.rs +++ b/tests/ui/repr/repr_align_greater_usize.rs @@ -20,8 +20,8 @@ use minicore::*; #[repr(align(16384))] struct Kitten; -#[repr(align(32768))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(32768))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct Cat; -#[repr(align(65536))] //[msp430]~ ERROR alignment must not be greater than `isize::MAX` +#[repr(align(65536))] //[msp430]~ ERROR invalid `repr(align)` attribute: alignment larger than `isize::MAX` bytes (32767 for the current target) [E0589] struct BigCat; diff --git a/tests/ui/resolve/slice-as-slice.stderr b/tests/ui/resolve/slice-as-slice.stderr index c93363431c595..f22a0dd6ac58e 100644 --- a/tests/ui/resolve/slice-as-slice.stderr +++ b/tests/ui/resolve/slice-as-slice.stderr @@ -4,9 +4,9 @@ warning: a method with this name may be added to the standard library in the fut LL | b(data.as_slice()); | ^^^^^^^^ | + = help: call with fully qualified syntax `ComponentSlice::as_slice(...)` to keep using the current method = warning: once this associated item is added to the standard library, the ambiguity may cause an error or change in behavior! = note: for more information, see issue #48919 - = help: call with fully qualified syntax `ComponentSlice::as_slice(...)` to keep using the current method = note: `#[warn(unstable_name_collisions)]` (part of `#[warn(future_incompatible)]`) on by default help: add `#![feature(str_as_str)]` to the crate attributes to enable `core::slice::::as_slice` | diff --git a/tests/ui/statics/uninhabited-static.stderr b/tests/ui/statics/uninhabited-static.stderr index a0f9ad6772de5..4762784574dc7 100644 --- a/tests/ui/statics/uninhabited-static.stderr +++ b/tests/ui/statics/uninhabited-static.stderr @@ -4,9 +4,9 @@ error: static of uninhabited type LL | static VOID2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error note: the lint level is defined here --> $DIR/uninhabited-static.rs:2:9 | @@ -19,9 +19,9 @@ error: static of uninhabited type LL | static NEVER2: Void = unsafe { std::mem::transmute(()) }; | ^^^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type --> $DIR/uninhabited-static.rs:6:5 @@ -29,9 +29,9 @@ error: static of uninhabited type LL | static VOID: Void; | ^^^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error: static of uninhabited type --> $DIR/uninhabited-static.rs:8:5 @@ -39,9 +39,9 @@ error: static of uninhabited type LL | static NEVER: !; | ^^^^^^^^^^^^^^^ | + = note: uninhabited statics cannot be initialized, and any access would be an immediate error = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #74840 - = note: uninhabited statics cannot be initialized, and any access would be an immediate error error[E0080]: constructing invalid value: encountered a value of uninhabited type `Void` --> $DIR/uninhabited-static.rs:12:31 diff --git a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr index 79bd1f2adc17b..918d05b5d6781 100644 --- a/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr +++ b/tests/ui/type-alias-enum-variants/enum-variant-priority-lint-ambiguous_associated_items.stderr @@ -4,8 +4,6 @@ error: ambiguous associated item LL | fn f() -> Self::V { 0 } | ^^^^^^^ help: use fully-qualified syntax: `::V` | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57644 note: `V` could refer to the variant defined here --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5 | @@ -16,6 +14,8 @@ note: `V` could also refer to the associated type defined here | LL | type V; | ^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57644 = note: `#[deny(ambiguous_associated_items)]` (part of `#[deny(future_incompatible)]`) on by default error: aborting due to 1 previous error diff --git a/triagebot.toml b/triagebot.toml index 8d6401c490561..14184e8f2683a 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1620,6 +1620,7 @@ dep-bumps = [ "/src/tools/rustdoc" = ["rustdoc"] "/src/tools/rustdoc-js" = ["rustdoc"] "/src/tools/rustdoc-themes" = ["rustdoc"] +"/src/tools/rustfmt" = ["rustfmt", "rustfmt-contributors"] "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] "/src/tools/rustdoc-gui-test" = ["bootstrap"]