diff --git a/Cargo.lock b/Cargo.lock index 02459afa90726..234d709f3c315 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4229,6 +4229,8 @@ dependencies = [ name = "rustc_macros" version = "0.0.0" dependencies = [ + "fluent-bundle", + "fluent-syntax", "proc-macro2", "quote", "syn 2.0.110", diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 38f728fa9f559..250bceecbd654 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -307,6 +307,14 @@ impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParse const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls; } +pub(crate) struct RustcHiddenTypeOfOpaquesParser; + +impl NoArgsAttributeParser for RustcHiddenTypeOfOpaquesParser { + const PATH: &[Symbol] = &[sym::rustc_hidden_type_of_opaques]; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); + const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHiddenTypeOfOpaques; +} pub(crate) struct RustcNounwindParser; impl NoArgsAttributeParser for RustcNounwindParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0cabc0895053e..51da6def086c2 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -75,13 +75,14 @@ use crate::attributes::rustc_dump::{ RustcDumpVtable, }; use crate::attributes::rustc_internal::{ - RustcHasIncoherentInherentImplsParser, RustcLayoutParser, RustcLayoutScalarValidRangeEndParser, - RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser, - RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser, - RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser, - RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, - RustcNonConstTraitMethodParser, RustcNounwindParser, RustcObjectLifetimeDefaultParser, - RustcOffloadKernelParser, RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser, + RustcHasIncoherentInherentImplsParser, RustcHiddenTypeOfOpaquesParser, RustcLayoutParser, + RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, + RustcLegacyConstGenericsParser, RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, + RustcLintQueryInstabilityParser, RustcLintUntrackedQueryInformationParser, RustcMainParser, + RustcMustImplementOneOfParser, RustcNeverReturnsNullPointerParser, + RustcNoImplicitAutorefsParser, RustcNonConstTraitMethodParser, RustcNounwindParser, + RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser, + RustcSimdMonomorphizeLaneLimitParser, }; use crate::attributes::semantics::MayDangleParser; use crate::attributes::stability::{ @@ -299,6 +300,7 @@ attribute_parsers!( Single>, Single>, Single>, + Single>, Single>, Single>, Single>, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index caf6a86af098a..d8587ed81d6de 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2309,12 +2309,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { tcx: TyCtxt<'hir>, issue_span: Span, expr_span: Span, - body_expr: Option<&'hir hir::Expr<'hir>>, - loop_bind: Option<&'hir Ident>, - loop_span: Option, - head_span: Option, - pat_span: Option, - head: Option<&'hir hir::Expr<'hir>>, + body_expr: Option<&'hir hir::Expr<'hir>> = None, + loop_bind: Option<&'hir Ident> = None, + loop_span: Option = None, + head_span: Option = None, + pat_span: Option = None, + head: Option<&'hir hir::Expr<'hir>> = None, } impl<'hir> Visitor<'hir> for ExprFinder<'hir> { fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) { @@ -2380,17 +2380,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { hir::intravisit::walk_expr(self, ex); } } - let mut finder = ExprFinder { - tcx, - expr_span: span, - issue_span, - loop_bind: None, - body_expr: None, - head_span: None, - loop_span: None, - pat_span: None, - head: None, - }; + let mut finder = ExprFinder { tcx, expr_span: span, issue_span, .. }; finder.visit_expr(tcx.hir_body(body_id).value); if let Some(body_expr) = finder.body_expr @@ -2625,13 +2615,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { struct ExpressionFinder<'tcx> { capture_span: Span, - closure_change_spans: Vec, - closure_arg_span: Option, - in_closure: bool, - suggest_arg: String, + closure_change_spans: Vec = vec![], + closure_arg_span: Option = None, + in_closure: bool = false, + suggest_arg: String = String::new(), tcx: TyCtxt<'tcx>, - closure_local_id: Option, - closure_call_changes: Vec<(Span, String)>, + closure_local_id: Option = None, + closure_call_changes: Vec<(Span, String)> = vec![], } impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> { fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { @@ -2712,16 +2702,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { }) = self.infcx.tcx.hir_node(self.mir_hir_id()) && let hir::Node::Expr(expr) = self.infcx.tcx.hir_node(body_id.hir_id) { - let mut finder = ExpressionFinder { - capture_span: *capture_kind_span, - closure_change_spans: vec![], - closure_arg_span: None, - in_closure: false, - suggest_arg: String::new(), - closure_local_id: None, - closure_call_changes: vec![], - tcx: self.infcx.tcx, - }; + let mut finder = + ExpressionFinder { capture_span: *capture_kind_span, tcx: self.infcx.tcx, .. }; finder.visit_expr(expr); if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a059481c326b..7c5cbc58e25c5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -4,6 +4,7 @@ #![allow(internal_features)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(default_field_values)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(negative_impls)] diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index c0737edd7d65f..c9e887061305f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -247,6 +247,9 @@ pub enum SubdiagMessage { /// Identifier of a Fluent message. Instances of this variant are generated by the /// `Subdiagnostic` derive. FluentIdentifier(FluentId), + /// An inline Fluent message. Instances of this variant are generated by the + /// `Subdiagnostic` derive. + Inline(Cow<'static, str>), /// Attribute of a Fluent message. Needs to be combined with a Fluent identifier to produce an /// actual translated message. Instances of this variant are generated by the `fluent_messages` /// macro. @@ -291,6 +294,8 @@ pub enum DiagMessage { /// /// FluentIdentifier(FluentId, Option), + /// An inline Fluent message, containing the to be translated diagnostic message. + Inline(Cow<'static, str>), } impl DiagMessage { @@ -305,21 +310,22 @@ impl DiagMessage { SubdiagMessage::FluentIdentifier(id) => { return DiagMessage::FluentIdentifier(id, None); } + SubdiagMessage::Inline(s) => return DiagMessage::Inline(s), SubdiagMessage::FluentAttr(attr) => attr, }; match self { - DiagMessage::Str(s) => DiagMessage::Str(s.clone()), DiagMessage::FluentIdentifier(id, _) => { DiagMessage::FluentIdentifier(id.clone(), Some(attr)) } + _ => panic!("Tried to add a subdiagnostic to a message without a fluent identifier"), } } pub fn as_str(&self) -> Option<&str> { match self { DiagMessage::Str(s) => Some(s), - DiagMessage::FluentIdentifier(_, _) => None, + DiagMessage::FluentIdentifier(_, _) | DiagMessage::Inline(_) => None, } } } @@ -353,6 +359,7 @@ impl From for SubdiagMessage { // There isn't really a sensible behaviour for this because it loses information but // this is the most sensible of the behaviours. DiagMessage::FluentIdentifier(_, Some(attr)) => SubdiagMessage::FluentAttr(attr), + DiagMessage::Inline(s) => SubdiagMessage::Inline(s), } } } diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index 43d5fca301ec8..0ee2b7b060909 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -3,11 +3,13 @@ use std::env; use std::error::Report; use std::sync::Arc; +use rustc_error_messages::langid; pub use rustc_error_messages::{FluentArgs, LazyFallbackBundle}; use tracing::{debug, trace}; use crate::error::{TranslateError, TranslateErrorKind}; -use crate::{DiagArg, DiagMessage, FluentBundle, Style}; +use crate::fluent_bundle::FluentResource; +use crate::{DiagArg, DiagMessage, FluentBundle, Style, fluent_bundle}; /// Convert diagnostic arguments (a rustc internal type that exists to implement /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. @@ -79,6 +81,28 @@ impl Translator { return Ok(Cow::Borrowed(msg)); } DiagMessage::FluentIdentifier(identifier, attr) => (identifier, attr), + // This translates an inline fluent diagnostic message + // It does this by creating a new `FluentBundle` with only one message, + // and then translating using this bundle. + DiagMessage::Inline(msg) => { + const GENERATED_MSG_ID: &str = "generated_msg"; + let resource = + FluentResource::try_new(format!("{GENERATED_MSG_ID} = {msg}\n")).unwrap(); + let mut bundle = fluent_bundle::FluentBundle::new(vec![langid!("en-US")]); + bundle.set_use_isolating(false); + bundle.add_resource(resource).unwrap(); + let message = bundle.get_message(GENERATED_MSG_ID).unwrap(); + let value = message.value().unwrap(); + + let mut errs = vec![]; + let translated = bundle.format_pattern(value, Some(args), &mut errs).to_string(); + debug!(?translated, ?errs); + return if errs.is_empty() { + Ok(Cow::Owned(translated)) + } else { + Err(TranslateError::fluent(&Cow::Borrowed(GENERATED_MSG_ID), args, errs)) + }; + } }; let translate_with_bundle = |bundle: &'a FluentBundle| -> Result, TranslateError<'_>> { diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 92dda79b09203..3104a08d75471 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1057,6 +1057,9 @@ pub enum AttributeKind { /// Represents `#[rustc_has_incoherent_inherent_impls]` RustcHasIncoherentInherentImpls, + /// Represents `#[rustc_hidden_type_of_opaques]` + RustcHiddenTypeOfOpaques, + /// Represents `#[rustc_layout]` RustcLayout(ThinVec), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 816ed07c1dc4c..f03f55f85b391 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -111,6 +111,7 @@ impl AttributeKind { RustcDumpVtable(..) => No, RustcDynIncompatibleTrait(..) => No, RustcHasIncoherentInherentImpls => Yes, + RustcHiddenTypeOfOpaques => No, RustcLayout(..) => No, RustcLayoutScalarValidRangeEnd(..) => Yes, RustcLayoutScalarValidRangeStart(..) => Yes, diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 2dfd4ab6111fe..bbf912cd4bde8 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -7,10 +7,9 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { - if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) { + if !find_attr!(tcx.get_all_attrs(CRATE_DEF_ID), AttributeKind::RustcHiddenTypeOfOpaques) { return; } - for id in tcx.hir_crate_items(()).opaques() { if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index f879153c5765a..d414f4dbcc240 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -51,12 +51,12 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>( struct HirWfCheck<'tcx> { tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>, - cause: Option>, - cause_depth: usize, + cause: Option> = None, + cause_depth: usize = 0, icx: ItemCtxt<'tcx>, def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, - depth: usize, + depth: usize = 0, } impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { @@ -124,16 +124,8 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>( } } - let mut visitor = HirWfCheck { - tcx, - predicate, - cause: None, - cause_depth: 0, - icx, - def_id, - param_env: tcx.param_env(def_id.to_def_id()), - depth: 0, - }; + let param_env = tcx.param_env(def_id.to_def_id()); + let mut visitor = HirWfCheck { tcx, predicate, icx, def_id, param_env, .. }; // Get the starting `hir::Ty` using our `WellFormedLoc`. // We will walk 'into' this type to try to find diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3a4d894239fc6..f7a1434359593 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -57,6 +57,7 @@ This API is completely unstable and subject to change. // tidy-alphabetical-start #![feature(assert_matches)] +#![feature(default_field_values)] #![feature(gen_blocks)] #![feature(if_let_guard)] #![feature(iter_intersperse)] diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c07cbfae256dd..2e85410c89604 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2647,7 +2647,15 @@ impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> { // To suggest a multipart suggestion when encountering `foo(1, "")` where the def // was `fn foo(())`. let (_, expected_ty) = self.formal_and_expected_inputs[expected_idx]; - suggestions.push((*arg_span, self.ty_to_snippet(expected_ty, expected_idx))); + // Check if the new suggestion would overlap with any existing suggestion. + // This can happen when we have both removal suggestions (which may include + // adjacent commas) and type replacement suggestions for the same span. + let dominated = suggestions + .iter() + .any(|(span, _)| span.contains(*arg_span) || arg_span.overlaps(*span)); + if !dominated { + suggestions.push((*arg_span, self.ty_to_snippet(expected_ty, expected_idx))); + } } } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ff108031badc1..d1d5d0a56eada 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -20,6 +20,7 @@ declare_lint_pass! { AMBIGUOUS_GLOB_IMPORTED_TRAITS, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS, + AMBIGUOUS_IMPORT_VISIBILITIES, AMBIGUOUS_PANIC_IMPORTS, ARITHMETIC_OVERFLOW, ASM_SUB_REGISTER, @@ -4564,6 +4565,55 @@ declare_lint! { }; } +declare_lint! { + /// The `ambiguous_import_visibilities` lint detects imports that should report ambiguity + /// errors, but previously didn't do that due to rustc bugs. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unknown_lints)] + /// #![deny(ambiguous_import_visibilities)] + /// mod reexport { + /// mod m { + /// pub struct S {} + /// } + /// + /// macro_rules! mac { + /// () => { use m::S; } + /// } + /// + /// pub use m::*; + /// mac!(); + /// + /// pub use S as Z; // ambiguous visibility + /// } + /// + /// fn main() { + /// reexport::Z {}; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust compile it successfully because it + /// fetched the glob import's visibility for `pub use S as Z` import, and ignored the private + /// `use m::S` import that appeared later. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub AMBIGUOUS_IMPORT_VISIBILITIES, + Warn, + "detects certain glob imports that require reporting an ambiguity error", + @future_incompatible = FutureIncompatibleInfo { + reason: fcw!(FutureReleaseError #149145), + }; +} + declare_lint! { /// The `refining_impl_trait_reachable` lint detects `impl Trait` return /// types in method signatures that are refined by a publically reachable diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index f9d3b75835907..f097aee54abb6 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -8,6 +8,8 @@ proc-macro = true [dependencies] # tidy-alphabetical-start +fluent-bundle = "0.16" +fluent-syntax = "0.12" proc-macro2 = "1" quote = "1" syn = { version = "2.0.9", features = ["full"] } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 7e784e3464e9f..b4270f45422e9 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -22,20 +22,22 @@ impl<'a> DiagnosticDerive<'a> { pub(crate) fn into_tokens(self) -> TokenStream { let DiagnosticDerive { mut structure } = self; let kind = DiagnosticDeriveKind::Diagnostic; - let slugs = RefCell::new(Vec::new()); + let messages = RefCell::new(Vec::new()); let implementation = kind.each_variant(&mut structure, |mut builder, variant| { let preamble = builder.preamble(variant); let body = builder.body(variant); - let Some(slug) = builder.primary_message() else { + let Some(message) = builder.primary_message() else { return DiagnosticDeriveError::ErrorHandled.to_compile_error(); }; - slugs.borrow_mut().push(slug.clone()); + messages.borrow_mut().push(message.clone()); + let message = message.diag_message(variant); + let init = quote! { let mut diag = rustc_errors::Diag::new( dcx, level, - crate::fluent_generated::#slug + #message ); }; @@ -66,7 +68,7 @@ impl<'a> DiagnosticDerive<'a> { } } }); - for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) { + for test in messages.borrow().iter().map(|s| s.generate_test(&structure)) { imp.extend(test); } imp @@ -86,17 +88,18 @@ impl<'a> LintDiagnosticDerive<'a> { pub(crate) fn into_tokens(self) -> TokenStream { let LintDiagnosticDerive { mut structure } = self; let kind = DiagnosticDeriveKind::LintDiagnostic; - let slugs = RefCell::new(Vec::new()); + let messages = RefCell::new(Vec::new()); let implementation = kind.each_variant(&mut structure, |mut builder, variant| { let preamble = builder.preamble(variant); let body = builder.body(variant); - let Some(slug) = builder.primary_message() else { + let Some(message) = builder.primary_message() else { return DiagnosticDeriveError::ErrorHandled.to_compile_error(); }; - slugs.borrow_mut().push(slug.clone()); + messages.borrow_mut().push(message.clone()); + let message = message.diag_message(variant); let primary_message = quote! { - diag.primary_message(crate::fluent_generated::#slug); + diag.primary_message(#message); }; let formatting_init = &builder.formatting_init; @@ -122,47 +125,10 @@ impl<'a> LintDiagnosticDerive<'a> { } } }); - for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) { + for test in messages.borrow().iter().map(|s| s.generate_test(&structure)) { imp.extend(test); } imp } } - -/// Generates a `#[test]` that verifies that all referenced variables -/// exist on this structure. -fn generate_test(slug: &syn::Path, structure: &Structure<'_>) -> TokenStream { - // FIXME: We can't identify variables in a subdiagnostic - for field in structure.variants().iter().flat_map(|v| v.ast().fields.iter()) { - for attr_name in field.attrs.iter().filter_map(|at| at.path().get_ident()) { - if attr_name == "subdiagnostic" { - return quote!(); - } - } - } - use std::sync::atomic::{AtomicUsize, Ordering}; - // We need to make sure that the same diagnostic slug can be used multiple times without - // causing an error, so just have a global counter here. - static COUNTER: AtomicUsize = AtomicUsize::new(0); - let slug = slug.get_ident().unwrap(); - let ident = quote::format_ident!("verify_{slug}_{}", COUNTER.fetch_add(1, Ordering::Relaxed)); - let ref_slug = quote::format_ident!("{slug}_refs"); - let struct_name = &structure.ast().ident; - let variables: Vec<_> = structure - .variants() - .iter() - .flat_map(|v| v.ast().fields.iter().filter_map(|f| f.ident.as_ref().map(|i| i.to_string()))) - .collect(); - // tidy errors on `#[test]` outside of test files, so we use `#[test ]` to work around this - quote! { - #[cfg(test)] - #[test ] - fn #ident() { - let variables = [#(#variables),*]; - for vref in crate::fluent_generated::#ref_slug { - assert!(variables.contains(vref), "{}: variable `{vref}` not found ({})", stringify!(#struct_name), stringify!(#slug)); - } - } - } -} diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 25110fd4f908e..e6d9409a1fa30 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -4,13 +4,14 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::parse::ParseStream; use syn::spanned::Spanned; -use syn::{Attribute, Meta, Path, Token, Type, parse_quote}; +use syn::{Attribute, LitStr, Meta, Path, Token, Type, parse_quote}; use synstructure::{BindingInfo, Structure, VariantInfo}; use super::utils::SubdiagnosticVariant; use crate::diagnostics::error::{ DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err, }; +use crate::diagnostics::message::Message; use crate::diagnostics::utils::{ FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption, SubdiagnosticKind, build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, @@ -41,9 +42,9 @@ pub(crate) struct DiagnosticDeriveVariantBuilder { /// derive builder. pub field_map: FieldMap, - /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that + /// Message is a mandatory part of the struct attribute as corresponds to the Fluent message that /// has the actual diagnostic message. - pub slug: Option, + pub message: Option, /// Error codes are a optional part of the struct attribute - this is only set to detect /// multiple specifications. @@ -90,7 +91,7 @@ impl DiagnosticDeriveKind { span, field_map: build_field_mapping(variant), formatting_init: TokenStream::new(), - slug: None, + message: None, code: None, }; f(builder, variant) @@ -105,8 +106,8 @@ impl DiagnosticDeriveKind { } impl DiagnosticDeriveVariantBuilder { - pub(crate) fn primary_message(&self) -> Option<&Path> { - match self.slug.as_ref() { + pub(crate) fn primary_message(&self) -> Option<&Message> { + match self.message.as_ref() { None => { span_err(self.span, "diagnostic slug not specified") .help( @@ -116,7 +117,7 @@ impl DiagnosticDeriveVariantBuilder { .emit(); None } - Some(slug) + Some(Message::Slug(slug)) if let Some(Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { @@ -126,7 +127,7 @@ impl DiagnosticDeriveVariantBuilder { .emit(); None } - Some(slug) => Some(slug), + Some(msg) => Some(msg), } } @@ -136,7 +137,8 @@ impl DiagnosticDeriveVariantBuilder { let ast = variant.ast(); let attrs = &ast.attrs; let preamble = attrs.iter().map(|attr| { - self.generate_structure_code_for_attr(attr).unwrap_or_else(|v| v.to_compile_error()) + self.generate_structure_code_for_attr(attr, variant) + .unwrap_or_else(|v| v.to_compile_error()) }); quote! { @@ -154,7 +156,7 @@ impl DiagnosticDeriveVariantBuilder { } // ..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)); + body.extend(self.generate_field_attrs_code(binding, variant)); } body } @@ -163,7 +165,7 @@ impl DiagnosticDeriveVariantBuilder { fn parse_subdiag_attribute( &self, attr: &Attribute, - ) -> Result, DiagnosticDeriveError> { + ) -> Result, DiagnosticDeriveError> { let Some(subdiag) = SubdiagnosticVariant::from_attr(attr, &self.field_map)? else { // Some attributes aren't errors - like documentation comments - but also aren't // subdiagnostics. @@ -175,15 +177,18 @@ impl DiagnosticDeriveVariantBuilder { .help("consider creating a `Subdiagnostic` instead")); } - let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind { - SubdiagnosticKind::Label => parse_quote! { _subdiag::label }, - SubdiagnosticKind::Note => parse_quote! { _subdiag::note }, - SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once }, - SubdiagnosticKind::Help => parse_quote! { _subdiag::help }, - SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once }, - SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn }, - SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion }, - SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), + // For subdiagnostics without a message specified, insert a placeholder slug + let slug = subdiag.slug.unwrap_or_else(|| { + Message::Slug(match subdiag.kind { + SubdiagnosticKind::Label => parse_quote! { _subdiag::label }, + SubdiagnosticKind::Note => parse_quote! { _subdiag::note }, + SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once }, + SubdiagnosticKind::Help => parse_quote! { _subdiag::help }, + SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once }, + SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn }, + SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion }, + SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), + }) }); Ok(Some((subdiag.kind, slug, false))) @@ -195,6 +200,7 @@ impl DiagnosticDeriveVariantBuilder { fn generate_structure_code_for_attr( &mut self, attr: &Attribute, + variant: &VariantInfo<'_>, ) -> Result { // Always allow documentation comments. if is_doc_comment(attr) { @@ -210,13 +216,28 @@ impl DiagnosticDeriveVariantBuilder { let mut input = &*input; let slug_recovery_point = input.fork(); - let slug = input.parse::()?; - if input.is_empty() || input.peek(Token![,]) { - self.slug = Some(slug); + if input.peek(LitStr) { + // Parse an inline message + let message = input.parse::()?; + if !message.suffix().is_empty() { + span_err( + message.span().unwrap(), + "Inline message is not allowed to have a suffix", + ) + .emit(); + } + self.message = Some(Message::Inline(message.span(), message.value())); } else { - input = &slug_recovery_point; + // Parse a slug + let slug = input.parse::()?; + if input.is_empty() || input.peek(Token![,]) { + self.message = Some(Message::Slug(slug)); + } else { + input = &slug_recovery_point; + } } + // Parse arguments while !input.is_empty() { input.parse::()?; // Allow trailing comma @@ -266,7 +287,7 @@ impl DiagnosticDeriveVariantBuilder { | SubdiagnosticKind::NoteOnce | SubdiagnosticKind::Help | SubdiagnosticKind::HelpOnce - | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug)), + | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug, variant)), SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => { throw_invalid_attr!(attr, |diag| diag .help("`#[label]` and `#[suggestion]` can only be applied to fields")); @@ -294,7 +315,11 @@ impl DiagnosticDeriveVariantBuilder { } } - fn generate_field_attrs_code(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream { + fn generate_field_attrs_code( + &mut self, + binding_info: &BindingInfo<'_>, + variant: &VariantInfo<'_>, + ) -> TokenStream { let field = binding_info.ast(); let field_binding = &binding_info.binding; @@ -333,6 +358,7 @@ impl DiagnosticDeriveVariantBuilder { attr, FieldInfo { binding: binding_info, ty: inner_ty, span: &field.span() }, binding, + variant ) .unwrap_or_else(|v| v.to_compile_error()); @@ -350,6 +376,7 @@ impl DiagnosticDeriveVariantBuilder { attr: &Attribute, info: FieldInfo<'_>, binding: TokenStream, + variant: &VariantInfo<'_>, ) -> Result { let ident = &attr.path().segments.last().unwrap().ident; let name = ident.to_string(); @@ -388,7 +415,7 @@ impl DiagnosticDeriveVariantBuilder { match subdiag { SubdiagnosticKind::Label => { report_error_if_not_applied_to_span(attr, &info)?; - Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug, variant)) } SubdiagnosticKind::Note | SubdiagnosticKind::NoteOnce @@ -399,11 +426,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, slug)) + Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug, variant)) } else if type_is_unit(inner) || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner)) { - Ok(self.add_subdiagnostic(&fn_ident, slug)) + Ok(self.add_subdiagnostic(&fn_ident, slug, variant)) } else { report_type_error(attr, "`Span`, `MultiSpan`, `bool` or `()`")? } @@ -429,6 +456,7 @@ impl DiagnosticDeriveVariantBuilder { applicability.set_once(quote! { #static_applicability }, span); } + let message = slug.diag_message(variant); let applicability = applicability .value() .unwrap_or_else(|| quote! { rustc_errors::Applicability::Unspecified }); @@ -438,7 +466,7 @@ impl DiagnosticDeriveVariantBuilder { Ok(quote! { diag.span_suggestions_with_style( #span_field, - crate::fluent_generated::#slug, + #message, #code_field, #applicability, #style @@ -455,22 +483,30 @@ impl DiagnosticDeriveVariantBuilder { &self, field_binding: TokenStream, kind: &Ident, - fluent_attr_identifier: Path, + message: Message, + variant: &VariantInfo<'_>, ) -> TokenStream { let fn_name = format_ident!("span_{}", kind); + let message = message.diag_message(variant); quote! { diag.#fn_name( #field_binding, - crate::fluent_generated::#fluent_attr_identifier + #message ); } } /// Adds a subdiagnostic by generating a `diag.span_$kind` call with the current slug /// and `fluent_attr_identifier`. - fn add_subdiagnostic(&self, kind: &Ident, fluent_attr_identifier: Path) -> TokenStream { + fn add_subdiagnostic( + &self, + kind: &Ident, + message: Message, + variant: &VariantInfo<'_>, + ) -> TokenStream { + let message = message.diag_message(variant); quote! { - diag.#kind(crate::fluent_generated::#fluent_attr_identifier); + diag.#kind(#message); } } diff --git a/compiler/rustc_macros/src/diagnostics/message.rs b/compiler/rustc_macros/src/diagnostics/message.rs new file mode 100644 index 0000000000000..153abecf89372 --- /dev/null +++ b/compiler/rustc_macros/src/diagnostics/message.rs @@ -0,0 +1,133 @@ +use fluent_bundle::FluentResource; +use fluent_syntax::ast::{Expression, InlineExpression, Pattern, PatternElement}; +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::Path; +use synstructure::{Structure, VariantInfo}; + +use crate::diagnostics::error::span_err; + +#[derive(Clone)] +pub(crate) enum Message { + Slug(Path), + Inline(Span, String), +} + +impl Message { + pub(crate) fn diag_message(&self, variant: &VariantInfo<'_>) -> TokenStream { + match self { + Message::Slug(slug) => { + quote! { crate::fluent_generated::#slug } + } + Message::Inline(message_span, message) => { + verify_fluent_message(*message_span, &message, variant); + quote! { rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed(#message)) } + } + } + } + + /// Generates a `#[test]` that verifies that all referenced variables + /// exist on this structure. + pub(crate) fn generate_test(&self, structure: &Structure<'_>) -> TokenStream { + match self { + Message::Slug(slug) => { + // FIXME: We can't identify variables in a subdiagnostic + for field in structure.variants().iter().flat_map(|v| v.ast().fields.iter()) { + for attr_name in field.attrs.iter().filter_map(|at| at.path().get_ident()) { + if attr_name == "subdiagnostic" { + return quote!(); + } + } + } + use std::sync::atomic::{AtomicUsize, Ordering}; + // We need to make sure that the same diagnostic slug can be used multiple times without + // causing an error, so just have a global counter here. + static COUNTER: AtomicUsize = AtomicUsize::new(0); + let slug = slug.get_ident().unwrap(); + let ident = quote::format_ident!( + "verify_{slug}_{}", + COUNTER.fetch_add(1, Ordering::Relaxed) + ); + let ref_slug = quote::format_ident!("{slug}_refs"); + let struct_name = &structure.ast().ident; + let variables: Vec<_> = structure + .variants() + .iter() + .flat_map(|v| { + v.ast() + .fields + .iter() + .filter_map(|f| f.ident.as_ref().map(|i| i.to_string())) + }) + .collect(); + // tidy errors on `#[test]` outside of test files, so we use `#[test ]` to work around this + quote! { + #[cfg(test)] + #[test ] + fn #ident() { + let variables = [#(#variables),*]; + for vref in crate::fluent_generated::#ref_slug { + assert!(variables.contains(vref), "{}: variable `{vref}` not found ({})", stringify!(#struct_name), stringify!(#slug)); + } + } + } + } + Message::Inline(..) => { + // We don't generate a test for inline diagnostics, we can verify these at compile-time! + // This verification is done in the `diag_message` function above + quote! {} + } + } + } +} + +fn verify_fluent_message(msg_span: Span, message: &str, variant: &VariantInfo<'_>) { + // Parse the fluent message + const GENERATED_MSG_ID: &str = "generated_msg"; + let resource = FluentResource::try_new(format!("{GENERATED_MSG_ID} = {message}\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 + let fields: Vec = variant + .bindings() + .iter() + .flat_map(|b| b.ast().ident.as_ref()) + .map(|id| id.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(); + } + // assert!(, ); + } +} + +fn variable_references<'a>(msg: &fluent_syntax::ast::Message<&'a str>) -> Vec<&'a str> { + let mut refs = vec![]; + if let Some(Pattern { elements }) = &msg.value { + for elt in elements { + if let PatternElement::Placeable { + expression: Expression::Inline(InlineExpression::VariableReference { id }), + } = elt + { + refs.push(id.name); + } + } + } + for attr in &msg.attributes { + for elt in &attr.value.elements { + if let PatternElement::Placeable { + expression: Expression::Inline(InlineExpression::VariableReference { id }), + } = elt + { + refs.push(id.name); + } + } + } + refs +} diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index 55228248188e5..09f05ce972f18 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -1,6 +1,7 @@ mod diagnostic; mod diagnostic_builder; mod error; +mod message; mod subdiagnostic; mod utils; diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index db2a19ab85ba4..adc968dacd5cd 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -11,6 +11,7 @@ use super::utils::SubdiagnosticVariant; use crate::diagnostics::error::{ DiagnosticDeriveError, invalid_attr, span_err, throw_invalid_attr, throw_span_err, }; +use crate::diagnostics::message::Message; use crate::diagnostics::utils::{ AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap, SetOnce, SpannedOption, SubdiagnosticKind, build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident, @@ -74,7 +75,7 @@ impl SubdiagnosticDerive { has_subdiagnostic: false, is_enum, }; - builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) + builder.into_tokens(variant).unwrap_or_else(|v| v.to_compile_error()) }); quote! { @@ -182,7 +183,9 @@ impl<'a> FromIterator<&'a SubdiagnosticKind> for KindsStatistics { } impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { - fn identify_kind(&mut self) -> Result, DiagnosticDeriveError> { + fn identify_kind( + &mut self, + ) -> Result, DiagnosticDeriveError> { let mut kind_slugs = vec![]; for attr in self.variant.ast().attrs { @@ -494,7 +497,10 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { } } - pub(crate) fn into_tokens(&mut self) -> Result { + pub(crate) fn into_tokens( + &mut self, + variant: &VariantInfo<'_>, + ) -> Result { let kind_slugs = self.identify_kind()?; let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); @@ -532,9 +538,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let mut calls = TokenStream::new(); for (kind, slug) in kind_slugs { let message = format_ident!("__message"); - calls.extend( - quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); }, - ); + let message_stream = slug.diag_message(variant); + calls.extend(quote! { let #message = #diag.eagerly_translate(#message_stream); }); let name = format_ident!("{}{}", if span_field.is_some() { "span_" } else { "" }, kind); let call = match kind { diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index f084ba60ae3f4..a5265a847a9c7 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -16,6 +16,7 @@ use super::error::invalid_attr; use crate::diagnostics::error::{ DiagnosticDeriveError, span_err, throw_invalid_attr, throw_span_err, }; +use crate::diagnostics::message::Message; thread_local! { pub(crate) static CODE_IDENT_COUNT: RefCell = RefCell::new(0); @@ -587,7 +588,7 @@ pub(super) enum SubdiagnosticKind { pub(super) struct SubdiagnosticVariant { pub(super) kind: SubdiagnosticKind, - pub(super) slug: Option, + pub(super) slug: Option, } impl SubdiagnosticVariant { @@ -696,11 +697,31 @@ impl SubdiagnosticVariant { list.parse_args_with(|input: ParseStream<'_>| { let mut is_first = true; while !input.is_empty() { + // Try to parse an inline diagnostic message + if input.peek(LitStr) { + let message = input.parse::()?; + if !message.suffix().is_empty() { + span_err( + message.span().unwrap(), + "Inline message is not allowed to have a suffix", + ).emit(); + } + if !input.is_empty() { input.parse::()?; } + if is_first { + slug = Some(Message::Inline(message.span(), message.value())); + is_first = false; + } else { + span_err(message.span().unwrap(), "a diagnostic message must be the first argument to the attribute").emit(); + } + continue + } + + // Try to parse a slug instead let arg_name: Path = input.parse::()?; let arg_name_span = arg_name.span().unwrap(); if input.is_empty() || input.parse::().is_ok() { if is_first { - slug = Some(arg_name); + slug = Some(Message::Slug(arg_name)); is_first = false; } else { span_err(arg_name_span, "a diagnostic slug must be the first argument to the attribute").emit(); @@ -709,6 +730,7 @@ impl SubdiagnosticVariant { } is_first = false; + // Try to parse an argument match (arg_name.require_ident()?.to_string().as_str(), &mut kind) { ("code", SubdiagnosticKind::Suggestion { code_field, .. }) => { let code_init = build_suggestion_code( diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 393e9c59c3556..973ceccc67f99 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -441,6 +441,8 @@ impl<'tcx> Place<'tcx> { where D: ?Sized + HasLocalDecls<'tcx>, { + // If there's a field projection element in `projection`, we *could* skip everything + // before that, but on 2026-01-31 a perf experiment showed no benefit from doing so. PlaceTy::from_ty(local_decls.local_decls()[local].ty).multi_projection_ty(tcx, projection) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 4e33b8ebb6dee..0220531b09fa8 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -408,6 +408,12 @@ impl> Visibility { } } +impl + Copy> Visibility { + pub fn min(self, vis: Visibility, tcx: TyCtxt<'_>) -> Visibility { + if self.is_at_least(vis, tcx) { vis } else { self } + } +} + impl Visibility { pub fn expect_local(self) -> Visibility { self.map_id(|id| id.expect_local()) diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index bc73d36216ef4..fd08b5a972c68 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -50,9 +50,9 @@ impl<'tcx> Value> for ty::Binder<'_, ty::FnSig<'_>> { ) -> Self { let err = Ty::new_error(tcx, guar); - let arity = if let Some(frame) = cycle_error.cycle.get(0) - && frame.query.dep_kind == dep_kinds::fn_sig - && let Some(def_id) = frame.query.def_id + let arity = if let Some(info) = cycle_error.cycle.get(0) + && info.frame.dep_kind == dep_kinds::fn_sig + && let Some(def_id) = info.frame.def_id && let Some(node) = tcx.hir_get_if_local(def_id) && let Some(sig) = node.fn_sig() { @@ -85,10 +85,10 @@ impl<'tcx> Value> for Representability { let mut item_and_field_ids = Vec::new(); let mut representable_ids = FxHashSet::default(); for info in &cycle_error.cycle { - if info.query.dep_kind == dep_kinds::representability - && let Some(field_id) = info.query.def_id + if info.frame.dep_kind == dep_kinds::representability + && let Some(field_id) = info.frame.def_id && let Some(field_id) = field_id.as_local() - && let Some(DefKind::Field) = info.query.info.def_kind + && let Some(DefKind::Field) = info.frame.info.def_kind { let parent_id = tcx.parent(field_id.to_def_id()); let item_id = match tcx.def_kind(parent_id) { @@ -99,8 +99,8 @@ impl<'tcx> Value> for Representability { } } for info in &cycle_error.cycle { - if info.query.dep_kind == dep_kinds::representability_adt_ty - && let Some(def_id) = info.query.def_id_for_ty_in_cycle + if info.frame.dep_kind == dep_kinds::representability_adt_ty + && let Some(def_id) = info.frame.def_id_for_ty_in_cycle && let Some(def_id) = def_id.as_local() && !item_and_field_ids.iter().any(|&(id, _)| id == def_id) { @@ -141,9 +141,9 @@ impl<'tcx> Value> for &[ty::Variance] { search_for_cycle_permutation( &cycle_error.cycle, |cycle| { - if let Some(frame) = cycle.get(0) - && frame.query.dep_kind == dep_kinds::variances_of - && let Some(def_id) = frame.query.def_id + if let Some(info) = cycle.get(0) + && info.frame.dep_kind == dep_kinds::variances_of + && let Some(def_id) = info.frame.def_id { let n = tcx.generics_of(def_id).own_params.len(); ControlFlow::Break(vec![ty::Bivariant; n].leak()) @@ -189,8 +189,8 @@ impl<'tcx, T> Value> for Result> let diag = search_for_cycle_permutation( &cycle_error.cycle, |cycle| { - if cycle[0].query.dep_kind == dep_kinds::layout_of - && let Some(def_id) = cycle[0].query.def_id_for_ty_in_cycle + if cycle[0].frame.dep_kind == dep_kinds::layout_of + && let Some(def_id) = cycle[0].frame.def_id_for_ty_in_cycle && let Some(def_id) = def_id.as_local() && let def_kind = tcx.def_kind(def_id) && matches!(def_kind, DefKind::Closure) @@ -213,18 +213,18 @@ impl<'tcx, T> Value> for Result> tcx.def_kind_descr_article(def_kind, def_id.to_def_id()), tcx.def_kind_descr(def_kind, def_id.to_def_id()), ); - for (i, frame) in cycle.iter().enumerate() { - if frame.query.dep_kind != dep_kinds::layout_of { + for (i, info) in cycle.iter().enumerate() { + if info.frame.dep_kind != dep_kinds::layout_of { continue; } - let Some(frame_def_id) = frame.query.def_id_for_ty_in_cycle else { + let Some(frame_def_id) = info.frame.def_id_for_ty_in_cycle else { continue; }; let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else { continue; }; let frame_span = - frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span); + info.frame.info.default_span(cycle[(i + 1) % cycle.len()].span); if frame_span.is_dummy() { continue; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 8cf68b280850e..e413780d6c4fd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -299,6 +299,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDumpVtable(..) | AttributeKind::RustcDynIncompatibleTrait(..) | AttributeKind::RustcHasIncoherentInherentImpls + | AttributeKind::RustcHiddenTypeOfOpaques | AttributeKind::RustcLayout(..) | AttributeKind::RustcLayoutScalarValidRangeEnd(..) | AttributeKind::RustcLayoutScalarValidRangeStart(..) @@ -390,7 +391,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::rustc_capture_analysis | sym::rustc_regions | sym::rustc_strict_coherence - | sym::rustc_hidden_type_of_opaques | sym::rustc_mir | sym::rustc_effective_visibility | sym::rustc_outlives diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 4e79d0842da22..bd69c99a32dc0 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -2,10 +2,13 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![feature(adt_const_params)] #![feature(min_specialization)] #![feature(rustc_attrs)] // tidy-alphabetical-end +use std::marker::ConstParamTy; + use rustc_data_structures::stable_hasher::HashStable; use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; @@ -35,29 +38,34 @@ pub use crate::plumbing::{QueryCtxt, query_key_hash_verify_all}; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; +#[derive(ConstParamTy)] // Allow this struct to be used for const-generic values. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct QueryFlags { + /// True if this query has the `anon` modifier. + is_anon: bool, + /// True if this query has the `depth_limit` modifier. + is_depth_limit: bool, + /// True if this query has the `feedable` modifier. + is_feedable: bool, +} + /// Combines a [`QueryVTable`] with some additional compile-time booleans /// to implement [`QueryDispatcher`], for use by code in [`rustc_query_system`]. /// /// Baking these boolean flags into the type gives a modest but measurable /// improvement to compiler perf and compiler code size; see /// . -struct SemiDynamicQueryDispatcher< - 'tcx, - C: QueryCache, - const ANON: bool, - const DEPTH_LIMIT: bool, - const FEEDABLE: bool, -> { +struct SemiDynamicQueryDispatcher<'tcx, C: QueryCache, const FLAGS: QueryFlags> { vtable: &'tcx QueryVTable<'tcx, C>, } // Manually implement Copy/Clone, because deriving would put trait bounds on the cache type. -impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy - for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> Copy + for SemiDynamicQueryDispatcher<'tcx, C, FLAGS> { } -impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone - for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> Clone + for SemiDynamicQueryDispatcher<'tcx, C, FLAGS> { fn clone(&self) -> Self { *self @@ -65,8 +73,8 @@ impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDA } // This is `impl QueryDispatcher for SemiDynamicQueryDispatcher`. -impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> - QueryDispatcher<'tcx> for SemiDynamicQueryDispatcher<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +impl<'tcx, C: QueryCache, const FLAGS: QueryFlags> QueryDispatcher<'tcx> + for SemiDynamicQueryDispatcher<'tcx, C, FLAGS> where for<'a> C::Key: HashStable>, { @@ -86,10 +94,7 @@ where } #[inline(always)] - fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<'tcx, Self::Key> - where - QueryCtxt<'tcx>: 'a, - { + fn query_state(self, qcx: QueryCtxt<'tcx>) -> &'tcx QueryState<'tcx, Self::Key> { // Safety: // This is just manually doing the subfield referencing through pointer math. unsafe { @@ -100,7 +105,7 @@ where } #[inline(always)] - fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache { + fn query_cache(self, qcx: QueryCtxt<'tcx>) -> &'tcx Self::Cache { // Safety: // This is just manually doing the subfield referencing through pointer math. unsafe { @@ -158,7 +163,7 @@ where #[inline(always)] fn anon(self) -> bool { - ANON + FLAGS.is_anon } #[inline(always)] @@ -168,12 +173,12 @@ where #[inline(always)] fn depth_limit(self) -> bool { - DEPTH_LIMIT + FLAGS.is_depth_limit } #[inline(always)] fn feedable(self) -> bool { - FEEDABLE + FLAGS.is_feedable } #[inline(always)] @@ -216,12 +221,12 @@ trait QueryDispatcherUnerased<'tcx> { ) -> Self::UnerasedValue; } -pub fn query_system<'a>( +pub fn query_system<'tcx>( local_providers: Providers, extern_providers: ExternProviders, on_disk_cache: Option, incremental: bool, -) -> QuerySystem<'a> { +) -> QuerySystem<'tcx> { QuerySystem { states: Default::default(), arenas: Default::default(), diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 2d4e10a0380c8..518140d219c60 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -48,6 +48,23 @@ impl<'tcx> QueryCtxt<'tcx> { pub fn new(tcx: TyCtxt<'tcx>) -> Self { QueryCtxt { tcx } } + + fn depth_limit_error(self, job: QueryJobId) { + let query_map = self.collect_active_jobs(true).expect("failed to collect active queries"); + let (info, depth) = job.find_dep_kind_root(query_map); + + let suggested_limit = match self.tcx.recursion_limit() { + Limit(0) => Limit(2), + limit => limit * 2, + }; + + self.tcx.sess.dcx().emit_fatal(QueryOverflow { + span: info.job.span, + note: QueryOverflowNote { desc: info.frame.info.extract().description, depth }, + suggested_limit, + crate_name: self.tcx.crate_name(LOCAL_CRATE), + }); + } } impl<'tcx> HasDepContext for QueryCtxt<'tcx> { @@ -104,13 +121,6 @@ impl<'tcx> QueryContext<'tcx> for QueryCtxt<'tcx> { if complete { Ok(jobs) } else { Err(jobs) } } - fn lift_query_info( - self, - info: &QueryStackDeferred<'tcx>, - ) -> rustc_query_system::query::QueryStackFrameExtra { - info.extract() - } - // Interactions with on_disk_cache fn load_side_effect( self, @@ -162,26 +172,6 @@ impl<'tcx> QueryContext<'tcx> for QueryCtxt<'tcx> { tls::enter_context(&new_icx, compute) }) } - - fn depth_limit_error(self, job: QueryJobId) { - let query_map = self.collect_active_jobs(true).expect("failed to collect active queries"); - let (info, depth) = job.find_dep_kind_root(query_map); - - let suggested_limit = match self.tcx.recursion_limit() { - Limit(0) => Limit(2), - limit => limit * 2, - }; - - self.tcx.sess.dcx().emit_fatal(QueryOverflow { - span: info.job.span, - note: QueryOverflowNote { - desc: self.lift_query_info(&info.query.info).description, - depth, - }, - suggested_limit, - crate_name: self.tcx.crate_name(LOCAL_CRATE), - }); - } } pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool { @@ -708,14 +698,18 @@ macro_rules! define_queries { data: PhantomData<&'tcx ()> } + const FLAGS: QueryFlags = QueryFlags { + is_anon: is_anon!([$($modifiers)*]), + is_depth_limit: depth_limit!([$($modifiers)*]), + is_feedable: feedable!([$($modifiers)*]), + }; + impl<'tcx> QueryDispatcherUnerased<'tcx> for QueryType<'tcx> { type UnerasedValue = queries::$name::Value<'tcx>; type Dispatcher = SemiDynamicQueryDispatcher< 'tcx, queries::$name::Storage<'tcx>, - { is_anon!([$($modifiers)*]) }, - { depth_limit!([$($modifiers)*]) }, - { feedable!([$($modifiers)*]) }, + FLAGS, >; const NAME: &'static &'static str = &stringify!($name); @@ -738,14 +732,14 @@ macro_rules! define_queries { qmap: &mut QueryMap<'tcx>, require_complete: bool, ) -> Option<()> { - let make_query = |tcx, key| { + let make_frame = |tcx, key| { let kind = rustc_middle::dep_graph::dep_kinds::$name; let name = stringify!($name); $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) }; let res = tcx.query_system.states.$name.collect_active_jobs( tcx, - make_query, + make_frame, qmap, require_complete, ); diff --git a/compiler/rustc_query_system/src/query/dispatcher.rs b/compiler/rustc_query_system/src/query/dispatcher.rs index ac6c38dd7db55..bcd3d0322d07c 100644 --- a/compiler/rustc_query_system/src/query/dispatcher.rs +++ b/compiler/rustc_query_system/src/query/dispatcher.rs @@ -25,7 +25,7 @@ type DepContextOf<'tcx, This: QueryDispatcher<'tcx>> = /// Those types are not visible from this `rustc_query_system` crate. /// /// "Dispatcher" should be understood as a near-synonym of "vtable". -pub trait QueryDispatcher<'tcx>: Copy { +pub trait QueryDispatcher<'tcx>: Copy + 'tcx { fn name(self) -> &'static str; /// Query context used by this dispatcher, i.e. `rustc_query_impl::QueryCtxt`. @@ -41,10 +41,10 @@ pub trait QueryDispatcher<'tcx>: Copy { fn format_value(self) -> fn(&Self::Value) -> String; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_state<'a>(self, tcx: Self::Qcx) -> &'a QueryState<'tcx, Self::Key>; + fn query_state(self, tcx: Self::Qcx) -> &'tcx QueryState<'tcx, Self::Key>; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_cache<'a>(self, tcx: Self::Qcx) -> &'a Self::Cache; + fn query_cache(self, tcx: Self::Qcx) -> &'tcx Self::Cache; fn will_cache_on_disk_for_key(self, tcx: DepContextOf<'tcx, Self>, key: &Self::Key) -> bool; diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 177bcd63cbc62..82b23b022c37e 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -23,15 +23,12 @@ use crate::query::{QueryContext, QueryStackFrame}; pub struct QueryInfo { /// The span corresponding to the reason for which this query was required. pub span: Span, - pub query: QueryStackFrame, + pub frame: QueryStackFrame, } impl<'tcx> QueryInfo> { - pub(crate) fn lift>( - &self, - qcx: Qcx, - ) -> QueryInfo { - QueryInfo { span: self.span, query: self.query.lift(qcx) } + pub(crate) fn lift(&self) -> QueryInfo { + QueryInfo { span: self.span, frame: self.frame.lift() } } } @@ -42,8 +39,8 @@ pub type QueryMap<'tcx> = FxHashMap>; pub struct QueryJobId(pub NonZero); impl QueryJobId { - fn query<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> QueryStackFrame> { - map.get(&self).unwrap().query.clone() + fn frame<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> QueryStackFrame> { + map.get(&self).unwrap().frame.clone() } fn span<'a, 'tcx>(self, map: &'a QueryMap<'tcx>) -> Span { @@ -61,7 +58,7 @@ impl QueryJobId { #[derive(Clone, Debug)] pub struct QueryJobInfo<'tcx> { - pub query: QueryStackFrame>, + pub frame: QueryStackFrame>, pub job: QueryJob<'tcx>, } @@ -125,7 +122,7 @@ impl QueryJobId { while let Some(job) = current_job { let info = query_map.get(&job).unwrap(); - cycle.push(QueryInfo { span: info.job.span, query: info.query.clone() }); + cycle.push(QueryInfo { span: info.job.span, frame: info.frame.clone() }); if job == *self { cycle.reverse(); @@ -140,7 +137,7 @@ impl QueryJobId { .job .parent .as_ref() - .map(|parent| (info.job.span, parent.query(&query_map))); + .map(|parent| (info.job.span, parent.frame(&query_map))); return CycleError { usage, cycle }; } @@ -158,13 +155,13 @@ impl QueryJobId { ) -> (QueryJobInfo<'tcx>, usize) { let mut depth = 1; let info = query_map.get(&self).unwrap(); - let dep_kind = info.query.dep_kind; + let dep_kind = info.frame.dep_kind; let mut current_id = info.job.parent; let mut last_layout = (info.clone(), depth); while let Some(id) = current_id { let info = query_map.get(&id).unwrap(); - if info.query.dep_kind == dep_kind { + if info.frame.dep_kind == dep_kind { depth += 1; last_layout = (info.clone(), depth); } @@ -389,7 +386,7 @@ where .iter() .min_by_key(|v| { let (span, query) = f(v); - let hash = query.query(query_map).hash; + let hash = query.frame(query_map).hash; // Prefer entry points which have valid spans for nicer error messages // We add an integer to the tuple ensuring that entry points // with valid spans are picked first @@ -473,14 +470,14 @@ fn remove_cycle<'tcx>( stack.rotate_left(pos); } - let usage = usage.as_ref().map(|(span, query)| (*span, query.query(query_map))); + let usage = usage.as_ref().map(|(span, query)| (*span, query.frame(query_map))); // Create the cycle error let error = CycleError { usage, cycle: stack .iter() - .map(|&(s, ref q)| QueryInfo { span: s, query: q.query(query_map) }) + .map(|&(s, ref q)| QueryInfo { span: s, frame: q.frame(query_map) }) .collect(), }; @@ -559,7 +556,7 @@ pub fn report_cycle<'a>( ) -> Diag<'a> { assert!(!stack.is_empty()); - let span = stack[0].query.info.default_span(stack[1 % stack.len()].span); + let span = stack[0].frame.info.default_span(stack[1 % stack.len()].span); let mut cycle_stack = Vec::new(); @@ -567,9 +564,9 @@ pub fn report_cycle<'a>( let stack_count = if stack.len() == 1 { StackCount::Single } else { StackCount::Multiple }; for i in 1..stack.len() { - let query = &stack[i].query; - let span = query.info.default_span(stack[(i + 1) % stack.len()].span); - cycle_stack.push(CycleStack { span, desc: query.info.description.to_owned() }); + let frame = &stack[i].frame; + let span = frame.info.default_span(stack[(i + 1) % stack.len()].span); + cycle_stack.push(CycleStack { span, desc: frame.info.description.to_owned() }); } let mut cycle_usage = None; @@ -581,9 +578,9 @@ pub fn report_cycle<'a>( } let alias = - if stack.iter().all(|entry| matches!(entry.query.info.def_kind, Some(DefKind::TyAlias))) { + if stack.iter().all(|entry| matches!(entry.frame.info.def_kind, Some(DefKind::TyAlias))) { Some(crate::error::Alias::Ty) - } else if stack.iter().all(|entry| entry.query.info.def_kind == Some(DefKind::TraitAlias)) { + } else if stack.iter().all(|entry| entry.frame.info.def_kind == Some(DefKind::TraitAlias)) { Some(crate::error::Alias::Trait) } else { None @@ -592,7 +589,7 @@ pub fn report_cycle<'a>( let cycle_diag = crate::error::Cycle { span, cycle_stack, - stack_bottom: stack[0].query.info.description.to_owned(), + stack_bottom: stack[0].frame.info.description.to_owned(), alias, cycle_usage, stack_count, @@ -628,12 +625,12 @@ pub fn print_query_stack<'tcx, Qcx: QueryContext<'tcx>>( let Some(query_info) = query_map.get(&query) else { break; }; - let query_extra = qcx.lift_query_info(&query_info.query.info); + let query_extra = query_info.frame.info.extract(); if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. dcx.struct_failure_note(format!( "#{} [{:?}] {}", - count_printed, query_info.query.dep_kind, query_extra.description + count_printed, query_info.frame.dep_kind, query_extra.description )) .with_span(query_info.job.span) .emit(); @@ -645,7 +642,7 @@ pub fn print_query_stack<'tcx, Qcx: QueryContext<'tcx>>( file, "#{} [{}] {}", count_total, - qcx.dep_context().dep_kind_vtable(query_info.query.dep_kind).name, + qcx.dep_context().dep_kind_vtable(query_info.frame.dep_kind).name, query_extra.description ); } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index 63202429679d2..54e5fa4d72297 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -70,9 +70,9 @@ impl<'tcx> QueryStackFrame> { Self { info, def_id, dep_kind, hash, def_id_for_ty_in_cycle } } - fn lift>(&self, qcx: Qcx) -> QueryStackFrame { + fn lift(&self) -> QueryStackFrame { QueryStackFrame { - info: qcx.lift_query_info(&self.info), + info: self.info.extract(), dep_kind: self.dep_kind, hash: self.hash, def_id: self.def_id, @@ -168,8 +168,6 @@ pub trait QueryContext<'tcx>: HasDepContext { fn collect_active_jobs(self, require_complete: bool) -> Result, QueryMap<'tcx>>; - fn lift_query_info(self, info: &QueryStackDeferred<'tcx>) -> QueryStackFrameExtra; - /// Load a side effect associated to the node in the previous session. fn load_side_effect( self, @@ -183,6 +181,4 @@ pub trait QueryContext<'tcx>: HasDepContext { /// new query job while it executes. fn start_query(self, token: QueryJobId, depth_limit: bool, compute: impl FnOnce() -> R) -> R; - - fn depth_limit_error(self, job: QueryJobId); } diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 98bbd3ebc4a0f..4728391161073 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -82,7 +82,7 @@ where pub fn collect_active_jobs( &self, qcx: Qcx, - make_query: fn(Qcx, K) -> QueryStackFrame>, + make_frame: fn(Qcx, K) -> QueryStackFrame>, jobs: &mut QueryMap<'tcx>, require_complete: bool, ) -> Option<()> { @@ -108,11 +108,11 @@ where } } - // Call `make_query` while we're not holding a `self.active` lock as `make_query` may call + // Call `make_frame` while we're not holding a `self.active` lock as `make_frame` may call // queries leading to a deadlock. for (key, job) in active { - let query = make_query(qcx, key); - jobs.insert(job.id, QueryJobInfo { query, job }); + let frame = make_frame(qcx, key); + jobs.insert(job.id, QueryJobInfo { frame, job }); } Some(()) @@ -127,11 +127,11 @@ impl<'tcx, K> Default for QueryState<'tcx, K> { /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. -struct JobOwner<'a, 'tcx, K> +struct JobOwner<'tcx, K> where K: Eq + Hash + Copy, { - state: &'a QueryState<'tcx, K>, + state: &'tcx QueryState<'tcx, K>, key: K, } @@ -170,7 +170,7 @@ where } CycleErrorHandling::Stash => { let guar = if let Some(root) = cycle_error.cycle.first() - && let Some(span) = root.query.info.span + && let Some(span) = root.frame.info.span { error.stash(span, StashKey::Cycle).unwrap() } else { @@ -181,7 +181,7 @@ where } } -impl<'a, 'tcx, K> JobOwner<'a, 'tcx, K> +impl<'tcx, K> JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -218,7 +218,7 @@ where } } -impl<'a, 'tcx, K> Drop for JobOwner<'a, 'tcx, K> +impl<'tcx, K> Drop for JobOwner<'tcx, K> where K: Eq + Hash + Copy, { @@ -253,10 +253,10 @@ pub struct CycleError { } impl<'tcx> CycleError> { - fn lift>(&self, qcx: Qcx) -> CycleError { + fn lift(&self) -> CycleError { CycleError { - usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift(qcx))), - cycle: self.cycle.iter().map(|info| info.lift(qcx)).collect(), + usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift())), + cycle: self.cycle.iter().map(|info| info.lift()).collect(), } } } @@ -297,7 +297,7 @@ where let query_map = qcx.collect_active_jobs(false).ok().expect("failed to collect active queries"); let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span); - (mk_cycle(query, qcx, error.lift(qcx)), None) + (mk_cycle(query, qcx, error.lift()), None) } #[inline(always)] @@ -345,7 +345,7 @@ where (v, Some(index)) } - Err(cycle) => (mk_cycle(query, qcx, cycle.lift(qcx)), None), + Err(cycle) => (mk_cycle(query, qcx, cycle.lift()), None), } } @@ -422,7 +422,7 @@ where fn execute_job<'tcx, Q, const INCR: bool>( query: Q, qcx: Q::Qcx, - state: &QueryState<'tcx, Q::Key>, + state: &'tcx QueryState<'tcx, Q::Key>, key: Q::Key, key_hash: u64, id: QueryJobId, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6884ed1891a3f..f09b987157996 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -24,8 +24,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_PANIC_IMPORTS, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_IMPORT_VISIBILITIES, + AMBIGUOUS_PANIC_IMPORTS, MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, }; use rustc_session::utils::was_invoked_from_cargo; use rustc_span::edit_distance::find_best_match_for_name; @@ -145,6 +145,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; let lint = match ambiguity_warning { + _ if ambiguity_error.ambig_vis.is_some() => AMBIGUOUS_IMPORT_VISIBILITIES, AmbiguityWarning::GlobImport => AMBIGUOUS_GLOB_IMPORTS, AmbiguityWarning::PanicImport => AMBIGUOUS_PANIC_IMPORTS, }; @@ -1995,7 +1996,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } fn ambiguity_diagnostic(&self, ambiguity_error: &AmbiguityError<'ra>) -> errors::Ambiguity { - let AmbiguityError { kind, ident, b1, b2, scope1, scope2, .. } = *ambiguity_error; + let AmbiguityError { kind, ambig_vis, ident, b1, b2, scope1, scope2, .. } = + *ambiguity_error; let extern_prelude_ambiguity = || { // Note: b1 may come from a module scope, as an extern crate item in module. matches!(scope2, Scope::ExternPreludeFlags) @@ -2074,9 +2076,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None }; + let ambig_vis = ambig_vis.map(|(vis1, vis2)| { + format!( + "{} or {}", + vis1.to_string(CRATE_DEF_ID, self.tcx), + vis2.to_string(CRATE_DEF_ID, self.tcx) + ) + }); + errors::Ambiguity { ident, help, + ambig_vis, kind: kind.descr(), b1_note, b1_help_msgs, diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 205f2c6aa5395..3e54464030527 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1463,6 +1463,7 @@ pub(crate) struct UnknownDiagnosticAttributeTypoSugg { // FIXME: Make this properly translatable. pub(crate) struct Ambiguity { pub ident: Ident, + pub ambig_vis: Option, pub kind: &'static str, pub help: Option<&'static [&'static str]>, pub b1_note: Spanned, @@ -1473,8 +1474,12 @@ pub(crate) struct Ambiguity { impl Ambiguity { fn decorate<'a>(self, diag: &mut Diag<'a, impl EmissionGuarantee>) { - diag.primary_message(format!("`{}` is ambiguous", self.ident)); - diag.span_label(self.ident.span, "ambiguous name"); + if let Some(ambig_vis) = self.ambig_vis { + diag.primary_message(format!("ambiguous import visibility: {ambig_vis}")); + } else { + diag.primary_message(format!("`{}` is ambiguous", self.ident)); + diag.span_label(self.ident.span, "ambiguous name"); + } diag.note(format!("ambiguous because of {}", self.kind)); diag.span_note(self.b1_note.span, self.b1_note.node); if let Some(help) = self.help { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 0e73c349c8cdd..d4d373d820644 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -5,6 +5,7 @@ use Namespace::*; use rustc_ast::{self as ast, NodeId}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS}; +use rustc_middle::ty::Visibility; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; @@ -485,9 +486,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We do not need to report them if we are either in speculative resolution, // or in late resolution when everything is already imported and expanded // and no ambiguities exist. - if matches!(finalize, None | Some(Finalize { stage: Stage::Late, .. })) { - return ControlFlow::Break(Ok(decl)); - } + let import_vis = match finalize { + None | Some(Finalize { stage: Stage::Late, .. }) => { + return ControlFlow::Break(Ok(decl)); + } + Some(Finalize { import_vis, .. }) => import_vis, + }; if let Some(&(innermost_decl, _)) = innermost_results.first() { // Found another solution, if the first one was "weak", report an error. @@ -500,6 +504,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { decl, scope, &innermost_results, + import_vis, ) { // No need to search for more potential ambiguities, one is enough. return ControlFlow::Break(Ok(innermost_decl)); @@ -779,12 +784,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { decl: Decl<'ra>, scope: Scope<'ra>, innermost_results: &[(Decl<'ra>, Scope<'ra>)], + import_vis: Option, ) -> bool { let (innermost_decl, innermost_scope) = innermost_results[0]; let (res, innermost_res) = (decl.res(), innermost_decl.res()); - if res == innermost_res { + let ambig_vis = if res != innermost_res { + None + } else if let Some(import_vis) = import_vis + && let min = + (|d: Decl<'_>| d.vis().min(import_vis.to_def_id(), self.tcx).expect_local()) + && let (min1, min2) = (min(decl), min(innermost_decl)) + && min1 != min2 + { + Some((min1, min2)) + } else { return false; - } + }; // FIXME: Use `scope` instead of `res` to detect built-in attrs and derive helpers, // it will exclude imports, make slightly more code legal, and will require lang approval. @@ -871,10 +886,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { || (self.is_specific_builtin_macro(res, sym::core_panic) && self.is_specific_builtin_macro(innermost_res, sym::std_panic))); - let warning = is_issue_147319_hack.then_some(AmbiguityWarning::PanicImport); + let warning = if ambig_vis.is_some() { + Some(AmbiguityWarning::GlobImport) + } else if is_issue_147319_hack { + Some(AmbiguityWarning::PanicImport) + } else { + None + }; self.ambiguity_errors.push(AmbiguityError { kind, + ambig_vis, ident: ident.orig(orig_ident_span), b1: innermost_decl, b2: decl, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 0573400280857..78ad139cff795 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1189,7 +1189,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, &import.parent_scope, - Some(Finalize { report_private: false, ..finalize }), + Some(Finalize { + report_private: false, + import_vis: Some(import.vis), + ..finalize + }), bindings[ns].get().decl(), Some(import), ); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 75bd2c62f9b47..3a65598584ae0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -969,6 +969,7 @@ enum AmbiguityWarning { struct AmbiguityError<'ra> { kind: AmbiguityKind, + ambig_vis: Option<(Visibility, Visibility)>, ident: Ident, b1: Decl<'ra>, b2: Decl<'ra>, @@ -2087,6 +2088,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(b2) = used_decl.ambiguity.get() { let ambiguity_error = AmbiguityError { kind: AmbiguityKind::GlobVsGlob, + ambig_vis: None, ident, b1: used_decl, b2, @@ -2556,6 +2558,8 @@ struct Finalize { used: Used = Used::Other, /// Finalizing early or late resolution. stage: Stage = Stage::Early, + /// Nominal visibility of the import item, in case we are resolving an import's final segment. + import_vis: Option = None, } impl Finalize { diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index cc142fab8e821..4630fd729c6a1 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -108,6 +108,17 @@ pub mod consts { pub const FRAC_1_SQRT_3: f128 = 0.577350269189625764509148780501957455647601751270126876018602_f128; + /// sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + // Also, #[unstable(feature = "f128", issue = "116909")] + pub const SQRT_5: f128 = 2.23606797749978969640917366873127623544061835961152572427089_f128; + + /// 1/sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + // Also, #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_1_SQRT_5: f128 = + 0.447213595499957939281834733746255247088123671922305144854179_f128; + /// Euler's number (e) #[unstable(feature = "f128", issue = "116909")] pub const E: f128 = 2.71828182845904523536028747135266249775724709369995957496697_f128; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e97a44e991f66..21ba8f1f2828d 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -103,6 +103,16 @@ pub mod consts { // Also, #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f16 = 0.577350269189625764509148780501957456_f16; + /// sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + // Also, #[unstable(feature = "f16", issue = "116909")] + pub const SQRT_5: f16 = 2.23606797749978969640917366873127623_f16; + + /// 1/sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + // Also, #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_1_SQRT_5: f16 = 0.44721359549995793928183473374625524_f16; + /// Euler's number (e) #[unstable(feature = "f16", issue = "116909")] pub const E: f16 = 2.71828182845904523536028747135266250_f16; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 3d8249631037f..c4ec774f5956f 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -356,6 +356,14 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f32 = 0.577350269189625764509148780501957456_f32; + /// sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + pub const SQRT_5: f32 = 2.23606797749978969640917366873127623_f32; + + /// 1/sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + pub const FRAC_1_SQRT_5: f32 = 0.44721359549995793928183473374625524_f32; + /// Euler's number (e) #[stable(feature = "rust1", since = "1.0.0")] pub const E: f32 = 2.71828182845904523536028747135266250_f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 566a6a7ec947f..0bb8813235779 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -356,6 +356,14 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "146939")] pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64; + /// sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + pub const SQRT_5: f64 = 2.23606797749978969640917366873127623_f64; + + /// 1/sqrt(5) + #[unstable(feature = "more_float_constants", issue = "146939")] + pub const FRAC_1_SQRT_5: f64 = 0.44721359549995793928183473374625524_f64; + /// Euler's number (e) #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b213fa7491775..dcde208fac77b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -260,6 +260,7 @@ all(target_vendor = "fortanix", target_env = "sgx"), feature(slice_index_methods, coerce_unsized, sgx_platform) )] +#![cfg_attr(all(test, target_os = "uefi"), feature(uefi_std))] #![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] #![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] // diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs index ab5406e605c6b..82e3fc9775cba 100644 --- a/library/std/src/os/uefi/env.rs +++ b/library/std/src/os/uefi/env.rs @@ -4,13 +4,25 @@ use crate::ffi::c_void; use crate::ptr::NonNull; -use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr, Ordering}; +use crate::sync::atomic::Ordering; -static SYSTEM_TABLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut()); -static IMAGE_HANDLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut()); -// Flag to check if BootServices are still valid. -// Start with assuming that they are not available -static BOOT_SERVICES_FLAG: Atomic = AtomicBool::new(false); +#[doc(hidden)] +#[cfg(not(test))] +pub mod globals { + use crate::ffi::c_void; + use crate::sync::atomic::{Atomic, AtomicBool, AtomicPtr}; + + pub static SYSTEM_TABLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut()); + pub static IMAGE_HANDLE: Atomic<*mut c_void> = AtomicPtr::new(crate::ptr::null_mut()); + // Flag to check if BootServices are still valid. + // Start with assuming that they are not available + pub static BOOT_SERVICES_FLAG: Atomic = AtomicBool::new(false); +} + +#[cfg(not(test))] +use globals::*; +#[cfg(test)] +use realstd::os::uefi::env::globals::*; /// Initializes the global System Table and Image Handle pointers. /// diff --git a/src/tools/compiletest/src/directives/auxiliary.rs b/src/tools/compiletest/src/directives/auxiliary.rs index 14cbab640eb6b..0e7e370adbd41 100644 --- a/src/tools/compiletest/src/directives/auxiliary.rs +++ b/src/tools/compiletest/src/directives/auxiliary.rs @@ -26,8 +26,12 @@ pub struct AuxCrate { } /// The value of a `proc-macro` directive. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub(crate) struct ProcMacro { + /// Contains `--extern` modifiers, if any. See the tracking issue for more + /// info: + /// With `proc-macro: noprelude:bar.rs` this will be `noprelude`. + pub extern_modifiers: Option, /// With `proc-macro: bar.rs` this will be `bar.rs`. pub path: String, } @@ -108,5 +112,17 @@ fn parse_aux_crate(r: String) -> AuxCrate { } fn parse_proc_macro(r: String) -> ProcMacro { - ProcMacro { path: r.trim().to_string() } + let r = r.trim(); + + // Matches: + // path + // modifiers:path + let caps = static_regex!(r"^(?:(?[^=]*?):)?(?.*)$") + .captures(r) + .expect("can never fail"); + + let modifiers = caps.name("modifiers").map(|m| m.as_str().to_string()); + let path = caps["path"].to_string(); + + ProcMacro { extern_modifiers: modifiers, path } } diff --git a/src/tools/compiletest/src/directives/auxiliary/tests.rs b/src/tools/compiletest/src/directives/auxiliary/tests.rs index ad205eaabfda2..74fff630692ea 100644 --- a/src/tools/compiletest/src/directives/auxiliary/tests.rs +++ b/src/tools/compiletest/src/directives/auxiliary/tests.rs @@ -25,3 +25,19 @@ fn test_aux_crate_value_with_modifiers() { fn test_aux_crate_value_invalid() { parse_aux_crate("foo.rs".to_string()); } + +#[test] +fn test_proc_macro_value_no_modifiers() { + assert_eq!( + ProcMacro { extern_modifiers: None, path: "foo.rs".to_string() }, + parse_proc_macro("foo.rs".to_string()) + ); +} + +#[test] +fn test_proc_macro_value_with_modifiers() { + assert_eq!( + ProcMacro { extern_modifiers: Some("noprelude".to_string()), path: "foo.rs".to_string() }, + parse_proc_macro("noprelude:foo.rs".to_string()) + ); +} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e6eb1f3bd957f..ef90b81fb2a73 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1312,7 +1312,7 @@ impl<'test> TestCx<'test> { let crate_name = path_to_crate_name(&proc_macro.path); add_extern( rustc, - None, // `extern_modifiers` + proc_macro.extern_modifiers.as_deref(), &crate_name, &proc_macro.path, AuxType::ProcMacro, diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs new file mode 100644 index 0000000000000..babe3813e40b2 --- /dev/null +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.rs @@ -0,0 +1,777 @@ +//@ check-fail +// Tests error conditions for specifying diagnostics using #[derive(Diagnostic)] +// This test specifically tests diagnostic derives involving the inline fluent syntax. + +//@ normalize-stderr: "the following other types implement trait `IntoDiagArg`:(?:.*\n){0,9}\s+and \d+ others" -> "normalized in stderr" +//@ normalize-stderr: "(COMPILER_DIR/.*\.rs):[0-9]+:[0-9]+" -> "$1:LL:CC" + +// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, +// changing the output of this test. Since Diagnostic is strictly internal to the compiler +// the test is just ignored on stable and beta: +//@ ignore-stage1 +//@ ignore-beta +//@ ignore-stable + +#![feature(rustc_private)] +#![crate_type = "lib"] + +extern crate rustc_span; +use rustc_span::symbol::Ident; +use rustc_span::Span; + +extern crate rustc_fluent_macro; +extern crate rustc_macros; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; + +extern crate rustc_middle; +use rustc_middle::ty::Ty; + +extern crate rustc_errors; +use rustc_errors::{Applicability, DiagMessage, ErrCode, MultiSpan, SubdiagMessage}; + +extern crate rustc_session; + +extern crate core; + +// E0123 and E0456 are no longer used, so we define our own constants here just for this test. +const E0123: ErrCode = ErrCode::from_u32(0123); +const E0456: ErrCode = ErrCode::from_u32(0456); + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct Hello {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +//~^ ERROR unsupported type attribute for diagnostic derive enum +enum DiagnosticOnEnum { + Foo, + //~^ ERROR diagnostic slug not specified + Bar, + //~^ ERROR diagnostic slug not specified +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[diag = "E0123"] +//~^ ERROR expected parentheses: #[diag(...)] +struct WrongStructAttrStyle {} + +#[derive(Diagnostic)] +#[nonsense("this is an example message", code = E0123)] +//~^ ERROR `#[nonsense(...)]` is not a valid attribute +//~^^ ERROR diagnostic slug not specified +//~^^^ ERROR cannot find attribute `nonsense` in this scope +struct InvalidStructAttr {} + +#[derive(Diagnostic)] +#[diag(code = E0123)] +//~^ ERROR diagnostic slug not specified +struct InvalidLitNestedAttr {} + +#[derive(Diagnostic)] +#[diag(nonsense("foo"), code = E0123, slug = "foo")] +//~^ ERROR derive(Diagnostic): diagnostic slug not specified +struct InvalidNestedStructAttr1 {} + +#[derive(Diagnostic)] +#[diag(nonsense = "...", code = E0123, slug = "foo")] +//~^ ERROR diagnostic slug not specified +struct InvalidNestedStructAttr2 {} + +#[derive(Diagnostic)] +#[diag(nonsense = 4, code = E0123, slug = "foo")] +//~^ ERROR diagnostic slug not specified +struct InvalidNestedStructAttr3 {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123, slug = "foo")] +//~^ ERROR unknown argument +struct InvalidNestedStructAttr4 {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct WrongPlaceField { + #[suggestion = "bar"] + //~^ ERROR `#[suggestion = ...]` is not a valid attribute + sp: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[diag("this is an example message", code = E0456)] +//~^ ERROR specified multiple times +struct DiagSpecifiedTwice {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123, code = E0456)] +//~^ ERROR specified multiple times +struct CodeSpecifiedTwice {} + +#[derive(Diagnostic)] +#[diag("this is an example message", no_crate::example, code = E0123)] +//~^ ERROR diagnostic slug must be the first argument +struct SlugSpecifiedTwice {} + +#[derive(Diagnostic)] +struct KindNotProvided {} //~ ERROR diagnostic slug not specified + +#[derive(Diagnostic)] +#[diag(code = E0123)] +//~^ ERROR diagnostic slug not specified +struct SlugNotProvided {} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct CodeNotProvided {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct MessageWrongType { + #[primary_span] + //~^ ERROR `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + foo: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct InvalidPathFieldAttr { + #[nonsense] + //~^ ERROR `#[nonsense]` is not a valid attribute + //~^^ ERROR cannot find attribute `nonsense` in this scope + foo: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithField { + name: String, + #[label("with a label")] + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithMessageAppliedToField { + #[label("with a label")] + //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + name: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithNonexistentField { + #[suggestion("with a suggestion", code = "{name}")] + //~^ ERROR `name` doesn't refer to a field on this type + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +//~^ ERROR invalid format string: expected `}` +#[diag("this is an example message", code = E0123)] +struct ErrorMissingClosingBrace { + #[suggestion("with a suggestion", code = "{name")] + suggestion: (Span, Applicability), + name: String, + val: usize, +} + +#[derive(Diagnostic)] +//~^ ERROR invalid format string: unmatched `}` +#[diag("this is an example message", code = E0123)] +struct ErrorMissingOpeningBrace { + #[suggestion("with a suggestion", code = "name}")] + suggestion: (Span, Applicability), + name: String, + val: usize, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct LabelOnSpan { + #[label("with a label")] + sp: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct LabelOnNonSpan { + #[label("with a label")] + //~^ ERROR the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + id: u32, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct Suggest { + #[suggestion("with a suggestion", code = "This is the suggested code")] + #[suggestion("with a suggestion", code = "This is the suggested code", style = "normal")] + #[suggestion("with a suggestion", code = "This is the suggested code", style = "short")] + #[suggestion("with a suggestion", code = "This is the suggested code", style = "hidden")] + #[suggestion("with a suggestion", code = "This is the suggested code", style = "verbose")] + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithoutCode { + #[suggestion("with a suggestion")] + //~^ ERROR suggestion without `code = "..."` + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithBadKey { + #[suggestion("with a suggestion", nonsense = "bar")] + //~^ ERROR invalid nested attribute + //~| ERROR suggestion without `code = "..."` + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithShorthandMsg { + #[suggestion("with a suggestion", msg = "bar")] + //~^ ERROR invalid nested attribute + //~| ERROR suggestion without `code = "..."` + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithoutMsg { + #[suggestion("with a suggestion", code = "bar")] + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithTypesSwapped { + #[suggestion("with a suggestion", code = "This is suggested code")] + suggestion: (Applicability, Span), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithWrongTypeApplicabilityOnly { + #[suggestion("with a suggestion", code = "This is suggested code")] + //~^ ERROR wrong field type for suggestion + suggestion: Applicability, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithSpanOnly { + #[suggestion("with a suggestion", code = "This is suggested code")] + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithDuplicateSpanAndApplicability { + #[suggestion("with a suggestion", code = "This is suggested code")] + suggestion: (Span, Span, Applicability), + //~^ ERROR specified multiple times +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct SuggestWithDuplicateApplicabilityAndSpan { + #[suggestion("with a suggestion", code = "This is suggested code")] + suggestion: (Applicability, Applicability, Span), + //~^ ERROR specified multiple times +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct WrongKindOfAnnotation { + #[label = "bar"] + //~^ ERROR `#[label = ...]` is not a valid attribute + z: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct OptionsInErrors { + #[label("with a label")] + label: Option, + #[suggestion("with a suggestion", code = "...")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct MoveOutOfBorrowError<'tcx> { + name: Ident, + ty: Ty<'tcx>, + #[primary_span] + #[label("with a label")] + span: Span, + #[label("with a label")] + other_span: Span, + #[suggestion("with a suggestion", code = "{name}.clone()")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithLifetime<'a> { + #[label("with a label")] + span: Span, + name: &'a str, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ArgFieldWithoutSkip { + #[primary_span] + span: Span, + other: Hello, + //~^ ERROR the trait bound `Hello: IntoDiagArg` is not satisfied +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +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] + other: Hello, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithSpannedNote { + #[note("with a note")] + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[note("with a note")] +struct ErrorWithNote { + val: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithSpannedHelpCustom { + #[help("with a help")] + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[help("with a help")] +struct ErrorWithHelp { + val: String, +} + +#[derive(Diagnostic)] +#[help("with a help")] +#[diag("this is an example message", code = E0123)] +struct ErrorWithHelpWrongOrder { + val: String, +} + +#[derive(Diagnostic)] +#[note("with a note")] +#[diag("this is an example message", code = E0123)] +struct ErrorWithNoteWrongOrder { + val: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ApplicabilityInBoth { + #[suggestion("with a suggestion", code = "...", applicability = "maybe-incorrect")] + //~^ ERROR specified multiple times + suggestion: (Span, Applicability), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct InvalidApplicability { + #[suggestion("with a suggestion", code = "...", applicability = "batman")] + //~^ ERROR invalid applicability + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ValidApplicability { + #[suggestion("with a suggestion", code = "...", applicability = "maybe-incorrect")] + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct NoApplicability { + #[suggestion("with a suggestion", code = "...")] + suggestion: Span, +} + +#[derive(Subdiagnostic)] +#[note("this is an example message")] +struct Note; + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct Subdiagnostic { + #[subdiagnostic] + note: Note, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct VecField { + #[primary_span] + #[label("with a label")] + spans: Vec, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct UnitField { + #[primary_span] + spans: Span, + #[help("with a help")] + bar: (), +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct OptUnitField { + #[primary_span] + spans: Span, + #[help("with a help")] + foo: Option<()>, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct BoolField { + #[primary_span] + spans: Span, + #[help("with a help")] + foo: bool, + #[help("with a help")] + //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type + // only allow plain 'bool' fields + bar: Option, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct LabelWithTrailingPath { + #[label("with a label", foo)] + //~^ ERROR a diagnostic slug must be the first argument to the attribute + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct LabelWithTrailingNameValue { + #[label("with a label", foo = "...")] + //~^ ERROR no nested attribute expected here + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct LabelWithTrailingList { + #[label("with a label", foo("..."))] + //~^ ERROR no nested attribute expected here + span: Span, +} + +#[derive(LintDiagnostic)] +#[diag("this is an example message")] +struct LintsGood {} + +#[derive(LintDiagnostic)] +#[diag("this is an example message")] +struct PrimarySpanOnLint { + #[primary_span] + //~^ ERROR `#[primary_span]` is not a valid attribute + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct ErrorWithMultiSpan { + #[primary_span] + span: MultiSpan, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[warning("with a warning")] +struct ErrorWithWarn { + val: String, +} + +#[derive(Diagnostic)] +#[error("this is an example message", code = E0123)] +//~^ ERROR `#[error(...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified +//~| ERROR cannot find attribute `error` in this scope +struct ErrorAttribute {} + +#[derive(Diagnostic)] +#[warn_("this is an example message", code = E0123)] +//~^ ERROR `#[warn_(...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified +//~| ERROR cannot find attribute `warn_` in this scope +struct WarnAttribute {} + +#[derive(Diagnostic)] +#[lint("this is an example message", code = E0123)] +//~^ ERROR `#[lint(...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified +//~| ERROR cannot find attribute `lint` in this scope +struct LintAttributeOnSessionDiag {} + +#[derive(LintDiagnostic)] +#[lint("this is an example message", code = E0123)] +//~^ ERROR `#[lint(...)]` is not a valid attribute +//~| ERROR diagnostic slug not specified +//~| ERROR cannot find attribute `lint` in this scope +struct LintAttributeOnLintDiag {} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct DuplicatedSuggestionCode { + #[suggestion("with a suggestion", code = "...", code = ",,,")] + //~^ ERROR specified multiple times + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct InvalidTypeInSuggestionTuple { + #[suggestion("with a suggestion", code = "...")] + suggestion: (Span, usize), + //~^ ERROR wrong types for suggestion +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct MissingApplicabilityInSuggestionTuple { + #[suggestion("with a suggestion", code = "...")] + suggestion: (Span,), + //~^ ERROR wrong types for suggestion +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct MissingCodeInSuggestion { + #[suggestion("with a suggestion")] + //~^ ERROR suggestion without `code = "..."` + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[multipart_suggestion("with a suggestion")] +//~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute +//~| ERROR cannot find attribute `multipart_suggestion` in this scope +#[multipart_suggestion()] +//~^ ERROR cannot find attribute `multipart_suggestion` in this scope +//~| ERROR `#[multipart_suggestion(...)]` is not a valid attribute +struct MultipartSuggestion { + #[multipart_suggestion("with a suggestion")] + //~^ ERROR `#[multipart_suggestion(...)]` is not a valid attribute + //~| ERROR cannot find attribute `multipart_suggestion` in this scope + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[suggestion("with a suggestion", code = "...")] +//~^ ERROR `#[suggestion(...)]` is not a valid attribute +struct SuggestionOnStruct { + #[primary_span] + suggestion: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +#[label] +//~^ ERROR `#[label]` is not a valid attribute +struct LabelOnStruct { + #[primary_span] + suggestion: Span, +} + +#[derive(Diagnostic)] +enum ExampleEnum { + #[diag("this is an example message")] + Foo { + #[primary_span] + sp: Span, + #[note("with a note")] + note_sp: Span, + }, + #[diag("this is an example message")] + Bar { + #[primary_span] + sp: Span, + }, + #[diag("this is an example message")] + Baz, +} + +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct RawIdentDiagnosticArg { + pub r#type: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticBad { + #[subdiagnostic(bad)] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + note: Note, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticBadStr { + #[subdiagnostic = "bad"] + //~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute + note: Note, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticBadTwice { + #[subdiagnostic(bad, bad)] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + note: Note, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticBadLitStr { + #[subdiagnostic("bad")] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + note: Note, +} + +#[derive(LintDiagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticEagerLint { + #[subdiagnostic(eager)] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + note: Note, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticEagerFormerlyCorrect { + #[subdiagnostic(eager)] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + note: Note, +} + +// Check that formatting of `correct` in suggestion doesn't move the binding for that field, making +// the `arg` call a compile error; and that isn't worked around by moving the `arg` call +// after the `span_suggestion` call - which breaks eager translation. + +#[derive(Subdiagnostic)] +#[suggestion("example message", applicability = "machine-applicable", code = "{correct}")] +pub(crate) struct SubdiagnosticWithSuggestion { + #[primary_span] + span: Span, + invalid: String, + correct: String, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SubdiagnosticEagerSuggestion { + #[subdiagnostic(eager)] + //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute + sub: SubdiagnosticWithSuggestion, +} + +/// with a doc comment on the type.. +#[derive(Diagnostic)] +#[diag("this is an example message", code = E0123)] +struct WithDocComment { + /// ..and the field + #[primary_span] + span: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionsGood { + #[suggestion("with a suggestion", code("foo", "bar"))] + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionsSingleItem { + #[suggestion("with a suggestion", code("foo"))] + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionsNoItem { + #[suggestion("with a suggestion", code())] + //~^ ERROR expected at least one string literal for `code(...)` + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionsInvalidItem { + #[suggestion("with a suggestion", code(foo))] + //~^ ERROR `code(...)` must contain only string literals + //~| ERROR unexpected token, expected `)` + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionsInvalidLiteral { + #[suggestion("with a suggestion", code = 3)] + //~^ ERROR expected string literal + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionStyleGood { + #[suggestion("with a suggestion", code = "", style = "hidden")] + sub: Span, +} + +#[derive(Diagnostic)] +#[diag("this is an example message")] +struct SuggestionOnVec { + #[suggestion("with a suggestion", code = "")] + //~^ ERROR `#[suggestion(...)]` is not a valid attribute + sub: Vec, +} + +#[derive(Diagnostic)] +#[diag("exists: {$sub}")] +struct VariableExists { + sub: String, +} + +#[derive(Diagnostic)] +#[diag("does not exist: {$nosub}")] +//~^ ERROR Variable `nosub` not found in diagnostic +struct VariableDoesNotExist { + sub: String, +} diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr new file mode 100644 index 0000000000000..2ba3079402802 --- /dev/null +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-inline.stderr @@ -0,0 +1,635 @@ +error: derive(Diagnostic): unsupported type attribute for diagnostic derive enum + --> $DIR/diagnostic-derive-inline.rs:45:1 + | +LL | #[diag("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:48:5 + | +LL | Foo, + | ^^^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:50:5 + | +LL | Bar, + | ^^^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: expected parentheses: #[diag(...)] + --> $DIR/diagnostic-derive-inline.rs:56:8 + | +LL | #[diag = "E0123"] + | ^ + +error: derive(Diagnostic): `#[nonsense(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:61:1 + | +LL | #[nonsense("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:61:1 + | +LL | #[nonsense("this is an example message", code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:68:1 + | +LL | #[diag(code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:73:1 + | +LL | #[diag(nonsense("foo"), code = E0123, slug = "foo")] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:78:1 + | +LL | #[diag(nonsense = "...", code = E0123, slug = "foo")] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:83:1 + | +LL | #[diag(nonsense = 4, code = E0123, slug = "foo")] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): unknown argument + --> $DIR/diagnostic-derive-inline.rs:88:52 + | +LL | #[diag("this is an example message", code = E0123, slug = "foo")] + | ^^^^ + | + = note: only the `code` parameter is valid after the slug + +error: derive(Diagnostic): `#[suggestion = ...]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:95:5 + | +LL | #[suggestion = "bar"] + | ^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:102:38 + | +LL | #[diag("this is an example message", code = E0456)] + | ^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:101:38 + | +LL | #[diag("this is an example message", code = E0123)] + | ^^^^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:107:52 + | +LL | #[diag("this is an example message", code = E0123, code = E0456)] + | ^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:107:38 + | +LL | #[diag("this is an example message", code = E0123, code = E0456)] + | ^^^^ + +error: derive(Diagnostic): diagnostic slug must be the first argument + --> $DIR/diagnostic-derive-inline.rs:112:38 + | +LL | #[diag("this is an example message", no_crate::example, code = E0123)] + | ^^^^^^^^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:117:1 + | +LL | struct KindNotProvided {} + | ^^^^^^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:120:1 + | +LL | #[diag(code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive-inline.rs:131:5 + | +LL | #[primary_span] + | ^ + +error: derive(Diagnostic): `#[nonsense]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:139:5 + | +LL | #[nonsense] + | ^ + +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive-inline.rs:156:5 + | +LL | #[label("with a label")] + | ^ + +error: derive(Diagnostic): `name` doesn't refer to a field on this type + --> $DIR/diagnostic-derive-inline.rs:164:46 + | +LL | #[suggestion("with a suggestion", code = "{name}")] + | ^^^^^^^^ + +error: invalid format string: expected `}` but string was terminated + --> $DIR/diagnostic-derive-inline.rs:169:10 + | +LL | #[derive(Diagnostic)] + | ^^^^^^^^^^ expected `}` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid format string: unmatched `}` found + --> $DIR/diagnostic-derive-inline.rs:179:10 + | +LL | #[derive(Diagnostic)] + | ^^^^^^^^^^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: derive(Diagnostic): the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/diagnostic-derive-inline.rs:199:5 + | +LL | #[label("with a label")] + | ^ + +error: derive(Diagnostic): suggestion without `code = "..."` + --> $DIR/diagnostic-derive-inline.rs:218:5 + | +LL | #[suggestion("with a suggestion")] + | ^ + +error: derive(Diagnostic): invalid nested attribute + --> $DIR/diagnostic-derive-inline.rs:226:39 + | +LL | #[suggestion("with a suggestion", nonsense = "bar")] + | ^^^^^^^^ + | + = help: only `style`, `code` and `applicability` are valid nested attributes + +error: derive(Diagnostic): suggestion without `code = "..."` + --> $DIR/diagnostic-derive-inline.rs:226:5 + | +LL | #[suggestion("with a suggestion", nonsense = "bar")] + | ^ + +error: derive(Diagnostic): invalid nested attribute + --> $DIR/diagnostic-derive-inline.rs:235:39 + | +LL | #[suggestion("with a suggestion", msg = "bar")] + | ^^^ + | + = help: only `style`, `code` and `applicability` are valid nested attributes + +error: derive(Diagnostic): suggestion without `code = "..."` + --> $DIR/diagnostic-derive-inline.rs:235:5 + | +LL | #[suggestion("with a suggestion", msg = "bar")] + | ^ + +error: derive(Diagnostic): wrong field type for suggestion + --> $DIR/diagnostic-derive-inline.rs:258:5 + | +LL | #[suggestion("with a suggestion", code = "This is suggested code")] + | ^ + | + = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:274:24 + | +LL | suggestion: (Span, Span, Applicability), + | ^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:274:18 + | +LL | suggestion: (Span, Span, Applicability), + | ^^^^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:282:33 + | +LL | suggestion: (Applicability, Applicability, Span), + | ^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:282:18 + | +LL | suggestion: (Applicability, Applicability, Span), + | ^^^^^^^^^^^^^ + +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:289:5 + | +LL | #[label = "bar"] + | ^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:390:5 + | +LL | #[suggestion("with a suggestion", code = "...", applicability = "maybe-incorrect")] + | ^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:392:24 + | +LL | suggestion: (Span, Applicability), + | ^^^^^^^^^^^^^ + +error: derive(Diagnostic): invalid applicability + --> $DIR/diagnostic-derive-inline.rs:398: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:461:5 + | +LL | #[help("with a help")] + | ^ + +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute + --> $DIR/diagnostic-derive-inline.rs:470:29 + | +LL | #[label("with a label", foo)] + | ^^^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/diagnostic-derive-inline.rs:478:29 + | +LL | #[label("with a label", foo = "...")] + | ^^^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/diagnostic-derive-inline.rs:486:29 + | +LL | #[label("with a label", foo("..."))] + | ^^^ + +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:498:5 + | +LL | #[primary_span] + | ^ + | + = help: the `primary_span` field attribute is not valid for lint diagnostics + +error: derive(Diagnostic): `#[error(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:518:1 + | +LL | #[error("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:518:1 + | +LL | #[error("this is an example message", code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): `#[warn_(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:525:1 + | +LL | #[warn_("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:525:1 + | +LL | #[warn_("this is an example message", code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:532:1 + | +LL | #[lint("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:532:1 + | +LL | #[lint("this is an example message", code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): `#[lint(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:539:1 + | +LL | #[lint("this is an example message", code = E0123)] + | ^ + +error: derive(Diagnostic): diagnostic slug not specified + --> $DIR/diagnostic-derive-inline.rs:539:1 + | +LL | #[lint("this is an example message", code = E0123)] + | ^ + | + = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/diagnostic-derive-inline.rs:548:53 + | +LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] + | ^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive-inline.rs:548:39 + | +LL | #[suggestion("with a suggestion", code = "...", code = ",,,")] + | ^^^^ + +error: derive(Diagnostic): wrong types for suggestion + --> $DIR/diagnostic-derive-inline.rs:557:24 + | +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:565:17 + | +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:572:5 + | +LL | #[suggestion("with a suggestion")] + | ^ + +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:579:1 + | +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:582:1 + | +LL | #[multipart_suggestion()] + | ^ + | + = help: consider creating a `Subdiagnostic` instead + +error: derive(Diagnostic): `#[multipart_suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:586:5 + | +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:594:1 + | +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:603:1 + | +LL | #[label] + | ^ + | + = help: `#[label]` and `#[suggestion]` can only be applied to fields + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:637:5 + | +LL | #[subdiagnostic(bad)] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic = ...]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:645:5 + | +LL | #[subdiagnostic = "bad"] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:653:5 + | +LL | #[subdiagnostic(bad, bad)] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:661:5 + | +LL | #[subdiagnostic("bad")] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:669:5 + | +LL | #[subdiagnostic(eager)] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:677:5 + | +LL | #[subdiagnostic(eager)] + | ^ + +error: derive(Diagnostic): `#[subdiagnostic(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:698:5 + | +LL | #[subdiagnostic(eager)] + | ^ + +error: derive(Diagnostic): expected at least one string literal for `code(...)` + --> $DIR/diagnostic-derive-inline.rs:729:44 + | +LL | #[suggestion("with a suggestion", code())] + | ^ + +error: derive(Diagnostic): `code(...)` must contain only string literals + --> $DIR/diagnostic-derive-inline.rs:737:44 + | +LL | #[suggestion("with a suggestion", code(foo))] + | ^^^ + +error: unexpected token, expected `)` + --> $DIR/diagnostic-derive-inline.rs:737:44 + | +LL | #[suggestion("with a suggestion", code(foo))] + | ^^^ + +error: expected string literal + --> $DIR/diagnostic-derive-inline.rs:746:46 + | +LL | #[suggestion("with a suggestion", code = 3)] + | ^ + +error: derive(Diagnostic): `#[suggestion(...)]` is not a valid attribute + --> $DIR/diagnostic-derive-inline.rs:761:5 + | +LL | #[suggestion("with a suggestion", code = "")] + | ^ + | + = note: `#[suggestion(...)]` applied to `Vec` field is ambiguous + = help: to show a suggestion consisting of multiple parts, use a `Subdiagnostic` annotated with `#[multipart_suggestion(...)]` + = 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:773:8 + | +LL | #[diag("does not exist: {$nosub}")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: Available fields: "sub" + +error: cannot find attribute `nonsense` in this scope + --> $DIR/diagnostic-derive-inline.rs:61:3 + | +LL | #[nonsense("this is an example message", code = E0123)] + | ^^^^^^^^ + +error: cannot find attribute `nonsense` in this scope + --> $DIR/diagnostic-derive-inline.rs:139:7 + | +LL | #[nonsense] + | ^^^^^^^^ + +error: cannot find attribute `error` in this scope + --> $DIR/diagnostic-derive-inline.rs:518:3 + | +LL | #[error("this is an example message", code = E0123)] + | ^^^^^ + | +help: `error` is an attribute that can be used by the derive macro `Error`, you might be missing a `derive` attribute + | +LL + #[derive(Error)] +LL | struct ErrorAttribute {} + | + +error: cannot find attribute `warn_` in this scope + --> $DIR/diagnostic-derive-inline.rs:525:3 + | +LL | #[warn_("this is an example message", code = E0123)] + | ^^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[warn_("this is an example message", code = E0123)] +LL + #[warn("this is an example message", code = E0123)] + | + +error: cannot find attribute `lint` in this scope + --> $DIR/diagnostic-derive-inline.rs:532:3 + | +LL | #[lint("this is an example message", code = E0123)] + | ^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[lint("this is an example message", code = E0123)] +LL + #[link("this is an example message", code = E0123)] + | + +error: cannot find attribute `lint` in this scope + --> $DIR/diagnostic-derive-inline.rs:539:3 + | +LL | #[lint("this is an example message", code = E0123)] + | ^^^^ + | +help: a built-in attribute with a similar name exists + | +LL - #[lint("this is an example message", code = E0123)] +LL + #[link("this is an example message", code = E0123)] + | + +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive-inline.rs:579:3 + | +LL | #[multipart_suggestion("with a suggestion")] + | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | + +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive-inline.rs:582:3 + | +LL | #[multipart_suggestion()] + | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | + +error: cannot find attribute `multipart_suggestion` in this scope + --> $DIR/diagnostic-derive-inline.rs:586: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:330: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:42:1 + | +LL | struct Hello {} + | ^^^^^^^^^^^^ + = help: normalized in stderr +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 80 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 new file mode 100644 index 0000000000000..eaa681d40be59 --- /dev/null +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.rs @@ -0,0 +1,807 @@ +//@ check-fail +// Tests error conditions for specifying inline subdiagnostics using #[derive(Subdiagnostic)] + +// The proc_macro2 crate handles spans differently when on beta/stable release rather than nightly, +// changing the output of this test. Since Subdiagnostic is strictly internal to the compiler +// the test is just ignored on stable and beta: +//@ ignore-stage1 +//@ ignore-beta +//@ ignore-stable + +#![feature(rustc_private)] +#![crate_type = "lib"] + +extern crate rustc_errors; +extern crate rustc_fluent_macro; +extern crate rustc_macros; +extern crate rustc_session; +extern crate rustc_span; +extern crate core; + +use rustc_errors::{Applicability, DiagMessage, SubdiagMessage}; +use rustc_macros::Subdiagnostic; +use rustc_span::Span; + +#[derive(Subdiagnostic)] +#[label("example message")] +struct A { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +enum B { + #[label("example message")] + A { + #[primary_span] + span: Span, + var: String, + }, + #[label("example message")] + B { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +//~^ ERROR label without `#[primary_span]` field +struct C { + var: String, +} + +#[derive(Subdiagnostic)] +#[label] +//~^ ERROR diagnostic slug must be first argument +struct D { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[foo] +//~^ ERROR `#[foo]` is not a valid attribute +//~^^ ERROR cannot find attribute `foo` in this scope +struct E { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label = "..."] +//~^ ERROR `#[label = ...]` is not a valid attribute +struct F { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label(bug = "...")] +//~^ ERROR no nested attribute expected here +//~| ERROR diagnostic slug must be first argument +struct G { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label(slug = 4)] +//~^ ERROR no nested attribute expected here +//~| ERROR diagnostic slug must be first argument +struct J { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label(slug("..."))] +//~^ ERROR no nested attribute expected here +//~| ERROR diagnostic slug must be first argument +struct K { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label()] +//~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute +struct M { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label("example message", code = "...")] +//~^ ERROR no nested attribute expected here +struct N { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[label("example message", applicability = "machine-applicable")] +//~^ ERROR no nested attribute expected here +struct O { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[foo] +//~^ ERROR cannot find attribute `foo` in this scope +//~^^ ERROR unsupported type attribute for subdiagnostic enum +enum P { + #[label("example message")] + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum Q { + #[bar] + //~^ ERROR `#[bar]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum R { + #[bar = "..."] + //~^ ERROR `#[bar = ...]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum S { + #[bar = 4] + //~^ ERROR `#[bar = ...]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum T { + #[bar("...")] + //~^ ERROR `#[bar(...)]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum U { + #[label(code = "...")] + //~^ ERROR diagnostic slug must be first argument of a `#[label(...)]` attribute + //~| ERROR no nested attribute expected here + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum V { + #[label("example message")] + A { + #[primary_span] + span: Span, + var: String, + }, + B { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +//~^ ERROR label without `#[primary_span]` field +struct W { + #[primary_span] + //~^ ERROR the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + span: String, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct X { + #[primary_span] + span: Span, + #[applicability] + //~^ ERROR `#[applicability]` is only valid on suggestions + applicability: Applicability, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct Y { + #[primary_span] + span: Span, + #[bar] + //~^ ERROR `#[bar]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + bar: String, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct Z { + #[primary_span] + span: Span, + #[bar = "..."] + //~^ ERROR `#[bar = ...]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + bar: String, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct AA { + #[primary_span] + span: Span, + #[bar("...")] + //~^ ERROR `#[bar(...)]` is not a valid attribute + //~^^ ERROR cannot find attribute `bar` in this scope + bar: String, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct AB { + #[primary_span] + span: Span, + #[skip_arg] + z: Z, +} + +#[derive(Subdiagnostic)] +union AC { + //~^ ERROR unexpected unsupported untagged union + span: u32, + b: u64, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +#[label("example message")] +struct AD { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[label("example message", no_crate::example)] +//~^ ERROR a diagnostic slug must be the first argument to the attribute +struct AE { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct AF { + #[primary_span] + //~^ NOTE previously specified here + span_a: Span, + #[primary_span] + //~^ ERROR specified multiple times + span_b: Span, +} + +#[derive(Subdiagnostic)] +struct AG { + //~^ ERROR subdiagnostic kind not specified + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +struct AH { + #[primary_span] + span: Span, + #[applicability] + applicability: Applicability, + var: String, +} + +#[derive(Subdiagnostic)] +enum AI { + #[suggestion("example message", code = "...")] + A { + #[primary_span] + span: Span, + #[applicability] + applicability: Applicability, + var: String, + }, + #[suggestion("example message", code = "...")] + B { + #[primary_span] + span: Span, + #[applicability] + applicability: Applicability, + var: String, + }, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...", code = "...")] +//~^ ERROR specified multiple times +//~^^ NOTE previously specified here +struct AJ { + #[primary_span] + span: Span, + #[applicability] + applicability: Applicability, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +struct AK { + #[primary_span] + span: Span, + #[applicability] + //~^ NOTE previously specified here + applicability_a: Applicability, + #[applicability] + //~^ ERROR specified multiple times + applicability_b: Applicability, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +struct AL { + #[primary_span] + span: Span, + #[applicability] + //~^ ERROR the `#[applicability]` attribute can only be applied to fields of type `Applicability` + applicability: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +struct AM { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message")] +//~^ ERROR suggestion without `code = "..."` +struct AN { + #[primary_span] + span: Span, + #[applicability] + applicability: Applicability, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...", applicability = "foo")] +//~^ ERROR invalid applicability +struct AO { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[help("example message")] +struct AP { + var: String, +} + +#[derive(Subdiagnostic)] +#[note("example message")] +struct AQ; + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +//~^ ERROR suggestion without `#[primary_span]` field +struct AR { + var: String, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...", applicability = "machine-applicable")] +struct AS { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[label] +//~^ ERROR unsupported type attribute for subdiagnostic enum +enum AT { + #[label("example message")] + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "{var}", applicability = "machine-applicable")] +struct AU { + #[primary_span] + span: Span, + var: String, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "{var}", applicability = "machine-applicable")] +//~^ ERROR `var` doesn't refer to a field on this type +struct AV { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +enum AW { + #[suggestion("example message", code = "{var}", applicability = "machine-applicable")] + A { + #[primary_span] + span: Span, + var: String, + }, +} + +#[derive(Subdiagnostic)] +enum AX { + #[suggestion("example message", code = "{var}", applicability = "machine-applicable")] + //~^ ERROR `var` doesn't refer to a field on this type + A { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +#[warning("example message")] +struct AY {} + +#[derive(Subdiagnostic)] +#[warning("example message")] +struct AZ { + #[primary_span] + span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "...")] +//~^ ERROR suggestion without `#[primary_span]` field +struct BA { + #[suggestion_part] + //~^ ERROR `#[suggestion_part]` is not a valid attribute + span: Span, + #[suggestion_part(code = "...")] + //~^ ERROR `#[suggestion_part(...)]` is not a valid attribute + span2: Span, + #[applicability] + applicability: Applicability, + var: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")] +//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields +//~| ERROR invalid nested attribute +struct BBa { + var: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BBb { + #[suggestion_part] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BBc { + #[suggestion_part()] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +//~^ ERROR multipart suggestion without any `#[suggestion_part(...)]` fields +struct BC { + #[primary_span] + //~^ ERROR `#[primary_span]` is not a valid attribute + span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BD { + #[suggestion_part] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span1: Span, + #[suggestion_part()] + //~^ ERROR `#[suggestion_part(...)]` attribute without `code = "..."` + span2: Span, + #[suggestion_part(foo = "bar")] + //~^ ERROR `code` is the only valid nested attribute + //~| ERROR expected `,` + span4: Span, + #[suggestion_part(code = "...")] + //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + s1: String, + #[suggestion_part()] + //~^ ERROR the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` + s2: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BE { + #[suggestion_part(code = "...", code = ",,,")] + //~^ ERROR specified multiple times + //~| NOTE previously specified here + span: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BF { + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BG { + #[applicability] + appl: Applicability, + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BH { + #[applicability] + //~^ ERROR `#[applicability]` has no effect + appl: Applicability, + #[suggestion_part(code = "(")] + first: Span, + #[suggestion_part(code = ")")] + second: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message", applicability = "machine-applicable")] +struct BI { + #[suggestion_part(code = "")] + spans: Vec, +} + +#[derive(Subdiagnostic)] +#[label("example message")] +struct BJ { + #[primary_span] + span: Span, + r#type: String, +} + +/// with a doc comment on the type.. +#[derive(Subdiagnostic)] +#[label("example message")] +struct BK { + /// ..and the field + #[primary_span] + span: Span, +} + +/// with a doc comment on the type.. +#[derive(Subdiagnostic)] +enum BL { + /// ..and the variant.. + #[label("example message")] + Foo { + /// ..and the field + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BM { + #[suggestion_part(code("foo"))] + //~^ ERROR expected exactly one string literal for `code = ...` + //~| ERROR unexpected token, expected `)` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BN { + #[suggestion_part(code("foo", "bar"))] + //~^ ERROR expected exactly one string literal for `code = ...` + //~| ERROR unexpected token, expected `)` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BO { + #[suggestion_part(code(3))] + //~^ ERROR expected exactly one string literal for `code = ...` + //~| ERROR unexpected token, expected `)` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BP { + #[suggestion_part(code())] + //~^ ERROR expected exactly one string literal for `code = ...` + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("example message")] +struct BQ { + #[suggestion_part(code = 3)] + //~^ ERROR expected string literal + span: Span, + r#type: String, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "")] +struct SuggestionStyleDefault { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "short")] +struct SuggestionStyleShort { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "hidden")] +struct SuggestionStyleHidden { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "verbose")] +struct SuggestionStyleVerbose { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "tool-only")] +struct SuggestionStyleToolOnly { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "hidden", style = "normal")] +//~^ ERROR specified multiple times +//~| NOTE previously specified here +struct SuggestionStyleTwice { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion_hidden("example message", code = "")] +//~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute +struct SuggestionStyleOldSyntax { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion_hidden("example message", code = "", style = "normal")] +//~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute +struct SuggestionStyleOldAndNewSyntax { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = "foo")] +//~^ ERROR invalid suggestion style +struct SuggestionStyleInvalid1 { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style = 42)] +//~^ ERROR expected string literal +struct SuggestionStyleInvalid2 { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style)] +//~^ ERROR a diagnostic slug must be the first argument to the attribute +struct SuggestionStyleInvalid3 { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "", style("foo"))] +//~^ ERROR expected `=` +struct SuggestionStyleInvalid4 { + #[primary_span] + sub: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion("example message", code = "")] +//~^ ERROR suggestion without `#[primary_span]` field +struct PrimarySpanOnVec { + #[primary_span] + //~^ ERROR `#[primary_span]` is not a valid attribute + //~| NOTE there must be exactly one primary span + sub: Vec, +} + +#[derive(Subdiagnostic)] +struct NestedParent { + #[subdiagnostic] + single_sub: A, + #[subdiagnostic] + option_sub: Option, + #[subdiagnostic] + vec_sub: Vec, +} diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr new file mode 100644 index 0000000000000..11753b949bc7f --- /dev/null +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive-inline.stderr @@ -0,0 +1,549 @@ +error: derive(Diagnostic): label without `#[primary_span]` field + --> $DIR/subdiagnostic-derive-inline.rs:50:1 + | +LL | #[label("example message")] + | ^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:57:1 + | +LL | #[label] + | ^ + +error: derive(Diagnostic): `#[foo]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:66:1 + | +LL | #[foo] + | ^ + +error: derive(Diagnostic): `#[label = ...]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:76:1 + | +LL | #[label = "..."] + | ^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:85:9 + | +LL | #[label(bug = "...")] + | ^^^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:85:1 + | +LL | #[label(bug = "...")] + | ^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:95:9 + | +LL | #[label(slug = 4)] + | ^^^^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:95:1 + | +LL | #[label(slug = 4)] + | ^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:105:9 + | +LL | #[label(slug("..."))] + | ^^^^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:105:1 + | +LL | #[label(slug("..."))] + | ^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:115:1 + | +LL | #[label()] + | ^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:124:28 + | +LL | #[label("example message", code = "...")] + | ^^^^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:133:28 + | +LL | #[label("example message", applicability = "machine-applicable")] + | ^^^^^^^^^^^^^ + +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum + --> $DIR/subdiagnostic-derive-inline.rs:142:1 + | +LL | #[foo] + | ^ + +error: derive(Diagnostic): `#[bar]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:156:5 + | +LL | #[bar] + | ^ + +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:168:5 + | +LL | #[bar = "..."] + | ^ + +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:180:5 + | +LL | #[bar = 4] + | ^ + +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:192:5 + | +LL | #[bar("...")] + | ^ + +error: derive(Diagnostic): no nested attribute expected here + --> $DIR/subdiagnostic-derive-inline.rs:204:13 + | +LL | #[label(code = "...")] + | ^^^^ + +error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute + --> $DIR/subdiagnostic-derive-inline.rs:204:5 + | +LL | #[label(code = "...")] + | ^ + +error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` + --> $DIR/subdiagnostic-derive-inline.rs:233:5 + | +LL | #[primary_span] + | ^ + +error: derive(Diagnostic): label without `#[primary_span]` field + --> $DIR/subdiagnostic-derive-inline.rs:230:1 + | +LL | #[label("example message")] + | ^ + +error: derive(Diagnostic): `#[applicability]` is only valid on suggestions + --> $DIR/subdiagnostic-derive-inline.rs:243:5 + | +LL | #[applicability] + | ^ + +error: derive(Diagnostic): `#[bar]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:253:5 + | +LL | #[bar] + | ^ + | + = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes + +error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:264:5 + | +LL | #[bar = "..."] + | ^ + +error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:275:5 + | +LL | #[bar("...")] + | ^ + | + = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes + +error: unexpected unsupported untagged union + --> $DIR/subdiagnostic-derive-inline.rs:291:1 + | +LL | / union AC { +LL | | +LL | | span: u32, +LL | | b: u64, +LL | | } + | |_^ + +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute + --> $DIR/subdiagnostic-derive-inline.rs:306:28 + | +LL | #[label("example message", no_crate::example)] + | ^^^^^^^^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/subdiagnostic-derive-inline.rs:319:5 + | +LL | #[primary_span] + | ^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive-inline.rs:316:5 + | +LL | #[primary_span] + | ^ + +error: derive(Diagnostic): subdiagnostic kind not specified + --> $DIR/subdiagnostic-derive-inline.rs:325:8 + | +LL | struct AG { + | ^^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/subdiagnostic-derive-inline.rs:362:47 + | +LL | #[suggestion("example message", code = "...", code = "...")] + | ^^^^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive-inline.rs:362:33 + | +LL | #[suggestion("example message", code = "...", code = "...")] + | ^^^^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/subdiagnostic-derive-inline.rs:380:5 + | +LL | #[applicability] + | ^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive-inline.rs:377:5 + | +LL | #[applicability] + | ^ + +error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability` + --> $DIR/subdiagnostic-derive-inline.rs:390:5 + | +LL | #[applicability] + | ^ + +error: derive(Diagnostic): suggestion without `code = "..."` + --> $DIR/subdiagnostic-derive-inline.rs:403:1 + | +LL | #[suggestion("example message")] + | ^ + +error: derive(Diagnostic): invalid applicability + --> $DIR/subdiagnostic-derive-inline.rs:413:63 + | +LL | #[suggestion("example message", code = "...", applicability = "foo")] + | ^^^^^ + +error: derive(Diagnostic): suggestion without `#[primary_span]` field + --> $DIR/subdiagnostic-derive-inline.rs:431:1 + | +LL | #[suggestion("example message", code = "...")] + | ^ + +error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum + --> $DIR/subdiagnostic-derive-inline.rs:445:1 + | +LL | #[label] + | ^ + +error: derive(Diagnostic): `var` doesn't refer to a field on this type + --> $DIR/subdiagnostic-derive-inline.rs:465: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:484: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:507:5 + | +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:510:5 + | +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:504:1 + | +LL | #[suggestion("example message", code = "...")] + | ^ + +error: derive(Diagnostic): invalid nested attribute + --> $DIR/subdiagnostic-derive-inline.rs:519:43 + | +LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")] + | ^^^^ + | + = help: only `style` and `applicability` are valid nested attributes + +error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields + --> $DIR/subdiagnostic-derive-inline.rs:519:1 + | +LL | #[multipart_suggestion("example message", code = "...", applicability = "machine-applicable")] + | ^ + +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive-inline.rs:529:5 + | +LL | #[suggestion_part] + | ^ + +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive-inline.rs:537:5 + | +LL | #[suggestion_part()] + | ^ + +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:546:5 + | +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:543:1 + | +LL | #[multipart_suggestion("example message")] + | ^ + +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive-inline.rs:554:5 + | +LL | #[suggestion_part] + | ^ + +error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` + --> $DIR/subdiagnostic-derive-inline.rs:557:5 + | +LL | #[suggestion_part()] + | ^ + +error: derive(Diagnostic): `code` is the only valid nested attribute + --> $DIR/subdiagnostic-derive-inline.rs:560: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:564: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:567:5 + | +LL | #[suggestion_part()] + | ^ + +error: expected `,` + --> $DIR/subdiagnostic-derive-inline.rs:560:27 + | +LL | #[suggestion_part(foo = "bar")] + | ^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/subdiagnostic-derive-inline.rs:575:37 + | +LL | #[suggestion_part(code = "...", code = ",,,")] + | ^^^^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive-inline.rs:575: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:604:5 + | +LL | #[applicability] + | ^ + +error: derive(Diagnostic): expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive-inline.rs:652:28 + | +LL | #[suggestion_part(code("foo"))] + | ^^^^^ + +error: unexpected token, expected `)` + --> $DIR/subdiagnostic-derive-inline.rs:652:28 + | +LL | #[suggestion_part(code("foo"))] + | ^^^^^ + +error: derive(Diagnostic): expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive-inline.rs:662:28 + | +LL | #[suggestion_part(code("foo", "bar"))] + | ^^^^^ + +error: unexpected token, expected `)` + --> $DIR/subdiagnostic-derive-inline.rs:662:28 + | +LL | #[suggestion_part(code("foo", "bar"))] + | ^^^^^ + +error: derive(Diagnostic): expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive-inline.rs:672:28 + | +LL | #[suggestion_part(code(3))] + | ^ + +error: unexpected token, expected `)` + --> $DIR/subdiagnostic-derive-inline.rs:672:28 + | +LL | #[suggestion_part(code(3))] + | ^ + +error: derive(Diagnostic): expected exactly one string literal for `code = ...` + --> $DIR/subdiagnostic-derive-inline.rs:682:28 + | +LL | #[suggestion_part(code())] + | ^ + +error: expected string literal + --> $DIR/subdiagnostic-derive-inline.rs:691:30 + | +LL | #[suggestion_part(code = 3)] + | ^ + +error: derive(Diagnostic): attribute specified multiple times + --> $DIR/subdiagnostic-derive-inline.rs:733:1 + | +LL | #[suggestion("example message", code = "", style = "hidden", style = "normal")] + | ^ + | +note: previously specified here + --> $DIR/subdiagnostic-derive-inline.rs:733: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:742:1 + | +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:750:1 + | +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:758:52 + | +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:766:52 + | +LL | #[suggestion("example message", code = "", style = 42)] + | ^^ + +error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute + --> $DIR/subdiagnostic-derive-inline.rs:774:44 + | +LL | #[suggestion("example message", code = "", style)] + | ^^^^^ + +error: expected `=` + --> $DIR/subdiagnostic-derive-inline.rs:782:49 + | +LL | #[suggestion("example message", code = "", style("foo"))] + | ^ + +error: derive(Diagnostic): `#[primary_span]` is not a valid attribute + --> $DIR/subdiagnostic-derive-inline.rs:793:5 + | +LL | #[primary_span] + | ^ + | + = note: there must be exactly one 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:790:1 + | +LL | #[suggestion("example message", code = "")] + | ^ + +error: cannot find attribute `foo` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:66:3 + | +LL | #[foo] + | ^^^ + +error: cannot find attribute `foo` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:142:3 + | +LL | #[foo] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:156:7 + | +LL | #[bar] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:168:7 + | +LL | #[bar = "..."] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:180:7 + | +LL | #[bar = 4] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:192:7 + | +LL | #[bar("...")] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:253:7 + | +LL | #[bar] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:264:7 + | +LL | #[bar = "..."] + | ^^^ + +error: cannot find attribute `bar` in this scope + --> $DIR/subdiagnostic-derive-inline.rs:275:7 + | +LL | #[bar("...")] + | ^^^ + +error: aborting due to 82 previous errors + diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index b2e7b4c61daa0..c06ea451b9bfb 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -93,15 +93,6 @@ struct G { var: String, } -#[derive(Subdiagnostic)] -#[label("...")] -//~^ ERROR expected identifier -struct H { - #[primary_span] - span: Span, - var: String, -} - #[derive(Subdiagnostic)] #[label(slug = 4)] //~^ ERROR no nested attribute expected here diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 63634741e9347..9f18f7ffabcc3 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -34,116 +34,110 @@ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label( LL | #[label(bug = "...")] | ^ -error: expected identifier - --> $DIR/subdiagnostic-derive.rs:97:9 - | -LL | #[label("...")] - | ^^^^^ - error: derive(Diagnostic): no nested attribute expected here - --> $DIR/subdiagnostic-derive.rs:106:9 + --> $DIR/subdiagnostic-derive.rs:97:9 | LL | #[label(slug = 4)] | ^^^^ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:106:1 + --> $DIR/subdiagnostic-derive.rs:97:1 | LL | #[label(slug = 4)] | ^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/subdiagnostic-derive.rs:116:9 + --> $DIR/subdiagnostic-derive.rs:107:9 | LL | #[label(slug("..."))] | ^^^^ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:116:1 + --> $DIR/subdiagnostic-derive.rs:107:1 | LL | #[label(slug("..."))] | ^ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:126:1 + --> $DIR/subdiagnostic-derive.rs:117:1 | LL | #[label()] | ^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/subdiagnostic-derive.rs:135:27 + --> $DIR/subdiagnostic-derive.rs:126:27 | LL | #[label(no_crate_example, code = "...")] | ^^^^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/subdiagnostic-derive.rs:144:27 + --> $DIR/subdiagnostic-derive.rs:135:27 | LL | #[label(no_crate_example, applicability = "machine-applicable")] | ^^^^^^^^^^^^^ error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:153:1 + --> $DIR/subdiagnostic-derive.rs:144:1 | LL | #[foo] | ^ error: derive(Diagnostic): `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:167:5 + --> $DIR/subdiagnostic-derive.rs:158:5 | LL | #[bar] | ^ error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:179:5 + --> $DIR/subdiagnostic-derive.rs:170:5 | LL | #[bar = "..."] | ^ error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:191:5 + --> $DIR/subdiagnostic-derive.rs:182:5 | LL | #[bar = 4] | ^ error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:203:5 + --> $DIR/subdiagnostic-derive.rs:194:5 | LL | #[bar("...")] | ^ error: derive(Diagnostic): no nested attribute expected here - --> $DIR/subdiagnostic-derive.rs:215:13 + --> $DIR/subdiagnostic-derive.rs:206:13 | LL | #[label(code = "...")] | ^^^^ error: derive(Diagnostic): diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:215:5 + --> $DIR/subdiagnostic-derive.rs:206:5 | LL | #[label(code = "...")] | ^ error: derive(Diagnostic): the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:244:5 + --> $DIR/subdiagnostic-derive.rs:235:5 | LL | #[primary_span] | ^ error: derive(Diagnostic): label without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:241:1 + --> $DIR/subdiagnostic-derive.rs:232:1 | LL | #[label(no_crate_example)] | ^ error: derive(Diagnostic): `#[applicability]` is only valid on suggestions - --> $DIR/subdiagnostic-derive.rs:254:5 + --> $DIR/subdiagnostic-derive.rs:245:5 | LL | #[applicability] | ^ error: derive(Diagnostic): `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:264:5 + --> $DIR/subdiagnostic-derive.rs:255:5 | LL | #[bar] | ^ @@ -151,13 +145,13 @@ LL | #[bar] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: derive(Diagnostic): `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:275:5 + --> $DIR/subdiagnostic-derive.rs:266:5 | LL | #[bar = "..."] | ^ error: derive(Diagnostic): `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:286:5 + --> $DIR/subdiagnostic-derive.rs:277:5 | LL | #[bar("...")] | ^ @@ -165,7 +159,7 @@ LL | #[bar("...")] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: unexpected unsupported untagged union - --> $DIR/subdiagnostic-derive.rs:302:1 + --> $DIR/subdiagnostic-derive.rs:293:1 | LL | / union AC { LL | | @@ -175,97 +169,97 @@ LL | | } | |_^ error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute - --> $DIR/subdiagnostic-derive.rs:317:27 + --> $DIR/subdiagnostic-derive.rs:308:27 | LL | #[label(no_crate_example, no_crate::example)] | ^^^^^^^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive.rs:330:5 + --> $DIR/subdiagnostic-derive.rs:321:5 | LL | #[primary_span] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:327:5 + --> $DIR/subdiagnostic-derive.rs:318:5 | LL | #[primary_span] | ^ error: derive(Diagnostic): subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:336:8 + --> $DIR/subdiagnostic-derive.rs:327:8 | LL | struct AG { | ^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive.rs:373:46 + --> $DIR/subdiagnostic-derive.rs:364:46 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:373:32 + --> $DIR/subdiagnostic-derive.rs:364:32 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive.rs:391:5 + --> $DIR/subdiagnostic-derive.rs:382:5 | LL | #[applicability] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:388:5 + --> $DIR/subdiagnostic-derive.rs:379:5 | LL | #[applicability] | ^ error: derive(Diagnostic): the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:401:5 + --> $DIR/subdiagnostic-derive.rs:392:5 | LL | #[applicability] | ^ error: derive(Diagnostic): suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:414:1 + --> $DIR/subdiagnostic-derive.rs:405:1 | LL | #[suggestion(no_crate_example)] | ^ error: derive(Diagnostic): invalid applicability - --> $DIR/subdiagnostic-derive.rs:424:62 + --> $DIR/subdiagnostic-derive.rs:415:62 | LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")] | ^^^^^ error: derive(Diagnostic): suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:442:1 + --> $DIR/subdiagnostic-derive.rs:433:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ error: derive(Diagnostic): unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:456:1 + --> $DIR/subdiagnostic-derive.rs:447:1 | LL | #[label] | ^ error: derive(Diagnostic): `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:476:39 + --> $DIR/subdiagnostic-derive.rs:467:39 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: derive(Diagnostic): `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:495:43 + --> $DIR/subdiagnostic-derive.rs:486:43 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: derive(Diagnostic): `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:518:5 + --> $DIR/subdiagnostic-derive.rs:509:5 | LL | #[suggestion_part] | ^ @@ -273,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.rs:521:5 + --> $DIR/subdiagnostic-derive.rs:512:5 | LL | #[suggestion_part(code = "...")] | ^ @@ -281,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.rs:515:1 + --> $DIR/subdiagnostic-derive.rs:506:1 | LL | #[suggestion(no_crate_example, code = "...")] | ^ error: derive(Diagnostic): invalid nested attribute - --> $DIR/subdiagnostic-derive.rs:530:42 + --> $DIR/subdiagnostic-derive.rs:521:42 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] | ^^^^ @@ -295,25 +289,25 @@ LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "mac = help: only `style` and `applicability` are valid nested attributes error: derive(Diagnostic): multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:530:1 + --> $DIR/subdiagnostic-derive.rs:521:1 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:540:5 + --> $DIR/subdiagnostic-derive.rs:531:5 | LL | #[suggestion_part] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:548:5 + --> $DIR/subdiagnostic-derive.rs:539:5 | LL | #[suggestion_part()] | ^ error: derive(Diagnostic): `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:557:5 + --> $DIR/subdiagnostic-derive.rs:548:5 | LL | #[primary_span] | ^ @@ -321,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.rs:554:1 + --> $DIR/subdiagnostic-derive.rs:545:1 | LL | #[multipart_suggestion(no_crate_example)] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:565:5 + --> $DIR/subdiagnostic-derive.rs:556:5 | LL | #[suggestion_part] | ^ error: derive(Diagnostic): `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:568:5 + --> $DIR/subdiagnostic-derive.rs:559:5 | LL | #[suggestion_part()] | ^ error: derive(Diagnostic): `code` is the only valid nested attribute - --> $DIR/subdiagnostic-derive.rs:571:23 + --> $DIR/subdiagnostic-derive.rs:562: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.rs:575:5 + --> $DIR/subdiagnostic-derive.rs:566: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.rs:578:5 + --> $DIR/subdiagnostic-derive.rs:569:5 | LL | #[suggestion_part()] | ^ error: expected `,` - --> $DIR/subdiagnostic-derive.rs:571:27 + --> $DIR/subdiagnostic-derive.rs:562:27 | LL | #[suggestion_part(foo = "bar")] | ^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive.rs:586:37 + --> $DIR/subdiagnostic-derive.rs:577:37 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:586:23 + --> $DIR/subdiagnostic-derive.rs:577: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.rs:615:5 + --> $DIR/subdiagnostic-derive.rs:606:5 | LL | #[applicability] | ^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:663:28 + --> $DIR/subdiagnostic-derive.rs:654:28 | LL | #[suggestion_part(code("foo"))] | ^^^^^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive.rs:663:28 + --> $DIR/subdiagnostic-derive.rs:654:28 | LL | #[suggestion_part(code("foo"))] | ^^^^^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:673:28 + --> $DIR/subdiagnostic-derive.rs:664:28 | LL | #[suggestion_part(code("foo", "bar"))] | ^^^^^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive.rs:673:28 + --> $DIR/subdiagnostic-derive.rs:664:28 | LL | #[suggestion_part(code("foo", "bar"))] | ^^^^^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:683:28 + --> $DIR/subdiagnostic-derive.rs:674:28 | LL | #[suggestion_part(code(3))] | ^ error: unexpected token, expected `)` - --> $DIR/subdiagnostic-derive.rs:683:28 + --> $DIR/subdiagnostic-derive.rs:674:28 | LL | #[suggestion_part(code(3))] | ^ error: derive(Diagnostic): expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:693:28 + --> $DIR/subdiagnostic-derive.rs:684:28 | LL | #[suggestion_part(code())] | ^ error: expected string literal - --> $DIR/subdiagnostic-derive.rs:702:30 + --> $DIR/subdiagnostic-derive.rs:693:30 | LL | #[suggestion_part(code = 3)] | ^ error: derive(Diagnostic): attribute specified multiple times - --> $DIR/subdiagnostic-derive.rs:744:1 + --> $DIR/subdiagnostic-derive.rs:735:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:744:1 + --> $DIR/subdiagnostic-derive.rs:735:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^ error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:753:1 + --> $DIR/subdiagnostic-derive.rs:744:1 | LL | #[suggestion_hidden(no_crate_example, code = "")] | ^ @@ -449,7 +443,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: derive(Diagnostic): `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:761:1 + --> $DIR/subdiagnostic-derive.rs:752:1 | LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] | ^ @@ -457,7 +451,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: derive(Diagnostic): invalid suggestion style - --> $DIR/subdiagnostic-derive.rs:769:51 + --> $DIR/subdiagnostic-derive.rs:760:51 | LL | #[suggestion(no_crate_example, code = "", style = "foo")] | ^^^^^ @@ -465,25 +459,25 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")] = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only` error: expected string literal - --> $DIR/subdiagnostic-derive.rs:777:51 + --> $DIR/subdiagnostic-derive.rs:768:51 | LL | #[suggestion(no_crate_example, code = "", style = 42)] | ^^ error: derive(Diagnostic): a diagnostic slug must be the first argument to the attribute - --> $DIR/subdiagnostic-derive.rs:785:43 + --> $DIR/subdiagnostic-derive.rs:776:43 | LL | #[suggestion(no_crate_example, code = "", style)] | ^^^^^ error: expected `=` - --> $DIR/subdiagnostic-derive.rs:793:48 + --> $DIR/subdiagnostic-derive.rs:784:48 | LL | #[suggestion(no_crate_example, code = "", style("foo"))] | ^ error: derive(Diagnostic): `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:804:5 + --> $DIR/subdiagnostic-derive.rs:795:5 | LL | #[primary_span] | ^ @@ -492,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.rs:801:1 + --> $DIR/subdiagnostic-derive.rs:792:1 | LL | #[suggestion(no_crate_example, code = "")] | ^ @@ -504,52 +498,52 @@ LL | #[foo] | ^^^ error: cannot find attribute `foo` in this scope - --> $DIR/subdiagnostic-derive.rs:153:3 + --> $DIR/subdiagnostic-derive.rs:144:3 | LL | #[foo] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:167:7 + --> $DIR/subdiagnostic-derive.rs:158:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:179:7 + --> $DIR/subdiagnostic-derive.rs:170:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:191:7 + --> $DIR/subdiagnostic-derive.rs:182:7 | LL | #[bar = 4] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:203:7 + --> $DIR/subdiagnostic-derive.rs:194:7 | LL | #[bar("...")] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:264:7 + --> $DIR/subdiagnostic-derive.rs:255:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:275:7 + --> $DIR/subdiagnostic-derive.rs:266:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:286:7 + --> $DIR/subdiagnostic-derive.rs:277:7 | LL | #[bar("...")] | ^^^ -error: aborting due to 83 previous errors +error: aborting due to 82 previous errors diff --git a/tests/ui/argument-suggestions/disjoint-spans-issue-151607.rs b/tests/ui/argument-suggestions/disjoint-spans-issue-151607.rs new file mode 100644 index 0000000000000..31390faa488b1 --- /dev/null +++ b/tests/ui/argument-suggestions/disjoint-spans-issue-151607.rs @@ -0,0 +1,16 @@ +// Regression test for #151607 +// The ICE was "all spans must be disjoint" when emitting diagnostics +// with overlapping suggestion spans. + +struct B; +struct D; +struct F; +fn foo(g: F, y: F, e: &E) { + //~^ ERROR cannot find type `E` in this scope + foo(B, g, D, E, F, G) + //~^ ERROR this function takes 3 arguments but 6 arguments were supplied + //~| ERROR cannot find value `E` in this scope + //~| ERROR cannot find value `G` in this scope +} + +fn main() {} diff --git a/tests/ui/argument-suggestions/disjoint-spans-issue-151607.stderr b/tests/ui/argument-suggestions/disjoint-spans-issue-151607.stderr new file mode 100644 index 0000000000000..f1bda1203347b --- /dev/null +++ b/tests/ui/argument-suggestions/disjoint-spans-issue-151607.stderr @@ -0,0 +1,85 @@ +error[E0425]: cannot find type `E` in this scope + --> $DIR/disjoint-spans-issue-151607.rs:8:24 + | +LL | struct B; + | --------- similarly named struct `B` defined here +... +LL | fn foo(g: F, y: F, e: &E) { + | ^ + | +help: a struct with a similar name exists + | +LL - fn foo(g: F, y: F, e: &E) { +LL + fn foo(g: F, y: F, e: &B) { + | +help: you might be missing a type parameter + | +LL | fn foo(g: F, y: F, e: &E) { + | +++ + +error[E0425]: cannot find value `E` in this scope + --> $DIR/disjoint-spans-issue-151607.rs:10:18 + | +LL | foo(B, g, D, E, F, G) + | ^ + | +help: a local variable with a similar name exists + | +LL - foo(B, g, D, E, F, G) +LL + foo(B, g, D, e, F, G) + | +help: consider importing one of these constants + | +LL + use std::f128::consts::E; + | +LL + use std::f16::consts::E; + | +LL + use std::f32::consts::E; + | +LL + use std::f64::consts::E; + | + +error[E0425]: cannot find value `G` in this scope + --> $DIR/disjoint-spans-issue-151607.rs:10:24 + | +LL | foo(B, g, D, E, F, G) + | ^ + | +help: a local variable with a similar name exists + | +LL - foo(B, g, D, E, F, G) +LL + foo(B, g, D, E, F, g) + | +help: you might be missing a const parameter + | +LL | fn foo(g: F, y: F, e: &E) { + | +++++++++++++++++++++ + +error[E0061]: this function takes 3 arguments but 6 arguments were supplied + --> $DIR/disjoint-spans-issue-151607.rs:10:5 + | +LL | foo(B, g, D, E, F, G) + | ^^^ - - - unexpected argument #4 + | | | + | | unexpected argument #3 of type `D` + | unexpected argument #1 of type `B` + | +note: function defined here + --> $DIR/disjoint-spans-issue-151607.rs:8:4 + | +LL | fn foo(g: F, y: F, e: &E) { + | ^^^ ----- +help: consider borrowing here + | +LL | foo(B, g, D, E, F, &G) + | + +help: remove the extra arguments + | +LL - foo(B, g, D, E, F, G) +LL + foo(, g, F, G) + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0061, E0425. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/imports/ambiguous-import-visibility-macro.rs b/tests/ui/imports/ambiguous-import-visibility-macro.rs new file mode 100644 index 0000000000000..e1861cc5d4e0a --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility-macro.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +macro_rules! globbing{ + () => { + pub use same_res_ambigious_extern_macro::*; + } +} + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +globbing! {} // this imports the same `RustEmbed` macro with `pub` visibility + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; //~ WARN ambiguous import visibility + //~| WARN this was previously accepted +fn main() {} diff --git a/tests/ui/imports/ambiguous-import-visibility-macro.stderr b/tests/ui/imports/ambiguous-import-visibility-macro.stderr new file mode 100644 index 0000000000000..ed6eb6f893af2 --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility-macro.stderr @@ -0,0 +1,29 @@ +warning: ambiguous import visibility: pub(crate) or pub + --> $DIR/ambiguous-import-visibility-macro.rs:17:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ + | + = 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 #149145 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `RustEmbed` could refer to the derive macro imported here + --> $DIR/ambiguous-import-visibility-macro.rs:7:17 + | +LL | pub use same_res_ambigious_extern_macro::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | globbing! {} // this imports the same `RustEmbed` macro with `pub` visibility + | ------------ in this macro invocation + = help: consider adding an explicit import of `RustEmbed` to disambiguate + = help: or use `crate::RustEmbed` to refer to this derive macro unambiguously +note: `RustEmbed` could also refer to the derive macro imported here + --> $DIR/ambiguous-import-visibility-macro.rs:11:1 + | +LL | #[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility + | ^^^^^^^^^^^^ + = note: `#[warn(ambiguous_import_visibilities)]` (part of `#[warn(future_incompatible)]`) on by default + = note: this warning originates in the macro `globbing` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/imports/ambiguous-import-visibility-module.rs b/tests/ui/imports/ambiguous-import-visibility-module.rs new file mode 100644 index 0000000000000..35c6da8b21a4f --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility-module.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ edition:2018.. + +mod reexport { + mod m { + pub struct S {} + } + + macro_rules! mac { + () => { + use m::S; + }; + } + + pub use m::*; + mac!(); + + pub use S as Z; //~ WARN ambiguous import visibility + //~| WARN this was previously accepted +} + +fn main() { + reexport::Z {}; +} diff --git a/tests/ui/imports/ambiguous-import-visibility-module.stderr b/tests/ui/imports/ambiguous-import-visibility-module.stderr new file mode 100644 index 0000000000000..a97070c20a62d --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility-module.stderr @@ -0,0 +1,29 @@ +warning: ambiguous import visibility: pub or pub(in crate::reexport) + --> $DIR/ambiguous-import-visibility-module.rs:18:13 + | +LL | pub use S as Z; + | ^ + | + = 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 #149145 + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution +note: `S` could refer to the struct imported here + --> $DIR/ambiguous-import-visibility-module.rs:11:17 + | +LL | use m::S; + | ^^^^ +... +LL | mac!(); + | ------ in this macro invocation + = help: use `self::S` to refer to this struct unambiguously +note: `S` could also refer to the struct imported here + --> $DIR/ambiguous-import-visibility-module.rs:15:13 + | +LL | pub use m::*; + | ^^^^ + = help: use `self::S` to refer to this struct unambiguously + = note: `#[warn(ambiguous_import_visibilities)]` (part of `#[warn(future_incompatible)]`) on by default + = note: this warning originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/imports/ambiguous-import-visibility.rs b/tests/ui/imports/ambiguous-import-visibility.rs new file mode 100644 index 0000000000000..4cb8b763fbc9d --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ edition:2018 +//@ proc-macro: same-res-ambigious-extern-macro.rs + +#[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility +extern crate same_res_ambigious_extern_macro; +// this imports the same `RustEmbed` macro with `pub` visibility +pub use same_res_ambigious_extern_macro::*; + +pub trait RustEmbed {} + +pub use RustEmbed as Embed; //~ WARN ambiguous import visibility + //~| WARN this was previously accepted +fn main() {} diff --git a/tests/ui/imports/ambiguous-import-visibility.stderr b/tests/ui/imports/ambiguous-import-visibility.stderr new file mode 100644 index 0000000000000..30cddca4697d5 --- /dev/null +++ b/tests/ui/imports/ambiguous-import-visibility.stderr @@ -0,0 +1,25 @@ +warning: ambiguous import visibility: pub(crate) or pub + --> $DIR/ambiguous-import-visibility.rs:12:9 + | +LL | pub use RustEmbed as Embed; + | ^^^^^^^^^ + | + = 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 #149145 + = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution +note: `RustEmbed` could refer to the derive macro imported here + --> $DIR/ambiguous-import-visibility.rs:8:9 + | +LL | pub use same_res_ambigious_extern_macro::*; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: consider adding an explicit import of `RustEmbed` to disambiguate + = help: or use `crate::RustEmbed` to refer to this derive macro unambiguously +note: `RustEmbed` could also refer to the derive macro imported here + --> $DIR/ambiguous-import-visibility.rs:5:1 + | +LL | #[macro_use] // this imports the `RustEmbed` macro with `pub(crate)` visibility + | ^^^^^^^^^^^^ + = note: `#[warn(ambiguous_import_visibilities)]` (part of `#[warn(future_incompatible)]`) on by default + +warning: 1 warning emitted + diff --git a/tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs b/tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs index 9e2aa898afe8d..d45f2639d182f 100644 --- a/tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs +++ b/tests/ui/privacy/pub-priv-dep/auxiliary/pm.rs @@ -1,8 +1,3 @@ -//@ force-host -//@ no-prefer-dynamic - -#![crate_type = "proc-macro"] - extern crate proc_macro; use proc_macro::TokenStream; diff --git a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs index ae86be19cf960..ba947de7f182a 100644 --- a/tests/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/tests/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -1,6 +1,6 @@ //@ aux-crate:priv:priv_dep=priv_dep.rs //@ aux-build:pub_dep.rs -//@ aux-crate:priv:pm=pm.rs +//@ proc-macro:priv:pm.rs //@ compile-flags: -Zunstable-options // Basic behavior check of exported_private_dependencies from either a public diff --git a/tests/ui/traits/next-solver/generalize/relate-alias-in-lub.rs b/tests/ui/traits/next-solver/generalize/relate-alias-in-lub.rs new file mode 100644 index 0000000000000..a81e18559a391 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/relate-alias-in-lub.rs @@ -0,0 +1,30 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass +// Reproduces https://github.com/rust-lang/rust/pull/151746#issuecomment-3822930803. +// +// The change we tried to make there caused relating a type variable with an alias inside lub, +// In 5bd20bbd0ba6c0285664e55a1ffc677d7487c98b, we moved around code +// that adds an alias-relate predicate to be earlier, from one shared codepath into several +// distinct code paths. However, we forgot the codepath in `LatticeOp`, causing an ICE in serde. +// In the end we dropped said commit, but the reproducer is still a useful as test. + +use std::marker::PhantomData; + +pub trait Trait { + type Error; +} + +pub struct Struct(PhantomData); + +impl Trait for () { + type Error = (); +} + +fn main() { + let _: Struct<<() as Trait>::Error> = match loop {} { + b => loop {}, + a => Struct(PhantomData), + }; +}