Add deprecated_safe
lint
It warns about usages of `std::env::{set_var, remove_var}` with an automatic fix wrapping the call in an `unsafe` block.
This commit is contained in:
parent
d7680e3556
commit
44f9f8bc33
10 changed files with 172 additions and 11 deletions
|
@ -37,6 +37,7 @@ declare_lint_pass! {
|
||||||
DEPRECATED,
|
DEPRECATED,
|
||||||
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
|
||||||
DEPRECATED_IN_FUTURE,
|
DEPRECATED_IN_FUTURE,
|
||||||
|
DEPRECATED_SAFE,
|
||||||
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
DEPRECATED_WHERE_CLAUSE_LOCATION,
|
||||||
DUPLICATE_MACRO_ATTRIBUTES,
|
DUPLICATE_MACRO_ATTRIBUTES,
|
||||||
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
|
||||||
|
@ -4844,3 +4845,51 @@ declare_lint! {
|
||||||
reference: "issue #124559 <https://github.com/rust-lang/rust/issues/124559>",
|
reference: "issue #124559 <https://github.com/rust-lang/rust/issues/124559>",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `deprecated_safe` lint detects unsafe functions being used as safe
|
||||||
|
/// functions.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,edition2021,compile_fail
|
||||||
|
/// #![deny(deprecated_safe)]
|
||||||
|
/// // edition 2021
|
||||||
|
/// use std::env;
|
||||||
|
/// fn enable_backtrace() {
|
||||||
|
/// env::set_var("RUST_BACKTRACE", "1");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Rust [editions] allow the language to evolve without breaking backward
|
||||||
|
/// compatibility. This lint catches code that uses `unsafe` functions that
|
||||||
|
/// were declared as safe (non-`unsafe`) in earlier editions. If you switch
|
||||||
|
/// the compiler to a new edition without updating the code, then it
|
||||||
|
/// will fail to compile if you are using a function previously marked as
|
||||||
|
/// safe.
|
||||||
|
///
|
||||||
|
/// You can audit the code to see if it suffices the preconditions of the
|
||||||
|
/// `unsafe` code, and if it does, you can wrap it in an `unsafe` block. If
|
||||||
|
/// you can't fulfill the preconditions, you probably need to switch to a
|
||||||
|
/// different way of doing what you want to achieve.
|
||||||
|
///
|
||||||
|
/// This lint can automatically wrap the calls in `unsafe` blocks, but this
|
||||||
|
/// obviously cannot verify that the preconditions of the `unsafe`
|
||||||
|
/// functions are fulfilled, so that is still up to the user.
|
||||||
|
///
|
||||||
|
/// The lint is currently "allow" by default, but that might change in the
|
||||||
|
/// future.
|
||||||
|
///
|
||||||
|
/// [editions]: https://doc.rust-lang.org/edition-guide/
|
||||||
|
pub DEPRECATED_SAFE,
|
||||||
|
Allow,
|
||||||
|
"detects unsafe functions being used as safe functions",
|
||||||
|
@future_incompatible = FutureIncompatibleInfo {
|
||||||
|
reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
|
||||||
|
reference: "issue #27970 <https://github.com/rust-lang/rust/issues/27970>",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,12 @@ mir_build_borrow_of_moved_value = borrow of moved value
|
||||||
.value_borrowed_label = value borrowed here after move
|
.value_borrowed_label = value borrowed here after move
|
||||||
.suggestion = borrow this binding in the pattern to avoid moving the value
|
.suggestion = borrow this binding in the pattern to avoid moving the value
|
||||||
|
|
||||||
|
mir_build_call_to_deprecated_safe_fn_requires_unsafe =
|
||||||
|
call to deprecated safe 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
|
||||||
|
.suggestion = you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code
|
||||||
|
|
||||||
mir_build_call_to_fn_with_requires_unsafe =
|
mir_build_call_to_fn_with_requires_unsafe =
|
||||||
call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
|
call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
|
||||||
.help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count ->
|
.help = in order for the call to be safe, the context requires the following additional target {$missing_target_features_count ->
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::thir::visit::Visitor;
|
||||||
use rustc_middle::thir::*;
|
use rustc_middle::thir::*;
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
|
||||||
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
|
use rustc_session::lint::builtin::{DEPRECATED_SAFE, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
|
||||||
use rustc_session::lint::Level;
|
use rustc_session::lint::Level;
|
||||||
use rustc_span::def_id::{DefId, LocalDefId};
|
use rustc_span::def_id::{DefId, LocalDefId};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
|
@ -115,7 +115,22 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
|
||||||
// caller is from an edition before 2024.
|
// caller is from an edition before 2024.
|
||||||
UnsafeOpKind::CallToUnsafeFunction(Some(id))
|
UnsafeOpKind::CallToUnsafeFunction(Some(id))
|
||||||
if !span.at_least_rust_2024()
|
if !span.at_least_rust_2024()
|
||||||
&& self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => {}
|
&& self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) =>
|
||||||
|
{
|
||||||
|
self.tcx.emit_node_span_lint(
|
||||||
|
DEPRECATED_SAFE,
|
||||||
|
self.hir_context,
|
||||||
|
span,
|
||||||
|
CallToDeprecatedSafeFnRequiresUnsafe {
|
||||||
|
span,
|
||||||
|
function: with_no_trimmed_paths!(self.tcx.def_path_str(id)),
|
||||||
|
sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
|
||||||
|
left: span.shrink_to_lo(),
|
||||||
|
right: span.shrink_to_hi(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
_ => kind.emit_requires_unsafe_err(
|
_ => kind.emit_requires_unsafe_err(
|
||||||
self.tcx,
|
self.tcx,
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -20,6 +20,25 @@ pub struct UnconditionalRecursion {
|
||||||
pub call_sites: Vec<Span>,
|
pub call_sites: Vec<Span>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)]
|
||||||
|
pub struct CallToDeprecatedSafeFnRequiresUnsafe {
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub function: String,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sub: CallToDeprecatedSafeFnRequiresUnsafeSub,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")]
|
||||||
|
pub struct CallToDeprecatedSafeFnRequiresUnsafeSub {
|
||||||
|
#[suggestion_part(code = "unsafe {{ ")]
|
||||||
|
pub left: Span,
|
||||||
|
#[suggestion_part(code = " }}")]
|
||||||
|
pub right: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe, code = E0133)]
|
#[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe, code = E0133)]
|
||||||
#[note]
|
#[note]
|
||||||
|
|
20
tests/ui/rust-2024/unsafe-env-suggestion.fixed
Normal file
20
tests/ui/rust-2024/unsafe-env-suggestion.fixed
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
#![deny(deprecated_safe)]
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[deny(unused_unsafe)]
|
||||||
|
fn main() {
|
||||||
|
unsafe { env::set_var("FOO", "BAR") };
|
||||||
|
//~^ ERROR call to deprecated safe function
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
unsafe { env::remove_var("FOO") };
|
||||||
|
//~^ ERROR call to deprecated safe function
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
env::set_var("FOO", "BAR");
|
||||||
|
env::remove_var("FOO");
|
||||||
|
}
|
||||||
|
}
|
20
tests/ui/rust-2024/unsafe-env-suggestion.rs
Normal file
20
tests/ui/rust-2024/unsafe-env-suggestion.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//@ run-rustfix
|
||||||
|
|
||||||
|
#![deny(deprecated_safe)]
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[deny(unused_unsafe)]
|
||||||
|
fn main() {
|
||||||
|
env::set_var("FOO", "BAR");
|
||||||
|
//~^ ERROR call to deprecated safe function
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
env::remove_var("FOO");
|
||||||
|
//~^ ERROR call to deprecated safe function
|
||||||
|
//~| WARN this is accepted in the current edition
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
env::set_var("FOO", "BAR");
|
||||||
|
env::remove_var("FOO");
|
||||||
|
}
|
||||||
|
}
|
33
tests/ui/rust-2024/unsafe-env-suggestion.stderr
Normal file
33
tests/ui/rust-2024/unsafe-env-suggestion.stderr
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
error: call to deprecated safe function `std::env::set_var` is unsafe and requires unsafe block
|
||||||
|
--> $DIR/unsafe-env-suggestion.rs:9:5
|
||||||
|
|
|
||||||
|
LL | env::set_var("FOO", "BAR");
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #27970 <https://github.com/rust-lang/rust/issues/27970>
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unsafe-env-suggestion.rs:3:9
|
||||||
|
|
|
||||||
|
LL | #![deny(deprecated_safe)]
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code
|
||||||
|
|
|
||||||
|
LL | unsafe { env::set_var("FOO", "BAR") };
|
||||||
|
| ++++++++ +
|
||||||
|
|
||||||
|
error: call to deprecated safe function `std::env::remove_var` is unsafe and requires unsafe block
|
||||||
|
--> $DIR/unsafe-env-suggestion.rs:12:5
|
||||||
|
|
|
||||||
|
LL | env::remove_var("FOO");
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
|
|
||||||
|
= warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
|
||||||
|
= note: for more information, see issue #27970 <https://github.com/rust-lang/rust/issues/27970>
|
||||||
|
help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code
|
||||||
|
|
|
||||||
|
LL | unsafe { env::remove_var("FOO") };
|
||||||
|
| ++++++++ +
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe function or block
|
error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe function or block
|
||||||
--> $DIR/unsafe-env.rs:24:5
|
--> $DIR/unsafe-env.rs:23:5
|
||||||
|
|
|
|
||||||
LL | unsafe_fn();
|
LL | unsafe_fn();
|
||||||
| ^^^^^^^^^^^ call to unsafe function
|
| ^^^^^^^^^^^ call to unsafe function
|
||||||
|
@ -7,13 +7,13 @@ LL | unsafe_fn();
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error: unnecessary `unsafe` block
|
error: unnecessary `unsafe` block
|
||||||
--> $DIR/unsafe-env.rs:27:5
|
--> $DIR/unsafe-env.rs:26:5
|
||||||
|
|
|
|
||||||
LL | unsafe {
|
LL | unsafe {
|
||||||
| ^^^^^^ unnecessary `unsafe` block
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unsafe-env.rs:12:8
|
--> $DIR/unsafe-env.rs:11:8
|
||||||
|
|
|
|
||||||
LL | #[deny(unused_unsafe)]
|
LL | #[deny(unused_unsafe)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block
|
error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block
|
||||||
--> $DIR/unsafe-env.rs:14:5
|
--> $DIR/unsafe-env.rs:13:5
|
||||||
|
|
|
|
||||||
LL | env::set_var("FOO", "BAR");
|
LL | env::set_var("FOO", "BAR");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
@ -7,7 +7,7 @@ LL | env::set_var("FOO", "BAR");
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error[E0133]: call to unsafe function `remove_var` is unsafe and requires unsafe block
|
error[E0133]: call to unsafe function `remove_var` is unsafe and requires unsafe block
|
||||||
--> $DIR/unsafe-env.rs:16:5
|
--> $DIR/unsafe-env.rs:15:5
|
||||||
|
|
|
|
||||||
LL | env::remove_var("FOO");
|
LL | env::remove_var("FOO");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
| ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
||||||
|
@ -15,7 +15,7 @@ LL | env::remove_var("FOO");
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block
|
error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block
|
||||||
--> $DIR/unsafe-env.rs:24:5
|
--> $DIR/unsafe-env.rs:23:5
|
||||||
|
|
|
|
||||||
LL | unsafe_fn();
|
LL | unsafe_fn();
|
||||||
| ^^^^^^^^^^^ call to unsafe function
|
| ^^^^^^^^^^^ call to unsafe function
|
||||||
|
@ -23,13 +23,13 @@ LL | unsafe_fn();
|
||||||
= note: consult the function's documentation for information on how to avoid undefined behavior
|
= note: consult the function's documentation for information on how to avoid undefined behavior
|
||||||
|
|
||||||
error: unnecessary `unsafe` block
|
error: unnecessary `unsafe` block
|
||||||
--> $DIR/unsafe-env.rs:27:5
|
--> $DIR/unsafe-env.rs:26:5
|
||||||
|
|
|
|
||||||
LL | unsafe {
|
LL | unsafe {
|
||||||
| ^^^^^^ unnecessary `unsafe` block
|
| ^^^^^^ unnecessary `unsafe` block
|
||||||
|
|
|
|
||||||
note: the lint level is defined here
|
note: the lint level is defined here
|
||||||
--> $DIR/unsafe-env.rs:12:8
|
--> $DIR/unsafe-env.rs:11:8
|
||||||
|
|
|
|
||||||
LL | #[deny(unused_unsafe)]
|
LL | #[deny(unused_unsafe)]
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
//@[e2024] compile-flags: -Zunstable-options
|
//@[e2024] compile-flags: -Zunstable-options
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
unsafe fn unsafe_fn() {}
|
unsafe fn unsafe_fn() {}
|
||||||
fn safe_fn() {}
|
fn safe_fn() {}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue