Auto merge of #143337 - matthiaskrgr:rollup-lqwhe0i, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - rust-lang/rust#141847 (Explain `TOCTOU` on the top of `std::fs`, and reference it in functions) - rust-lang/rust#142138 (Add `Vec::into_chunks`) - rust-lang/rust#142321 (Expose elf abi on ppc64 targets) - rust-lang/rust#142886 (ci: aarch64-gnu: Stop skipping `panic_abort_doc_tests`) - rust-lang/rust#143194 (fix bitcast of single-element SIMD vectors) - rust-lang/rust#143231 (Suggest use another lifetime specifier instead of underscore lifetime) - rust-lang/rust#143232 ([COMPILETEST-UNTANGLE 3/N] Use "directives" consistently within compiletest) - rust-lang/rust#143258 (Don't recompute `DisambiguatorState` for every RPITIT in trait definition) - rust-lang/rust#143274 (ci: support optional jobs) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6677875279
42 changed files with 306 additions and 132 deletions
|
|
@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// While optimizations will remove no-op transmutes, they might still be
|
||||
// there in debug or things that aren't no-op in MIR because they change
|
||||
// the Rust type but not the underlying layout/niche.
|
||||
if from_scalar == to_scalar {
|
||||
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
|
||||
return imm;
|
||||
}
|
||||
|
||||
|
|
@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => {
|
||||
if from_backend_ty == to_backend_ty {
|
||||
imm
|
||||
} else {
|
||||
bx.bitcast(imm, to_backend_ty)
|
||||
}
|
||||
}
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
|
||||
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
|
||||
(Pointer(..), Int(..)) => {
|
||||
|
|
|
|||
|
|
@ -2459,13 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
// type a projection.
|
||||
let in_trait = match opaque_ty.origin {
|
||||
hir::OpaqueTyOrigin::FnReturn {
|
||||
parent,
|
||||
in_trait_or_impl: Some(hir::RpitContext::Trait),
|
||||
..
|
||||
}
|
||||
| hir::OpaqueTyOrigin::AsyncFn {
|
||||
parent,
|
||||
in_trait_or_impl: Some(hir::RpitContext::Trait),
|
||||
..
|
||||
} => true,
|
||||
} => Some(parent),
|
||||
hir::OpaqueTyOrigin::FnReturn {
|
||||
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
|
||||
..
|
||||
|
|
@ -2474,7 +2476,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
in_trait_or_impl: None | Some(hir::RpitContext::TraitImpl),
|
||||
..
|
||||
}
|
||||
| hir::OpaqueTyOrigin::TyAlias { .. } => false,
|
||||
| hir::OpaqueTyOrigin::TyAlias { .. } => None,
|
||||
};
|
||||
|
||||
self.lower_opaque_ty(opaque_ty.def_id, in_trait)
|
||||
|
|
@ -2594,17 +2596,25 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
|
||||
/// Lower an opaque type (i.e., an existential impl-Trait type) from the HIR.
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: bool) -> Ty<'tcx> {
|
||||
fn lower_opaque_ty(&self, def_id: LocalDefId, in_trait: Option<LocalDefId>) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
let lifetimes = tcx.opaque_captured_lifetimes(def_id);
|
||||
debug!(?lifetimes);
|
||||
|
||||
// If this is an RPITIT and we are using the new RPITIT lowering scheme, we
|
||||
// generate the def_id of an associated type for the trait and return as
|
||||
// type a projection.
|
||||
let def_id = if in_trait {
|
||||
tcx.associated_type_for_impl_trait_in_trait(def_id).to_def_id()
|
||||
// If this is an RPITIT and we are using the new RPITIT lowering scheme,
|
||||
// do a linear search to map this to the synthetic associated type that
|
||||
// it will be lowered to.
|
||||
let def_id = if let Some(parent_def_id) = in_trait {
|
||||
*tcx.associated_types_for_impl_traits_in_associated_fn(parent_def_id)
|
||||
.iter()
|
||||
.find(|rpitit| match tcx.opt_rpitit_info(**rpitit) {
|
||||
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
|
||||
opaque_def_id.expect_local() == def_id
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.unwrap()
|
||||
} else {
|
||||
def_id.to_def_id()
|
||||
};
|
||||
|
|
@ -2627,7 +2637,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
});
|
||||
debug!(?args);
|
||||
|
||||
if in_trait {
|
||||
if in_trait.is_some() {
|
||||
Ty::new_projection_from_args(tcx, def_id, args)
|
||||
} else {
|
||||
Ty::new_opaque(tcx, def_id, args)
|
||||
|
|
|
|||
|
|
@ -1093,13 +1093,6 @@ rustc_queries! {
|
|||
separate_provide_extern
|
||||
}
|
||||
|
||||
/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
|
||||
/// associated item.
|
||||
query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
|
||||
desc { |tcx| "creating the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
|
||||
cache_on_disk_if { true }
|
||||
}
|
||||
|
||||
/// Given an `impl_id`, return the trait it implements along with some header information.
|
||||
/// Return `None` if this is an inherent impl.
|
||||
query impl_trait_header(impl_id: DefId) -> Option<ty::ImplTraitHeader<'tcx>> {
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ resolve_undeclared_label =
|
|||
|
||||
resolve_underscore_lifetime_is_reserved = `'_` cannot be used here
|
||||
.label = `'_` is a reserved lifetime name
|
||||
.help = use another lifetime specifier
|
||||
|
||||
resolve_unexpected_res_change_ty_to_const_param_sugg =
|
||||
you might have meant to write a const parameter here
|
||||
|
|
|
|||
|
|
@ -934,6 +934,7 @@ pub(crate) struct ImplicitElidedLifetimeNotAllowedHere {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(resolve_underscore_lifetime_is_reserved, code = E0637)]
|
||||
#[help]
|
||||
pub(crate) struct UnderscoreLifetimeIsReserved {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv1".into();
|
||||
base.llvm_abiname = "elfv1".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
|
|||
base.stack_probes = StackProbeType::Inline;
|
||||
// FIXME(compiler-team#422): musl targets should be dynamically linked by default.
|
||||
base.crt_static_default = true;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv1".into();
|
||||
base.llvm_abiname = "elfv1".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
|
|||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||
base.max_atomic_width = Some(64);
|
||||
base.stack_probes = StackProbeType::Inline;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
|
|||
base.stack_probes = StackProbeType::Inline;
|
||||
// FIXME(compiler-team#422): musl targets should be dynamically linked by default.
|
||||
base.crt_static_default = true;
|
||||
base.abi = "elfv2".into();
|
||||
base.llvm_abiname = "elfv2".into();
|
||||
|
||||
Target {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
|
||||
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_hir::{self as hir, AmbigArg};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
|
|
@ -14,7 +13,6 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
associated_item_def_ids,
|
||||
associated_items,
|
||||
associated_types_for_impl_traits_in_associated_fn,
|
||||
associated_type_for_impl_trait_in_trait,
|
||||
impl_item_implementor_ids,
|
||||
..*providers
|
||||
};
|
||||
|
|
@ -160,20 +158,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
|
|||
container: ty::AssocItemContainer::Impl,
|
||||
}
|
||||
}
|
||||
struct RPITVisitor {
|
||||
rpits: FxIndexSet<LocalDefId>,
|
||||
struct RPITVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
synthetics: Vec<LocalDefId>,
|
||||
data: DefPathData,
|
||||
disambiguator: DisambiguatorState,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for RPITVisitor {
|
||||
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||
if let hir::TyKind::OpaqueDef(opaq) = ty.kind
|
||||
&& self.rpits.insert(opaq.def_id)
|
||||
{
|
||||
for bound in opaq.bounds {
|
||||
intravisit::walk_param_bound(self, bound);
|
||||
}
|
||||
}
|
||||
intravisit::walk_ty(self, ty)
|
||||
impl<'tcx> Visitor<'tcx> for RPITVisitor<'tcx> {
|
||||
fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) -> Self::Result {
|
||||
self.synthetics.push(associated_type_for_impl_trait_in_trait(
|
||||
self.tcx,
|
||||
opaque.def_id,
|
||||
self.data,
|
||||
&mut self.disambiguator,
|
||||
));
|
||||
intravisit::walk_opaque_ty(self, opaque)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,14 +194,18 @@ fn associated_types_for_impl_traits_in_associated_fn(
|
|||
|
||||
match tcx.def_kind(parent_def_id) {
|
||||
DefKind::Trait => {
|
||||
let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
|
||||
|
||||
if let Some(output) = tcx.hir_get_fn_output(fn_def_id) {
|
||||
let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
|
||||
let mut visitor = RPITVisitor {
|
||||
tcx,
|
||||
synthetics: vec![],
|
||||
data,
|
||||
disambiguator: DisambiguatorState::with(parent_def_id, data, 0),
|
||||
};
|
||||
visitor.visit_fn_ret_ty(output);
|
||||
|
||||
tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
|
||||
tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
|
||||
}))
|
||||
tcx.arena.alloc_from_iter(
|
||||
visitor.synthetics.into_iter().map(|def_id| def_id.to_def_id()),
|
||||
)
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
|
|
@ -211,7 +215,6 @@ fn associated_types_for_impl_traits_in_associated_fn(
|
|||
let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else {
|
||||
return &[];
|
||||
};
|
||||
|
||||
tcx.arena.alloc_from_iter(
|
||||
tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
|
||||
move |&trait_assoc_def_id| {
|
||||
|
|
@ -236,6 +239,8 @@ fn associated_types_for_impl_traits_in_associated_fn(
|
|||
fn associated_type_for_impl_trait_in_trait(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_ty_def_id: LocalDefId,
|
||||
data: DefPathData,
|
||||
disambiguator: &mut DisambiguatorState,
|
||||
) -> LocalDefId {
|
||||
let (hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
|
||||
| hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. }) =
|
||||
|
|
@ -246,22 +251,15 @@ fn associated_type_for_impl_trait_in_trait(
|
|||
let trait_def_id = tcx.local_parent(fn_def_id);
|
||||
assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait);
|
||||
|
||||
// Collect all opaque types in return position for the method and use
|
||||
// the index as the disambiguator to make an unique def path.
|
||||
let mut visitor = RPITVisitor { rpits: FxIndexSet::default() };
|
||||
visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap());
|
||||
let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap();
|
||||
|
||||
let span = tcx.def_span(opaque_ty_def_id);
|
||||
// Also use the method name to create an unique def path.
|
||||
let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id()));
|
||||
let trait_assoc_ty = tcx.at(span).create_def(
|
||||
trait_def_id,
|
||||
// No name because this is an anonymous associated type.
|
||||
None,
|
||||
DefKind::AssocTy,
|
||||
Some(data),
|
||||
&mut DisambiguatorState::with(trait_def_id, data, disambiguator),
|
||||
disambiguator,
|
||||
);
|
||||
|
||||
let local_def_id = trait_assoc_ty.def_id();
|
||||
|
|
|
|||
|
|
@ -3031,6 +3031,61 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||
(initialized, spare, &mut self.len)
|
||||
}
|
||||
}
|
||||
|
||||
/// Groups every `N` elements in the `Vec<T>` into chunks to produce a `Vec<[T; N]>`, dropping
|
||||
/// elements in the remainder. `N` must be greater than zero.
|
||||
///
|
||||
/// If the capacity is not a multiple of the chunk size, the buffer will shrink down to the
|
||||
/// nearest multiple with a reallocation or deallocation.
|
||||
///
|
||||
/// This function can be used to reverse [`Vec::into_flattened`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(vec_into_chunks)]
|
||||
///
|
||||
/// let vec = vec![0, 1, 2, 3, 4, 5, 6, 7];
|
||||
/// assert_eq!(vec.into_chunks::<3>(), [[0, 1, 2], [3, 4, 5]]);
|
||||
///
|
||||
/// let vec = vec![0, 1, 2, 3];
|
||||
/// let chunks: Vec<[u8; 10]> = vec.into_chunks();
|
||||
/// assert!(chunks.is_empty());
|
||||
///
|
||||
/// let flat = vec![0; 8 * 8 * 8];
|
||||
/// let reshaped: Vec<[[[u8; 8]; 8]; 8]> = flat.into_chunks().into_chunks().into_chunks();
|
||||
/// assert_eq!(reshaped.len(), 1);
|
||||
/// ```
|
||||
#[cfg(not(no_global_oom_handling))]
|
||||
#[unstable(feature = "vec_into_chunks", issue = "142137")]
|
||||
pub fn into_chunks<const N: usize>(mut self) -> Vec<[T; N], A> {
|
||||
const {
|
||||
assert!(N != 0, "chunk size must be greater than zero");
|
||||
}
|
||||
|
||||
let (len, cap) = (self.len(), self.capacity());
|
||||
|
||||
let len_remainder = len % N;
|
||||
if len_remainder != 0 {
|
||||
self.truncate(len - len_remainder);
|
||||
}
|
||||
|
||||
let cap_remainder = cap % N;
|
||||
if !T::IS_ZST && cap_remainder != 0 {
|
||||
self.buf.shrink_to_fit(cap - cap_remainder);
|
||||
}
|
||||
|
||||
let (ptr, _, _, alloc) = self.into_raw_parts_with_alloc();
|
||||
|
||||
// SAFETY:
|
||||
// - `ptr` and `alloc` were just returned from `self.into_raw_parts_with_alloc()`
|
||||
// - `[T; N]` has the same alignment as `T`
|
||||
// - `size_of::<[T; N]>() * cap / N == size_of::<T>() * cap`
|
||||
// - `len / N <= cap / N` because `len <= cap`
|
||||
// - the allocated memory consists of `len / N` valid values of type `[T; N]`
|
||||
// - `cap / N` fits the size of the allocated memory after shrinking
|
||||
unsafe { Vec::from_raw_parts_in(ptr.cast(), len / N, cap / N, alloc) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone, A: Allocator> Vec<T, A> {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,27 @@
|
|||
//! filesystem. All methods in this module represent cross-platform filesystem
|
||||
//! operations. Extra platform-specific functionality can be found in the
|
||||
//! extension traits of `std::os::$platform`.
|
||||
//!
|
||||
//! # Time of Check to Time of Use (TOCTOU)
|
||||
//!
|
||||
//! Many filesystem operations are subject to a race condition known as "Time of Check to Time of Use"
|
||||
//! (TOCTOU). This occurs when a program checks a condition (like file existence or permissions)
|
||||
//! and then uses the result of that check to make a decision, but the condition may have changed
|
||||
//! between the check and the use.
|
||||
//!
|
||||
//! For example, checking if a file exists and then creating it if it doesn't is vulnerable to
|
||||
//! TOCTOU - another process could create the file between your check and creation attempt.
|
||||
//!
|
||||
//! Another example is with symbolic links: when removing a directory, if another process replaces
|
||||
//! the directory with a symbolic link between the check and the removal operation, the removal
|
||||
//! might affect the wrong location. This is why operations like [`remove_dir_all`] need to use
|
||||
//! atomic operations to prevent such race conditions.
|
||||
//!
|
||||
//! To avoid TOCTOU issues:
|
||||
//! - Be aware that metadata operations (like [`metadata`] or [`symlink_metadata`]) may be affected by
|
||||
//! changes made by other processes.
|
||||
//! - Use atomic operations when possible (like [`File::create_new`] instead of checking existence then creating).
|
||||
//! - Keep file open for the duration of operations.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
|
@ -548,13 +569,14 @@ impl File {
|
|||
/// non-exhaustive list of likely errors.
|
||||
///
|
||||
/// This option is useful because it is atomic. Otherwise between checking whether a file
|
||||
/// exists and creating a new one, the file may have been created by another process (a TOCTOU
|
||||
/// exists and creating a new one, the file may have been created by another process (a [TOCTOU]
|
||||
/// race condition / attack).
|
||||
///
|
||||
/// This can also be written using
|
||||
/// `File::options().read(true).write(true).create_new(true).open(...)`.
|
||||
///
|
||||
/// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists
|
||||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1610,7 +1632,7 @@ impl OpenOptions {
|
|||
///
|
||||
/// This option is useful because it is atomic. Otherwise between checking
|
||||
/// whether a file exists and creating a new one, the file may have been
|
||||
/// created by another process (a TOCTOU race condition / attack).
|
||||
/// created by another process (a [TOCTOU] race condition / attack).
|
||||
///
|
||||
/// If `.create_new(true)` is set, [`.create()`] and [`.truncate()`] are
|
||||
/// ignored.
|
||||
|
|
@ -1621,6 +1643,7 @@ impl OpenOptions {
|
|||
/// [`.create()`]: OpenOptions::create
|
||||
/// [`.truncate()`]: OpenOptions::truncate
|
||||
/// [`AlreadyExists`]: io::ErrorKind::AlreadyExists
|
||||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -2954,17 +2977,17 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
|
|||
/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile`.
|
||||
///
|
||||
/// ## Time-of-check to time-of-use (TOCTOU) race conditions
|
||||
/// On a few platforms there is no way to remove a directory's contents without following symlinks
|
||||
/// unless you perform a check and then operate on paths based on that directory.
|
||||
/// This allows concurrently-running code to replace the directory with a symlink after the check,
|
||||
/// causing a removal to instead operate on a path based on the symlink. This is a TOCTOU race.
|
||||
/// By default, `fs::remove_dir_all` protects against a symlink TOCTOU race on all platforms
|
||||
/// except the following. It should not be used in security-sensitive contexts on these platforms:
|
||||
/// - Miri: Even when emulating targets where the underlying implementation will protect against
|
||||
/// TOCTOU races, Miri will not do so.
|
||||
/// - Redox OS: This function does not protect against TOCTOU races, as Redox does not implement
|
||||
/// the required platform support to do so.
|
||||
/// See the [module-level TOCTOU explanation](self#time-of-check-to-time-of-use-toctou).
|
||||
///
|
||||
/// On most platforms, `fs::remove_dir_all` protects against symlink TOCTOU races by default.
|
||||
/// However, on the following platforms, this protection is not provided and the function should
|
||||
/// not be used in security-sensitive contexts:
|
||||
/// - **Miri**: Even when emulating targets where the underlying implementation will protect against
|
||||
/// TOCTOU races, Miri will not do so.
|
||||
/// - **Redox OS**: This function does not protect against TOCTOU races, as Redox does not implement
|
||||
/// the required platform support to do so.
|
||||
///
|
||||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
|
||||
/// [changes]: io#platform-specific-behavior
|
||||
///
|
||||
/// # Errors
|
||||
|
|
@ -3238,7 +3261,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
|
|||
/// permission is denied on one of the parent directories.
|
||||
///
|
||||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
|
||||
/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
|
||||
/// where those bugs are not an issue.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -3251,6 +3274,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
|
|||
/// ```
|
||||
///
|
||||
/// [`Path::exists`]: crate::path::Path::exists
|
||||
/// [TOCTOU]: self#time-of-check-to-time-of-use-toctou
|
||||
#[stable(feature = "fs_try_exists", since = "1.81.0")]
|
||||
#[inline]
|
||||
pub fn exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
|
||||
|
|
|
|||
|
|
@ -3127,7 +3127,7 @@ impl Path {
|
|||
/// Returns `true` if the path points at an existing entity.
|
||||
///
|
||||
/// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
|
||||
/// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs.
|
||||
/// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
|
|
@ -3148,6 +3148,7 @@ impl Path {
|
|||
/// check errors, call [`Path::try_exists`].
|
||||
///
|
||||
/// [`try_exists()`]: Self::try_exists
|
||||
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
|
|
@ -3167,7 +3168,7 @@ impl Path {
|
|||
/// permission is denied on one of the parent directories.
|
||||
///
|
||||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
|
||||
/// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
|
||||
/// where those bugs are not an issue.
|
||||
///
|
||||
/// This is an alias for [`std::fs::exists`](crate::fs::exists).
|
||||
|
|
@ -3180,6 +3181,7 @@ impl Path {
|
|||
/// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
|
||||
/// ```
|
||||
///
|
||||
/// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
|
||||
/// [`exists()`]: Self::exists
|
||||
#[stable(feature = "path_try_exists", since = "1.63.0")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ pub struct JobDatabase {
|
|||
pub try_jobs: Vec<Job>,
|
||||
#[serde(rename = "auto")]
|
||||
pub auto_jobs: Vec<Job>,
|
||||
#[serde(rename = "optional")]
|
||||
pub optional_jobs: Vec<Job>,
|
||||
|
||||
/// Shared environments for the individual run types.
|
||||
envs: JobEnvironments,
|
||||
|
|
@ -75,9 +77,10 @@ impl JobDatabase {
|
|||
/// Find `auto` jobs that correspond to the passed `pattern`.
|
||||
/// Patterns are matched using the glob syntax.
|
||||
/// For example `dist-*` matches all jobs starting with `dist-`.
|
||||
fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
|
||||
fn find_auto_or_optional_jobs_by_pattern(&self, pattern: &str) -> Vec<Job> {
|
||||
self.auto_jobs
|
||||
.iter()
|
||||
.chain(self.optional_jobs.iter())
|
||||
.filter(|j| glob_match::glob_match(pattern, &j.name))
|
||||
.cloned()
|
||||
.collect()
|
||||
|
|
@ -181,7 +184,7 @@ fn calculate_jobs(
|
|||
let mut jobs: Vec<Job> = vec![];
|
||||
let mut unknown_patterns = vec![];
|
||||
for pattern in patterns {
|
||||
let matched_jobs = db.find_auto_jobs_by_pattern(pattern);
|
||||
let matched_jobs = db.find_auto_or_optional_jobs_by_pattern(pattern);
|
||||
if matched_jobs.is_empty() {
|
||||
unknown_patterns.push(pattern.clone());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,13 @@ auto:
|
|||
- name: test-msvc-i686-2
|
||||
os: ubuntu
|
||||
env: {}
|
||||
optional:
|
||||
- name: optional-job-1
|
||||
os: ubuntu
|
||||
env: {}
|
||||
- name: optional-dist-x86_64
|
||||
os: ubuntu
|
||||
env: {}
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -57,12 +64,18 @@ auto:
|
|||
"*i686*",
|
||||
&["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"],
|
||||
);
|
||||
// Test that optional jobs are found
|
||||
check_pattern(&db, "optional-*", &["optional-job-1", "optional-dist-x86_64"]);
|
||||
check_pattern(&db, "*optional*", &["optional-job-1", "optional-dist-x86_64"]);
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) {
|
||||
let jobs =
|
||||
db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::<Vec<_>>();
|
||||
let jobs = db
|
||||
.find_auto_or_optional_jobs_by_pattern(pattern)
|
||||
.into_iter()
|
||||
.map(|j| j.name)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(jobs, expected);
|
||||
}
|
||||
|
|
@ -116,8 +129,13 @@ fn validate_jobs() {
|
|||
load_job_db(&db_str).expect("Failed to load job database")
|
||||
};
|
||||
|
||||
let all_jobs =
|
||||
db.pr_jobs.iter().chain(db.try_jobs.iter()).chain(db.auto_jobs.iter()).collect::<Vec<_>>();
|
||||
let all_jobs = db
|
||||
.pr_jobs
|
||||
.iter()
|
||||
.chain(db.try_jobs.iter())
|
||||
.chain(db.auto_jobs.iter())
|
||||
.chain(db.optional_jobs.iter())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let errors: Vec<anyhow::Error> =
|
||||
all_jobs.into_iter().filter_map(|job| validate_codebuild_image(job).err()).collect();
|
||||
|
|
|
|||
|
|
@ -139,3 +139,8 @@ auto:
|
|||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
CODEGEN_BACKENDS: llvm,cranelift
|
||||
<<: *job-windows
|
||||
|
||||
# Jobs that only run when explicitly invoked via `@bors try`.
|
||||
optional:
|
||||
- name: test-optional-job
|
||||
<<: *job-linux-4c
|
||||
|
|
|
|||
|
|
@ -26,6 +26,5 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--enable-sanitizers \
|
||||
--enable-profiler \
|
||||
--enable-compiler-docs
|
||||
# FIXME: Skipping cargo panic_abort_doc_tests due to https://github.com/rust-lang/rust/issues/123733
|
||||
ENV SCRIPT python3 ../x.py --stage 2 test && \
|
||||
python3 ../x.py --stage 2 test src/tools/cargo --test-args \"--skip panic_abort_doc_tests\"
|
||||
python3 ../x.py --stage 2 test src/tools/cargo
|
||||
|
|
|
|||
|
|
@ -160,6 +160,17 @@ pr:
|
|||
try:
|
||||
- <<: *job-dist-x86_64-linux
|
||||
|
||||
# Jobs that only run when explicitly invoked in one of the following ways:
|
||||
# - comment `@bors2 try jobs=<job-name>`
|
||||
# - `try-job: <job-name>` in the PR description and comment `@bors try` or `@bors2 try`.
|
||||
optional:
|
||||
# This job is used just to test optional jobs.
|
||||
# It will be replaced by tier 2 and tier 3 jobs in the future.
|
||||
- name: optional-mingw-check-1
|
||||
env:
|
||||
IMAGE: mingw-check-1
|
||||
<<: *job-linux-4c
|
||||
|
||||
# Main CI jobs that have to be green to merge a commit into master
|
||||
# These jobs automatically inherit envs.auto, to avoid repeating
|
||||
# it in each job definition.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/// This was originally generated by collecting directives from ui tests and then extracting their
|
||||
/// directive names. This is **not** an exhaustive list of all possible directives. Instead, this is
|
||||
/// a best-effort approximation for diagnostics. Add new headers to this list when needed.
|
||||
/// a best-effort approximation for diagnostics. Add new directives to this list when needed.
|
||||
const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
|
||||
// tidy-alphabetical-start
|
||||
"add-core-stubs",
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ use tracing::*;
|
|||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
use crate::debuggers::{extract_cdb_version, extract_gdb_version};
|
||||
use crate::directives::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::directives::needs::CachedNeedsConditions;
|
||||
use crate::errors::ErrorKind;
|
||||
use crate::executor::{CollectedTestDesc, ShouldPanic};
|
||||
use crate::header::auxiliary::{AuxProps, parse_and_update_aux};
|
||||
use crate::header::needs::CachedNeedsConditions;
|
||||
use crate::help;
|
||||
use crate::util::static_regex;
|
||||
|
||||
|
|
@ -24,11 +24,11 @@ mod needs;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub struct HeadersCache {
|
||||
pub struct DirectivesCache {
|
||||
needs: CachedNeedsConditions,
|
||||
}
|
||||
|
||||
impl HeadersCache {
|
||||
impl DirectivesCache {
|
||||
pub fn load(config: &Config) -> Self {
|
||||
Self { needs: CachedNeedsConditions::load(config) }
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ impl EarlyProps {
|
|||
pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
|
||||
let mut props = EarlyProps::default();
|
||||
let mut poisoned = false;
|
||||
iter_header(
|
||||
iter_directives(
|
||||
config.mode,
|
||||
&config.suite,
|
||||
&mut poisoned,
|
||||
|
|
@ -138,12 +138,12 @@ pub struct TestProps {
|
|||
pub incremental_dir: Option<Utf8PathBuf>,
|
||||
// If `true`, this test will use incremental compilation.
|
||||
//
|
||||
// This can be set manually with the `incremental` header, or implicitly
|
||||
// This can be set manually with the `incremental` directive, or implicitly
|
||||
// by being a part of an incremental mode test. Using the `incremental`
|
||||
// header should be avoided if possible; using an incremental mode test is
|
||||
// directive should be avoided if possible; using an incremental mode test is
|
||||
// preferred. Incremental mode tests support multiple passes, which can
|
||||
// verify that the incremental cache can be loaded properly after being
|
||||
// created. Just setting the header will only verify the behavior with
|
||||
// created. Just setting the directive will only verify the behavior with
|
||||
// creating an incremental cache, but doesn't check that it is created
|
||||
// correctly.
|
||||
//
|
||||
|
|
@ -347,7 +347,7 @@ impl TestProps {
|
|||
|
||||
let mut poisoned = false;
|
||||
|
||||
iter_header(
|
||||
iter_directives(
|
||||
config.mode,
|
||||
&config.suite,
|
||||
&mut poisoned,
|
||||
|
|
@ -642,11 +642,11 @@ impl TestProps {
|
|||
let check_ui = |mode: &str| {
|
||||
// Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
|
||||
if config.mode != Mode::Ui && config.mode != Mode::Crashes {
|
||||
panic!("`{}-fail` header is only supported in UI tests", mode);
|
||||
panic!("`{}-fail` directive is only supported in UI tests", mode);
|
||||
}
|
||||
};
|
||||
if config.mode == Mode::Ui && config.parse_name_directive(ln, "compile-fail") {
|
||||
panic!("`compile-fail` header is useless in UI tests");
|
||||
panic!("`compile-fail` directive is useless in UI tests");
|
||||
}
|
||||
let fail_mode = if config.parse_name_directive(ln, "check-fail") {
|
||||
check_ui("check");
|
||||
|
|
@ -662,7 +662,7 @@ impl TestProps {
|
|||
};
|
||||
match (self.fail_mode, fail_mode) {
|
||||
(None, Some(_)) => self.fail_mode = fail_mode,
|
||||
(Some(_), Some(_)) => panic!("multiple `*-fail` headers in a single test"),
|
||||
(Some(_), Some(_)) => panic!("multiple `*-fail` directives in a single test"),
|
||||
(_, None) => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -674,10 +674,10 @@ impl TestProps {
|
|||
(Mode::Codegen, "build-pass") => (),
|
||||
(Mode::Incremental, _) => {
|
||||
if revision.is_some() && !self.revisions.iter().all(|r| r.starts_with("cfail")) {
|
||||
panic!("`{s}` header is only supported in `cfail` incremental tests")
|
||||
panic!("`{s}` directive is only supported in `cfail` incremental tests")
|
||||
}
|
||||
}
|
||||
(mode, _) => panic!("`{s}` header is not supported in `{mode}` tests"),
|
||||
(mode, _) => panic!("`{s}` directive is not supported in `{mode}` tests"),
|
||||
};
|
||||
let pass_mode = if config.parse_name_directive(ln, "check-pass") {
|
||||
check_no_run("check-pass");
|
||||
|
|
@ -693,7 +693,7 @@ impl TestProps {
|
|||
};
|
||||
match (self.pass_mode, pass_mode) {
|
||||
(None, Some(_)) => self.pass_mode = pass_mode,
|
||||
(Some(_), Some(_)) => panic!("multiple `*-pass` headers in a single test"),
|
||||
(Some(_), Some(_)) => panic!("multiple `*-pass` directives in a single test"),
|
||||
(_, None) => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -794,7 +794,7 @@ const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
|
|||
&["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
|
||||
|
||||
/// The (partly) broken-down contents of a line containing a test directive,
|
||||
/// which [`iter_header`] passes to its callback function.
|
||||
/// which [`iter_directives`] passes to its callback function.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
|
|
@ -867,7 +867,7 @@ pub(crate) fn check_directive<'a>(
|
|||
|
||||
const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@";
|
||||
|
||||
fn iter_header(
|
||||
fn iter_directives(
|
||||
mode: Mode,
|
||||
_suite: &str,
|
||||
poisoned: &mut bool,
|
||||
|
|
@ -1163,8 +1163,7 @@ enum NormalizeKind {
|
|||
Stderr64bit,
|
||||
}
|
||||
|
||||
/// Parses the regex and replacement values of a `//@ normalize-*` header,
|
||||
/// in the format:
|
||||
/// Parses the regex and replacement values of a `//@ normalize-*` directive, in the format:
|
||||
/// ```text
|
||||
/// "REGEX" -> "REPLACEMENT"
|
||||
/// ```
|
||||
|
|
@ -1373,7 +1372,7 @@ where
|
|||
|
||||
pub(crate) fn make_test_description<R: Read>(
|
||||
config: &Config,
|
||||
cache: &HeadersCache,
|
||||
cache: &DirectivesCache,
|
||||
name: String,
|
||||
path: &Utf8Path,
|
||||
src: R,
|
||||
|
|
@ -1387,7 +1386,7 @@ pub(crate) fn make_test_description<R: Read>(
|
|||
let mut local_poisoned = false;
|
||||
|
||||
// Scan through the test file to handle `ignore-*`, `only-*`, and `needs-*` directives.
|
||||
iter_header(
|
||||
iter_directives(
|
||||
config.mode,
|
||||
&config.suite,
|
||||
&mut local_poisoned,
|
||||
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
use std::iter;
|
||||
|
||||
use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
|
||||
use crate::common::Config;
|
||||
use crate::header::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
|
||||
|
||||
/// Properties parsed from `aux-*` test directives.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use crate::common::{CompareMode, Config, Debugger};
|
||||
use crate::header::IgnoreDecision;
|
||||
use crate::directives::IgnoreDecision;
|
||||
|
||||
const EXTRA_ARCHS: &[&str] = &["spirv"];
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
|
||||
use crate::header::{IgnoreDecision, llvm_has_libzstd};
|
||||
use crate::directives::{IgnoreDecision, llvm_has_libzstd};
|
||||
|
||||
pub(super) fn handle_needs(
|
||||
cache: &CachedNeedsConditions,
|
||||
|
|
@ -4,7 +4,7 @@ use camino::Utf8Path;
|
|||
use semver::Version;
|
||||
|
||||
use super::{
|
||||
EarlyProps, HeadersCache, extract_llvm_version, extract_version_range, iter_header,
|
||||
DirectivesCache, EarlyProps, extract_llvm_version, extract_version_range, iter_directives,
|
||||
parse_normalize_rule,
|
||||
};
|
||||
use crate::common::{Config, Debugger, Mode};
|
||||
|
|
@ -17,9 +17,9 @@ fn make_test_description<R: Read>(
|
|||
src: R,
|
||||
revision: Option<&str>,
|
||||
) -> CollectedTestDesc {
|
||||
let cache = HeadersCache::load(config);
|
||||
let cache = DirectivesCache::load(config);
|
||||
let mut poisoned = false;
|
||||
let test = crate::header::make_test_description(
|
||||
let test = crate::directives::make_test_description(
|
||||
config,
|
||||
&cache,
|
||||
name,
|
||||
|
|
@ -785,7 +785,7 @@ fn threads_support() {
|
|||
|
||||
fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
|
||||
let rdr = std::io::Cursor::new(&buf);
|
||||
iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
|
||||
iter_directives(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -12,9 +12,9 @@ pub mod common;
|
|||
pub mod compute_diff;
|
||||
mod debuggers;
|
||||
pub mod diagnostics;
|
||||
pub mod directives;
|
||||
pub mod errors;
|
||||
mod executor;
|
||||
pub mod header;
|
||||
mod json;
|
||||
mod raise_fd_limit;
|
||||
mod read2;
|
||||
|
|
@ -37,13 +37,13 @@ use rayon::iter::{ParallelBridge, ParallelIterator};
|
|||
use tracing::debug;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use self::header::{EarlyProps, make_test_description};
|
||||
use self::directives::{EarlyProps, make_test_description};
|
||||
use crate::common::{
|
||||
CompareMode, Config, Debugger, Mode, PassMode, TestPaths, UI_EXTENSIONS, expected_output_path,
|
||||
output_base_dir, output_relative_path,
|
||||
};
|
||||
use crate::directives::DirectivesCache;
|
||||
use crate::executor::{CollectedTest, ColorConfig, OutputFormat};
|
||||
use crate::header::HeadersCache;
|
||||
use crate::util::logv;
|
||||
|
||||
/// Creates the `Config` instance for this invocation of compiletest.
|
||||
|
|
@ -254,8 +254,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||
Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
|
||||
};
|
||||
let llvm_version =
|
||||
matches.opt_str("llvm-version").as_deref().map(header::extract_llvm_version).or_else(
|
||||
|| header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
|
||||
matches.opt_str("llvm-version").as_deref().map(directives::extract_llvm_version).or_else(
|
||||
|| directives::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?),
|
||||
);
|
||||
|
||||
let run_ignored = matches.opt_present("ignored");
|
||||
|
|
@ -618,7 +618,7 @@ pub fn run_tests(config: Arc<Config>) {
|
|||
/// Read-only context data used during test collection.
|
||||
struct TestCollectorCx {
|
||||
config: Arc<Config>,
|
||||
cache: HeadersCache,
|
||||
cache: DirectivesCache,
|
||||
common_inputs_stamp: Stamp,
|
||||
modified_tests: Vec<Utf8PathBuf>,
|
||||
}
|
||||
|
|
@ -654,7 +654,7 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
|
|||
modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
|
||||
fatal!("modified_tests: {}: {err}", config.src_test_suite_root);
|
||||
});
|
||||
let cache = HeadersCache::load(&config);
|
||||
let cache = DirectivesCache::load(&config);
|
||||
|
||||
let cx = TestCollectorCx { config, cache, common_inputs_stamp, modified_tests };
|
||||
let collector = collect_tests_from_dir(&cx, &cx.config.src_test_suite_root, Utf8Path::new(""))
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ use crate::common::{
|
|||
output_base_dir, output_base_name, output_testname_unique,
|
||||
};
|
||||
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
|
||||
use crate::directives::TestProps;
|
||||
use crate::errors::{Error, ErrorKind, load_errors};
|
||||
use crate::header::TestProps;
|
||||
use crate::read2::{Truncated, read2_abbreviated};
|
||||
use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
|
||||
use crate::{ColorConfig, help, json, stamp_file_path, warning};
|
||||
|
|
@ -2039,7 +2039,7 @@ impl<'test> TestCx<'test> {
|
|||
// Provide more context on failures.
|
||||
filecheck.args(&["--dump-input-context", "100"]);
|
||||
|
||||
// Add custom flags supplied by the `filecheck-flags:` test header.
|
||||
// Add custom flags supplied by the `filecheck-flags:` test directive.
|
||||
filecheck.args(&self.props.filecheck_flags);
|
||||
|
||||
// FIXME(jieyouxu): don't pass an empty Path
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl TestCx<'_> {
|
|||
std::fs::remove_file(pdb_file).unwrap();
|
||||
}
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
// compile test file (it should have 'compile-flags:-g' in the directive)
|
||||
let should_run = self.run_if_enabled();
|
||||
let compile_result = self.compile_test(should_run, Emit::None);
|
||||
if !compile_result.status.success() {
|
||||
|
|
@ -135,7 +135,7 @@ impl TestCx<'_> {
|
|||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let mut cmds = dbg_cmds.commands.join("\n");
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
// compile test file (it should have 'compile-flags:-g' in the directive)
|
||||
let should_run = self.run_if_enabled();
|
||||
let compiler_run_result = self.compile_test(should_run, Emit::None);
|
||||
if !compiler_run_result.status.success() {
|
||||
|
|
@ -359,7 +359,7 @@ impl TestCx<'_> {
|
|||
}
|
||||
|
||||
fn run_debuginfo_lldb_test_no_opt(&self) {
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
// compile test file (it should have 'compile-flags:-g' in the directive)
|
||||
let should_run = self.run_if_enabled();
|
||||
let compile_result = self.compile_test(should_run, Emit::None);
|
||||
if !compile_result.status.success() {
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ impl TestCx<'_> {
|
|||
// don't test rustfix with nll right now
|
||||
} else if self.config.rustfix_coverage {
|
||||
// Find out which tests have `MachineApplicable` suggestions but are missing
|
||||
// `run-rustfix` or `run-rustfix-only-machine-applicable` headers.
|
||||
// `run-rustfix` or `run-rustfix-only-machine-applicable` directives.
|
||||
//
|
||||
// This will return an empty `Vec` in case the executed test file has a
|
||||
// `compile-flags: --error-format=xxxx` header with a value other than `json`.
|
||||
// `compile-flags: --error-format=xxxx` directive with a value other than `json`.
|
||||
let suggestions = get_suggestions_from_json(
|
||||
&rustfix_input,
|
||||
&HashSet::new(),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||
use std::{env, fs};
|
||||
|
||||
use build_helper::util::try_run;
|
||||
use compiletest::header::TestProps;
|
||||
use compiletest::directives::TestProps;
|
||||
use config::Config;
|
||||
|
||||
mod config;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
//@ add-core-stubs
|
||||
//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
|
||||
#![no_core]
|
||||
extern crate minicore;
|
||||
|
||||
use minicore::*;
|
||||
|
||||
// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
|
||||
// without needing to pointercast, and SRoA will turn that into a `bitcast`.
|
||||
|
|
@ -14,7 +20,7 @@
|
|||
// CHECK-NEXT: ret i32 %_0
|
||||
#[no_mangle]
|
||||
pub fn f32_to_bits(x: f32) -> u32 {
|
||||
unsafe { std::mem::transmute(x) }
|
||||
unsafe { mem::transmute(x) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
|
||||
|
|
@ -22,7 +28,7 @@ pub fn f32_to_bits(x: f32) -> u32 {
|
|||
// CHECK-NEXT: ret i8 %_0
|
||||
#[no_mangle]
|
||||
pub fn bool_to_byte(b: bool) -> u8 {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
|
||||
|
|
@ -30,14 +36,14 @@ pub fn bool_to_byte(b: bool) -> u8 {
|
|||
// CHECK-NEXT: ret i1 %_0
|
||||
#[no_mangle]
|
||||
pub unsafe fn byte_to_bool(byte: u8) -> bool {
|
||||
std::mem::transmute(byte)
|
||||
mem::transmute(byte)
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p)
|
||||
// CHECK: ret ptr %p
|
||||
#[no_mangle]
|
||||
pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
|
||||
unsafe { std::mem::transmute(p) }
|
||||
unsafe { mem::transmute(p) }
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
|
||||
|
|
@ -45,7 +51,7 @@ pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
|
|||
// CHECK-NEXT: ret [[USIZE]] %_0
|
||||
#[no_mangle]
|
||||
pub fn ptr_to_int(p: *mut u16) -> usize {
|
||||
unsafe { std::mem::transmute(p) }
|
||||
unsafe { mem::transmute(p) }
|
||||
}
|
||||
|
||||
// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
|
||||
|
|
@ -53,7 +59,7 @@ pub fn ptr_to_int(p: *mut u16) -> usize {
|
|||
// CHECK-NEXT: ret ptr %_0
|
||||
#[no_mangle]
|
||||
pub fn int_to_ptr(i: usize) -> *mut u16 {
|
||||
unsafe { std::mem::transmute(i) }
|
||||
unsafe { mem::transmute(i) }
|
||||
}
|
||||
|
||||
// This is the one case where signedness matters to transmuting:
|
||||
|
|
@ -70,7 +76,7 @@ pub enum FakeBoolSigned {
|
|||
// CHECK-NEXT: ret i8 %_0
|
||||
#[no_mangle]
|
||||
pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
|
||||
|
|
@ -78,7 +84,7 @@ pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
|
|||
// CHECK-NEXT: ret i1 %_0
|
||||
#[no_mangle]
|
||||
pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
|
|
@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned {
|
|||
// CHECK: ret i1 %b
|
||||
#[no_mangle]
|
||||
pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
|
||||
// CHECK: ret i1 %b
|
||||
#[no_mangle]
|
||||
pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
|
||||
unsafe { std::mem::transmute(b) }
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
struct S([i64; 1]);
|
||||
|
||||
// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b)
|
||||
// CHECK: bitcast <1 x i64> %b to i64
|
||||
// CHECK: ret i64
|
||||
#[no_mangle]
|
||||
#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
|
||||
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
|
||||
#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
|
||||
#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
|
||||
#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
|
||||
pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
||||
// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b)
|
||||
// CHECK: bitcast i64 %b to <1 x i64>
|
||||
// CHECK: ret <1 x i64>
|
||||
#[no_mangle]
|
||||
#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
|
||||
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
|
||||
#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
|
||||
#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
|
||||
#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
|
||||
pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
|
||||
unsafe { mem::transmute(b) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
|
|||
LL | target_abi = "_UNEXPECTED_VALUE",
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
|
||||
= note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elfv1`, `elfv2`, `fortanix`, `ilp32`, `ilp32e`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
|
||||
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
|
||||
|
||||
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ error[E0637]: `'_` cannot be used here
|
|||
|
|
||||
LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/E0637.rs:1:62
|
||||
|
|
|
|||
|
|
@ -3,36 +3,48 @@ error[E0637]: `'_` cannot be used here
|
|||
|
|
||||
LL | impl<'_> IceCube<'_> {}
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/in-binder.rs:12:15
|
||||
|
|
||||
LL | struct Struct<'_> {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/in-binder.rs:17:11
|
||||
|
|
||||
LL | enum Enum<'_> {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/in-binder.rs:22:13
|
||||
|
|
||||
LL | union Union<'_> {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/in-binder.rs:27:13
|
||||
|
|
||||
LL | trait Trait<'_> {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/in-binder.rs:31:8
|
||||
|
|
||||
LL | fn foo<'_>() {
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,16 @@ error[E0637]: `'_` cannot be used here
|
|||
|
|
||||
LL | fn foo<'_>
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/underscore-lifetime-binders.rs:10:25
|
||||
|
|
||||
LL | fn meh() -> Box<dyn for<'_> Meh<'_>>
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
|
||||
= help: use another lifetime specifier
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/underscore-lifetime-binders.rs:10:33
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue