| use rustc_errors::codes::*; |
| use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintDiagnostic, Subdiagnostic, msg}; |
| use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; |
| use rustc_middle::mir::AssertKind; |
| use rustc_middle::query::Key; |
| use rustc_middle::ty::TyCtxt; |
| use rustc_session::lint::{self, Lint}; |
| use rustc_span::def_id::DefId; |
| use rustc_span::{Ident, Span, Symbol}; |
| |
| /// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a |
| /// `#[target_feature]` attribute where the caller enables a different set of target features. |
| pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( |
| tcx: TyCtxt<'tcx>, |
| call_span: Span, |
| callee_def_id: DefId, |
| caller_def_id: DefId, |
| callee_only: &[&'a str], |
| ) { |
| tcx.node_span_lint( |
| lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, |
| tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), |
| call_span, |
| |lint| { |
| let callee = tcx.def_path_str(callee_def_id); |
| let caller = tcx.def_path_str(caller_def_id); |
| |
| lint.primary_message(format!( |
| "call to `#[inline(always)]`-annotated `{callee}` \ |
| requires the same target features to be inlined" |
| )); |
| lint.note("function will not be inlined"); |
| |
| lint.note(format!( |
| "the following target features are on `{callee}` but missing from `{caller}`: {}", |
| callee_only.join(", ") |
| )); |
| lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here")); |
| |
| let feats = callee_only.join(","); |
| lint.span_suggestion( |
| tcx.def_span(caller_def_id).shrink_to_lo(), |
| format!("add `#[target_feature]` attribute to `{caller}`"), |
| format!("#[target_feature(enable = \"{feats}\")]\n"), |
| lint::Applicability::MaybeIncorrect, |
| ); |
| }, |
| ); |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("function cannot return without recursing")] |
| #[help("a `loop` may express intention better if this is on purpose")] |
| pub(crate) struct UnconditionalRecursion { |
| #[label("cannot return without recursing")] |
| pub(crate) span: Span, |
| #[label("recursive call site")] |
| pub(crate) call_sites: Vec<Span>, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`{$callee}` is incompatible with `#[rustc_force_inline]`")] |
| #[note("incompatible due to: {$reason}")] |
| pub(crate) struct InvalidForceInline { |
| #[primary_span] |
| pub attr_span: Span, |
| #[label("`{$callee}` defined here")] |
| pub callee_span: Span, |
| pub callee: String, |
| pub reason: &'static str, |
| } |
| |
| #[derive(LintDiagnostic)] |
| pub(crate) enum ConstMutate { |
| #[diag("attempting to modify a `const` item")] |
| #[note( |
| "each usage of a `const` item creates a new temporary; the original `const` item will not be modified" |
| )] |
| Modify { |
| #[note("`const` item defined here")] |
| konst: Span, |
| }, |
| #[diag("taking a mutable reference to a `const` item")] |
| #[note("each usage of a `const` item creates a new temporary")] |
| #[note("the mutable reference will refer to this temporary, not the original `const` item")] |
| MutBorrow { |
| #[note("mutable reference created due to call to this method")] |
| method_call: Option<Span>, |
| #[note("`const` item defined here")] |
| konst: Span, |
| }, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("reference to field of packed {$ty_descr} is unaligned", code = E0793)] |
| #[note( |
| "this {$ty_descr} is {$align -> |
| [one] {\"\"} |
| *[other] {\"at most \"} |
| }{$align}-byte aligned, but the type of this field may require higher alignment" |
| )] |
| #[note( |
| "creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)" |
| )] |
| #[help( |
| "copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)" |
| )] |
| pub(crate) struct UnalignedPackedRef { |
| #[primary_span] |
| pub span: Span, |
| pub ty_descr: &'static str, |
| pub align: u64, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("MIR pass `{$name}` is unknown and will be ignored")] |
| pub(crate) struct UnknownPassName<'a> { |
| pub(crate) name: &'a str, |
| } |
| |
| pub(crate) struct AssertLint<P> { |
| pub span: Span, |
| pub assert_kind: AssertKind<P>, |
| pub lint_kind: AssertLintKind, |
| } |
| |
| pub(crate) enum AssertLintKind { |
| ArithmeticOverflow, |
| UnconditionalPanic, |
| } |
| |
| impl<'a, P: std::fmt::Debug> LintDiagnostic<'a, ()> for AssertLint<P> { |
| fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, ()>) { |
| diag.primary_message(match self.lint_kind { |
| AssertLintKind::ArithmeticOverflow => { |
| msg!("this arithmetic operation will overflow") |
| } |
| AssertLintKind::UnconditionalPanic => { |
| msg!("this operation will panic at runtime") |
| } |
| }); |
| let label = self.assert_kind.diagnostic_message(); |
| self.assert_kind.add_args(&mut |name, value| { |
| diag.arg(name, value); |
| }); |
| diag.span_label(self.span, label); |
| } |
| } |
| |
| impl AssertLintKind { |
| pub(crate) fn lint(&self) -> &'static Lint { |
| match self { |
| AssertLintKind::ArithmeticOverflow => lint::builtin::ARITHMETIC_OVERFLOW, |
| AssertLintKind::UnconditionalPanic => lint::builtin::UNCONDITIONAL_PANIC, |
| } |
| } |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("call to inline assembly that may unwind")] |
| pub(crate) struct AsmUnwindCall { |
| #[label("call to inline assembly that may unwind")] |
| pub span: Span, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag( |
| "call to {$foreign -> |
| [true] foreign function |
| *[false] function pointer |
| } with FFI-unwind ABI" |
| )] |
| pub(crate) struct FfiUnwindCall { |
| #[label( |
| "call to {$foreign -> |
| [true] foreign function |
| *[false] function pointer |
| } with FFI-unwind ABI" |
| )] |
| pub span: Span, |
| pub foreign: bool, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("taking a reference to a function item does not give a function pointer")] |
| pub(crate) struct FnItemRef { |
| #[suggestion( |
| "cast `{$ident}` to obtain a function pointer", |
| code = "{sugg}", |
| applicability = "unspecified" |
| )] |
| pub span: Span, |
| pub sugg: String, |
| pub ident: Ident, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("value captured by `{$name}` is never read")] |
| #[help("did you mean to capture by reference instead?")] |
| pub(crate) struct UnusedCaptureMaybeCaptureRef { |
| pub name: Symbol, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("variable `{$name}` is assigned to, but never used")] |
| #[note("consider using `_{$name}` instead")] |
| pub(crate) struct UnusedVarAssignedOnly { |
| pub name: Symbol, |
| #[subdiagnostic] |
| pub typo: Option<PatternTypo>, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("value assigned to `{$name}` is never read")] |
| pub(crate) struct UnusedAssign { |
| pub name: Symbol, |
| #[subdiagnostic] |
| pub suggestion: Option<UnusedAssignSuggestion>, |
| #[help("maybe it is overwritten before being read?")] |
| pub help: bool, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion( |
| "you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding", |
| applicability = "maybe-incorrect" |
| )] |
| pub(crate) struct UnusedAssignSuggestion { |
| pub pre: &'static str, |
| #[suggestion_part(code = "{pre}mut ")] |
| pub ty_span: Option<Span>, |
| #[suggestion_part(code = "")] |
| pub ty_ref_span: Span, |
| #[suggestion_part(code = "*")] |
| pub pre_lhs_span: Span, |
| #[suggestion_part(code = "")] |
| pub rhs_borrow_span: Span, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("value passed to `{$name}` is never read")] |
| #[help("maybe it is overwritten before being read?")] |
| pub(crate) struct UnusedAssignPassed { |
| pub name: Symbol, |
| } |
| |
| #[derive(LintDiagnostic)] |
| #[diag("unused variable: `{$name}`")] |
| pub(crate) struct UnusedVariable { |
| pub name: Symbol, |
| #[subdiagnostic] |
| pub string_interp: Vec<UnusedVariableStringInterp>, |
| #[subdiagnostic] |
| pub sugg: UnusedVariableSugg, |
| } |
| |
| #[derive(Subdiagnostic)] |
| pub(crate) enum UnusedVariableSugg { |
| #[multipart_suggestion("try ignoring the field", applicability = "machine-applicable")] |
| TryIgnore { |
| #[suggestion_part(code = "{name}: _")] |
| shorthands: Vec<Span>, |
| #[suggestion_part(code = "_")] |
| non_shorthands: Vec<Span>, |
| name: Symbol, |
| }, |
| |
| #[multipart_suggestion( |
| "if this is intentional, prefix it with an underscore", |
| applicability = "machine-applicable" |
| )] |
| TryPrefix { |
| #[suggestion_part(code = "_{name}")] |
| spans: Vec<Span>, |
| name: Symbol, |
| #[subdiagnostic] |
| typo: Option<PatternTypo>, |
| }, |
| |
| #[help("`{$name}` is captured in macro and introduced a unused variable")] |
| NoSugg { |
| #[primary_span] |
| span: Span, |
| name: Symbol, |
| }, |
| } |
| |
| pub(crate) struct UnusedVariableStringInterp { |
| pub lit: Span, |
| } |
| |
| impl Subdiagnostic for UnusedVariableStringInterp { |
| fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { |
| diag.span_label( |
| self.lit, |
| msg!("you might have meant to use string interpolation in this string literal"), |
| ); |
| diag.multipart_suggestion( |
| msg!("string interpolation only works in `format!` invocations"), |
| vec![ |
| (self.lit.shrink_to_lo(), String::from("format!(")), |
| (self.lit.shrink_to_hi(), String::from(")")), |
| ], |
| Applicability::MachineApplicable, |
| ); |
| } |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[multipart_suggestion( |
| "you might have meant to pattern match on the similarly named {$kind} `{$item_name}`", |
| style = "verbose", |
| applicability = "maybe-incorrect" |
| )] |
| pub(crate) struct PatternTypo { |
| #[suggestion_part(code = "{code}")] |
| pub span: Span, |
| pub code: String, |
| pub item_name: Symbol, |
| pub kind: &'static str, |
| } |
| |
| pub(crate) struct MustNotSupend<'a, 'tcx> { |
| pub tcx: TyCtxt<'tcx>, |
| pub yield_sp: Span, |
| pub reason: Option<MustNotSuspendReason>, |
| pub src_sp: Span, |
| pub pre: &'a str, |
| pub def_id: DefId, |
| pub post: &'a str, |
| } |
| |
| // Needed for def_path_str |
| impl<'a> LintDiagnostic<'a, ()> for MustNotSupend<'_, '_> { |
| fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) { |
| diag.primary_message(msg!( |
| "{$pre}`{$def_path}`{$post} held across a suspend point, but should not be" |
| )); |
| diag.span_label(self.yield_sp, msg!("the value is held across this suspend point")); |
| if let Some(reason) = self.reason { |
| diag.subdiagnostic(reason); |
| } |
| diag.span_help(self.src_sp, msg!("consider using a block (`{\"{ ... }\"}`) to shrink the value's scope, ending before the suspend point")); |
| diag.arg("pre", self.pre); |
| diag.arg("def_path", self.tcx.def_path_str(self.def_id)); |
| diag.arg("post", self.post); |
| } |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[note("{$reason}")] |
| pub(crate) struct MustNotSuspendReason { |
| #[primary_span] |
| pub span: Span, |
| pub reason: Symbol, |
| } |
| |
| #[derive(Diagnostic)] |
| #[diag("`{$callee}` could not be inlined into `{$caller}` but is required to be inlined")] |
| #[note("could not be inlined due to: {$reason}")] |
| pub(crate) struct ForceInlineFailure { |
| #[label("within `{$caller}`...")] |
| pub caller_span: Span, |
| #[label("`{$callee}` defined here")] |
| pub callee_span: Span, |
| #[label("annotation here")] |
| pub attr_span: Span, |
| #[primary_span] |
| #[label("...`{$callee}` called here")] |
| pub call_span: Span, |
| pub callee: String, |
| pub caller: String, |
| pub reason: &'static str, |
| #[subdiagnostic] |
| pub justification: Option<ForceInlineJustification>, |
| } |
| |
| #[derive(Subdiagnostic)] |
| #[note("`{$callee}` is required to be inlined to: {$sym}")] |
| pub(crate) struct ForceInlineJustification { |
| pub sym: Symbol, |
| } |