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:
commit
642c19bfc3
36 changed files with 320 additions and 57 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 ==================================================================================
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
3
tests/run-make/rustdoc-test-builder/foo.rs
Normal file
3
tests/run-make/rustdoc-test-builder/foo.rs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
//! ```
|
||||
//! let x = 12;
|
||||
//! ```
|
||||
22
tests/run-make/rustdoc-test-builder/rmake.rs
Normal file
22
tests/run-make/rustdoc-test-builder/rmake.rs
Normal 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();
|
||||
}
|
||||
37
tests/ui/asm/hexagon-register-pairs.rs
Normal file
37
tests/ui/asm/hexagon-register-pairs.rs
Normal 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
|
||||
}
|
||||
}
|
||||
25
tests/ui/asm/hexagon-register-pairs.stderr
Normal file
25
tests/ui/asm/hexagon-register-pairs.stderr
Normal 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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue