5683791ebb
Add MVP suggestion for `unsafe_op_in_unsafe_fn` Rebase of https://github.com/rust-lang/rust/pull/99827 cc tracking issue https://github.com/rust-lang/rust/issues/71668 No real changes since the original PR, just migrated the new suggestion to use fluent messages and added a couple more testcases, AFAICT from the discussion there were no outstanding changes requested.
268 lines
9.2 KiB
Rust
268 lines
9.2 KiB
Rust
use rustc_errors::{
|
|
Applicability, DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
|
|
IntoDiagnostic,
|
|
};
|
|
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
|
use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
|
|
use rustc_session::lint::{self, Lint};
|
|
use rustc_span::Span;
|
|
|
|
#[derive(LintDiagnostic)]
|
|
pub(crate) enum ConstMutate {
|
|
#[diag(mir_transform_const_modify)]
|
|
#[note]
|
|
Modify {
|
|
#[note(mir_transform_const_defined_here)]
|
|
konst: Span,
|
|
},
|
|
#[diag(mir_transform_const_mut_borrow)]
|
|
#[note]
|
|
#[note(mir_transform_note2)]
|
|
MutBorrow {
|
|
#[note(mir_transform_note3)]
|
|
method_call: Option<Span>,
|
|
#[note(mir_transform_const_defined_here)]
|
|
konst: Span,
|
|
},
|
|
}
|
|
|
|
#[derive(Diagnostic)]
|
|
#[diag(mir_transform_unaligned_packed_ref, code = "E0793")]
|
|
#[note]
|
|
#[note(mir_transform_note_ub)]
|
|
#[help]
|
|
pub(crate) struct UnalignedPackedRef {
|
|
#[primary_span]
|
|
pub span: Span,
|
|
}
|
|
|
|
#[derive(LintDiagnostic)]
|
|
#[diag(mir_transform_unused_unsafe)]
|
|
pub(crate) struct UnusedUnsafe {
|
|
#[label(mir_transform_unused_unsafe)]
|
|
pub span: Span,
|
|
#[label]
|
|
pub nested_parent: Option<Span>,
|
|
}
|
|
|
|
pub(crate) struct RequiresUnsafe {
|
|
pub span: Span,
|
|
pub details: RequiresUnsafeDetail,
|
|
pub enclosing: Option<Span>,
|
|
pub op_in_unsafe_fn_allowed: bool,
|
|
}
|
|
|
|
// The primary message for this diagnostic should be '{$label} is unsafe and...',
|
|
// so we need to eagerly translate the label here, which isn't supported by the derive API
|
|
// We could also exhaustively list out the primary messages for all unsafe violations,
|
|
// but this would result in a lot of duplication.
|
|
impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
|
|
#[track_caller]
|
|
fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> {
|
|
let mut diag =
|
|
handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe);
|
|
diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
|
|
diag.set_span(self.span);
|
|
diag.span_label(self.span, self.details.label());
|
|
diag.note(self.details.note());
|
|
let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
|
|
diag.set_arg("details", desc);
|
|
diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
|
|
if let Some(sp) = self.enclosing {
|
|
diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited);
|
|
}
|
|
diag
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub(crate) struct RequiresUnsafeDetail {
|
|
pub span: Span,
|
|
pub violation: UnsafetyViolationDetails,
|
|
}
|
|
|
|
impl RequiresUnsafeDetail {
|
|
fn note(self) -> DiagnosticMessage {
|
|
use UnsafetyViolationDetails::*;
|
|
match self.violation {
|
|
CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note,
|
|
UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note,
|
|
InitializingTypeWith => {
|
|
crate::fluent_generated::mir_transform_initializing_valid_range_note
|
|
}
|
|
CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note,
|
|
UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note,
|
|
UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note,
|
|
DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note,
|
|
AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note,
|
|
MutationOfLayoutConstrainedField => {
|
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_note
|
|
}
|
|
BorrowOfLayoutConstrainedField => {
|
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note
|
|
}
|
|
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note,
|
|
}
|
|
}
|
|
|
|
fn label(self) -> DiagnosticMessage {
|
|
use UnsafetyViolationDetails::*;
|
|
match self.violation {
|
|
CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label,
|
|
UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label,
|
|
InitializingTypeWith => {
|
|
crate::fluent_generated::mir_transform_initializing_valid_range_label
|
|
}
|
|
CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label,
|
|
UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label,
|
|
UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label,
|
|
DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label,
|
|
AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label,
|
|
MutationOfLayoutConstrainedField => {
|
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_label
|
|
}
|
|
BorrowOfLayoutConstrainedField => {
|
|
crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label
|
|
}
|
|
CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label,
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) struct UnsafeOpInUnsafeFn {
|
|
pub details: RequiresUnsafeDetail,
|
|
|
|
/// These spans point to:
|
|
/// 1. the start of the function body
|
|
/// 2. the end of the function body
|
|
/// 3. the function signature
|
|
pub suggest_unsafe_block: Option<(Span, Span, Span)>,
|
|
}
|
|
|
|
impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
|
|
#[track_caller]
|
|
fn decorate_lint<'b>(
|
|
self,
|
|
diag: &'b mut DiagnosticBuilder<'a, ()>,
|
|
) -> &'b mut DiagnosticBuilder<'a, ()> {
|
|
let handler = diag.handler().expect("lint should not yet be emitted");
|
|
let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
|
|
diag.set_arg("details", desc);
|
|
diag.span_label(self.details.span, self.details.label());
|
|
diag.note(self.details.note());
|
|
|
|
if let Some((start, end, fn_sig)) = self.suggest_unsafe_block {
|
|
diag.span_note(fn_sig, crate::fluent_generated::mir_transform_note);
|
|
diag.tool_only_multipart_suggestion(
|
|
crate::fluent_generated::mir_transform_suggestion,
|
|
vec![(start, " unsafe {".into()), (end, "}".into())],
|
|
Applicability::MaybeIncorrect,
|
|
);
|
|
}
|
|
|
|
diag
|
|
}
|
|
|
|
fn msg(&self) -> DiagnosticMessage {
|
|
crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn
|
|
}
|
|
}
|
|
|
|
pub(crate) enum AssertLint<P> {
|
|
ArithmeticOverflow(Span, AssertKind<P>),
|
|
UnconditionalPanic(Span, AssertKind<P>),
|
|
}
|
|
|
|
impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
|
|
fn decorate_lint<'b>(
|
|
self,
|
|
diag: &'b mut DiagnosticBuilder<'a, ()>,
|
|
) -> &'b mut DiagnosticBuilder<'a, ()> {
|
|
let span = self.span();
|
|
let assert_kind = self.panic();
|
|
let message = assert_kind.diagnostic_message();
|
|
assert_kind.add_args(&mut |name, value| {
|
|
diag.set_arg(name, value);
|
|
});
|
|
diag.span_label(span, message);
|
|
|
|
diag
|
|
}
|
|
|
|
fn msg(&self) -> DiagnosticMessage {
|
|
match self {
|
|
AssertLint::ArithmeticOverflow(..) => {
|
|
crate::fluent_generated::mir_transform_arithmetic_overflow
|
|
}
|
|
AssertLint::UnconditionalPanic(..) => {
|
|
crate::fluent_generated::mir_transform_operation_will_panic
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<P> AssertLint<P> {
|
|
pub fn lint(&self) -> &'static Lint {
|
|
match self {
|
|
AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW,
|
|
AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC,
|
|
}
|
|
}
|
|
pub fn span(&self) -> Span {
|
|
match self {
|
|
AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp,
|
|
}
|
|
}
|
|
pub fn panic(self) -> AssertKind<P> {
|
|
match self {
|
|
AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(LintDiagnostic)]
|
|
#[diag(mir_transform_ffi_unwind_call)]
|
|
pub(crate) struct FfiUnwindCall {
|
|
#[label(mir_transform_ffi_unwind_call)]
|
|
pub span: Span,
|
|
pub foreign: bool,
|
|
}
|
|
|
|
#[derive(LintDiagnostic)]
|
|
#[diag(mir_transform_fn_item_ref)]
|
|
pub(crate) struct FnItemRef {
|
|
#[suggestion(code = "{sugg}", applicability = "unspecified")]
|
|
pub span: Span,
|
|
pub sugg: String,
|
|
pub ident: String,
|
|
}
|
|
|
|
#[derive(LintDiagnostic)]
|
|
#[diag(mir_transform_must_not_suspend)]
|
|
pub(crate) struct MustNotSupend<'a> {
|
|
#[label]
|
|
pub yield_sp: Span,
|
|
#[subdiagnostic]
|
|
pub reason: Option<MustNotSuspendReason>,
|
|
#[help]
|
|
pub src_sp: Span,
|
|
pub pre: &'a str,
|
|
pub def_path: String,
|
|
pub post: &'a str,
|
|
}
|
|
|
|
#[derive(Subdiagnostic)]
|
|
#[note(mir_transform_note)]
|
|
pub(crate) struct MustNotSuspendReason {
|
|
#[primary_span]
|
|
pub span: Span,
|
|
pub reason: String,
|
|
}
|
|
|
|
#[derive(Diagnostic)]
|
|
#[diag(mir_transform_simd_shuffle_last_const)]
|
|
pub(crate) struct SimdShuffleLastConst {
|
|
#[primary_span]
|
|
pub span: Span,
|
|
}
|