diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7b27049a579a1..fc49508a6803e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -644,8 +644,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ through unstable paths" ), rustc_attr!( - rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, + rustc_deprecated_safe_2024, Normal, template!(List: r#"todo = "...""#), + ErrorFollowing, EncodeCrossCrate::Yes, "rustc_deprecated_safe_2024 is supposed to be used in libstd only", ), diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 0c277811fdacf..3ec8ba8ca39c7 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -32,7 +32,7 @@ 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 + .suggestion = you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions mir_build_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a65586ccdb7e7..ab22956b9a926 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,6 +1,7 @@ use crate::build::ExprCategory; use crate::errors::*; +use rustc_ast::Attribute; use rustc_errors::DiagArgValue; use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; @@ -90,6 +91,19 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool { + fn parse_rustc_deprecated_safe_2024_attr(attr: &Attribute) -> Option { + for item in attr.meta_item_list().unwrap_or_default() { + if item.has_name(sym::todo) { + return Some( + item.value_str().expect( + "`#[rustc_deprecated_safe_2024(todo)]` must have a string value", + ), + ); + } + } + None + } + match kind { // Allow calls to deprecated-safe unsafe functions if the caller is // from an edition before 2024. @@ -97,7 +111,17 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { if !span.at_least_rust_2024() && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => { + let attr = self.tcx.get_attr(id, sym::rustc_deprecated_safe_2024).unwrap(); + let suggestion = parse_rustc_deprecated_safe_2024_attr(attr); + let sm = self.tcx.sess.source_map(); + let suggestion = suggestion + .and_then(|suggestion| { + sm.indentation_before(span) + .map(|indent| format!("{}// TODO: {}\n", indent, suggestion)) + }) + .unwrap_or_default(); + self.tcx.emit_node_span_lint( DEPRECATED_SAFE, self.hir_context, @@ -106,7 +130,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { span, function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), sub: CallToDeprecatedSafeFnRequiresUnsafeSub { - indent: sm.indentation_before(span).unwrap_or_default(), + start_of_line_suggestion: suggestion, start_of_line: sm.span_extend_to_line(span).shrink_to_lo(), left: span.shrink_to_lo(), right: span.shrink_to_hi(), diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 7c73d8a6d47d4..f3c58d62d31c8 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -33,10 +33,8 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[derive(Subdiagnostic)] #[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { - pub(crate) indent: String, - #[suggestion_part( - code = "{indent}// TODO: Audit that the environment access only happens in single-threaded code.\n" // ignore-tidy-todo - )] + pub(crate) start_of_line_suggestion: String, + #[suggestion_part(code = "{start_of_line_suggestion}")] pub(crate) start_of_line: Span, #[suggestion_part(code = "unsafe {{ ")] pub(crate) left: Span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2fe7c951793f7..212f2819e4b6b 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1888,6 +1888,7 @@ symbols! { to_string, to_string_method, to_vec, + todo, todo_macro, tool_attributes, tool_lints, diff --git a/library/std/src/env.rs b/library/std/src/env.rs index fc9b8cfd46d65..53a291dca4e1b 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -357,7 +357,13 @@ impl Error for VarError { /// } /// assert_eq!(env::var(key), Ok("VALUE".to_string())); /// ``` -#[rustc_deprecated_safe_2024] +#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] +#[cfg_attr( + not(bootstrap), + rustc_deprecated_safe_2024( + todo = "Audit that the environment access only happens in single-threaded code." + ) +)] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { let (key, value) = (key.as_ref(), value.as_ref()); @@ -421,7 +427,13 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { /// } /// assert!(env::var(key).is_err()); /// ``` -#[rustc_deprecated_safe_2024] +#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] +#[cfg_attr( + not(bootstrap), + rustc_deprecated_safe_2024( + todo = "Audit that the environment access only happens in single-threaded code." + ) +)] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { let key = key.as_ref();