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:
bors 2025-07-02 20:25:23 +00:00
commit 6677875279
42 changed files with 306 additions and 132 deletions

View file

@ -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(..)) => {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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