Auto merge of #121914 - Nadrieril:rollup-ol98ncg, r=Nadrieril

Rollup of 5 pull requests

Successful merges:

 - #120761 (Add initial support for DataFlowSanitizer)
 - #121622 (Preserve same vtable pointer when cloning raw waker, to fix Waker::will_wake)
 - #121716 (match lowering: Lower bindings in a predictable order)
 - #121731 (Now that inlining, mir validation and const eval all use reveal-all, we won't be constraining hidden types here anymore)
 - #121841 (`f16` and `f128` step 2: intrinsics)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-03-02 22:59:19 +00:00
commit 0decdac390
52 changed files with 1156 additions and 144 deletions

View File

@ -1920,22 +1920,28 @@ pub struct FnSig {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum FloatTy {
F16,
F32,
F64,
F128,
}
impl FloatTy {
pub fn name_str(self) -> &'static str {
match self {
FloatTy::F16 => "f16",
FloatTy::F32 => "f32",
FloatTy::F64 => "f64",
FloatTy::F128 => "f128",
}
}
pub fn name(self) -> Symbol {
match self {
FloatTy::F16 => sym::f16,
FloatTy::F32 => sym::f32,
FloatTy::F64 => sym::f64,
FloatTy::F128 => sym::f128,
}
}
}

View File

@ -519,12 +519,22 @@ pub(crate) unsafe fn llvm_optimize(
let pgo_sample_use_path = get_pgo_sample_use_path(config);
let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
let instr_profile_output_path = get_instr_profile_output_path(config);
let sanitize_dataflow_abilist: Vec<_> = config
.sanitizer_dataflow_abilist
.iter()
.map(|file| CString::new(file.as_str()).unwrap())
.collect();
let sanitize_dataflow_abilist_ptrs: Vec<_> =
sanitize_dataflow_abilist.iter().map(|file| file.as_ptr()).collect();
// Sanitizer instrumentation is only inserted during the pre-link optimization stage.
let sanitizer_options = if !is_lto {
Some(llvm::SanitizerOptions {
sanitize_address: config.sanitizer.contains(SanitizerSet::ADDRESS),
sanitize_address_recover: config.sanitizer_recover.contains(SanitizerSet::ADDRESS),
sanitize_cfi: config.sanitizer.contains(SanitizerSet::CFI),
sanitize_dataflow: config.sanitizer.contains(SanitizerSet::DATAFLOW),
sanitize_dataflow_abilist: sanitize_dataflow_abilist_ptrs.as_ptr(),
sanitize_dataflow_abilist_len: sanitize_dataflow_abilist_ptrs.len(),
sanitize_kcfi: config.sanitizer.contains(SanitizerSet::KCFI),
sanitize_memory: config.sanitizer.contains(SanitizerSet::MEMORY),
sanitize_memory_recover: config.sanitizer_recover.contains(SanitizerSet::MEMORY),

View File

@ -685,8 +685,10 @@ impl<'ll> CodegenCx<'ll, '_> {
let t_i64 = self.type_i64();
let t_i128 = self.type_i128();
let t_isize = self.type_isize();
let t_f16 = self.type_f16();
let t_f32 = self.type_f32();
let t_f64 = self.type_f64();
let t_f128 = self.type_f128();
let t_metadata = self.type_metadata();
let t_token = self.type_token();
@ -728,69 +730,115 @@ impl<'ll> CodegenCx<'ll, '_> {
ifn!("llvm.debugtrap", fn() -> void);
ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
ifn!("llvm.pow.f128", fn(t_f128, t_f128) -> t_f128);
ifn!("llvm.sqrt.f16", fn(t_f16) -> t_f16);
ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
ifn!("llvm.sqrt.f128", fn(t_f128) -> t_f128);
ifn!("llvm.sin.f16", fn(t_f16) -> t_f16);
ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
ifn!("llvm.sin.f128", fn(t_f128) -> t_f128);
ifn!("llvm.cos.f16", fn(t_f16) -> t_f16);
ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
ifn!("llvm.cos.f128", fn(t_f128) -> t_f128);
ifn!("llvm.exp.f16", fn(t_f16) -> t_f16);
ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
ifn!("llvm.exp.f128", fn(t_f128) -> t_f128);
ifn!("llvm.exp2.f16", fn(t_f16) -> t_f16);
ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
ifn!("llvm.exp2.f128", fn(t_f128) -> t_f128);
ifn!("llvm.log.f16", fn(t_f16) -> t_f16);
ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
ifn!("llvm.log.f128", fn(t_f128) -> t_f128);
ifn!("llvm.log10.f16", fn(t_f16) -> t_f16);
ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
ifn!("llvm.log10.f128", fn(t_f128) -> t_f128);
ifn!("llvm.log2.f16", fn(t_f16) -> t_f16);
ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
ifn!("llvm.log2.f128", fn(t_f128) -> t_f128);
ifn!("llvm.fma.f16", fn(t_f16, t_f16, t_f16) -> t_f16);
ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16);
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
ifn!("llvm.fabs.f128", fn(t_f128) -> t_f128);
ifn!("llvm.minnum.f16", fn(t_f16, t_f16) -> t_f16);
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128);
ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
ifn!("llvm.floor.f128", fn(t_f128) -> t_f128);
ifn!("llvm.ceil.f16", fn(t_f16) -> t_f16);
ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
ifn!("llvm.ceil.f128", fn(t_f128) -> t_f128);
ifn!("llvm.trunc.f16", fn(t_f16) -> t_f16);
ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
ifn!("llvm.trunc.f128", fn(t_f128) -> t_f128);
ifn!("llvm.copysign.f16", fn(t_f16, t_f16) -> t_f16);
ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
ifn!("llvm.copysign.f128", fn(t_f128, t_f128) -> t_f128);
ifn!("llvm.round.f16", fn(t_f16) -> t_f16);
ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
ifn!("llvm.round.f128", fn(t_f128) -> t_f128);
ifn!("llvm.roundeven.f16", fn(t_f16) -> t_f16);
ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
ifn!("llvm.roundeven.f128", fn(t_f128) -> t_f128);
ifn!("llvm.rint.f16", fn(t_f16) -> t_f16);
ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
ifn!("llvm.rint.f128", fn(t_f128) -> t_f128);
ifn!("llvm.nearbyint.f16", fn(t_f16) -> t_f16);
ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64);
ifn!("llvm.nearbyint.f128", fn(t_f128) -> t_f128);
ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8);
ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16);

View File

@ -695,7 +695,7 @@ impl MsvcBasicName for ty::UintTy {
impl MsvcBasicName for ty::FloatTy {
fn msvc_basic_name(self) -> &'static str {
// FIXME: f16 and f128 have no MSVE representation. We could improve the debuginfo.
// FIXME: f16 and f128 have no MSVC representation. We could improve the debuginfo.
// See: <https://github.com/rust-lang/rust/pull/114607/files#r1454683264>
match self {
ty::FloatTy::F16 => "half",

View File

@ -28,51 +28,118 @@ fn get_simple_intrinsic<'ll>(
name: Symbol,
) -> Option<(&'ll Type, &'ll Value)> {
let llvm_name = match name {
sym::sqrtf16 => "llvm.sqrt.f16",
sym::sqrtf32 => "llvm.sqrt.f32",
sym::sqrtf64 => "llvm.sqrt.f64",
sym::sqrtf128 => "llvm.sqrt.f128",
sym::powif16 => "llvm.powi.f16",
sym::powif32 => "llvm.powi.f32",
sym::powif64 => "llvm.powi.f64",
sym::powif128 => "llvm.powi.f128",
sym::sinf16 => "llvm.sin.f16",
sym::sinf32 => "llvm.sin.f32",
sym::sinf64 => "llvm.sin.f64",
sym::sinf128 => "llvm.sin.f128",
sym::cosf16 => "llvm.cos.f16",
sym::cosf32 => "llvm.cos.f32",
sym::cosf64 => "llvm.cos.f64",
sym::cosf128 => "llvm.cos.f128",
sym::powf16 => "llvm.pow.f16",
sym::powf32 => "llvm.pow.f32",
sym::powf64 => "llvm.pow.f64",
sym::powf128 => "llvm.pow.f128",
sym::expf16 => "llvm.exp.f16",
sym::expf32 => "llvm.exp.f32",
sym::expf64 => "llvm.exp.f64",
sym::expf128 => "llvm.exp.f128",
sym::exp2f16 => "llvm.exp2.f16",
sym::exp2f32 => "llvm.exp2.f32",
sym::exp2f64 => "llvm.exp2.f64",
sym::exp2f128 => "llvm.exp2.f128",
sym::logf16 => "llvm.log.f16",
sym::logf32 => "llvm.log.f32",
sym::logf64 => "llvm.log.f64",
sym::logf128 => "llvm.log.f128",
sym::log10f16 => "llvm.log10.f16",
sym::log10f32 => "llvm.log10.f32",
sym::log10f64 => "llvm.log10.f64",
sym::log10f128 => "llvm.log10.f128",
sym::log2f16 => "llvm.log2.f16",
sym::log2f32 => "llvm.log2.f32",
sym::log2f64 => "llvm.log2.f64",
sym::log2f128 => "llvm.log2.f128",
sym::fmaf16 => "llvm.fma.f16",
sym::fmaf32 => "llvm.fma.f32",
sym::fmaf64 => "llvm.fma.f64",
sym::fmaf128 => "llvm.fma.f128",
sym::fabsf16 => "llvm.fabs.f16",
sym::fabsf32 => "llvm.fabs.f32",
sym::fabsf64 => "llvm.fabs.f64",
sym::fabsf128 => "llvm.fabs.f128",
sym::minnumf16 => "llvm.minnum.f16",
sym::minnumf32 => "llvm.minnum.f32",
sym::minnumf64 => "llvm.minnum.f64",
sym::minnumf128 => "llvm.minnum.f128",
sym::maxnumf16 => "llvm.maxnum.f16",
sym::maxnumf32 => "llvm.maxnum.f32",
sym::maxnumf64 => "llvm.maxnum.f64",
sym::maxnumf128 => "llvm.maxnum.f128",
sym::copysignf16 => "llvm.copysign.f16",
sym::copysignf32 => "llvm.copysign.f32",
sym::copysignf64 => "llvm.copysign.f64",
sym::copysignf128 => "llvm.copysign.f128",
sym::floorf16 => "llvm.floor.f16",
sym::floorf32 => "llvm.floor.f32",
sym::floorf64 => "llvm.floor.f64",
sym::floorf128 => "llvm.floor.f128",
sym::ceilf16 => "llvm.ceil.f16",
sym::ceilf32 => "llvm.ceil.f32",
sym::ceilf64 => "llvm.ceil.f64",
sym::ceilf128 => "llvm.ceil.f128",
sym::truncf16 => "llvm.trunc.f16",
sym::truncf32 => "llvm.trunc.f32",
sym::truncf64 => "llvm.trunc.f64",
sym::truncf128 => "llvm.trunc.f128",
sym::rintf16 => "llvm.rint.f16",
sym::rintf32 => "llvm.rint.f32",
sym::rintf64 => "llvm.rint.f64",
sym::rintf128 => "llvm.rint.f128",
sym::nearbyintf16 => "llvm.nearbyint.f16",
sym::nearbyintf32 => "llvm.nearbyint.f32",
sym::nearbyintf64 => "llvm.nearbyint.f64",
sym::nearbyintf128 => "llvm.nearbyint.f128",
sym::roundf16 => "llvm.round.f16",
sym::roundf32 => "llvm.round.f32",
sym::roundf64 => "llvm.round.f64",
sym::roundf128 => "llvm.round.f128",
sym::ptr_mask => "llvm.ptrmask",
sym::roundevenf16 => "llvm.roundeven.f16",
sym::roundevenf32 => "llvm.roundeven.f32",
sym::roundevenf64 => "llvm.roundeven.f64",
sym::roundevenf128 => "llvm.roundeven.f128",
_ => return None,
};
Some(cx.get_intrinsic(llvm_name))

View File

@ -480,6 +480,9 @@ pub struct SanitizerOptions {
pub sanitize_address: bool,
pub sanitize_address_recover: bool,
pub sanitize_cfi: bool,
pub sanitize_dataflow: bool,
pub sanitize_dataflow_abilist: *const *const c_char,
pub sanitize_dataflow_abilist_len: size_t,
pub sanitize_kcfi: bool,
pub sanitize_memory: bool,
pub sanitize_memory_recover: bool,

View File

@ -1221,6 +1221,9 @@ fn add_sanitizer_libraries(
if sanitizer.contains(SanitizerSet::ADDRESS) {
link_sanitizer_runtime(sess, flavor, linker, "asan");
}
if sanitizer.contains(SanitizerSet::DATAFLOW) {
link_sanitizer_runtime(sess, flavor, linker, "dfsan");
}
if sanitizer.contains(SanitizerSet::LEAK) {
link_sanitizer_runtime(sess, flavor, linker, "lsan");
}

View File

@ -95,6 +95,7 @@ pub struct ModuleConfig {
pub sanitizer: SanitizerSet,
pub sanitizer_recover: SanitizerSet,
pub sanitizer_dataflow_abilist: Vec<String>,
pub sanitizer_memory_track_origins: usize,
// Flags indicating which outputs to produce.
@ -197,6 +198,10 @@ impl ModuleConfig {
),
sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
sanitizer_dataflow_abilist: if_regular!(
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
Vec::new()
),
sanitizer_recover: if_regular!(
sess.opts.unstable_opts.sanitizer_recover,
SanitizerSet::empty()

View File

@ -4,7 +4,7 @@
//! other areas of the compiler as well.
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance};
use rustc_trait_selection::traits::ObligationCtxt;
@ -33,9 +33,6 @@ pub fn is_equal_up_to_subtyping<'tcx>(
/// When validating assignments, the variance should be `Covariant`. When checking
/// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant`
/// because we want to check for type equality.
///
/// This mostly ignores opaque types as it can be used in constraining contexts
/// while still computing the final underlying type.
pub fn relate_types<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
@ -47,8 +44,7 @@ pub fn relate_types<'tcx>(
return true;
}
let mut builder =
tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(DefiningAnchor::Bubble);
let mut builder = tcx.infer_ctxt().ignoring_regions();
let infcx = builder.build();
let ocx = ObligationCtxt::new(&infcx);
let cause = ObligationCause::dummy();
@ -58,20 +54,5 @@ pub fn relate_types<'tcx>(
Ok(()) => {}
Err(_) => return false,
};
let errors = ocx.select_all_or_error();
// With `Reveal::All`, opaque types get normalized away, with `Reveal::UserFacing`
// we would get unification errors because we're unable to look into opaque types,
// even if they're constrained in our current function.
for (key, ty) in infcx.take_opaque_types() {
let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args);
if hidden_ty != ty.hidden_type.ty {
span_bug!(
ty.hidden_type.span,
"{}, {}",
tcx.type_of(key.def_id).instantiate(tcx, key.args),
ty.hidden_type.ty
);
}
}
errors.is_empty()
ocx.select_all_or_error().is_empty()
}

View File

@ -2460,6 +2460,7 @@ impl PrimTy {
Self::Uint(UintTy::Usize),
Self::Float(FloatTy::F32),
Self::Float(FloatTy::F64),
// FIXME(f16_f128): add these when enabled below
Self::Bool,
Self::Char,
Self::Str,
@ -2509,6 +2510,10 @@ impl PrimTy {
sym::usize => Self::Uint(UintTy::Usize),
sym::f32 => Self::Float(FloatTy::F32),
sym::f64 => Self::Float(FloatTy::F64),
// FIXME(f16_f128): enabling these will open the gates of f16 and f128 being
// understood by rustc.
// sym::f16 => Self::Float(FloatTy::F16),
// sym::f128 => Self::Float(FloatTy::F128),
sym::bool => Self::Bool,
sym::char => Self::Char,
sym::str => Self::Str,

View File

@ -112,11 +112,15 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -
| sym::likely
| sym::unlikely
| sym::ptr_guaranteed_cmp
| sym::minnumf16
| sym::minnumf32
| sym::minnumf64
| sym::minnumf128
| sym::maxnumf16
| sym::maxnumf32
| sym::rustc_peek
| sym::maxnumf64
| sym::maxnumf128
| sym::rustc_peek
| sym::type_name
| sym::forget
| sym::black_box
@ -302,50 +306,118 @@ pub fn check_intrinsic_type(
],
Ty::new_unit(tcx),
),
sym::sqrtf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::sqrtf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::sqrtf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::sqrtf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::powif16 => (0, 0, vec![tcx.types.f16, tcx.types.i32], tcx.types.f16),
sym::powif32 => (0, 0, vec![tcx.types.f32, tcx.types.i32], tcx.types.f32),
sym::powif64 => (0, 0, vec![tcx.types.f64, tcx.types.i32], tcx.types.f64),
sym::powif128 => (0, 0, vec![tcx.types.f128, tcx.types.i32], tcx.types.f128),
sym::sinf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::sinf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::sinf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::sinf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::cosf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::cosf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::cosf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::cosf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::powf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
sym::powf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
sym::powf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
sym::powf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
sym::expf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::expf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::expf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::expf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::exp2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::exp2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::exp2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::exp2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::logf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::logf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::logf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::logf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::log10f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::log10f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::log10f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::log10f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::log2f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::log2f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::log2f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::log2f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::fmaf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16, tcx.types.f16], tcx.types.f16),
sym::fmaf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32, tcx.types.f32], tcx.types.f32),
sym::fmaf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64, tcx.types.f64], tcx.types.f64),
sym::fmaf128 => {
(0, 0, vec![tcx.types.f128, tcx.types.f128, tcx.types.f128], tcx.types.f128)
}
sym::fabsf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::fabsf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::fabsf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::fabsf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::minnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
sym::minnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
sym::minnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
sym::minnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
sym::maxnumf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
sym::maxnumf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
sym::maxnumf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
sym::maxnumf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
sym::copysignf16 => (0, 0, vec![tcx.types.f16, tcx.types.f16], tcx.types.f16),
sym::copysignf32 => (0, 0, vec![tcx.types.f32, tcx.types.f32], tcx.types.f32),
sym::copysignf64 => (0, 0, vec![tcx.types.f64, tcx.types.f64], tcx.types.f64),
sym::copysignf128 => (0, 0, vec![tcx.types.f128, tcx.types.f128], tcx.types.f128),
sym::floorf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::floorf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::floorf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::floorf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::ceilf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::ceilf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::ceilf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::ceilf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::truncf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::truncf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::truncf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::rintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::rintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::rintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::rintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::nearbyintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::nearbyintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::nearbyintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::nearbyintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::roundf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::roundf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::roundevenf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16),
sym::roundevenf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32),
sym::roundevenf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64),
sym::roundevenf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128),
sym::volatile_load | sym::unaligned_volatile_load => {
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0))

View File

@ -811,6 +811,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(sanitizer_cfi_canonical_jump_tables, None);
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
tracked!(sanitizer_cfi_normalize_integers, Some(true));
tracked!(sanitizer_dataflow_abilist, vec![String::from("/rustc/abc")]);
tracked!(sanitizer_memory_track_origins, 2);
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
tracked!(saturating_float_casts, Some(true));

View File

@ -42,6 +42,7 @@
#endif
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Instrumentation/AddressSanitizer.h"
#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h"
#include "llvm/Support/TimeProfiler.h"
#if LLVM_VERSION_GE(19, 0)
#include "llvm/Support/PGOOptions.h"
@ -686,6 +687,9 @@ struct LLVMRustSanitizerOptions {
bool SanitizeAddress;
bool SanitizeAddressRecover;
bool SanitizeCFI;
bool SanitizeDataFlow;
char **SanitizeDataFlowABIList;
size_t SanitizeDataFlowABIListLen;
bool SanitizeKCFI;
bool SanitizeMemory;
bool SanitizeMemoryRecover;
@ -883,6 +887,18 @@ LLVMRustOptimize(
}
if (SanitizerOptions) {
if (SanitizerOptions->SanitizeDataFlow) {
std::vector<std::string> ABIListFiles(
SanitizerOptions->SanitizeDataFlowABIList,
SanitizerOptions->SanitizeDataFlowABIList +
SanitizerOptions->SanitizeDataFlowABIListLen);
OptimizerLastEPCallbacks.push_back(
[ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(DataFlowSanitizerPass(ABIListFiles));
}
);
}
if (SanitizerOptions->SanitizeMemory) {
MemorySanitizerOptions Options(
SanitizerOptions->SanitizeMemoryTrackOrigins,

View File

@ -1991,8 +1991,10 @@ pub fn uint_ty(uty: ast::UintTy) -> UintTy {
pub fn float_ty(fty: ast::FloatTy) -> FloatTy {
match fty {
ast::FloatTy::F16 => FloatTy::F16,
ast::FloatTy::F32 => FloatTy::F32,
ast::FloatTy::F64 => FloatTy::F64,
ast::FloatTy::F128 => FloatTy::F128,
}
}

View File

@ -701,7 +701,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.bind_pattern(
self.source_info(irrefutable_pat.span),
candidate,
&fake_borrow_temps,
fake_borrow_temps.as_slice(),
irrefutable_pat.span,
None,
false,
@ -1938,7 +1938,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let post_guard_block = self.bind_pattern(
self.source_info(pat.span),
guard_candidate,
&fake_borrow_temps,
fake_borrow_temps.as_slice(),
expr_span,
None,
false,
@ -2425,7 +2425,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let matching = this.bind_pattern(
this.source_info(pattern.span),
candidate,
&fake_borrow_temps,
fake_borrow_temps.as_slice(),
initializer_span,
None,
true,
@ -2434,7 +2434,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let failure = this.bind_pattern(
this.source_info(else_block_span),
wildcard,
&fake_borrow_temps,
fake_borrow_temps.as_slice(),
initializer_span,
None,
true,

View File

@ -41,60 +41,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// let y = x;
// }
//
// We can't just reverse the binding order, because we must preserve pattern-order
// otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
// and bindings at the same depth stay in source order.
//
// To do this, every time around the loop we prepend the newly found bindings to the
// bindings we already had.
//
// example:
// candidate.bindings = [1, 2, 3]
// bindings in iter 1: [4, 5]
// bindings in iter 2: [6, 7]
//
// final bindings: [6, 7, 4, 5, 1, 2, 3]
let mut accumulated_bindings = mem::take(candidate_bindings);
let mut simplified_match_pairs = Vec::new();
// Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
loop {
for mut match_pair in mem::take(match_pairs) {
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
if let Some(binding) = binding {
candidate_bindings.push(binding);
}
if let Some(ascription) = ascription {
candidate_ascriptions.push(ascription);
}
// Simplifiable pattern; we replace it with its subpairs and simplify further.
match_pairs.append(&mut match_pair.subpairs);
} else {
// Unsimplifiable pattern; we recursively simplify its subpairs and don't
// process it further.
self.simplify_match_pairs(
&mut match_pair.subpairs,
candidate_bindings,
candidate_ascriptions,
);
simplified_match_pairs.push(match_pair);
// We therefore lower bindings from left-to-right, except we lower the `x` in `x @ pat`
// after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
// match lowering forces us to lower bindings inside or-patterns last.
for mut match_pair in mem::take(match_pairs) {
self.simplify_match_pairs(
&mut match_pair.subpairs,
candidate_bindings,
candidate_ascriptions,
);
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
if let Some(binding) = binding {
candidate_bindings.push(binding);
}
}
// This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
candidate_bindings.extend_from_slice(&accumulated_bindings);
mem::swap(candidate_bindings, &mut accumulated_bindings);
candidate_bindings.clear();
if match_pairs.is_empty() {
break;
if let Some(ascription) = ascription {
candidate_ascriptions.push(ascription);
}
// Simplifiable pattern; we replace it with its already simplified subpairs.
match_pairs.append(&mut match_pair.subpairs);
} else {
// Unsimplifiable pattern; we keep it.
match_pairs.push(match_pair);
}
}
// Store computed bindings back in `candidate_bindings`.
mem::swap(candidate_bindings, &mut accumulated_bindings);
// Store simplified match pairs back in `match_pairs`.
mem::swap(match_pairs, &mut simplified_match_pairs);
// Move or-patterns to the end, because they can result in us
// creating additional candidates, so we want to test them as
// late as possible.

View File

@ -371,7 +371,8 @@ mod desc {
pub const parse_list: &str = "a space-separated list of strings";
pub const parse_list_with_polarity: &str =
"a comma-separated list of strings, with elements beginning with + or -";
pub const parse_opt_comma_list: &str = "a comma-separated list of strings";
pub const parse_comma_list: &str = "a comma-separated list of strings";
pub const parse_opt_comma_list: &str = parse_comma_list;
pub const parse_number: &str = "a number";
pub const parse_opt_number: &str = parse_number;
pub const parse_threads: &str = parse_number;
@ -381,7 +382,7 @@ mod desc {
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@ -602,6 +603,18 @@ mod parse {
}
}
pub(crate) fn parse_comma_list(slot: &mut Vec<String>, v: Option<&str>) -> bool {
match v {
Some(s) => {
let mut v: Vec<_> = s.split(',').map(|s| s.to_string()).collect();
v.sort_unstable();
*slot = v;
true
}
None => false,
}
}
pub(crate) fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
match v {
Some(s) => {
@ -718,6 +731,7 @@ mod parse {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
"cfi" => SanitizerSet::CFI,
"dataflow" => SanitizerSet::DATAFLOW,
"kcfi" => SanitizerSet::KCFI,
"kernel-address" => SanitizerSet::KERNELADDRESS,
"leak" => SanitizerSet::LEAK,
@ -1846,6 +1860,8 @@ written to standard error output)"),
"enable generalizing pointer types (default: no)"),
sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
"enable normalizing integer types (default: no)"),
sanitizer_dataflow_abilist: Vec<String> = (Vec::new(), parse_comma_list, [TRACKED],
"additional ABI list files that control how shadow parameters are passed (comma separated)"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
"enable origins tracking in MemorySanitizer"),
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],

View File

@ -490,6 +490,8 @@ symbols! {
catch_unwind,
cause,
cdylib,
ceilf128,
ceilf16,
ceilf32,
ceilf64,
cfg,
@ -595,6 +597,8 @@ symbols! {
copy,
copy_closures,
copy_nonoverlapping,
copysignf128,
copysignf16,
copysignf32,
copysignf64,
core,
@ -607,6 +611,8 @@ symbols! {
coroutine_resume,
coroutine_state,
coroutines,
cosf128,
cosf16,
cosf32,
cosf64,
count,
@ -737,10 +743,14 @@ symbols! {
exhaustive_integer_patterns,
exhaustive_patterns,
existential_type,
exp2f128,
exp2f16,
exp2f32,
exp2f64,
expect,
expected,
expf128,
expf16,
expf32,
expf64,
explicit_generic_args_with_impl_trait,
@ -759,7 +769,9 @@ symbols! {
external_doc,
f,
f128,
f128_nan,
f16,
f16_nan,
f16c_target_feature,
f32,
f32_legacy_const_digits,
@ -793,6 +805,8 @@ symbols! {
f64_legacy_const_neg_infinity,
f64_legacy_const_radix,
f64_nan,
fabsf128,
fabsf16,
fabsf32,
fabsf64,
fadd_algebraic,
@ -813,8 +827,12 @@ symbols! {
file,
float,
float_to_int_unchecked,
floorf128,
floorf16,
floorf32,
floorf64,
fmaf128,
fmaf16,
fmaf32,
fmaf64,
fmt,
@ -1030,11 +1048,17 @@ symbols! {
loaded_from_disk,
local,
local_inner_macros,
log10f128,
log10f16,
log10f32,
log10f64,
log2f128,
log2f16,
log2f32,
log2f64,
log_syntax,
logf128,
logf16,
logf32,
logf64,
loongarch_target_feature,
@ -1062,6 +1086,8 @@ symbols! {
match_beginning_vert,
match_default_bindings,
matches_macro,
maxnumf128,
maxnumf16,
maxnumf32,
maxnumf64,
may_dangle,
@ -1093,6 +1119,8 @@ symbols! {
min_exhaustive_patterns,
min_specialization,
min_type_alias_impl_trait,
minnumf128,
minnumf16,
minnumf32,
minnumf64,
mips_target_feature,
@ -1155,6 +1183,8 @@ symbols! {
native_link_modifiers_whole_archive,
natvis_file,
ne,
nearbyintf128,
nearbyintf16,
nearbyintf32,
nearbyintf64,
needs_allocator,
@ -1289,8 +1319,12 @@ symbols! {
poll_next,
post_dash_lto: "post-lto",
powerpc_target_feature,
powf128,
powf16,
powf32,
powf64,
powif128,
powif16,
powif32,
powif64,
pre_dash_lto: "pre-lto",
@ -1416,6 +1450,8 @@ symbols! {
return_position_impl_trait_in_trait,
return_type_notation,
rhs,
rintf128,
rintf16,
rintf32,
rintf64,
riscv_target_feature,
@ -1424,8 +1460,12 @@ symbols! {
ropi_rwpi: "ropi-rwpi",
rotate_left,
rotate_right,
roundevenf128,
roundevenf16,
roundevenf32,
roundevenf64,
roundf128,
roundf16,
roundf32,
roundf64,
rt,
@ -1630,6 +1670,8 @@ symbols! {
simd_trunc,
simd_xor,
since,
sinf128,
sinf16,
sinf32,
sinf64,
size,
@ -1647,6 +1689,8 @@ symbols! {
specialization,
speed,
spotlight,
sqrtf128,
sqrtf16,
sqrtf32,
sqrtf64,
sreg,
@ -1746,6 +1790,8 @@ symbols! {
transparent_enums,
transparent_unions,
trivial_bounds,
truncf128,
truncf16,
truncf32,
truncf64,
try_blocks,

View File

@ -464,16 +464,17 @@ fn encode_ty<'tcx>(
typeid.push_str(&s);
}
// Rust's f32 and f64 single (32-bit) and double (64-bit) precision floating-point types
// have IEEE-754 binary32 and binary64 floating-point layouts, respectively.
// Rust's f16, f32, f64, and f126 half (16-bit), single (32-bit), double (64-bit), and
// quad (128-bit) precision floating-point types have IEEE-754 binary16, binary32,
// binary64, and binary128 floating-point layouts, respectively.
//
// (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#fixed-width-floating-point-types.)
ty::Float(float_ty) => {
typeid.push(match float_ty {
FloatTy::F16 => unimplemented!("f16_f128"),
FloatTy::F32 => 'f',
FloatTy::F64 => 'd',
FloatTy::F128 => unimplemented!("f16_f128"),
typeid.push_str(match float_ty {
FloatTy::F16 => "Dh",
FloatTy::F32 => "f",
FloatTy::F64 => "d",
FloatTy::F128 => "g",
});
}
@ -557,7 +558,7 @@ fn encode_ty<'tcx>(
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression).
let builtin_types = [
"v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y",
"n", "o", "f", "d", "e", "g", "z",
"n", "o", "f", "d", "e", "g", "z", "Dh",
];
if !builtin_types.contains(&str) {
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);

View File

@ -320,8 +320,11 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
ty::Uint(UintTy::U64) => "y",
ty::Uint(UintTy::U128) => "o",
ty::Uint(UintTy::Usize) => "j",
// FIXME(f16_f128): update these once `rustc-demangle` supports the new types
ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
ty::Float(FloatTy::F32) => "f",
ty::Float(FloatTy::F64) => "d",
ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
ty::Never => "z",
// Placeholders (should be demangled as `_`).

View File

@ -1221,6 +1221,7 @@ bitflags::bitflags! {
const KCFI = 1 << 8;
const KERNELADDRESS = 1 << 9;
const SAFESTACK = 1 << 10;
const DATAFLOW = 1 << 11;
}
}
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
@ -1233,6 +1234,7 @@ impl SanitizerSet {
Some(match self {
SanitizerSet::ADDRESS => "address",
SanitizerSet::CFI => "cfi",
SanitizerSet::DATAFLOW => "dataflow",
SanitizerSet::KCFI => "kcfi",
SanitizerSet::KERNELADDRESS => "kernel-address",
SanitizerSet::LEAK => "leak",
@ -2790,6 +2792,7 @@ impl Target {
base.$key_name |= match s.as_str() {
Some("address") => SanitizerSet::ADDRESS,
Some("cfi") => SanitizerSet::CFI,
Some("dataflow") => SanitizerSet::DATAFLOW,
Some("kcfi") => SanitizerSet::KCFI,
Some("kernel-address") => SanitizerSet::KERNELADDRESS,
Some("leak") => SanitizerSet::LEAK,

View File

@ -10,6 +10,7 @@ pub fn target() -> Target {
base.static_position_independent_executables = true;
base.supported_sanitizers = SanitizerSet::ADDRESS
| SanitizerSet::CFI
| SanitizerSet::DATAFLOW
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::SAFESTACK

View File

@ -136,6 +136,15 @@ impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for RawWaker {
#[inline(always)]
fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
// Increment the reference count of the arc to clone it.
//
// The #[inline(always)] is to ensure that raw_waker and clone_waker are
// always generated in the same code generation unit as one another, and
// therefore that the structurally identical const-promoted RawWakerVTable
// within both functions is deduplicated at LLVM IR code generation time.
// This allows optimizing Waker::will_wake to a single pointer comparison of
// the vtable pointers, rather than comparing all four function pointers
// within the vtables.
#[inline(always)]
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
unsafe { Arc::increment_strong_count(waker as *const W) };
RawWaker::new(
@ -304,6 +313,10 @@ impl<W: LocalWake + 'static> From<Rc<W>> for RawWaker {
#[inline(always)]
fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
// Increment the reference count of the Rc to clone it.
//
// Refer to the comment on raw_waker's clone_waker regarding why this is
// always inline.
#[inline(always)]
unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
unsafe { Rc::increment_strong_count(waker as *const W) };
RawWaker::new(

View File

@ -41,6 +41,7 @@
#![feature(thin_box)]
#![feature(strict_provenance)]
#![feature(drain_keep_rest)]
#![feature(local_waker)]
#![allow(internal_features)]
#![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)]
@ -62,6 +63,7 @@ mod rc;
mod slice;
mod str;
mod string;
mod task;
mod thin_box;
mod vec;
mod vec_deque;

View File

@ -0,0 +1,34 @@
use alloc::rc::Rc;
use alloc::sync::Arc;
use alloc::task::{LocalWake, Wake};
use core::task::{LocalWaker, Waker};
#[test]
fn test_waker_will_wake_clone() {
struct NoopWaker;
impl Wake for NoopWaker {
fn wake(self: Arc<Self>) {}
}
let waker = Waker::from(Arc::new(NoopWaker));
let clone = waker.clone();
assert!(waker.will_wake(&clone));
assert!(clone.will_wake(&waker));
}
#[test]
fn test_local_waker_will_wake_clone() {
struct NoopWaker;
impl LocalWake for NoopWaker {
fn wake(self: Rc<Self>) {}
}
let waker = LocalWaker::from(Rc::new(NoopWaker));
let clone = waker.clone();
assert!(waker.will_wake(&clone));
assert!(clone.will_wake(&waker));
}

View File

@ -48,7 +48,7 @@ o("codegen-tests", "rust.codegen-tests", "run the tests/codegen tests")
o("ninja", "llvm.ninja", "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)")
o("locked-deps", "build.locked-deps", "force Cargo.lock to be up to date")
o("vendor", "build.vendor", "enable usage of vendored Rust crates")
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, lsan, msan, tsan, hwasan)")
o("sanitizers", "build.sanitizers", "build the sanitizer runtimes (asan, dfsan, lsan, msan, tsan, hwasan)")
o("dist-src", "rust.dist-src", "when building tarballs enables building a source tarball")
o("cargo-native-static", "build.cargo-native-static", "static native libraries in cargo")
o("profiler", "build.profiler", "build the profiler runtime")

View File

@ -1,4 +1,4 @@
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasnt changed.
Last change is for: https://github.com/rust-lang/rust/pull/116881
Last change is for: https://github.com/rust-lang/rust/pull/120761

View File

@ -1088,7 +1088,7 @@ fn supported_sanitizers(
"x86_64-unknown-illumos" => common_libs("illumos", "x86_64", &["asan"]),
"x86_64-pc-solaris" => common_libs("solaris", "x86_64", &["asan"]),
"x86_64-unknown-linux-gnu" => {
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "safestack", "tsan"])
common_libs("linux", "x86_64", &["asan", "dfsan", "lsan", "msan", "safestack", "tsan"])
}
"x86_64-unknown-linux-musl" => {
common_libs("linux", "x86_64", &["asan", "lsan", "msan", "tsan"])

View File

@ -29,6 +29,8 @@ This feature allows for use of one of following sanitizers:
* Those that apart from testing, may be used in production:
* [ControlFlowIntegrity](#controlflowintegrity) LLVM Control Flow Integrity
(CFI) provides forward-edge control flow protection.
* [DataFlowSanitizer](#dataflowsanitizer) a generic dynamic data flow analysis
framework.
* [KernelControlFlowIntegrity](#kernelcontrolflowintegrity) LLVM Kernel
Control Flow Integrity (KCFI) provides forward-edge control flow protection
for operating systems kernels.
@ -39,14 +41,21 @@ This feature allows for use of one of following sanitizers:
* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow
protection (aarch64 only).
To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory`,
`-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or `-Zsanitizer=thread`.
You might also need the `--target` and `build-std` flags. Example:
To enable a sanitizer compile with `-Zsanitizer=address`, `-Zsanitizer=cfi`,
`-Zsanitizer=dataflow`,`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`,
`-Zsanitizer=memory`, `-Zsanitizer=memtag`, `-Zsanitizer=shadow-call-stack`, or
`-Zsanitizer=thread`. You might also need the `--target` and `build-std` flags.
Example:
```shell
$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu
```
Additional options for sanitizers can be passed to LLVM command line argument
processor via LLVM arguments using `llvm-args` codegen option (e.g.,
`-Cllvm-args=-dfsan-combine-pointer-labels-on-load=false`). See the sanitizer
documentation for more information about additional options.
# AddressSanitizer
AddressSanitizer is a memory error detector. It can detect the following types
@ -639,6 +648,21 @@ LLVM KCFI is supported on the following targets:
See the [Clang KernelControlFlowIntegrity documentation][clang-kcfi] for more
details.
# DataFlowSanitizer
DataFlowSanitizer is a generalised dynamic data flow analysis.
Unlike other Sanitizer tools, this tool is not designed to detect a specific
class of bugs on its own. Instead, it provides a generic dynamic data flow
analysis framework to be used by clients to help detect application-specific
issues within their own code.
DataFlowSanitizer is supported on the following targets:
* `x86_64-unknown-linux-gnu`
See the [Clang DataFlowSanitizer documentation][clang-dataflow] for more details.
# KernelAddressSanitizer
KernelAddressSanitizer (KASAN) is a freestanding version of AddressSanitizer
@ -849,6 +873,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
* [AddressSanitizer in Clang][clang-asan]
* [ControlFlowIntegrity in Clang][clang-cfi]
* [DataFlowSanitizer in Clang][clang-dataflow]
* [HWAddressSanitizer in Clang][clang-hwasan]
* [Linux Kernel's KernelAddressSanitizer documentation][linux-kasan]
* [LeakSanitizer in Clang][clang-lsan]
@ -858,6 +883,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
[clang-dataflow]: https://clang.llvm.org/docs/DataFlowSanitizer.html
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html

View File

@ -1777,8 +1777,10 @@ impl PrimitiveType {
hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32,
hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64,
hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128,
hir::PrimTy::Float(FloatTy::F16) => PrimitiveType::F16,
hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32,
hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64,
hir::PrimTy::Float(FloatTy::F128) => PrimitiveType::F128,
hir::PrimTy::Str => PrimitiveType::Str,
hir::PrimTy::Bool => PrimitiveType::Bool,
hir::PrimTy::Char => PrimitiveType::Char,
@ -1977,8 +1979,10 @@ impl From<ast::UintTy> for PrimitiveType {
impl From<ast::FloatTy> for PrimitiveType {
fn from(float_ty: ast::FloatTy) -> PrimitiveType {
match float_ty {
ast::FloatTy::F16 => PrimitiveType::F16,
ast::FloatTy::F32 => PrimitiveType::F32,
ast::FloatTy::F64 => PrimitiveType::F64,
ast::FloatTy::F128 => PrimitiveType::F128,
}
}
}

View File

@ -75,9 +75,12 @@ impl ApproxConstant {
fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
match *lit {
LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"),
FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"),
},
// FIXME(f16_f128): add `f16` and `f128` when these types become stable.
LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
_ => (),
}

View File

@ -76,8 +76,10 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
let digits = count_digits(sym_str);
let max = max_digits(fty);
let type_suffix = match lit_float_ty {
LitFloatType::Suffixed(ast::FloatTy::F16) => Some("f16"),
LitFloatType::Suffixed(ast::FloatTy::F32) => Some("f32"),
LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
LitFloatType::Suffixed(ast::FloatTy::F128) => Some("f128"),
LitFloatType::Unsuffixed => None,
};
let (is_whole, is_inf, mut float_str) = match fty {

View File

@ -277,12 +277,16 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option<Ty<'tcx>>) -> Constan
LitKind::Char(c) => Constant::Char(c),
LitKind::Int(n, _) => Constant::Int(n.get()),
LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty {
ast::FloatTy::F16 => unimplemented!("f16_f128"),
ast::FloatTy::F32 => Constant::F32(is.as_str().parse().unwrap()),
ast::FloatTy::F64 => Constant::F64(is.as_str().parse().unwrap()),
ast::FloatTy::F128 => unimplemented!("f16_f128"),
},
LitKind::Float(ref is, LitFloatType::Unsuffixed) => match ty.expect("type of float is known").kind() {
ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
ty::Float(FloatTy::F32) => Constant::F32(is.as_str().parse().unwrap()),
ty::Float(FloatTy::F64) => Constant::F64(is.as_str().parse().unwrap()),
ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
_ => bug!(),
},
LitKind::Bool(b) => Constant::Bool(b),

View File

@ -156,6 +156,7 @@ impl PanicStrategy {
pub enum Sanitizer {
Address,
Cfi,
Dataflow,
Kcfi,
KernelAddress,
Leak,

View File

@ -29,6 +29,11 @@ pub(super) fn handle_needs(
condition: cache.sanitizer_cfi,
ignore_reason: "ignored on targets without CFI sanitizer",
},
Need {
name: "needs-sanitizer-dataflow",
condition: cache.sanitizer_dataflow,
ignore_reason: "ignored on targets without dataflow sanitizer",
},
Need {
name: "needs-sanitizer-kcfi",
condition: cache.sanitizer_kcfi,
@ -190,6 +195,7 @@ pub(super) struct CachedNeedsConditions {
sanitizer_support: bool,
sanitizer_address: bool,
sanitizer_cfi: bool,
sanitizer_dataflow: bool,
sanitizer_kcfi: bool,
sanitizer_kasan: bool,
sanitizer_leak: bool,
@ -229,6 +235,7 @@ impl CachedNeedsConditions {
sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(),
sanitizer_address: sanitizers.contains(&Sanitizer::Address),
sanitizer_cfi: sanitizers.contains(&Sanitizer::Cfi),
sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow),
sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),

View File

@ -43,6 +43,7 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[
"tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
"tests/ui/proc-macro/auxiliary/included-file.txt", // more include
"tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
"tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file
"tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
"tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file
"tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file

View File

@ -0,0 +1,10 @@
// Verifies that functions are instrumented.
//
//@ needs-sanitizer-dataflow
//@ compile-flags: -Copt-level=0 -Zsanitizer=dataflow
#![crate_type="lib"]
pub fn foo() {
}
// CHECK: define{{.*}}foo{{.*}}.dfsan

View File

@ -51,13 +51,13 @@
- }
-
- bb3: {
StorageLive(_9);
_9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_8);
_8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
StorageLive(_9);
_9 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
_0 = const 0_u32;
StorageDead(_8);
StorageDead(_9);
StorageDead(_8);
- goto -> bb4;
+ goto -> bb3;
}

View File

@ -57,13 +57,13 @@
- }
-
- bb4: {
StorageLive(_10);
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_9);
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
StorageLive(_10);
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
_0 = const 0_u32;
StorageDead(_9);
StorageDead(_10);
StorageDead(_9);
- goto -> bb6;
+ goto -> bb4;
}

View File

@ -51,13 +51,13 @@
- }
-
- bb3: {
StorageLive(_9);
_9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
StorageLive(_8);
_8 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
StorageLive(_9);
_9 = (((_3.1: std::option::Option<bool>) as Some).0: bool);
_0 = const 0_u32;
StorageDead(_8);
StorageDead(_9);
StorageDead(_8);
- goto -> bb4;
+ goto -> bb3;
}

View File

@ -69,16 +69,16 @@
- bb4: {
+ bb3: {
StorageLive(_13);
_13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
StorageLive(_12);
_12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_11);
_11 = (((_4.0: std::option::Option<u32>) as Some).0: u32);
StorageLive(_12);
_12 = (((_4.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_13);
_13 = (((_4.2: std::option::Option<u32>) as Some).0: u32);
_0 = const 0_u32;
StorageDead(_11);
StorageDead(_12);
StorageDead(_13);
StorageDead(_12);
StorageDead(_11);
- goto -> bb5;
+ goto -> bb4;
}

View File

@ -116,12 +116,12 @@
}
bb6: {
StorageLive(_13);
_39 = deref_copy (_4.1: &ViewportPercentageLength);
_13 = (((*_39) as Vw).0: f32);
StorageLive(_12);
_40 = deref_copy (_4.0: &ViewportPercentageLength);
_12 = (((*_40) as Vw).0: f32);
_39 = deref_copy (_4.0: &ViewportPercentageLength);
_12 = (((*_39) as Vw).0: f32);
StorageLive(_13);
_40 = deref_copy (_4.1: &ViewportPercentageLength);
_13 = (((*_40) as Vw).0: f32);
StorageLive(_14);
StorageLive(_15);
_15 = _12;
@ -132,18 +132,18 @@
StorageDead(_15);
_3 = ViewportPercentageLength::Vw(move _14);
StorageDead(_14);
StorageDead(_12);
StorageDead(_13);
StorageDead(_12);
goto -> bb10;
}
bb7: {
StorageLive(_18);
_41 = deref_copy (_4.1: &ViewportPercentageLength);
_18 = (((*_41) as Vh).0: f32);
StorageLive(_17);
_42 = deref_copy (_4.0: &ViewportPercentageLength);
_17 = (((*_42) as Vh).0: f32);
_41 = deref_copy (_4.0: &ViewportPercentageLength);
_17 = (((*_41) as Vh).0: f32);
StorageLive(_18);
_42 = deref_copy (_4.1: &ViewportPercentageLength);
_18 = (((*_42) as Vh).0: f32);
StorageLive(_19);
StorageLive(_20);
_20 = _17;
@ -154,18 +154,18 @@
StorageDead(_20);
_3 = ViewportPercentageLength::Vh(move _19);
StorageDead(_19);
StorageDead(_17);
StorageDead(_18);
StorageDead(_17);
goto -> bb10;
}
bb8: {
StorageLive(_23);
_43 = deref_copy (_4.1: &ViewportPercentageLength);
_23 = (((*_43) as Vmin).0: f32);
StorageLive(_22);
_44 = deref_copy (_4.0: &ViewportPercentageLength);
_22 = (((*_44) as Vmin).0: f32);
_43 = deref_copy (_4.0: &ViewportPercentageLength);
_22 = (((*_43) as Vmin).0: f32);
StorageLive(_23);
_44 = deref_copy (_4.1: &ViewportPercentageLength);
_23 = (((*_44) as Vmin).0: f32);
StorageLive(_24);
StorageLive(_25);
_25 = _22;
@ -176,18 +176,18 @@
StorageDead(_25);
_3 = ViewportPercentageLength::Vmin(move _24);
StorageDead(_24);
StorageDead(_22);
StorageDead(_23);
StorageDead(_22);
goto -> bb10;
}
bb9: {
StorageLive(_28);
_45 = deref_copy (_4.1: &ViewportPercentageLength);
_28 = (((*_45) as Vmax).0: f32);
StorageLive(_27);
_46 = deref_copy (_4.0: &ViewportPercentageLength);
_27 = (((*_46) as Vmax).0: f32);
_45 = deref_copy (_4.0: &ViewportPercentageLength);
_27 = (((*_45) as Vmax).0: f32);
StorageLive(_28);
_46 = deref_copy (_4.1: &ViewportPercentageLength);
_28 = (((*_46) as Vmax).0: f32);
StorageLive(_29);
StorageLive(_30);
_30 = _27;
@ -198,8 +198,8 @@
StorageDead(_30);
_3 = ViewportPercentageLength::Vmax(move _29);
StorageDead(_29);
StorageDead(_27);
StorageDead(_28);
StorageDead(_27);
goto -> bb10;
}

View File

@ -59,13 +59,13 @@
}
bb5: {
StorageLive(_10);
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
StorageLive(_9);
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32);
StorageLive(_10);
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32);
_0 = const 0_u32;
StorageDead(_9);
StorageDead(_10);
StorageDead(_9);
goto -> bb8;
}

View File

@ -19,8 +19,7 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
bb0: {
PlaceMention(_1);
_2 = discriminant((_1.2: std::option::Option<i32>));
switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1];
}
bb1: {
@ -29,11 +28,12 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
}
bb2: {
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1];
_2 = discriminant((_1.2: std::option::Option<i32>));
switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1];
}
bb3: {
switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1];
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1];
}
bb4: {

View File

@ -100,7 +100,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
LL | sanitize = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expected values for `sanitize` are: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
= note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
= note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`

View File

@ -1,5 +1,5 @@
error[E0282]: type annotations needed
--> $DIR/hidden-type-is-opaque-2.rs:8:17
--> $DIR/hidden-type-is-opaque-2.rs:10:17
|
LL | Thunk::new(|mut cont| {
| ^^^^^^^^
@ -13,7 +13,7 @@ LL | Thunk::new(|mut cont: /* Type */| {
| ++++++++++++
error[E0282]: type annotations needed
--> $DIR/hidden-type-is-opaque-2.rs:18:17
--> $DIR/hidden-type-is-opaque-2.rs:20:17
|
LL | Thunk::new(|mut cont| {
| ^^^^^^^^

View File

@ -0,0 +1,31 @@
error[E0282]: type annotations needed
--> $DIR/hidden-type-is-opaque-2.rs:10:17
|
LL | Thunk::new(|mut cont| {
| ^^^^^^^^
LL |
LL | cont.reify_as();
| ---- type must be known at this point
|
help: consider giving this closure parameter an explicit type
|
LL | Thunk::new(|mut cont: /* Type */| {
| ++++++++++++
error[E0282]: type annotations needed
--> $DIR/hidden-type-is-opaque-2.rs:20:17
|
LL | Thunk::new(|mut cont| {
| ^^^^^^^^
LL |
LL | cont.reify_as();
| ---- type must be known at this point
|
help: consider giving this closure parameter an explicit type
|
LL | Thunk::new(|mut cont: /* Type */| {
| ++++++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0282`.

View File

@ -1,6 +1,8 @@
// This doesn't work, because we don't flow information from opaque types
// into function arguments via the function's generic parameters
// FIXME(oli-obk): make `expected_inputs_for_expected_output` support this
//@ revisions: default next
//@[next] compile-flags: -Znext-solver
#![feature(type_alias_impl_trait)]

View File

@ -0,0 +1,17 @@
//@ known-bug: unknown
#![allow(unused)]
struct A(u32);
pub fn main() {
// The or-pattern bindings are lowered after `x`, which triggers the error.
let x @ (A(a) | A(a)) = A(10);
// ERROR: use of moved value
assert!(x.0 == 10);
assert!(a == 10);
// This works.
let (x @ A(a) | x @ A(a)) = A(10);
assert!(x.0 == 10);
assert!(a == 10);
}

View File

@ -0,0 +1,31 @@
error[E0382]: use of moved value
--> $DIR/bind-by-copy-or-pat.rs:8:16
|
LL | let x @ (A(a) | A(a)) = A(10);
| - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait
| | |
| | value used here after move
| value moved here
|
help: borrow this binding in the pattern to avoid moving the value
|
LL | let ref x @ (A(a) | A(a)) = A(10);
| +++
error[E0382]: use of moved value
--> $DIR/bind-by-copy-or-pat.rs:8:23
|
LL | let x @ (A(a) | A(a)) = A(10);
| - ^ ----- move occurs because value has type `A`, which does not implement the `Copy` trait
| | |
| | value used here after move
| value moved here
|
help: borrow this binding in the pattern to avoid moving the value
|
LL | let ref x @ (A(a) | A(a)) = A(10);
| +++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.

View File

@ -0,0 +1,505 @@
fun:main=uninstrumented
fun:main=discard
###############################################################################
# DFSan interface functions
###############################################################################
fun:dfsan_union=uninstrumented
fun:dfsan_union=discard
fun:dfsan_create_label=uninstrumented
fun:dfsan_create_label=discard
fun:dfsan_set_label=uninstrumented
fun:dfsan_set_label=discard
fun:dfsan_add_label=uninstrumented
fun:dfsan_add_label=discard
fun:dfsan_get_label=uninstrumented
fun:dfsan_get_label=custom
fun:dfsan_read_label=uninstrumented
fun:dfsan_read_label=discard
fun:dfsan_get_label_count=uninstrumented
fun:dfsan_get_label_count=discard
fun:dfsan_get_label_info=uninstrumented
fun:dfsan_get_label_info=discard
fun:dfsan_has_label=uninstrumented
fun:dfsan_has_label=discard
fun:dfsan_has_label_with_desc=uninstrumented
fun:dfsan_has_label_with_desc=discard
fun:dfsan_set_write_callback=uninstrumented
fun:dfsan_set_write_callback=custom
fun:dfsan_flush=uninstrumented
fun:dfsan_flush=discard
fun:dfsan_print_origin_trace=uninstrumented
fun:dfsan_print_origin_trace=discard
fun:dfsan_print_origin_id_trace=uninstrumented
fun:dfsan_print_origin_id_trace=discard
fun:dfsan_sprint_origin_trace=uninstrumented
fun:dfsan_sprint_origin_trace=discard
fun:dfsan_sprint_origin_id_trace=uninstrumented
fun:dfsan_sprint_origin_id_trace=discard
fun:dfsan_sprint_stack_trace=uninstrumented
fun:dfsan_sprint_stack_trace=discard
fun:dfsan_get_origin=uninstrumented
fun:dfsan_get_origin=custom
fun:dfsan_read_origin_of_first_taint=uninstrumented
fun:dfsan_read_origin_of_first_taint=discard
fun:dfsan_get_init_origin=uninstrumented
fun:dfsan_get_init_origin=discard
fun:dfsan_get_track_origins=uninstrumented
fun:dfsan_get_track_origins=discard
fun:dfsan_set_conditional_callback=uninstrumented
fun:dfsan_set_conditional_callback=discard
fun:dfsan_get_labels_in_signal_conditional=uninstrumented
fun:dfsan_get_labels_in_signal_conditional=discard
fun:dfsan_set_reaches_function_callback=uninstrumented
fun:dfsan_set_reaches_function_callback=discard
fun:dfsan_get_labels_in_signal_reaches_function=uninstrumented
fun:dfsan_get_labels_in_signal_reaches_function=discard
fun:dfsan_reaches_function_callback=uninstrumented
fun:dfsan_reaches_function_callback=discard
###############################################################################
# glibc
###############################################################################
# Functions of memory allocators
fun:__libc_memalign=discard
fun:aligned_alloc=discard
fun:calloc=discard
fun:cfree=discard
fun:mallinfo=discard
fun:malloc=discard
fun:free=discard
fun:malloc_stats=discard
fun:malloc_usable_size=discard
fun:mallopt=discard
fun:memalign=discard
fun:posix_memalign=discard
fun:pvalloc=discard
fun:realloc=discard
fun:reallocarray=discard
fun:valloc=discard
# Functions that return a value that depends on the input, but the output might
# not be necessarily data-dependent on the input.
fun:isalpha=functional
fun:isdigit=functional
fun:isprint=functional
fun:isxdigit=functional
fun:isalnum=functional
fun:ispunct=functional
fun:isspace=functional
fun:tolower=functional
fun:_tolower=functional
fun:toupper=functional
# Functions that return a value that is data-dependent on the input.
fun:__isinf=functional
fun:__isinff=functional
fun:__signbit=functional
fun:__signbitf=functional
fun:__signbitl=functional
fun:btowc=functional
fun:exp=functional
fun:exp2=functional
fun:expf=functional
fun:expl=functional
fun:fabs=functional
fun:finite=functional
fun:finitef=functional
fun:finitel=functional
fun:floor=functional
fun:fmod=functional
fun:isinf=functional
fun:isinff=functional
fun:isinfl=functional
fun:isnan=functional
fun:isnanf=functional
fun:isnanl=functional
fun:log=functional
fun:log1p=functional
fun:log1pf=functional
fun:log1pl=functional
fun:log2=functional
fun:log2f=functional
fun:log2l=functional
fun:modf=functional
fun:nextafter=functional
fun:nextafterf=functional
fun:nextafterl=functional
fun:nexttoward=functional
fun:nexttowardf=functional
fun:nexttowardl=functional
fun:pow=functional
fun:powf=functional
fun:powl=functional
fun:round=functional
fun:sqrt=functional
fun:sqrtf=functional
fun:sqrtl=functional
fun:wctob=functional
# Functions that produce an output that does not depend on the input (shadow is
# zeroed automatically).
fun:__assert_fail=discard
fun:__cmsg_nxthdr=discard
fun:__ctype_b_loc=discard
fun:__cxa_atexit=discard
fun:__errno_location=discard
fun:__newlocale=discard
fun:__sbrk=discard
fun:__sigsetjmp=discard
fun:__uselocale=discard
fun:__wctype_l=discard
fun:access=discard
fun:alarm=discard
fun:atexit=discard
fun:bind=discard
fun:chdir=discard
fun:close=discard
fun:closedir=discard
fun:connect=discard
fun:creat=discard
fun:dladdr=discard
fun:dlclose=discard
fun:epoll_create=discard
fun:epoll_create1=discard
fun:epoll_ctl=discard
fun:fclose=discard
fun:feof=discard
fun:ferror=discard
fun:fflush=discard
fun:fileno=discard
fun:fopen=discard
fun:fprintf=discard
fun:fputc=discard
fun:fputc=discard
fun:fputs=discard
fun:fputs=discard
fun:fseek=discard
fun:ftell=discard
fun:fwrite=discard
fun:getenv=discard
fun:getuid=discard
fun:geteuid=discard
fun:getpagesize=discard
fun:getpid=discard
fun:kill=discard
fun:listen=discard
fun:lseek=discard
fun:mkdir=discard
fun:mmap=discard
fun:munmap=discard
fun:open=discard
fun:openat=discard
fun:pipe=discard
fun:posix_fadvise=discard
fun:prctl=discard
fun:printf=discard
fun:pthread_sigmask=discard
fun:putc=discard
fun:putchar=discard
fun:puts=discard
fun:rand=discard
fun:random=discard
fun:remove=discard
fun:sched_getcpu=discard
fun:sched_get_priority_max=discard
fun:sched_setaffinity=discard
fun:sched_yield=discard
fun:sem_destroy=discard
fun:sem_init=discard
fun:sem_post=discard
fun:sem_wait=discard
fun:send=discard
fun:sendmsg=discard
fun:sendto=discard
fun:setsockopt=discard
fun:shutdown=discard
fun:sleep=discard
fun:socket=discard
fun:strerror=discard
fun:strspn=discard
fun:strcspn=discard
fun:symlink=discard
fun:syscall=discard
fun:unlink=discard
fun:uselocale=discard
fun:vfprintf=discard
# Functions that produce output does not depend on the input (need to zero the
# shadow manually).
fun:_dl_get_tls_static_info=custom
fun:clock_gettime=custom
fun:dlopen=custom
fun:epoll_wait=custom
fun:fgets=custom
fun:fstat=custom
fun:getcwd=custom
fun:get_current_dir_name=custom
fun:getentropy=custom
fun:gethostname=custom
fun:getpeername=custom
fun:getrlimit=custom
fun:getrusage=custom
fun:getsockname=custom
fun:getsockopt=custom
fun:nanosleep=custom
fun:pread=custom
fun:read=custom
fun:recvmmsg=custom
fun:recvmsg=custom
fun:sigaltstack=custom
fun:socketpair=custom
fun:stat=custom
fun:time=custom
# Functions that produce an output that depend on the input (propagate the
# shadow manually).
fun:ctime_r=custom
fun:inet_pton=custom
fun:localtime_r=custom
fun:memcpy=custom
fun:memmove=custom
fun:memset=custom
fun:strcpy=custom
fun:strdup=custom
fun:strncpy=custom
fun:strtod=custom
fun:strtol=custom
fun:strtoll=custom
fun:strtoul=custom
fun:strtoull=custom
fun:strcat=custom
fun:strncat=custom
fun:__isoc23_strtod=custom
fun:__isoc23_strtol=custom
fun:__isoc23_strtoll=custom
fun:__isoc23_strtoul=custom
fun:__isoc23_strtoull=custom
# Functions that produce an output that is computed from the input, but is not
# necessarily data dependent.
fun:bcmp=custom
fun:memchr=custom
fun:memcmp=custom
fun:strcasecmp=custom
fun:strchr=custom
fun:strcmp=custom
fun:strlen=custom
fun:strnlen=custom
fun:strncasecmp=custom
fun:strncmp=custom
fun:strpbrk=custom
fun:strrchr=custom
fun:strstr=custom
fun:strsep=custom
# Functions which take action based on global state, such as running a callback
# set by a separate function.
fun:write=custom
# Functions that take a callback (wrap the callback manually).
fun:dl_iterate_phdr=custom
fun:getpwuid_r=custom
fun:poll=custom
fun:sched_getaffinity=custom
fun:select=custom
fun:sigemptyset=custom
fun:sigaction=custom
fun:signal=custom
fun:gettimeofday=custom
# sprintf-like
fun:sprintf=custom
fun:snprintf=custom
# scanf-like
fun:sscanf=custom
fun:__isoc99_sscanf=custom
fun:__isoc23_sscanf=custom
# TODO: custom
fun:asprintf=discard
fun:qsort=discard
# fork
fun:fork=custom
###############################################################################
# pthread
###############################################################################
fun:__pthread_register_cancel=discard
fun:__pthread_unregister_cancel=discard
fun:pthread_attr_destroy=discard
fun:pthread_attr_getaffinity_np=discard
fun:pthread_attr_getdetachstate=discard
fun:pthread_attr_getguardsize=discard
fun:pthread_attr_getinheritsched=discard
fun:pthread_attr_getschedparam=discard
fun:pthread_attr_getschedpolicy=discard
fun:pthread_attr_getscope=discard
fun:pthread_attr_getstack=discard
fun:pthread_attr_getstackaddr=disacrd
fun:pthread_attr_getstacksize=discard
fun:pthread_attr_init=discard
fun:pthread_attr_setaffinity_np=discard
fun:pthread_attr_setdetachstate=discard
fun:pthread_attr_setguardsize=discard
fun:pthread_attr_setinheritsched=discard
fun:pthread_attr_setschedparam=discard
fun:pthread_attr_setschedpolicy=discard
fun:pthread_attr_setscope=discard
fun:pthread_attr_setstack=discard
fun:pthread_attr_setstackaddr=discard
fun:pthread_attr_setstacksize=discard
fun:pthread_equal=discard
fun:pthread_getschedparam=discard
fun:pthread_getspecific=discard
fun:pthread_key_create=discard
fun:pthread_key_delete=discard
fun:pthread_mutex_destroy=discard
fun:pthread_mutex_init=discard
fun:pthread_mutex_lock=discard
fun:pthread_mutex_trylock=discard
fun:pthread_mutex_unlock=discard
fun:pthread_mutexattr_destroy=discard
fun:pthread_mutexattr_init=discard
fun:pthread_mutexattr_settype=discard
fun:pthread_rwlock_destroy=discard
fun:pthread_rwlock_init=discard
fun:pthread_rwlock_rdlock=discard
fun:pthread_rwlock_timedrdlock=discard
fun:pthread_rwlock_timedwrlock=discard
fun:pthread_rwlock_tryrdlock=discard
fun:pthread_rwlock_trywrlock=discard
fun:pthread_rwlock_wrlock=discard
fun:pthread_rwlock_unlock=discard
fun:pthread_setschedparam=discard
fun:pthread_setname_np=discard
fun:pthread_once=discard
fun:pthread_self=discard
fun:pthread_setspecific=discard
# Functions that take a callback (wrap the callback manually).
fun:pthread_create=custom
# Functions that produce output does not depend on the input (need to zero the
# shadow manually).
fun:pthread_join=custom
###############################################################################
# libffi/libgo
###############################################################################
# Functions that are written in asm or are called from asm.
fun:ffi_call_unix64=uninstrumented
fun:ffi_call_unix64=discard
fun:ffi_closure_unix64_inner=uninstrumented
fun:ffi_closure_unix64_inner=discard
fun:ffi_closure_unix64=uninstrumented
fun:ffi_closure_unix64=discard
fun:__go_get_closure=uninstrumented
fun:__go_get_closure=discard
fun:__go_makefunc_can_recover=uninstrumented
fun:__go_makefunc_can_recover=discard
fun:__go_makefunc_returning=uninstrumented
fun:__go_makefunc_returning=discard
fun:reflect.MakeFuncStubGo=uninstrumented
fun:reflect.MakeFuncStubGo=discard
fun:reflect.makeFuncStub=uninstrumented
fun:reflect.makeFuncStub=discard
###############################################################################
# lib/Fuzzer
###############################################################################
# Replaces __sanitizer_cov_trace_cmp with __dfsw___sanitizer_cov_trace_cmp
fun:__sanitizer_cov_trace_cmp1=custom
fun:__sanitizer_cov_trace_cmp1=uninstrumented
fun:__sanitizer_cov_trace_cmp2=custom
fun:__sanitizer_cov_trace_cmp2=uninstrumented
fun:__sanitizer_cov_trace_cmp4=custom
fun:__sanitizer_cov_trace_cmp4=uninstrumented
fun:__sanitizer_cov_trace_cmp8=custom
fun:__sanitizer_cov_trace_cmp8=uninstrumented
fun:__sanitizer_cov_trace_const_cmp1=custom
fun:__sanitizer_cov_trace_const_cmp1=uninstrumented
fun:__sanitizer_cov_trace_const_cmp2=custom
fun:__sanitizer_cov_trace_const_cmp2=uninstrumented
fun:__sanitizer_cov_trace_const_cmp4=custom
fun:__sanitizer_cov_trace_const_cmp4=uninstrumented
fun:__sanitizer_cov_trace_const_cmp8=custom
fun:__sanitizer_cov_trace_const_cmp8=uninstrumented
# Similar for __sanitizer_cov_trace_switch
fun:__sanitizer_cov_trace_switch=custom
fun:__sanitizer_cov_trace_switch=uninstrumented
# Ignores all other __sanitizer callbacks.
fun:__sanitizer_cov=uninstrumented
fun:__sanitizer_cov=discard
fun:__sanitizer_cov_module_init=uninstrumented
fun:__sanitizer_cov_module_init=discard
fun:__sanitizer_cov_with_check=uninstrumented
fun:__sanitizer_cov_with_check=discard
fun:__sanitizer_set_death_callback=uninstrumented
fun:__sanitizer_set_death_callback=discard
fun:__sanitizer_update_counter_bitset_and_clear_counters=uninstrumented
fun:__sanitizer_update_counter_bitset_and_clear_counters=discard
fun:__sanitizer_cov_trace_pc*=uninstrumented
fun:__sanitizer_cov_trace_pc*=discard
fun:__sanitizer_cov_pcs_init=uninstrumented
fun:__sanitizer_cov_pcs_init=discard
fun:__sanitizer_get_current_allocated_bytes=uninstrumented
fun:__sanitizer_get_current_allocated_bytes=discard
fun:__sanitizer_get_heap_size=uninstrumented
fun:__sanitizer_get_heap_size=discard
fun:__sanitizer_get_free_bytes=uninstrumented
fun:__sanitizer_get_free_bytes=discard
fun:__sanitizer_get_unmapped_bytes=uninstrumented
fun:__sanitizer_get_unmapped_bytes=discard
fun:__sanitizer_get_estimated_allocated_size=uninstrumented
fun:__sanitizer_get_estimated_allocated_size=discard
fun:__sanitizer_get_ownership=uninstrumented
fun:__sanitizer_get_ownership=discard
fun:__sanitizer_get_allocated_begin=uninstrumented
fun:__sanitizer_get_allocated_begin=discard
fun:__sanitizer_get_allocated_size=uninstrumented
fun:__sanitizer_get_allocated_size=discard
fun:__sanitizer_get_allocated_size_fast=uninstrumented
fun:__sanitizer_get_allocated_size_fast=discard
fun:__sanitizer_print_stack_trace=uninstrumented
fun:__sanitizer_print_stack_trace=discard
fun:TcmallocSlab_Internal_PushBatch_FixedShift=uninstrumented
fun:TcmallocSlab_Internal_PushBatch_FixedShift=discard
fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=uninstrumented
fun:TcmallocSlab_Internal_PushBatch_FixedShift_VCPU=discard
fun:TcmallocSlab_Internal_PerCpuCmpxchg64=uninstrumented
fun:TcmallocSlab_Internal_PerCpuCmpxchg64=discard
fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=uninstrumented
fun:TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU=discard
fun:TcmallocSlab_Internal_PopBatch_FixedShift=uninstrumented
fun:TcmallocSlab_Internal_PopBatch_FixedShift=discard
fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=uninstrumented
fun:TcmallocSlab_Internal_PopBatch_FixedShift_VCPU=discard
# Ignores the dfsan wrappers.
fun:__dfsw_*=uninstrumented
fun:__dfsw_*=discard
fun:__dfso_*=uninstrumented
fun:__dfso_*=discard
# Rust functions.
fun:__rdl_alloc=uninstrumented
fun:__rdl_alloc_zeroed=uninstrumented
fun:__rdl_dealloc=uninstrumented
fun:__rdl_realloc=uninstrumented
fun:__rg_oom=uninstrumented
fun:__rust_alloc=uninstrumented
fun:__rust_alloc_error_handler=uninstrumented
fun:__rust_alloc_zeroed=uninstrumented
fun:__rust_dealloc=uninstrumented
fun:__rust_realloc=uninstrumented
fun:_ZN4core*=uninstrumented
fun:_ZN3std*=uninstrumented
fun:rust_eh_personality=uninstrumented

View File

@ -0,0 +1,60 @@
#![allow(non_camel_case_types)]
// Verifies that labels are propagated through loads and stores.
//
//@ needs-sanitizer-support
//@ needs-sanitizer-dataflow
//@ run-pass
//@ compile-flags: -Zsanitizer=dataflow -Zsanitizer-dataflow-abilist={{src-base}}/sanitizer/dataflow-abilist.txt
use std::mem::size_of;
use std::os::raw::{c_int, c_long, c_void};
type dfsan_label = u8;
extern "C" {
fn dfsan_add_label(label: dfsan_label, addr: *mut c_void, size: usize);
fn dfsan_get_label(data: c_long) -> dfsan_label;
fn dfsan_has_label(label: dfsan_label, elem: dfsan_label) -> c_int;
fn dfsan_read_label(addr: *const c_void, size: usize) -> dfsan_label;
fn dfsan_set_label(label: dfsan_label, addr: *mut c_void, size: usize);
}
fn propagate2(i: &i64) -> i64 {
i.clone()
}
fn propagate(i: i64) -> i64 {
let v = vec!(i, 1, 2, 3);
let j = v.iter().sum();
propagate2(&j)
}
pub fn main() {
let mut i = 1i64;
let i_ptr = &mut i as *mut i64;
let i_label: dfsan_label = 1;
unsafe {
dfsan_set_label(i_label, i_ptr as *mut c_void, size_of::<i64>());
}
let new_label = unsafe { dfsan_get_label(i) };
assert_eq!(i_label, new_label);
let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
assert_eq!(i_label, read_label);
let j_label: dfsan_label = 2;
unsafe {
dfsan_add_label(j_label, i_ptr as *mut c_void, size_of::<i64>());
}
let read_label = unsafe { dfsan_read_label(i_ptr as *const c_void, size_of::<i64>()) };
assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
let mut new_i = propagate(i);
let new_i_ptr = &mut new_i as *mut i64;
let read_label = unsafe { dfsan_read_label(new_i_ptr as *const c_void, size_of::<i64>()) };
assert_eq!(unsafe { dfsan_has_label(read_label, i_label) }, 1);
assert_eq!(unsafe { dfsan_has_label(read_label, j_label) }, 1);
}