Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bc911c2
std-detect: improve detect macro docs
folkertdev Oct 11, 2025
ec1b2fa
Gracefully handle in case we cannot run the compiler in doctests
GuillaumeGomez Oct 20, 2025
5d0011c
Add regression test when unable to run compiler in doctest
GuillaumeGomez Oct 20, 2025
e207006
Add default sanitizers to TargetOptions
ilovepi Sep 25, 2025
71e2e0c
Minor fixes to StdNonZeroNumberProvider for gdb
tromey Nov 5, 2025
d2b021c
Add num_children method to some gdb pretty-printers
tromey Nov 5, 2025
2c3c82c
Add new `run_make_support::CompletedProcess::assert_ice` method
GuillaumeGomez Nov 3, 2025
71e599b
Make named asm_labels lint not trigger on hexagon register spans
androm3da Jun 26, 2025
0717a39
Fix broken qemu-cskyv2 link
ehuss Nov 5, 2025
54df8da
CI fixes after recent rebase changes
androm3da Nov 6, 2025
12deb2f
Rollup merge of #143037 - androm3da:bcain/hexagon_regspan_label, r=Am…
Zalathar Nov 6, 2025
efdc8ac
Rollup merge of #147043 - ilovepi:default-sanitizers, r=petrochenkov
Zalathar Nov 6, 2025
c9ca719
Rollup merge of #147586 - folkertdev:std-detect-expands-to-true, r=Am…
Zalathar Nov 6, 2025
dd80361
Rollup merge of #147912 - GuillaumeGomez:graceful-doctest-error-handl…
Zalathar Nov 6, 2025
2d77f23
Rollup merge of #148540 - tromey:non-zero-gdb-cleanup, r=bjorn3
Zalathar Nov 6, 2025
8e7417c
Rollup merge of #148541 - tromey:add-num-children, r=bjorn3
Zalathar Nov 6, 2025
7c58e15
Rollup merge of #148549 - ehuss:fix-csky-link, r=Kivooeo
Zalathar Nov 6, 2025
642c19b
Auto merge of #148560 - Zalathar:rollup-c62przo, r=Zalathar
bors Nov 6, 2025
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
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
}
}
}
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
} else if cx.tcx.sess.sanitizers().contains(SanitizerSet::MEMORY) {
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
// memory sanitizer's behavior.

Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
no_sanitize: SanitizerSet,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
let enabled = tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
let enabled = tcx.sess.sanitizers() - no_sanitize;
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
}
Expand Down Expand Up @@ -240,13 +240,7 @@ fn probestack_attr<'ll, 'tcx>(cx: &SimpleCx<'ll>, tcx: TyCtxt<'tcx>) -> Option<&
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
if tcx
.sess
.opts
.unstable_opts
.sanitizer
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
{
if tcx.sess.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD) {
return None;
}

Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1227,7 +1227,7 @@ fn add_sanitizer_libraries(
return;
}

let sanitizer = sess.opts.unstable_opts.sanitizer;
let sanitizer = sess.sanitizers();
if sanitizer.contains(SanitizerSet::ADDRESS) {
link_sanitizer_runtime(sess, flavor, linker, "asan");
}
Expand Down Expand Up @@ -2497,11 +2497,7 @@ fn add_order_independent_options(
&& crate_type == CrateType::Executable
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
{
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
} else {
""
};
let prefix = if sess.sanitizers().contains(SanitizerSet::ADDRESS) { "asan/" } else { "" };
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl ModuleConfig {
debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling,
instrument_coverage: if_regular!(sess.instrument_coverage(), false),

sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
sanitizer: if_regular!(sess.sanitizers(), SanitizerSet::empty()),
sanitizer_dataflow_abilist: if_regular!(
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
Vec::new()
Expand Down
73 changes: 73 additions & 0 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2875,6 +2875,71 @@ enum AsmLabelKind {
Binary,
}

/// Checks if a potential label is actually a Hexagon register span notation.
///
/// Hexagon assembly uses register span notation like `r1:0`, `V5:4.w`, `p1:0` etc.
/// These follow the pattern: `[letter][digit(s)]:[digit(s)][optional_suffix]`
///
/// Returns `true` if the string matches a valid Hexagon register span pattern.
pub fn is_hexagon_register_span(possible_label: &str) -> bool {
// Extract the full register span from the context
if let Some(colon_idx) = possible_label.find(':') {
let after_colon = &possible_label[colon_idx + 1..];
is_hexagon_register_span_impl(&possible_label[..colon_idx], after_colon)
} else {
false
}
}

/// Helper function for use within the lint when we have statement context.
fn is_hexagon_register_span_context(
possible_label: &str,
statement: &str,
colon_idx: usize,
) -> bool {
// Extract what comes after the colon in the statement
let after_colon_start = colon_idx + 1;
if after_colon_start >= statement.len() {
return false;
}

// Get the part after the colon, up to the next whitespace or special character
let after_colon_full = &statement[after_colon_start..];
let after_colon = after_colon_full
.chars()
.take_while(|&c| c.is_ascii_alphanumeric() || c == '.')
.collect::<String>();

is_hexagon_register_span_impl(possible_label, &after_colon)
}

/// Core implementation for checking hexagon register spans.
fn is_hexagon_register_span_impl(before_colon: &str, after_colon: &str) -> bool {
if before_colon.len() < 1 || after_colon.is_empty() {
return false;
}

let mut chars = before_colon.chars();
let start = chars.next().unwrap();

// Must start with a letter (r, V, p, etc.)
if !start.is_ascii_alphabetic() {
return false;
}

let rest = &before_colon[1..];

// Check if the part after the first letter is all digits and non-empty
if rest.is_empty() || !rest.chars().all(|c| c.is_ascii_digit()) {
return false;
}

// Check if after colon starts with digits (may have suffix like .w, .h)
let digits_after = after_colon.chars().take_while(|c| c.is_ascii_digit()).collect::<String>();

!digits_after.is_empty()
}

impl<'tcx> LateLintPass<'tcx> for AsmLabels {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if let hir::Expr {
Expand Down Expand Up @@ -2957,6 +3022,14 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
break 'label_loop;
}

// Check for Hexagon register span notation (e.g., "r1:0", "V5:4", "V3:2.w")
// This is valid Hexagon assembly syntax, not a label
if matches!(cx.tcx.sess.asm_arch, Some(InlineAsmArch::Hexagon))
&& is_hexagon_register_span_context(possible_label, statement, idx)
{
break 'label_loop;
}

for c in chars {
// Inside a template format arg, any character is permitted for the
// purposes of label detection because we assume that it can be
Expand Down
27 changes: 27 additions & 0 deletions compiler/rustc_lint/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use rustc_span::{Symbol, create_default_session_globals_then};

use crate::builtin::is_hexagon_register_span;
use crate::levels::parse_lint_and_tool_name;

#[test]
Expand All @@ -27,3 +28,29 @@ fn parse_lint_multiple_path() {
)
});
}

#[test]
fn test_hexagon_register_span_patterns() {
// Valid Hexagon register span patterns
assert!(is_hexagon_register_span("r1:0"));
assert!(is_hexagon_register_span("r15:14"));
assert!(is_hexagon_register_span("V5:4"));
assert!(is_hexagon_register_span("V3:2"));
assert!(is_hexagon_register_span("V5:4.w"));
assert!(is_hexagon_register_span("V3:2.h"));
assert!(is_hexagon_register_span("r99:98"));
assert!(is_hexagon_register_span("V123:122.whatever"));

// Invalid patterns - these should be treated as potential labels
assert!(!is_hexagon_register_span("label1"));
assert!(!is_hexagon_register_span("foo:"));
assert!(!is_hexagon_register_span(":0"));
assert!(!is_hexagon_register_span("r:0")); // missing digits before colon
assert!(!is_hexagon_register_span("r1:")); // missing digits after colon
assert!(!is_hexagon_register_span("r1:a")); // non-digit after colon
assert!(!is_hexagon_register_span("1:0")); // starts with digit, not letter
assert!(!is_hexagon_register_span("r1")); // no colon
assert!(!is_hexagon_register_span("r")); // too short
assert!(!is_hexagon_register_span("")); // empty
assert!(!is_hexagon_register_span("ra:0")); // letter in first digit group
}
10 changes: 5 additions & 5 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ impl CStore {
match (&left_name_val, &right_name_val) {
(Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
cmp::Ordering::Equal => {
if !l.1.consistent(&tcx.sess.opts, Some(&r.1)) {
if !l.1.consistent(&tcx.sess, Some(&r.1)) {
report_diff(
&l.0.prefix,
&l.0.name,
Expand All @@ -424,26 +424,26 @@ impl CStore {
right_name_val = None;
}
cmp::Ordering::Greater => {
if !r.1.consistent(&tcx.sess.opts, None) {
if !r.1.consistent(&tcx.sess, None) {
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
}
right_name_val = None;
}
cmp::Ordering::Less => {
if !l.1.consistent(&tcx.sess.opts, None) {
if !l.1.consistent(&tcx.sess, None) {
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
}
left_name_val = None;
}
},
(Some(l), None) => {
if !l.1.consistent(&tcx.sess.opts, None) {
if !l.1.consistent(&tcx.sess, None) {
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
}
left_name_val = None;
}
(None, Some(r)) => {
if !r.1.consistent(&tcx.sess.opts, None) {
if !r.1.consistent(&tcx.sess, None) {
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
}
right_name_val = None;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn walk_native_lib_search_dirs<R>(
|| sess.target.os == "linux"
|| sess.target.os == "fuchsia"
|| sess.target.is_like_aix
|| sess.target.is_like_darwin && !sess.opts.unstable_opts.sanitizer.is_empty()
|| sess.target.is_like_darwin && !sess.sanitizers().is_empty()
{
f(&sess.target_tlib_path.dir, false)?;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/config/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol());
}

for mut s in sess.opts.unstable_opts.sanitizer {
for mut s in sess.sanitizers() {
// KASAN is still ASAN under the hood, so it uses the same attribute.
if s == SanitizerSet::KERNELADDRESS {
s = SanitizerSet::ADDRESS;
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use rustc_target::spec::{
use crate::config::*;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
use crate::{EarlyDiagCtxt, lint};
use crate::{EarlyDiagCtxt, Session, lint};

macro_rules! insert {
($opt_name:ident, $opt_expr:expr, $sub_hashes:expr) => {
Expand Down Expand Up @@ -111,12 +111,12 @@ mod target_modifier_consistency_check {
lparsed & tmod_sanitizers == rparsed & tmod_sanitizers
}
pub(super) fn sanitizer_cfi_normalize_integers(
opts: &Options,
sess: &Session,
l: &TargetModifier,
r: Option<&TargetModifier>,
) -> bool {
// For kCFI, the helper flag -Zsanitizer-cfi-normalize-integers should also be a target modifier
if opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI) {
if sess.sanitizers().contains(SanitizerSet::KCFI) {
if let Some(r) = r {
return l.extend().tech_value == r.extend().tech_value;
} else {
Expand All @@ -133,7 +133,7 @@ impl TargetModifier {
}
// Custom consistency check for target modifiers (or default `l.tech_value == r.tech_value`)
// When other is None, consistency with default value is checked
pub fn consistent(&self, opts: &Options, other: Option<&TargetModifier>) -> bool {
pub fn consistent(&self, sess: &Session, other: Option<&TargetModifier>) -> bool {
assert!(other.is_none() || self.opt == other.unwrap().opt);
match self.opt {
OptionsTargetModifiers::UnstableOptions(unstable) => match unstable {
Expand All @@ -142,7 +142,7 @@ impl TargetModifier {
}
UnstableOptionsTargetModifiers::sanitizer_cfi_normalize_integers => {
return target_modifier_consistency_check::sanitizer_cfi_normalize_integers(
opts, self, other,
sess, self, other,
);
}
_ => {}
Expand Down Expand Up @@ -2575,6 +2575,7 @@ written to standard error output)"),
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
target features (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::sanitizers()` instead of this field")]
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED TARGET_MODIFIER],
"use a sanitizer"),
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
Expand Down
10 changes: 7 additions & 3 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl Session {
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
self.sanitizers().contains(SanitizerSet::CFI)
}

pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
Expand All @@ -347,7 +347,7 @@ impl Session {
}

pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
self.sanitizers().contains(SanitizerSet::KCFI)
}

pub fn is_split_lto_unit_enabled(&self) -> bool {
Expand Down Expand Up @@ -527,7 +527,7 @@ impl Session {
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
}

pub fn diagnostic_width(&self) -> usize {
Expand Down Expand Up @@ -922,6 +922,10 @@ impl Session {
min
}
}

pub fn sanitizers(&self) -> SanitizerSet {
return self.opts.unstable_opts.sanitizer | self.target.options.default_sanitizers;
}
}

// JUSTIFICATION: part of session construction
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_target/src/spec/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,11 @@ impl Target {
supported_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
}

if let Some(default_sanitizers) = json.default_sanitizers {
base.default_sanitizers =
default_sanitizers.into_iter().fold(SanitizerSet::empty(), |a, b| a | b);
}

forward!(generate_arange_section);
forward!(supports_stack_protector);
forward!(small_data_threshold_support);
Expand Down Expand Up @@ -392,6 +397,7 @@ impl ToJson for Target {
target_option_val!(split_debuginfo);
target_option_val!(supported_split_debuginfo);
target_option_val!(supported_sanitizers);
target_option_val!(default_sanitizers);
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
target_option_val!(supports_stack_protector);
Expand Down Expand Up @@ -612,6 +618,7 @@ struct TargetSpecJson {
split_debuginfo: Option<SplitDebuginfo>,
supported_split_debuginfo: Option<StaticCow<[SplitDebuginfo]>>,
supported_sanitizers: Option<Vec<SanitizerSet>>,
default_sanitizers: Option<Vec<SanitizerSet>>,
generate_arange_section: Option<bool>,
supports_stack_protector: Option<bool>,
small_data_threshold_support: Option<SmallDataThresholdSupport>,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,13 @@ pub struct TargetOptions {
/// distributed with the target, the sanitizer should still appear in this list for the target.
pub supported_sanitizers: SanitizerSet,

/// The sanitizers that are enabled by default on this target.
///
/// Note that the support here is at a codegen level. If the machine code with sanitizer
/// enabled can generated on this target, but the necessary supporting libraries are not
/// distributed with the target, the sanitizer should still appear in this list for the target.
pub default_sanitizers: SanitizerSet,

/// Minimum number of bits in #[repr(C)] enum. Defaults to the size of c_int
pub c_enum_min_bits: Option<u64>,

Expand Down Expand Up @@ -2658,6 +2665,7 @@ impl Default for TargetOptions {
// `Off` is supported by default, but targets can remove this manually, e.g. Windows.
supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
supported_sanitizers: SanitizerSet::empty(),
default_sanitizers: SanitizerSet::empty(),
c_enum_min_bits: None,
generate_arange_section: true,
supports_stack_protector: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
| SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::SHADOWCALLSTACK;
base.default_sanitizers = SanitizerSet::SHADOWCALLSTACK;
base.supports_xray = true;

base.add_pre_link_args(
Expand Down
Loading
Loading