Auto merge of #148560 - Zalathar:rollup-c62przo, r=Zalathar

Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#143037 (Make named asm_labels lint not trigger on hexagon register spans)
 - rust-lang/rust#147043 (Add default sanitizers to TargetOptions)
 - rust-lang/rust#147586 (std-detect: improve detect macro docs)
 - rust-lang/rust#147912 ([rustdoc] Gracefully handle error in case we cannot run the compiler in doctests)
 - rust-lang/rust#148540 (Minor fixes to StdNonZeroNumberProvider for gdb)
 - rust-lang/rust#148541 (Add num_children method to some gdb pretty-printers)
 - rust-lang/rust#148549 (Fix broken qemu-cskyv2 link)

Failed merges:

 - rust-lang/rust#147935 (Add LLVM realtime sanitizer)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-11-06 08:39:07 +00:00
commit 642c19bfc3
36 changed files with 320 additions and 57 deletions

View file

@ -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.

View file

@ -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));
}
@ -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;
}

View file

@ -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");
}
@ -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"));
}

View file

@ -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()

View file

@ -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 {
@ -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

View file

@ -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]
@ -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
}

View file

@ -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,
@ -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;

View file

@ -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)?;
}

View file

@ -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;

View file

@ -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) => {
@ -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 {
@ -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 {
@ -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,
);
}
_ => {}
@ -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],

View file

@ -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 {
@ -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 {
@ -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 {
@ -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

View file

@ -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);
@ -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);
@ -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>,

View file

@ -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>,
@ -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,

View file

@ -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(

View file

@ -9,6 +9,7 @@ pub(crate) fn target() -> Target {
base.max_atomic_width = Some(64);
base.stack_probes = StackProbeType::Inline;
base.supported_sanitizers = SanitizerSet::SHADOWCALLSTACK;
base.default_sanitizers = SanitizerSet::SHADOWCALLSTACK;
base.supports_xray = true;
Target {

View file

@ -5,13 +5,18 @@ features! {
@CFG: any(target_arch = "aarch64", target_arch = "arm64ec");
@MACRO_NAME: is_aarch64_feature_detected;
@MACRO_ATTRS:
/// This macro tests, at runtime, whether an `aarch64` feature is enabled on aarch64 platforms.
/// Currently most features are only supported on linux-based platforms.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
///
/// This macro takes one argument which is a string literal of the feature being tested for.
/// The feature names are mostly taken from their FEAT_* definitions in the [ARM Architecture
/// Reference Manual][docs].
///
/// Currently most features are only supported on linux-based platforms: on other platforms the
/// runtime check will always return `false`.
///
/// ## Supported arguments
///
/// * `"aes"` - FEAT_AES & FEAT_PMULL

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "arm";
@MACRO_NAME: is_arm_feature_detected;
@MACRO_ATTRS:
/// Checks if `arm` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_arm_feature_detection", issue = "111190")]
@NO_RUNTIME_DETECTION: "v7";
@NO_RUNTIME_DETECTION: "vfp2";

View file

@ -5,7 +5,11 @@ features! {
@CFG: any(target_arch = "loongarch32", target_arch = "loongarch64");
@MACRO_NAME: is_loongarch_feature_detected;
@MACRO_ATTRS:
/// Checks if `loongarch` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
///
/// Supported arguments are:
///
/// * `"32s"`

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "mips";
@MACRO_NAME: is_mips_feature_detected;
@MACRO_ATTRS:
/// Checks if `mips` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")]
@FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa";
/// MIPS SIMD Architecture (MSA)

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "mips64";
@MACRO_NAME: is_mips64_feature_detected;
@MACRO_ATTRS:
/// Checks if `mips64` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")]
@FEATURE: #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] msa: "msa";
/// MIPS SIMD Architecture (MSA)

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "powerpc";
@MACRO_NAME: is_powerpc_feature_detected;
@MACRO_ATTRS:
/// Checks if `powerpc` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")]
@FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec";
/// Altivec

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "powerpc64";
@MACRO_NAME: is_powerpc64_feature_detected;
@MACRO_ATTRS:
/// Checks if `powerpc` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")]
@FEATURE: #[unstable(feature = "stdarch_powerpc_feature_detection", issue = "111191")] altivec: "altivec";
/// Altivec

View file

@ -5,8 +5,10 @@ features! {
@CFG: any(target_arch = "riscv32", target_arch = "riscv64");
@MACRO_NAME: is_riscv_feature_detected;
@MACRO_ATTRS:
/// A macro to test at *runtime* whether instruction sets are available on
/// RISC-V platforms.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
///
/// RISC-V standard defined the base sets and the extension sets.
/// The base sets are RV32I, RV64I, RV32E or RV128I. Any RISC-V platform

View file

@ -5,7 +5,10 @@ features! {
@CFG: target_arch = "s390x";
@MACRO_NAME: is_s390x_feature_detected;
@MACRO_ATTRS:
/// Checks if `s390x` feature is enabled.
/// Check for the presence of a CPU feature at runtime.
///
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
#[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")]
@FEATURE: #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] concurrent_functions: "concurrent-functions";
/// s390x concurrent-functions facility

View file

@ -20,13 +20,12 @@ features! {
@CFG: any(target_arch = "x86", target_arch = "x86_64");
@MACRO_NAME: is_x86_feature_detected;
@MACRO_ATTRS:
/// A macro to test at *runtime* whether a CPU feature is available on
/// x86/x86-64 platforms.
/// Check for the presence of a CPU feature at runtime.
///
/// This macro is provided in the standard library and will detect at runtime
/// whether the specified CPU feature is detected. This does **not** resolve at
/// compile time unless the specified feature is already enabled for the entire
/// crate. Runtime detection currently relies mostly on the `cpuid` instruction.
/// When the feature is known to be enabled at compile time (e.g. via `-Ctarget-feature`)
/// the macro expands to `true`.
///
/// Runtime detection currently relies mostly on the `cpuid` instruction.
///
/// This macro only takes one argument which is a string literal of the feature
/// being tested for. The feature names supported are the lowercase versions of

View file

@ -65,7 +65,7 @@ To test cross-compiled binaries on a `x86_64` system, you can use the `qemu-csky
To use:
* Install `qemu-cskyv2` (If you don't already have a qemu, you can download from [here](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1689324918932/xuantie-qemu-x86_64-Ubuntu-18.04-20230714-0202.tar.gz"), and unpack it into a directory.)
* Install `qemu-cskyv2` (If you don't already have a qemu, you can download from [here](https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1689324918932/xuantie-qemu-x86_64-Ubuntu-18.04-20230714-0202.tar.gz), and unpack it into a directory.)
* Link your built toolchain via:
* `rustup toolchain link stage2 ${RUST}/build/x86_64-unknown-linux-gnu/stage2`
* Create a test program

View file

@ -128,6 +128,9 @@ class StdSliceProvider(printer_base):
self._data_ptr + index for index in xrange(self._length)
)
def num_children(self):
return self._length
@staticmethod
def display_hint():
return "array"
@ -149,6 +152,9 @@ class StdVecProvider(printer_base):
self._data_ptr + index for index in xrange(self._length)
)
def num_children(self):
return self._length
@staticmethod
def display_hint():
return "array"
@ -177,6 +183,9 @@ class StdVecDequeProvider(printer_base):
for index in xrange(self._size)
)
def num_children(self):
return self._size
@staticmethod
def display_hint():
return "array"
@ -252,15 +261,15 @@ class StdNonZeroNumberProvider(printer_base):
def __init__(self, valobj):
fields = valobj.type.fields()
assert len(fields) == 1
field = list(fields)[0]
field = fields[0]
inner_valobj = valobj[field.name]
inner_valobj = valobj[field]
inner_fields = inner_valobj.type.fields()
assert len(inner_fields) == 1
inner_field = list(inner_fields)[0]
inner_field = inner_fields[0]
self._value = str(inner_valobj[inner_field.name])
self._value = inner_valobj[inner_field]
def to_string(self):
return self._value
@ -478,5 +487,11 @@ class StdHashMapProvider(printer_base):
else:
yield "[{}]".format(index), element[ZERO_FIELD]
def num_children(self):
result = self._size
if self._show_values:
result *= 2
return result
def display_hint(self):
return "map" if self._show_values else "array"

View file

@ -671,7 +671,13 @@ fn run_test(
debug!("compiler invocation for doctest: {compiler:?}");
let mut child = compiler.spawn().expect("Failed to spawn rustc process");
let mut child = match compiler.spawn() {
Ok(child) => child,
Err(error) => {
eprintln!("Failed to spawn {:?}: {error:?}", compiler.get_program());
return (Duration::default(), Err(TestFailure::CompileError));
}
};
let output = if let Some(merged_test_code) = &doctest.merged_test_code {
// compile-fail tests never get merged, so this should always pass
let status = child.wait().expect("Failed to wait");
@ -733,7 +739,13 @@ fn run_test(
let status = if !status.success() {
status
} else {
let mut child_runner = runner_compiler.spawn().expect("Failed to spawn rustc process");
let mut child_runner = match runner_compiler.spawn() {
Ok(child) => child,
Err(error) => {
eprintln!("Failed to spawn {:?}: {error:?}", runner_compiler.get_program());
return (Duration::default(), Err(TestFailure::CompileError));
}
};
child_runner.wait().expect("Failed to wait")
};

View file

@ -387,6 +387,13 @@ impl CompletedProcess {
self
}
/// Checks that `stderr` doesn't contain the Internal Compiler Error message.
#[track_caller]
pub fn assert_not_ice(&self) -> &Self {
self.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug");
self
}
/// Checks that `stderr` does not contain the regex pattern `unexpected`.
#[track_caller]
pub fn assert_stderr_not_contains_regex<S: AsRef<str>>(&self, unexpected: S) -> &Self {

View file

@ -202,6 +202,8 @@
// gdb-command:print nz_usize
// gdb-check:[...]$12 = 122
// gdb-command:print/x nz_i8
// gdb-check:[...]$13 = 0xb
// === LLDB TESTS ==================================================================================

View file

@ -43,5 +43,5 @@ fn main() {
.extern_("minibevy", "libminibevy-b.rmeta")
.extern_("minirapier", "libminirapier.rmeta")
.run_fail()
.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug");
.assert_not_ice();
}

View file

@ -24,5 +24,5 @@ fn main() {
.arg(format!("--include-parts-dir={}", parts_out_dir.display()))
.arg("--merge=finalize")
.run();
output.assert_stderr_not_contains("error: the compiler unexpectedly panicked. this is a bug.");
output.assert_not_ice();
}

View file

@ -0,0 +1,3 @@
//! ```
//! let x = 12;
//! ```

View file

@ -0,0 +1,22 @@
// This test ensures that if the rustdoc test binary is not executable, it will
// gracefully fail and not panic.
//@ needs-target-std
use run_make_support::{path, rfs, rustdoc};
fn main() {
let absolute_path = path("foo.rs").canonicalize().expect("failed to get absolute path");
let output = rustdoc()
.input("foo.rs")
.arg("--test")
.arg("-Zunstable-options")
.arg("--test-builder")
.arg(&absolute_path)
.run_fail();
// We check that rustdoc outputs the error correctly...
output.assert_stdout_contains("Failed to spawn ");
// ... and that we didn't panic.
output.assert_not_ice();
}

View file

@ -0,0 +1,37 @@
//@ add-minicore
//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b
//@ needs-llvm-components: hexagon
//@ ignore-backends: gcc
#![feature(no_core, asm_experimental_arch)]
#![crate_type = "lib"]
#![no_core]
//~? WARN unstable feature specified for `-Ctarget-feature`: `hvx-length128b`
extern crate minicore;
use minicore::*;
fn test_register_spans() {
unsafe {
// These are valid Hexagon register span notations, not labels
// Should NOT trigger the named labels lint
// General register pairs
asm!("r1:0 = memd(r29+#0)", lateout("r0") _, lateout("r1") _);
asm!("r3:2 = combine(#1, #0)", lateout("r2") _, lateout("r3") _);
asm!("r15:14 = memd(r30+#8)", lateout("r14") _, lateout("r15") _);
asm!("memd(r29+#0) = r5:4", in("r4") 0u32, in("r5") 0u32);
// These patterns look like register spans but test different edge cases
// All should NOT trigger the lint as they match valid hexagon register syntax patterns
asm!("V5:4 = vaddw(v1:0, v1:0)", options(nostack)); // Uppercase V register pair
asm!("v1:0.w = vsub(v1:0.w,v1:0.w):sat", options(nostack)); // Lowercase v with suffix
// Mixed with actual labels should still trigger for the labels
asm!("label1: r7:6 = combine(#2, #3)"); //~ ERROR avoid using named labels
// Regular labels should still trigger
asm!("hexagon_label: nop"); //~ ERROR avoid using named labels
}
}

View file

@ -0,0 +1,25 @@
warning: unstable feature specified for `-Ctarget-feature`: `hvx-length128b`
|
= note: this feature is not stably supported; its behavior can change in the future
error: avoid using named labels in inline assembly
--> $DIR/hexagon-register-pairs.rs:32:15
|
LL | asm!("label1: r7:6 = combine(#2, #3)");
| ^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
= note: `#[deny(named_asm_labels)]` on by default
error: avoid using named labels in inline assembly
--> $DIR/hexagon-register-pairs.rs:35:15
|
LL | asm!("hexagon_label: nop");
| ^^^^^^^^^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: aborting due to 2 previous errors; 1 warning emitted