Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,11 @@ pub fn parse_cfg_entry(
Some(sym::target) => parse_cfg_entry_target(cx, list, meta.span())?,
Some(sym::version) => parse_cfg_entry_version(cx, list, meta.span())?,
_ => {
return Err(cx.emit_err(session_diagnostics::InvalidPredicate {
span: meta.span(),
predicate: meta.path().to_string(),
}));
let mut possibilities = vec![sym::any, sym::all, sym::not, sym::target];
if cx.features().cfg_version() {
possibilities.push(sym::version);
}
return Err(cx.adcx().expected_specific_argument(meta.span(), &possibilities));
}
},
a @ (ArgParser::NoArgs | ArgParser::NameValue(_)) => {
Expand Down
20 changes: 16 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,10 @@ pub(crate) struct ExportNameParser;
impl SingleAttributeParser for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
unsafe_since: Some(Edition2024),
};
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Static),
Allow(Target::Fn),
Expand Down Expand Up @@ -217,7 +220,10 @@ impl AttributeParser for NakedParser {
this.span = Some(cx.attr_span);
}
})];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "the `#[naked]` attribute adds the safety obligation that the function's body must respect the function’s calling convention, uphold its signature, and either return or diverge (i.e., not fall through past the end of the assembly code).",
unsafe_since: None,
};
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Expand Down Expand Up @@ -347,7 +353,10 @@ pub(crate) struct NoMangleParser;
impl NoArgsAttributeParser for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
unsafe_since: Some(Edition2024),
};
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Static),
Expand Down Expand Up @@ -540,7 +549,10 @@ pub(crate) struct ForceTargetFeatureParser;
impl CombineAttributeParser for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "a function with the signature of the function the attribute is applied to must only be callable if the force-enabled features are guaranteed to be present",
unsafe_since: None,
};
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
Expand Down
15 changes: 12 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,10 @@ fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReaso
impl SingleAttributeParser for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them",
unsafe_since: Some(Edition2024),
};
const STABILITY: AttributeStability = AttributeStability::Stable;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Static),
Expand Down Expand Up @@ -540,7 +543,10 @@ impl NoArgsAttributeParser for ExportStableParser {
pub(crate) struct FfiConstParser;
impl NoArgsAttributeParser for FfiConstParser {
const PATH: &[Symbol] = &[sym::ffi_const];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "`#[ffi_const]` functions shall have no effects except for its return value, which can only depend on the values of the function parameters, and is not affected by changes to the observable state of the program.",
unsafe_since: None,
};
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const STABILITY: AttributeStability = unstable!(ffi_const);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::FfiConst;
Expand All @@ -549,7 +555,10 @@ impl NoArgsAttributeParser for FfiConstParser {
pub(crate) struct FfiPureParser;
impl NoArgsAttributeParser for FfiPureParser {
const PATH: &[Symbol] = &[sym::ffi_pure];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
note: "`#[ffi_pure]` functions shall have no effects except for its return value, which shall not change across two consecutive function calls with the same parameters.",
unsafe_since: None,
};
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const STABILITY: AttributeStability = unstable!(ffi_pure);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,11 @@ pub enum AttributeSafety {
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
/// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
/// earlier editions, but become unsafe in later ones.
Unsafe { unsafe_since: Option<Edition> },
Unsafe {
/// The `note` is emitted during the `unsafe_code`, and explains to the user why this attribute is unsafe.
note: &'static str,
unsafe_since: Option<Edition>,
},
}

/// An even simpler version of [`SingleAttributeParser`]:
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -826,3 +826,11 @@ pub(crate) enum InvalidOnClause {
"using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported"
)]
pub(crate) struct DupesNotAllowed;

#[derive(Diagnostic)]
#[diag("usage of the unsafe `#[{$attr_path}]` attribute")]
#[note("{$note}")]
pub(crate) struct UnsafeAttribute {
pub attr_path: AttrPath,
pub note: &'static str,
}
16 changes: 15 additions & 1 deletion compiler/rustc_attr_parsing/src/safety.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use rustc_ast::Safety;
use rustc_errors::{Diagnostic, MultiSpan};
use rustc_hir::AttrPath;
use rustc_lint_defs::builtin::UNSAFE_CODE;
use rustc_session::lint::LintId;
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
use rustc_span::Span;
Expand All @@ -21,6 +22,7 @@ impl<'sess> AttributeParser<'sess> {
return;
}

// Check if expected & actual safety match
match (expected_safety, attr_safety) {
// - Unsafe builtin attribute
// - User wrote `#[unsafe(..)]`, which is permitted on any edition
Expand All @@ -30,7 +32,7 @@ impl<'sess> AttributeParser<'sess> {

// - Unsafe builtin attribute
// - User did not write `#[unsafe(..)]`
(AttributeSafety::Unsafe { unsafe_since }, Safety::Default) => {
(AttributeSafety::Unsafe { unsafe_since, note: _ }, Safety::Default) => {
let path_span = attr_path.span;

// If the `attr_item`'s span is not from a macro, then just suggest
Expand Down Expand Up @@ -112,5 +114,17 @@ impl<'sess> AttributeParser<'sess> {
);
}
}

// Emit `unsafe_code` lint
if let AttributeSafety::Unsafe { note, .. } = expected_safety {
let attr_path = attr_path.clone();
emit_lint(
LintId::of(UNSAFE_CODE),
attr_span.into(),
EmitAttribute(Box::new(move |dcx, level, _| {
diagnostics::UnsafeAttribute { attr_path, note }.into_diag(dcx, level)
})),
)
}
}
}
9 changes: 0 additions & 9 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@ use rustc_target::spec::TargetTuple;
use crate::AttributeTemplate;
use crate::context::Suggestion;

#[derive(Diagnostic)]
#[diag("invalid predicate `{$predicate}`", code = E0537)]
pub(crate) struct InvalidPredicate {
#[primary_span]
pub span: Span,

pub predicate: String,
}

#[derive(Diagnostic)]
#[diag("{$attr_str} attribute cannot have empty value")]
pub(crate) struct DocAliasEmpty<'a> {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_error_codes/src/error_codes/E0537.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#### Note: this error code is no longer emitted by the compiler
An unknown predicate was used inside the `cfg` attribute.

Erroneous code example:

```compile_fail,E0537
```compile_fail,E0539
#[cfg(unknown())] // error: invalid predicate `unknown`
pub fn something() {}

Expand Down
79 changes: 0 additions & 79 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,46 +189,6 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
}
}

declare_lint! {
/// The `unsafe_code` lint catches usage of `unsafe` code and other
/// potentially unsound constructs like `no_mangle`, `export_name`,
/// and `link_section`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unsafe_code)]
/// fn main() {
/// unsafe {
///
/// }
/// }
///
/// #[no_mangle]
/// fn func_0() { }
///
/// #[export_name = "exported_symbol_name"]
/// pub fn name_in_rust() { }
///
/// #[no_mangle]
/// #[link_section = ".example_section"]
/// pub static VAR1: u32 = 1;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is intended to restrict the usage of `unsafe` blocks and other
/// constructs (including, but not limited to `no_mangle`, `link_section`
/// and `export_name` attributes) wrong usage of which causes undefined
/// behavior.
UNSAFE_CODE,
Allow,
"usage of `unsafe` code and other potentially unsound constructs",
@eval_always = true
}

declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]);

impl UnsafeCode {
Expand Down Expand Up @@ -271,34 +231,6 @@ impl EarlyLintPass for UnsafeCode {
self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
}

ast::ItemKind::Fn(..) => {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleFn);
}

if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameFn);
}

if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionFn);
}
}

ast::ItemKind::Static(..) => {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleStatic);
}

if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameStatic);
}

if let Some(attr) = attr::find_by_name(&it.attrs, sym::link_section) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::LinkSectionStatic);
}
}

ast::ItemKind::GlobalAsm(..) => {
self.report_unsafe(cx, it.span, BuiltinUnsafe::GlobalAsm);
}
Expand All @@ -325,17 +257,6 @@ impl EarlyLintPass for UnsafeCode {
}
}

fn check_impl_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
if let ast::AssocItemKind::Fn(..) = it.kind {
if let Some(attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::NoMangleMethod);
}
if let Some(attr) = attr::find_by_name(&it.attrs, sym::export_name) {
self.report_unsafe(cx, attr.span, BuiltinUnsafe::ExportNameMethod);
}
}
}

fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast::NodeId) {
if let FnKind::Fn(
ctxt,
Expand Down
40 changes: 0 additions & 40 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,46 +160,6 @@ pub(crate) enum BuiltinUnsafe {
UnsafeTrait,
#[diag("implementation of an `unsafe` trait")]
UnsafeImpl,
#[diag("declaration of a `no_mangle` function")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
NoMangleFn,
#[diag("declaration of a function with `export_name`")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
ExportNameFn,
#[diag("declaration of a function with `link_section`")]
#[note(
"the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them"
)]
LinkSectionFn,
#[diag("declaration of a `no_mangle` static")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
NoMangleStatic,
#[diag("declaration of a static with `export_name`")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
ExportNameStatic,
#[diag("declaration of a static with `link_section`")]
#[note(
"the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them"
)]
LinkSectionStatic,
#[diag("declaration of a `no_mangle` method")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
NoMangleMethod,
#[diag("declaration of a method with `export_name`")]
#[note(
"the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them"
)]
ExportNameMethod,
#[diag("declaration of an `unsafe` function")]
DeclUnsafeFn,
#[diag("declaration of an `unsafe` method")]
Expand Down
40 changes: 40 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5513,3 +5513,43 @@ declare_lint! {
report_in_deps: false,
};
}

declare_lint! {
/// The `unsafe_code` lint catches usage of `unsafe` code and other
/// potentially unsound constructs like `no_mangle`, `export_name`,
/// and `link_section`.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unsafe_code)]
/// fn main() {
/// unsafe {
///
/// }
/// }
///
/// #[no_mangle]
/// fn func_0() { }
///
/// #[export_name = "exported_symbol_name"]
/// pub fn name_in_rust() { }
///
/// #[no_mangle]
/// #[link_section = ".example_section"]
/// pub static VAR1: u32 = 1;
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This lint is intended to restrict the usage of `unsafe` blocks and other
/// constructs (including, but not limited to `no_mangle`, `link_section`
/// and `export_name` attributes) wrong usage of which causes undefined
/// behavior.
pub UNSAFE_CODE,
Allow,
"usage of `unsafe` code and other potentially unsound constructs",
@eval_always = true
}
5 changes: 2 additions & 3 deletions src/librustdoc/passes/strip_aliased_non_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,8 @@ impl DocFolder for NonLocalStripper<'_> {
// FIXME(#125009): Not-local should probably consider same Cargo workspace
if let Some(def_id) = i.def_id()
&& !def_id.is_local()
&& (i.is_doc_hidden()
// Default to *not* stripping items with inherited visibility.
|| i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public))
// Default to *not* stripping items with inherited visibility.
&& i.visibility(self.tcx).is_some_and(|viz| viz != Visibility::Public)
{
return Some(strip_item(i));
}
Expand Down
Loading
Loading