Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7f53271
Suggest similar keyword when visibility is not followed by an item
FranciscoTGouveia Mar 29, 2026
b994a05
Fix pattern assignment suggestions for uninitialized bindings
chenyukang Apr 1, 2026
e70561b
Move some thin local LTO handling to start_executing_work
bjorn3 Feb 12, 2026
cee57cc
Handle lto_import_only_modules for fat LTO earlier
bjorn3 Feb 15, 2026
ed16e62
Introduce ThinLtoInput
bjorn3 Feb 13, 2026
f08aa80
Inline Linker type
bjorn3 Feb 24, 2026
3303a26
Slightly improve comment in produce_final_output_artifacts
bjorn3 Mar 3, 2026
3569377
Fix ICE in unsafe binder discriminant queries
cijiugechu Apr 2, 2026
65b88ea
fix(lints): Improve ill_formed_attribute_input with better help message
JayanAXHF Apr 5, 2026
c324d6e
Simplify attribute validation
JonathanBrouwer Apr 3, 2026
abb15f5
Remove `emit_fatal_malformed_builtin_attribute`
JonathanBrouwer Apr 4, 2026
cb87c36
Remove template from BUILTIN_ATTRIBUTES
JonathanBrouwer Apr 4, 2026
f967bf3
Remove EncodeCrossCrate from BUILTIN_ATTRIBUTES
JonathanBrouwer Apr 4, 2026
eecf63c
Remove AttributeDuplicates from BUILTIN_ATTRIBUTES
JonathanBrouwer Apr 4, 2026
9058b5f
Remove AttributeType from BUILTIN_ATTRIBUTES
JonathanBrouwer Apr 4, 2026
c7f99c4
Remove AttributeSafety from BUILTIN_ATTRIBUTES
JonathanBrouwer Apr 4, 2026
6927e64
Remove unused attribute check for unparsed builtin attributes
JonathanBrouwer Apr 4, 2026
c88ef81
Promote `char::is_case_ignorable` from perma-unstable to unstable
Jules-Bertholet Apr 1, 2026
c3709ee
ast_validation: scalable vectors okay for rustdoc
davidtwco Apr 3, 2026
b79ee96
Rollup merge of #153440 - bjorn3:lto_refactors13, r=TaKO8Ki
JonathanBrouwer Apr 5, 2026
75623b2
Rollup merge of #154561 - FranciscoTGouveia:typo-detection-after-visi…
JonathanBrouwer Apr 5, 2026
40779a8
Rollup merge of #154657 - chenyukang:yukang-fix-145564-pattern-assign…
JonathanBrouwer Apr 5, 2026
a378665
Rollup merge of #154717 - cijiugechu:fix/unsafe-binder-discriminant, …
JonathanBrouwer Apr 5, 2026
6c42816
Rollup merge of #154722 - JayanAXHF:fix/update-ignore-error-message, …
JonathanBrouwer Apr 5, 2026
575d171
Rollup merge of #154808 - JonathanBrouwer:attr_cleanup, r=jdonszelmann
JonathanBrouwer Apr 5, 2026
5bc663b
Rollup merge of #154849 - Jules-Bertholet:case-ignorable, r=Mark-Simu…
JonathanBrouwer Apr 5, 2026
322e501
Rollup merge of #154850 - davidtwco:scalable-vectors-rustdoc, r=Jonat…
JonathanBrouwer Apr 5, 2026
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
4 changes: 3 additions & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1379,7 +1379,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
this.dcx()
.emit_err(errors::ScalableVectorNotTupleStruct { span: item.span });
}
if !self.sess.target.arch.supports_scalable_vectors() {
if !self.sess.target.arch.supports_scalable_vectors()
&& !self.sess.opts.actually_rustdoc
{
this.dcx().emit_err(errors::ScalableVectorBadArch { span: attr.span });
}
}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_session::parse::{ParseSess, feature_err};
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};
use thin_vec::ThinVec;

use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, ShouldEmit, Stage};
use crate::parser::{
AllowExprMetavar, ArgParser, MetaItemListParser, MetaItemOrLitParser, NameValueParser,
Expand Down Expand Up @@ -408,6 +409,7 @@ fn parse_cfg_attr_internal<'a>(
attribute.style,
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
Some(attribute.get_normal_item().unsafety),
AttributeSafety::Normal,
ParsedDescription::Attribute,
pred_span,
CRATE_NODE_ID,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/cfg_select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use rustc_session::Session;
use rustc_session::lint::builtin::UNREACHABLE_CFG_SELECT_PREDICATES;
use rustc_span::{ErrorGuaranteed, Span, Symbol, sym};

use crate::attributes::AttributeSafety;
use crate::parser::{AllowExprMetavar, MetaItemOrLitParser};
use crate::{AttributeParser, ParsedDescription, ShouldEmit, errors, parse_cfg_entry};

Expand Down Expand Up @@ -105,6 +106,7 @@ pub fn parse_cfg_select(
AttrStyle::Inner,
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
None,
AttributeSafety::Normal,
ParsedDescription::Macro,
cfg_span,
lint_node_id,
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition::Edition2024;

use super::prelude::*;
use crate::attributes::AttributeSafety;
use crate::session_diagnostics::{
NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
Expand Down Expand Up @@ -121,6 +123,7 @@ pub(crate) struct ExportNameParser;
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Static),
Allow(Target::Fn),
Expand Down Expand Up @@ -238,6 +241,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
this.span = Some(cx.attr_span);
}
})];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Expand Down Expand Up @@ -363,6 +367,7 @@ pub(crate) struct NoMangleParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoMangleParser {
const PATH: &[Symbol] = &[sym::no_mangle];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Fn),
Allow(Target::Static),
Expand Down Expand Up @@ -565,6 +570,7 @@ pub(crate) struct ForceTargetFeatureParser;
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
type Item = (Symbol, Span);
const PATH: &[Symbol] = &[sym::force_target_feature];
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
features: items,
attr_span: span,
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,11 @@ impl DocParser {
let span = cx.attr_span;
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
AttributeLintKind::IllFormedAttributeInput {
suggestions,
docs: None,
help: None,
},
span,
);
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use rustc_hir::attrs::*;
use rustc_session::Session;
use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_session::parse::feature_err;
use rustc_span::edition::Edition::Edition2024;
use rustc_span::kw;
use rustc_target::spec::{Arch, BinaryFormat};

use super::prelude::*;
use super::util::parse_single_integer;
use crate::attributes::AttributeSafety;
use crate::attributes::cfg::parse_cfg_entry;
use crate::session_diagnostics::{
AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
Expand Down Expand Up @@ -468,6 +470,7 @@ pub(crate) struct LinkSectionParser;
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
Allow(Target::Static),
Allow(Target::Fn),
Expand Down Expand Up @@ -513,6 +516,7 @@ pub(crate) struct FfiConstParser;
impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
const PATH: &[Symbol] = &[sym::ffi_const];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
}
Expand All @@ -521,6 +525,7 @@ pub(crate) struct FfiPureParser;
impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
const PATH: &[Symbol] = &[sym::ffi_pure];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
}
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::marker::PhantomData;

use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_span::edition::Edition;
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;

Expand Down Expand Up @@ -98,6 +99,7 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
/// If an attribute has this symbol, the `accept` function will be called on it.
const ATTRIBUTES: AcceptMapping<Self, S>;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;

/// The parser has gotten a chance to accept the attributes on an item,
/// here it can produce an attribute.
Expand Down Expand Up @@ -128,6 +130,7 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
/// Configures what to do when when the same attribute is
/// applied more than once on the same syntax node.
const ON_DUPLICATE: OnDuplicate<S>;
const SAFETY: AttributeSafety = AttributeSafety::Normal;

const ALLOWED_TARGETS: AllowedTargets;

Expand Down Expand Up @@ -166,6 +169,7 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
},
)];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
Some(self.1?.0)
Expand Down Expand Up @@ -218,6 +222,18 @@ impl<S: Stage> OnDuplicate<S> {
}
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// 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> },
}

/// An even simpler version of [`SingleAttributeParser`]:
/// now automatically check that there are no arguments provided to the attribute.
///
Expand All @@ -227,6 +243,7 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
const PATH: &[Symbol];
const ON_DUPLICATE: OnDuplicate<S>;
const ALLOWED_TARGETS: AllowedTargets;
const SAFETY: AttributeSafety = AttributeSafety::Normal;

/// Create the [`AttributeKind`] given attribute's [`Span`].
const CREATE: fn(Span) -> AttributeKind;
Expand All @@ -243,6 +260,7 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> Default for WithoutArgs<T, S> {
impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for WithoutArgs<T, S> {
const PATH: &[Symbol] = T::PATH;
const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
const SAFETY: AttributeSafety = T::SAFETY;
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const TEMPLATE: AttributeTemplate = template!(Word);

Expand Down Expand Up @@ -272,6 +290,7 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
/// For example, individual representations from `#[repr(...)]` attributes into an `AttributeKind::Repr(x)`,
/// where `x` is a vec of these individual reprs.
const CONVERT: ConvertFn<Self::Item>;
const SAFETY: AttributeSafety = AttributeSafety::Normal;

const ALLOWED_TARGETS: AllowedTargets;

Expand Down Expand Up @@ -313,6 +332,7 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
group.items.extend(T::extend(cx, args))
})];
const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
const SAFETY: AttributeSafety = T::SAFETY;

fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(first_span) = self.first_span {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
};
Some(str_value)
}
ArgParser::List(_) => {
cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
ArgParser::List(list) => {
let help = list.single().and_then(|item| item.meta_item()).and_then(|item| {
item.args().no_args().ok()?;
Some(item.path().to_string())
});
cx.adcx().warn_ill_formed_attribute_input_with_help(
ILL_FORMED_ATTRIBUTE_INPUT,
help,
);
return None;
}
},
Expand Down
13 changes: 11 additions & 2 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use crate::attributes::stability::*;
use crate::attributes::test_attrs::*;
use crate::attributes::traits::*;
use crate::attributes::transparency::*;
use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs};
use crate::parser::{ArgParser, RefPathParser};
use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions,
Expand All @@ -76,6 +76,7 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(super) template: AttributeTemplate,
pub(super) accept_fn: AcceptFn<S>,
pub(super) allowed_targets: AllowedTargets,
pub(super) safety: AttributeSafety,
pub(super) finalizer: FinalizeFn<S>,
}

Expand Down Expand Up @@ -126,6 +127,7 @@ macro_rules! attribute_parsers {
accept_fn(s, cx, args)
})
}),
safety: <$names as crate::attributes::AttributeParser<$stage>>::SAFETY,
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
let state = STATE_OBJECT.take();
Expand Down Expand Up @@ -830,11 +832,18 @@ where
}

pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) {
self.warn_ill_formed_attribute_input_with_help(lint, None)
}
pub(crate) fn warn_ill_formed_attribute_input_with_help(
&mut self,
lint: &'static Lint,
help: Option<String>,
) {
let suggestions = self.suggestions();
let span = self.attr_span;
self.emit_lint(
lint,
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None },
AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None, help },
span,
);
}
Expand Down
35 changes: 27 additions & 8 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use rustc_session::Session;
use rustc_session::lint::{BuiltinLintDiag, LintId};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};

use crate::attributes::AttributeSafety;
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
Expand Down Expand Up @@ -172,6 +173,7 @@ impl<'sess> AttributeParser<'sess, Early> {
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
template: &AttributeTemplate,
allow_expr_metavar: AllowExprMetavar,
expected_safety: AttributeSafety,
) -> Option<T> {
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
panic!("parse_single called on a doc attr")
Expand All @@ -194,6 +196,7 @@ impl<'sess> AttributeParser<'sess, Early> {
attr.style,
path,
Some(normal_attr.item.unsafety),
expected_safety,
ParsedDescription::Attribute,
target_span,
target_node_id,
Expand All @@ -215,6 +218,7 @@ impl<'sess> AttributeParser<'sess, Early> {
attr_style: AttrStyle,
attr_path: AttrPath,
attr_safety: Option<Safety>,
expected_safety: AttributeSafety,
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
Expand All @@ -236,7 +240,13 @@ impl<'sess> AttributeParser<'sess, Early> {
)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
expected_safety,
&mut emit_lint,
)
}
let attr_id = sess.psess.attr_id_generator.mk_attr_id();
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
Expand Down Expand Up @@ -353,17 +363,18 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
};

self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
);

let parts =
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();

if let Some(accept) = S::parsers().accepters.get(parts.as_slice()) {
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
accept.safety,
&mut emit_lint,
);

let Some(args) = ArgParser::from_attr_args(
args,
&parts,
Expand Down Expand Up @@ -437,6 +448,14 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
span: attr_span,
};

self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
AttributeSafety::Normal,
&mut emit_lint,
);

if !matches!(self.stage.should_emit(), ShouldEmit::Nothing)
&& target == Target::Crate
{
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ mod session_diagnostics;
mod target_checking;
pub mod validate_attr;

pub use attributes::AttributeSafety;
pub use attributes::cfg::{
CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg, parse_cfg_attr, parse_cfg_entry,
};
Expand Down
Loading
Loading