Rollup merge of #111004 - clubby789:migrate-mir-transform, r=oli-obk
Migrate `mir_transform` to translatable diagnostics cc #100717
This commit is contained in:
commit
68594142b1
16 changed files with 470 additions and 200 deletions
|
@ -3353,6 +3353,7 @@ dependencies = [
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_mir_build",
|
"rustc_mir_build",
|
||||||
"rustc_mir_dataflow",
|
"rustc_mir_dataflow",
|
||||||
|
"rustc_mir_transform",
|
||||||
"rustc_monomorphize",
|
"rustc_monomorphize",
|
||||||
"rustc_parse",
|
"rustc_parse",
|
||||||
"rustc_passes",
|
"rustc_passes",
|
||||||
|
@ -3861,8 +3862,10 @@ dependencies = [
|
||||||
"rustc_const_eval",
|
"rustc_const_eval",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
|
"rustc_fluent_macro",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
"rustc_macros",
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_mir_dataflow",
|
"rustc_mir_dataflow",
|
||||||
"rustc_serialize",
|
"rustc_serialize",
|
||||||
|
|
|
@ -51,6 +51,7 @@ rustc_interface = { path = "../rustc_interface" }
|
||||||
rustc_ast = { path = "../rustc_ast" }
|
rustc_ast = { path = "../rustc_ast" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
||||||
|
rustc_mir_transform = { path = "../rustc_mir_transform" }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
@ -64,5 +65,8 @@ features = [
|
||||||
[features]
|
[features]
|
||||||
llvm = ['rustc_interface/llvm']
|
llvm = ['rustc_interface/llvm']
|
||||||
max_level_info = ['rustc_log/max_level_info']
|
max_level_info = ['rustc_log/max_level_info']
|
||||||
rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
|
rustc_use_parallel_compiler = [
|
||||||
'rustc_middle/rustc_use_parallel_compiler']
|
'rustc_data_structures/rustc_use_parallel_compiler',
|
||||||
|
'rustc_interface/rustc_use_parallel_compiler',
|
||||||
|
'rustc_middle/rustc_use_parallel_compiler'
|
||||||
|
]
|
||||||
|
|
|
@ -99,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
|
||||||
rustc_middle::DEFAULT_LOCALE_RESOURCE,
|
rustc_middle::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
|
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
|
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
|
||||||
|
rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
|
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_parse::DEFAULT_LOCALE_RESOURCE,
|
rustc_parse::DEFAULT_LOCALE_RESOURCE,
|
||||||
rustc_passes::DEFAULT_LOCALE_RESOURCE,
|
rustc_passes::DEFAULT_LOCALE_RESOURCE,
|
||||||
|
|
|
@ -571,6 +571,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
|
||||||
Some((diagnostic, handler))
|
Some((diagnostic, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieves the [`Handler`] if available
|
||||||
|
pub fn handler(&self) -> Option<&Handler> {
|
||||||
|
match self.inner.state {
|
||||||
|
DiagnosticBuilderState::Emittable(handler) => Some(handler),
|
||||||
|
DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Buffers the diagnostic for later emission,
|
/// Buffers the diagnostic for later emission,
|
||||||
/// unless handler has disabled such buffering.
|
/// unless handler has disabled such buffering.
|
||||||
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
|
||||||
|
|
|
@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
|
||||||
rustc_target = { path = "../rustc_target" }
|
rustc_target = { path = "../rustc_target" }
|
||||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||||
rustc_span = { path = "../rustc_span" }
|
rustc_span = { path = "../rustc_span" }
|
||||||
|
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||||
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
coverage_test_macros = { path = "src/coverage/test_macros" }
|
coverage_test_macros = { path = "src/coverage/test_macros" }
|
||||||
|
|
66
compiler/rustc_mir_transform/messages.ftl
Normal file
66
compiler/rustc_mir_transform/messages.ftl
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
mir_transform_const_modify = 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
|
||||||
|
|
||||||
|
mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
|
||||||
|
.note = each usage of a `const` item creates a new temporary
|
||||||
|
.note2 = the mutable reference will refer to this temporary, not the original `const` item
|
||||||
|
.note3 = mutable reference created due to call to this method
|
||||||
|
|
||||||
|
mir_transform_const_defined_here = `const` item defined here
|
||||||
|
|
||||||
|
mir_transform_unaligned_packed_ref = reference to packed field is unaligned
|
||||||
|
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
|
||||||
|
.note_ub = 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)
|
||||||
|
|
||||||
|
mir_transform_unused_unsafe = unnecessary `unsafe` block
|
||||||
|
.label = because it's nested under this `unsafe` block
|
||||||
|
|
||||||
|
mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
|
||||||
|
[true] function or block
|
||||||
|
*[false] block
|
||||||
|
}
|
||||||
|
.not_inherited = items do not inherit unsafety from separate enclosing items
|
||||||
|
|
||||||
|
mir_transform_call_to_unsafe_label = call to unsafe function
|
||||||
|
mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
mir_transform_use_of_asm_label = use of inline assembly
|
||||||
|
mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||||
|
mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||||
|
mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||||
|
mir_transform_const_ptr2int_label = cast of pointer to int
|
||||||
|
mir_transform_const_ptr2int_note = casting pointers to integers in constants
|
||||||
|
mir_transform_use_of_static_mut_label = use of mutable static
|
||||||
|
mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||||
|
mir_transform_use_of_extern_static_label = use of extern static
|
||||||
|
mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||||
|
mir_transform_deref_ptr_label = dereference of raw pointer
|
||||||
|
mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||||
|
mir_transform_union_access_label = access to union field
|
||||||
|
mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||||
|
mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
|
||||||
|
mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
|
||||||
|
mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
|
||||||
|
mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
|
||||||
|
mir_transform_target_feature_call_label = call to function with `#[target_feature]`
|
||||||
|
mir_transform_target_feature_call_note = can only be called if the required target features are available
|
||||||
|
|
||||||
|
mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
|
||||||
|
|
||||||
|
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
|
||||||
|
mir_transform_operation_will_panic = this operation will panic at runtime
|
||||||
|
|
||||||
|
mir_transform_ffi_unwind_call = call to {$foreign ->
|
||||||
|
[true] foreign function
|
||||||
|
*[false] function pointer
|
||||||
|
} with FFI-unwind ABI
|
||||||
|
|
||||||
|
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
|
||||||
|
.suggestion = cast `{$ident}` to obtain a function pointer
|
||||||
|
|
||||||
|
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
|
||||||
|
.label = the value is held across this suspend point
|
||||||
|
.note = {$reason}
|
||||||
|
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
|
||||||
|
|
||||||
|
mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
|
|
@ -1,11 +1,12 @@
|
||||||
use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
|
use rustc_hir::HirId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::MirLint;
|
use crate::{errors, MirLint};
|
||||||
|
|
||||||
pub struct CheckConstItemMutation;
|
pub struct CheckConstItemMutation;
|
||||||
|
|
||||||
|
@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lint_const_item_usage(
|
/// If we should lint on this usage, return the [`HirId`], source [`Span`]
|
||||||
|
/// and [`Span`] of the const item to use in the lint.
|
||||||
|
fn should_lint_const_item_usage(
|
||||||
&self,
|
&self,
|
||||||
place: &Place<'tcx>,
|
place: &Place<'tcx>,
|
||||||
const_item: DefId,
|
const_item: DefId,
|
||||||
location: Location,
|
location: Location,
|
||||||
msg: impl Into<DiagnosticMessage>,
|
) -> Option<(HirId, Span, Span)> {
|
||||||
decorate: impl for<'a, 'b> FnOnce(
|
|
||||||
&'a mut DiagnosticBuilder<'b, ()>,
|
|
||||||
) -> &'a mut DiagnosticBuilder<'b, ()>,
|
|
||||||
) {
|
|
||||||
// Don't lint on borrowing/assigning when a dereference is involved.
|
// Don't lint on borrowing/assigning when a dereference is involved.
|
||||||
// If we 'leave' the temporary via a dereference, we must
|
// If we 'leave' the temporary via a dereference, we must
|
||||||
// be modifying something else
|
// be modifying something else
|
||||||
|
@ -83,16 +82,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
|
||||||
.assert_crate_local()
|
.assert_crate_local()
|
||||||
.lint_root;
|
.lint_root;
|
||||||
|
|
||||||
self.tcx.struct_span_lint_hir(
|
Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
|
||||||
CONST_ITEM_MUTATION,
|
} else {
|
||||||
lint_root,
|
None
|
||||||
source_info.span,
|
|
||||||
msg,
|
|
||||||
|lint| {
|
|
||||||
decorate(lint)
|
|
||||||
.span_note(self.tcx.def_span(const_item), "`const` item defined here")
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
|
||||||
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
|
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
|
||||||
// so emitting a lint would be redundant.
|
// so emitting a lint would be redundant.
|
||||||
if !lhs.projection.is_empty() {
|
if !lhs.projection.is_empty() {
|
||||||
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
|
if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
|
||||||
self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
|
&& let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
|
||||||
lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
|
self.tcx.emit_spanned_lint(
|
||||||
})
|
CONST_ITEM_MUTATION,
|
||||||
|
lint_root,
|
||||||
|
span,
|
||||||
|
errors::ConstMutate::Modify { konst: item }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are looking for MIR of the form:
|
// We are looking for MIR of the form:
|
||||||
|
@ -143,17 +139,22 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
|
||||||
});
|
});
|
||||||
let lint_loc =
|
let lint_loc =
|
||||||
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
|
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
|
||||||
self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
|
|
||||||
lint
|
|
||||||
.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");
|
|
||||||
|
|
||||||
if let Some((method_did, _substs)) = method_did {
|
let method_call = if let Some((method_did, _)) = method_did {
|
||||||
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
|
Some(self.tcx.def_span(method_did))
|
||||||
}
|
} else {
|
||||||
|
None
|
||||||
lint
|
};
|
||||||
});
|
if let Some((lint_root, span, item)) =
|
||||||
|
self.should_lint_const_item_usage(place, def_id, lint_loc)
|
||||||
|
{
|
||||||
|
self.tcx.emit_spanned_lint(
|
||||||
|
CONST_ITEM_MUTATION,
|
||||||
|
lint_root,
|
||||||
|
span,
|
||||||
|
errors::ConstMutate::MutBorrow { method_call, konst: item },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.super_rvalue(rvalue, loc);
|
self.super_rvalue(rvalue, loc);
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
|
|
||||||
use crate::util;
|
|
||||||
use crate::MirLint;
|
use crate::MirLint;
|
||||||
|
use crate::{errors, util};
|
||||||
|
|
||||||
pub struct CheckPackedRef;
|
pub struct CheckPackedRef;
|
||||||
|
|
||||||
|
@ -49,25 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
|
||||||
// shouldn't do.
|
// shouldn't do.
|
||||||
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
|
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
|
||||||
} else {
|
} else {
|
||||||
struct_span_err!(
|
self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
|
||||||
self.tcx.sess,
|
|
||||||
self.source_info.span,
|
|
||||||
E0793,
|
|
||||||
"reference to packed field is unaligned"
|
|
||||||
)
|
|
||||||
.note(
|
|
||||||
"packed structs are only aligned by one byte, and many modern architectures \
|
|
||||||
penalize unaligned field accesses"
|
|
||||||
)
|
|
||||||
.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)"
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use rustc_data_structures::unord::{UnordItems, UnordSet};
|
use rustc_data_structures::unord::{UnordItems, UnordSet};
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -15,6 +14,8 @@ use rustc_session::lint::Level;
|
||||||
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
pub struct UnsafetyChecker<'a, 'tcx> {
|
pub struct UnsafetyChecker<'a, 'tcx> {
|
||||||
body: &'a Body<'tcx>,
|
body: &'a Body<'tcx>,
|
||||||
body_did: LocalDefId,
|
body_did: LocalDefId,
|
||||||
|
@ -509,21 +510,12 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResu
|
||||||
|
|
||||||
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
|
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
|
||||||
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
|
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
|
||||||
let msg = "unnecessary `unsafe` block";
|
let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
|
||||||
tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
|
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
|
||||||
lint.span_label(span, msg);
|
} else {
|
||||||
match kind {
|
None
|
||||||
UnusedUnsafe::Unused => {}
|
};
|
||||||
UnusedUnsafe::InUnsafeBlock(id) => {
|
tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
|
||||||
lint.span_label(
|
|
||||||
tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
|
|
||||||
"because it's nested under this `unsafe` block",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lint
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
|
@ -537,26 +529,11 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
|
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
|
||||||
|
|
||||||
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
|
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
|
||||||
let (description, note) = details.description_and_note();
|
let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
UnsafetyViolationKind::General => {
|
UnsafetyViolationKind::General => {
|
||||||
// once
|
let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
|
||||||
let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
|
|
||||||
" function or"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut err = struct_span_err!(
|
|
||||||
tcx.sess,
|
|
||||||
source_info.span,
|
|
||||||
E0133,
|
|
||||||
"{} is unsafe and requires unsafe{} block",
|
|
||||||
description,
|
|
||||||
unsafe_fn_msg,
|
|
||||||
);
|
|
||||||
err.span_label(source_info.span, description).note(note);
|
|
||||||
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
|
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
|
||||||
if let Node::Expr(block) = node
|
if let Node::Expr(block) = node
|
||||||
&& let ExprKind::Block(block, _) = block.kind
|
&& let ExprKind::Block(block, _) = block.kind
|
||||||
|
@ -572,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if let Some((id, _)) = note_non_inherited {
|
let enclosing = if let Some((id, _)) = note_non_inherited {
|
||||||
let span = tcx.hir().span(id);
|
Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
|
||||||
err.span_label(
|
} else {
|
||||||
tcx.sess.source_map().guess_head_span(span),
|
None
|
||||||
"items do not inherit unsafety from separate enclosing items",
|
};
|
||||||
);
|
tcx.sess.emit_err(errors::RequiresUnsafe {
|
||||||
}
|
span: source_info.span,
|
||||||
|
enclosing,
|
||||||
err.emit();
|
details,
|
||||||
|
op_in_unsafe_fn_allowed,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
|
UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
|
||||||
UNSAFE_OP_IN_UNSAFE_FN,
|
UNSAFE_OP_IN_UNSAFE_FN,
|
||||||
lint_root,
|
lint_root,
|
||||||
source_info.span,
|
source_info.span,
|
||||||
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|
errors::UnsafeOpInUnsafeFn { details },
|
||||||
|lint| lint.span_label(source_info.span, description).note(note),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Propagates constants for early reporting of statically known
|
//! Propagates constants for early reporting of statically known
|
||||||
//! assertion failures
|
//! assertion failures
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use either::Left;
|
use either::Left;
|
||||||
|
|
||||||
use rustc_const_eval::interpret::Immediate;
|
use rustc_const_eval::interpret::Immediate;
|
||||||
|
@ -17,7 +19,6 @@ use rustc_middle::ty::InternalSubsts;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
|
self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
|
||||||
};
|
};
|
||||||
use rustc_session::lint;
|
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
||||||
use rustc_trait_selection::traits;
|
use rustc_trait_selection::traits;
|
||||||
|
@ -25,6 +26,7 @@ use rustc_trait_selection::traits;
|
||||||
use crate::const_prop::CanConstProp;
|
use crate::const_prop::CanConstProp;
|
||||||
use crate::const_prop::ConstPropMachine;
|
use crate::const_prop::ConstPropMachine;
|
||||||
use crate::const_prop::ConstPropMode;
|
use crate::const_prop::ConstPropMode;
|
||||||
|
use crate::errors::AssertLint;
|
||||||
use crate::MirLint;
|
use crate::MirLint;
|
||||||
|
|
||||||
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
/// The maximum number of bytes that we'll allocate space for a local or the return value.
|
||||||
|
@ -311,18 +313,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_assert_as_lint(
|
fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint<impl Debug>) {
|
||||||
&self,
|
|
||||||
lint: &'static lint::Lint,
|
|
||||||
location: Location,
|
|
||||||
message: &'static str,
|
|
||||||
panic: AssertKind<impl std::fmt::Debug>,
|
|
||||||
) {
|
|
||||||
let source_info = self.body().source_info(location);
|
|
||||||
if let Some(lint_root) = self.lint_root(*source_info) {
|
if let Some(lint_root) = self.lint_root(*source_info) {
|
||||||
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
|
self.tcx.emit_spanned_lint(lint.lint(), lint_root, source_info.span, lint);
|
||||||
lint.span_label(source_info.span, format!("{:?}", panic))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,11 +328,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
|
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
|
||||||
// appropriate to use.
|
// appropriate to use.
|
||||||
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
|
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(
|
||||||
"this arithmetic operation will overflow",
|
source_info.span,
|
||||||
AssertKind::OverflowNeg(val.to_const_int()),
|
AssertKind::OverflowNeg(val.to_const_int()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -370,23 +365,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
let r_bits = r.to_scalar().to_bits(right_size).ok();
|
let r_bits = r.to_scalar().to_bits(right_size).ok();
|
||||||
if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
|
if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
|
||||||
debug!("check_binary_op: reporting assert for {:?}", location);
|
debug!("check_binary_op: reporting assert for {:?}", location);
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
|
let panic = AssertKind::Overflow(
|
||||||
|
op,
|
||||||
|
match l {
|
||||||
|
Some(l) => l.to_const_int(),
|
||||||
|
// Invent a dummy value, the diagnostic ignores it anyway
|
||||||
|
None => ConstInt::new(
|
||||||
|
ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
|
||||||
|
left_ty.is_signed(),
|
||||||
|
left_ty.is_ptr_sized_integral(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
r.to_const_int(),
|
||||||
|
);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(source_info.span, panic),
|
||||||
"this arithmetic operation will overflow",
|
|
||||||
AssertKind::Overflow(
|
|
||||||
op,
|
|
||||||
match l {
|
|
||||||
Some(l) => l.to_const_int(),
|
|
||||||
// Invent a dummy value, the diagnostic ignores it anyway
|
|
||||||
None => ConstInt::new(
|
|
||||||
ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
|
|
||||||
left_ty.is_signed(),
|
|
||||||
left_ty.is_ptr_sized_integral(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
r.to_const_int(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -398,11 +393,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
|
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
|
||||||
Ok(overflow)
|
Ok(overflow)
|
||||||
})? {
|
})? {
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::ARITHMETIC_OVERFLOW,
|
source_info,
|
||||||
location,
|
AssertLint::ArithmeticOverflow(
|
||||||
"this arithmetic operation will overflow",
|
source_info.span,
|
||||||
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
|
AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
@ -543,11 +540,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
// Need proper const propagator for these.
|
// Need proper const propagator for these.
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
|
let source_info = self.body().source_info(location);
|
||||||
self.report_assert_as_lint(
|
self.report_assert_as_lint(
|
||||||
lint::builtin::UNCONDITIONAL_PANIC,
|
source_info,
|
||||||
location,
|
AssertLint::UnconditionalPanic(source_info.span, msg),
|
||||||
"this operation will panic at runtime",
|
|
||||||
msg,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
245
compiler/rustc_mir_transform/src/errors.rs
Normal file
245
compiler/rustc_mir_transform/src/errors.rs
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
use rustc_errors::{
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
|
||||||
|
#[track_caller]
|
||||||
|
fn decorate_lint<'b>(
|
||||||
|
self,
|
||||||
|
diag: &'b mut DiagnosticBuilder<'a, ()>,
|
||||||
|
) -> &'b mut DiagnosticBuilder<'a, ()> {
|
||||||
|
let desc = diag
|
||||||
|
.handler()
|
||||||
|
.expect("lint should not yet be emitted")
|
||||||
|
.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());
|
||||||
|
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, ()> {
|
||||||
|
diag.span_label(self.span(), format!("{:?}", self.panic()));
|
||||||
|
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,
|
||||||
|
}
|
|
@ -8,6 +8,8 @@ use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
use rustc_target::spec::PanicStrategy;
|
use rustc_target::spec::PanicStrategy;
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
fn abi_can_unwind(abi: Abi) -> bool {
|
fn abi_can_unwind(abi: Abi) -> bool {
|
||||||
use Abi::*;
|
use Abi::*;
|
||||||
match abi {
|
match abi {
|
||||||
|
@ -107,13 +109,13 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
|
||||||
.lint_root;
|
.lint_root;
|
||||||
let span = terminator.source_info.span;
|
let span = terminator.source_info.span;
|
||||||
|
|
||||||
let msg = match fn_def_id {
|
let foreign = fn_def_id.is_some();
|
||||||
Some(_) => "call to foreign function with FFI-unwind ABI",
|
tcx.emit_spanned_lint(
|
||||||
None => "call to function pointer with FFI-unwind ABI",
|
FFI_UNWIND_CALLS,
|
||||||
};
|
lint_root,
|
||||||
tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
|
span,
|
||||||
lint.span_label(span, msg)
|
errors::FfiUnwindCall { span, foreign },
|
||||||
});
|
);
|
||||||
|
|
||||||
tainted = true;
|
tainted = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_errors::Applicability;
|
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
|
@ -8,7 +7,7 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
|
||||||
use rustc_span::{symbol::sym, Span};
|
use rustc_span::{symbol::sym, Span};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use crate::MirLint;
|
use crate::{errors, MirLint};
|
||||||
|
|
||||||
pub struct FunctionItemReferences;
|
pub struct FunctionItemReferences;
|
||||||
|
|
||||||
|
@ -174,27 +173,21 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
|
||||||
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
|
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
|
||||||
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
|
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
|
||||||
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
|
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
|
||||||
self.tcx.struct_span_lint_hir(
|
let sugg = format!(
|
||||||
|
"{} as {}{}fn({}{}){}",
|
||||||
|
if params.is_empty() { ident.clone() } else { format!("{}::<{}>", ident, params) },
|
||||||
|
unsafety,
|
||||||
|
abi,
|
||||||
|
vec!["_"; num_args].join(", "),
|
||||||
|
variadic,
|
||||||
|
ret,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.tcx.emit_spanned_lint(
|
||||||
FUNCTION_ITEM_REFERENCES,
|
FUNCTION_ITEM_REFERENCES,
|
||||||
lint_root,
|
lint_root,
|
||||||
span,
|
span,
|
||||||
"taking a reference to a function item does not give a function pointer",
|
errors::FnItemRef { span, sugg, ident },
|
||||||
|lint| {
|
|
||||||
lint.span_suggestion(
|
|
||||||
span,
|
|
||||||
format!("cast `{}` to obtain a function pointer", ident),
|
|
||||||
format!(
|
|
||||||
"{} as {}{}fn({}{}){}",
|
|
||||||
if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
|
|
||||||
unsafety,
|
|
||||||
abi,
|
|
||||||
vec!["_"; num_args].join(", "),
|
|
||||||
variadic,
|
|
||||||
ret,
|
|
||||||
),
|
|
||||||
Applicability::Unspecified,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
//! Otherwise it drops all the values in scope at the last suspension point.
|
//! Otherwise it drops all the values in scope at the last suspension point.
|
||||||
|
|
||||||
use crate::deref_separator::deref_finder;
|
use crate::deref_separator::deref_finder;
|
||||||
|
use crate::errors;
|
||||||
use crate::simplify;
|
use crate::simplify;
|
||||||
use crate::MirPass;
|
use crate::MirPass;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
@ -1891,36 +1892,21 @@ fn check_must_not_suspend_def(
|
||||||
data: SuspendCheckData<'_>,
|
data: SuspendCheckData<'_>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
|
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
|
||||||
let msg = rustc_errors::DelayDm(|| {
|
let reason = attr.value_str().map(|s| errors::MustNotSuspendReason {
|
||||||
format!(
|
span: data.source_span,
|
||||||
"{}`{}`{} held across a suspend point, but should not be",
|
reason: s.as_str().to_string(),
|
||||||
data.descr_pre,
|
|
||||||
tcx.def_path_str(def_id),
|
|
||||||
data.descr_post,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
tcx.struct_span_lint_hir(
|
tcx.emit_spanned_lint(
|
||||||
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
|
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
|
||||||
hir_id,
|
hir_id,
|
||||||
data.source_span,
|
data.source_span,
|
||||||
msg,
|
errors::MustNotSupend {
|
||||||
|lint| {
|
yield_sp: data.yield_span,
|
||||||
// add span pointing to the offending yield/await
|
reason,
|
||||||
lint.span_label(data.yield_span, "the value is held across this suspend point");
|
src_sp: data.source_span,
|
||||||
|
pre: data.descr_pre,
|
||||||
// Add optional reason note
|
def_path: tcx.def_path_str(def_id),
|
||||||
if let Some(note) = attr.value_str() {
|
post: data.descr_post,
|
||||||
// FIXME(guswynn): consider formatting this better
|
|
||||||
lint.span_note(data.source_span, note.as_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add some quick suggestions on what to do
|
|
||||||
// FIXME: can `drop` work as a suggestion here as well?
|
|
||||||
lint.span_help(
|
|
||||||
data.source_span,
|
|
||||||
"consider using a block (`{ ... }`) \
|
|
||||||
to shrink the value's scope, ending before the suspend point",
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#![allow(rustc::potential_query_instability)]
|
#![allow(rustc::potential_query_instability)]
|
||||||
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(drain_filter)]
|
#![feature(drain_filter)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
@ -69,6 +71,7 @@ pub mod dump_mir;
|
||||||
mod early_otherwise_branch;
|
mod early_otherwise_branch;
|
||||||
mod elaborate_box_derefs;
|
mod elaborate_box_derefs;
|
||||||
mod elaborate_drops;
|
mod elaborate_drops;
|
||||||
|
mod errors;
|
||||||
mod ffi_unwind_calls;
|
mod ffi_unwind_calls;
|
||||||
mod function_item_references;
|
mod function_item_references;
|
||||||
mod generator;
|
mod generator;
|
||||||
|
@ -105,6 +108,11 @@ use rustc_const_eval::transform::promote_consts;
|
||||||
use rustc_const_eval::transform::validate;
|
use rustc_const_eval::transform::validate;
|
||||||
use rustc_mir_dataflow::rustc_peek;
|
use rustc_mir_dataflow::rustc_peek;
|
||||||
|
|
||||||
|
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||||
|
use rustc_fluent_macro::fluent_messages;
|
||||||
|
|
||||||
|
fluent_messages! { "../messages.ftl" }
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
check_unsafety::provide(providers);
|
check_unsafety::provide(providers);
|
||||||
coverage::query::provide(providers);
|
coverage::query::provide(providers);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Lowers intrinsic calls
|
//! Lowers intrinsic calls
|
||||||
|
|
||||||
use crate::MirPass;
|
use crate::{errors, MirPass};
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::subst::SubstsRef;
|
use rustc_middle::ty::subst::SubstsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
|
@ -310,11 +310,7 @@ fn resolve_rust_intrinsic<'tcx>(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
|
||||||
match &args[2] {
|
if !matches!(args[2], Operand::Constant(_)) {
|
||||||
Operand::Constant(_) => {} // all good
|
tcx.sess.emit_err(errors::SimdShuffleLastConst { span });
|
||||||
_ => {
|
|
||||||
let msg = "last argument of `simd_shuffle` is required to be a `const` item";
|
|
||||||
tcx.sess.span_err(span, msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue