diff --git a/compiler/rustc_error_messages/locales/en-US/lint.ftl b/compiler/rustc_error_messages/locales/en-US/lint.ftl index 1518adf8e4e..3fa52ff0eb3 100644 --- a/compiler/rustc_error_messages/locales/en-US/lint.ftl +++ b/compiler/rustc_error_messages/locales/en-US/lint.ftl @@ -370,6 +370,8 @@ lint_builtin_anonymous_params = anonymous parameters are deprecated and will be .suggestion = try naming the parameter or explicitly ignoring it lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} + .msg_suggestion = {$msg} + .default_suggestion = remove this attribute lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used. lint_builtin_deprecated_attr_default_suggestion = remove this attribute @@ -430,10 +432,16 @@ lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may n .note = see issue #{$n} for more information .help = consider using `min_{$name}` instead, which is more stable and complete -lint_builtin_clashing_extern_same_name = `{$this_fi}` redeclared with a different signature +lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization +lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized + +lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed +lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit` instead, and only call `assume_init` after initialization is done + +lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration -lint_builtin_clashing_extern_diff_name = `{$this_fi}` redeclares `{$orig}` with a different signature +lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index f7055019bab..2bdff0d5a09 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1,3 +1,5 @@ +// #![deny(rustc::untranslatable_diagnostic)] +// #![deny(rustc::diagnostic_outside_of_impl)] //! Lints in the Rust compiler. //! //! This contains lints which can feasibly be implemented as their own @@ -23,16 +25,21 @@ use crate::{ errors::BuiltinEllpisisInclusiveRangePatterns, lints::{ - BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle, - BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, - BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures, + BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern, + BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, + BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, + BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, + BuiltinExplicitOutlivesSuggestion, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinIncompleteFeaturesNote, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns, - BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinUnexpectedCliConfigName, - BuiltinUnexpectedCliConfigValue, BuiltinUnnameableTestItems, BuiltinUnreachablePub, - BuiltinUnsafe, BuiltinUnstableFeatures, BuiltinUnusedDocComment, - BuiltinUnusedDocCommentSub, BuiltinWhileTrue, + BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds, + BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause, + BuiltinUnexpectedCliConfigName, BuiltinUnexpectedCliConfigValue, + BuiltinUngatedAsyncFnTrackCaller, BuiltinUnnameableTestItems, BuiltinUnpermittedTypeInit, + BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe, + BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub, + BuiltinWhileTrue, SuggestChangingAssocTypes, }, types::{transparent_newtype_field, CItemKind}, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, @@ -45,9 +52,7 @@ use rustc_ast_pretty::pprust::{self, expr_to_string}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{ - fluent, Applicability, DecorateLint, DelayDm, Diagnostic, DiagnosticStyledString, MultiSpan, -}; +use rustc_errors::{fluent, Applicability, DecorateLint, MultiSpan}; use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -923,24 +928,18 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { _, ) = gate { - // FIXME(davidtwco) translatable deprecated attr - cx.struct_span_lint( + let suggestion = match suggestion { + Some(msg) => { + BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg } + } + None => { + BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } + } + }; + cx.emit_spanned_lint( DEPRECATED, attr.span, - fluent::lint_builtin_deprecated_attr_link, - |lint| { - lint.set_arg("name", name) - .set_arg("reason", reason) - .set_arg("link", link) - .span_suggestion_short( - attr.span, - suggestion.map(|s| s.into()).unwrap_or( - fluent::lint_builtin_deprecated_attr_default_suggestion, - ), - "", - Applicability::MachineApplicable, - ) - }, + BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, ); } return; @@ -1305,20 +1304,10 @@ fn check_fn( // Now, check if the function has the `#[track_caller]` attribute && let Some(attr) = attrs.iter().find(|attr| attr.has_name(sym::track_caller)) { - cx.struct_span_lint( - UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span, - fluent::lint_ungated_async_fn_track_caller, - |lint| { - lint.span_label(span, fluent::label); - rustc_session::parse::add_feature_diagnostics( - lint, - &cx.tcx.sess.parse_sess, - sym::closure_track_caller, - ); - lint - }, - ); + cx.emit_spanned_lint(UNGATED_ASYNC_FN_TRACK_CALLER, attr.span, BuiltinUngatedAsyncFnTrackCaller { + label: span, + parse_sess: &cx.tcx.sess.parse_sess, + }); } } } @@ -1447,7 +1436,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_ ); impl TypeAliasBounds { - fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { + pub(crate) fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { match *qpath { hir::QPath::TypeRelative(ref ty, _) => { // If this is a type variable, we found a `T::Assoc`. @@ -1461,29 +1450,6 @@ fn is_type_variable_assoc(qpath: &hir::QPath<'_>) -> bool { hir::QPath::Resolved(..) | hir::QPath::LangItem(..) => false, } } - - fn suggest_changing_assoc_types(ty: &hir::Ty<'_>, err: &mut Diagnostic) { - // Access to associates types should use `::Assoc`, which does not need a - // bound. Let's see if this type does that. - - // We use a HIR visitor to walk the type. - use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a> { - err: &'a mut Diagnostic, - } - impl Visitor<'_> for WalkAssocTypes<'_> { - fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) { - if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); - } - intravisit::walk_qpath(self, qpath, id) - } - } - - // Let's go for a walk! - let mut visitor = WalkAssocTypes { err }; - visitor.visit_ty(ty); - } } impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { @@ -1517,35 +1483,31 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { let mut suggested_changing_assoc_types = false; if !where_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_where_clause, |lint| { - lint.set_span(where_spans); - lint.span_suggestion( - type_alias_generics.where_clause_span, - fluent::suggestion, - "", - Applicability::MachineApplicable, - ); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, lint); - suggested_changing_assoc_types = true; - } - lint + let sub = (!suggested_changing_assoc_types).then(|| { + suggested_changing_assoc_types = true; + SuggestChangingAssocTypes { ty } }); + cx.emit_spanned_lint( + TYPE_ALIAS_BOUNDS, + where_spans, + BuiltinTypeAliasWhereClause { + suggestion: type_alias_generics.where_clause_span, + sub, + }, + ); } if !inline_spans.is_empty() { - cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint_builtin_type_alias_generic_bounds, |lint| { - lint.set_span(inline_spans); - lint.multipart_suggestion( - fluent::suggestion, - inline_sugg, - Applicability::MachineApplicable, - ); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, lint); - } - lint + let suggestion = BuiltinTypeAliasGenericBoundsSuggestion { suggestions: inline_sugg }; + let sub = (!suggested_changing_assoc_types).then(|| { + suggested_changing_assoc_types = true; + SuggestChangingAssocTypes { ty } }); + cx.emit_spanned_lint( + TYPE_ALIAS_BOUNDS, + inline_spans, + BuiltinTypeAliasGenericBounds { suggestion, sub }, + ); } } } @@ -2376,6 +2338,36 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { declare_lint_pass!(InvalidValue => [INVALID_VALUE]); +/// Information about why a type cannot be initialized this way. +pub struct InitError { + pub(crate) message: String, + /// Spans from struct fields and similar that can be obtained from just the type. + pub(crate) span: Option, + /// Used to report a trace through adts. + pub(crate) nested: Option>, +} +impl InitError { + fn spanned(self, span: Span) -> InitError { + Self { span: Some(span), ..self } + } + + fn nested(self, nested: impl Into>) -> InitError { + assert!(self.nested.is_none()); + Self { nested: nested.into().map(Box::new), ..self } + } +} + +impl<'a> From<&'a str> for InitError { + fn from(s: &'a str) -> Self { + s.to_owned().into() + } +} +impl From for InitError { + fn from(message: String) -> Self { + Self { message, span: None, nested: None } + } +} + impl<'tcx> LateLintPass<'tcx> for InvalidValue { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) { #[derive(Debug, Copy, Clone, PartialEq)] @@ -2384,36 +2376,6 @@ enum InitKind { Uninit, } - /// Information about why a type cannot be initialized this way. - struct InitError { - message: String, - /// Spans from struct fields and similar that can be obtained from just the type. - span: Option, - /// Used to report a trace through adts. - nested: Option>, - } - impl InitError { - fn spanned(self, span: Span) -> InitError { - Self { span: Some(span), ..self } - } - - fn nested(self, nested: impl Into>) -> InitError { - assert!(self.nested.is_none()); - Self { nested: nested.into().map(Box::new), ..self } - } - } - - impl<'a> From<&'a str> for InitError { - fn from(s: &'a str) -> Self { - s.to_owned().into() - } - } - impl From for InitError { - fn from(message: String) -> Self { - Self { message, span: None, nested: None } - } - } - /// Test if this constant is all-0. fn is_zero(expr: &hir::Expr<'_>) -> bool { use hir::ExprKind::*; @@ -2637,46 +2599,16 @@ fn ty_find_init_error<'tcx>( // using zeroed or uninitialized memory. // We are extremely conservative with what we warn about. let conjured_ty = cx.typeck_results().expr_ty(expr); - if let Some(mut err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) - { - // FIXME(davidtwco): make translatable - cx.struct_span_lint( + if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) { + let msg = match init { + InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed, + InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint, + }; + let sub = BuiltinUnpermittedTypeInitSub { err }; + cx.emit_spanned_lint( INVALID_VALUE, expr.span, - DelayDm(|| { - format!( - "the type `{}` does not permit {}", - conjured_ty, - match init { - InitKind::Zeroed => "zero-initialization", - InitKind::Uninit => "being left uninitialized", - }, - ) - }), - |lint| { - lint.span_label( - expr.span, - "this code causes undefined behavior when executed", - ); - lint.span_label( - expr.span, - "help: use `MaybeUninit` instead, \ - and only call `assume_init` after initialization is done", - ); - loop { - if let Some(span) = err.span { - lint.span_note(span, &err.message); - } else { - lint.note(&err.message); - } - if let Some(e) = err.nested { - err = *e; - } else { - break; - } - } - lint - }, + BuiltinUnpermittedTypeInit { msg, ty: conjured_ty, label: expr.span, sub }, ); } } @@ -3022,31 +2954,44 @@ fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignI SymbolName::Normal(_) => fi.span, SymbolName::Link(_, annot_span) => fi.span.to(annot_span), }; - // Finally, emit the diagnostic. - let msg = if orig.get_name() == this_fi.ident.name { - fluent::lint_builtin_clashing_extern_same_name - } else { - fluent::lint_builtin_clashing_extern_diff_name + // Finally, emit the diagnostic. + let mut expected_str = DiagnosticStyledString::new(); + expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false); + let mut found_str = DiagnosticStyledString::new(); + found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); + + let this = this_fi.ident.name; + let orig = orig.get_name(); + let previous_decl_label = get_relevant_span(orig_fi); + let mismatch_label = get_relevant_span(this_fi); + let sub = BuiltinClashingExternSub { + tcx, + expected: existing_decl_ty, + found: this_decl_ty, }; - tcx.struct_span_lint_hir( + let decorator = if orig == this { + BuiltinClashingExtern::SameName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } + } else { + BuiltinClashingExtern::DiffName { + this, + orig, + previous_decl_label, + mismatch_label, + sub, + } + }; + tcx.emit_spanned_lint( CLASHING_EXTERN_DECLARATIONS, this_fi.hir_id(), get_relevant_span(this_fi), - msg, - |lint| { - let mut expected_str = DiagnosticStyledString::new(); - expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false); - let mut found_str = DiagnosticStyledString::new(); - found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true); - - lint.set_arg("this_fi", this_fi.ident.name) - .set_arg("orig", orig.get_name()) - .span_label(get_relevant_span(orig_fi), fluent::previous_decl_label) - .span_label(get_relevant_span(this_fi), fluent::mismatch_label) - // FIXME(davidtwco): translatable expected/found - .note_expected_found(&"", expected_str, &"", found_str) - }, + decorator, ); } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 147cd3e0460..ee6fa5300f4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,14 +1,18 @@ use std::num::NonZeroU32; use rustc_errors::{ - fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, SuggestionStyle, + fluent, AddToDiagnostic, Applicability, DecorateLint, DiagnosticMessage, + DiagnosticStyledString, SuggestionStyle, }; use rustc_hir::def_id::DefId; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{Predicate, Ty, TyCtxt}; -use rustc_span::{edition::Edition, symbol::Ident, Span, Symbol}; +use rustc_session::parse::ParseSess; +use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol}; -use crate::{errors::OverruledAttributeSub, LateContext}; +use crate::{ + builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, +}; // array_into_iter.rs #[derive(LintDiagnostic)] @@ -142,7 +146,31 @@ pub struct BuiltinAnonymousParams<'a> { pub ty_snip: &'a str, } -// FIXME: add lint::builtin_deprecated_attr_link +// FIXME(davidtwco) translatable deprecated attr +#[derive(LintDiagnostic)] +#[diag(lint_builtin_deprecated_attr_link)] +pub struct BuiltinDeprecatedAttrLink<'a> { + pub name: Symbol, + pub reason: &'a str, + pub link: &'a str, + #[subdiagnostic] + pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>, +} + +#[derive(Subdiagnostic)] +pub enum BuiltinDeprecatedAttrLinkSuggestion<'a> { + #[suggestion(msg_suggestion, code = "", applicability = "machine-applicable")] + Msg { + #[primary_span] + suggestion: Span, + msg: &'a str, + }, + #[suggestion(default_suggestion, code = "", applicability = "machine-applicable")] + Default { + #[primary_span] + suggestion: Span, + }, +} #[derive(LintDiagnostic)] #[diag(lint_builtin_deprecated_attr_used)] @@ -199,6 +227,31 @@ pub struct BuiltinConstNoMangle { #[diag(lint_builtin_unstable_features)] pub struct BuiltinUnstableFeatures; +// lint_ungated_async_fn_track_caller +pub struct BuiltinUngatedAsyncFnTrackCaller<'a> { + pub label: Span, + pub parse_sess: &'a ParseSess, +} + +impl<'a> DecorateLint<'a, ()> for BuiltinUngatedAsyncFnTrackCaller<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.span_label(self.label, fluent::label); + rustc_session::parse::add_feature_diagnostics( + diag, + &self.parse_sess, + sym::closure_track_caller, + ); + diag + } + + fn msg(&self) -> DiagnosticMessage { + fluent::lint_ungated_async_fn_track_caller + } +} + #[derive(LintDiagnostic)] #[diag(lint_builtin_unreachable_pub)] pub struct BuiltinUnreachablePub<'a> { @@ -209,9 +262,83 @@ pub struct BuiltinUnreachablePub<'a> { pub help: Option<()>, } -// FIXME: migrate builtin_type_alias_where_clause +pub struct SuggestChangingAssocTypes<'a, 'b> { + pub ty: &'a rustc_hir::Ty<'b>, +} -// FIXME: migrate builtin_type_alias_generic_bounds +impl AddToDiagnostic for SuggestChangingAssocTypes<'_, '_> { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + // Access to associates types should use `::Assoc`, which does not need a + // bound. Let's see if this type does that. + + // We use a HIR visitor to walk the type. + use rustc_hir::intravisit::{self, Visitor}; + struct WalkAssocTypes<'a> { + err: &'a mut rustc_errors::Diagnostic, + } + impl Visitor<'_> for WalkAssocTypes<'_> { + fn visit_qpath( + &mut self, + qpath: &rustc_hir::QPath<'_>, + id: rustc_hir::HirId, + span: Span, + ) { + if TypeAliasBounds::is_type_variable_assoc(qpath) { + self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); + } + intravisit::walk_qpath(self, qpath, id) + } + } + + // Let's go for a walk! + let mut visitor = WalkAssocTypes { err: diag }; + visitor.visit_ty(self.ty); + } +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_type_alias_where_clause)] +pub struct BuiltinTypeAliasWhereClause<'a, 'b> { + #[suggestion(code = "", applicability = "machine-applicable")] + pub suggestion: Span, + #[subdiagnostic] + pub sub: Option>, +} + +#[derive(LintDiagnostic)] +#[diag(lint_builtin_type_alias_generic_bounds)] +pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { + #[subdiagnostic] + pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion, + #[subdiagnostic] + pub sub: Option>, +} + +pub struct BuiltinTypeAliasGenericBoundsSuggestion { + pub suggestions: Vec<(Span, String)>, +} + +impl AddToDiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + diag.multipart_suggestion( + fluent::suggestion, + self.suggestions, + Applicability::MachineApplicable, + ); + } +} #[derive(LintDiagnostic)] #[diag(lint_builtin_trivial_bounds)] @@ -285,9 +412,107 @@ pub struct BuiltinIncompleteFeaturesNote { pub n: NonZeroU32, } -// FIXME: migrate "the type `{}` does not permit {}" +pub struct BuiltinUnpermittedTypeInit<'a> { + pub msg: DiagnosticMessage, + pub ty: Ty<'a>, + pub label: Span, + pub sub: BuiltinUnpermittedTypeInitSub, +} -// FIXME: fluent::lint::builtin_clashing_extern_{same,diff}_name +impl<'a> DecorateLint<'a, ()> for BuiltinUnpermittedTypeInit<'_> { + fn decorate_lint<'b>( + self, + diag: &'b mut rustc_errors::DiagnosticBuilder<'a, ()>, + ) -> &'b mut rustc_errors::DiagnosticBuilder<'a, ()> { + diag.set_arg("ty", self.ty); + diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label); + diag.span_label(self.label, fluent::lint_builtin_unpermitted_type_init_label_suggestion); + self.sub.add_to_diagnostic(diag); + diag + } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + self.msg.clone() + } +} + +// FIXME(davidtwco): make translatable +pub struct BuiltinUnpermittedTypeInitSub { + pub err: InitError, +} + +impl AddToDiagnostic for BuiltinUnpermittedTypeInitSub { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + let mut err = self.err; + loop { + if let Some(span) = err.span { + diag.span_note(span, err.message); + } else { + diag.note(err.message); + } + if let Some(e) = err.nested { + err = *e; + } else { + break; + } + } + } +} + +#[derive(LintDiagnostic)] +pub enum BuiltinClashingExtern<'a> { + #[diag(lint_builtin_clashing_extern_same_name)] + SameName { + this: Symbol, + orig: Symbol, + #[label(previous_decl_label)] + previous_decl_label: Span, + #[label(mismatch_label)] + mismatch_label: Span, + #[subdiagnostic] + sub: BuiltinClashingExternSub<'a>, + }, + #[diag(lint_builtin_clashing_extern_diff_name)] + DiffName { + this: Symbol, + orig: Symbol, + #[label(previous_decl_label)] + previous_decl_label: Span, + #[label(mismatch_label)] + mismatch_label: Span, + #[subdiagnostic] + sub: BuiltinClashingExternSub<'a>, + }, +} + +// FIXME(davidtwco): translatable expected/found +pub struct BuiltinClashingExternSub<'a> { + pub tcx: TyCtxt<'a>, + pub expected: Ty<'a>, + pub found: Ty<'a>, +} + +impl AddToDiagnostic for BuiltinClashingExternSub<'_> { + fn add_to_diagnostic_with(self, diag: &mut rustc_errors::Diagnostic, _: F) + where + F: Fn( + &mut rustc_errors::Diagnostic, + rustc_errors::SubdiagnosticMessage, + ) -> rustc_errors::SubdiagnosticMessage, + { + let mut expected_str = DiagnosticStyledString::new(); + expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false); + let mut found_str = DiagnosticStyledString::new(); + found_str.push(self.found.fn_sig(self.tcx).to_string(), true); + diag.note_expected_found(&"", expected_str, &"", found_str); + } +} #[derive(LintDiagnostic)] #[diag(lint_builtin_deref_nullptr)]