Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6c4c438
destabilise target-spec-json
davidtwco Dec 19, 2025
6f12b86
s390x: support `f16` and `f16x8` in inline assembly
folkertdev Jan 8, 2026
ef1e4e6
Move checks from `check_doc_attrs` directly into `rustc_attr_parsing`
GuillaumeGomez Jan 10, 2026
b327e30
core: ptr: split_at_mut: fix typo in safety doc
lschuermann Jan 12, 2026
284d136
Dogfood `-Zno-embed-metadata` for the standard library
Kobzol Aug 25, 2025
e03cb1f
run-make-support: resolve .rmeta companion for .rlib stubs
akshitgaur2005 Jan 2, 2026
6ca9501
Relax test expectation for @__llvm_profile_runtime_user
zmodem Jan 12, 2026
c451e9b
Remove a workaround for a bug
bjorn3 Sep 19, 2021
a2cc9ef
std: move `errno` and related functions into `sys::io`
joboet Jan 6, 2026
210c157
update import in UI test
joboet Jan 6, 2026
90b32e7
Fix typo in `MaybeUninit` docs
tbu- Jan 12, 2026
50b60aa
std: sys: net: uefi: Make TcpStream Send
Ayush1325 Jan 12, 2026
439da07
Update books
rustbot Jan 12, 2026
418cff3
Port `#[must_not_suspend]` to attribute parser
Bryntet Jan 10, 2026
b07d983
Rollup merge of #145343 - dogfood-z-no-embed-metadata, r=bjorn3
matthiaskrgr Jan 12, 2026
1e66be8
Rollup merge of #150151 - destabilise-target-spec-json, r=Kivooeo
matthiaskrgr Jan 12, 2026
fa403e4
Rollup merge of #150723 - move_pal_error, r=@tgross35
matthiaskrgr Jan 12, 2026
6230311
Rollup merge of #150826 - s390x-asm-f16-vector, r=uweigand,tgross35
matthiaskrgr Jan 12, 2026
9026074
Rollup merge of #150934 - move-doc-attr-checks, r=JonathanBrouwer
matthiaskrgr Jan 12, 2026
fff757e
Rollup merge of #150943 - port_must_not_suspend, r=jdonszelmann,Jonat…
matthiaskrgr Jan 12, 2026
5ed98e1
Rollup merge of #150990 - uefi-run-test, r=joboet
matthiaskrgr Jan 12, 2026
34e6590
Rollup merge of #150995 - dev/core-ptr-split-at-mut-docs-fix, r=joboet
matthiaskrgr Jan 12, 2026
b0f2220
Rollup merge of #150998 - win___llvm_profile_runtime_user, r=durin42
matthiaskrgr Jan 12, 2026
7abcfaa
Rollup merge of #151002 - remove_bug_workaround, r=lqd
matthiaskrgr Jan 12, 2026
42a7b42
Rollup merge of #151005 - pr_doc_maybeuninit_typo, r=joboet
matthiaskrgr Jan 12, 2026
d63bda3
Rollup merge of #151011 - docs-update, r=ehuss
matthiaskrgr Jan 12, 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
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ attr_parsing_doc_alias_malformed =
attr_parsing_doc_alias_start_end =
{$attr_str} cannot start or end with ' '
attr_parsing_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
attr_parsing_doc_attribute_not_attribute =
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
.help = only existing builtin attributes are allowed in core/std
Expand Down
119 changes: 96 additions & 23 deletions compiler/rustc_attr_parsing/src/attributes/doc.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
use rustc_feature::template;
use rustc_hir::Target;
use rustc_hir::attrs::{
AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow,
};
Expand All @@ -12,8 +13,8 @@ use super::{AcceptMapping, AttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
use crate::session_diagnostics::{
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute,
DocKeywordNotKeyword,
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
DocAttributeNotAttribute, DocKeywordNotKeyword,
};

fn check_keyword<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool {
Expand Down Expand Up @@ -43,16 +44,39 @@ fn check_attribute<S: Stage>(
false
}

fn parse_keyword_and_attribute<S, F>(
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
fn check_attr_not_crate_level<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
span: Span,
attr_name: Symbol,
) -> bool {
if cx.shared.target.is_some_and(|target| target == Target::Crate) {
cx.emit_err(DocAttrNotCrateLevel { span, attr_name });
return false;
}
true
}

/// Checks that an attribute is used at the crate level. Returns `true` if valid.
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
if cx.shared.target.is_some_and(|target| target != Target::Crate) {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::AttrCrateLevelOnly,
span,
);
return false;
}
true
}

fn parse_keyword_and_attribute<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
path: &OwnedPathParser,
args: &ArgParser,
attr_value: &mut Option<(Symbol, Span)>,
callback: F,
) where
S: Stage,
F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool,
{
attr_name: Symbol,
) {
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
return;
Expand All @@ -63,16 +87,26 @@ fn parse_keyword_and_attribute<S, F>(
return;
};

if !callback(cx, value, nv.value_span) {
let ret = if attr_name == sym::keyword {
check_keyword(cx, value, nv.value_span)
} else {
check_attribute(cx, value, nv.value_span)
};
if !ret {
return;
}

let span = path.span();
if attr_value.is_some() {
cx.duplicate_key(path.span(), path.word_sym().unwrap());
cx.duplicate_key(span, path.word_sym().unwrap());
return;
}

*attr_value = Some((value, path.span()));
if !check_attr_not_crate_level(cx, span, attr_name) {
return;
}

*attr_value = Some((value, span));
}

#[derive(Default, Debug)]
Expand Down Expand Up @@ -102,6 +136,10 @@ impl DocParser {
return;
}

if !check_attr_crate_level(cx, path.span()) {
return;
}

self.attribute.no_crate_inject = Some(path.span())
}
Some(sym::attr) => {
Expand Down Expand Up @@ -155,6 +193,9 @@ impl DocParser {
cx.emit_err(DocAliasStartEnd { span, attr_str });
return;
}
if !check_attr_not_crate_level(cx, span, sym::alias) {
return;
}

if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() {
cx.emit_lint(
Expand Down Expand Up @@ -366,7 +407,33 @@ impl DocParser {
self.attribute.$ident = Some(path.span());
}};
}
macro_rules! string_arg {
macro_rules! no_args_and_not_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return;
}
let span = path.span();
if !check_attr_not_crate_level(cx, span, sym::$ident) {
return;
}
self.attribute.$ident = Some(span);
}};
}
macro_rules! no_args_and_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return;
}
let span = path.span();
if !check_attr_crate_level(cx, span) {
return;
}
self.attribute.$ident = Some(span);
}};
}
macro_rules! string_arg_and_crate_level {
($ident: ident) => {{
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
Expand All @@ -378,6 +445,10 @@ impl DocParser {
return;
};

if !check_attr_crate_level(cx, path.span()) {
return;
}

// FIXME: It's errorring when the attribute is passed multiple times on the command
// line.
// The right fix for this would be to only check this rule if the attribute is
Expand All @@ -394,12 +465,14 @@ impl DocParser {
match path.word_sym() {
Some(sym::alias) => self.parse_alias(cx, path, args),
Some(sym::hidden) => no_args!(hidden),
Some(sym::html_favicon_url) => string_arg!(html_favicon_url),
Some(sym::html_logo_url) => string_arg!(html_logo_url),
Some(sym::html_no_source) => no_args!(html_no_source),
Some(sym::html_playground_url) => string_arg!(html_playground_url),
Some(sym::html_root_url) => string_arg!(html_root_url),
Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url),
Some(sym::html_favicon_url) => string_arg_and_crate_level!(html_favicon_url),
Some(sym::html_logo_url) => string_arg_and_crate_level!(html_logo_url),
Some(sym::html_no_source) => no_args_and_crate_level!(html_no_source),
Some(sym::html_playground_url) => string_arg_and_crate_level!(html_playground_url),
Some(sym::html_root_url) => string_arg_and_crate_level!(html_root_url),
Some(sym::issue_tracker_base_url) => {
string_arg_and_crate_level!(issue_tracker_base_url)
}
Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline),
Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline),
Some(sym::masked) => no_args!(masked),
Expand All @@ -410,18 +483,18 @@ impl DocParser {
path,
args,
&mut self.attribute.keyword,
check_keyword,
sym::keyword,
),
Some(sym::attribute) => parse_keyword_and_attribute(
cx,
path,
args,
&mut self.attribute.attribute,
check_attribute,
sym::attribute,
),
Some(sym::fake_variadic) => no_args!(fake_variadic),
Some(sym::search_unbox) => no_args!(search_unbox),
Some(sym::rust_logo) => no_args!(rust_logo),
Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic),
Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox),
Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo),
Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args),
Some(sym::test) => {
let Some(list) = args.list() else {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub(crate) mod link_attrs;
pub(crate) mod lint_helpers;
pub(crate) mod loop_match;
pub(crate) mod macro_attrs;
pub(crate) mod must_not_suspend;
pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude;
pub(crate) mod no_link;
Expand Down
35 changes: 35 additions & 0 deletions compiler/rustc_attr_parsing/src/attributes/must_not_suspend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use super::prelude::*;

pub(crate) struct MustNotSuspendParser;

impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::Trait),
]);
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);

fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let reason = match args {
ArgParser::NameValue(reason) => match reason.value_as_str() {
Some(val) => Some(val),
None => {
cx.expected_nv_or_no_args(reason.value_span);
return None;
}
},
ArgParser::NoArgs => None,
ArgParser::List(list) => {
cx.expected_nv_or_no_args(list.span);
return None;
}
};

Some(AttributeKind::MustNotSupend { reason })
}
}
4 changes: 3 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser,
MacroUseParser,
};
use crate::attributes::must_not_suspend::MustNotSuspendParser;
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::no_link::NoLinkParser;
Expand Down Expand Up @@ -89,7 +90,6 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
};
use crate::target_checking::AllowedTargets;

type GroupType<S> = LazyLock<GroupTypeInner<S>>;

pub(super) struct GroupTypeInner<S: Stage> {
Expand Down Expand Up @@ -208,6 +208,7 @@ attribute_parsers!(
Single<LinkageParser>,
Single<MacroExportParser>,
Single<MoveSizeLimitParser>,
Single<MustNotSuspendParser>,
Single<MustUseParser>,
Single<ObjcClassParser>,
Single<ObjcSelectorParser>,
Expand Down Expand Up @@ -655,6 +656,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
pub(crate) target_span: Span,
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
pub(crate) target_id: S::Id,
pub(crate) target: Option<rustc_hir::Target>,

pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ impl<'sess> AttributeParser<'sess, Early> {
cx: &mut parser,
target_span,
target_id: target_node_id,
target: None,
emit_lint: &mut emit_lint,
},
attr_span,
Expand Down Expand Up @@ -378,6 +379,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
cx: self,
target_span,
target_id,
target: Some(target),
emit_lint: &mut emit_lint,
},
attr_span,
Expand Down Expand Up @@ -429,6 +431,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
cx: self,
target_span,
target_id,
target: Some(target),
emit_lint: &mut emit_lint,
},
all_attrs: &attr_paths,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ pub(crate) struct DocAliasStartEnd<'a> {
pub attr_str: &'a str,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_doc_attr_not_crate_level)]
pub(crate) struct DocAttrNotCrateLevel {
#[primary_span]
pub span: Span,
pub attr_name: Symbol,
}

#[derive(Diagnostic)]
#[diag(attr_parsing_doc_keyword_not_keyword)]
#[help]
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1124,9 +1124,10 @@ fn get_backend_from_raw_matches(
let backend_name = debug_flags
.iter()
.find_map(|x| x.strip_prefix("codegen-backend=").or(x.strip_prefix("codegen_backend=")));
let unstable_options = debug_flags.iter().find(|x| *x == "unstable-options").is_some();
let target = parse_target_triple(early_dcx, matches);
let sysroot = Sysroot::new(matches.opt_str("sysroot").map(PathBuf::from));
let target = config::build_target_config(early_dcx, &target, sysroot.path());
let target = config::build_target_config(early_dcx, &target, sysroot.path(), unstable_options);

get_codegen_backend(early_dcx, &sysroot, backend_name, &target)
}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,9 @@ pub enum AttributeKind {
/// Represents `#[move_size_limit]`
MoveSizeLimit { attr_span: Span, limit_span: Span, limit: Limit },

/// Represents `#[must_not_suspend]`
MustNotSupend { reason: Option<Symbol> },

/// Represents `#[must_use]`.
MustUse {
span: Span,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/attrs/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ impl AttributeKind {
Marker(..) => No,
MayDangle(..) => No,
MoveSizeLimit { .. } => No,
MustNotSupend { .. } => Yes,
MustUse { .. } => Yes,
Naked(..) => No,
NoCore(..) => No,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
&early_dcx,
&config.opts.target_triple,
config.opts.sysroot.path(),
config.opts.unstable_opts.unstable_options,
);
let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
let path_mapping = config.opts.file_path_mapping();
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ where
&early_dcx,
&sessopts.target_triple,
sessopts.sysroot.path(),
sessopts.unstable_opts.unstable_options,
);
let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm();
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` order
lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
.help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
lint_attr_crate_level =
this attribute can only be applied at the crate level
.suggestion = to apply to the crate, use an inner attribute
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
lint_bad_attribute_argument = bad attribute argument
lint_bad_opt_access = {$msg}
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_lint/src/early/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,5 +417,7 @@ pub fn decorate_attribute_lint(
}

&AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag),

&AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag),
}
}
Loading
Loading