mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 16:24:46 +00:00
Auto merge of #104417 - mejrs:mir_build, r=davidtwco
Migrate rustc_mir_build diagnostics
Rebases https://github.com/rust-lang/rust/pull/100854
~~The remaining issue is how to better resolve 72bea68af4
~~
~~The diagnostic macros seems to generate a broken diagnostic, and I couldn't figure out how to manually format the fluent message, so I hardcoded the format string for now. I'd like pointers to a better fix for this.~~
Also, I'm not 100% sure I didn't mess up a rebase somewhere 🙂
r? `@davidtwco`
This commit is contained in:
commit
35a99eef32
@ -4069,6 +4069,7 @@ dependencies = [
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
"rustc_middle",
|
||||
"rustc_serialize",
|
||||
"rustc_session",
|
||||
|
301
compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Normal file
301
compiler/rustc_error_messages/locales/en-US/mir_build.ftl
Normal file
@ -0,0 +1,301 @@
|
||||
mir_build_unconditional_recursion = function cannot return without recursing
|
||||
.label = cannot return without recursing
|
||||
.help = a `loop` may express intention better if this is on purpose
|
||||
|
||||
mir_build_unconditional_recursion_call_site_label = recursive call site
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
|
||||
call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
|
||||
call to unsafe function is unsafe and requires unsafe block (error E0133)
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
|
||||
use of inline assembly is unsafe and requires unsafe block (error E0133)
|
||||
.note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||
.label = use of inline assembly
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
|
||||
initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
|
||||
block (error E0133)
|
||||
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||
.label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
|
||||
use of mutable static is unsafe and requires unsafe block (error E0133)
|
||||
.note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
.label = use of mutable static
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
|
||||
use of extern static is unsafe and requires unsafe block (error E0133)
|
||||
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||
.label = use of extern static
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
|
||||
dereference of raw pointer is unsafe and requires unsafe block (error E0133)
|
||||
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
.label = dereference of raw pointer
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
|
||||
access to union field is unsafe and requires unsafe block (error E0133)
|
||||
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
.label = access to union field
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
|
||||
mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
|
||||
.note = mutating layout constrained fields cannot statically be checked for valid values
|
||||
.label = mutation of layout constrained field
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
|
||||
borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
|
||||
.note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
|
||||
.label = borrow of layout constrained field with interior mutability
|
||||
|
||||
mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
|
||||
call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
|
||||
.note = can only be called if the required target features are available
|
||||
.label = call to function with `#[target_feature]`
|
||||
|
||||
mir_build_call_to_unsafe_fn_requires_unsafe =
|
||||
call to unsafe function `{$function}` is unsafe and requires unsafe block
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
|
||||
call to unsafe function is unsafe and requires unsafe block
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
call to unsafe function `{$function}` is unsafe and requires unsafe function or block
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
|
||||
call to unsafe function is unsafe and requires unsafe function or block
|
||||
.note = consult the function's documentation for information on how to avoid undefined behavior
|
||||
.label = call to unsafe function
|
||||
|
||||
mir_build_inline_assembly_requires_unsafe =
|
||||
use of inline assembly is unsafe and requires unsafe block
|
||||
.note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||
.label = use of inline assembly
|
||||
|
||||
mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
use of inline assembly is unsafe and requires unsafe function or block
|
||||
.note = inline assembly is entirely unchecked and can cause undefined behavior
|
||||
.label = use of inline assembly
|
||||
|
||||
mir_build_initializing_type_with_requires_unsafe =
|
||||
initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
|
||||
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||
.label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||
|
||||
mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
|
||||
.note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
|
||||
.label = initializing type with `rustc_layout_scalar_valid_range` attr
|
||||
|
||||
mir_build_mutable_static_requires_unsafe =
|
||||
use of mutable static is unsafe and requires unsafe block
|
||||
.note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
.label = use of mutable static
|
||||
|
||||
mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
use of mutable static is unsafe and requires unsafe function or block
|
||||
.note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
|
||||
.label = use of mutable static
|
||||
|
||||
mir_build_extern_static_requires_unsafe =
|
||||
use of extern static is unsafe and requires unsafe block
|
||||
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||
.label = use of extern static
|
||||
|
||||
mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
use of extern static is unsafe and requires unsafe function or block
|
||||
.note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
|
||||
.label = use of extern static
|
||||
|
||||
mir_build_deref_raw_pointer_requires_unsafe =
|
||||
dereference of raw pointer is unsafe and requires unsafe block
|
||||
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
.label = dereference of raw pointer
|
||||
|
||||
mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
dereference of raw pointer is unsafe and requires unsafe function or block
|
||||
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
|
||||
.label = dereference of raw pointer
|
||||
|
||||
mir_build_union_field_requires_unsafe =
|
||||
access to union field is unsafe and requires unsafe block
|
||||
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
.label = access to union field
|
||||
|
||||
mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
access to union field is unsafe and requires unsafe function or block
|
||||
.note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
|
||||
.label = access to union field
|
||||
|
||||
mir_build_mutation_of_layout_constrained_field_requires_unsafe =
|
||||
mutation of layout constrained field is unsafe and requires unsafe block
|
||||
.note = mutating layout constrained fields cannot statically be checked for valid values
|
||||
.label = mutation of layout constrained field
|
||||
|
||||
mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
mutation of layout constrained field is unsafe and requires unsafe function or block
|
||||
.note = mutating layout constrained fields cannot statically be checked for valid values
|
||||
.label = mutation of layout constrained field
|
||||
|
||||
mir_build_borrow_of_layout_constrained_field_requires_unsafe =
|
||||
borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
|
||||
.note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
|
||||
.label = borrow of layout constrained field with interior mutability
|
||||
|
||||
mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
|
||||
.note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
|
||||
.label = borrow of layout constrained field with interior mutability
|
||||
|
||||
mir_build_call_to_fn_with_requires_unsafe =
|
||||
call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
|
||||
.note = can only be called if the required target features are available
|
||||
.label = call to function with `#[target_feature]`
|
||||
|
||||
mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
|
||||
call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
|
||||
.note = can only be called if the required target features are available
|
||||
.label = call to function with `#[target_feature]`
|
||||
|
||||
mir_build_unused_unsafe = unnecessary `unsafe` block
|
||||
.label = unnecessary `unsafe` block
|
||||
|
||||
mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
|
||||
mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
|
||||
|
||||
mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
|
||||
.def_note = `{$peeled_ty}` defined here
|
||||
.type_note = the matched value is of type `{$ty}`
|
||||
.non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
|
||||
.reference_note = references are always considered inhabited
|
||||
.suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
|
||||
.help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
|
||||
|
||||
mir_build_static_in_pattern = statics cannot be referenced in patterns
|
||||
|
||||
mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
|
||||
|
||||
mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
|
||||
|
||||
mir_build_non_const_path = runtime values cannot be referenced in patterns
|
||||
|
||||
mir_build_unreachable_pattern = unreachable pattern
|
||||
.label = unreachable pattern
|
||||
.catchall_label = matches any value
|
||||
|
||||
mir_build_const_pattern_depends_on_generic_parameter =
|
||||
constant pattern depends on a generic parameter
|
||||
|
||||
mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
|
||||
|
||||
mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
|
||||
lower range bound must be less than or equal to upper
|
||||
.label = lower bound larger than upper bound
|
||||
.teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
|
||||
|
||||
mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
|
||||
|
||||
mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
} in let chain
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match
|
||||
.help = consider moving {$count ->
|
||||
[one] it
|
||||
*[other] them
|
||||
} outside of the construct
|
||||
|
||||
mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
} in let chain
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match
|
||||
.help = consider moving {$count ->
|
||||
[one] it
|
||||
*[other] them
|
||||
} into the body
|
||||
|
||||
mir_build_bindings_with_variant_name =
|
||||
pattern binding `{$ident}` is named the same as one of the variants of the type `{$ty_path}`
|
||||
.suggestion = to match on the variant, qualify the path
|
||||
|
||||
mir_build_irrefutable_let_patterns_generic_let = irrefutable `let` {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
}
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match, so the `let` is useless
|
||||
.help = consider removing `let`
|
||||
|
||||
mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
}
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match, so the `if let` is useless
|
||||
.help = consider replacing the `if let` with a `let`
|
||||
|
||||
mir_build_irrefutable_let_patterns_if_let_guard = irrefutable `if let` guard {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
}
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match, so the guard is useless
|
||||
.help = consider removing the guard and adding a `let` inside the match arm
|
||||
|
||||
mir_build_irrefutable_let_patterns_let_else = irrefutable `let...else` {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
}
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match, so the `else` clause is useless
|
||||
.help = consider removing the `else` clause
|
||||
|
||||
mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count ->
|
||||
[one] pattern
|
||||
*[other] patterns
|
||||
}
|
||||
.note = {$count ->
|
||||
[one] this pattern
|
||||
*[other] these patterns
|
||||
} will always match, so the loop will never exit
|
||||
.help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
|
||||
|
||||
mir_build_borrow_of_moved_value = borrow of moved value
|
||||
.label = value moved into `{$name}` here
|
||||
.occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
|
||||
.value_borrowed_label = value borrowed here after move
|
||||
.suggestion = borrow this binding in the pattern to avoid moving the value
|
||||
|
||||
mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
|
||||
.label = first mutable borrow, by `{$name}`, occurs here
|
||||
.mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
|
||||
.immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
|
||||
.moved = also moved into `{$name_moved}` here
|
@ -57,6 +57,7 @@ fluent_messages! {
|
||||
lint => "../locales/en-US/lint.ftl",
|
||||
metadata => "../locales/en-US/metadata.ftl",
|
||||
middle => "../locales/en-US/middle.ftl",
|
||||
mir_build => "../locales/en-US/mir_build.ftl",
|
||||
mir_dataflow => "../locales/en-US/mir_dataflow.ftl",
|
||||
monomorphize => "../locales/en-US/monomorphize.ftl",
|
||||
parse => "../locales/en-US/parse.ftl",
|
||||
|
@ -17,6 +17,7 @@ rustc_index = { path = "../rustc_index" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_infer = { path = "../rustc_infer" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
rustc_session = { path = "../rustc_session" }
|
||||
rustc_span = { path = "../rustc_span" }
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::build::ExprCategory;
|
||||
use crate::errors::*;
|
||||
use rustc_middle::thir::visit::{self, Visitor};
|
||||
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::BorrowKind;
|
||||
use rustc_middle::thir::*;
|
||||
@ -12,7 +12,6 @@ use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Bound;
|
||||
|
||||
struct UnsafetyVisitor<'a, 'tcx> {
|
||||
@ -46,7 +45,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
self.warn_unused_unsafe(
|
||||
hir_id,
|
||||
block_span,
|
||||
Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")),
|
||||
Some(UnusedUnsafeEnclosing::Block {
|
||||
span: self.tcx.sess.source_map().guess_head_span(enclosing_span),
|
||||
}),
|
||||
);
|
||||
f(self);
|
||||
} else {
|
||||
@ -60,7 +61,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
hir_id,
|
||||
span,
|
||||
if self.unsafe_op_in_unsafe_fn_allowed() {
|
||||
self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn"))
|
||||
self.body_unsafety
|
||||
.unsafe_fn_sig_span()
|
||||
.map(|span| UnusedUnsafeEnclosing::Function { span })
|
||||
} else {
|
||||
None
|
||||
},
|
||||
@ -83,30 +86,11 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
}
|
||||
SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
|
||||
SafetyContext::UnsafeFn => {
|
||||
let (description, note) = kind.description_and_note(self.tcx);
|
||||
// unsafe_op_in_unsafe_fn is disallowed
|
||||
self.tcx.struct_span_lint_hir(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
self.hir_context,
|
||||
span,
|
||||
format!("{} is unsafe and requires unsafe block (error E0133)", description,),
|
||||
|lint| lint.span_label(span, kind.simple_description()).note(note),
|
||||
)
|
||||
kind.emit_unsafe_op_in_unsafe_fn_lint(self.tcx, self.hir_context, span);
|
||||
}
|
||||
SafetyContext::Safe => {
|
||||
let (description, note) = kind.description_and_note(self.tcx);
|
||||
let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" };
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0133,
|
||||
"{} is unsafe and requires unsafe{} block",
|
||||
description,
|
||||
fn_sugg,
|
||||
)
|
||||
.span_label(span, kind.simple_description())
|
||||
.note(note)
|
||||
.emit();
|
||||
kind.emit_requires_unsafe_err(self.tcx, span, unsafe_op_in_unsafe_fn_allowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -115,17 +99,15 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||
&self,
|
||||
hir_id: hir::HirId,
|
||||
block_span: Span,
|
||||
enclosing_unsafe: Option<(Span, &'static str)>,
|
||||
enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
|
||||
) {
|
||||
let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
|
||||
let msg = "unnecessary `unsafe` block";
|
||||
self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
|
||||
lint.span_label(block_span, msg);
|
||||
if let Some((span, kind)) = enclosing_unsafe {
|
||||
lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
|
||||
}
|
||||
lint
|
||||
});
|
||||
self.tcx.emit_spanned_lint(
|
||||
UNUSED_UNSAFE,
|
||||
hir_id,
|
||||
block_span,
|
||||
UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
|
||||
);
|
||||
}
|
||||
|
||||
/// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
|
||||
@ -536,79 +518,187 @@ enum UnsafeOpKind {
|
||||
use UnsafeOpKind::*;
|
||||
|
||||
impl UnsafeOpKind {
|
||||
pub fn simple_description(&self) -> &'static str {
|
||||
pub fn emit_unsafe_op_in_unsafe_fn_lint(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) {
|
||||
match self {
|
||||
CallToUnsafeFunction(..) => "call to unsafe function",
|
||||
UseOfInlineAssembly => "use of inline assembly",
|
||||
InitializingTypeWith => "initializing type with `rustc_layout_scalar_valid_range` attr",
|
||||
UseOfMutableStatic => "use of mutable static",
|
||||
UseOfExternStatic => "use of extern static",
|
||||
DerefOfRawPointer => "dereference of raw pointer",
|
||||
AccessToUnionField => "access to union field",
|
||||
MutationOfLayoutConstrainedField => "mutation of layout constrained field",
|
||||
BorrowOfLayoutConstrainedField => {
|
||||
"borrow of layout constrained field with interior mutability"
|
||||
}
|
||||
CallToFunctionWith(..) => "call to function with `#[target_feature]`",
|
||||
CallToUnsafeFunction(did) if did.is_some() => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
|
||||
span,
|
||||
function: &tcx.def_path_str(did.unwrap()),
|
||||
},
|
||||
),
|
||||
CallToUnsafeFunction(..) => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { span },
|
||||
),
|
||||
UseOfInlineAssembly => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { span },
|
||||
),
|
||||
InitializingTypeWith => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { span },
|
||||
),
|
||||
UseOfMutableStatic => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { span },
|
||||
),
|
||||
UseOfExternStatic => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { span },
|
||||
),
|
||||
DerefOfRawPointer => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { span },
|
||||
),
|
||||
AccessToUnionField => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { span },
|
||||
),
|
||||
MutationOfLayoutConstrainedField => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { span },
|
||||
),
|
||||
BorrowOfLayoutConstrainedField => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { span },
|
||||
),
|
||||
CallToFunctionWith(did) => tcx.emit_spanned_lint(
|
||||
UNSAFE_OP_IN_UNSAFE_FN,
|
||||
hir_id,
|
||||
span,
|
||||
UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
|
||||
span,
|
||||
function: &tcx.def_path_str(*did),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description_and_note(&self, tcx: TyCtxt<'_>) -> (Cow<'static, str>, &'static str) {
|
||||
pub fn emit_requires_unsafe_err(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
span: Span,
|
||||
unsafe_op_in_unsafe_fn_allowed: bool,
|
||||
) {
|
||||
match self {
|
||||
CallToUnsafeFunction(did) => (
|
||||
if let Some(did) = did {
|
||||
Cow::from(format!("call to unsafe function `{}`", tcx.def_path_str(*did)))
|
||||
} else {
|
||||
Cow::Borrowed(self.simple_description())
|
||||
},
|
||||
"consult the function's documentation for information on how to avoid undefined \
|
||||
behavior",
|
||||
),
|
||||
UseOfInlineAssembly => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"inline assembly is entirely unchecked and can cause undefined behavior",
|
||||
),
|
||||
InitializingTypeWith => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"initializing a layout restricted type's field with a value outside the valid \
|
||||
range is undefined behavior",
|
||||
),
|
||||
UseOfMutableStatic => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"mutable statics can be mutated by multiple threads: aliasing violations or data \
|
||||
races will cause undefined behavior",
|
||||
),
|
||||
UseOfExternStatic => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"extern statics are not controlled by the Rust type system: invalid data, \
|
||||
aliasing violations or data races will cause undefined behavior",
|
||||
),
|
||||
DerefOfRawPointer => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
|
||||
and cause data races: all of these are undefined behavior",
|
||||
),
|
||||
AccessToUnionField => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"the field may not be properly initialized: using uninitialized data will cause \
|
||||
undefined behavior",
|
||||
),
|
||||
MutationOfLayoutConstrainedField => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"mutating layout constrained fields cannot statically be checked for valid values",
|
||||
),
|
||||
BorrowOfLayoutConstrainedField => (
|
||||
Cow::Borrowed(self.simple_description()),
|
||||
"references to fields of layout constrained fields lose the constraints. Coupled \
|
||||
with interior mutability, the field can be changed to invalid values",
|
||||
),
|
||||
CallToFunctionWith(did) => (
|
||||
Cow::from(format!(
|
||||
"call to function `{}` with `#[target_feature]`",
|
||||
tcx.def_path_str(*did)
|
||||
)),
|
||||
"can only be called if the required target features are available",
|
||||
),
|
||||
CallToUnsafeFunction(did) if did.is_some() && unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
span,
|
||||
function: &tcx.def_path_str(did.unwrap()),
|
||||
});
|
||||
}
|
||||
CallToUnsafeFunction(did) if did.is_some() => {
|
||||
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
|
||||
span,
|
||||
function: &tcx.def_path_str(did.unwrap()),
|
||||
});
|
||||
}
|
||||
CallToUnsafeFunction(..) if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess.emit_err(
|
||||
CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { span },
|
||||
);
|
||||
}
|
||||
CallToUnsafeFunction(..) => {
|
||||
tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless { span });
|
||||
}
|
||||
UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
UseOfInlineAssembly => {
|
||||
tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe { span });
|
||||
}
|
||||
InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
InitializingTypeWith => {
|
||||
tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe { span });
|
||||
}
|
||||
UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
UseOfMutableStatic => {
|
||||
tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafe { span });
|
||||
}
|
||||
UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
UseOfExternStatic => {
|
||||
tcx.sess.emit_err(UseOfExternStaticRequiresUnsafe { span });
|
||||
}
|
||||
DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
DerefOfRawPointer => {
|
||||
tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafe { span });
|
||||
}
|
||||
AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess
|
||||
.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span });
|
||||
}
|
||||
AccessToUnionField => {
|
||||
tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafe { span });
|
||||
}
|
||||
MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess.emit_err(
|
||||
MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
span,
|
||||
},
|
||||
);
|
||||
}
|
||||
MutationOfLayoutConstrainedField => {
|
||||
tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe { span });
|
||||
}
|
||||
BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess.emit_err(
|
||||
BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { span },
|
||||
);
|
||||
}
|
||||
BorrowOfLayoutConstrainedField => {
|
||||
tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe { span });
|
||||
}
|
||||
CallToFunctionWith(did) if unsafe_op_in_unsafe_fn_allowed => {
|
||||
tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
span,
|
||||
function: &tcx.def_path_str(*did),
|
||||
});
|
||||
}
|
||||
CallToFunctionWith(did) => {
|
||||
tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
|
||||
span,
|
||||
function: &tcx.def_path_str(*did),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
616
compiler/rustc_mir_build/src/errors.rs
Normal file
616
compiler/rustc_mir_build/src/errors.rs
Normal file
@ -0,0 +1,616 @@
|
||||
use crate::thir::pattern::MatchCheckCtxt;
|
||||
use rustc_errors::Handler;
|
||||
use rustc_errors::{
|
||||
error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{self, Ty};
|
||||
use rustc_span::{symbol::Ident, Span};
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unconditional_recursion)]
|
||||
#[help]
|
||||
pub struct UnconditionalRecursion {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(mir_build_unconditional_recursion_call_site_label)]
|
||||
pub call_sites: Vec<Span>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe<'a> {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe)]
|
||||
pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe)]
|
||||
#[note]
|
||||
pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe<'a> {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct CallToUnsafeFunctionRequiresUnsafe<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = "E0133")]
|
||||
#[note]
|
||||
pub struct CallToUnsafeFunctionRequiresUnsafeNameless {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed,
|
||||
code = "E0133"
|
||||
)]
|
||||
#[note]
|
||||
pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_inline_assembly_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfInlineAssemblyRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_initializing_type_with_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct InitializingTypeWithRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
|
||||
code = "E0133"
|
||||
)]
|
||||
#[note]
|
||||
pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_mutable_static_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfMutableStaticRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_extern_static_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfExternStaticRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_deref_raw_pointer_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct DerefOfRawPointerRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_union_field_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct AccessToUnionFieldRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
|
||||
code = "E0133"
|
||||
)]
|
||||
#[note]
|
||||
pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(
|
||||
mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed,
|
||||
code = "E0133"
|
||||
)]
|
||||
#[note]
|
||||
pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_call_to_fn_with_requires_unsafe, code = "E0133")]
|
||||
#[note]
|
||||
pub struct CallToFunctionWithRequiresUnsafe<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = "E0133")]
|
||||
#[note]
|
||||
pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
pub function: &'a str,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unused_unsafe)]
|
||||
pub struct UnusedUnsafe {
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub enclosing: Option<UnusedUnsafeEnclosing>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum UnusedUnsafeEnclosing {
|
||||
#[label(mir_build_unused_unsafe_enclosing_block_label)]
|
||||
Block {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[label(mir_build_unused_unsafe_enclosing_fn_label)]
|
||||
Function {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
}
|
||||
|
||||
pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
|
||||
pub cx: &'m MatchCheckCtxt<'p, 'tcx>,
|
||||
pub expr_span: Span,
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
|
||||
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
|
||||
let mut diag = handler.struct_span_err_with_code(
|
||||
self.span,
|
||||
rustc_errors::fluent::mir_build_non_exhaustive_patterns_type_not_empty,
|
||||
error_code!(E0004),
|
||||
);
|
||||
|
||||
let peeled_ty = self.ty.peel_refs();
|
||||
diag.set_arg("ty", self.ty);
|
||||
diag.set_arg("peeled_ty", peeled_ty);
|
||||
|
||||
if let ty::Adt(def, _) = peeled_ty.kind() {
|
||||
let def_span = self
|
||||
.cx
|
||||
.tcx
|
||||
.hir()
|
||||
.get_if_local(def.did())
|
||||
.and_then(|node| node.ident())
|
||||
.map(|ident| ident.span)
|
||||
.unwrap_or_else(|| self.cx.tcx.def_span(def.did()));
|
||||
|
||||
// workaround to make test pass
|
||||
let mut span: MultiSpan = def_span.into();
|
||||
span.push_span_label(def_span, "");
|
||||
|
||||
diag.span_note(span, rustc_errors::fluent::def_note);
|
||||
}
|
||||
|
||||
let is_variant_list_non_exhaustive = match self.ty.kind() {
|
||||
ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if is_variant_list_non_exhaustive {
|
||||
diag.note(rustc_errors::fluent::non_exhaustive_type_note);
|
||||
} else {
|
||||
diag.note(rustc_errors::fluent::type_note);
|
||||
}
|
||||
|
||||
if let ty::Ref(_, sub_ty, _) = self.ty.kind() {
|
||||
if !sub_ty.is_inhabited_from(self.cx.tcx, self.cx.module, self.cx.param_env) {
|
||||
diag.note(rustc_errors::fluent::reference_note);
|
||||
}
|
||||
}
|
||||
|
||||
let mut suggestion = None;
|
||||
let sm = self.cx.tcx.sess.source_map();
|
||||
if self.span.eq_ctxt(self.expr_span) {
|
||||
// Get the span for the empty match body `{}`.
|
||||
let (indentation, more) = if let Some(snippet) = sm.indentation_before(self.span) {
|
||||
(format!("\n{}", snippet), " ")
|
||||
} else {
|
||||
(" ".to_string(), "")
|
||||
};
|
||||
suggestion = Some((
|
||||
self.span.shrink_to_hi().with_hi(self.expr_span.hi()),
|
||||
format!(
|
||||
" {{{indentation}{more}_ => todo!(),{indentation}}}",
|
||||
indentation = indentation,
|
||||
more = more,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some((span, sugg)) = suggestion {
|
||||
diag.span_suggestion_verbose(
|
||||
span,
|
||||
rustc_errors::fluent::suggestion,
|
||||
sugg,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
diag.help(rustc_errors::fluent::help);
|
||||
}
|
||||
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_static_in_pattern, code = "E0158")]
|
||||
pub struct StaticInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_assoc_const_in_pattern, code = "E0158")]
|
||||
pub struct AssocConstInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_const_param_in_pattern, code = "E0158")]
|
||||
pub struct ConstParamInPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_non_const_path, code = "E0080")]
|
||||
pub struct NonConstPath {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_unreachable_pattern)]
|
||||
pub struct UnreachablePattern {
|
||||
#[label]
|
||||
pub span: Option<Span>,
|
||||
#[label(catchall_label)]
|
||||
pub catchall: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_const_pattern_depends_on_generic_parameter)]
|
||||
pub struct ConstPatternDependsOnGenericParameter {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_could_not_eval_const_pattern)]
|
||||
pub struct CouldNotEvalConstPattern {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = "E0030")]
|
||||
pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[note(teach_note)]
|
||||
pub teach: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = "E0579")]
|
||||
pub struct LowerRangeBoundMustBeLessThanUpper {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_leading_irrefutable_let_patterns)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct LeadingIrrefutableLetPatterns {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_trailing_irrefutable_let_patterns)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct TrailingIrrefutableLetPatterns {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_bindings_with_variant_name, code = "E0170")]
|
||||
pub struct BindingsWithVariantName {
|
||||
#[suggestion(code = "{ty_path}::{ident}", applicability = "machine-applicable")]
|
||||
pub suggestion: Option<Span>,
|
||||
pub ty_path: String,
|
||||
pub ident: Ident,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_irrefutable_let_patterns_generic_let)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct IrrefutableLetPatternsGenericLet {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_irrefutable_let_patterns_if_let)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct IrrefutableLetPatternsIfLet {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_irrefutable_let_patterns_if_let_guard)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct IrrefutableLetPatternsIfLetGuard {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_irrefutable_let_patterns_let_else)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct IrrefutableLetPatternsLetElse {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(mir_build_irrefutable_let_patterns_while_let)]
|
||||
#[note]
|
||||
#[help]
|
||||
pub struct IrrefutableLetPatternsWhileLet {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_borrow_of_moved_value)]
|
||||
pub struct BorrowOfMovedValue<'tcx> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
#[label(occurs_because_label)]
|
||||
pub binding_span: Span,
|
||||
#[label(value_borrowed_label)]
|
||||
pub conflicts_ref: Vec<Span>,
|
||||
pub name: Ident,
|
||||
pub ty: Ty<'tcx>,
|
||||
#[suggestion(code = "ref ", applicability = "machine-applicable")]
|
||||
pub suggest_borrowing: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(mir_build_multiple_mut_borrows)]
|
||||
pub struct MultipleMutBorrows {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub binding_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub occurences: Vec<MultipleMutBorrowOccurence>,
|
||||
pub name: Ident,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum MultipleMutBorrowOccurence {
|
||||
#[label(mutable_borrow)]
|
||||
Mutable {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name_mut: Ident,
|
||||
},
|
||||
#[label(immutable_borrow)]
|
||||
Immutable {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name_immut: Ident,
|
||||
},
|
||||
#[label(moved)]
|
||||
Moved {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
name_moved: Ident,
|
||||
},
|
||||
}
|
@ -19,6 +19,7 @@ extern crate rustc_middle;
|
||||
|
||||
mod build;
|
||||
mod check_unsafety;
|
||||
mod errors;
|
||||
mod lints;
|
||||
pub mod thir;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
use crate::errors::UnconditionalRecursion;
|
||||
use rustc_data_structures::graph::iterate::{
|
||||
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
|
||||
};
|
||||
@ -36,19 +37,11 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
|
||||
|
||||
let sp = tcx.def_span(def_id);
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
tcx.struct_span_lint_hir(
|
||||
tcx.emit_spanned_lint(
|
||||
UNCONDITIONAL_RECURSION,
|
||||
hir_id,
|
||||
sp,
|
||||
"function cannot return without recursing",
|
||||
|lint| {
|
||||
lint.span_label(sp, "cannot return without recursing");
|
||||
// offer some help to the programmer.
|
||||
for call_span in vis.reachable_recursive_calls {
|
||||
lint.span_label(call_span, "recursive call site");
|
||||
}
|
||||
lint.help("a `loop` may express intention better if this is on purpose")
|
||||
},
|
||||
UnconditionalRecursion { span: sp, call_sites: vis.reachable_recursive_calls },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -4,18 +4,22 @@ use super::usefulness::{
|
||||
};
|
||||
use super::{PatCtxt, PatternError};
|
||||
|
||||
use crate::errors::*;
|
||||
|
||||
use rustc_arena::TypedArena;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_errors::{
|
||||
error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
|
||||
ErrorGuaranteed, MultiSpan,
|
||||
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
|
||||
MultiSpan,
|
||||
};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::*;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{HirId, Pat};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
|
||||
|
||||
use rustc_session::lint::builtin::{
|
||||
BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
|
||||
};
|
||||
@ -107,28 +111,20 @@ impl PatCtxt<'_, '_> {
|
||||
for error in &self.errors {
|
||||
match *error {
|
||||
PatternError::StaticInPattern(span) => {
|
||||
self.span_e0158(span, "statics cannot be referenced in patterns")
|
||||
self.tcx.sess.emit_err(StaticInPattern { span });
|
||||
}
|
||||
PatternError::AssocConstInPattern(span) => {
|
||||
self.span_e0158(span, "associated consts cannot be referenced in patterns")
|
||||
self.tcx.sess.emit_err(AssocConstInPattern { span });
|
||||
}
|
||||
PatternError::ConstParamInPattern(span) => {
|
||||
self.span_e0158(span, "const parameters cannot be referenced in patterns")
|
||||
self.tcx.sess.emit_err(ConstParamInPattern { span });
|
||||
}
|
||||
PatternError::NonConstPath(span) => {
|
||||
rustc_middle::mir::interpret::struct_error(
|
||||
self.tcx.at(span),
|
||||
"runtime values cannot be referenced in patterns",
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(NonConstPath { span });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn span_e0158(&self, span: Span, text: &str) {
|
||||
struct_span_err!(self.tcx.sess, span, E0158, "{}", text).emit();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
||||
@ -345,29 +341,6 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
||||
);
|
||||
return true;
|
||||
}
|
||||
let lint_affix = |affix: &[Option<(Span, bool)>], kind, suggestion| {
|
||||
let span_start = affix[0].unwrap().0;
|
||||
let span_end = affix.last().unwrap().unwrap().0;
|
||||
let span = span_start.to(span_end);
|
||||
let cnt = affix.len();
|
||||
let s = pluralize!(cnt);
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
IRREFUTABLE_LET_PATTERNS,
|
||||
top,
|
||||
span,
|
||||
format!("{kind} irrefutable pattern{s} in let chain"),
|
||||
|lint| {
|
||||
lint.note(format!(
|
||||
"{these} pattern{s} will always match",
|
||||
these = pluralize!("this", cnt),
|
||||
))
|
||||
.help(format!(
|
||||
"consider moving {} {suggestion}",
|
||||
if cnt > 1 { "them" } else { "it" }
|
||||
))
|
||||
},
|
||||
);
|
||||
};
|
||||
if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
|
||||
// The chain has a non-zero prefix of irrefutable `let` statements.
|
||||
|
||||
@ -381,13 +354,21 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
|
||||
if !matches!(let_source, LetSource::WhileLet | LetSource::IfLetGuard) {
|
||||
// Emit the lint
|
||||
let prefix = &chain_refutabilities[..until];
|
||||
lint_affix(prefix, "leading", "outside of the construct");
|
||||
let span_start = prefix[0].unwrap().0;
|
||||
let span_end = prefix.last().unwrap().unwrap().0;
|
||||
let span = span_start.to(span_end);
|
||||
let count = prefix.len();
|
||||
cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, LeadingIrrefutableLetPatterns { count });
|
||||
}
|
||||
}
|
||||
if let Some(from) = chain_refutabilities.iter().rposition(|r| !matches!(*r, Some((_, false)))) && from != (chain_refutabilities.len() - 1) {
|
||||
// The chain has a non-empty suffix of irrefutable `let` statements
|
||||
let suffix = &chain_refutabilities[from + 1..];
|
||||
lint_affix(suffix, "trailing", "into the body");
|
||||
let span_start = suffix[0].unwrap().0;
|
||||
let span_end = suffix.last().unwrap().unwrap().0;
|
||||
let span = span_start.to(span_end);
|
||||
let count = suffix.len();
|
||||
cx.tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, top, span, TrailingIrrefutableLetPatterns { count });
|
||||
}
|
||||
true
|
||||
}
|
||||
@ -568,32 +549,22 @@ fn check_for_bindings_named_same_as_variants(
|
||||
})
|
||||
{
|
||||
let variant_count = edef.variants().len();
|
||||
cx.tcx.struct_span_lint_hir(
|
||||
let ty_path = with_no_trimmed_paths!({
|
||||
cx.tcx.def_path_str(edef.did())
|
||||
});
|
||||
cx.tcx.emit_spanned_lint(
|
||||
BINDINGS_WITH_VARIANT_NAME,
|
||||
p.hir_id,
|
||||
p.span,
|
||||
DelayDm(|| format!(
|
||||
"pattern binding `{}` is named the same as one \
|
||||
of the variants of the type `{}`",
|
||||
ident, cx.tcx.def_path_str(edef.did())
|
||||
)),
|
||||
|lint| {
|
||||
let ty_path = cx.tcx.def_path_str(edef.did());
|
||||
lint.code(error_code!(E0170));
|
||||
|
||||
BindingsWithVariantName {
|
||||
// If this is an irrefutable pattern, and there's > 1 variant,
|
||||
// then we can't actually match on this. Applying the below
|
||||
// suggestion would produce code that breaks on `check_irrefutable`.
|
||||
if rf == Refutable || variant_count == 1 {
|
||||
lint.span_suggestion(
|
||||
p.span,
|
||||
"to match on the variant, qualify the path",
|
||||
format!("{}::{}", ty_path, ident),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
|
||||
lint
|
||||
suggestion: if rf == Refutable || variant_count == 1 {
|
||||
Some(p.span)
|
||||
} else { None },
|
||||
ty_path,
|
||||
ident,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -611,14 +582,12 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
|
||||
}
|
||||
|
||||
fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
|
||||
tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
|
||||
if let Some(catchall) = catchall {
|
||||
// We had a catchall pattern, hint at that.
|
||||
lint.span_label(span, "unreachable pattern");
|
||||
lint.span_label(catchall, "matches any value");
|
||||
}
|
||||
lint
|
||||
});
|
||||
tcx.emit_spanned_lint(
|
||||
UNREACHABLE_PATTERNS,
|
||||
id,
|
||||
span,
|
||||
UnreachablePattern { span: if catchall.is_some() { Some(span) } else { None }, catchall },
|
||||
);
|
||||
}
|
||||
|
||||
fn irrefutable_let_pattern(tcx: TyCtxt<'_>, id: HirId, span: Span) {
|
||||
@ -634,67 +603,18 @@ fn irrefutable_let_patterns(
|
||||
span: Span,
|
||||
) {
|
||||
macro_rules! emit_diag {
|
||||
(
|
||||
$lint:expr,
|
||||
$source_name:expr,
|
||||
$note_sufix:expr,
|
||||
$help_sufix:expr
|
||||
) => {{
|
||||
let s = pluralize!(count);
|
||||
let these = pluralize!("this", count);
|
||||
tcx.struct_span_lint_hir(
|
||||
IRREFUTABLE_LET_PATTERNS,
|
||||
id,
|
||||
span,
|
||||
format!("irrefutable {} pattern{s}", $source_name),
|
||||
|lint| {
|
||||
lint.note(&format!(
|
||||
"{these} pattern{s} will always match, so the {}",
|
||||
$note_sufix
|
||||
))
|
||||
.help(concat!("consider ", $help_sufix))
|
||||
},
|
||||
)
|
||||
($lint:tt) => {{
|
||||
tcx.emit_spanned_lint(IRREFUTABLE_LET_PATTERNS, id, span, $lint { count });
|
||||
}};
|
||||
}
|
||||
|
||||
match source {
|
||||
LetSource::GenericLet => {
|
||||
emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
|
||||
}
|
||||
LetSource::IfLet => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`if let`",
|
||||
"`if let` is useless",
|
||||
"replacing the `if let` with a `let`"
|
||||
);
|
||||
}
|
||||
LetSource::IfLetGuard => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`if let` guard",
|
||||
"guard is useless",
|
||||
"removing the guard and adding a `let` inside the match arm"
|
||||
);
|
||||
}
|
||||
LetSource::LetElse => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`let...else`",
|
||||
"`else` clause is useless",
|
||||
"removing the `else` clause"
|
||||
);
|
||||
}
|
||||
LetSource::WhileLet => {
|
||||
emit_diag!(
|
||||
lint,
|
||||
"`while let`",
|
||||
"loop will never exit",
|
||||
"instead using a `loop { ... }` with a `let` inside it"
|
||||
);
|
||||
}
|
||||
};
|
||||
LetSource::GenericLet => emit_diag!(IrrefutableLetPatternsGenericLet),
|
||||
LetSource::IfLet => emit_diag!(IrrefutableLetPatternsIfLet),
|
||||
LetSource::IfLetGuard => emit_diag!(IrrefutableLetPatternsIfLetGuard),
|
||||
LetSource::LetElse => emit_diag!(IrrefutableLetPatternsLetElse),
|
||||
LetSource::WhileLet => emit_diag!(IrrefutableLetPatternsWhileLet),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_let_irrefutable<'p, 'tcx>(
|
||||
@ -760,15 +680,17 @@ fn non_exhaustive_match<'p, 'tcx>(
|
||||
// informative.
|
||||
let mut err;
|
||||
let pattern;
|
||||
let mut patterns_len = 0;
|
||||
let patterns_len;
|
||||
if is_empty_match && !non_empty_enum {
|
||||
err = create_e0004(
|
||||
cx.tcx.sess,
|
||||
sp,
|
||||
format!("non-exhaustive patterns: type `{}` is non-empty", scrut_ty),
|
||||
);
|
||||
pattern = "_".to_string();
|
||||
cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
|
||||
cx,
|
||||
expr_span,
|
||||
span: sp,
|
||||
ty: scrut_ty,
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// FIXME: migration of this diagnostic will require list support
|
||||
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
|
||||
err = create_e0004(
|
||||
cx.tcx.sess,
|
||||
@ -1039,24 +961,17 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
|
||||
}
|
||||
});
|
||||
if !conflicts_ref.is_empty() {
|
||||
let occurs_because = format!(
|
||||
"move occurs because `{}` has type `{}` which does not implement the `Copy` trait",
|
||||
sess.emit_err(BorrowOfMovedValue {
|
||||
span: pat.span,
|
||||
binding_span,
|
||||
conflicts_ref,
|
||||
name,
|
||||
typeck_results.node_type(pat.hir_id),
|
||||
);
|
||||
let mut err = sess.struct_span_err(pat.span, "borrow of moved value");
|
||||
err.span_label(binding_span, format!("value moved into `{}` here", name))
|
||||
.span_label(binding_span, occurs_because)
|
||||
.span_labels(conflicts_ref, "value borrowed here after move");
|
||||
if pat.span.contains(binding_span) {
|
||||
err.span_suggestion_verbose(
|
||||
binding_span.shrink_to_lo(),
|
||||
"borrow this binding in the pattern to avoid moving the value",
|
||||
"ref ".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
ty: typeck_results.node_type(pat.hir_id),
|
||||
suggest_borrowing: pat
|
||||
.span
|
||||
.contains(binding_span)
|
||||
.then(|| binding_span.shrink_to_lo()),
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1086,19 +1001,18 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
|
||||
// Report errors if any.
|
||||
if !conflicts_mut_mut.is_empty() {
|
||||
// Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
|
||||
let mut err = sess
|
||||
.struct_span_err(pat.span, "cannot borrow value as mutable more than once at a time");
|
||||
err.span_label(binding_span, format!("first mutable borrow, by `{}`, occurs here", name));
|
||||
for (span, name) in conflicts_mut_mut {
|
||||
err.span_label(span, format!("another mutable borrow, by `{}`, occurs here", name));
|
||||
let mut occurences = vec![];
|
||||
|
||||
for (span, name_mut) in conflicts_mut_mut {
|
||||
occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
|
||||
}
|
||||
for (span, name) in conflicts_mut_ref {
|
||||
err.span_label(span, format!("also borrowed as immutable, by `{}`, here", name));
|
||||
for (span, name_immut) in conflicts_mut_ref {
|
||||
occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
|
||||
}
|
||||
for (span, name) in conflicts_move {
|
||||
err.span_label(span, format!("also moved into `{}` here", name));
|
||||
for (span, name_moved) in conflicts_move {
|
||||
occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
|
||||
}
|
||||
err.emit();
|
||||
sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
|
||||
} else if !conflicts_mut_ref.is_empty() {
|
||||
// Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
|
||||
let (primary, also) = match mut_outer {
|
||||
|
@ -6,10 +6,12 @@ mod deconstruct_pat;
|
||||
mod usefulness;
|
||||
|
||||
pub(crate) use self::check_match::check_match;
|
||||
pub(crate) use self::usefulness::MatchCheckCtxt;
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::thir::util::UserAnnotatedTyHelpers;
|
||||
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_errors::error_code;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
@ -139,13 +141,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
// `x..y` where `x >= y`. The range is empty => error.
|
||||
(RangeEnd::Excluded, _) => {
|
||||
struct_span_err!(
|
||||
self.tcx.sess,
|
||||
span,
|
||||
E0579,
|
||||
"lower range bound must be less than upper"
|
||||
)
|
||||
.emit();
|
||||
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span });
|
||||
PatKind::Wild
|
||||
}
|
||||
// `x..=y` where `x == y`.
|
||||
@ -156,23 +152,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
// `x..=y` where `x > y` hence the range is empty => error.
|
||||
(RangeEnd::Included, _) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess,
|
||||
self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
|
||||
span,
|
||||
E0030,
|
||||
"lower range bound must be less than or equal to upper"
|
||||
);
|
||||
err.span_label(span, "lower bound larger than upper bound");
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"When matching against a range, the compiler \
|
||||
verifies that the range is non-empty. Range \
|
||||
patterns include both end-points, so this is \
|
||||
equivalent to requiring the start of the range \
|
||||
to be less than or equal to the end of the range.",
|
||||
);
|
||||
}
|
||||
err.emit();
|
||||
teach: if self.tcx.sess.teach(&error_code!(E0030)) { Some(()) } else { None },
|
||||
});
|
||||
PatKind::Wild
|
||||
}
|
||||
}
|
||||
@ -501,7 +484,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
}
|
||||
|
||||
Err(_) => {
|
||||
self.tcx.sess.span_err(span, "could not evaluate constant pattern");
|
||||
self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
return pat_from_kind(PatKind::Wild);
|
||||
}
|
||||
};
|
||||
@ -548,11 +531,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
Err(ErrorHandled::TooGeneric) => {
|
||||
// While `Reported | Linted` cases will have diagnostics emitted already
|
||||
// it is not true for TooGeneric case, so we need to give user more information.
|
||||
self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
pat_from_kind(PatKind::Wild)
|
||||
}
|
||||
Err(_) => {
|
||||
self.tcx.sess.span_err(span, "could not evaluate constant pattern");
|
||||
self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
|
||||
pat_from_kind(PatKind::Wild)
|
||||
}
|
||||
}
|
||||
@ -584,7 +567,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind,
|
||||
mir::ConstantKind::Unevaluated(..) => {
|
||||
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||
self.tcx.sess.span_err(span, "constant pattern depends on a generic parameter");
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
return PatKind::Wild;
|
||||
}
|
||||
}
|
||||
|
@ -20,19 +20,19 @@ fn main() {
|
||||
|
||||
match foo::Foo::Foo {
|
||||
Foo => {}
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
}
|
||||
|
||||
let Foo = foo::Foo::Foo;
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
|
||||
fn in_param(Foo: foo::Foo) {}
|
||||
//~^ ERROR variable `Foo` should have a snake case name
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo`
|
||||
//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
//~^^^ WARN unused variable: `Foo`
|
||||
|
||||
test(1);
|
||||
|
@ -1,22 +1,22 @@
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:22:9
|
||||
|
|
||||
LL | Foo => {}
|
||||
| ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
|
||||
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
|
||||
|
|
||||
= note: `#[warn(bindings_with_variant_name)]` on by default
|
||||
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:28:9
|
||||
|
|
||||
LL | let Foo = foo::Foo::Foo;
|
||||
| ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
|
||||
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
|
||||
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo`
|
||||
warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:33:17
|
||||
|
|
||||
LL | fn in_param(Foo: foo::Foo) {}
|
||||
| ^^^ help: to match on the variant, qualify the path: `Foo::Foo`
|
||||
| ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo`
|
||||
|
||||
warning: unused variable: `Foo`
|
||||
--> $DIR/lint-uppercase-variables.rs:22:9
|
||||
|
Loading…
Reference in New Issue
Block a user