Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9363038
bootstrap: fix RUSTFLAGS with spaces in paths via CARGO_ENCODED_RUSTF…
Rohan-Singla Jun 18, 2026
63d3395
bootstrap: also use CARGO_ENCODED_RUSTDOCFLAGS to support spaces in…
Rohan-Singla Jun 18, 2026
386748b
⏺ bootstrap: reset CARGO_ENCODED_RUSTFLAGS in Miri test runner
Rohan-Singla Jun 18, 2026
8085cd3
bootstrap: use \x1f-delimited String for Rustflags instead of Vec<Str…
Rohan-Singla Jun 18, 2026
b4a7c3e
unset RUSTFLAGS/RUSTDOCFLAGS when setting encoded forms
Rohan-Singla Jun 21, 2026
a89705b
Avoid panics bubbling out to proc macros
Mark-Simulacrum Jun 22, 2026
7f2574f
Move attribute and keyword docs from `std` to `core`
jschillem Jun 28, 2026
cca8cd1
Use doctest attribute `ignore-wasm` instead of manual `cfg_attr`
fmease Jun 29, 2026
96f3774
Record step creation locations in bootstrap tracing DOT graph
Kobzol Jun 29, 2026
e6dc840
Add a few `#[track_caller]` annotations to make tracing locations mor…
Kobzol Jun 29, 2026
ee4ea97
Better record locations of executed steps
Kobzol Jun 29, 2026
69f0187
Avoid building rustdoc for tests without doctests
chenyukang Jun 27, 2026
c340e8a
Allow section override when using patchable-function-entries
pmur Jun 3, 2026
cd0a3c4
Fix spacing issue for unused parentheses lint
chenyukang Jun 30, 2026
b674511
Rollup merge of #158073 - Rohan-Singla:fix/#158052, r=kobzol,mark-sim…
JonathanBrouwer Jun 30, 2026
3dc45e1
Rollup merge of #158256 - Mark-Simulacrum:no-panic-pm-parsing, r=bjorn3
JonathanBrouwer Jun 30, 2026
912d8f2
Rollup merge of #158561 - chenyukang:yukang-fix-158299-core-tests-rus…
JonathanBrouwer Jun 30, 2026
cd1d41e
Rollup merge of #158562 - Kobzol:bootstrap-tracing-step-caller, r=jie…
JonathanBrouwer Jun 30, 2026
86eb76f
Rollup merge of #157445 - pmur:murp/extend-patchable, r=mejrs
JonathanBrouwer Jun 30, 2026
dab9ecf
Rollup merge of #158327 - jschillem:docs-move-attributes-and-keywords…
JonathanBrouwer Jun 30, 2026
cdfa297
Rollup merge of #158591 - chenyukang:yukang-fix-158583-unused-parens-…
JonathanBrouwer Jun 30, 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
62 changes: 37 additions & 25 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use rustc_span::edition::Edition::Edition2024;
use super::prelude::*;
use crate::attributes::AttributeSafety;
use crate::session_diagnostics::{
EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
SanitizeInvalidStatic, TargetFeatureOnLangItem,
EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport,
NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral,
ObjcSelectorExpectedStringLiteral, SanitizeInvalidStatic, TargetFeatureOnLangItem,
};
use crate::target_checking::Policy::AllowSilent;

Expand Down Expand Up @@ -795,82 +795,94 @@ pub(crate) struct PatchableFunctionEntryParser;
impl SingleAttributeParser for PatchableFunctionEntryParser {
const PATH: &[Symbol] = &[sym::patchable_function_entry];
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
const TEMPLATE: AttributeTemplate =
template!(List: &["prefix_nops = m, entry_nops = n, section = \"section\""]);
const STABILITY: AttributeStability = unstable!(patchable_function_entry);

fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
let meta_item_list = cx.expect_list(args, cx.attr_span)?;

let mut prefix = None;
let mut entry = None;
let mut section = None;

if meta_item_list.len() == 0 {
cx.adcx().expected_at_least_one_argument(meta_item_list.span);
return None;
}

let mut errored = false;

for item in meta_item_list.mixed() {
let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
continue;
return None;
};

let attrib_to_write = match ident.name {
sym::prefix_nops => {
// Duplicate prefixes are not allowed
if prefix.is_some() {
errored = true;
cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
continue;
return None;
}
&mut prefix
}
sym::entry_nops => {
// Duplicate entries are not allowed
if entry.is_some() {
errored = true;
cx.adcx().duplicate_key(ident.span, sym::entry_nops);
continue;
return None;
}
&mut entry
}
sym::section => {
// Duplicate entries are not allowed
if section.is_some() {
cx.adcx().duplicate_key(ident.span, sym::section);
return None;
}
// Only a string type value is allowed.
let Some(value_str) = value.value_as_str() else {
cx.adcx().expect_string_literal(value);
return None;
};
// The section name does not allow null characters.
if value_str.as_str().contains('\0') {
cx.emit_err(NullOnSection { span: value.value_span });
}
// The section name is not allowed to be empty, LLVM does
// not allow them.
if value_str.is_empty() {
cx.emit_err(EmptySection { span: value.value_span });
}
section = Some(value_str);
// Integer parsing is not needed, process next item.
continue;
}
_ => {
errored = true;
cx.adcx().expected_specific_argument(
ident.span,
&[sym::prefix_nops, sym::entry_nops],
);
continue;
return None;
}
};

let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
errored = true;
cx.adcx().expected_integer_literal(value.value_span);
continue;
return None;
};

let Ok(val) = val.get().try_into() else {
errored = true;
cx.adcx().expected_integer_literal_in_range(
value.value_span,
u8::MIN as isize,
u8::MAX as isize,
);
continue;
return None;
};

*attrib_to_write = Some(val);
}

if errored {
None
} else {
Some(AttributeKind::PatchableFunctionEntry {
prefix: prefix.unwrap_or(0),
entry: entry.unwrap_or(0),
})
}
Some(AttributeKind::PatchableFunctionEntry { prefix, entry, section })
}
}
14 changes: 14 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,13 @@ pub(crate) struct EmptyExportName {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("`section` may not be empty")]
pub(crate) struct EmptySection {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("`export_name` may not contain null characters", code = E0648)]
pub(crate) struct NullOnExport {
Expand Down Expand Up @@ -327,6 +334,13 @@ pub(crate) struct NullOnObjcSelector {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("`section` may not contain null characters", code = E0648)]
pub(crate) struct NullOnSection {
#[primary_span]
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("`objc::class!` expected a string literal")]
pub(crate) struct ObjcClassExpectedStringLiteral {
Expand Down
32 changes: 27 additions & 5 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,26 @@ fn patchable_function_entry_attrs<'ll>(
attr: Option<PatchableFunctionEntry>,
) -> SmallVec<[&'ll Attribute; 2]> {
let mut attrs = SmallVec::new();
let patchable_spec = attr.unwrap_or_else(|| {
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry)
});
let entry = patchable_spec.entry();
let prefix = patchable_spec.prefix();

let mut entry = sess.opts.unstable_opts.patchable_function_entry.entry();
let mut prefix = sess.opts.unstable_opts.patchable_function_entry.prefix();
let mut section = sess.opts.unstable_opts.patchable_function_entry.section();
let section_sym;

// Apply attribute specified overrides, if any.
if let Some(patchable_spec) = attr {
if let Some(sym) = patchable_spec.section() {
section_sym = sym;
section = Some(section_sym.as_str());
}
// Override the nop counts if either is present. If only one is present, the
// other count is implied to be 0.
if patchable_spec.entry().is_some() || patchable_spec.prefix().is_some() {
entry = patchable_spec.entry().unwrap_or(0);
prefix = patchable_spec.prefix().unwrap_or(0);
}
}

if entry > 0 {
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
Expand All @@ -105,6 +120,13 @@ fn patchable_function_entry_attrs<'ll>(
&format!("{}", prefix),
));
}
if let Some(section) = section {
attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"patchable-function-entry-section",
section,
));
}
attrs
}

Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::PatchableFunctionEntry;
use rustc_middle::mono::CodegenUnit;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
Expand Down Expand Up @@ -343,14 +342,13 @@ pub(crate) unsafe fn create_module<'ll>(

// Add "kcfi-offset" module flag with -Z patchable-function-entry (See
// https://reviews.llvm.org/D141172).
let pfe =
PatchableFunctionEntry::from_config(sess.opts.unstable_opts.patchable_function_entry);
if pfe.prefix() > 0 {
let patchable_prefix_nops = sess.opts.unstable_opts.patchable_function_entry.prefix();
if patchable_prefix_nops > 0 {
llvm::add_module_flag_u32(
llmod,
llvm::ModuleFlagMergeBehavior::Override,
"kcfi-offset",
pfe.prefix().into(),
patchable_prefix_nops.into(),
);
}

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,11 @@ fn process_builtin_attrs(
AttributeKind::RustcOffloadKernel => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::OFFLOAD_KERNEL
}
AttributeKind::PatchableFunctionEntry { prefix, entry } => {
AttributeKind::PatchableFunctionEntry { prefix, entry, section } => {
codegen_fn_attrs.patchable_function_entry =
Some(PatchableFunctionEntry::from_prefix_and_entry(*prefix, *entry));
Some(PatchableFunctionEntry::from_prefix_entry_and_section(
*prefix, *entry, *section,
));
}
AttributeKind::InstrumentFn(instrument_fn) => {
codegen_fn_attrs.instrument_fn = match instrument_fn {
Expand Down
21 changes: 13 additions & 8 deletions compiler/rustc_expand/src/proc_macro_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,9 +490,11 @@ impl server::Server for Rustc<'_, '_> {
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, String> {
let name = FileName::proc_macro_source_code(s);

let mut parser =
let mut parser = rustc_errors::catch_fatal_errors(|| {
new_parser_from_source_str(self.psess(), name, s.to_owned(), StripTokens::Nothing)
.map_err(cancel_diags_into_string)?;
})
.map_err(|_| String::from("failed to parse to literal"))?
.map_err(cancel_diags_into_string)?;

let first_span = parser.token.span.data();
let minus_present = parser.eat(exp!(Minus));
Expand Down Expand Up @@ -569,12 +571,15 @@ impl server::Server for Rustc<'_, '_> {
}

fn ts_from_str(&mut self, src: &str) -> Result<Self::TokenStream, String> {
source_str_to_stream(
self.psess(),
FileName::proc_macro_source_code(src),
src.to_string(),
Some(self.call_site),
)
rustc_errors::catch_fatal_errors(|| {
source_str_to_stream(
self.psess(),
FileName::proc_macro_source_code(src),
src.to_string(),
Some(self.call_site),
)
})
.map_err(|_| String::from("failed to parse to tokenstream"))?
.map_err(cancel_diags_into_string)
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir/src/attrs/data_structures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1271,8 +1271,9 @@ pub enum AttributeKind {

/// Represents `#[patchable_function_entry]`
PatchableFunctionEntry {
prefix: u8,
entry: u8,
prefix: Option<u8>,
entry: Option<u8>,
section: Option<Symbol>,
},

/// Represents `#[path]`
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(panic_in_drop, PanicStrategy::Abort);
tracked!(
patchable_function_entry,
PatchableFunctionEntry::from_total_and_prefix_nops(10, 5)
PatchableFunctionEntry::from_parts(10, 5, None)
.expect("total must be greater than or equal to prefix")
);
tracked!(plt, Some(true));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ trait UnusedDelimLint {
&& !snip.starts_with(' ')
{
" "
} else if let Ok(snip) = sm.span_to_prev_source(value_span)
} else if let Ok(snip) = sm.span_to_next_source(value_span)
&& snip.starts_with(|c: char| c.is_alphanumeric())
{
" "
Expand Down
25 changes: 17 additions & 8 deletions compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pub struct CodegenFnAttrs {
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
pub alignment: Option<Align>,
/// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around
/// the function entry.
/// the function entry, or override default section to record entry location.
pub patchable_function_entry: Option<PatchableFunctionEntry>,
/// The `#[rustc_objc_class = "..."]` attribute.
pub objc_class: Option<Symbol>,
Expand Down Expand Up @@ -162,24 +162,33 @@ pub struct TargetFeature {
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, StableHash)]
pub struct PatchableFunctionEntry {
/// Nops to prepend to the function
prefix: u8,
prefix: Option<u8>,
/// Nops after entry, but before body
entry: u8,
entry: Option<u8>,
/// Optional, specific section to record entry location in
section: Option<Symbol>,
}

impl PatchableFunctionEntry {
pub fn from_config(config: rustc_session::config::PatchableFunctionEntry) -> Self {
Self { prefix: config.prefix(), entry: config.entry() }
pub fn from_prefix_entry_and_section(
prefix: Option<u8>,
entry: Option<u8>,
section: Option<Symbol>,
) -> Self {
Self { prefix, entry, section }
}
pub fn from_prefix_and_entry(prefix: u8, entry: u8) -> Self {
Self { prefix, entry }
Self { prefix: Some(prefix), entry: Some(entry), section: None }
}
pub fn prefix(&self) -> u8 {
pub fn prefix(&self) -> Option<u8> {
self.prefix
}
pub fn entry(&self) -> u8 {
pub fn entry(&self) -> Option<u8> {
self.entry
}
pub fn section(&self) -> Option<Symbol> {
self.section
}
}

#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, StableHash)]
Expand Down
Loading
Loading