diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 6a0d70790cfef..626b7e1084192 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -5,6 +5,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_index::Idx; use rustc_index::bit_set::SparseBitMatrix; use rustc_index::interval::{IntervalSet, SparseIntervalMatrix}; +use rustc_middle::bug; use rustc_middle::mir::{BasicBlock, Location}; use rustc_middle::ty::{self, RegionVid}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; @@ -35,6 +36,17 @@ pub(crate) enum RegionElement<'tcx> { PlaceholderRegion(ty::PlaceholderRegion<'tcx>), } +/// Either a mapping of which points a region is live at (for regular bodies), +/// or which regions are live in the body somewhere (for promoteds, which do +/// not care about where they are live, only that they are). +#[derive(Clone)] // FIXME(#146079) +enum LiveRegions { + /// region `'r` is live at locations `L`. + AtPoints(SparseIntervalMatrix), + /// Region `'r` is live in function body. + InBody(FxHashSet), +} + /// Records the CFG locations where each region is live. When we initially compute liveness, we use /// an interval matrix storing liveness ranges for each region-vid. #[derive(Clone)] // FIXME(#146079) @@ -42,15 +54,8 @@ pub(crate) struct LivenessValues { /// The map from locations to points. location_map: Rc, - /// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and - /// currently only used for validating promoteds (which don't care about more precise tracking). - live_regions: Option>, - - /// For each region: the points where it is live. - /// - /// This is not initialized for promoteds, because we don't care *where* within a promoted a - /// region is live, only that it is. - points: Option>, + /// Where a region is live. + live_regions: LiveRegions, /// When using `-Zpolonius=next`, the set of loans that are live at a given point in the CFG. live_loans: Option, @@ -60,8 +65,9 @@ impl LivenessValues { /// Create an empty map of regions to locations where they're live. pub(crate) fn with_specific_points(location_map: Rc) -> Self { LivenessValues { - live_regions: None, - points: Some(SparseIntervalMatrix::new(location_map.num_points())), + live_regions: LiveRegions::AtPoints(SparseIntervalMatrix::new( + location_map.num_points(), + )), location_map, live_loans: None, } @@ -73,8 +79,7 @@ impl LivenessValues { /// which regions are live. pub(crate) fn without_specific_points(location_map: Rc) -> Self { LivenessValues { - live_regions: Some(Default::default()), - points: None, + live_regions: LiveRegions::InBody(Default::default()), location_map, live_loans: None, } @@ -83,14 +88,16 @@ impl LivenessValues { /// Returns the liveness matrix of points where each region is live. Panics if the liveness /// values have been created without any per-point data (that is, for promoteds). pub(crate) fn points(&self) -> &SparseIntervalMatrix { - self.points - .as_ref() - .expect("this `LivenessValues` wasn't created using `with_specific_points`") + if let LiveRegions::AtPoints(points) = &self.live_regions { + points + } else { + bug!("this `LivenessValues` wasn't created using `with_specific_points`") + } } /// Iterate through each region that has a value in this set. pub(crate) fn regions(&self) -> impl Iterator { - self.points.as_ref().expect("use with_specific_points").rows() + self.points().rows() } /// Iterate through each region that has a value in this set. @@ -98,36 +105,53 @@ impl LivenessValues { #[rustc_lint_query_instability] #[allow(rustc::potential_query_instability)] pub(crate) fn live_regions_unordered(&self) -> impl Iterator { - self.live_regions.as_ref().unwrap().iter().copied() + if let LiveRegions::InBody(live_regions) = &self.live_regions { + live_regions.iter().copied() + } else { + bug!("this `LivenessValues` wasn't created using `without_specific_points`") + } } /// Records `region` as being live at the given `location`. pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { let point = self.location_map.point_from_location(location); debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); - if let Some(points) = &mut self.points { - points.insert(region, point); - } else if self.location_map.point_in_range(point) { - self.live_regions.as_mut().unwrap().insert(region); - } + match &mut self.live_regions { + LiveRegions::AtPoints(points) => { + points.insert(region, point); + } + + LiveRegions::InBody(live_regions) if self.location_map.point_in_range(point) => { + live_regions.insert(region); + } + + LiveRegions::InBody(_) => (), + }; } /// Records `region` as being live at all the given `points`. pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet) { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); - if let Some(this) = &mut self.points { - this.union_row(region, points); - } else if points.iter().any(|point| self.location_map.point_in_range(point)) { - self.live_regions.as_mut().unwrap().insert(region); - } + match &mut self.live_regions { + LiveRegions::AtPoints(these_points) => { + these_points.union_row(region, points); + } + LiveRegions::InBody(live_regions) + if points.iter().any(|point| self.location_map.point_in_range(point)) => + { + live_regions.insert(region); + } + LiveRegions::InBody(_) => (), + }; } /// Records `region` as being live at all the control-flow points. pub(crate) fn add_all_points(&mut self, region: RegionVid) { - if let Some(points) = &mut self.points { - points.insert_all_into_row(region); - } else { - self.live_regions.as_mut().unwrap().insert(region); + match &mut self.live_regions { + LiveRegions::AtPoints(points) => points.insert_all_into_row(region), + LiveRegions::InBody(live_regions) => { + live_regions.insert(region); + } } } @@ -142,23 +166,12 @@ impl LivenessValues { /// [`point`][rustc_mir_dataflow::points::PointIndex]. #[inline] pub(crate) fn is_live_at_point(&self, region: RegionVid, point: PointIndex) -> bool { - if let Some(points) = &self.points { - points.row(region).is_some_and(|r| r.contains(point)) - } else { - unreachable!( - "Should be using LivenessValues::with_specific_points to ask whether live at a location" - ) - } + self.points().row(region).is_some_and(|r| r.contains(point)) } /// Returns an iterator of all the points where `region` is live. fn live_points(&self, region: RegionVid) -> impl Iterator { - let Some(points) = &self.points else { - unreachable!( - "Should be using LivenessValues::with_specific_points to ask whether live at a location" - ) - }; - points + self.points() .row(region) .into_iter() .flat_map(|set| set.iter()) @@ -328,10 +341,7 @@ impl<'tcx, N: Idx> RegionValues<'tcx, N> { /// elements for the region `from` from `values` and add them to /// the region `to` in `self`. pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) { - let Some(value_points) = &values.points else { - panic!("LivenessValues must track specific points for use in merge_liveness"); - }; - if let Some(set) = value_points.row(from) { + if let Some(set) = values.points().row(from) { self.points.union_row(to, set); } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 1dee2f34371e8..b4a97c0b137c9 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -844,14 +844,13 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // current number of evaluated terminators is a power of 2. The latter gives us a cheap // way to implement exponential backoff. let span = ecx.cur_span(); + let mut warn = + ecx.tcx.dcx().create_warn(LongRunningWarn { span, item_span: ecx.tcx.span }); // We store a unique number in `force_duplicate` to evade `-Z deduplicate-diagnostics`. // `new_steps` is guaranteed to be unique because `ecx.machine.num_evaluated_steps` is // always increasing. - ecx.tcx.dcx().emit_warn(LongRunningWarn { - span, - item_span: ecx.tcx.span, - force_duplicate: new_steps, - }); + warn.arg("force_duplicate", new_steps); + warn.emit(); } } diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 311696a3acc99..9faf9a59fc22a 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -298,8 +298,6 @@ pub(crate) struct LongRunningWarn { pub span: Span, #[help("the constant being evaluated")] pub item_span: Span, - // Used for evading `-Z deduplicate-diagnostics`. - pub force_duplicate: usize, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d51a0bf2c3ef4..7d687099f9715 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -845,7 +845,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut path = None; let mut err = self.dcx().create_err(errors::InvalidCallee { span: callee_expr.span, - ty: callee_ty, found: match &unit_variant { Some((_, kind, path)) => format!("{kind} `{path}`"), None => format!("`{}`", self.tcx.short_string(callee_ty, &mut path)), @@ -949,7 +948,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let Some(span) = self.tcx.hir_res_span(def) { - let callee_ty = callee_ty.to_string(); let label = match (unit_variant, inner_callee_path) { (Some((_, kind, path)), _) => { err.arg("kind", kind); @@ -959,6 +957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (_, Some(hir::QPath::Resolved(_, path))) => { self.tcx.sess.source_map().span_to_snippet(path.span).ok().map(|p| { err.arg("func", p); + err.arg("ty", callee_ty); msg!("`{$func}` defined here returns `{$ty}`") }) } @@ -968,6 +967,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type definitions themselves, but rather variables *of* that type. Res::Local(hir_id) => { err.arg("local_name", self.tcx.hir_name(hir_id)); + err.arg("ty", callee_ty); Some(msg!("`{$local_name}` has type `{$ty}`")) } Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => { @@ -975,7 +975,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(msg!("`{$path}` defined here")) } _ => { - err.arg("path", callee_ty); + err.arg("path", callee_ty.to_string()); Some(msg!("`{$path}` defined here")) } } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3457cc373413a..a9a819935287c 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -476,10 +476,9 @@ pub(crate) struct SlicingSuggestion { #[derive(Diagnostic)] #[diag("expected function, found {$found}", code = E0618)] -pub(crate) struct InvalidCallee<'tcx> { +pub(crate) struct InvalidCallee { #[primary_span] pub span: Span, - pub ty: Ty<'tcx>, pub found: String, } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index c77e70dcbe9bb..227a413ea9b07 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1562,17 +1562,16 @@ pub(crate) enum NonCamelCaseTypeSub { pub(crate) struct NonSnakeCaseDiag<'a> { pub sort: &'a str, pub name: &'a str, - pub sc: String, #[subdiagnostic] pub sub: NonSnakeCaseDiagSub, } pub(crate) enum NonSnakeCaseDiagSub { Label { span: Span }, - Help, + Help { sc: String }, RenameOrConvertSuggestion { span: Span, suggestion: Ident }, ConvertSuggestion { span: Span, suggestion: String }, - SuggestionAndNote { span: Span }, + SuggestionAndNote { sc: String, span: Span }, } impl Subdiagnostic for NonSnakeCaseDiagSub { @@ -1581,7 +1580,8 @@ impl Subdiagnostic for NonSnakeCaseDiagSub { NonSnakeCaseDiagSub::Label { span } => { diag.span_label(span, msg!("should have a snake_case name")); } - NonSnakeCaseDiagSub::Help => { + NonSnakeCaseDiagSub::Help { sc } => { + diag.arg("sc", sc); diag.help(msg!("convert the identifier to snake case: `{$sc}`")); } NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion } => { @@ -1600,7 +1600,8 @@ impl Subdiagnostic for NonSnakeCaseDiagSub { Applicability::MaybeIncorrect, ); } - NonSnakeCaseDiagSub::SuggestionAndNote { span } => { + NonSnakeCaseDiagSub::SuggestionAndNote { sc, span } => { + diag.arg("sc", sc); diag.note(msg!("`{$sc}` cannot be used as a raw identifier")); diag.span_suggestion( span, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index fbbfbd86d319f..e3653c55f53a4 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -311,18 +311,18 @@ impl NonSnakeCase { suggestion: sc_ident, } } else { - NonSnakeCaseDiagSub::SuggestionAndNote { span } + NonSnakeCaseDiagSub::SuggestionAndNote { sc, span } } } else { - NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc.clone() } + NonSnakeCaseDiagSub::ConvertSuggestion { span, suggestion: sc } } } else { - NonSnakeCaseDiagSub::Help + NonSnakeCaseDiagSub::Help { sc } } } else { NonSnakeCaseDiagSub::Label { span } }; - cx.emit_span_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sc, sub }); + cx.emit_span_lint(NON_SNAKE_CASE, span, NonSnakeCaseDiag { sort, name, sub }); } } } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 6b19aa17c6d6c..f646a558266e2 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -232,6 +232,5 @@ struct OpaqueHiddenInferredBoundLint<'tcx> { struct AddBound<'tcx> { #[primary_span] suggest_span: Span, - #[skip_arg] trait_ref: TraitPredPrintModifiersAndPath<'tcx>, } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 2f7c3cc6a46d2..ac777b37a4303 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -26,7 +26,7 @@ impl<'a> DiagnosticDerive<'a> { let Some(message) = builder.primary_message() else { return DiagnosticDeriveError::ErrorHandled.to_compile_error(); }; - let message = message.diag_message(Some(variant)); + let message = message.diag_message(); let init = quote! { let mut diag = rustc_errors::Diag::new( diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index e335037f2c4c9..cdff1280d69f9 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -1,5 +1,7 @@ #![deny(unused_must_use)] +use std::collections::HashSet; + use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::parse::ParseStream; @@ -52,6 +54,7 @@ where formatting_init: TokenStream::new(), message: None, code: None, + used_fields: HashSet::new(), }; f(builder, variant) }); @@ -83,6 +86,8 @@ pub(crate) struct DiagnosticDeriveVariantBuilder { /// Error codes are a optional part of the struct attribute - this is only set to detect /// multiple specifications. pub code: SpannedOption<()>, + + pub used_fields: HashSet, } impl DiagnosticDeriveVariantBuilder { @@ -107,8 +112,7 @@ impl DiagnosticDeriveVariantBuilder { let ast = variant.ast(); let attrs = &ast.attrs; let preamble = attrs.iter().map(|attr| { - self.generate_structure_code_for_attr(attr, variant) - .unwrap_or_else(|v| v.to_compile_error()) + self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error()) }); quote! { @@ -120,23 +124,34 @@ impl DiagnosticDeriveVariantBuilder { /// calls to `arg` when no attributes are present. pub(crate) fn body(&mut self, variant: &VariantInfo<'_>) -> TokenStream { let mut body = quote! {}; + let mut second_part = quote! {}; + + // Subdiagnostic additions. + for binding in variant.bindings().iter().filter(|bi| !should_generate_arg(bi.ast())) { + second_part.extend(self.generate_field_attrs_code(binding)); + } // Generate `arg` calls first.. for binding in variant.bindings().iter().filter(|bi| should_generate_arg(bi.ast())) { - body.extend(self.generate_field_code(binding)); - } - // ..and then subdiagnostic additions. - for binding in variant.bindings().iter().filter(|bi| !should_generate_arg(bi.ast())) { - body.extend(self.generate_field_attrs_code(binding, variant)); + if self.is_used_in_message(binding) { + body.extend(self.generate_field_code(binding)); + } } + body.extend(second_part); body } + fn is_used_in_message(&self, binding: &BindingInfo<'_>) -> bool { + binding.ast().ident.as_ref().is_some_and(|ident| self.used_fields.contains(ident)) + } + /// Parse a `SubdiagnosticKind` from an `Attribute`. fn parse_subdiag_attribute( - &self, + &mut self, attr: &Attribute, ) -> Result, DiagnosticDeriveError> { - let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, &self.field_map)? else { + let Some(subdiag) = + SubdiagnosticVariant::from_attr(attr, &self.field_map, &mut self.used_fields)? + else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. return Ok(None); @@ -160,7 +175,6 @@ impl DiagnosticDeriveVariantBuilder { fn generate_structure_code_for_attr( &mut self, attr: &Attribute, - variant: &VariantInfo<'_>, ) -> Result { // Always allow documentation comments. if is_doc_comment(attr) { @@ -183,11 +197,14 @@ impl DiagnosticDeriveVariantBuilder { ) .emit(); } - self.message = Some(Message { - attr_span: attr.span(), - message_span: message.span(), - value: message.value(), - }); + let message = Message::new( + attr.span(), + message.span(), + message.value(), + &self.field_map, + &mut self.used_fields, + ); + self.message = Some(message); } // Parse arguments @@ -240,7 +257,7 @@ impl DiagnosticDeriveVariantBuilder { | SubdiagnosticKind::NoteOnce | SubdiagnosticKind::Help | SubdiagnosticKind::HelpOnce - | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, message, variant)), + | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, message)), SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => { throw_invalid_attr!(attr, |diag| diag .help("`#[label]` and `#[suggestion]` can only be applied to fields")); @@ -268,11 +285,7 @@ impl DiagnosticDeriveVariantBuilder { } } - fn generate_field_attrs_code( - &mut self, - binding_info: &BindingInfo<'_>, - variant: &VariantInfo<'_>, - ) -> TokenStream { + fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { let field = binding_info.ast(); let field_binding = &binding_info.binding; @@ -311,7 +324,6 @@ impl DiagnosticDeriveVariantBuilder { attr, FieldInfo { binding: binding_info, ty: inner_ty, span: &field.span() }, binding, - variant ) .unwrap_or_else(|v| v.to_compile_error()); @@ -329,14 +341,10 @@ impl DiagnosticDeriveVariantBuilder { attr: &Attribute, info: FieldInfo<'_>, binding: TokenStream, - variant: &VariantInfo<'_>, ) -> Result { let ident = &attr.path().segments.last().unwrap().ident; let name = ident.to_string(); match (&attr.meta, name.as_str()) { - // Don't need to do anything - by virtue of the attribute existing, the - // `arg` call will not be generated. - (Meta::Path(_), "skip_arg") => return Ok(quote! {}), (Meta::Path(_), "primary_span") => { report_error_if_not_applied_to_span(attr, &info)?; @@ -359,7 +367,7 @@ impl DiagnosticDeriveVariantBuilder { match subdiag { SubdiagnosticKind::Label => { report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, message, variant)) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, message)) } SubdiagnosticKind::Note | SubdiagnosticKind::NoteOnce @@ -370,11 +378,11 @@ impl DiagnosticDeriveVariantBuilder { if type_matches_path(inner, &["rustc_span", "Span"]) || type_matches_path(inner, &["rustc_span", "MultiSpan"]) { - Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, message, variant)) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, message)) } else if type_is_unit(inner) || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner)) { - Ok(self.add_subdiagnostic(&fn_ident, message, variant)) + Ok(self.add_subdiagnostic(&fn_ident, message)) } else { report_type_error(attr, "`Span`, `MultiSpan`, `bool` or `()`")? } @@ -400,7 +408,7 @@ impl DiagnosticDeriveVariantBuilder { applicability.set_once(quote! { #static_applicability }, span); } - let message = message.diag_message(Some(variant)); + let message = message.diag_message(); let applicability = applicability .value() .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified }); @@ -428,10 +436,9 @@ impl DiagnosticDeriveVariantBuilder { field_binding: TokenStream, kind: &Ident, message: Message, - variant: &VariantInfo<'_>, ) -> TokenStream { let fn_name = format_ident!("span_{}", kind); - let message = message.diag_message(Some(variant)); + let message = message.diag_message(); quote! { diag.#fn_name( #field_binding, @@ -442,13 +449,8 @@ impl DiagnosticDeriveVariantBuilder { /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current message /// and `fluent_attr_identifier`. - fn add_subdiagnostic( - &self, - kind: &Ident, - message: Message, - variant: &VariantInfo<'_>, - ) -> TokenStream { - let message = message.diag_message(Some(variant)); + fn add_subdiagnostic(&self, kind: &Ident, message: Message) -> TokenStream { + let message = message.diag_message(); quote! { diag.#kind(#message); } diff --git a/compiler/rustc_macros/src/diagnostics/message.rs b/compiler/rustc_macros/src/diagnostics/message.rs index 11bf904c18e1b..094736e94870b 100644 --- a/compiler/rustc_macros/src/diagnostics/message.rs +++ b/compiler/rustc_macros/src/diagnostics/message.rs @@ -1,11 +1,13 @@ +use std::collections::{HashMap, HashSet}; + use fluent_bundle::FluentResource; use fluent_syntax::ast::{Expression, InlineExpression, Pattern, PatternElement}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::ext::IdentExt; -use synstructure::VariantInfo; use crate::diagnostics::error::span_err; +use crate::diagnostics::utils::FieldMap; #[derive(Clone)] pub(crate) struct Message { @@ -15,53 +17,69 @@ pub(crate) struct Message { } impl Message { + // About `allow(rustc::potential_query_instability)`: The order of key/values of `fields` and + // `field_map` doesn't matters. + #[allow(rustc::potential_query_instability)] + pub(crate) fn new( + attr_span: Span, + message_span: Span, + message_str: String, + field_map: &FieldMap, + used_fields: &mut HashSet, + ) -> Self { + // Parse the fluent message + const GENERATED_MSG_ID: &str = "generated_msg"; + let resource = + FluentResource::try_new(format!("{GENERATED_MSG_ID} = {message_str}\n")).unwrap(); + assert_eq!(resource.entries().count(), 1); + let Some(fluent_syntax::ast::Entry::Message(flt_message)) = resource.get_entry(0) else { + panic!("Did not parse into a message") + }; + + let mut fields: HashMap = + HashMap::with_capacity(field_map.len()); + for (_, (ident, _)) in field_map { + fields.insert(ident.unraw().to_string(), (ident, false)); + } + for variable in variable_references(&flt_message) { + match fields.get_mut(variable) { + Some((_, seen)) => *seen = true, + None => { + span_err( + message_span.unwrap(), + format!("Variable `{variable}` not found in diagnostic "), + ) + .help(format!( + "Available fields: {:?}", + fields.keys().map(|s| s.as_str()).collect::>().join(", ") + )) + .emit(); + } + } + } + for (name, seen) in fields.values() { + if *seen { + used_fields.insert((*name).clone()); + } + } + Self { attr_span, message_span, value: message_str } + } + /// Get the diagnostic message for this diagnostic /// The passed `variant` is used to check whether all variables in the message are used. /// For subdiagnostics, we cannot check this. - pub(crate) fn diag_message(&self, variant: Option<&VariantInfo<'_>>) -> TokenStream { + pub(crate) fn diag_message(&self) -> TokenStream { let message = &self.value; - self.verify(variant); + self.verify(); quote! { rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed(#message)) } } - fn verify(&self, variant: Option<&VariantInfo<'_>>) { - verify_variables_used(self.message_span, &self.value, variant); + fn verify(&self) { verify_message_style(self.message_span, &self.value); verify_message_formatting(self.attr_span, self.message_span, &self.value); } } -fn verify_variables_used(msg_span: Span, message_str: &str, variant: Option<&VariantInfo<'_>>) { - // Parse the fluent message - const GENERATED_MSG_ID: &str = "generated_msg"; - let resource = - FluentResource::try_new(format!("{GENERATED_MSG_ID} = {message_str}\n")).unwrap(); - assert_eq!(resource.entries().count(), 1); - let Some(fluent_syntax::ast::Entry::Message(message)) = resource.get_entry(0) else { - panic!("Did not parse into a message") - }; - - // Check if all variables are used - if let Some(variant) = variant { - let fields: Vec = variant - .bindings() - .iter() - .flat_map(|b| b.ast().ident.as_ref()) - .map(|id| id.unraw().to_string()) - .collect(); - for variable in variable_references(&message) { - if !fields.iter().any(|f| f == variable) { - span_err( - msg_span.unwrap(), - format!("Variable `{variable}` not found in diagnostic "), - ) - .help(format!("Available fields: {:?}", fields.join(", "))) - .emit(); - } - } - } -} - fn variable_references<'a>(msg: &fluent_syntax::ast::Message<&'a str>) -> Vec<&'a str> { let mut refs = vec![]; diff --git a/compiler/rustc_macros/src/diagnostics/msg_macro.rs b/compiler/rustc_macros/src/diagnostics/msg_macro.rs index 66bc200707efa..831a94432c29a 100644 --- a/compiler/rustc_macros/src/diagnostics/msg_macro.rs +++ b/compiler/rustc_macros/src/diagnostics/msg_macro.rs @@ -6,5 +6,5 @@ pub(crate) fn msg_macro(input: proc_macro::TokenStream) -> proc_macro::TokenStre let inline = parse_macro_input!(input as LitStr); let message = Message { attr_span: inline.span(), message_span: inline.span(), value: inline.value() }; - message.diag_message(None).into() + message.diag_message().into() } diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 3e094ee8d42b6..f9ef016a16af6 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -1,5 +1,7 @@ #![deny(unused_must_use)] +use std::collections::HashSet; + use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use syn::parse::ParseStream; @@ -61,6 +63,8 @@ impl SubdiagnosticDerive { } } + let mut used_fields: HashSet = HashSet::new(); + structure.bind_with(|_| synstructure::BindStyle::Move); let variants_ = structure.each_variant(|variant| { let mut builder = SubdiagnosticDeriveVariantBuilder { @@ -74,6 +78,7 @@ impl SubdiagnosticDerive { has_suggestion_parts: false, has_subdiagnostic: false, is_enum, + used_fields: &mut used_fields, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -142,6 +147,8 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> { /// Set to true when this variant is an enum variant rather than just the body of a struct. is_enum: bool, + + used_fields: &'parent mut HashSet, } /// Provides frequently-needed information about the diagnostic kinds being derived for this type. @@ -190,7 +197,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { for attr in self.variant.ast().attrs { let Some(SubdiagnosticVariant { kind, message }) = - SubdiagnosticVariant::from_attr(attr, &self.fields)? + SubdiagnosticVariant::from_attr(attr, &self.fields, &mut self.used_fields)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. @@ -301,7 +308,6 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let name = name.as_str(); match name { - "skip_arg" => Ok(quote! {}), "primary_span" => { if kind_stats.has_multipart_suggestion { invalid_attr(attr) @@ -391,7 +397,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { invalid_attr(attr) .help(format!( - "only `{}`, `applicability` and `skip_arg` are valid field attributes", + "only `{}`, `applicability` is a valid field attribute", span_attrs.join(", ") )) .emit(); @@ -490,13 +496,17 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { span_attrs.push("primary_span") } diag.help(format!( - "only `{}`, `applicability` and `skip_arg` are valid field attributes", + "only `{}`, `applicability` is a valid field attribute", span_attrs.join(", ") )) }), } } + fn is_used_in_message(&self, binding: &BindingInfo<'_>) -> bool { + binding.ast().ident.as_ref().is_some_and(|ident| self.used_fields.contains(ident)) + } + pub(crate) fn into_tokens(&mut self) -> Result { let kind_messages = self.identify_kind()?; @@ -533,8 +543,13 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { .variant .bindings() .iter() - .filter(|binding| should_generate_arg(binding.ast())) - .map(|binding| self.generate_field_arg(binding)) + .filter_map(|binding| { + if should_generate_arg(binding.ast()) && self.is_used_in_message(binding) { + Some(self.generate_field_arg(binding)) + } else { + None + } + }) .collect(); let plain_args = quote! { let mut sub_args = rustc_errors::DiagArgMap::default(); @@ -546,7 +561,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let mut calls = TokenStream::new(); for (kind, messages) in kind_messages { let message = format_ident!("__message"); - let message_stream = messages.diag_message(Some(self.variant)); + let message_stream = messages.diag_message(); calls.extend(quote! { let #message = rustc_errors::format_diag_message(&#message_stream, &sub_args); }); let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 55a8445744cba..b65e39469ec51 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::{BTreeSet, HashMap}; +use std::collections::{BTreeSet, HashMap, HashSet}; use std::fmt; use std::str::FromStr; @@ -260,7 +260,7 @@ impl SetOnce for SpannedOption { } } -pub(super) type FieldMap = HashMap; +pub(super) type FieldMap = HashMap; /// In the strings in the attributes supplied to this macro, we want callers to be able to /// reference fields in the format string. For example: @@ -344,7 +344,7 @@ pub(super) fn build_format( let args = referenced_fields.into_iter().map(|field: String| { let field_ident = format_ident!("{}", field); let value = match field_map.get(&field) { - Some(value) => value.clone(), + Some(value) => value.1.clone(), // This field doesn't exist. Emit a diagnostic. None => { span_err(span.unwrap(), format!("`{field}` doesn't refer to a field on this type")) @@ -408,11 +408,11 @@ impl quote::ToTokens for Applicability { /// Build the mapping of field names to fields. This allows attributes to peek values from /// other fields. -pub(super) fn build_field_mapping(variant: &VariantInfo<'_>) -> HashMap { +pub(super) fn build_field_mapping(variant: &VariantInfo<'_>) -> FieldMap { let mut fields_map = FieldMap::new(); for binding in variant.bindings() { if let Some(ident) = &binding.ast().ident { - fields_map.insert(ident.to_string(), quote! { #binding }); + fields_map.insert(ident.to_string(), (ident.clone(), quote! { #binding })); } } fields_map @@ -598,6 +598,7 @@ impl SubdiagnosticVariant { pub(super) fn from_attr( attr: &Attribute, fields: &FieldMap, + used_fields: &mut HashSet, ) -> Result, DiagnosticDeriveError> { // Always allow documentation comments. if is_doc_comment(attr) { @@ -708,7 +709,13 @@ impl SubdiagnosticVariant { } if !input.is_empty() { input.parse::()?; } if is_first { - message = Some(Message { attr_span: attr.span(), message_span: inline_message.span(), value: inline_message.value() }); + message = Some(Message::new( + attr.span(), + inline_message.span(), + inline_message.value(), + fields, + used_fields, + )); is_first = false; } else { span_err(inline_message.span().unwrap(), "a diagnostic message must be the first argument to the attribute").emit(); diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 32a5d6a1c6cf2..8624e0524b04e 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -181,7 +181,6 @@ decl_derive!( note_once, warning, // field attributes - skip_arg, primary_span, label, subdiagnostic, @@ -208,7 +207,6 @@ decl_derive!( multipart_suggestion_short, multipart_suggestion_hidden, // field attributes - skip_arg, primary_span, suggestion_part, applicability)] => diagnostics::subdiagnostic_derive diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index c55275962e085..b4dac5b244f10 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -724,9 +724,25 @@ pub(crate) struct NonConstPath { pub(crate) span: Span, } +pub(crate) struct UnreachablePattern<'tcx> { + pub(crate) covered_by_many_n_more_count: Option, + pub(crate) inner: UnreachablePatternInner<'tcx>, +} + +impl<'a, 'tcx, G: EmissionGuarantee> Diagnostic<'a, G> for UnreachablePattern<'tcx> { + #[track_caller] + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let mut diag = self.inner.into_diag(dcx, level); + if let Some(covered_by_many_n_more_count) = self.covered_by_many_n_more_count { + diag.arg("covered_by_many_n_more_count", covered_by_many_n_more_count); + } + diag + } +} + #[derive(Diagnostic)] #[diag("unreachable pattern")] -pub(crate) struct UnreachablePattern<'tcx> { +pub(crate) struct UnreachablePatternInner<'tcx> { #[label("no value can reach this")] pub(crate) span: Option, #[label("matches no values because `{$matches_no_values_ty}` is uninhabited")] @@ -756,7 +772,6 @@ pub(crate) struct UnreachablePattern<'tcx> { pub(crate) covered_by_one: Option, #[note("multiple earlier patterns match some of the same values")] pub(crate) covered_by_many: Option, - pub(crate) covered_by_many_n_more_count: usize, #[suggestion("remove the match arm", code = "", applicability = "machine-applicable")] pub(crate) suggest_remove: Option, } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index afd8447b17ede..b4c340cfee2c0 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -953,7 +953,7 @@ fn report_unreachable_pattern<'p, 'tcx>( ) { static CAP_COVERED_BY_MANY: usize = 4; let pat_span = pat.data().span; - let mut lint = UnreachablePattern { + let mut lint = UnreachablePatternInner { span: Some(pat_span), matches_no_values: None, matches_no_values_ty: **pat.ty(), @@ -961,13 +961,13 @@ fn report_unreachable_pattern<'p, 'tcx>( covered_by_catchall: None, covered_by_one: None, covered_by_many: None, - covered_by_many_n_more_count: 0, wanted_constant: None, accessible_constant: None, inaccessible_constant: None, pattern_let_binding: None, suggest_remove: None, }; + let mut covered_by_many_n_more_count = None; match explanation.covered_by.as_slice() { [] => { // Empty pattern; we report the uninhabited type that caused the emptiness. @@ -1006,7 +1006,7 @@ fn report_unreachable_pattern<'p, 'tcx>( if remain == 0 { multispan.push_span_label(pat_span, msg!("collectively making this unreachable")); } else { - lint.covered_by_many_n_more_count = remain; + covered_by_many_n_more_count = Some(remain); multispan.push_span_label( pat_span, msg!("...and {$covered_by_many_n_more_count} other patterns collectively make this unreachable"), @@ -1015,7 +1015,12 @@ fn report_unreachable_pattern<'p, 'tcx>( lint.covered_by_many = Some(multispan); } } - cx.tcx.emit_node_span_lint(UNREACHABLE_PATTERNS, hir_id, pat_span, lint); + cx.tcx.emit_node_span_lint( + UNREACHABLE_PATTERNS, + hir_id, + pat_span, + UnreachablePattern { inner: lint, covered_by_many_n_more_count }, + ); } /// Detect typos that were meant to be a `const` but were interpreted as a new pattern binding. @@ -1023,7 +1028,7 @@ fn find_fallback_pattern_typo<'tcx>( cx: &PatCtxt<'_, 'tcx>, hir_id: HirId, pat: &Pat<'tcx>, - lint: &mut UnreachablePattern<'_>, + lint: &mut UnreachablePatternInner<'_>, ) { if cx.tcx.lint_level_spec_at_node(UNREACHABLE_PATTERNS, hir_id).is_allow() { // This is because we use `with_no_trimmed_paths` later, so if we never emit the lint we'd diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2d9e0a857bf5e..3a726cbce8182 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3461,10 +3461,6 @@ pub(crate) struct UnexpectedExpressionInPattern { pub span: Span, /// Was a `RangePatternBound` expected? pub is_bound: bool, - /// The unexpected expr's precedence. Not used directly in the error message, but needed for - /// the stashing of this error to work correctly. We store a `u32` rather than an - /// `ExprPrecedence` to avoid having to impl `IntoDiagArg` for `ExprPrecedence`. - pub expr_precedence: u32, } #[derive(Subdiagnostic)] @@ -4642,7 +4638,7 @@ pub(crate) struct ReservedMultihashLint { #[derive(Subdiagnostic)] #[suggestion( - "if you meant to write a path, use a double colon:", + "if you meant to write a path, use a double colon", code = "::", applicability = "maybe-incorrect" )] @@ -4653,13 +4649,13 @@ pub(crate) struct UseDoubleColonSuggestion { #[derive(Subdiagnostic)] #[multipart_suggestion( - "if you meant to create a regular struct, use curly braces:", + "if you meant to create a regular struct, use curly braces", applicability = "maybe-incorrect" )] pub(crate) struct UseRegularStructSuggestion { - #[suggestion_part(code = "{{")] + #[suggestion_part(code = " {{ ")] pub open: Span, - #[suggestion_part(code = "}}")] + #[suggestion_part(code = " }}")] pub close: Span, #[suggestion_part(code = "")] pub semicolon: Option, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3f6429c6a60f0..8f4ffc9a7ec46 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2163,8 +2163,10 @@ impl<'a> Parser<'a> { }) .map(|(r, _)| r) .map_err(|mut error| { - if encountered_colon { + if self.token == token::Colon { error.subdiagnostic(UseDoubleColonSuggestion { colon: self.token.span }); + } + if encountered_colon { self.eat_to_tokens(&[exp!(CloseParen)]); self.bump(); error.subdiagnostic(UseRegularStructSuggestion { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index b8718b503df26..b66dcddc8d333 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -497,18 +497,14 @@ impl<'a> Parser<'a> { && self.look_ahead(1, Token::is_range_separator); let span = expr.span; - - Some(( - self.dcx() - .create_err(UnexpectedExpressionInPattern { - span, - is_bound, - expr_precedence: expr.precedence() as u32, - }) - .stash(span, StashKey::ExprInPat) - .unwrap(), - span, - )) + let mut diag = self.dcx().create_err(UnexpectedExpressionInPattern { span, is_bound }); + // The unexpected expr's precedence. Not used directly in the error message, but + // needed for the stashing of this error to work correctly. We store a `u32` rather + // than an `ExprPrecedence` to avoid having to impl `IntoDiagArg` for + // `ExprPrecedence`. + diag.arg("expr_precedence", expr.precedence() as u32); + + Some((diag.stash(span, StashKey::ExprInPat).unwrap(), span)) } /// Called by [`Parser::parse_stmt_without_recovery`], used to add statement-aware subdiagnostics to the errors stashed diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 92a0f14f3e94e..b79460afad99e 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -184,15 +184,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn handle_res(&mut self, res: Res) { match res { - Res::Def( - DefKind::Const { .. } - | DefKind::AssocConst { .. } - | DefKind::AssocTy - | DefKind::TyAlias, - def_id, - ) => { - self.check_def_id(def_id); - } Res::PrimTy(..) | Res::SelfCtor(..) | Res::Local(..) => {} Res::Def(DefKind::Ctor(CtorOf::Variant, ..), ctor_def_id) => { // Using a variant in patterns should not make the variant live, diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 8804cf8459abf..de1aae502c491 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -15,30 +15,20 @@ pub(super) trait Decode<'a, 's, S>: Sized { } macro_rules! rpc_encode_decode { - (le $ty:ident $size:literal) => { + (le $ty:ty) => { impl Encode for $ty { fn encode(self, w: &mut Buffer, _: &mut S) { - const N: usize = size_of::<$ty>(); - - // We can pad with zeros without changing the value because of - // little endian encoding. - let mut bytes = [0; $size]; - bytes[..N].copy_from_slice(&self.to_le_bytes()); - - w.extend_from_array(&bytes); + w.extend_from_array(&self.to_le_bytes()); } } impl Decode<'_, '_, S> for $ty { fn decode(r: &mut &[u8], _: &mut S) -> Self { const N: usize = size_of::<$ty>(); - const { - assert!(N <= $size); - } let mut bytes = [0; N]; bytes.copy_from_slice(&r[..N]); - *r = &r[$size..]; + *r = &r[N..]; Self::from_le_bytes(bytes) } @@ -118,8 +108,42 @@ impl Decode<'_, '_, S> for u8 { } } -rpc_encode_decode!(le u32 4); -rpc_encode_decode!(le usize 8); +rpc_encode_decode!(le u32); +#[cfg(target_pointer_width = "64")] +rpc_encode_decode!(le usize); + +#[cfg(not(target_pointer_width = "64"))] +const MAX_USIZE_SIZE: usize = 8; + +#[cfg(not(target_pointer_width = "64"))] +impl Encode for usize { + fn encode(self, w: &mut Buffer, _: &mut S) { + const N: usize = size_of::(); + + // We can pad with zeros without changing the value because of + // little endian encoding. + let mut bytes = [0; MAX_USIZE_SIZE]; + bytes[..N].copy_from_slice(&self.to_le_bytes()); + + w.extend_from_array(&bytes); + } +} + +#[cfg(not(target_pointer_width = "64"))] +impl Decode<'_, '_, S> for usize { + fn decode(r: &mut &[u8], _: &mut S) -> Self { + const N: usize = size_of::(); + const { + assert!(N <= MAX_USIZE_SIZE); + } + + let mut bytes = [0; N]; + bytes.copy_from_slice(&r[..N]); + *r = &r[MAX_USIZE_SIZE..]; + + Self::from_le_bytes(bytes) + } +} impl Encode for bool { fn encode(self, w: &mut Buffer, s: &mut S) { diff --git a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md index a3a7a11258c8a..cc3690e1ae481 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/diagnostic-structs.md @@ -49,7 +49,6 @@ translatable error messages are written and how they are generated. Every field of the `Diagnostic` which does not have an annotation is available in Fluent messages as a variable, like `field_name` in the example above. -Fields can be annotated `#[skip_arg]` if this is undesired. Using the `#[primary_span]` attribute on a field (that has type `Span`) indicates the primary span of the diagnostic which will have the main message of the diagnostic. @@ -172,9 +171,6 @@ tcx.dcx().emit_err(FieldAlreadyDeclared { - `#[primary_span]` (_Optional_) - _Applied to `Span` fields on `Subdiagnostic`s. - Indicates the primary span of the diagnostic. -- `#[skip_arg]` (_Optional_) - - _Applied to any field._ - - Prevents the field from being provided as a diagnostic argument. ## `#[derive(Subdiagnostic)]` It is common in the compiler to write a function that conditionally adds a @@ -225,7 +221,6 @@ A primary span is only necessary for a label or suggestion, which can not be spa Every field of the type/variant which does not have an annotation is available in Fluent messages as a variable. -Fields can be annotated `#[skip_arg]` if this is undesired. Like `Diagnostic`, `Subdiagnostic` supports `Option` and `Vec` fields. @@ -348,9 +343,6 @@ to multipart suggestions) - `#[applicability]` (_Optional_; only applicable to (simple and multipart) suggestions) - _Applied to `Applicability` fields._ - Indicates the applicability of the suggestion. -- `#[skip_arg]` (_Optional_) - - _Applied to any field._ - - Prevents the field from being provided as a diagnostic argument. [defn]: https://github.com/rust-lang/rust/blob/6201eabde85db854c1ebb57624be5ec699246b50/compiler/rustc_hir_analysis/src/errors.rs#L68-L77 [use]: https://github.com/rust-lang/rust/blob/f1112099eba41abadb6f921df7edba70affe92c5/compiler/rustc_hir_analysis/src/collect.rs#L823-L827 diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 49a8c077188dd..8385e691ed385 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -628,7 +628,11 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: let count_types = required_types.len() + provided_types.len(); let count_consts = required_consts.len() + provided_consts.len(); let count_methods = required_methods.len() + provided_methods.len(); - let must_implement_one_of_functions = &tcx.trait_def(t.def_id).must_implement_one_of; + let &rustc_middle::ty::TraitDef { + must_implement_one_of: ref must_implement_one_of_functions, + impl_restriction, + .. + } = tcx.trait_def(t.def_id); // Output the trait definition wrap_item(w, |mut w| { @@ -782,6 +786,25 @@ fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt: // Trait documentation write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + if let rustc_middle::ty::trait_def::ImplRestrictionKind::Restricted(def_id, _) = + impl_restriction + { + let v1; + let v2; + write!( + w, + "
This trait cannot be implemented outside {}.
", + if cx.cache().document_private { + v1 = + rustc_middle::ty::print::with_resolve_crate_name!(tcx.def_path_str(def_id)); + v1.as_str() + } else { + v2 = tcx.crate_name(def_id.krate); + v2.as_str() + }, + )?; + } + fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::Display { fmt::from_fn(|w| { let name = m.name.unwrap(); diff --git a/tests/rustdoc-html/impl/impl-restriction-document-private.rs b/tests/rustdoc-html/impl/impl-restriction-document-private.rs new file mode 100644 index 0000000000000..6ea55eff54cf6 --- /dev/null +++ b/tests/rustdoc-html/impl/impl-restriction-document-private.rs @@ -0,0 +1,15 @@ +//@ compile-flags: --document-private-items +#![crate_name = "c"] +#![feature(impl_restriction)] + +//@ matches c/trait.Foo.html '//*[@class="stab impl_restriction"]' \ +// 'This trait cannot be implemented outside c.$' +//@ has c/trait.Foo.html '//*[@class="stab impl_restriction"]//code' 'c' +pub impl(crate) trait Foo {} + +pub mod inner { + //@ matches c/inner/trait.Bar.html '//*[@class="stab impl_restriction"]' \ + // 'This trait cannot be implemented outside c::inner.$' + //@ has c/inner/trait.Bar.html '//*[@class="stab impl_restriction"]//code' 'c::inner' + pub impl(self) trait Bar {} +} diff --git a/tests/rustdoc-html/impl/impl-restriction.rs b/tests/rustdoc-html/impl/impl-restriction.rs new file mode 100644 index 0000000000000..11df67425f9b9 --- /dev/null +++ b/tests/rustdoc-html/impl/impl-restriction.rs @@ -0,0 +1,14 @@ +#![crate_name = "c"] +#![feature(impl_restriction)] + +//@ matches c/trait.Foo.html '//*[@class="stab impl_restriction"]' \ +// 'This trait cannot be implemented outside c.$' +//@ has c/trait.Foo.html '//*[@class="stab impl_restriction"]//code' 'c' +pub impl(crate) trait Foo {} + +pub mod inner { + //@ matches c/inner/trait.Bar.html '//*[@class="stab impl_restriction"]' \ + // 'This trait cannot be implemented outside c.$' + //@ has c/inner/trait.Bar.html '//*[@class="stab impl_restriction"]//code' 'c' + pub impl(self) trait Bar {} +} diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs index c1146de0fef1f..72b54ed472756 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs @@ -26,7 +26,7 @@ use rustc_span::Span; struct NotIntoDiagArg; #[derive(Diagnostic)] -#[diag("example message")] +#[diag("example message {$arg}")] struct Test { #[primary_span] span: Span, @@ -36,7 +36,7 @@ struct Test { } #[derive(Subdiagnostic)] -#[label("example message")] +#[label("example message {$arg}")] struct SubTest { #[primary_span] span: Span, diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs index 26d92126fe87a..0956556bf5ef2 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs @@ -327,7 +327,6 @@ struct ArgFieldWithoutSkip { #[primary_span] span: Span, other: Hello, - //~^ ERROR the trait bound `Hello: IntoDiagArg` is not satisfied } #[derive(Diagnostic)] @@ -335,9 +334,8 @@ struct ArgFieldWithoutSkip { struct ArgFieldWithSkip { #[primary_span] span: Span, - // `Hello` does not implement `IntoDiagArg` so this would result in an error if - // not for `#[skip_arg]`. - #[skip_arg] + // `Hello` does not implement `IntoDiagArg` so this would result if `Diagnostic` + // doesn't skip it correctly. other: Hello, } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr index 28800016cea9b..486ae9c28e84b 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -253,61 +253,61 @@ LL | #[label = "bar"] | ^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/diagnostic-derive-inline.rs:389:5 + --> $DIR/diagnostic-derive-inline.rs:387:5 | LL | #[suggestion("with a suggestion", code = "...", applicability = "maybe-incorrect")] | ^ | note: previously specified here - --> $DIR/diagnostic-derive-inline.rs:391:24 + --> $DIR/diagnostic-derive-inline.rs:389:24 | LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ error: derive(Diagnostic): invalid applicability - --> $DIR/diagnostic-derive-inline.rs:397:69 + --> $DIR/diagnostic-derive-inline.rs:395:69 | LL | #[suggestion("with a suggestion", code = "...", applicability = "batman")] | ^^^^^^^^ error: derive(Diagnostic): the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` - --> $DIR/diagnostic-derive-inline.rs:460:5 + --> $DIR/diagnostic-derive-inline.rs:458:5 | LL | #[help("with a help")] | ^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/diagnostic-derive-inline.rs:469:29 + --> $DIR/diagnostic-derive-inline.rs:467:29 | LL | #[label("with a label", foo)] | ^^^ error: derive(Diagnostic): a diagnostic message must be the first argument to the attribute - --> $DIR/diagnostic-derive-inline.rs:477:29 + --> $DIR/diagnostic-derive-inline.rs:475:29 | LL | #[label("with a label", "and another one?")] | ^^^^^^^^^^^^^^^^^^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/diagnostic-derive-inline.rs:485:29 + --> $DIR/diagnostic-derive-inline.rs:483:29 | LL | #[label("with a label", foo = "...")] | ^^^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/diagnostic-derive-inline.rs:493:29 + --> $DIR/diagnostic-derive-inline.rs:491:29 | LL | #[label("with a label", foo("..."))] | ^^^ error: derive(Diagnostic): `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:513:1 + --> $DIR/diagnostic-derive-inline.rs:511:1 | LL | #[error("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:513:1 + --> $DIR/diagnostic-derive-inline.rs:511:1 | LL | #[error("this is an example message", code = E0123)] | ^ @@ -315,13 +315,13 @@ LL | #[error("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:520:1 + --> $DIR/diagnostic-derive-inline.rs:518:1 | LL | #[warn_("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:520:1 + --> $DIR/diagnostic-derive-inline.rs:518:1 | LL | #[warn_("this is an example message", code = E0123)] | ^ @@ -329,13 +329,13 @@ LL | #[warn_("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:527:1 + --> $DIR/diagnostic-derive-inline.rs:525:1 | LL | #[lint("this is an example message", code = E0123)] | ^ error: derive(Diagnostic): diagnostic message not specified - --> $DIR/diagnostic-derive-inline.rs:527:1 + --> $DIR/diagnostic-derive-inline.rs:525:1 | LL | #[lint("this is an example message", code = E0123)] | ^ @@ -343,19 +343,19 @@ LL | #[lint("this is an example message", code = E0123)] = help: specify the message as the first argument to the `#[diag(...)]` attribute, such as `#[diag("Example error")]` error: derive(Diagnostic): attribute specified multiple times - --> $DIR/diagnostic-derive-inline.rs:536:53 + --> $DIR/diagnostic-derive-inline.rs:534:53 | LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive-inline.rs:536:39 + --> $DIR/diagnostic-derive-inline.rs:534:39 | LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] | ^^^^ error: derive(Diagnostic): wrong types for suggestion - --> $DIR/diagnostic-derive-inline.rs:545:24 + --> $DIR/diagnostic-derive-inline.rs:543:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -363,7 +363,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: derive(Diagnostic): wrong types for suggestion - --> $DIR/diagnostic-derive-inline.rs:553:17 + --> $DIR/diagnostic-derive-inline.rs:551:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -371,13 +371,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: derive(Diagnostic): suggestion without `code = "..."` - --> $DIR/diagnostic-derive-inline.rs:560:5 + --> $DIR/diagnostic-derive-inline.rs:558:5 | LL | #[suggestion("with a suggestion")] | ^ error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:567:1 + --> $DIR/diagnostic-derive-inline.rs:565:1 | LL | #[multipart_suggestion("with a suggestion")] | ^ @@ -385,7 +385,7 @@ LL | #[multipart_suggestion("with a suggestion")] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:570:1 + --> $DIR/diagnostic-derive-inline.rs:568:1 | LL | #[multipart_suggestion()] | ^ @@ -393,7 +393,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:574:5 + --> $DIR/diagnostic-derive-inline.rs:572:5 | LL | #[multipart_suggestion("with a suggestion")] | ^ @@ -401,7 +401,7 @@ LL | #[multipart_suggestion("with a suggestion")] = help: consider creating a `Subdiagnostic` instead error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:582:1 + --> $DIR/diagnostic-derive-inline.rs:580:1 | LL | #[suggestion("with a suggestion", code = "...")] | ^ @@ -409,7 +409,7 @@ LL | #[suggestion("with a suggestion", code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: derive(Diagnostic): `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:591:1 + --> $DIR/diagnostic-derive-inline.rs:589:1 | LL | #[label] | ^ @@ -417,67 +417,67 @@ LL | #[label] = help: subdiagnostic message is missing error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:625:5 + --> $DIR/diagnostic-derive-inline.rs:623:5 | LL | #[subdiagnostic(bad)] | ^ error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:633:5 + --> $DIR/diagnostic-derive-inline.rs:631:5 | LL | #[subdiagnostic = "bad"] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:641:5 + --> $DIR/diagnostic-derive-inline.rs:639:5 | LL | #[subdiagnostic(bad, bad)] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:649:5 + --> $DIR/diagnostic-derive-inline.rs:647:5 | LL | #[subdiagnostic("bad")] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:657:5 + --> $DIR/diagnostic-derive-inline.rs:655:5 | LL | #[subdiagnostic(eager)] | ^ error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:678:5 + --> $DIR/diagnostic-derive-inline.rs:676:5 | LL | #[subdiagnostic(eager)] | ^ error: derive(Diagnostic): expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive-inline.rs:709:44 + --> $DIR/diagnostic-derive-inline.rs:707:44 | LL | #[suggestion("with a suggestion", code())] | ^ error: derive(Diagnostic): `code(...)` must contain only string literals - --> $DIR/diagnostic-derive-inline.rs:717:44 + --> $DIR/diagnostic-derive-inline.rs:715:44 | LL | #[suggestion("with a suggestion", code(foo))] | ^^^ error: unexpected token, expected `)` - --> $DIR/diagnostic-derive-inline.rs:717:44 + --> $DIR/diagnostic-derive-inline.rs:715:44 | LL | #[suggestion("with a suggestion", code(foo))] | ^^^ error: expected string literal - --> $DIR/diagnostic-derive-inline.rs:726:46 + --> $DIR/diagnostic-derive-inline.rs:724:46 | LL | #[suggestion("with a suggestion", code = 3)] | ^ error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive-inline.rs:741:5 + --> $DIR/diagnostic-derive-inline.rs:739:5 | LL | #[suggestion("with a suggestion", code = "")] | ^ @@ -487,7 +487,7 @@ LL | #[suggestion("with a suggestion", code = "")] = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` error: derive(Diagnostic): Variable `nosub` not found in diagnostic - --> $DIR/diagnostic-derive-inline.rs:753:8 + --> $DIR/diagnostic-derive-inline.rs:751:8 | LL | #[diag("does not exist: {$nosub}")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive-inline.rs:513:3 + --> $DIR/diagnostic-derive-inline.rs:511:3 | LL | #[error("this is an example message", code = E0123)] | ^^^^^ @@ -519,7 +519,7 @@ LL | struct ErrorAttribute {} | error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive-inline.rs:520:3 + --> $DIR/diagnostic-derive-inline.rs:518:3 | LL | #[warn_("this is an example message", code = E0123)] | ^^^^^ @@ -531,7 +531,7 @@ LL + #[warn("this is an example message", code = E0123)] | error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive-inline.rs:527:3 + --> $DIR/diagnostic-derive-inline.rs:525:3 | LL | #[lint("this is an example message", code = E0123)] | ^^^^ @@ -543,7 +543,7 @@ LL + #[link("this is an example message", code = E0123)] | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:567:3 + --> $DIR/diagnostic-derive-inline.rs:565:3 | LL | #[multipart_suggestion("with a suggestion")] | ^^^^^^^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:570:3 + --> $DIR/diagnostic-derive-inline.rs:568:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ @@ -567,36 +567,12 @@ LL | struct MultipartSuggestion { | error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive-inline.rs:574:7 + --> $DIR/diagnostic-derive-inline.rs:572:7 | LL | #[multipart_suggestion("with a suggestion")] | ^^^^^^^^^^^^^^^^^^^^ | = note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute -error[E0277]: the trait bound `Hello: IntoDiagArg` is not satisfied - --> $DIR/diagnostic-derive-inline.rs:329:12 - | -LL | #[derive(Diagnostic)] - | ---------- required by a bound introduced by this call -... -LL | other: Hello, - | ^^^^^ unsatisfied trait bound - | -help: the nightly-only, unstable trait `IntoDiagArg` is not implemented for `Hello` - --> $DIR/diagnostic-derive-inline.rs:41:1 - | -LL | struct Hello {} - | ^^^^^^^^^^^^ - = help: normalized in stderr - = note: there's an inherent method on `DiagInner` of the same name, which can be auto-dereferenced from `&mut DiagInner` -note: required by a bound in `Diag::<'a, G>::arg` - --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC - ::: $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC - | - = note: in this macro invocation - = note: this error originates in the macro `with_fn` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 76 previous errors +error: aborting due to 75 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.rs index 2aed4fa9465c4..1bec8ac03c981 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.rs +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.rs @@ -290,7 +290,6 @@ struct AA { struct AB { #[primary_span] span: Span, - #[skip_arg] z: Z, } diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr index 8e634bf78797f..cf3c9dd9ce10d 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr @@ -142,7 +142,7 @@ error: derive(Diagnostic): `#[bar]` is not a valid attribute LL | #[bar] | ^ | - = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes + = help: only `primary_span`, `applicability` is a valid field attribute error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute --> $DIR/subdiagnostic-derive-inline.rs:271:5 @@ -156,10 +156,10 @@ error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute LL | #[bar("...")] | ^ | - = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes + = help: only `primary_span`, `applicability` is a valid field attribute error: unexpected unsupported untagged union - --> $DIR/subdiagnostic-derive-inline.rs:298:1 + --> $DIR/subdiagnostic-derive-inline.rs:297:1 | LL | / union AC { LL | | @@ -169,97 +169,97 @@ LL | | } | |_^ error: expected this path to be an identifier - --> $DIR/subdiagnostic-derive-inline.rs:313:28 + --> $DIR/subdiagnostic-derive-inline.rs:312:28 | LL | #[label("example message", no_crate::example)] | ^^^^^^^^^^^^^^^^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive-inline.rs:326:5 + --> $DIR/subdiagnostic-derive-inline.rs:325:5 | LL | #[primary_span] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive-inline.rs:323:5 + --> $DIR/subdiagnostic-derive-inline.rs:322:5 | LL | #[primary_span] | ^ error: derive(Diagnostic): subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive-inline.rs:332:8 + --> $DIR/subdiagnostic-derive-inline.rs:331:8 | LL | struct AG { | ^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive-inline.rs:369:47 + --> $DIR/subdiagnostic-derive-inline.rs:368:47 | LL | #[suggestion("example message", code = "...", code = "...")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive-inline.rs:369:33 + --> $DIR/subdiagnostic-derive-inline.rs:368:33 | LL | #[suggestion("example message", code = "...", code = "...")] | ^^^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive-inline.rs:387:5 + --> $DIR/subdiagnostic-derive-inline.rs:386:5 | LL | #[applicability] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive-inline.rs:384:5 + --> $DIR/subdiagnostic-derive-inline.rs:383:5 | LL | #[applicability] | ^ error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive-inline.rs:397:5 + --> $DIR/subdiagnostic-derive-inline.rs:396:5 | LL | #[applicability] | ^ error: derive(Diagnostic): suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:410:1 + --> $DIR/subdiagnostic-derive-inline.rs:409:1 | LL | #[suggestion("example message")] | ^ error: derive(Diagnostic): invalid applicability - --> $DIR/subdiagnostic-derive-inline.rs:420:63 + --> $DIR/subdiagnostic-derive-inline.rs:419:63 | LL | #[suggestion("example message", code = "...", applicability = "foo")] | ^^^^^ error: derive(Diagnostic): suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive-inline.rs:438:1 + --> $DIR/subdiagnostic-derive-inline.rs:437:1 | LL | #[suggestion("example message", code = "...")] | ^ error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive-inline.rs:452:1 + --> $DIR/subdiagnostic-derive-inline.rs:451:1 | LL | #[label] | ^ error: derive(Diagnostic): `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive-inline.rs:472:40 + --> $DIR/subdiagnostic-derive-inline.rs:471:40 | LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: derive(Diagnostic): `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive-inline.rs:491:44 + --> $DIR/subdiagnostic-derive-inline.rs:490:44 | LL | #[suggestion("example message", code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:514:5 + --> $DIR/subdiagnostic-derive-inline.rs:513:5 | LL | #[suggestion_part] | ^ @@ -267,7 +267,7 @@ LL | #[suggestion_part] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead error: derive(Diagnostic): `#[suggestion_part(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:517:5 + --> $DIR/subdiagnostic-derive-inline.rs:516:5 | LL | #[suggestion_part(code = "...")] | ^ @@ -275,13 +275,13 @@ LL | #[suggestion_part(code = "...")] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions error: derive(Diagnostic): suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive-inline.rs:511:1 + --> $DIR/subdiagnostic-derive-inline.rs:510:1 | LL | #[suggestion("example message", code = "...")] | ^ error: derive(Diagnostic): invalid nested attribute - --> $DIR/subdiagnostic-derive-inline.rs:526:43 + --> $DIR/subdiagnostic-derive-inline.rs:525:43 | LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")] | ^^^^ @@ -289,25 +289,25 @@ LL | #[multipart_suggestion("example message", code = "...", applicability = "ma = help: only `style` and `applicability` are valid nested attributes error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive-inline.rs:526:1 + --> $DIR/subdiagnostic-derive-inline.rs:525:1 | LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:536:5 + --> $DIR/subdiagnostic-derive-inline.rs:535:5 | LL | #[suggestion_part] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:544:5 + --> $DIR/subdiagnostic-derive-inline.rs:543:5 | LL | #[suggestion_part()] | ^ error: derive(Diagnostic): `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:553:5 + --> $DIR/subdiagnostic-derive-inline.rs:552:5 | LL | #[primary_span] | ^ @@ -315,127 +315,127 @@ LL | #[primary_span] = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive-inline.rs:550:1 + --> $DIR/subdiagnostic-derive-inline.rs:549:1 | LL | #[multipart_suggestion("example message")] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:561:5 + --> $DIR/subdiagnostic-derive-inline.rs:560:5 | LL | #[suggestion_part] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:564:5 + --> $DIR/subdiagnostic-derive-inline.rs:563:5 | LL | #[suggestion_part()] | ^ error: derive(Diagnostic): `code` is the only valid nested attribute - --> $DIR/subdiagnostic-derive-inline.rs:567:23 + --> $DIR/subdiagnostic-derive-inline.rs:566:23 | LL | #[suggestion_part(foo = "bar")] | ^^^ error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive-inline.rs:571:5 + --> $DIR/subdiagnostic-derive-inline.rs:570:5 | LL | #[suggestion_part(code = "...")] | ^ error: derive(Diagnostic): the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive-inline.rs:574:5 + --> $DIR/subdiagnostic-derive-inline.rs:573:5 | LL | #[suggestion_part()] | ^ error: expected `,` - --> $DIR/subdiagnostic-derive-inline.rs:567:27 + --> $DIR/subdiagnostic-derive-inline.rs:566:27 | LL | #[suggestion_part(foo = "bar")] | ^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive-inline.rs:582:37 + --> $DIR/subdiagnostic-derive-inline.rs:581:37 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive-inline.rs:582:23 + --> $DIR/subdiagnostic-derive-inline.rs:581:23 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ error: derive(Diagnostic): `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` - --> $DIR/subdiagnostic-derive-inline.rs:611:5 + --> $DIR/subdiagnostic-derive-inline.rs:610:5 | LL | #[applicability] | ^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive-inline.rs:659:28 + --> $DIR/subdiagnostic-derive-inline.rs:658:28 | LL | #[suggestion_part(code("foo"))] | ^^^^^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive-inline.rs:659:28 + --> $DIR/subdiagnostic-derive-inline.rs:658:28 | LL | #[suggestion_part(code("foo"))] | ^^^^^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive-inline.rs:669:28 + --> $DIR/subdiagnostic-derive-inline.rs:668:28 | LL | #[suggestion_part(code("foo", "bar"))] | ^^^^^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive-inline.rs:669:28 + --> $DIR/subdiagnostic-derive-inline.rs:668:28 | LL | #[suggestion_part(code("foo", "bar"))] | ^^^^^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive-inline.rs:679:28 + --> $DIR/subdiagnostic-derive-inline.rs:678:28 | LL | #[suggestion_part(code(3))] | ^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive-inline.rs:679:28 + --> $DIR/subdiagnostic-derive-inline.rs:678:28 | LL | #[suggestion_part(code(3))] | ^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive-inline.rs:689:28 + --> $DIR/subdiagnostic-derive-inline.rs:688:28 | LL | #[suggestion_part(code())] | ^ error: expected string literal - --> $DIR/subdiagnostic-derive-inline.rs:698:30 + --> $DIR/subdiagnostic-derive-inline.rs:697:30 | LL | #[suggestion_part(code = 3)] | ^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive-inline.rs:740:1 + --> $DIR/subdiagnostic-derive-inline.rs:739:1 | LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive-inline.rs:740:1 + --> $DIR/subdiagnostic-derive-inline.rs:739:1 | LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")] | ^ error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:749:1 + --> $DIR/subdiagnostic-derive-inline.rs:748:1 | LL | #[suggestion_hidden("example message", code = "")] | ^ @@ -443,7 +443,7 @@ LL | #[suggestion_hidden("example message", code = "")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:757:1 + --> $DIR/subdiagnostic-derive-inline.rs:756:1 | LL | #[suggestion_hidden("example message", code = "", style = "normal")] | ^ @@ -451,7 +451,7 @@ LL | #[suggestion_hidden("example message", code = "", style = "normal")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: derive(Diagnostic): invalid suggestion style - --> $DIR/subdiagnostic-derive-inline.rs:765:52 + --> $DIR/subdiagnostic-derive-inline.rs:764:52 | LL | #[suggestion("example message", code = "", style = "foo")] | ^^^^^ @@ -459,25 +459,25 @@ LL | #[suggestion("example message", code = "", style = "foo")] = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only` error: expected string literal - --> $DIR/subdiagnostic-derive-inline.rs:773:52 + --> $DIR/subdiagnostic-derive-inline.rs:772:52 | LL | #[suggestion("example message", code = "", style = 42)] | ^^ error: expected `=` - --> $DIR/subdiagnostic-derive-inline.rs:781:49 + --> $DIR/subdiagnostic-derive-inline.rs:780:49 | LL | #[suggestion("example message", code = "", style)] | ^ error: expected `=` - --> $DIR/subdiagnostic-derive-inline.rs:789:49 + --> $DIR/subdiagnostic-derive-inline.rs:788:49 | LL | #[suggestion("example message", code = "", style("foo"))] | ^ error: derive(Diagnostic): `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive-inline.rs:800:5 + --> $DIR/subdiagnostic-derive-inline.rs:799:5 | LL | #[primary_span] | ^ @@ -486,7 +486,7 @@ LL | #[primary_span] = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead error: derive(Diagnostic): suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive-inline.rs:797:1 + --> $DIR/subdiagnostic-derive-inline.rs:796:1 | LL | #[suggestion("example message", code = "")] | ^ diff --git a/tests/ui/eii/auxiliary/other_crate_privacy2.rs b/tests/ui/eii/auxiliary/other_crate_privacy2.rs index 9fb19298f09f0..7577a500231e7 100644 --- a/tests/ui/eii/auxiliary/other_crate_privacy2.rs +++ b/tests/ui/eii/auxiliary/other_crate_privacy2.rs @@ -14,8 +14,10 @@ mod private { pub fn decl3(x: u64); } -pub use private::eii3 as eii4; -pub use private::decl3 as decl4; +pub use private::{decl3 as decl4, eii3 as eii4}; + +#[eii(eii5)] +static FOO: u8; pub fn local_call_decl1(x: u64) { decl1(x) diff --git a/tests/ui/eii/privacy2.rs b/tests/ui/eii/privacy2.rs index b5d8660fa4248..a096266703015 100644 --- a/tests/ui/eii/privacy2.rs +++ b/tests/ui/eii/privacy2.rs @@ -7,6 +7,7 @@ extern crate other_crate_privacy2 as codegen; // has a span but in the other crate //~? ERROR `#[eii2]` function required, but not found //~? ERROR `#[eii3]` function required, but not found +//~? ERROR `#[eii5]` static required, but not found #[codegen::eii1] fn eii1_impl(x: u64) { diff --git a/tests/ui/eii/privacy2.stderr b/tests/ui/eii/privacy2.stderr index bf84385add65f..92d09d72276d0 100644 --- a/tests/ui/eii/privacy2.stderr +++ b/tests/ui/eii/privacy2.stderr @@ -1,11 +1,11 @@ error[E0433]: cannot find `eii3` in `codegen` - --> $DIR/privacy2.rs:16:12 + --> $DIR/privacy2.rs:17:12 | LL | #[codegen::eii3] | ^^^^ could not find `eii3` in `codegen` error[E0603]: function `decl1` is private - --> $DIR/privacy2.rs:26:14 + --> $DIR/privacy2.rs:27:14 | LL | codegen::decl1(42); | ^^^^^ private function @@ -32,7 +32,15 @@ LL | #[eii(eii3)] | = help: expected at least one implementation in crate `privacy2` or any of its dependencies -error: aborting due to 4 previous errors +error: `#[eii5]` static required, but not found + --> $DIR/auxiliary/other_crate_privacy2.rs:19:7 + | +LL | #[eii(eii5)] + | ^^^^ expected because `#[eii5]` was declared here in crate `other_crate_privacy2` + | + = help: expected at least one implementation in crate `privacy2` or any of its dependencies + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0433, E0603. For more information about an error, try `rustc --explain E0433`. diff --git a/tests/ui/parser/colon-in-tuple-struct.rs b/tests/ui/parser/colon-in-tuple-struct.rs new file mode 100644 index 0000000000000..2ed0d0fbc11a4 --- /dev/null +++ b/tests/ui/parser/colon-in-tuple-struct.rs @@ -0,0 +1,5 @@ +// Suggest the user to use double colon when there's a colon in tuple struct + +struct Foo(std::string:String); +//~^ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` +//~| HELP if you meant to write a path, use a double colon diff --git a/tests/ui/parser/colon-in-tuple-struct.stderr b/tests/ui/parser/colon-in-tuple-struct.stderr new file mode 100644 index 0000000000000..c0108779d4042 --- /dev/null +++ b/tests/ui/parser/colon-in-tuple-struct.stderr @@ -0,0 +1,13 @@ +error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` + --> $DIR/colon-in-tuple-struct.rs:3:23 + | +LL | struct Foo(std::string:String); + | ^ expected one of 7 possible tokens + | +help: if you meant to write a path, use a double colon + | +LL | struct Foo(std::string::String); + | + + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/field-name-in-tuple-struct.rs b/tests/ui/parser/field-name-in-tuple-struct.rs index f2ccdd8cfdf29..128c6b2f226e2 100644 --- a/tests/ui/parser/field-name-in-tuple-struct.rs +++ b/tests/ui/parser/field-name-in-tuple-struct.rs @@ -2,5 +2,5 @@ struct Foo(a:u8,b:u8); //~^ ERROR expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` -//~| HELP if you meant to write a path, use a double colon: -//~| HELP if you meant to create a regular struct, use curly braces: +//~| HELP if you meant to write a path, use a double colon +//~| HELP if you meant to create a regular struct, use curly braces diff --git a/tests/ui/parser/field-name-in-tuple-struct.stderr b/tests/ui/parser/field-name-in-tuple-struct.stderr index 0b0964f29033d..bf15aba41bdb3 100644 --- a/tests/ui/parser/field-name-in-tuple-struct.stderr +++ b/tests/ui/parser/field-name-in-tuple-struct.stderr @@ -4,14 +4,14 @@ error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` LL | struct Foo(a:u8,b:u8); | ^ expected one of 7 possible tokens | -help: if you meant to write a path, use a double colon: +help: if you meant to write a path, use a double colon | LL | struct Foo(a::u8,b:u8); | + -help: if you meant to create a regular struct, use curly braces: +help: if you meant to create a regular struct, use curly braces | LL - struct Foo(a:u8,b:u8); -LL + struct Foo{a:u8,b:u8} +LL + struct Foo { a:u8,b:u8 } | error: aborting due to 1 previous error