diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index c6c85ffa84dd7..17ca1aa7fe170 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -1,7 +1,4 @@ -use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticArgFromDisplay, - SubdiagnosticMessage, -}; +use rustc_errors::DiagnosticArgFromDisplay; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; @@ -15,25 +12,15 @@ pub struct GenericTypeWithParentheses { pub sub: Option, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] +#[multipart_suggestion(ast_lowering::use_angle_brackets, applicability = "maybe-incorrect")] pub struct UseAngleBrackets { + #[suggestion_part(code = "<")] pub open_param: Span, + #[suggestion_part(code = ">")] pub close_param: Span, } -impl AddToDiagnostic for UseAngleBrackets { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - diag.multipart_suggestion( - fluent::ast_lowering::use_angle_brackets, - vec![(self.open_param, String::from("<")), (self.close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ); - } -} - #[derive(Diagnostic)] #[diag(ast_lowering::invalid_abi, code = "E0703")] #[note] @@ -68,30 +55,20 @@ pub struct AssocTyParentheses { pub sub: AssocTyParenthesesSub, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub enum AssocTyParenthesesSub { - Empty { parentheses_span: Span }, - NotEmpty { open_param: Span, close_param: Span }, -} - -impl AddToDiagnostic for AssocTyParenthesesSub { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self { - Self::Empty { parentheses_span } => diag.multipart_suggestion( - fluent::ast_lowering::remove_parentheses, - vec![(parentheses_span, String::new())], - Applicability::MaybeIncorrect, - ), - Self::NotEmpty { open_param, close_param } => diag.multipart_suggestion( - fluent::ast_lowering::use_angle_brackets, - vec![(open_param, String::from("<")), (close_param, String::from(">"))], - Applicability::MaybeIncorrect, - ), - }; - } + #[multipart_suggestion(ast_lowering::remove_parentheses)] + Empty { + #[suggestion_part(code = "")] + parentheses_span: Span, + }, + #[multipart_suggestion(ast_lowering::use_angle_brackets)] + NotEmpty { + #[suggestion_part(code = "<")] + open_param: Span, + #[suggestion_part(code = ">")] + close_param: Span, + }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1a4c60087c385..1dc8b85d7e6e7 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -14,6 +14,7 @@ use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{error_code, fluent, pluralize, struct_span_err, Applicability}; +use rustc_macros::Subdiagnostic; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -1782,15 +1783,17 @@ pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> } /// Used to forbid `let` expressions in certain syntactic locations. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Subdiagnostic)] pub(crate) enum ForbiddenLetReason { /// `let` is not valid and the source environment is not important GenericForbidden, /// A let chain with the `||` operator - NotSupportedOr(Span), + #[note(ast_passes::not_supported_or)] + NotSupportedOr(#[primary_span] Span), /// A let chain with invalid parentheses /// /// For example, `let 1 = 1 && (expr && expr)` is allowed /// but `(let 1 = 1 && (let 1 = 1 && (let 1 = 1))) && let a = 1` is not - NotSupportedParentheses(Span), + #[note(ast_passes::not_supported_parentheses)] + NotSupportedParentheses(#[primary_span] Span), } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index ba2ed24fc08fc..8319352bd24bd 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -16,23 +16,6 @@ pub struct ForbiddenLet { pub(crate) reason: ForbiddenLetReason, } -impl AddToDiagnostic for ForbiddenLetReason { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self { - Self::GenericForbidden => {} - Self::NotSupportedOr(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_or); - } - Self::NotSupportedParentheses(span) => { - diag.span_note(span, fluent::ast_passes::not_supported_parentheses); - } - } - } -} - #[derive(Diagnostic)] #[diag(ast_passes::forbidden_let_stable)] #[note] diff --git a/compiler/rustc_error_messages/locales/en-US/infer.ftl b/compiler/rustc_error_messages/locales/en-US/infer.ftl index 65371a285911e..18b3408b06ab4 100644 --- a/compiler/rustc_error_messages/locales/en-US/infer.ftl +++ b/compiler/rustc_error_messages/locales/en-US/infer.ftl @@ -164,7 +164,9 @@ infer_region_explanation = {$pref_kind -> } infer_mismatched_static_lifetime = incompatible lifetime on type -infer_msl_impl_note = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement +infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement infer_msl_introduces_static = introduces a `'static` lifetime requirement infer_msl_unmet_req = because this has an unmet lifetime requirement infer_msl_trait_note = this has an implicit `'static` lifetime requirement diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 47127ea8e9ce8..e2277923072f9 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -54,3 +54,7 @@ session_crate_name_empty = crate name must not be empty session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}` session_expr_parentheses_needed = parentheses are required to parse this as an expression + +session_skipping_const_checks = skipping const checks +session_unleashed_feature_help_named = skipping check for `{$gate}` feature +session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 860f24871bcdc..571b7dbfd1b04 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -1,14 +1,14 @@ use crate::{ fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg, }; -use rustc_target::abi::TargetDataLayoutErrors; -use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; - use rustc_ast as ast; use rustc_ast_pretty::pprust; use rustc_hir as hir; +use rustc_lint_defs::Level; use rustc_span::edition::Edition; use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; +use rustc_target::abi::TargetDataLayoutErrors; +use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; use std::borrow::Cow; use std::fmt; use std::num::ParseIntError; @@ -155,6 +155,21 @@ impl IntoDiagnosticArg for ast::token::TokenKind { } } +impl IntoDiagnosticArg for Level { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + Level::Allow => "-A", + Level::Warn => "-W", + Level::ForceWarn(_) => "--force-warn", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Expect(_) => { + unreachable!("lints with the level of `expect` should not run this code"); + } + })) + } +} + impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> { let mut diag; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 500900d3d4a74..25e8630bf6bd7 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -459,47 +459,34 @@ impl AddToDiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { } } -pub struct ImplNote { - pub impl_span: Option, -} - -impl AddToDiagnostic for ImplNote { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self.impl_span { - Some(span) => diag.span_note(span, fluent::infer::msl_impl_note), - None => diag.note(fluent::infer::msl_impl_note), - }; - } -} - -pub enum TraitSubdiag { - Note { span: Span }, - Sugg { span: Span }, +// FIXME(#100717): replace with a `Option` when subdiagnostic supports that +#[derive(Subdiagnostic)] +pub enum DoesNotOutliveStaticFromImpl { + #[note(infer::does_not_outlive_static_from_impl)] + Spanned { + #[primary_span] + span: Span, + }, + #[note(infer::does_not_outlive_static_from_impl)] + Unspanned, } -// FIXME(#100717) used in `Vec` so requires eager translation/list support -impl AddToDiagnostic for TraitSubdiag { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - match self { - TraitSubdiag::Note { span } => { - diag.span_note(span, "this has an implicit `'static` lifetime requirement"); - } - TraitSubdiag::Sugg { span } => { - diag.span_suggestion_verbose( - span, - "consider relaxing the implicit `'static` requirement", - " + '_".to_owned(), - rustc_errors::Applicability::MaybeIncorrect, - ); - } - } - } +#[derive(Subdiagnostic)] +pub enum ImplicitStaticLifetimeSubdiag { + #[note(infer::implicit_static_lifetime_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion_verbose( + infer::implicit_static_lifetime_suggestion, + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, } #[derive(Diagnostic)] @@ -512,7 +499,7 @@ pub struct MismatchedStaticLifetime<'a> { #[subdiagnostic] pub expl: Option>, #[subdiagnostic] - pub impl_note: ImplNote, - #[subdiagnostic] - pub trait_subdiags: Vec, + pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, + #[subdiagnostic(eager)] + pub implicit_static_lifetimes: Vec, } diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index 1410e2b63b0b8..c5f2a1a3f7dce 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -2,7 +2,9 @@ //! to hold. use crate::errors::{note_and_explain, IntroducesStaticBecauseUnmetLifetimeReq}; -use crate::errors::{ImplNote, MismatchedStaticLifetime, TraitSubdiag}; +use crate::errors::{ + DoesNotOutliveStaticFromImpl, ImplicitStaticLifetimeSubdiag, MismatchedStaticLifetime, +}; use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{SubregionOrigin, TypeTrace}; @@ -56,7 +58,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { note_and_explain::SuffixKind::Continues, ); let mut impl_span = None; - let mut trait_subdiags = Vec::new(); + let mut implicit_static_lifetimes = Vec::new(); if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) { // If an impl is local, then maybe this isn't what they want. Try to // be as helpful as possible with implicit lifetimes. @@ -90,10 +92,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // Otherwise, point at all implicit static lifetimes for span in &traits { - trait_subdiags.push(TraitSubdiag::Note { span: *span }); + implicit_static_lifetimes + .push(ImplicitStaticLifetimeSubdiag::Note { span: *span }); // It would be nice to put this immediately under the above note, but they get // pushed to the end. - trait_subdiags.push(TraitSubdiag::Sugg { span: span.shrink_to_hi() }); + implicit_static_lifetimes + .push(ImplicitStaticLifetimeSubdiag::Sugg { span: span.shrink_to_hi() }); } } } else { @@ -105,8 +109,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { cause_span: cause.span, unmet_lifetime_reqs: multispan_subdiag, expl, - impl_note: ImplNote { impl_span }, - trait_subdiags, + does_not_outlive_static_from_impl: impl_span + .map(|span| DoesNotOutliveStaticFromImpl::Spanned { span }) + .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned), + implicit_static_lifetimes, }; let reported = self.tcx().sess.emit_err(err); Some(reported) diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs index 97d012fb611d0..34b70030a5828 100644 --- a/compiler/rustc_lint/src/errors.rs +++ b/compiler/rustc_lint/src/errors.rs @@ -88,34 +88,13 @@ pub struct BuiltinEllpisisInclusiveRangePatterns { pub replace: String, } +#[derive(Subdiagnostic)] +#[note(lint::requested_level)] pub struct RequestedLevel { pub level: Level, pub lint_name: String, } -impl AddToDiagnostic for RequestedLevel { - fn add_to_diagnostic_with(self, diag: &mut Diagnostic, _: F) - where - F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage, - { - diag.note(fluent::lint::requested_level); - diag.set_arg( - "level", - match self.level { - Level::Allow => "-A", - Level::Warn => "-W", - Level::ForceWarn(_) => "--force-warn", - Level::Deny => "-D", - Level::Forbid => "-F", - Level::Expect(_) => { - unreachable!("lints with the level of `expect` should not run this code"); - } - }, - ); - diag.set_arg("lint_name", self.lint_name); - } -} - #[derive(Diagnostic)] #[diag(lint::unsupported_group, code = "E0602")] pub struct UnsupportedGroup { diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 787c9518b5089..36657909b19ee 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -7,6 +7,7 @@ use rustc_errors::{fluent, pluralize, Applicability, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_infer::traits::util::elaborate_predicates_with_span; use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; @@ -204,10 +205,13 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { ty::Adt(def, _) => check_must_use_def(cx, def.did(), span, descr_pre, descr_post), ty::Opaque(def, _) => { let mut has_emitted = false; - for &(predicate, _) in cx.tcx.explicit_item_bounds(def) { + for obligation in elaborate_predicates_with_span( + cx.tcx, + cx.tcx.explicit_item_bounds(def).iter().cloned(), + ) { // We only look at the `DefId`, so it is safe to skip the binder here. if let ty::PredicateKind::Trait(ref poly_trait_predicate) = - predicate.kind().skip_binder() + obligation.predicate.kind().skip_binder() { let def_id = poly_trait_predicate.trait_ref.def_id; let descr_pre = diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index dcbe89251cb36..9f7d2661a3e8b 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -5,7 +5,7 @@ use crate::diagnostics::error::{ DiagnosticDeriveError, }; use crate::diagnostics::utils::{ - build_field_mapping, report_error_if_not_applied_to_span, report_type_error, + build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; @@ -152,8 +152,12 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { fn parse_subdiag_attribute( &self, attr: &Attribute, - ) -> Result<(SubdiagnosticKind, Path), DiagnosticDeriveError> { - let (subdiag, slug) = SubdiagnosticKind::from_attr(attr, self)?; + ) -> Result, DiagnosticDeriveError> { + let Some((subdiag, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(None); + }; if let SubdiagnosticKind::MultipartSuggestion { .. } = subdiag { let meta = attr.parse_meta()?; @@ -170,7 +174,7 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(), }); - Ok((subdiag, slug)) + Ok(Some((subdiag, slug))) } /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct @@ -182,6 +186,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { ) -> Result { let diag = &self.parent.diag; + // Always allow documentation comments. + if is_doc_comment(attr) { + return Ok(quote! {}); + } + let name = attr.path.segments.last().unwrap().ident.to_string(); let name = name.as_str(); let meta = attr.parse_meta()?; @@ -250,7 +259,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { return Ok(tokens); } - let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; + let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(quote! {}); + }; let fn_ident = format_ident!("{}", subdiag); match subdiag { SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { @@ -291,6 +304,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { .attrs .iter() .map(move |attr| { + // Always allow documentation comments. + if is_doc_comment(attr) { + return quote! {}; + } + let name = attr.path.segments.last().unwrap().ident.to_string(); let needs_clone = name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_)); @@ -397,8 +415,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { _ => (), } - let (subdiag, slug) = self.parse_subdiag_attribute(attr)?; - + let Some((subdiag, slug)) = self.parse_subdiag_attribute(attr)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + return Ok(quote! {}); + }; let fn_ident = format_ident!("{}", subdiag); match subdiag { SubdiagnosticKind::Label => { diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs index 3d4c3ab9fd7c9..d1acb71384220 100644 --- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs @@ -5,9 +5,9 @@ use crate::diagnostics::error::{ DiagnosticDeriveError, }; use crate::diagnostics::utils::{ - build_field_mapping, new_code_ident, report_error_if_not_applied_to_applicability, - report_error_if_not_applied_to_span, FieldInfo, FieldInnerTy, FieldMap, HasFieldMap, SetOnce, - SpannedOption, SubdiagnosticKind, + build_field_mapping, is_doc_comment, new_code_ident, + report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo, + FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -41,8 +41,14 @@ impl SubdiagnosticDeriveBuilder { } } - if matches!(ast.data, syn::Data::Enum(..)) { + let is_enum = matches!(ast.data, syn::Data::Enum(..)); + if is_enum { for attr in &ast.attrs { + // Always allow documentation comments. + if is_doc_comment(attr) { + continue; + } + span_err( attr.span().unwrap(), "unsupported type attribute for subdiagnostic enum", @@ -62,6 +68,7 @@ impl SubdiagnosticDeriveBuilder { span_field: None, applicability: None, has_suggestion_parts: false, + is_enum, }; builder.into_tokens().unwrap_or_else(|v| v.to_compile_error()) }); @@ -79,7 +86,7 @@ impl SubdiagnosticDeriveBuilder { gen impl rustc_errors::AddToDiagnostic for @Self { fn add_to_diagnostic_with<__F>(self, #diag: &mut rustc_errors::Diagnostic, #f: __F) where - __F: Fn( + __F: core::ops::Fn( &mut rustc_errors::Diagnostic, rustc_errors::SubdiagnosticMessage ) -> rustc_errors::SubdiagnosticMessage, @@ -122,6 +129,9 @@ struct SubdiagnosticDeriveVariantBuilder<'parent, 'a> { /// Set to true when a `#[suggestion_part]` field is encountered, used to generate an error /// during finalization if still `false`. has_suggestion_parts: bool, + + /// Set to true when this variant is an enum variant rather than just the body of a struct. + is_enum: bool, } impl<'parent, 'a> HasFieldMap for SubdiagnosticDeriveVariantBuilder<'parent, 'a> { @@ -173,7 +183,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { let mut kind_slugs = vec![]; for attr in self.variant.ast().attrs { - let (kind, slug) = SubdiagnosticKind::from_attr(attr, self)?; + let Some((kind, slug)) = SubdiagnosticKind::from_attr(attr, self)? else { + // Some attributes aren't errors - like documentation comments - but also aren't + // subdiagnostics. + continue; + }; let Some(slug) = slug else { let name = attr.path.segments.last().unwrap().ident.to_string(); @@ -227,6 +241,11 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { ast.attrs .iter() .map(|attr| { + // Always allow documentation comments. + if is_doc_comment(attr) { + return quote! {}; + } + let info = FieldInfo { binding, ty: inner_ty.inner_type().unwrap_or(&ast.ty), @@ -290,6 +309,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { report_error_if_not_applied_to_span(attr, &info)?; let binding = info.binding.binding.clone(); + // FIXME(#100717): support `Option` on `primary_span` like in the + // diagnostic derive self.span_field.set_once(binding, span); } @@ -443,10 +464,16 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> { pub fn into_tokens(&mut self) -> Result { let kind_slugs = self.identify_kind()?; if kind_slugs.is_empty() { - throw_span_err!( - self.variant.ast().ident.span().unwrap(), - "subdiagnostic kind not specified" - ); + if self.is_enum { + // It's okay for a variant to not be a subdiagnostic at all.. + return Ok(quote! {}); + } else { + // ..but structs should always be _something_. + throw_span_err!( + self.variant.ast().ident.span().unwrap(), + "subdiagnostic kind not specified" + ); + } }; let kind_stats: KindsStatistics = kind_slugs.iter().map(|(kind, _slug)| kind).collect(); diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 4fd4adc511267..61d5007fc30f0 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -477,7 +477,12 @@ impl SubdiagnosticKind { pub(super) fn from_attr( attr: &Attribute, fields: &impl HasFieldMap, - ) -> Result<(SubdiagnosticKind, Option), DiagnosticDeriveError> { + ) -> Result)>, DiagnosticDeriveError> { + // Always allow documentation comments. + if is_doc_comment(attr) { + return Ok(None); + } + let span = attr.span().unwrap(); let name = attr.path.segments.last().unwrap().ident.to_string(); @@ -526,7 +531,9 @@ impl SubdiagnosticKind { | SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn - | SubdiagnosticKind::MultipartSuggestion { .. } => return Ok((kind, None)), + | SubdiagnosticKind::MultipartSuggestion { .. } => { + return Ok(Some((kind, None))); + } SubdiagnosticKind::Suggestion { .. } => { throw_span_err!(span, "suggestion without `code = \"...\"`") } @@ -626,7 +633,7 @@ impl SubdiagnosticKind { | SubdiagnosticKind::MultipartSuggestion { .. } => {} } - Ok((kind, slug)) + Ok(Some((kind, slug))) } } @@ -654,3 +661,7 @@ impl quote::IdentFragment for SubdiagnosticKind { pub(super) fn should_generate_set_arg(field: &Field) -> bool { field.attrs.is_empty() } + +pub(super) fn is_doc_comment(attr: &Attribute) -> bool { + attr.path.segments.last().unwrap().ident.to_string() == "doc" +} diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 59efb5aff7531..ba3d8f64bbc76 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1939,11 +1939,11 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { match ty.kind { TyKind::ImplicitSelf => true, TyKind::Path(None, _) => { - let path_res = self.r.partial_res_map[&ty.id].expect_full_res(); - if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path_res { + let path_res = self.r.partial_res_map[&ty.id].full_res(); + if let Some(Res::SelfTyParam { .. } | Res::SelfTyAlias { .. }) = path_res { return true; } - Some(path_res) == self.impl_self + self.impl_self.is_some() && path_res == self.impl_self } _ => false, } diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index d12796f289e96..500ab4a584cab 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,9 +1,7 @@ use std::num::NonZeroU32; use crate::cgu_reuse_tracker::CguReuse; -use rustc_errors::{ - fluent, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan, -}; +use rustc_errors::MultiSpan; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; @@ -148,24 +146,15 @@ pub struct CrateNameEmpty { pub span: Option, } +#[derive(Diagnostic)] +#[diag(session::invalid_character_in_create_name)] pub struct InvalidCharacterInCrateName<'a> { + #[primary_span] pub span: Option, pub character: char, pub crate_name: &'a str, } -impl IntoDiagnostic<'_> for InvalidCharacterInCrateName<'_> { - fn into_diagnostic(self, sess: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - let mut diag = sess.struct_err(fluent::session::invalid_character_in_create_name); - if let Some(sp) = self.span { - diag.set_span(sp); - } - diag.set_arg("character", self.character); - diag.set_arg("crate_name", self.crate_name); - diag - } -} - #[derive(Subdiagnostic)] #[multipart_suggestion(session::expr_parentheses_needed, applicability = "machine-applicable")] pub struct ExprParenthesesNeeded { @@ -180,3 +169,25 @@ impl ExprParenthesesNeeded { ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() } } } + +#[derive(Diagnostic)] +#[diag(session::skipping_const_checks)] +pub struct SkippingConstChecks { + #[subdiagnostic(eager)] + pub unleashed_features: Vec, +} + +#[derive(Subdiagnostic)] +pub enum UnleashedFeatureHelp { + #[help(session::unleashed_feature_help_named)] + Named { + #[primary_span] + span: Span, + gate: Symbol, + }, + #[help(session::unleashed_feature_help_unnamed)] + Unnamed { + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b5e25f45fa757..100c66f63641c 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -5,9 +5,10 @@ use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, S use crate::errors::{ CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, - SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks, SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, - TargetRequiresUnwindTables, UnstableVirtualFunctionElimination, UnsupportedDwarfVersion, + TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination, + UnsupportedDwarfVersion, }; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; @@ -232,21 +233,19 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. - // FIXME(#100717): needs eager translation/lists - #[allow(rustc::untranslatable_diagnostic)] - #[allow(rustc::diagnostic_outside_of_impl)] - let mut diag = self.struct_warn("skipping const checks"); - for &(span, feature_gate) in unleashed_features.iter() { - // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. - if let Some(gate) = feature_gate { - diag.span_help(span, &format!("skipping check for `{gate}` feature")); - // The unleash flag must *not* be used to just "hack around" feature gates. - must_err = true; - } else { - diag.span_help(span, "skipping check that does not even have a feature gate"); - } - } - diag.emit(); + self.emit_warning(SkippingConstChecks { + unleashed_features: unleashed_features + .iter() + .map(|(span, gate)| { + gate.map(|gate| { + must_err = true; + UnleashedFeatureHelp::Named { span: *span, gate } + }) + .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span }) + }) + .collect(), + }); + // If we should err, make sure we did. if must_err && self.has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs index 9692222534eaa..6c66b93a3e1a3 100644 --- a/library/std/src/sys/solid/fs.rs +++ b/library/std/src/sys/solid/fs.rs @@ -175,15 +175,19 @@ impl Iterator for ReadDir { type Item = io::Result; fn next(&mut self) -> Option> { - unsafe { - let mut out_dirent = MaybeUninit::uninit(); - error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir( + let entry = unsafe { + let mut out_entry = MaybeUninit::uninit(); + match error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir( self.inner.dirp, - out_dirent.as_mut_ptr(), - )) - .ok()?; - Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) })) - } + out_entry.as_mut_ptr(), + )) { + Ok(_) => out_entry.assume_init(), + Err(e) if e.as_raw() == abi::SOLID_ERR_NOTFOUND => return None, + Err(e) => return Some(Err(e.as_io_error())), + } + }; + + (entry.d_name[0] != 0).then(|| Ok(DirEntry { entry, inner: Arc::clone(&self.inner) })) } } diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 759a59e1f98d2..d4a1b9d9b50c8 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -356,7 +356,7 @@ impl Instant { /// /// # Panics /// - /// Previous rust versions panicked when self was earlier than the current time. Currently this + /// Previous rust versions panicked when the current time was earlier than self. Currently this /// method returns a Duration of zero in that case. Future versions may reintroduce the panic. /// See [Monotonicity]. /// diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 7bdd226cb692e..f512c5023d93f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -228,7 +228,7 @@ impl Step for TheBook { } // build the version info page and CSS - builder.ensure(Standalone { compiler, target }); + let shared_assets = builder.ensure(SharedAssets { target }); // build the redirect pages builder.info(&format!("Documenting book redirect pages ({})", target)); @@ -237,7 +237,7 @@ impl Step for TheBook { let path = file.path(); let path = path.to_str().unwrap(); - invoke_rustdoc(builder, compiler, target, path); + invoke_rustdoc(builder, compiler, &shared_assets, target, path); } if builder.was_invoked_explicitly::(Kind::Doc) { @@ -251,6 +251,7 @@ impl Step for TheBook { fn invoke_rustdoc( builder: &Builder<'_>, compiler: Compiler, + shared_assets: &SharedAssetsPaths, target: TargetSelection, markdown: &str, ) { @@ -260,7 +261,6 @@ fn invoke_rustdoc( let header = builder.src.join("src/doc/redirect.inc"); let footer = builder.src.join("src/doc/footer.inc"); - let version_info = out.join("version_info.html"); let mut cmd = builder.rustdoc_cmd(compiler); @@ -269,7 +269,7 @@ fn invoke_rustdoc( cmd.arg("--html-after-content") .arg(&footer) .arg("--html-before-content") - .arg(&version_info) + .arg(&shared_assets.version_info) .arg("--html-in-header") .arg(&header) .arg("--markdown-no-toc") @@ -300,7 +300,7 @@ impl Step for Standalone { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/doc").default_condition(builder.config.docs) + run.path("src/doc").alias("standalone").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -325,21 +325,11 @@ impl Step for Standalone { let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); + let version_info = builder.ensure(SharedAssets { target: self.target }).version_info; + let favicon = builder.src.join("src/doc/favicon.inc"); let footer = builder.src.join("src/doc/footer.inc"); let full_toc = builder.src.join("src/doc/full-toc.inc"); - t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); - - let version_input = builder.src.join("src/doc/version_info.html.template"); - let version_info = out.join("version_info.html"); - - if !builder.config.dry_run && !up_to_date(&version_input, &version_info) { - let info = t!(fs::read_to_string(&version_input)) - .replace("VERSION", &builder.rust_release()) - .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or("")) - .replace("STAMP", builder.rust_info.sha().unwrap_or("")); - t!(fs::write(&version_info, &info)); - } for file in t!(fs::read_dir(builder.src.join("src/doc"))) { let file = t!(file); @@ -401,6 +391,45 @@ impl Step for Standalone { } } +#[derive(Debug, Clone)] +pub struct SharedAssetsPaths { + pub version_info: PathBuf, +} + +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct SharedAssets { + target: TargetSelection, +} + +impl Step for SharedAssets { + type Output = SharedAssetsPaths; + const DEFAULT: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + // Other tasks depend on this, no need to execute it on its own + run.never() + } + + // Generate shared resources used by other pieces of documentation. + fn run(self, builder: &Builder<'_>) -> Self::Output { + let out = builder.doc_out(self.target); + + let version_input = builder.src.join("src").join("doc").join("version_info.html.template"); + let version_info = out.join("version_info.html"); + if !builder.config.dry_run && !up_to_date(&version_input, &version_info) { + let info = t!(fs::read_to_string(&version_input)) + .replace("VERSION", &builder.rust_release()) + .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or("")) + .replace("STAMP", builder.rust_info.sha().unwrap_or("")); + t!(fs::write(&version_info, &info)); + } + + builder.copy(&builder.src.join("src").join("doc").join("rust.css"), &out.join("rust.css")); + + SharedAssetsPaths { version_info } + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { pub stage: u32, diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md index 507631cdc540a..432e0cfc960e3 100644 --- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md +++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md @@ -1,7 +1,7 @@ # armeb-unknown-linux-gnueabi **Tier: 3** -Target for cross-compiling Linux user-mode applications targetting the ARM BE8 architecture. +Target for cross-compiling Linux user-mode applications targeting the ARM BE8 architecture. ## Overview BE8 architecture retains the same little-endian ordered code-stream used by conventional little endian ARM systems, however the data accesses are in big-endian. BE8 is used primarily in high-performance networking applications where the ability to read packets in their native "Network Byte Order" is important (many network protocols transmit data in big-endian byte order for their wire formats). diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5f674ed7441ba..13d63ffa0ee3c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1201,21 +1201,19 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } if let ty::TraitContainer = assoc_item.container { - // FIXME(fmease): `tcx.explicit_item_bounds` does not contain the bounds of GATs, - // e.g. the bounds `Copy`, `Display` & (implicitly) `Sized` in - // `type Assoc where T: Display`. This also means that we - // later incorrectly render `where T: ?Sized`. - // - // The result of `tcx.explicit_predicates_of` *does* contain them but - // it does not contain the other bounds / predicates we need. - // Either merge those two interned lists somehow or refactor - // `clean_ty_generics` to call `explicit_item_bounds` by itself. let bounds = tcx.explicit_item_bounds(assoc_item.def_id); - let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; - let mut generics = - clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates); - // Filter out the bounds that are (likely?) directly attached to the associated type, - // as opposed to being located in the where clause. + let predicates = tcx.explicit_predicates_of(assoc_item.def_id).predicates; + let predicates = + tcx.arena.alloc_from_iter(bounds.into_iter().chain(predicates).copied()); + let mut generics = clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + ty::GenericPredicates { parent: None, predicates }, + ); + // Move bounds that are (likely) directly attached to the associated type + // from the where clause to the associated type. + // There is no guarantee that this is what the user actually wrote but we have + // no way of knowing. let mut bounds = generics .where_predicates .drain_filter(|pred| match *pred { @@ -1273,6 +1271,24 @@ pub(crate) fn clean_middle_assoc_item<'tcx>( } None => bounds.push(GenericBound::maybe_sized(cx)), } + // Move bounds that are (likely) directly attached to the parameters of the + // (generic) associated type from the where clause to the respective parameter. + // There is no guarantee that this is what the user actually wrote but we have + // no way of knowing. + let mut where_predicates = Vec::new(); + for mut pred in generics.where_predicates { + if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred + && let Some(GenericParamDef { + kind: GenericParamDefKind::Type { bounds: param_bounds, .. }, + .. + }) = generics.params.iter_mut().find(|param| ¶m.name == arg) + { + param_bounds.extend(mem::take(bounds)); + } else { + where_predicates.push(pred); + } + } + generics.where_predicates = where_predicates; if tcx.impl_defaultness(assoc_item.def_id).has_value() { AssocTypeItem( diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index d8f4bc2db22e1..0b816eace64b1 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -409,9 +409,12 @@ function loadCss(cssFileName) { break; case "+": + ev.preventDefault(); + expandAllDocs(); + break; case "-": ev.preventDefault(); - toggleAllDocs(); + collapseAllDocs(); break; case "?": @@ -614,15 +617,31 @@ function loadCss(cssFileName) { sidebarElems.appendChild(ul); } + function expandAllDocs() { + const innerToggle = document.getElementById(toggleAllDocsId); + removeClass(innerToggle, "will-expand"); + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + if (!hasClass(e, "type-contents-toggle")) { + e.open = true; + } + }); + innerToggle.title = "collapse all docs"; + innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "−" minus sign + } - function labelForToggleButton(sectionIsCollapsed) { - if (sectionIsCollapsed) { - // button will expand the section - return "+"; - } - // button will collapse the section - // note that this text is also set in the HTML template in ../render/mod.rs - return "\u2212"; // "\u2212" is "−" minus sign + function collapseAllDocs() { + const innerToggle = document.getElementById(toggleAllDocsId); + addClass(innerToggle, "will-expand"); + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { + if (e.parentNode.id !== "implementations-list" || + (!hasClass(e, "implementors-toggle") && + !hasClass(e, "type-contents-toggle")) + ) { + e.open = false; + } + }); + innerToggle.title = "expand all docs"; + innerToggle.children[0].innerText = "+"; } function toggleAllDocs() { @@ -630,29 +649,11 @@ function loadCss(cssFileName) { if (!innerToggle) { return; } - let sectionIsCollapsed = false; if (hasClass(innerToggle, "will-expand")) { - removeClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { - if (!hasClass(e, "type-contents-toggle")) { - e.open = true; - } - }); - innerToggle.title = "collapse all docs"; + expandAllDocs(); } else { - addClass(innerToggle, "will-expand"); - onEachLazy(document.getElementsByClassName("rustdoc-toggle"), e => { - if (e.parentNode.id !== "implementations-list" || - (!hasClass(e, "implementors-toggle") && - !hasClass(e, "type-contents-toggle")) - ) { - e.open = false; - } - }); - sectionIsCollapsed = true; - innerToggle.title = "expand all docs"; + collapseAllDocs(); } - innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed); } (function() { diff --git a/src/test/rustdoc-gui/shortcuts.goml b/src/test/rustdoc-gui/shortcuts.goml index ea6f55272ffc9..9068680d640c1 100644 --- a/src/test/rustdoc-gui/shortcuts.goml +++ b/src/test/rustdoc-gui/shortcuts.goml @@ -11,3 +11,21 @@ press-key: "?" assert-css: ("#help-button .popover", {"display": "block"}) press-key: "Escape" assert-css: ("#help-button .popover", {"display": "none"}) +// Checking doc collapse and expand. +// It should be displaying a "-": +assert-text: ("#toggle-all-docs", "[\u2212]") +press-key: "-" +wait-for-text: ("#toggle-all-docs", "[+]") +assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) +// Pressing it again shouldn't do anything. +press-key: "-" +assert-text: ("#toggle-all-docs", "[+]") +assert-attribute: ("#toggle-all-docs", {"class": "will-expand"}) +// Expanding now. +press-key: "+" +wait-for-text: ("#toggle-all-docs", "[\u2212]") +assert-attribute: ("#toggle-all-docs", {"class": ""}) +// Pressing it again shouldn't do anything. +press-key: "+" +assert-text: ("#toggle-all-docs", "[\u2212]") +assert-attribute: ("#toggle-all-docs", {"class": ""}) diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html new file mode 100644 index 0000000000000..8934bc1ee339c --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out0.html @@ -0,0 +1 @@ +

type Out0: Support<Item = ()>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html new file mode 100644 index 0000000000000..bf330670ed0fa --- /dev/null +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out2.html @@ -0,0 +1 @@ +

type Out2<T>: Support<Item = T>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html similarity index 100% rename from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out9.html rename to src/test/rustdoc/inline_cross/assoc_item_trait_bounds.out9.html diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs similarity index 79% rename from src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs rename to src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs index 00976aa74420f..5f4712aab5b19 100644 --- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.rs +++ b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds.rs @@ -1,13 +1,10 @@ // Regression test for issues #77763, #84579 and #102142. #![crate_name = "main"] -// aux-build:assoc_item_trait_bounds_with_bindings.rs +// aux-build:assoc_item_trait_bounds.rs // build-aux-docs // ignore-cross-compile -extern crate assoc_item_trait_bounds_with_bindings as aux; - -// FIXME(fmease): Don't render an incorrect `T: ?Sized` where-clause for parameters -// of GATs like `Main::Out{2,4}`. Add a snapshot test once it's fixed. +extern crate assoc_item_trait_bounds as aux; // @has main/trait.Main.html // @has - '//*[@id="associatedtype.Out0"]' 'type Out0: Support' @@ -24,11 +21,15 @@ extern crate assoc_item_trait_bounds_with_bindings as aux; // @has - '//*[@id="associatedtype.Out11"]' "type Out11: for<'r, 's> Helper = &'s (), B<'r> = ()>" // @has - '//*[@id="associatedtype.Out12"]' "type Out12: for<'w> Helper = Cow<'w, str>, A<'w> = bool>" // @has - '//*[@id="associatedtype.Out13"]' "type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>" +// @has - '//*[@id="associatedtype.Out14"]' "type Out14" // -// Snapshots: Check that we do not render any where-clauses for those associated types since all of -// the trait bounds contained within were moved to the bounds of the respective item. +// Snapshots: +// Check that we don't render any where-clauses for the following associated types since +// all corresponding projection equality predicates should have already been re-sugared +// to associated type bindings: // // @snapshot out0 - '//*[@id="associatedtype.Out0"]/*[@class="code-header"]' +// @snapshot out2 - '//*[@id="associatedtype.Out2"]/*[@class="code-header"]' // @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]' // // @has - '//*[@id="tymethod.make"]' \ diff --git a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html b/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html deleted file mode 100644 index 927a1a42a1f78..0000000000000 --- a/src/test/rustdoc/inline_cross/assoc_item_trait_bounds_with_bindings.out0.html +++ /dev/null @@ -1 +0,0 @@ -

type Out0: Support<Item = ()>

\ No newline at end of file diff --git a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs similarity index 96% rename from src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs rename to src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs index f451b1a0e9920..d326e61daea26 100644 --- a/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds_with_bindings.rs +++ b/src/test/rustdoc/inline_cross/auxiliary/assoc_item_trait_bounds.rs @@ -15,6 +15,7 @@ pub trait Main { type Out11: for<'r, 's> Helper = &'s (), B<'r> = ()>; type Out12: for<'w> Helper = std::borrow::Cow<'w, str>, A<'w> = bool>; type Out13: for<'fst, 'snd> Aid<'snd, Result<'fst> = &'fst mut str>; + type Out14; fn make(_: F, _: impl FnMut(&str) -> bool) where diff --git a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index e873c36e0b39a..b8deb48d49add 100644 --- a/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -749,3 +749,12 @@ struct SubdiagnosticEagerSuggestion { #[subdiagnostic(eager)] sub: SubdiagnosticWithSuggestion, } + +/// with a doc comment on the type.. +#[derive(Diagnostic)] +#[diag(compiletest::example, code = "E0123")] +struct WithDocComment { + /// ..and the field + #[primary_span] + span: Span, +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index 84ee5af42dea5..2fe93d46d0ac0 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -237,7 +237,6 @@ enum V { var: String, }, B { - //~^ ERROR subdiagnostic kind not specified #[primary_span] span: Span, var: String, @@ -641,3 +640,24 @@ struct BJ { span: Span, r#type: String, } + +/// with a doc comment on the type.. +#[derive(Subdiagnostic)] +#[label(parser::add_paren)] +struct BK { + /// ..and the field + #[primary_span] + span: Span, +} + +/// with a doc comment on the type.. +#[derive(Subdiagnostic)] +enum BL { + /// ..and the variant.. + #[label(parser::add_paren)] + Foo { + /// ..and the field + #[primary_span] + span: Span, + } +} diff --git a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 171b89e657d81..1173d24248bc4 100644 --- a/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/src/test/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -134,20 +134,14 @@ error: diagnostic slug must be first argument of a `#[label(...)]` attribute LL | #[label(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^ -error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:239:5 - | -LL | B { - | ^ - error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:251:5 + --> $DIR/subdiagnostic-derive.rs:250:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: label without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:248:1 + --> $DIR/subdiagnostic-derive.rs:247:1 | LL | / #[label(parser::add_paren)] LL | | @@ -159,13 +153,13 @@ LL | | } | |_^ error: `#[applicability]` is only valid on suggestions - --> $DIR/subdiagnostic-derive.rs:261:5 + --> $DIR/subdiagnostic-derive.rs:260:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:271:5 + --> $DIR/subdiagnostic-derive.rs:270:5 | LL | #[bar] | ^^^^^^ @@ -173,13 +167,13 @@ LL | #[bar] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:282:5 + --> $DIR/subdiagnostic-derive.rs:281:5 | LL | #[bar = "..."] | ^^^^^^^^^^^^^^ error: `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:293:5 + --> $DIR/subdiagnostic-derive.rs:292:5 | LL | #[bar("...")] | ^^^^^^^^^^^^^ @@ -187,7 +181,7 @@ LL | #[bar("...")] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: unexpected unsupported untagged union - --> $DIR/subdiagnostic-derive.rs:309:1 + --> $DIR/subdiagnostic-derive.rs:308:1 | LL | / union AC { LL | | @@ -197,7 +191,7 @@ LL | | } | |_^ error: `#[label(parser::add_paren)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:324:28 + --> $DIR/subdiagnostic-derive.rs:323:28 | LL | #[label(parser::add_paren, parser::add_paren)] | ^^^^^^^^^^^^^^^^^ @@ -205,67 +199,67 @@ LL | #[label(parser::add_paren, parser::add_paren)] = help: a diagnostic slug must be the first argument to the attribute error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:337:5 + --> $DIR/subdiagnostic-derive.rs:336:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:334:5 + --> $DIR/subdiagnostic-derive.rs:333:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:343:8 + --> $DIR/subdiagnostic-derive.rs:342:8 | LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:380:47 + --> $DIR/subdiagnostic-derive.rs:379:47 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:380:33 + --> $DIR/subdiagnostic-derive.rs:379:33 | LL | #[suggestion(parser::add_paren, code = "...", code = "...")] | ^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:398:5 + --> $DIR/subdiagnostic-derive.rs:397:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:395:5 + --> $DIR/subdiagnostic-derive.rs:394:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:408:5 + --> $DIR/subdiagnostic-derive.rs:407:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:421:1 + --> $DIR/subdiagnostic-derive.rs:420:1 | LL | #[suggestion(parser::add_paren)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:431:46 + --> $DIR/subdiagnostic-derive.rs:430:46 | LL | #[suggestion(parser::add_paren, code ="...", applicability = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:449:1 + --> $DIR/subdiagnostic-derive.rs:448:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | @@ -275,25 +269,25 @@ LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:463:1 + --> $DIR/subdiagnostic-derive.rs:462:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:483:39 + --> $DIR/subdiagnostic-derive.rs:482:39 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:502:43 + --> $DIR/subdiagnostic-derive.rs:501:43 | LL | #[suggestion(parser::add_paren, code ="{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:525:5 + --> $DIR/subdiagnostic-derive.rs:524:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ @@ -301,7 +295,7 @@ LL | #[suggestion_part] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead error: `#[suggestion_part(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:528:5 + --> $DIR/subdiagnostic-derive.rs:527:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -309,7 +303,7 @@ LL | #[suggestion_part(code = "...")] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:522:1 + --> $DIR/subdiagnostic-derive.rs:521:1 | LL | / #[suggestion(parser::add_paren, code = "...")] LL | | @@ -321,7 +315,7 @@ LL | | } | |_^ error: `#[multipart_suggestion(code = ...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:537:43 + --> $DIR/subdiagnostic-derive.rs:536:43 | LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] | ^^^^^^^^^^^^ @@ -329,7 +323,7 @@ LL | #[multipart_suggestion(parser::add_paren, code = "...", applicability = "ma = help: only `applicability` is a valid nested attributes error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:537:1 + --> $DIR/subdiagnostic-derive.rs:536:1 | LL | / #[multipart_suggestion(parser::add_paren, code = "...", applicability = "machine-applicable")] LL | | @@ -340,19 +334,19 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:547:5 + --> $DIR/subdiagnostic-derive.rs:546:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:555:5 + --> $DIR/subdiagnostic-derive.rs:554:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:564:5 + --> $DIR/subdiagnostic-derive.rs:563:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -360,7 +354,7 @@ LL | #[primary_span] = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:561:1 + --> $DIR/subdiagnostic-derive.rs:560:1 | LL | / #[multipart_suggestion(parser::add_paren)] LL | | @@ -372,19 +366,19 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:572:5 + --> $DIR/subdiagnostic-derive.rs:571:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:575:5 + --> $DIR/subdiagnostic-derive.rs:574:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(foo = ...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:578:23 + --> $DIR/subdiagnostic-derive.rs:577:23 | LL | #[suggestion_part(foo = "bar")] | ^^^^^^^^^^^ @@ -392,31 +386,31 @@ LL | #[suggestion_part(foo = "bar")] = help: `code` is the only valid nested attribute error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:581:5 + --> $DIR/subdiagnostic-derive.rs:580:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:584:5 + --> $DIR/subdiagnostic-derive.rs:583:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:592:37 + --> $DIR/subdiagnostic-derive.rs:591:37 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:592:23 + --> $DIR/subdiagnostic-derive.rs:591:23 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^^^^^^^^^ error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` - --> $DIR/subdiagnostic-derive.rs:621:5 + --> $DIR/subdiagnostic-derive.rs:620:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ @@ -458,19 +452,19 @@ LL | #[bar("...")] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:271:7 + --> $DIR/subdiagnostic-derive.rs:270:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:282:7 + --> $DIR/subdiagnostic-derive.rs:281:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:293:7 + --> $DIR/subdiagnostic-derive.rs:292:7 | LL | #[bar("...")] | ^^^ @@ -481,6 +475,6 @@ error[E0425]: cannot find value `slug` in module `rustc_errors::fluent` LL | #[label(slug)] | ^^^^ not found in `rustc_errors::fluent` -error: aborting due to 68 previous errors +error: aborting due to 67 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/lint/unused/unused-supertrait.rs b/src/test/ui/lint/unused/unused-supertrait.rs new file mode 100644 index 0000000000000..64a8e5204579c --- /dev/null +++ b/src/test/ui/lint/unused/unused-supertrait.rs @@ -0,0 +1,11 @@ +#![deny(unused_must_use)] + +fn it() -> impl ExactSizeIterator { + let x: Box> = todo!(); + x +} + +fn main() { + it(); + //~^ ERROR unused implementer of `Iterator` that must be used +} diff --git a/src/test/ui/lint/unused/unused-supertrait.stderr b/src/test/ui/lint/unused/unused-supertrait.stderr new file mode 100644 index 0000000000000..0a3eca314d47a --- /dev/null +++ b/src/test/ui/lint/unused/unused-supertrait.stderr @@ -0,0 +1,15 @@ +error: unused implementer of `Iterator` that must be used + --> $DIR/unused-supertrait.rs:9:5 + | +LL | it(); + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-supertrait.rs:1:9 + | +LL | #![deny(unused_must_use)] + | ^^^^^^^^^^^^^^^ + = note: iterators are lazy and do nothing unless consumed + +error: aborting due to previous error + diff --git a/src/test/ui/resolve/issue-103202.rs b/src/test/ui/resolve/issue-103202.rs new file mode 100644 index 0000000000000..469d9d7c860ca --- /dev/null +++ b/src/test/ui/resolve/issue-103202.rs @@ -0,0 +1,7 @@ +struct S {} + +impl S { + fn f(self: &S::x) {} //~ ERROR ambiguous associated type +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-103202.stderr b/src/test/ui/resolve/issue-103202.stderr new file mode 100644 index 0000000000000..880389371ef70 --- /dev/null +++ b/src/test/ui/resolve/issue-103202.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-103202.rs:4:17 + | +LL | fn f(self: &S::x) {} + | ^^^^ help: use fully-qualified syntax: `::x` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`.