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 f42aca685f60e..7865c523f758c 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, @@ -1805,15 +1806,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.rs b/compiler/rustc_errors/src/diagnostic.rs index 518c59dba5366..a63fc0ca285da 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -567,6 +567,11 @@ impl Diagnostic { style: SuggestionStyle, ) -> &mut Self { assert!(!suggestion.is_empty()); + debug_assert!( + !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: suggestion @@ -644,6 +649,10 @@ impl Diagnostic { applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { + debug_assert!( + !(sp.is_empty() && suggestion.to_string().is_empty()), + "Span must not be empty and have no suggestion" + ); self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], @@ -684,6 +693,12 @@ impl Diagnostic { ) -> &mut Self { let mut suggestions: Vec<_> = suggestions.collect(); suggestions.sort(); + + debug_assert!( + !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + let substitutions = suggestions .into_iter() .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }) @@ -705,8 +720,18 @@ impl Diagnostic { suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self { + let suggestions: Vec<_> = suggestions.collect(); + debug_assert!( + !(suggestions + .iter() + .flat_map(|suggs| suggs) + .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: suggestions + .into_iter() .map(|sugg| Substitution { parts: sugg .into_iter() 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_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index cd8a525e062c5..052ca229f0127 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -22,7 +22,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{FileName, Span, DUMMY_SP}; +use rustc_span::{BytePos, FileName, Span, DUMMY_SP}; use smallvec::{smallvec, SmallVec}; use std::default::Default; @@ -1228,8 +1228,9 @@ pub fn expr_to_spanned_string<'a>( ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), ast::LitKind::ByteStr(_) => { let mut err = cx.struct_span_err(l.span, err_msg); + let span = expr.span.shrink_to_lo(); err.span_suggestion( - expr.span.shrink_to_lo(), + span.with_hi(span.lo() + BytePos(1)), "consider removing the leading `b`", "", Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 9b9ef2b1fbd02..a0350c26d827c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -3051,24 +3051,27 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map_or(false, |s| s.trim_end().ends_with('<')); let is_global = poly_trait_ref.trait_ref.path.is_global(); - let sugg = Vec::from_iter([ - ( - self_ty.span.shrink_to_lo(), - format!( - "{}dyn {}", - if needs_bracket { "<" } else { "" }, - if is_global { "(" } else { "" }, - ), + + let mut sugg = Vec::from_iter([( + self_ty.span.shrink_to_lo(), + format!( + "{}dyn {}", + if needs_bracket { "<" } else { "" }, + if is_global { "(" } else { "" }, ), - ( + )]); + + if is_global || needs_bracket { + sugg.push(( self_ty.span.shrink_to_hi(), format!( "{}{}", if is_global { ")" } else { "" }, if needs_bracket { ">" } else { "" }, ), - ), - ]); + )); + } + if self_ty.span.edition() >= Edition::Edition2021 { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; 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/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 886e25f2d788b..715ba4ca156d4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -3176,6 +3176,7 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail + /// # #![feature(asm_experimental_arch)] /// use std::arch::asm; /// /// fn main() { 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_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 8390d80a458cf..d6cc31331a3bc 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2878,7 +2878,7 @@ declare_lint! { /// ### Example /// /// ```rust - /// #![feature(naked_functions)] + /// #![feature(asm_experimental_arch, naked_functions)] /// /// use std::arch::asm; /// 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_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 40d85c833a7dd..d654d84cdd594 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1374,9 +1374,17 @@ impl<'a> Parser<'a> { kind: IncDecRecovery, (pre_span, post_span): (Span, Span), ) -> MultiSugg { + let mut patches = Vec::new(); + + if !pre_span.is_empty() { + patches.push((pre_span, String::new())); + } + + patches.push((post_span, format!(" {}= 1", kind.op.chr()))); + MultiSugg { msg: format!("use `{}= 1` instead", kind.op.chr()), - patches: vec![(pre_span, String::new()), (post_span, format!(" {}= 1", kind.op.chr()))], + patches, applicability: Applicability::MachineApplicable, } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c4644d4f076e2..5d868ebec9448 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, Span, SyntaxContext}; use crate::imports::{Import, ImportKind, ImportResolver}; use crate::late::{PatternSource, Rib}; @@ -47,6 +47,7 @@ pub(crate) type Suggestion = (Vec<(Span, String)>, String, Applicability); /// similarly named label and whether or not it is reachable. pub(crate) type LabelSuggestion = (Ident, bool); +#[derive(Debug)] pub(crate) enum SuggestionTarget { /// The target has a similar name as the name used by the programmer (probably a typo) SimilarlyNamed, @@ -54,6 +55,7 @@ pub(crate) enum SuggestionTarget { SingleItem, } +#[derive(Debug)] pub(crate) struct TypoSuggestion { pub candidate: Symbol, pub res: Res, @@ -482,11 +484,12 @@ impl<'a> Resolver<'a> { module: Module<'a>, names: &mut Vec, filter_fn: &impl Fn(Res) -> bool, + ctxt: Option, ) { for (key, resolution) in self.resolutions(module).borrow().iter() { if let Some(binding) = resolution.borrow().binding { let res = binding.res(); - if filter_fn(res) { + if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) { names.push(TypoSuggestion::typo_from_res(key.ident.name, res)); } } @@ -1181,10 +1184,10 @@ impl<'a> Resolver<'a> { Scope::CrateRoot => { let root_ident = Ident::new(kw::PathRoot, ident.span); let root_module = this.resolve_crate_root(root_ident); - this.add_module_candidates(root_module, &mut suggestions, filter_fn); + this.add_module_candidates(root_module, &mut suggestions, filter_fn, None); } Scope::Module(module, _) => { - this.add_module_candidates(module, &mut suggestions, filter_fn); + this.add_module_candidates(module, &mut suggestions, filter_fn, None); } Scope::MacroUsePrelude => { suggestions.extend(this.macro_use_prelude.iter().filter_map( @@ -1221,7 +1224,7 @@ impl<'a> Resolver<'a> { Scope::StdLibPrelude => { if let Some(prelude) = this.prelude { let mut tmp_suggestions = Vec::new(); - this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn); + this.add_module_candidates(prelude, &mut tmp_suggestions, filter_fn, None); suggestions.extend( tmp_suggestions .into_iter() diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 4fd5bc1d60a47..e3dba2366a40e 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -131,6 +131,7 @@ pub(super) enum LifetimeElisionCandidate { } /// Only used for diagnostics. +#[derive(Debug)] struct BaseError { msg: String, fallback_label: String, @@ -140,6 +141,22 @@ struct BaseError { suggestion: Option<(Span, &'static str, String)>, } +#[derive(Debug)] +enum TypoCandidate { + Typo(TypoSuggestion), + Shadowed(Res), + None, +} + +impl TypoCandidate { + fn to_opt_suggestion(self) -> Option { + match self { + TypoCandidate::Typo(sugg) => Some(sugg), + TypoCandidate::Shadowed(_) | TypoCandidate::None => None, + } + } +} + impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { @@ -496,7 +513,8 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } // Try Levenshtein algorithm. - let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + let typo_sugg = + self.lookup_typo_candidate(path, source.namespace(), is_expected).to_opt_suggestion(); if path.len() == 1 && self.self_type_is_available() { if let Some(candidate) = self.lookup_assoc_candidate(ident, ns, is_expected) { let self_is_available = self.self_value_is_available(path[0].ident.span); @@ -660,7 +678,18 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let is_expected = &|res| source.is_expected(res); let ident_span = path.last().map_or(span, |ident| ident.ident.span); let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected); + if let TypoCandidate::Shadowed(res) = typo_sugg + && let Some(id) = res.opt_def_id() + && let Some(sugg_span) = self.r.opt_span(id) + { + err.span_label( + sugg_span, + format!("you might have meant to refer to this {}", res.descr()), + ); + return true; + } let mut fallback = false; + let typo_sugg = typo_sugg.to_opt_suggestion(); if !self.r.add_typo_suggestion(err, typo_sugg, ident_span) { fallback = true; match self.diagnostic_metadata.current_let_binding { @@ -1581,22 +1610,38 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { path: &[Segment], ns: Namespace, filter_fn: &impl Fn(Res) -> bool, - ) -> Option { + ) -> TypoCandidate { let mut names = Vec::new(); if path.len() == 1 { + let mut ctxt = path.last().unwrap().ident.span.ctxt(); + // Search in lexical scope. // Walk backwards up the ribs in scope and collect candidates. for rib in self.ribs[ns].iter().rev() { + let rib_ctxt = if rib.kind.contains_params() { + ctxt.normalize_to_macros_2_0() + } else { + ctxt.normalize_to_macro_rules() + }; + // Locals and type parameters for (ident, &res) in &rib.bindings { - if filter_fn(res) { + if filter_fn(res) && ident.span.ctxt() == rib_ctxt { names.push(TypoSuggestion::typo_from_res(ident.name, res)); } } + + if let RibKind::MacroDefinition(def) = rib.kind && def == self.r.macro_def(ctxt) { + // If an invocation of this macro created `ident`, give up on `ident` + // and switch to `ident`'s source from the macro definition. + ctxt.remove_mark(); + continue; + } + // Items in scope if let RibKind::ModuleRibKind(module) = rib.kind { // Items from this module - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); if let ModuleKind::Block = module.kind { // We can see through blocks @@ -1622,7 +1667,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { })); if let Some(prelude) = self.r.prelude { - self.r.add_module_candidates(prelude, &mut names, &filter_fn); + self.r.add_module_candidates(prelude, &mut names, &filter_fn, None); } } break; @@ -1641,7 +1686,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(mod_path, Some(TypeNS), None) { - self.r.add_module_candidates(module, &mut names, &filter_fn); + self.r.add_module_candidates(module, &mut names, &filter_fn, None); } } @@ -1654,10 +1699,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { name, None, ) { - Some(found) if found != name => { - names.into_iter().find(|suggestion| suggestion.candidate == found) + Some(found) => { + let Some(sugg) = names.into_iter().find(|suggestion| suggestion.candidate == found) else { + return TypoCandidate::None; + }; + if found == name { + TypoCandidate::Shadowed(sugg.res) + } else { + TypoCandidate::Typo(sugg) + } } - _ => None, + _ => TypoCandidate::None, } } 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/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css index 0a19a99abf054..63b35f5d0df0d 100644 --- a/src/librustdoc/html/static/css/noscript.css +++ b/src/librustdoc/html/static/css/noscript.css @@ -14,7 +14,7 @@ rules. display: none; } -.sub { +nav.sub { /* The search bar and related controls don't work without JS */ display: none; } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 746a510c488f9..afe1ca5d7e520 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -365,15 +365,8 @@ img { overflow: visible; } -.sub-container { - display: flex; - flex-direction: row; - flex-wrap: nowrap; -} - .sub-logo-container { - display: block; - margin-right: 20px; + line-height: 0; } .sub-logo-container > img { @@ -696,14 +689,21 @@ pre, .rustdoc.source .example-wrap { } nav.sub { - position: relative; flex-grow: 1; - margin-bottom: 25px; + flex-flow: row nowrap; + margin: 4px 0 25px 0; + display: flex; + align-items: center; +} +nav.sub form { + flex-grow: 1; } .source nav.sub { + margin: 0 0 15px 0; +} +.source nav.sub form { margin-left: 32px; } -nav.sub form { display: inline; } a { text-decoration: none; @@ -796,7 +796,6 @@ table, position: relative; display: flex; height: 34px; - margin-top: 4px; } .search-results-title { margin-top: 0; @@ -1822,10 +1821,6 @@ in storage.js margin-left: 0px; } - .source .content { - margin-top: 10px; - } - .anchor { display: none !important; } @@ -1934,6 +1929,11 @@ in storage.js .impl-items > .item-info { margin-left: 34px; } + + .source nav.sub { + margin: 0; + padding: 8px; + } } @media print { @@ -1962,12 +1962,12 @@ in storage.js overflow-wrap: anywhere; } - .sub-container { + nav.sub { flex-direction: column; } - .sub-logo-container { - align-self: center; + nav.sub form { + align-self: stretch; } .sub-logo-container > img { diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 20a314a1c00e3..2a111f94e5078 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -102,7 +102,7 @@

{#- -#} {#- -#}
{#- -#}
{#- -#} -
{#- -#} +
{#- -#} +
{#- -#} + {#- -#} + Change settings {#- -#} + {#- -#} +
{#- -#} +
{#- -#} + {#- -#} + {#- -#}
{{- content|safe -}}
{#- -#} {#- -#}
{#- -#} diff --git a/src/test/pretty/raw-str-nonexpr.rs b/src/test/pretty/raw-str-nonexpr.rs index 7af80979b4349..12440b5ae6ed5 100644 --- a/src/test/pretty/raw-str-nonexpr.rs +++ b/src/test/pretty/raw-str-nonexpr.rs @@ -1,3 +1,4 @@ +// needs-asm-support // pp-exact #[cfg(foo = r#"just parse this"#)] diff --git a/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile b/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile index 3c4dade0f5215..ff9cc57098c6b 100644 --- a/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile +++ b/src/test/run-make-fulldeps/intrinsic-unreachable/Makefile @@ -1,5 +1,6 @@ include ../tools.mk +# needs-asm-support # ignore-windows-msvc # # Because of Windows exception handling, the code is not necessarily any shorter. diff --git a/src/test/rustdoc-gui/help-page.goml b/src/test/rustdoc-gui/help-page.goml index 51f089cce747f..521e14748af12 100644 --- a/src/test/rustdoc-gui/help-page.goml +++ b/src/test/rustdoc-gui/help-page.goml @@ -5,12 +5,12 @@ wait-for: "#help" assert-css: ("#help", {"display": "block"}) click: "#help-button > a" assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub-container", "#help", ["offsetWidth"]) -compare-elements-position: (".sub-container", "#help", ("x")) +compare-elements-property: (".sub", "#help", ["offsetWidth"]) +compare-elements-position: (".sub", "#help", ("x")) size: (500, 1000) // Try mobile next. assert-css: ("#help", {"display": "block"}) -compare-elements-property: (".sub-container", "#help", ["offsetWidth"]) -compare-elements-position: (".sub-container", "#help", ("x")) +compare-elements-property: (".sub", "#help", ["offsetWidth"]) +compare-elements-position: (".sub", "#help", ("x")) // This test ensures that opening the help popover without switching pages works. goto: "file://" + |DOC_PATH| + "/test_docs/index.html" @@ -20,5 +20,5 @@ click: "#help-button > a" assert-css: ("#help", {"display": "block"}) click: "#help-button > a" assert-css: ("#help", {"display": "none"}) -compare-elements-property-false: (".sub-container", "#help", ["offsetWidth"]) -compare-elements-position-false: (".sub-container", "#help", ("x")) +compare-elements-property-false: (".sub", "#help", ["offsetWidth"]) +compare-elements-position-false: (".sub", "#help", ("x")) diff --git a/src/test/rustdoc-gui/settings.goml b/src/test/rustdoc-gui/settings.goml index ed4e9c2516b0b..f258f4d2a838e 100644 --- a/src/test/rustdoc-gui/settings.goml +++ b/src/test/rustdoc-gui/settings.goml @@ -147,7 +147,7 @@ assert-css: ( ) assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS) -compare-elements-position: (".sub-container", "#settings", ("x")) +compare-elements-position: (".sub form", "#settings", ("x")) // We now check the display with JS disabled. assert-false: "noscript section" diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml index 76260d621eae1..29d65fc7ebc7a 100644 --- a/src/test/rustdoc-gui/source-code-page.goml +++ b/src/test/rustdoc-gui/source-code-page.goml @@ -23,7 +23,7 @@ assert-css: (".src-line-numbers", {"text-align": "right"}) show-text: true goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // We use this assert-position to know where we will click. -assert-position: ("//*[@id='1']", {"x": 104, "y": 103}) +assert-position: ("//*[@id='1']", {"x": 104, "y": 112}) // We click on the left of the "1" span but still in the "src-line-number" `
`.
 click: (103, 103)
 assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
@@ -47,3 +47,25 @@ assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
 
 // Check the spacing.
 assert-css: ("#source-sidebar > details.dir-entry", {"padding-left": "4px"})
+
+// Check the search form
+assert-css: ("nav.sub", {"flex-direction": "row"})
+// The goal of this test is to ensure the search input is perfectly centered
+// between the top of the page and the top of the gray code block.
+// To check this, we maintain the invariant:
+//
+// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
+assert-property: ("nav.sub form", {"offsetTop": 28, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 90})
+// 28 = 90 - 34 - 28
+
+// Now do the same check on moderately-sized mobile.
+size: (700, 700)
+assert-css: ("nav.sub", {"flex-direction": "row"})
+assert-property: ("nav.sub form", {"offsetTop": 21, "offsetHeight": 34})
+assert-property: ("#main-content", {"offsetTop": 76})
+// 21 = 76 - 34 - 21
+
+// Tiny mobile gets a different display where the logo is stacked on top.
+size: (450, 700)
+assert-css: ("nav.sub", {"flex-direction": "column"})
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/asm/unpretty-expanded.rs b/src/test/ui/asm/unpretty-expanded.rs
index 6128f49b89a34..25cf1c3d730eb 100644
--- a/src/test/ui/asm/unpretty-expanded.rs
+++ b/src/test/ui/asm/unpretty-expanded.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // check-pass
 // compile-flags: -Zunpretty=expanded
 core::arch::global_asm!("x: .byte 42");
diff --git a/src/test/ui/asm/unpretty-expanded.stdout b/src/test/ui/asm/unpretty-expanded.stdout
index 15b60d1559c65..ab1b5f45e5c8a 100644
--- a/src/test/ui/asm/unpretty-expanded.stdout
+++ b/src/test/ui/asm/unpretty-expanded.stdout
@@ -4,6 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
+// needs-asm-support
 // check-pass
 // compile-flags: -Zunpretty=expanded
 global_asm! ("x: .byte 42");
diff --git a/src/test/ui/empty_global_asm.rs b/src/test/ui/empty_global_asm.rs
index dbcc7be057814..af13762d11857 100644
--- a/src/test/ui/empty_global_asm.rs
+++ b/src/test/ui/empty_global_asm.rs
@@ -1,21 +1,8 @@
+// needs-asm-support
 // run-pass
 
-#[allow(unused_imports)]
 use std::arch::global_asm;
 
-#[cfg(target_arch = "x86")]
-global_asm!("");
-
-#[cfg(target_arch = "x86_64")]
-global_asm!("");
-
-#[cfg(target_arch = "arm")]
-global_asm!("");
-
-#[cfg(target_arch = "aarch64")]
-global_asm!("");
-
-#[cfg(target_arch = "mips")]
 global_asm!("");
 
 fn main() {}
diff --git a/src/test/ui/hygiene/globs.stderr b/src/test/ui/hygiene/globs.stderr
index bcfcc28adf776..1f2a96a4c411a 100644
--- a/src/test/ui/hygiene/globs.stderr
+++ b/src/test/ui/hygiene/globs.stderr
@@ -1,9 +1,16 @@
 error[E0425]: cannot find function `f` in this scope
   --> $DIR/globs.rs:22:9
    |
+LL |     pub fn g() {}
+   |     ---------- similarly named function `g` defined here
+...
 LL |         f();
-   |         ^ not found in this scope
+   |         ^
+   |
+help: a function with a similar name exists
    |
+LL |         g();
+   |         ~
 help: consider importing this function
    |
 LL | use foo::f;
@@ -12,8 +19,11 @@ LL | use foo::f;
 error[E0425]: cannot find function `g` in this scope
   --> $DIR/globs.rs:15:5
    |
+LL |       pub fn f() {}
+   |       ---------- similarly named function `f` defined here
+...
 LL |       g();
-   |       ^ not found in this scope
+   |       ^
 ...
 LL | /     m! {
 LL | |         use bar::*;
@@ -23,6 +33,10 @@ LL | |     }
    | |_____- in this macro invocation
    |
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: a function with a similar name exists
+   |
+LL |     f();
+   |     ~
 help: consider importing this function
    |
 LL | use bar::g;
diff --git a/src/test/ui/hygiene/rustc-macro-transparency.stderr b/src/test/ui/hygiene/rustc-macro-transparency.stderr
index 17d05dd09636c..1d2a1e1249864 100644
--- a/src/test/ui/hygiene/rustc-macro-transparency.stderr
+++ b/src/test/ui/hygiene/rustc-macro-transparency.stderr
@@ -19,14 +19,8 @@ LL |     semitransparent;
 error[E0423]: expected value, found macro `opaque`
   --> $DIR/rustc-macro-transparency.rs:30:5
    |
-LL |     struct Opaque;
-   |     -------------- similarly named unit struct `Opaque` defined here
-...
 LL |     opaque;
-   |     ^^^^^^
-   |     |
-   |     not a value
-   |     help: a unit struct with a similar name exists (notice the capitalization): `Opaque`
+   |     ^^^^^^ not a value
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/lexical-scopes.stderr b/src/test/ui/lexical-scopes.stderr
index 08e4be2c0c352..535985452232d 100644
--- a/src/test/ui/lexical-scopes.stderr
+++ b/src/test/ui/lexical-scopes.stderr
@@ -1,6 +1,8 @@
 error[E0574]: expected struct, variant or union type, found type parameter `T`
   --> $DIR/lexical-scopes.rs:3:13
    |
+LL | struct T { i: i32 }
+   | ------------------- you might have meant to refer to this struct
 LL | fn f() {
    |      - found this type parameter
 LL |     let t = T { i: 0 };
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..d2f8c00784817
--- /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: iterators are lazy and do nothing unless consumed
+note: the lint level is defined here
+  --> $DIR/unused-supertrait.rs:1:9
+   |
+LL | #![deny(unused_must_use)]
+   |         ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/macro-context.stderr b/src/test/ui/macros/macro-context.stderr
index 2a2e0c6c66a51..f597c398b7c17 100644
--- a/src/test/ui/macros/macro-context.stderr
+++ b/src/test/ui/macros/macro-context.stderr
@@ -57,7 +57,7 @@ error[E0425]: cannot find value `i` in this scope
   --> $DIR/macro-context.rs:3:13
    |
 LL |     () => ( i ; typeof );
-   |             ^ help: a local variable with a similar name exists: `a`
+   |             ^ not found in this scope
 ...
 LL |     let i = m!();
    |             ---- in this macro invocation
diff --git a/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
index 6060f872f227a..df7c4f72eb0b6 100644
--- a/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
+++ b/src/test/ui/proc-macro/gen-macro-rules-hygiene.stderr
@@ -13,7 +13,7 @@ error[E0425]: cannot find value `local_use` in this scope
   --> $DIR/gen-macro-rules-hygiene.rs:12:1
    |
 LL | gen_macro_rules!();
-   | ^^^^^^^^^^^^^^^^^^ not found in this scope
+   | ^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
 ...
 LL |         generated!();
    |         ------------ in this macro invocation
@@ -24,7 +24,7 @@ error[E0425]: cannot find value `local_def` in this scope
   --> $DIR/gen-macro-rules-hygiene.rs:21:9
    |
 LL |         local_def;
-   |         ^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/proc-macro/mixed-site-span.stderr b/src/test/ui/proc-macro/mixed-site-span.stderr
index eab4317ded85d..1378608012464 100644
--- a/src/test/ui/proc-macro/mixed-site-span.stderr
+++ b/src/test/ui/proc-macro/mixed-site-span.stderr
@@ -10,7 +10,7 @@ error[E0425]: cannot find value `local_use` in this scope
   --> $DIR/mixed-site-span.rs:13:9
    |
 LL |         proc_macro_rules!();
-   |         ^^^^^^^^^^^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^^^^^^^^^^^ help: a local variable with a similar name exists: `local_def`
    |
    = note: this error originates in the macro `proc_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -18,7 +18,7 @@ error[E0425]: cannot find value `local_def` in this scope
   --> $DIR/mixed-site-span.rs:17:9
    |
 LL |         local_def;
-   |         ^^^^^^^^^ not found in this scope
+   |         ^^^^^^^^^ help: a local variable with a similar name exists: `local_use`
 
 error[E0412]: cannot find type `ItemUse` in crate `$crate`
   --> $DIR/mixed-site-span.rs:24:1
diff --git a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
index af9f4612ab342..eb26cd9cabb82 100644
--- a/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
+++ b/src/test/ui/resolve/point-at-type-parameter-shadowing-another-type.stderr
@@ -1,11 +1,16 @@
 error[E0574]: expected struct, variant or union type, found type parameter `Baz`
   --> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
    |
-LL | impl Foo for Bar {
-   |      --- found this type parameter
+LL | / struct Baz {
+LL | |     num: usize,
+LL | | }
+   | |_- you might have meant to refer to this struct
+LL |
+LL |   impl Foo for Bar {
+   |        --- found this type parameter
 ...
-LL |             Baz { num } => num,
-   |             ^^^ not a struct, variant or union type
+LL |               Baz { num } => num,
+   |               ^^^ not a struct, variant or union type
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 825ec84b4a812..b8ed9b9ec18f7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -69,11 +69,13 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
                     "only a `panic!` in `if`-then statement",
                     |diag| {
                         // comments can be noisy, do not show them to the user
-                        diag.tool_only_span_suggestion(
-                                    expr.span.shrink_to_lo(),
-                                    "add comments back",
-                                    comments,
-                                    applicability);
+                        if !comments.is_empty() {
+                            diag.tool_only_span_suggestion(
+                                        expr.span.shrink_to_lo(),
+                                        "add comments back",
+                                        comments,
+                                        applicability);
+                        }
                         diag.span_suggestion(
                                     expr.span,
                                     "try instead",
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 9d26e5900866c..67debe7e08af6 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -180,10 +180,13 @@ fn assignment_suggestions<'tcx>(
     let suggestions = assignments
         .iter()
         .flat_map(|assignment| {
-            [
-                assignment.span.until(assignment.rhs_span),
-                assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()),
-            ]
+            let mut spans = vec![assignment.span.until(assignment.rhs_span)];
+
+            if assignment.rhs_span.hi() != assignment.span.hi() {
+                spans.push(assignment.rhs_span.shrink_to_hi().with_hi(assignment.span.hi()));
+            }
+
+            spans
         })
         .map(|span| (span, String::new()))
         .collect::>();
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index e43635abcd112..79c29c04e0596 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -1,3 +1,4 @@
+// needs-asm-support
 // run-rustfix
 
 #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index d999b3b7dc80d..2d7985457d8b4 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // run-rustfix
 
 #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)]
diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr
index 2ef9966525cef..2c4c49d2522ca 100644
--- a/src/tools/clippy/tests/ui/entry.stderr
+++ b/src/tools/clippy/tests/ui/entry.stderr
@@ -1,5 +1,5 @@
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:24:5
+  --> $DIR/entry.rs:25:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         m.insert(k, v);
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::map-entry` implied by `-D warnings`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:29:5
+  --> $DIR/entry.rs:30:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -32,7 +32,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:38:5
+  --> $DIR/entry.rs:39:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -55,7 +55,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:47:5
+  --> $DIR/entry.rs:48:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         if true {
@@ -79,7 +79,7 @@ LL +     }
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:57:5
+  --> $DIR/entry.rs:58:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         foo();
@@ -96,7 +96,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:63:5
+  --> $DIR/entry.rs:64:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         match 0 {
@@ -122,7 +122,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:75:5
+  --> $DIR/entry.rs:76:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         match 0 {
@@ -146,7 +146,7 @@ LL +     }
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:85:5
+  --> $DIR/entry.rs:86:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         foo();
@@ -187,7 +187,7 @@ LL +     });
    |
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:119:5
+  --> $DIR/entry.rs:120:5
    |
 LL | /     if !m.contains_key(&m!(k)) {
 LL | |         m.insert(m!(k), m!(v));
@@ -195,7 +195,7 @@ LL | |     }
    | |_____^ help: try this: `m.entry(m!(k)).or_insert_with(|| m!(v));`
 
 error: usage of `contains_key` followed by `insert` on a `HashMap`
-  --> $DIR/entry.rs:151:5
+  --> $DIR/entry.rs:152:5
    |
 LL | /     if !m.contains_key(&k) {
 LL | |         let x = (String::new(), String::new());
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 7718588fdf6f4..237638ee1344c 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -4,13 +4,9 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
 LL | |     }
-   | |_____^
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);`
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qaqaq{:?}", a);
-   |
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:34:5
@@ -18,12 +14,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qwqwq");
-   |
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:51:5
@@ -31,12 +22,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!b.is_empty(), "panic1");
-   |
+   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:54:5
@@ -44,12 +30,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() && a.is_empty()), "panic2");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:57:5
@@ -57,12 +38,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:60:5
@@ -70,12 +46,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() || a.is_empty()), "panic4");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:63:5
@@ -83,12 +54,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
@@ -96,12 +62,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() {
 LL | |         panic!("with expansion {}", one!())
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!a.is_empty(), "with expansion {}", one!());
-   |
+   | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:73:5
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
index 7718588fdf6f4..237638ee1344c 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
@@ -4,13 +4,9 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
 LL | |     }
-   | |_____^
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);`
    |
    = note: `-D clippy::manual-assert` implied by `-D warnings`
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qaqaq{:?}", a);
-   |
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:34:5
@@ -18,12 +14,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(a.is_empty(), "qwqwq");
-   |
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:51:5
@@ -31,12 +22,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!b.is_empty(), "panic1");
-   |
+   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:54:5
@@ -44,12 +30,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() && a.is_empty()), "panic2");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:57:5
@@ -57,12 +38,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:60:5
@@ -70,12 +46,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(b.is_empty() || a.is_empty()), "panic4");
-   |
+   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:63:5
@@ -83,12 +54,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-   |
+   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
@@ -96,12 +62,7 @@ error: only a `panic!` in `if`-then statement
 LL | /     if a.is_empty() {
 LL | |         panic!("with expansion {}", one!())
 LL | |     }
-   | |_____^
-   |
-help: try instead
-   |
-LL |     assert!(!a.is_empty(), "with expansion {}", one!());
-   |
+   | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
 error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:73:5
diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index 29cc026a8fd39..590ad63c90be3 100644
--- a/src/tools/clippy/tests/ui/missing_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -1,3 +1,4 @@
+// needs-asm-support
 // aux-build: proc_macro_with_span.rs
 
 #![warn(clippy::missing_docs_in_private_items)]
diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
index 6c8e66f464377..d3bef28bf64c6 100644
--- a/src/tools/clippy/tests/ui/missing_doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/missing_doc.rs:15:1
+  --> $DIR/missing_doc.rs:16:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing_doc.rs:16:1
+  --> $DIR/missing_doc.rs:17:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:18:1
+  --> $DIR/missing_doc.rs:19:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:19:1
+  --> $DIR/missing_doc.rs:20:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:23:1
+  --> $DIR/missing_doc.rs:24:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:24:1
+  --> $DIR/missing_doc.rs:25:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing_doc.rs:38:1
+  --> $DIR/missing_doc.rs:39:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:39:5
+  --> $DIR/missing_doc.rs:40:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:39:12
+  --> $DIR/missing_doc.rs:40:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:39:22
+  --> $DIR/missing_doc.rs:40:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:40:5
+  --> $DIR/missing_doc.rs:41:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing_doc.rs:43:1
+  --> $DIR/missing_doc.rs:44:1
    |
 LL | / pub enum PubBaz {
 LL | |     PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing_doc.rs:44:5
+  --> $DIR/missing_doc.rs:45:5
    |
 LL |     PubBazA { a: isize },
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing_doc.rs:44:15
+  --> $DIR/missing_doc.rs:45:15
    |
 LL |     PubBazA { a: isize },
    |               ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing_doc.rs:64:1
+  --> $DIR/missing_doc.rs:65:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing_doc.rs:71:1
+  --> $DIR/missing_doc.rs:72:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing_doc.rs:73:1
+  --> $DIR/missing_doc.rs:74:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing_doc.rs:80:1
+  --> $DIR/missing_doc.rs:81:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing_doc.rs:82:1
+  --> $DIR/missing_doc.rs:83:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -126,31 +126,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:85:5
+  --> $DIR/missing_doc.rs:86:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:86:5
+  --> $DIR/missing_doc.rs:87:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:87:5
+  --> $DIR/missing_doc.rs:88:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:92:9
+  --> $DIR/missing_doc.rs:93:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing_doc.rs:93:9
+  --> $DIR/missing_doc.rs:94:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^