diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 5f8933aa2beba..8d7351d3a510c 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -125,9 +125,9 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { - /// Because we want to track parent items and so forth, enable - /// deep walking so that we walk nested items in the context of - /// their outer items. + // Because we want to track parent items and so forth, enable + // deep walking so that we walk nested items in the context of + // their outer items. fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 9ac282df5b5ea..09d71f5dd5579 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -916,8 +916,8 @@ pub(crate) fn codegen_call_with_unwind_action( pub(crate) fn lib_call_arg_param(tcx: TyCtxt<'_>, ty: Type, is_signed: bool) -> AbiParam { let param = AbiParam::new(ty); if ty.is_int() && u64::from(ty.bits()) < tcx.data_layout.pointer_size().bits() { - match (&tcx.sess.target.arch, tcx.sess.target.vendor.as_ref()) { - (Arch::X86_64, _) | (Arch::AArch64, "apple") => match (ty, is_signed) { + match (&tcx.sess.target.arch, tcx.sess.target.is_like_darwin) { + (Arch::X86_64, _) | (Arch::AArch64, true) => match (ty, is_signed) { (types::I8 | types::I16, true) => param.sext(), (types::I8 | types::I16, false) => param.uext(), _ => param, diff --git a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs index 91f7220667ff9..86bff32dc623c 100644 --- a/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs +++ b/compiler/rustc_codegen_cranelift/src/codegen_f16_f128.rs @@ -5,7 +5,7 @@ use crate::prelude::*; pub(crate) fn f16_to_f32(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { let (value, arg_ty) = - if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 { + if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { ( fx.bcx.ins().bitcast(types::I16, MemFlags::new(), value), lib_call_arg_param(fx.tcx, types::I16, false), @@ -22,8 +22,7 @@ fn f16_to_f64(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { } pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 @@ -38,8 +37,7 @@ pub(crate) fn f32_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value } fn f64_to_f16(fx: &mut FunctionCx<'_, '_, '_>, value: Value) -> Value { - let ret_ty = if fx.tcx.sess.target.vendor == "apple" && fx.tcx.sess.target.arch == Arch::X86_64 - { + let ret_ty = if fx.tcx.sess.target.is_like_darwin && fx.tcx.sess.target.arch == Arch::X86_64 { types::I16 } else { types::F16 diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index c5724c20b2165..2817dcf8e976a 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1819,7 +1819,7 @@ fn self_contained_components( LinkSelfContainedDefault::InferredForMusl => sess.crt_static(Some(crate_type)), LinkSelfContainedDefault::InferredForMingw => { sess.host == sess.target - && sess.target.vendor != "uwp" + && sess.target.abi != "uwp" && detect_self_contained_mingw(sess, linker) } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index eb2740d59b4b5..5abcf99b3d67a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -83,7 +83,7 @@ pub(crate) fn get_linker<'a>( // To comply with the Windows App Certification Kit, // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). let t = &sess.target; - if matches!(flavor, LinkerFlavor::Msvc(..)) && t.vendor == "uwp" { + if matches!(flavor, LinkerFlavor::Msvc(..)) && t.abi == "uwp" { if let Some(ref tool) = msvc_tool { let original_path = tool.path(); if let Some(root_lib_path) = original_path.ancestors().nth(4) { @@ -134,7 +134,7 @@ pub(crate) fn get_linker<'a>( // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. - assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp"); + assert!(cmd.get_args().is_empty() || sess.target.abi == "uwp"); match flavor { LinkerFlavor::Unix(Cc::No) if sess.target.os == "l4re" => { Box::new(L4Bender::new(cmd, sess)) as Box diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index 08e2f35595332..bde36f45b3838 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -171,7 +171,7 @@ pub fn asm_const_to_str<'tcx>( } pub fn is_mingw_gnu_toolchain(target: &Target) -> bool { - target.vendor == "pc" && target.os == "windows" && target.env == "gnu" && target.abi.is_empty() + target.os == "windows" && target.env == "gnu" && target.abi.is_empty() } pub fn i686_decorated_name( diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 81a7ee1ff45fe..e6fa1fa5ce50a 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2322,11 +2322,6 @@ impl HumanEmitter { show_code_change { for part in parts { - let snippet = if let Ok(snippet) = sm.span_to_snippet(part.span) { - snippet - } else { - String::new() - }; let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; let span_end_pos = sm.lookup_char_pos(part.span.hi()).col_display; @@ -2402,7 +2397,7 @@ impl HumanEmitter { // LL - REMOVED <- row_num - 2 - (newlines - first_i - 1) // LL + NEWER // | <- row_num - + let snippet = sm.span_to_snippet(part.span).unwrap_or_default(); let newlines = snippet.lines().count(); if newlines > 0 && row_num > newlines { // Account for removals where the part being removed spans multiple diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 79f3d7f2ff8f5..c881c77f38f15 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1487,11 +1487,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { match assoc_tag { // Don't attempt to look up inherent associated types when the feature is not // enabled. Theoretically it'd be fine to do so since we feature-gate their - // definition site. However, due to current limitations of the implementation - // (caused by us performing selection during HIR ty lowering instead of in the - // trait solver), IATs can lead to cycle errors (#108491) which mask the - // feature-gate error, needlessly confusing users who use IATs by accident - // (#113265). + // definition site. However, the current implementation of inherent associated + // items is somewhat brittle, so let's not run it by default. ty::AssocTag::Type => return Ok(None), ty::AssocTag::Const => { // We also gate the mgca codepath for type-level uses of inherent consts @@ -1520,9 +1517,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) .collect(); + // At the moment, we actually bail out with a hard error if the selection of an inherent + // associated item fails (see below). This means we never consider trait associated items + // as potential fallback candidates (#142006). To temporarily mask that issue, let's not + // select at all if there are no early inherent candidates. + if candidates.is_empty() { + return Ok(None); + } + let (applicable_candidates, fulfillment_errors) = self.select_inherent_assoc_candidates(span, self_ty, candidates.clone()); + // FIXME(#142006): Don't eagerly error here, there might be applicable trait candidates. let InherentAssocCandidate { impl_, assoc_item, scope: def_scope } = match &applicable_candidates[..] { &[] => Err(self.report_unresolved_inherent_assoc_item( @@ -1543,6 +1549,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )), }?; + // FIXME(#142006): Don't eagerly validate here, there might be trait candidates that are + // accessible (visible and stable) contrary to the inherent candidate. self.check_assoc_item(assoc_item, name, def_scope, block, span); // FIXME(fmease): Currently creating throwaway `parent_args` to please diff --git a/compiler/rustc_hir_analysis/src/variance/terms.rs b/compiler/rustc_hir_analysis/src/variance/terms.rs index cf38957bf24aa..9c7680b921205 100644 --- a/compiler/rustc_hir_analysis/src/variance/terms.rs +++ b/compiler/rustc_hir_analysis/src/variance/terms.rs @@ -44,7 +44,7 @@ impl<'a> fmt::Debug for VarianceTerm<'a> { } } -/// The first pass over the crate simply builds up the set of inferreds. +// The first pass over the crate simply builds up the set of inferreds. pub(crate) struct TermsContext<'a, 'tcx> { pub tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 191eb721b3477..ae145543e70dc 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -55,10 +55,10 @@ macro_rules! late_lint_methods { /// Each `check` method checks a single syntax node, and should not /// invoke methods recursively (unlike `Visitor`). By default they /// do nothing. -// +/// // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. - +// macro_rules! declare_late_lint_pass { ([], [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( pub trait LateLintPass<'tcx>: LintPass { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 291f5c65dfa27..10fe23a0a65c9 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -67,7 +67,7 @@ pub fn walk_native_lib_search_dirs( // FIXME: On AIX this also has the side-effect of making the list of library search paths // non-empty, which is needed or the linker may decide to record the LIBPATH env, if // defined, as the search path instead of appending the default search paths. - if sess.target.vendor == "fortanix" + if sess.target.abi == "fortanix" || sess.target.os == "linux" || sess.target.os == "fuchsia" || sess.target.is_like_aix diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 5764a9c84eeaf..6985cc7ddcfa1 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -16,7 +16,7 @@ use crate::ty::{self, ConstKind, GenericArgsRef, ScalarInt, Ty, TyCtxt}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants - +/// /// Represents the result of const evaluation via the `eval_to_allocation` query. /// Not to be confused with `ConstAllocation`, which directly refers to the underlying data! /// Here we indirect via an `AllocId`. diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 26ff87417ab0d..50c88e8b1e62a 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -298,7 +298,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::target_thread_local); } - ins_str!(sym::target_vendor, &sess.target.vendor); + ins_sym!(sym::target_vendor, sess.target.vendor_symbol()); // If the user wants a test runner, then add the test cfg. if sess.is_test_crate() { @@ -456,7 +456,7 @@ impl CheckCfg { ); values_target_os.insert(Symbol::intern(&target.options.os)); values_target_pointer_width.insert(sym::integer(target.pointer_width)); - values_target_vendor.insert(Symbol::intern(&target.options.vendor)); + values_target_vendor.insert(target.vendor_symbol()); } } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 2d83caa07676a..73a0d9eea7326 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,7 +9,9 @@ // tidy-alphabetical-start #![cfg_attr(bootstrap, feature(debug_closure_helpers))] +#![expect(internal_features)] #![feature(iter_intersperse)] +#![feature(rustc_attrs)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs index 374918d38a791..4f9d9c83761f4 100644 --- a/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs +++ b/compiler/rustc_target/src/spec/base/windows_uwp_msvc.rs @@ -1,10 +1,9 @@ use crate::spec::{LinkerFlavor, Lld, TargetOptions, base}; pub(crate) fn opts() -> TargetOptions { - let mut opts = base::windows_msvc::opts(); + let mut opts = + TargetOptions { abi: "uwp".into(), vendor: "uwp".into(), ..base::windows_msvc::opts() }; - opts.abi = "uwp".into(); - opts.vendor = "uwp".into(); opts.add_pre_link_args(LinkerFlavor::Msvc(Lld::No), &["/APPCONTAINER", "mincore.lib"]); opts diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index ab2879f6c6ea8..8ac09205fbc89 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -261,6 +261,7 @@ impl ToJson for Target { ($attr:ident) => {{ target_option_val!($attr, (stringify!($attr)).replace("_", "-")) }}; ($attr:ident, $json_name:expr) => {{ let name = $json_name; + #[allow(rustc::bad_opt_access)] if default.$attr != target.$attr { d.insert(name.into(), target.$attr.to_json()); } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 2dd0fbc4517a5..08fae288c441c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2045,6 +2045,7 @@ type StaticCow = Cow<'static, T>; /// construction, all its fields logically belong to `Target` and available from `Target` /// through `Deref` impls. #[derive(PartialEq, Clone, Debug)] +#[rustc_lint_opt_ty] pub struct TargetOptions { /// Used as the `target_endian` `cfg` variable. Defaults to little endian. pub endian: Endian, @@ -2063,7 +2064,10 @@ pub struct TargetOptions { /// However, parts of the backend do check this field for specific values to enable special behavior. pub abi: StaticCow, /// Vendor name to use for conditional compilation (`target_vendor`). Defaults to "unknown". - pub vendor: StaticCow, + #[rustc_lint_opt_deny_field_access( + "use `Target::is_like_*` instead of this field; see https://github.com/rust-lang/rust/issues/100343 for rationale" + )] + vendor: StaticCow, /// Linker to invoke pub linker: Option>, @@ -3323,6 +3327,10 @@ impl Target { Align::MAX } } + + pub fn vendor_symbol(&self) -> Symbol { + Symbol::intern(&self.vendor) + } } /// Either a target tuple string or a path to a JSON file. diff --git a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs index a79c642870126..37a8b1d878098 100644 --- a/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs +++ b/compiler/rustc_target/src/spec/targets/armv6k_nintendo_3ds.rs @@ -5,7 +5,6 @@ use crate::spec::{ /// A base target for Nintendo 3DS devices using the devkitARM toolchain. /// /// Requires the devkitARM toolchain for 3DS targets on the host system. - pub(crate) fn target() -> Target { let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 6c02ec26fea48..631b9770fac54 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -7,7 +7,6 @@ use crate::spec::{ /// A base target for PlayStation Vita devices using the VITASDK toolchain (using newlib). /// /// Requires the VITASDK toolchain on the host system. - pub(crate) fn target() -> Target { let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs index c026f915906cb..43ebc54c2b402 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_gnu.rs @@ -1,15 +1,18 @@ use crate::spec::{ - Arch, Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, base, + Arch, Cc, FramePointer, LinkerFlavor, Lld, RustcAbi, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { - let mut base = base::windows_gnu::opts(); - base.vendor = "win7".into(); - base.rustc_abi = Some(RustcAbi::X86Sse2); - base.cpu = "pentium4".into(); - base.max_atomic_width = Some(64); - base.frame_pointer = FramePointer::Always; // Required for backtraces - base.linker = Some("i686-w64-mingw32-gcc".into()); + let mut base = TargetOptions { + vendor: "win7".into(), + rustc_abi: Some(RustcAbi::X86Sse2), + cpu: "pentium4".into(), + max_atomic_width: Some(64), + frame_pointer: FramePointer::Always, // Required for backtraces + linker: Some("i686-w64-mingw32-gcc".into()), + ..base::windows_gnu::opts() + }; // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs index 68131bf654264..8994c245d7b90 100644 --- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs @@ -1,18 +1,22 @@ -use crate::spec::{Arch, LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, base}; +use crate::spec::{ + Arch, LinkerFlavor, Lld, RustcAbi, SanitizerSet, Target, TargetMetadata, TargetOptions, base, +}; pub(crate) fn target() -> Target { - let mut base = base::windows_msvc::opts(); - base.vendor = "win7".into(); - base.rustc_abi = Some(RustcAbi::X86Sse2); - base.cpu = "pentium4".into(); - base.max_atomic_width = Some(64); - base.supported_sanitizers = SanitizerSet::ADDRESS; - // On Windows 7 32-bit, the alignment characteristic of the TLS Directory - // don't appear to be respected by the PE Loader, leading to crashes. As - // a result, let's disable has_thread_local to make sure TLS goes through - // the emulation layer. - // See https://github.com/rust-lang/rust/issues/138903 - base.has_thread_local = false; + let mut base = TargetOptions { + vendor: "win7".into(), + rustc_abi: Some(RustcAbi::X86Sse2), + cpu: "pentium4".into(), + max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS, + // On Windows 7 32-bit, the alignment characteristic of the TLS Directory + // don't appear to be respected by the PE Loader, leading to crashes. As + // a result, let's disable has_thread_local to make sure TLS goes through + // the emulation layer. + // See https://github.com/rust-lang/rust/issues/138903 + has_thread_local: false, + ..base::windows_msvc::opts() + }; base.add_pre_link_args( LinkerFlavor::Msvc(Lld::No), diff --git a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs index 79035c791156d..498d8182ad589 100644 --- a/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/sparcv9_sun_solaris.rs @@ -1,15 +1,17 @@ use rustc_abi::Endian; -use crate::spec::{Arch, Cc, LinkerFlavor, Target, TargetMetadata, base}; +use crate::spec::{Arch, Cc, LinkerFlavor, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::solaris::opts(); - base.endian = Endian::Big; + let mut base = TargetOptions { + endian: Endian::Big, + // llvm calls this "v9" + cpu: "v9".into(), + vendor: "sun".into(), + max_atomic_width: Some(64), + ..base::solaris::opts() + }; base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); - // llvm calls this "v9" - base.cpu = "v9".into(); - base.vendor = "sun".into(); - base.max_atomic_width = Some(64); Target { llvm_target: "sparcv9-sun-solaris".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs index 7b8d5def3a70b..39ebe62430479 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_pc_solaris.rs @@ -1,16 +1,19 @@ use crate::spec::{ - Arch, Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetMetadata, base, + Arch, Cc, LinkerFlavor, SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, + base, }; pub(crate) fn target() -> Target { - let mut base = base::solaris::opts(); + let mut base = TargetOptions { + cpu: "x86-64".into(), + plt_by_default: false, + vendor: "pc".into(), + max_atomic_width: Some(64), + stack_probes: StackProbeType::Inline, + supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD, + ..base::solaris::opts() + }; base.add_pre_link_args(LinkerFlavor::Unix(Cc::Yes), &["-m64"]); - base.cpu = "x86-64".into(); - base.plt_by_default = false; - base.vendor = "pc".into(); - base.max_atomic_width = Some(64); - base.stack_probes = StackProbeType::Inline; - base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; Target { llvm_target: "x86_64-pc-solaris".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs index 22a1a126b8912..0bd4215855264 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_gnu.rs @@ -1,18 +1,20 @@ -use crate::spec::{Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, base}; +use crate::spec::{Arch, Cc, LinkerFlavor, Lld, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::windows_gnu::opts(); - base.vendor = "win7".into(); - base.cpu = "x86-64".into(); - base.plt_by_default = false; + let mut base = TargetOptions { + vendor: "win7".into(), + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + linker: Some("x86_64-w64-mingw32-gcc".into()), + ..base::windows_gnu::opts() + }; // Use high-entropy 64 bit address space for ASLR base.add_pre_link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), &["-m", "i386pep", "--high-entropy-va"], ); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64", "-Wl,--high-entropy-va"]); - base.max_atomic_width = Some(64); - base.linker = Some("x86_64-w64-mingw32-gcc".into()); Target { llvm_target: "x86_64-pc-windows-gnu".into(), diff --git a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs index 99b59154811f2..1cc2efaae5f5f 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_win7_windows_msvc.rs @@ -1,12 +1,14 @@ -use crate::spec::{Arch, SanitizerSet, Target, TargetMetadata, base}; +use crate::spec::{Arch, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { - let mut base = base::windows_msvc::opts(); - base.vendor = "win7".into(); - base.cpu = "x86-64".into(); - base.plt_by_default = false; - base.max_atomic_width = Some(64); - base.supported_sanitizers = SanitizerSet::ADDRESS; + let base = TargetOptions { + vendor: "win7".into(), + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + supported_sanitizers: SanitizerSet::ADDRESS, + ..base::windows_msvc::opts() + }; Target { llvm_target: "x86_64-pc-windows-msvc".into(), diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 7d395eb780346..70e764de90698 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -992,10 +992,10 @@ macro_rules! int_impl { /// /// ``` /// #![feature(exact_div)] - #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_exact_div(-1), Some(", stringify!($Max), "));")] - #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_exact_div(2), None);")] - #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_exact_div(-1), None);")] - #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_exact_div(0), None);")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).checked_div_exact(-1), Some(", stringify!($Max), "));")] + #[doc = concat!("assert_eq!((-5", stringify!($SelfT), ").checked_div_exact(2), None);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.checked_div_exact(-1), None);")] + #[doc = concat!("assert_eq!((1", stringify!($SelfT), ").checked_div_exact(0), None);")] /// ``` #[unstable( feature = "exact_div", @@ -1004,7 +1004,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_exact_div(self, rhs: Self) -> Option { + pub const fn checked_div_exact(self, rhs: Self) -> Option { if intrinsics::unlikely(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) { None } else { @@ -1034,18 +1034,18 @@ macro_rules! int_impl { /// /// ``` /// #![feature(exact_div)] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), Some(32));")] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), Some(2));")] - #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).exact_div(-1), Some(", stringify!($Max), "));")] - #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".exact_div(2), None);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".div_exact(2), Some(32));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".div_exact(32), Some(2));")] + #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 1).div_exact(-1), Some(", stringify!($Max), "));")] + #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".div_exact(2), None);")] /// ``` /// ```should_panic /// #![feature(exact_div)] - #[doc = concat!("let _ = 64", stringify!($SelfT),".exact_div(0);")] + #[doc = concat!("let _ = 64", stringify!($SelfT),".div_exact(0);")] /// ``` /// ```should_panic /// #![feature(exact_div)] - #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.exact_div(-1);")] + #[doc = concat!("let _ = ", stringify!($SelfT), "::MIN.div_exact(-1);")] /// ``` #[unstable( feature = "exact_div", @@ -1055,7 +1055,7 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn exact_div(self, rhs: Self) -> Option { + pub const fn div_exact(self, rhs: Self) -> Option { if self % rhs != 0 { None } else { @@ -1069,7 +1069,7 @@ macro_rules! int_impl { /// /// This results in undefined behavior when `rhs == 0`, `self % rhs != 0`, or #[doc = concat!("`self == ", stringify!($SelfT), "::MIN && rhs == -1`,")] - /// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`. + /// i.e. when [`checked_div_exact`](Self::checked_div_exact) would return `None`. #[unstable( feature = "exact_div", issue = "139911", @@ -1077,10 +1077,10 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self { + pub const unsafe fn unchecked_div_exact(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, - concat!(stringify!($SelfT), "::unchecked_exact_div cannot overflow, divide by zero, or leave a remainder"), + concat!(stringify!($SelfT), "::unchecked_div_exact cannot overflow, divide by zero, or leave a remainder"), ( lhs: $SelfT = self, rhs: $SelfT = rhs, @@ -1431,17 +1431,17 @@ macro_rules! int_impl { /// ``` /// #![feature(exact_bitshifts)] /// - #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")] - #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 2), Some(1 << ", stringify!($SelfT), "::BITS - 2));")] - #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(", stringify!($SelfT), "::BITS - 1), None);")] - #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 2), Some(-0x2 << ", stringify!($SelfT), "::BITS - 2));")] - #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").exact_shl(", stringify!($SelfT), "::BITS - 1), None);")] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".shl_exact(4), Some(0x10));")] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".shl_exact(", stringify!($SelfT), "::BITS - 2), Some(1 << ", stringify!($SelfT), "::BITS - 2));")] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".shl_exact(", stringify!($SelfT), "::BITS - 1), None);")] + #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").shl_exact(", stringify!($SelfT), "::BITS - 2), Some(-0x2 << ", stringify!($SelfT), "::BITS - 2));")] + #[doc = concat!("assert_eq!((-0x2", stringify!($SelfT), ").shl_exact(", stringify!($SelfT), "::BITS - 1), None);")] /// ``` #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> { + pub const fn shl_exact(self, rhs: u32) -> Option<$SelfT> { if rhs < self.leading_zeros() || rhs < self.leading_ones() { // SAFETY: rhs is checked above Some(unsafe { self.unchecked_shl(rhs) }) @@ -1458,16 +1458,16 @@ macro_rules! int_impl { /// /// This results in undefined behavior when `rhs >= self.leading_zeros() && rhs >= /// self.leading_ones()` i.e. when - #[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")] + #[doc = concat!("[`", stringify!($SelfT), "::shl_exact`]")] /// would return `None`. #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT { + pub const unsafe fn unchecked_shl_exact(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( check_library_ub, - concat!(stringify!($SelfT), "::unchecked_exact_shl cannot shift out bits that would change the value of the first bit"), + concat!(stringify!($SelfT), "::unchecked_shl_exact cannot shift out bits that would change the value of the first bit"), ( zeros: u32 = self.leading_zeros(), ones: u32 = self.leading_ones(), @@ -1503,7 +1503,7 @@ macro_rules! int_impl { } } - /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// Strict shift right. Computes `self >> rhs`, panicking if `rhs` is /// larger than or equal to the number of bits in `self`. /// /// # Panics @@ -1611,14 +1611,14 @@ macro_rules! int_impl { /// ``` /// #![feature(exact_bitshifts)] /// - #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")] - #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".shr_exact(4), Some(0x1));")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".shr_exact(5), None);")] /// ``` #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> { + pub const fn shr_exact(self, rhs: u32) -> Option<$SelfT> { if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS { // SAFETY: rhs is checked above Some(unsafe { self.unchecked_shr(rhs) }) @@ -1636,16 +1636,16 @@ macro_rules! int_impl { /// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >= #[doc = concat!(stringify!($SelfT), "::BITS`")] /// i.e. when - #[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")] + #[doc = concat!("[`", stringify!($SelfT), "::shr_exact`]")] /// would return `None`. #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT { + pub const unsafe fn unchecked_shr_exact(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( check_library_ub, - concat!(stringify!($SelfT), "::unchecked_exact_shr cannot shift out non-zero bits"), + concat!(stringify!($SelfT), "::unchecked_shr_exact cannot shift out non-zero bits"), ( zeros: u32 = self.trailing_zeros(), bits: u32 = <$SelfT>::BITS, diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 2996e7b00da4e..d38d3a1a5ad46 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1222,10 +1222,10 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(exact_div)] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(2), Some(32));")] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(32), Some(2));")] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_exact_div(0), None);")] - #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".checked_exact_div(2), None);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_div_exact(2), Some(32));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_div_exact(32), Some(2));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".checked_div_exact(0), None);")] + #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".checked_div_exact(2), None);")] /// ``` #[unstable( feature = "exact_div", @@ -1234,7 +1234,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_exact_div(self, rhs: Self) -> Option { + pub const fn checked_div_exact(self, rhs: Self) -> Option { if intrinsics::unlikely(rhs == 0) { None } else { @@ -1259,9 +1259,9 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(exact_div)] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(2), Some(32));")] - #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".exact_div(32), Some(2));")] - #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".exact_div(2), None);")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".div_exact(2), Some(32));")] + #[doc = concat!("assert_eq!(64", stringify!($SelfT), ".div_exact(32), Some(2));")] + #[doc = concat!("assert_eq!(65", stringify!($SelfT), ".div_exact(2), None);")] /// ``` #[unstable( feature = "exact_div", @@ -1271,7 +1271,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] - pub const fn exact_div(self, rhs: Self) -> Option { + pub const fn div_exact(self, rhs: Self) -> Option { if self % rhs != 0 { None } else { @@ -1284,7 +1284,7 @@ macro_rules! uint_impl { /// # Safety /// /// This results in undefined behavior when `rhs == 0` or `self % rhs != 0`, - /// i.e. when [`checked_exact_div`](Self::checked_exact_div) would return `None`. + /// i.e. when [`checked_div_exact`](Self::checked_div_exact) would return `None`. #[unstable( feature = "exact_div", issue = "139911", @@ -1292,10 +1292,10 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_div(self, rhs: Self) -> Self { + pub const unsafe fn unchecked_div_exact(self, rhs: Self) -> Self { assert_unsafe_precondition!( check_language_ub, - concat!(stringify!($SelfT), "::unchecked_exact_div divide by zero or leave a remainder"), + concat!(stringify!($SelfT), "::unchecked_div_exact divide by zero or leave a remainder"), ( lhs: $SelfT = self, rhs: $SelfT = rhs, @@ -1830,14 +1830,14 @@ macro_rules! uint_impl { /// ``` /// #![feature(exact_bitshifts)] /// - #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(4), Some(0x10));")] - #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".exact_shl(129), None);")] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".shl_exact(4), Some(0x10));")] + #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".shl_exact(129), None);")] /// ``` #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn exact_shl(self, rhs: u32) -> Option<$SelfT> { + pub const fn shl_exact(self, rhs: u32) -> Option<$SelfT> { if rhs <= self.leading_zeros() && rhs < <$SelfT>::BITS { // SAFETY: rhs is checked above Some(unsafe { self.unchecked_shl(rhs) }) @@ -1855,16 +1855,16 @@ macro_rules! uint_impl { /// This results in undefined behavior when `rhs > self.leading_zeros() || rhs >= #[doc = concat!(stringify!($SelfT), "::BITS`")] /// i.e. when - #[doc = concat!("[`", stringify!($SelfT), "::exact_shl`]")] + #[doc = concat!("[`", stringify!($SelfT), "::shl_exact`]")] /// would return `None`. #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_shl(self, rhs: u32) -> $SelfT { + pub const unsafe fn unchecked_shl_exact(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( check_library_ub, - concat!(stringify!($SelfT), "::exact_shl_unchecked cannot shift out non-zero bits"), + concat!(stringify!($SelfT), "::unchecked_shl_exact cannot shift out non-zero bits"), ( zeros: u32 = self.leading_zeros(), bits: u32 = <$SelfT>::BITS, @@ -1900,7 +1900,7 @@ macro_rules! uint_impl { } } - /// Strict shift right. Computes `self >> rhs`, panicking `rhs` is + /// Strict shift right. Computes `self >> rhs`, panicking if `rhs` is /// larger than or equal to the number of bits in `self`. /// /// # Panics @@ -2002,14 +2002,14 @@ macro_rules! uint_impl { /// ``` /// #![feature(exact_bitshifts)] /// - #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(4), Some(0x1));")] - #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".exact_shr(5), None);")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".shr_exact(4), Some(0x1));")] + #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".shr_exact(5), None);")] /// ``` #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn exact_shr(self, rhs: u32) -> Option<$SelfT> { + pub const fn shr_exact(self, rhs: u32) -> Option<$SelfT> { if rhs <= self.trailing_zeros() && rhs < <$SelfT>::BITS { // SAFETY: rhs is checked above Some(unsafe { self.unchecked_shr(rhs) }) @@ -2027,16 +2027,16 @@ macro_rules! uint_impl { /// This results in undefined behavior when `rhs > self.trailing_zeros() || rhs >= #[doc = concat!(stringify!($SelfT), "::BITS`")] /// i.e. when - #[doc = concat!("[`", stringify!($SelfT), "::exact_shr`]")] + #[doc = concat!("[`", stringify!($SelfT), "::shr_exact`]")] /// would return `None`. #[unstable(feature = "exact_bitshifts", issue = "144336")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn unchecked_exact_shr(self, rhs: u32) -> $SelfT { + pub const unsafe fn unchecked_shr_exact(self, rhs: u32) -> $SelfT { assert_unsafe_precondition!( check_library_ub, - concat!(stringify!($SelfT), "::exact_shr_unchecked cannot shift out non-zero bits"), + concat!(stringify!($SelfT), "::unchecked_shr_exact cannot shift out non-zero bits"), ( zeros: u32 = self.trailing_zeros(), bits: u32 = <$SelfT>::BITS, diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index e640b7853bd94..37336f49ef1b6 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -724,42 +724,42 @@ macro_rules! int_module { } } - const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; - const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; - const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; - const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; - const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; - const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; - const EXACT_DIV_SUCCESS_DIVIDEND3: $T = -91; - const EXACT_DIV_SUCCESS_DIVISOR3: $T = 13; - const EXACT_DIV_SUCCESS_QUOTIENT3: $T = -7; - const EXACT_DIV_SUCCESS_DIVIDEND4: $T = -57; - const EXACT_DIV_SUCCESS_DIVISOR4: $T = -3; - const EXACT_DIV_SUCCESS_QUOTIENT4: $T = 19; + const DIV_EXACT_SUCCESS_DIVIDEND1: $T = 42; + const DIV_EXACT_SUCCESS_DIVISOR1: $T = 6; + const DIV_EXACT_SUCCESS_QUOTIENT1: $T = 7; + const DIV_EXACT_SUCCESS_DIVIDEND2: $T = 18; + const DIV_EXACT_SUCCESS_DIVISOR2: $T = 3; + const DIV_EXACT_SUCCESS_QUOTIENT2: $T = 6; + const DIV_EXACT_SUCCESS_DIVIDEND3: $T = -91; + const DIV_EXACT_SUCCESS_DIVISOR3: $T = 13; + const DIV_EXACT_SUCCESS_QUOTIENT3: $T = -7; + const DIV_EXACT_SUCCESS_DIVIDEND4: $T = -57; + const DIV_EXACT_SUCCESS_DIVISOR4: $T = -3; + const DIV_EXACT_SUCCESS_QUOTIENT4: $T = 19; test_runtime_and_compiletime! { - fn test_exact_div() { + fn test_div_exact() { // 42 / 6 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND1, DIV_EXACT_SUCCESS_DIVISOR1), Some(DIV_EXACT_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND1, DIV_EXACT_SUCCESS_DIVISOR1), Some(DIV_EXACT_SUCCESS_QUOTIENT1)); // 18 / 3 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND2, DIV_EXACT_SUCCESS_DIVISOR2), Some(DIV_EXACT_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND2, DIV_EXACT_SUCCESS_DIVISOR2), Some(DIV_EXACT_SUCCESS_QUOTIENT2)); // -91 / 13 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND3, DIV_EXACT_SUCCESS_DIVISOR3), Some(DIV_EXACT_SUCCESS_QUOTIENT3)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND3, DIV_EXACT_SUCCESS_DIVISOR3), Some(DIV_EXACT_SUCCESS_QUOTIENT3)); // -57 / -3 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND4, DIV_EXACT_SUCCESS_DIVISOR4), Some(DIV_EXACT_SUCCESS_QUOTIENT4)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND4, DIV_EXACT_SUCCESS_DIVISOR4), Some(DIV_EXACT_SUCCESS_QUOTIENT4)); // failures - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(1, 2), None); - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None); - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(<$T>::MIN, -1), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(0, 0), None); } } }; diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index c1cfc448f14f5..b89a371efcc25 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -595,27 +595,27 @@ macro_rules! uint_module { } } - const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; - const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; - const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; - const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; - const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; - const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + const DIV_EXACT_SUCCESS_DIVIDEND1: $T = 42; + const DIV_EXACT_SUCCESS_DIVISOR1: $T = 6; + const DIV_EXACT_SUCCESS_QUOTIENT1: $T = 7; + const DIV_EXACT_SUCCESS_DIVIDEND2: $T = 18; + const DIV_EXACT_SUCCESS_DIVISOR2: $T = 3; + const DIV_EXACT_SUCCESS_QUOTIENT2: $T = 6; test_runtime_and_compiletime! { - fn test_exact_div() { + fn test_div_exact() { // 42 / 6 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND1, DIV_EXACT_SUCCESS_DIVISOR1), Some(DIV_EXACT_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND1, DIV_EXACT_SUCCESS_DIVISOR1), Some(DIV_EXACT_SUCCESS_QUOTIENT1)); // 18 / 3 - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(DIV_EXACT_SUCCESS_DIVIDEND2, DIV_EXACT_SUCCESS_DIVISOR2), Some(DIV_EXACT_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(DIV_EXACT_SUCCESS_DIVIDEND2, DIV_EXACT_SUCCESS_DIVISOR2), Some(DIV_EXACT_SUCCESS_QUOTIENT2)); // failures - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); - assert_eq_const_safe!(Option<$T>: <$T>::exact_div(1, 2), None); - assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::div_exact(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_div_exact(0, 0), None); } } }; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 909262d563e9f..edafc9e7a089f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -4,6 +4,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; +use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::thin_vec::ThinVec; use rustc_hir as hir; use rustc_hir::attrs::{self, DeprecatedSince}; @@ -988,3 +989,55 @@ fn format_integer_type(it: rustc_abi::IntegerType) -> String { } .to_owned() } + +pub(super) fn target(sess: &rustc_session::Session) -> Target { + // Build a set of which features are enabled on this target + let globally_enabled_features: FxHashSet<&str> = + sess.unstable_target_features.iter().map(|name| name.as_str()).collect(); + + // Build a map of target feature stability by feature name + use rustc_target::target_features::Stability; + let feature_stability: FxHashMap<&str, Stability> = sess + .target + .rust_target_features() + .iter() + .copied() + .map(|(name, stability, _)| (name, stability)) + .collect(); + + Target { + triple: sess.opts.target_triple.tuple().into(), + target_features: sess + .target + .rust_target_features() + .iter() + .copied() + .filter(|(_, stability, _)| { + // Describe only target features which the user can toggle + stability.toggle_allowed().is_ok() + }) + .map(|(name, stability, implied_features)| { + TargetFeature { + name: name.into(), + unstable_feature_gate: match stability { + Stability::Unstable(feature_gate) => Some(feature_gate.as_str().into()), + _ => None, + }, + implies_features: implied_features + .iter() + .copied() + .filter(|name| { + // Imply only target features which the user can toggle + feature_stability + .get(name) + .map(|stability| stability.toggle_allowed().is_ok()) + .unwrap_or(false) + }) + .map(String::from) + .collect(), + globally_enabled: globally_enabled_features.contains(name), + } + }) + .collect(), + } +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index b724d7e866a05..b020e3d924a46 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -14,7 +14,6 @@ use std::io::{BufWriter, Write, stdout}; use std::path::PathBuf; use std::rc::Rc; -use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -123,58 +122,6 @@ impl<'tcx> JsonRenderer<'tcx> { } } -fn target(sess: &rustc_session::Session) -> types::Target { - // Build a set of which features are enabled on this target - let globally_enabled_features: FxHashSet<&str> = - sess.unstable_target_features.iter().map(|name| name.as_str()).collect(); - - // Build a map of target feature stability by feature name - use rustc_target::target_features::Stability; - let feature_stability: FxHashMap<&str, Stability> = sess - .target - .rust_target_features() - .iter() - .copied() - .map(|(name, stability, _)| (name, stability)) - .collect(); - - types::Target { - triple: sess.opts.target_triple.tuple().into(), - target_features: sess - .target - .rust_target_features() - .iter() - .copied() - .filter(|(_, stability, _)| { - // Describe only target features which the user can toggle - stability.toggle_allowed().is_ok() - }) - .map(|(name, stability, implied_features)| { - types::TargetFeature { - name: name.into(), - unstable_feature_gate: match stability { - Stability::Unstable(feature_gate) => Some(feature_gate.as_str().into()), - _ => None, - }, - implies_features: implied_features - .iter() - .copied() - .filter(|name| { - // Imply only target features which the user can toggle - feature_stability - .get(name) - .map(|stability| stability.toggle_allowed().is_ok()) - .unwrap_or(false) - }) - .map(String::from) - .collect(), - globally_enabled: globally_enabled_features.contains(name), - } - }) - .collect(), - } -} - impl<'tcx> JsonRenderer<'tcx> { pub(crate) fn init( krate: clean::Crate, @@ -317,7 +264,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { // multiple targets: https://github.com/rust-lang/rust/pull/137632 // // We want to describe a single target, so pass tcx.sess rather than tcx. - let target = target(self.tcx.sess); + let target = conversions::target(self.tcx.sess); debug!("Constructing Output"); let output_crate = types::Crate { diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 7c1bbe940321f..8e9c28e69ea7b 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -14,6 +14,7 @@ use crate::directives::directive_names::{ KNOWN_DIRECTIVE_NAMES_SET, KNOWN_HTMLDOCCK_DIRECTIVE_NAMES, KNOWN_JSONDOCCK_DIRECTIVE_NAMES, }; pub(crate) use crate::directives::file::FileDirectives; +use crate::directives::handlers::DIRECTIVE_HANDLERS_MAP; use crate::directives::line::{DirectiveLine, line_directive}; use crate::directives::needs::CachedNeedsConditions; use crate::edition::{Edition, parse_edition}; @@ -26,6 +27,7 @@ mod auxiliary; mod cfg; mod directive_names; mod file; +mod handlers; mod line; mod needs; #[cfg(test)] @@ -359,269 +361,9 @@ impl TestProps { return; } - use directives::*; - - config.push_name_value_directive( - ln, - ERROR_PATTERN, - &mut self.error_patterns, - |r| r, - ); - config.push_name_value_directive( - ln, - REGEX_ERROR_PATTERN, - &mut self.regex_error_patterns, - |r| r, - ); - - config.push_name_value_directive(ln, DOC_FLAGS, &mut self.doc_flags, |r| r); - - fn split_flags(flags: &str) -> Vec { - // Individual flags can be single-quoted to preserve spaces; see - // . - flags - .split('\'') - .enumerate() - .flat_map(|(i, f)| { - if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() } - }) - .map(move |s| s.to_owned()) - .collect::>() - } - - if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { - let flags = split_flags(&flags); - for (i, flag) in flags.iter().enumerate() { - if flag == "--edition" || flag.starts_with("--edition=") { - panic!("you must use `//@ edition` to configure the edition"); - } - if (flag == "-C" - && flags.get(i + 1).is_some_and(|v| v.starts_with("incremental="))) - || flag.starts_with("-Cincremental=") - { - panic!( - "you must use `//@ incremental` to enable incremental compilation" - ); - } - } - self.compile_flags.extend(flags); - } - - if let Some(range) = parse_edition_range(config, ln) { - self.edition = Some(range.edition_to_test(config.edition)); - } - - config.parse_and_update_revisions(ln, &mut self.revisions); - - if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) { - self.run_flags.extend(split_flags(&flags)); - } - - if self.pp_exact.is_none() { - self.pp_exact = config.parse_pp_exact(ln); - } - - config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice); - config.set_name_directive(ln, BUILD_AUX_DOCS, &mut self.build_aux_docs); - config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut self.unique_doc_out_dir); - - config.set_name_directive(ln, FORCE_HOST, &mut self.force_host); - config.set_name_directive(ln, CHECK_STDOUT, &mut self.check_stdout); - config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut self.check_run_results); - config.set_name_directive( - ln, - DONT_CHECK_COMPILER_STDOUT, - &mut self.dont_check_compiler_stdout, - ); - config.set_name_directive( - ln, - DONT_CHECK_COMPILER_STDERR, - &mut self.dont_check_compiler_stderr, - ); - config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic); - - if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { - self.pretty_mode = m; - } - - config.set_name_directive( - ln, - PRETTY_COMPARE_ONLY, - &mut self.pretty_compare_only, - ); - - // Call a helper method to deal with aux-related directives. - parse_and_update_aux(config, ln, &mut self.aux); - - config.push_name_value_directive( - ln, - EXEC_ENV, - &mut self.exec_env, - Config::parse_env, - ); - config.push_name_value_directive( - ln, - UNSET_EXEC_ENV, - &mut self.unset_exec_env, - |r| r.trim().to_owned(), - ); - config.push_name_value_directive( - ln, - RUSTC_ENV, - &mut self.rustc_env, - Config::parse_env, - ); - config.push_name_value_directive( - ln, - UNSET_RUSTC_ENV, - &mut self.unset_rustc_env, - |r| r.trim().to_owned(), - ); - config.push_name_value_directive( - ln, - FORBID_OUTPUT, - &mut self.forbid_output, - |r| r, - ); - config.set_name_directive( - ln, - CHECK_TEST_LINE_NUMBERS_MATCH, - &mut self.check_test_line_numbers_match, - ); - - self.update_pass_mode(ln, config); - self.update_fail_mode(ln, config); - - config.set_name_directive(ln, IGNORE_PASS, &mut self.ignore_pass); - - if let Some(NormalizeRule { kind, regex, replacement }) = - config.parse_custom_normalization(ln) - { - let rule_tuple = (regex, replacement); - match kind { - NormalizeKind::Stdout => self.normalize_stdout.push(rule_tuple), - NormalizeKind::Stderr => self.normalize_stderr.push(rule_tuple), - NormalizeKind::Stderr32bit => { - if config.target_cfg().pointer_width == 32 { - self.normalize_stderr.push(rule_tuple); - } - } - NormalizeKind::Stderr64bit => { - if config.target_cfg().pointer_width == 64 { - self.normalize_stderr.push(rule_tuple); - } - } - } - } - - if let Some(code) = config - .parse_name_value_directive(ln, FAILURE_STATUS) - .and_then(|code| code.trim().parse::().ok()) - { - self.failure_status = Some(code); - } - - config.set_name_directive( - ln, - DONT_CHECK_FAILURE_STATUS, - &mut self.dont_check_failure_status, - ); - - config.set_name_directive(ln, RUN_RUSTFIX, &mut self.run_rustfix); - config.set_name_directive( - ln, - RUSTFIX_ONLY_MACHINE_APPLICABLE, - &mut self.rustfix_only_machine_applicable, - ); - config.set_name_value_directive( - ln, - ASSEMBLY_OUTPUT, - &mut self.assembly_output, - |r| r.trim().to_string(), - ); - config.set_name_directive( - ln, - STDERR_PER_BITWIDTH, - &mut self.stderr_per_bitwidth, - ); - config.set_name_directive(ln, INCREMENTAL, &mut self.incremental); - - // Unlike the other `name_value_directive`s this needs to be handled manually, - // because it sets a `bool` flag. - if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { - let known_bug = known_bug.trim(); - if known_bug == "unknown" - || known_bug.split(',').all(|issue_ref| { - issue_ref - .trim() - .split_once('#') - .filter(|(_, number)| { - number.chars().all(|digit| digit.is_numeric()) - }) - .is_some() - }) - { - self.known_bug = true; - } else { - panic!( - "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." - ); - } - } else if config.parse_name_directive(ln, KNOWN_BUG) { - panic!( - "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." - ); - } - - config.set_name_value_directive( - ln, - TEST_MIR_PASS, - &mut self.mir_unit_test, - |s| s.trim().to_string(), - ); - config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); - - if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { - self.llvm_cov_flags.extend(split_flags(&flags)); - } - - if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) { - self.filecheck_flags.extend(split_flags(&flags)); - } - - config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut self.no_auto_check_cfg); - - self.update_add_minicore(ln, config); - - if let Some(flags) = - config.parse_name_value_directive(ln, MINICORE_COMPILE_FLAGS) - { - let flags = split_flags(&flags); - for flag in &flags { - if flag == "--edition" || flag.starts_with("--edition=") { - panic!("you must use `//@ edition` to configure the edition"); - } - } - self.minicore_compile_flags.extend(flags); + if let Some(handler) = DIRECTIVE_HANDLERS_MAP.get(ln.name) { + handler.handle(config, ln, self); } - - if let Some(err_kind) = - config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) - { - self.dont_require_annotations - .insert(ErrorKind::expect_from_user_str(err_kind.trim())); - } - - config.set_name_directive( - ln, - DISABLE_GDB_PRETTY_PRINTERS, - &mut self.disable_gdb_pretty_printers, - ); - config.set_name_directive( - ln, - COMPARE_OUTPUT_BY_LINES, - &mut self.compare_output_by_lines, - ); }, ); } @@ -1691,3 +1433,16 @@ impl EditionRange { } } } + +fn split_flags(flags: &str) -> Vec { + // Individual flags can be single-quoted to preserve spaces; see + // . + // FIXME(#147955): Replace this ad-hoc quoting with an escape/quote system that + // is closer to what actual shells do, so that it's more flexible and familiar. + flags + .split('\'') + .enumerate() + .flat_map(|(i, f)| if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }) + .map(move |s| s.to_owned()) + .collect::>() +} diff --git a/src/tools/compiletest/src/directives/handlers.rs b/src/tools/compiletest/src/directives/handlers.rs new file mode 100644 index 0000000000000..b53bda90f626b --- /dev/null +++ b/src/tools/compiletest/src/directives/handlers.rs @@ -0,0 +1,372 @@ +use std::collections::HashMap; +use std::sync::{Arc, LazyLock}; + +use crate::common::Config; +use crate::directives::{ + DirectiveLine, NormalizeKind, NormalizeRule, TestProps, parse_and_update_aux, + parse_edition_range, split_flags, +}; +use crate::errors::ErrorKind; + +pub(crate) static DIRECTIVE_HANDLERS_MAP: LazyLock> = + LazyLock::new(make_directive_handlers_map); + +#[derive(Clone)] +pub(crate) struct Handler { + handler_fn: Arc) + Send + Sync>, +} + +impl Handler { + pub(crate) fn handle(&self, config: &Config, line: &DirectiveLine<'_>, props: &mut TestProps) { + (self.handler_fn)(HandlerArgs { config, line, props }) + } +} + +struct HandlerArgs<'a> { + config: &'a Config, + line: &'a DirectiveLine<'a>, + props: &'a mut TestProps, +} + +/// Intermediate data structure, used for defining a list of handlers. +struct NamedHandler { + names: Vec<&'static str>, + handler: Handler, +} + +/// Helper function to create a simple handler, so that changes can be made +/// to the handler struct without disturbing existing handler declarations. +fn handler( + name: &'static str, + handler_fn: impl Fn(&Config, &DirectiveLine<'_>, &mut TestProps) + Send + Sync + 'static, +) -> NamedHandler { + multi_handler(&[name], handler_fn) +} + +/// Associates the same handler function with multiple directive names. +fn multi_handler( + names: &[&'static str], + handler_fn: impl Fn(&Config, &DirectiveLine<'_>, &mut TestProps) + Send + Sync + 'static, +) -> NamedHandler { + NamedHandler { + names: names.to_owned(), + handler: Handler { + handler_fn: Arc::new(move |args| handler_fn(args.config, args.line, args.props)), + }, + } +} + +fn make_directive_handlers_map() -> HashMap<&'static str, Handler> { + use crate::directives::directives::*; + + // FIXME(Zalathar): Now that most directive-processing has been extracted + // into individual handlers, there should be many opportunities to simplify + // these handlers, e.g. by getting rid of now-redundant name checks. + + let handlers: Vec = vec![ + handler(ERROR_PATTERN, |config, ln, props| { + config.push_name_value_directive(ln, ERROR_PATTERN, &mut props.error_patterns, |r| r); + }), + handler(REGEX_ERROR_PATTERN, |config, ln, props| { + config.push_name_value_directive( + ln, + REGEX_ERROR_PATTERN, + &mut props.regex_error_patterns, + |r| r, + ); + }), + handler(DOC_FLAGS, |config, ln, props| { + config.push_name_value_directive(ln, DOC_FLAGS, &mut props.doc_flags, |r| r); + }), + handler(COMPILE_FLAGS, |config, ln, props| { + if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) { + let flags = split_flags(&flags); + // FIXME(#147955): Extract and unify this with other handlers that + // check compiler flags, e.g. MINICORE_COMPILE_FLAGS. + for (i, flag) in flags.iter().enumerate() { + if flag == "--edition" || flag.starts_with("--edition=") { + panic!("you must use `//@ edition` to configure the edition"); + } + if (flag == "-C" + && flags.get(i + 1).is_some_and(|v| v.starts_with("incremental="))) + || flag.starts_with("-Cincremental=") + { + panic!("you must use `//@ incremental` to enable incremental compilation"); + } + } + props.compile_flags.extend(flags); + } + }), + handler("edition", |config, ln, props| { + if let Some(range) = parse_edition_range(config, ln) { + props.edition = Some(range.edition_to_test(config.edition)); + } + }), + handler("revisions", |config, ln, props| { + config.parse_and_update_revisions(ln, &mut props.revisions); + }), + handler(RUN_FLAGS, |config, ln, props| { + if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) { + props.run_flags.extend(split_flags(&flags)); + } + }), + handler("pp-exact", |config, ln, props| { + if props.pp_exact.is_none() { + props.pp_exact = config.parse_pp_exact(ln); + } + }), + handler(SHOULD_ICE, |config, ln, props| { + config.set_name_directive(ln, SHOULD_ICE, &mut props.should_ice); + }), + handler(BUILD_AUX_DOCS, |config, ln, props| { + config.set_name_directive(ln, BUILD_AUX_DOCS, &mut props.build_aux_docs); + }), + handler(UNIQUE_DOC_OUT_DIR, |config, ln, props| { + config.set_name_directive(ln, UNIQUE_DOC_OUT_DIR, &mut props.unique_doc_out_dir); + }), + handler(FORCE_HOST, |config, ln, props| { + config.set_name_directive(ln, FORCE_HOST, &mut props.force_host); + }), + handler(CHECK_STDOUT, |config, ln, props| { + config.set_name_directive(ln, CHECK_STDOUT, &mut props.check_stdout); + }), + handler(CHECK_RUN_RESULTS, |config, ln, props| { + config.set_name_directive(ln, CHECK_RUN_RESULTS, &mut props.check_run_results); + }), + handler(DONT_CHECK_COMPILER_STDOUT, |config, ln, props| { + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDOUT, + &mut props.dont_check_compiler_stdout, + ); + }), + handler(DONT_CHECK_COMPILER_STDERR, |config, ln, props| { + config.set_name_directive( + ln, + DONT_CHECK_COMPILER_STDERR, + &mut props.dont_check_compiler_stderr, + ); + }), + handler(NO_PREFER_DYNAMIC, |config, ln, props| { + config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut props.no_prefer_dynamic); + }), + handler(PRETTY_MODE, |config, ln, props| { + if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE) { + props.pretty_mode = m; + } + }), + handler(PRETTY_COMPARE_ONLY, |config, ln, props| { + config.set_name_directive(ln, PRETTY_COMPARE_ONLY, &mut props.pretty_compare_only); + }), + multi_handler( + &[AUX_BUILD, AUX_BIN, AUX_CRATE, PROC_MACRO, AUX_CODEGEN_BACKEND], + |config, ln, props| { + // Call a helper method to deal with aux-related directives. + parse_and_update_aux(config, ln, &mut props.aux); + }, + ), + handler(EXEC_ENV, |config, ln, props| { + config.push_name_value_directive(ln, EXEC_ENV, &mut props.exec_env, Config::parse_env); + }), + handler(UNSET_EXEC_ENV, |config, ln, props| { + config.push_name_value_directive(ln, UNSET_EXEC_ENV, &mut props.unset_exec_env, |r| { + r.trim().to_owned() + }); + }), + handler(RUSTC_ENV, |config, ln, props| { + config.push_name_value_directive( + ln, + RUSTC_ENV, + &mut props.rustc_env, + Config::parse_env, + ); + }), + handler(UNSET_RUSTC_ENV, |config, ln, props| { + config.push_name_value_directive( + ln, + UNSET_RUSTC_ENV, + &mut props.unset_rustc_env, + |r| r.trim().to_owned(), + ); + }), + handler(FORBID_OUTPUT, |config, ln, props| { + config.push_name_value_directive(ln, FORBID_OUTPUT, &mut props.forbid_output, |r| r); + }), + handler(CHECK_TEST_LINE_NUMBERS_MATCH, |config, ln, props| { + config.set_name_directive( + ln, + CHECK_TEST_LINE_NUMBERS_MATCH, + &mut props.check_test_line_numbers_match, + ); + }), + multi_handler(&["check-pass", "build-pass", "run-pass"], |config, ln, props| { + props.update_pass_mode(ln, config); + }), + multi_handler( + &["check-fail", "build-fail", "run-fail", "run-crash", "run-fail-or-crash"], + |config, ln, props| { + props.update_fail_mode(ln, config); + }, + ), + handler(IGNORE_PASS, |config, ln, props| { + config.set_name_directive(ln, IGNORE_PASS, &mut props.ignore_pass); + }), + multi_handler( + &[ + "normalize-stdout", + "normalize-stderr", + "normalize-stderr-32bit", + "normalize-stderr-64bit", + ], + |config, ln, props| { + if let Some(NormalizeRule { kind, regex, replacement }) = + config.parse_custom_normalization(ln) + { + let rule_tuple = (regex, replacement); + match kind { + NormalizeKind::Stdout => props.normalize_stdout.push(rule_tuple), + NormalizeKind::Stderr => props.normalize_stderr.push(rule_tuple), + NormalizeKind::Stderr32bit => { + if config.target_cfg().pointer_width == 32 { + props.normalize_stderr.push(rule_tuple); + } + } + NormalizeKind::Stderr64bit => { + if config.target_cfg().pointer_width == 64 { + props.normalize_stderr.push(rule_tuple); + } + } + } + } + }, + ), + handler(FAILURE_STATUS, |config, ln, props| { + if let Some(code) = config + .parse_name_value_directive(ln, FAILURE_STATUS) + .and_then(|code| code.trim().parse::().ok()) + { + props.failure_status = Some(code); + } + }), + handler(DONT_CHECK_FAILURE_STATUS, |config, ln, props| { + config.set_name_directive( + ln, + DONT_CHECK_FAILURE_STATUS, + &mut props.dont_check_failure_status, + ); + }), + handler(RUN_RUSTFIX, |config, ln, props| { + config.set_name_directive(ln, RUN_RUSTFIX, &mut props.run_rustfix); + }), + handler(RUSTFIX_ONLY_MACHINE_APPLICABLE, |config, ln, props| { + config.set_name_directive( + ln, + RUSTFIX_ONLY_MACHINE_APPLICABLE, + &mut props.rustfix_only_machine_applicable, + ); + }), + handler(ASSEMBLY_OUTPUT, |config, ln, props| { + config.set_name_value_directive(ln, ASSEMBLY_OUTPUT, &mut props.assembly_output, |r| { + r.trim().to_string() + }); + }), + handler(STDERR_PER_BITWIDTH, |config, ln, props| { + config.set_name_directive(ln, STDERR_PER_BITWIDTH, &mut props.stderr_per_bitwidth); + }), + handler(INCREMENTAL, |config, ln, props| { + config.set_name_directive(ln, INCREMENTAL, &mut props.incremental); + }), + handler(KNOWN_BUG, |config, ln, props| { + // Unlike the other `name_value_directive`s this needs to be handled manually, + // because it sets a `bool` flag. + if let Some(known_bug) = config.parse_name_value_directive(ln, KNOWN_BUG) { + let known_bug = known_bug.trim(); + if known_bug == "unknown" + || known_bug.split(',').all(|issue_ref| { + issue_ref + .trim() + .split_once('#') + .filter(|(_, number)| number.chars().all(|digit| digit.is_numeric())) + .is_some() + }) + { + props.known_bug = true; + } else { + panic!( + "Invalid known-bug value: {known_bug}\nIt requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + ); + } + } else if config.parse_name_directive(ln, KNOWN_BUG) { + panic!( + "Invalid known-bug attribute, requires comma-separated issue references (`#000` or `chalk#000`) or `known-bug: unknown`." + ); + } + }), + handler(TEST_MIR_PASS, |config, ln, props| { + config.set_name_value_directive(ln, TEST_MIR_PASS, &mut props.mir_unit_test, |s| { + s.trim().to_string() + }); + }), + handler(REMAP_SRC_BASE, |config, ln, props| { + config.set_name_directive(ln, REMAP_SRC_BASE, &mut props.remap_src_base); + }), + handler(LLVM_COV_FLAGS, |config, ln, props| { + if let Some(flags) = config.parse_name_value_directive(ln, LLVM_COV_FLAGS) { + props.llvm_cov_flags.extend(split_flags(&flags)); + } + }), + handler(FILECHECK_FLAGS, |config, ln, props| { + if let Some(flags) = config.parse_name_value_directive(ln, FILECHECK_FLAGS) { + props.filecheck_flags.extend(split_flags(&flags)); + } + }), + handler(NO_AUTO_CHECK_CFG, |config, ln, props| { + config.set_name_directive(ln, NO_AUTO_CHECK_CFG, &mut props.no_auto_check_cfg); + }), + handler(ADD_MINICORE, |config, ln, props| { + props.update_add_minicore(ln, config); + }), + handler(MINICORE_COMPILE_FLAGS, |config, ln, props| { + if let Some(flags) = config.parse_name_value_directive(ln, MINICORE_COMPILE_FLAGS) { + let flags = split_flags(&flags); + // FIXME(#147955): Extract and unify this with other handlers that + // check compiler flags, e.g. COMPILE_FLAGS. + for flag in &flags { + if flag == "--edition" || flag.starts_with("--edition=") { + panic!("you must use `//@ edition` to configure the edition"); + } + } + props.minicore_compile_flags.extend(flags); + } + }), + handler(DONT_REQUIRE_ANNOTATIONS, |config, ln, props| { + if let Some(err_kind) = config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS) + { + props + .dont_require_annotations + .insert(ErrorKind::expect_from_user_str(err_kind.trim())); + } + }), + handler(DISABLE_GDB_PRETTY_PRINTERS, |config, ln, props| { + config.set_name_directive( + ln, + DISABLE_GDB_PRETTY_PRINTERS, + &mut props.disable_gdb_pretty_printers, + ); + }), + handler(COMPARE_OUTPUT_BY_LINES, |config, ln, props| { + config.set_name_directive( + ln, + COMPARE_OUTPUT_BY_LINES, + &mut props.compare_output_by_lines, + ); + }), + ]; + + handlers + .into_iter() + .flat_map(|NamedHandler { names, handler }| { + names.into_iter().map(move |name| (name, Handler::clone(&handler))) + }) + .collect() +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index e221c3a2daf2e..fe39e382ed5b6 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -1,14 +1,31 @@ +use std::collections::BTreeSet; + use camino::Utf8Path; use semver::Version; use crate::common::{Config, Debugger, TestMode}; use crate::directives::{ - self, AuxProps, DirectivesCache, EarlyProps, Edition, EditionRange, FileDirectives, - extract_llvm_version, extract_version_range, line_directive, parse_edition, - parse_normalize_rule, + self, AuxProps, DIRECTIVE_HANDLERS_MAP, DirectivesCache, EarlyProps, Edition, EditionRange, + FileDirectives, KNOWN_DIRECTIVE_NAMES_SET, extract_llvm_version, extract_version_range, + line_directive, parse_edition, parse_normalize_rule, }; use crate::executor::{CollectedTestDesc, ShouldFail}; +/// All directive handlers should have a name that is also in `KNOWN_DIRECTIVE_NAMES_SET`. +#[test] +fn handler_names() { + let unknown_names = DIRECTIVE_HANDLERS_MAP + .keys() + .copied() + .filter(|name| !KNOWN_DIRECTIVE_NAMES_SET.contains(name)) + .collect::>(); + + assert!( + unknown_names.is_empty(), + "Directive handler names not in `directive_names.rs`: {unknown_names:#?}" + ); +} + fn make_test_description( config: &Config, name: String, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 304ae00b01a92..a4f8e9ccaab99 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -715,7 +715,7 @@ impl<'tcx> MiriMachine<'tcx> { match target.arch { Arch::Wasm32 | Arch::Wasm64 => 64 * 1024, // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances Arch::AArch64 => { - if target.options.vendor.as_ref() == "apple" { + if target.is_like_darwin { // No "definitive" source, but see: // https://www.wwdcnotes.com/notes/wwdc20/10214/ // https://github.com/ziglang/zig/issues/11308 etc. diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-2.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-2.rs new file mode 100644 index 0000000000000..9d4ce84e93d23 --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-2.rs @@ -0,0 +1,481 @@ +//@ revisions: all strong none missing +//@ assembly-output: emit-asm +//@ ignore-apple slightly different policy on stack protection of arrays +//@ ignore-msvc stack check code uses different function names +//@ ignore-nvptx64 stack protector is not supported +//@ ignore-wasm32-bare +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +extern "C" { + fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8; + fn printf(fmt: *const u8, ...) -> i32; + fn funcall(p: *mut i32); + fn funcall2(p: *mut *mut i32); + fn funfloat(p: *mut f64); + fn funfloat2(p: *mut *mut f64); + fn testi_aux() -> f64; + fn getp() -> *mut i32; + fn dummy(_: ...) -> i32; + + static STR: [u8; 1]; +} + +extern "C-unwind" { + fn except(p: *mut i32); +} + +#[repr(C)] +struct Pair { + a: i32, + b: i32, +} + +#[repr(C)] +struct Nest { + first: Pair, + second: Pair, +} + +// test1: array of [16 x i8] +// CHECK-LABEL: test1{{:|\[}} +#[no_mangle] +pub fn test1(a: *const u8) { + let mut buf: [u8; 16] = [0; 16]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test2: array [4 x i8] +// CHECK-LABEL: test2{{:|\[}} +#[no_mangle] +pub fn test2(a: *const u8) { + let mut buf: [u8; 4] = [0; 4]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test3: no arrays / no nested arrays +// CHECK-LABEL: test3{{:|\[}} +#[no_mangle] +pub fn test3(a: *const u8) { + unsafe { + printf(STR.as_ptr(), a); + } + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test4: Address-of local taken (j = &a) +// CHECK-LABEL: test4{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test4() { + let mut a: i32 = 0; + + let mut j: *mut i32 = std::ptr::null_mut(); + + let tmp = std::ptr::read_volatile(&a); + let tmp2 = tmp.wrapping_add(1); + std::ptr::write_volatile(&mut a, tmp2); + + std::ptr::write_volatile(&mut j, &mut a); + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test5: PtrToInt Cast +// CHECK-LABEL: test5{{:|\[}} +#[no_mangle] +pub fn test5(a: i32) { + let ptr_val: usize = &a as *const i32 as usize; + + unsafe { + printf(STR.as_ptr(), ptr_val); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test6: Passing addr-of to function call +// CHECK-LABEL: test6{{:|\[}} +#[no_mangle] +pub fn test6(mut b: i32) { + unsafe { + funcall(&mut b as *mut i32); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test7: Addr-of in select instruction +// CHECK-LABEL: test7{{:|\[}} +#[no_mangle] +pub fn test7() { + let x: f64; + + unsafe { + let call = testi_aux(); + x = call; + + let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() }; + + printf(STR.as_ptr(), y); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test8: Addr-of in phi instruction +// CHECK-LABEL: test8{{:|\[}} +#[no_mangle] +pub fn test8() { + let mut _x: f64; + + unsafe { + let call = testi_aux(); + _x = call; + + let y: *const f64; + + if call > 3.14 { + let call1 = testi_aux(); + _x = call1; + y = std::ptr::null(); + } else { + if call > 1.0 { + y = &_x; + } else { + y = std::ptr::null(); + } + } + + printf(STR.as_ptr(), y); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test9: Addr-of struct element(GEP followed by store) +// CHECK-LABEL: test9{{:|\[}} +#[no_mangle] +pub fn test9() { + let mut c = Pair { a: 0, b: 0 }; + let b: *mut i32; + + unsafe { + let y: *mut i32 = &mut c.b; + + b = y; + + printf(STR.as_ptr(), b); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test10: Addr-of struct element, GEP followed by ptrtoint +// CHECK-LABEL: test10{{:|\[}} +#[no_mangle] +pub fn test10() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + let addr: i64 = y as i64; + + printf(STR.as_ptr(), addr); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test11: Addr-of struct element, GEP followed by callinst +// CHECK-LABEL: test11{{:|\[}} +#[no_mangle] +pub fn test11() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + printf(STR.as_ptr(), y); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12) +// CHECK-LABEL: test12{{:|\[}} +#[no_mangle] +pub fn test12() { + let mut a: i32 = 0; + + unsafe { + let add_ptr = (&mut a as *mut i32).offset(-12); + + printf(STR.as_ptr(), add_ptr); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test13: Addr-of a local cast to a ptr of a different type +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test13{{:|\[}} +#[no_mangle] +pub fn test13() { + let mut a: i32 = 0; + + unsafe { + let mut b: *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization + let tmp = std::ptr::read_volatile(&b); + + printf(STR.as_ptr(), tmp); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test14: Addr-of a local cast to a ptr of a different type (optimized) +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test14{{:|\[}} +#[no_mangle] +pub fn test14() { + let a: i32 = 0; + unsafe { + funfloat((&a as *const i32).cast::() as *mut f64); + } + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test15: Addr-of a variable passed into an invoke instruction +// CHECK-LABEL: test15{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test15() -> i32 { + let mut a: i32 = 0; + + except(&mut a as *mut i32); + + 0 + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test16: Addr-of a struct element passed into an invoke instruction +// (GEP followed by an invoke) +// CHECK-LABEL: test16{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test16() -> i32 { + let mut c = Pair { a: 0, b: 0 }; + + except(&mut c.a as *mut i32); + + 0 + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test17: Addr-of a pointer +// CHECK-LABEL: test17{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test17() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funcall2(tmp); + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test18: Addr-of a casted pointer +// CHECK-LABEL: test18{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test18() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funfloat2(tmp as *mut *mut f64); + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test19: array of [4 x i32] +// CHECK-LABEL: test19{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test19() -> i32 { + let a: [i32; 4] = [0; 4]; + + let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization + + std::ptr::read_volatile(&a[0]) + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// test20: Nested structure, no arrays, no address-of expressions +// Verify that the resulting gep-of-gep does not incorrectly trigger +// a stack protector +// CHECK-LABEL: test20{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test20() { + let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } }; + + let whole: Nest = std::ptr::read_volatile(&c); + + let v: i32 = whole.second.a; + + printf(STR.as_ptr(), v); + + // strong-NOT: __stack_chk_fail +} + +// test21: Address-of a structure taken in a function with a loop where +// the alloca is an incoming value to a PHI node and a use of that PHI +// node is also an incoming value +// Verify that the address-of analysis does not get stuck in infinite +// recursion when chasing the alloca through the PHI nodes +// CHECK-LABEL: test21{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test21() -> i32 { + let mut tmp: *mut u8 = std::ptr::null_mut(); + let tmp_ptr: *mut *mut u8 = &mut tmp; + + let tmp1 = dummy(tmp_ptr); + + let cur = std::ptr::read_volatile(tmp_ptr); + + let v = (cur as usize as i64) as i32; + + if v > 0 { + let mut phi_ptr: *mut u8 = cur; + let mut phi_idx: i64 = 1; + let mut phi_acc: i32 = tmp1; + + loop { + let b = std::ptr::read_volatile(phi_ptr as *const u8); + let cond = b == 1u8; + let plus = phi_acc.wrapping_add(8); + let next_acc = if cond { plus } else { phi_acc }; + + if (phi_idx as i32) == v { + dummy(next_acc); + break; + } + + let slot = tmp_ptr.add(phi_idx as usize); + let next = std::ptr::read_volatile(slot); + phi_ptr = next; + phi_idx += 1; + phi_acc = next_acc; + } + } else { + dummy(tmp1); + } + + 0 + + // strong: __stack_chk_fail +} + +// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 { + let mut x: i32 = 0; + + std::ptr::write_volatile(&mut x, 1); + + let y = std::ptr::read_volatile(&x); + + let result = y.wrapping_mul(42); + + result + + // strong-NOT: __stack_chk_fail +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit-2.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit-2.rs new file mode 100644 index 0000000000000..8cd7f730bd5e5 --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-32bit-2.rs @@ -0,0 +1,484 @@ +//@ revisions: all strong none missing +//@ assembly-output: emit-asm +//@ only-windows +//@ only-msvc +//@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +extern "C" { + fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8; + fn printf(fmt: *const u8, ...) -> i32; + fn funcall(p: *mut i32); + fn funcall2(p: *mut *mut i32); + fn funfloat(p: *mut f64); + fn funfloat2(p: *mut *mut f64); + fn testi_aux() -> f64; + fn getp() -> *mut i32; + fn dummy(_: ...) -> i32; + + static STR: [u8; 1]; +} + +extern "C-unwind" { + fn except(p: *mut i32); +} + +#[repr(C)] +struct Pair { + a: i32, + b: i32, +} + +#[repr(C)] +struct Nest { + first: Pair, + second: Pair, +} + +// test1: array of [16 x i8] +// CHECK-LABEL: test1{{:|\[}} +#[no_mangle] +pub fn test1(a: *const u8) { + let mut buf: [u8; 16] = [0; 16]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test2: array [4 x i8] +// CHECK-LABEL: test2{{:|\[}} +#[no_mangle] +pub fn test2(a: *const u8) { + let mut buf: [u8; 4] = [0; 4]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test3: no arrays / no nested arrays +// CHECK-LABEL: test3{{:|\[}} +#[no_mangle] +pub fn test3(a: *const u8) { + unsafe { + printf(STR.as_ptr(), a); + } + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test4: Address-of local taken (j = &a) +// CHECK-LABEL: test4{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test4() { + let mut a: i32 = 0; + + let mut j: *mut i32 = std::ptr::null_mut(); + + let tmp = std::ptr::read_volatile(&a); + let tmp2 = tmp.wrapping_add(1); + std::ptr::write_volatile(&mut a, tmp2); + + std::ptr::write_volatile(&mut j, &mut a); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test5: PtrToInt Cast +// CHECK-LABEL: test5{{:|\[}} +#[no_mangle] +pub fn test5(a: i32) { + let ptr_val: usize = &a as *const i32 as usize; + + unsafe { + printf(STR.as_ptr(), ptr_val); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test6: Passing addr-of to function call +// CHECK-LABEL: test6{{:|\[}} +#[no_mangle] +pub fn test6(mut b: i32) { + unsafe { + funcall(&mut b as *mut i32); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test7: Addr-of in select instruction +// CHECK-LABEL: test7{{:|\[}} +#[no_mangle] +pub fn test7() { + let x: f64; + + unsafe { + let call = testi_aux(); + x = call; + + let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() }; + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test8: Addr-of in phi instruction +// CHECK-LABEL: test8{{:|\[}} +#[no_mangle] +pub fn test8() { + let mut _x: f64; + + unsafe { + let call = testi_aux(); + _x = call; + + let y: *const f64; + + if call > 3.14 { + let call1 = testi_aux(); + _x = call1; + y = std::ptr::null(); + } else { + if call > 1.0 { + y = &_x; + } else { + y = std::ptr::null(); + } + } + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test9: Addr-of struct element(GEP followed by store) +// CHECK-LABEL: test9{{:|\[}} +#[no_mangle] +pub fn test9() { + let mut c = Pair { a: 0, b: 0 }; + let b: *mut i32; + + unsafe { + let y: *mut i32 = &mut c.b; + + b = y; + + printf(STR.as_ptr(), b); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test10: Addr-of struct element, GEP followed by ptrtoint +// CHECK-LABEL: test10{{:|\[}} +#[no_mangle] +pub fn test10() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + let addr: i64 = y as i64; + + printf(STR.as_ptr(), addr); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test11: Addr-of struct element, GEP followed by callinst +// CHECK-LABEL: test11{{:|\[}} +#[no_mangle] +pub fn test11() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12) +// CHECK-LABEL: test12{{:|\[}} +#[no_mangle] +pub fn test12() { + let mut a: i32 = 0; + + unsafe { + let add_ptr = (&mut a as *mut i32).offset(-12); + + printf(STR.as_ptr(), add_ptr); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test13: Addr-of a local cast to a ptr of a different type +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test13{{:|\[}} +#[no_mangle] +pub fn test13() { + let mut a: i32 = 0; + + unsafe { + let mut b: *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization + let tmp = std::ptr::read_volatile(&b); + + printf(STR.as_ptr(), tmp); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test14: Addr-of a local cast to a ptr of a different type (optimized) +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test14{{:|\[}} +#[no_mangle] +pub fn test14() { + let a: i32 = 0; + unsafe { + funfloat((&a as *const i32).cast::() as *mut f64); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test15: Addr-of a variable passed into an invoke instruction +// CHECK-LABEL: test15{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test15() -> i32 { + let mut a: i32 = 0; + + except(&mut a as *mut i32); + + 0 + + // stack protector does not generated by LLVM because of Windows SEH. + + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test16: Addr-of a struct element passed into an invoke instruction +// (GEP followed by an invoke) +// CHECK-LABEL: test16{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test16() -> i32 { + let mut c = Pair { a: 0, b: 0 }; + + except(&mut c.a as *mut i32); + + 0 + + // stack protector does not generated by LLVM because of Windows SEH. + + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test17: Addr-of a pointer +// CHECK-LABEL: test17{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test17() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funcall2(tmp); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test18: Addr-of a casted pointer +// CHECK-LABEL: test18{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test18() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funfloat2(tmp as *mut *mut f64); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test19: array of [4 x i32] +// CHECK-LABEL: test19{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test19() -> i32 { + let a: [i32; 4] = [0; 4]; + + let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization + + std::ptr::read_volatile(&a[0]) + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test20: Nested structure, no arrays, no address-of expressions +// Verify that the resulting gep-of-gep does not incorrectly trigger +// a stack protector +// CHECK-LABEL: test20{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test20() { + let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } }; + + let whole: Nest = std::ptr::read_volatile(&c); + + let v: i32 = whole.second.a; + + printf(STR.as_ptr(), v); + + // strong-NOT: __security_check_cookie +} + +// test21: Address-of a structure taken in a function with a loop where +// the alloca is an incoming value to a PHI node and a use of that PHI +// node is also an incoming value +// Verify that the address-of analysis does not get stuck in infinite +// recursion when chasing the alloca through the PHI nodes +// CHECK-LABEL: test21{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test21() -> i32 { + let mut tmp: *mut u8 = std::ptr::null_mut(); + let tmp_ptr: *mut *mut u8 = &mut tmp; + + let tmp1 = dummy(tmp_ptr); + + let cur = std::ptr::read_volatile(tmp_ptr); + + let v = (cur as usize as i64) as i32; + + if v > 0 { + let mut phi_ptr: *mut u8 = cur; + let mut phi_idx: i64 = 1; + let mut phi_acc: i32 = tmp1; + + loop { + let b = std::ptr::read_volatile(phi_ptr as *const u8); + let cond = b == 1u8; + let plus = phi_acc.wrapping_add(8); + let next_acc = if cond { plus } else { phi_acc }; + + if (phi_idx as i32) == v { + dummy(next_acc); + break; + } + + let slot = tmp_ptr.add(phi_idx as usize); + let next = std::ptr::read_volatile(slot); + phi_ptr = next; + phi_idx += 1; + phi_acc = next_acc; + } + } else { + dummy(tmp1); + } + + 0 + + // strong: __security_check_cookie +} + +// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 { + let mut x: i32 = 0; + + std::ptr::write_volatile(&mut x, 1); + + let y = std::ptr::read_volatile(&x); + + let result = y.wrapping_mul(42); + + result + + // strong-NOT: __security_check_cookie +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit-2.rs b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit-2.rs new file mode 100644 index 0000000000000..ac0f89b8e9c0a --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-heuristics-effect-windows-64bit-2.rs @@ -0,0 +1,491 @@ +//@ revisions: all strong none missing +//@ assembly-output: emit-asm +//@ only-windows +//@ only-msvc +//@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [none] compile-flags: -Z stack-protector=none +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![feature(unsized_fn_params)] + +extern "C" { + fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8; + fn printf(fmt: *const u8, ...) -> i32; + fn funcall(p: *mut i32); + fn funcall2(p: *mut *mut i32); + fn funfloat(p: *mut f64); + fn funfloat2(p: *mut *mut f64); + fn testi_aux() -> f64; + fn getp() -> *mut i32; + fn dummy(_: ...) -> i32; + + static STR: [u8; 1]; +} + +extern "C-unwind" { + fn except(p: *mut i32); +} + +#[repr(C)] +struct Pair { + a: i32, + b: i32, +} + +#[repr(C)] +struct Nest { + first: Pair, + second: Pair, +} + +// test1: array of [16 x i8] +// CHECK-LABEL: test1{{:|\[}} +#[no_mangle] +pub fn test1(a: *const u8) { + let mut buf: [u8; 16] = [0; 16]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test2: array [4 x i8] +// CHECK-LABEL: test2{{:|\[}} +#[no_mangle] +pub fn test2(a: *const u8) { + let mut buf: [u8; 4] = [0; 4]; + + unsafe { + strcpy(buf.as_mut_ptr(), a); + printf(STR.as_ptr(), buf.as_ptr()); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test3: no arrays / no nested arrays +// CHECK-LABEL: test3{{:|\[}} +#[no_mangle] +pub fn test3(a: *const u8) { + unsafe { + printf(STR.as_ptr(), a); + } + + // all: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test4: Address-of local taken (j = &a) +// CHECK-LABEL: test4{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test4() { + let mut a: i32 = 0; + + let mut j: *mut i32 = std::ptr::null_mut(); + + let tmp = std::ptr::read_volatile(&a); + let tmp2 = tmp.wrapping_add(1); + std::ptr::write_volatile(&mut a, tmp2); + + std::ptr::write_volatile(&mut j, &mut a); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test5: PtrToInt Cast +// CHECK-LABEL: test5{{:|\[}} +#[no_mangle] +pub fn test5(a: i32) { + let ptr_val: usize = &a as *const i32 as usize; + + unsafe { + printf(STR.as_ptr(), ptr_val); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test6: Passing addr-of to function call +// CHECK-LABEL: test6{{:|\[}} +#[no_mangle] +pub fn test6(mut b: i32) { + unsafe { + funcall(&mut b as *mut i32); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test7: Addr-of in select instruction +// CHECK-LABEL: test7{{:|\[}} +#[no_mangle] +pub fn test7() { + let x: f64; + + unsafe { + let call = testi_aux(); + x = call; + + let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() }; + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test8: Addr-of in phi instruction +// CHECK-LABEL: test8{{:|\[}} +#[no_mangle] +pub fn test8() { + let mut _x: f64; + + unsafe { + let call = testi_aux(); + _x = call; + + let y: *const f64; + + if call > 3.14 { + let call1 = testi_aux(); + _x = call1; + y = std::ptr::null(); + } else { + if call > 1.0 { + y = &_x; + } else { + y = std::ptr::null(); + } + } + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test9: Addr-of struct element(GEP followed by store) +// CHECK-LABEL: test9{{:|\[}} +#[no_mangle] +pub fn test9() { + let mut c = Pair { a: 0, b: 0 }; + let b: *mut i32; + + unsafe { + let y: *mut i32 = &mut c.b; + + b = y; + + printf(STR.as_ptr(), b); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test10: Addr-of struct element, GEP followed by ptrtoint +// CHECK-LABEL: test10{{:|\[}} +#[no_mangle] +pub fn test10() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + let addr: i64 = y as i64; + + printf(STR.as_ptr(), addr); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test11: Addr-of struct element, GEP followed by callinst +// CHECK-LABEL: test11{{:|\[}} +#[no_mangle] +pub fn test11() { + let mut c = Pair { a: 0, b: 0 }; + + unsafe { + let y: *mut i32 = &mut c.b; + + printf(STR.as_ptr(), y); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12) +// CHECK-LABEL: test12{{:|\[}} +#[no_mangle] +pub fn test12() { + let mut a: i32 = 0; + + unsafe { + let add_ptr = (&mut a as *mut i32).offset(-12); + + printf(STR.as_ptr(), add_ptr); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test13: Addr-of a local cast to a ptr of a different type +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test13{{:|\[}} +#[no_mangle] +pub fn test13() { + let mut a: i32 = 0; + + unsafe { + let mut b: *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization + let tmp = std::ptr::read_volatile(&b); + + printf(STR.as_ptr(), tmp); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test14: Addr-of a local cast to a ptr of a different type (optimized) +// (e.g., int a; ... ; ptr b = &a;) +// CHECK-LABEL: test14{{:|\[}} +#[no_mangle] +pub fn test14() { + let a: i32 = 0; + unsafe { + funfloat((&a as *const i32).cast::() as *mut f64); + } + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test15: Addr-of a variable passed into an invoke instruction +// CHECK-LABEL: test15{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test15() -> i32 { + // CHECK-DAG: .seh_endprologue + + let mut a: i32 = 0; + + except(&mut a as *mut i32); + + 0 + + // stack protector does not generated by LLVM because of Windows SEH. + + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc +} + +// test16: Addr-of a struct element passed into an invoke instruction +// (GEP followed by an invoke) +// CHECK-LABEL: test16{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test16() -> i32 { + // CHECK-DAG: .seh_endprologue + + let mut c = Pair { a: 0, b: 0 }; + + except(&mut c.a as *mut i32); + + 0 + + // stack protector does not generated by LLVM because of Windows SEH. + + // all-NOT: __security_check_cookie + // strong-NOT: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie + + // CHECK-DAG: .seh_endproc +} + +// test17: Addr-of a pointer +// CHECK-LABEL: test17{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test17() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funcall2(tmp); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test18: Addr-of a casted pointer +// CHECK-LABEL: test18{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test18() { + let mut a: *mut i32 = getp(); + + let mut _b: *mut *mut i32 = std::ptr::null_mut(); + + std::ptr::write_volatile(&mut _b, &mut a); + + let tmp = std::ptr::read_volatile(&_b); + + funfloat2(tmp as *mut *mut f64); + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test19: array of [4 x i32] +// CHECK-LABEL: test19{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test19() -> i32 { + let a: [i32; 4] = [0; 4]; + + let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization + + std::ptr::read_volatile(&a[0]) + + // all: __security_check_cookie + // strong: __security_check_cookie + // none-NOT: __security_check_cookie + // missing-NOT: __security_check_cookie +} + +// test20: Nested structure, no arrays, no address-of expressions +// Verify that the resulting gep-of-gep does not incorrectly trigger +// a stack protector +// CHECK-LABEL: test20{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test20() { + let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } }; + + let whole: Nest = std::ptr::read_volatile(&c); + + let v: i32 = whole.second.a; + + printf(STR.as_ptr(), v); + + // strong-NOT: __security_check_cookie +} + +// test21: Address-of a structure taken in a function with a loop where +// the alloca is an incoming value to a PHI node and a use of that PHI +// node is also an incoming value +// Verify that the address-of analysis does not get stuck in infinite +// recursion when chasing the alloca through the PHI nodes +// CHECK-LABEL: test21{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn test21() -> i32 { + let mut tmp: *mut u8 = std::ptr::null_mut(); + let tmp_ptr: *mut *mut u8 = &mut tmp; + + let tmp1 = dummy(tmp_ptr); + + let cur = std::ptr::read_volatile(tmp_ptr); + + let v = (cur as usize as i64) as i32; + + if v > 0 { + let mut phi_ptr: *mut u8 = cur; + let mut phi_idx: i64 = 1; + let mut phi_acc: i32 = tmp1; + + loop { + let b = std::ptr::read_volatile(phi_ptr as *const u8); + let cond = b == 1u8; + let plus = phi_acc.wrapping_add(8); + let next_acc = if cond { plus } else { phi_acc }; + + if (phi_idx as i32) == v { + dummy(next_acc); + break; + } + + let slot = tmp_ptr.add(phi_idx as usize); + let next = std::ptr::read_volatile(slot); + phi_ptr = next; + phi_idx += 1; + phi_acc = next_acc; + } + } else { + dummy(tmp1); + } + + 0 + + // strong: __security_check_cookie +} + +// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}} +#[no_mangle] +pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 { + let mut x: i32 = 0; + + std::ptr::write_volatile(&mut x, 1); + + let y = std::ptr::read_volatile(&x); + + let result = y.wrapping_mul(42); + + result + + // strong-NOT: __security_check_cookie +} diff --git a/tests/assembly-llvm/stack-protector/stack-protector-safe-stack.rs b/tests/assembly-llvm/stack-protector/stack-protector-safe-stack.rs new file mode 100644 index 0000000000000..14e1c3fed6db2 --- /dev/null +++ b/tests/assembly-llvm/stack-protector/stack-protector-safe-stack.rs @@ -0,0 +1,42 @@ +//@ revisions: all strong none safestack safestack_strong safestack_all +//@ assembly-output: emit-asm +//@ ignore-msvc safestack sanitizer not supported +//@ ignore-nvptx64 stack protector is not supported +//@ ignore-wasm32-bare +//@ ignore-aarch64 +//@ [all] compile-flags: -Z stack-protector=all +//@ [strong] compile-flags: -Z stack-protector=strong +//@ [none] compile-flags: -Z stack-protector=none +//@ [safestack] compile-flags: -Z stack-protector=none -Z sanitizer=safestack +// RUSTFLAGS: -Cunsafe-allow-abi-mismatch=sanitizer +//@ [safestack_strong] compile-flags: -Z stack-protector=strong -Z sanitizer=safestack +// RUSTFLAGS: -Cunsafe-allow-abi-mismatch=sanitizer +//@ [safestack_all] compile-flags: -Z stack-protector=all -Z sanitizer=safestack +// RUSTFLAGS: -Cunsafe-allow-abi-mismatch=sanitizer +//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] +#![allow(internal_features)] +#![feature(unsized_fn_params)] + +// Check the coexistence of stack-protector and safe-stack. +// CHECK-LABEL: test1{{:|\[}} +#[no_mangle] +pub unsafe fn test1(src: *const u8, len: usize) -> u8 { + let mut buf = [0u8; 64]; + std::ptr::copy_nonoverlapping(src, buf.as_mut_ptr(), len.min(buf.len())); + buf[0] + + // none-NOT: __stack_chk_fail + // strong: __stack_chk_fail + // all: __stack_chk_fail + + // safestack: __safestack_unsafe_stack_ptr + // safestack-NOT: __stack_chk_fail + + // safestack_strong: __safestack_unsafe_stack_ptr + // safestack_strong: __stack_chk_fail + + // safestack_all: __safestack_unsafe_stack_ptr + // safestack_all: __stack_chk_fail +} diff --git a/tests/ui/associated-inherent-types/fall-back-to-trait-candidate.rs b/tests/ui/associated-inherent-types/fall-back-to-trait-candidate.rs new file mode 100644 index 0000000000000..6c3eee0f7ec74 --- /dev/null +++ b/tests/ui/associated-inherent-types/fall-back-to-trait-candidate.rs @@ -0,0 +1,25 @@ +// Ensure that IAT selection doesn't hard error on associated type paths that could refer to +// an inherent associated type if we can't find an applicable inherent candidate since there +// might still be valid trait associated type candidates. +// +// FIXME(#142006): This only covers the bare minimum, we also need to disqualify inherent +// candidates if they're inaccessible or if the impl headers don't match / apply. +// +// issue: +//@ check-pass + +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +struct Type; +trait Trait { type AssocTy; fn scope(); } + +impl Trait for Type { + type AssocTy = (); + + fn scope() { + let (): Self::AssocTy; + } +} + +fn main() { ::scope(); } diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs deleted file mode 100644 index 337fd8fa00c55..0000000000000 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![feature(inherent_associated_types)] -#![allow(incomplete_features)] - -// Check that it's okay to report “[inherent] associated type […] not found” for inherent associated -// type candidates that are not applicable (due to unsuitable Self type) even if there exists a -// “shadowed” associated type from a trait with the same name since its use would be ambiguous -// anyway if the IAT didn't exist. -// FIXME(inherent_associated_types): Figure out which error would be more helpful here. - -//@ revisions: shadowed uncovered - -struct S(T); - -trait Tr { - type Pr; -} - -impl Tr for S { - type Pr = (); -} - -#[cfg(shadowed)] -impl S<()> { - type Pr = i32; -} - -fn main() { - let _: S::::Pr = (); - //[shadowed]~^ ERROR associated type `Pr` not found - //[uncovered]~^^ ERROR associated type `Pr` not found -} diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.shadowed.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.shadowed.stderr deleted file mode 100644 index a247d6d5b45bd..0000000000000 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.shadowed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0220]: associated type `Pr` not found for `S` in the current scope - --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 - | -LL | struct S(T); - | ----------- associated type `Pr` not found for this struct -... -LL | let _: S::::Pr = (); - | ^^ associated item not found in `S` - | - = note: the associated type was found for - - `S<()>` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr b/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr deleted file mode 100644 index f35158c5b4101..0000000000000 --- a/tests/ui/associated-inherent-types/not-found-self-type-differs-shadowing-trait-item.uncovered.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0220]: associated type `Pr` not found for `S` in the current scope - --> $DIR/not-found-self-type-differs-shadowing-trait-item.rs:28:23 - | -LL | struct S(T); - | ----------- associated type `Pr` not found for this struct -... -LL | let _: S::::Pr = (); - | ^^ associated item not found in `S` - | - = note: the associated type was found for - - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-inherent-types/prefer-inherent-over-trait.rs b/tests/ui/associated-inherent-types/prefer-inherent-over-trait.rs new file mode 100644 index 0000000000000..6c81ef7409d4a --- /dev/null +++ b/tests/ui/associated-inherent-types/prefer-inherent-over-trait.rs @@ -0,0 +1,28 @@ +#![feature(inherent_associated_types)] +#![expect(incomplete_features)] + +// Ensure that prefer inherent associated types over trait associated types +// (assuming the impl headers match and they're accessible). +//@ check-pass + +struct Adt; + +impl Adt { + type Ty = (); +} + +trait Trait { + type Ty; + fn scope(); +} + +impl Trait for Adt { + type Ty = i32; + fn scope() { + // We prefer the inherent assoc ty `Adt::Ty` (`()`) over the + // trait assoc ty `::Ty` (`i32`). + let (): Self::Ty; + } +} + +fn main() {}