Auto merge of #144562 - matthiaskrgr:rollup-mlvn7qo, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - rust-lang/rust#144072 (update `Atomic*::from_ptr` and `Atomic*::as_ptr` docs) - rust-lang/rust#144151 (`tests/ui/issues/`: The Issues Strike Back [1/N]) - rust-lang/rust#144300 (Clippy fixes for miropt-test-tools) - rust-lang/rust#144399 (Add a ratchet for moving all standard library tests to separate packages) - rust-lang/rust#144472 (str: Mark unstable `round_char_boundary` feature functions as const) - rust-lang/rust#144503 (Various refactors to the codegen coordinator code (part 3)) - rust-lang/rust#144530 (coverage: Infer `instances_used` from `pgo_func_name_var_map`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
65b6cdb6a6
68 changed files with 350 additions and 324 deletions
|
|
@ -4,7 +4,6 @@ use gccjit::{Context, OutputKind};
|
|||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
|
||||
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_session::config::OutputType;
|
||||
use rustc_span::fatal_error::FatalError;
|
||||
|
|
@ -258,14 +257,6 @@ pub(crate) fn codegen(
|
|||
))
|
||||
}
|
||||
|
||||
pub(crate) fn link(
|
||||
_cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
_dcx: DiagCtxtHandle<'_>,
|
||||
mut _modules: Vec<ModuleCodegen<GccContext>>,
|
||||
) -> Result<ModuleCodegen<GccContext>, FatalError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub(crate) fn save_temp_bitcode(
|
||||
cgcx: &CodegenContext<GccCodegenBackend>,
|
||||
_module: &ModuleCodegen<GccContext>,
|
||||
|
|
|
|||
|
|
@ -426,14 +426,6 @@ impl WriteBackendMethods for GccCodegenBackend {
|
|||
fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn run_link(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
modules: Vec<ModuleCodegen<Self::Module>>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::write::link(cgcx, dcx, modules)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_
|
|||
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
|
||||
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
|
||||
|
||||
codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
|
||||
codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$err})
|
||||
|
||||
codegen_llvm_mismatch_data_layout =
|
||||
data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}`
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use std::sync::Arc;
|
|||
use std::{io, iter, slice};
|
||||
|
||||
use object::read::archive::ArchiveFile;
|
||||
use object::{Object, ObjectSection};
|
||||
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
|
||||
use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
|
|
@ -105,31 +106,15 @@ fn get_bitcode_slice_from_object_data<'a>(
|
|||
// name" which in the public API for sections gets treated as part of the section name, but
|
||||
// internally in MachOObjectFile.cpp gets treated separately.
|
||||
let section_name = bitcode_section_name(cgcx).to_str().unwrap().trim_start_matches("__LLVM,");
|
||||
let mut len = 0;
|
||||
let data = unsafe {
|
||||
llvm::LLVMRustGetSliceFromObjectDataByName(
|
||||
obj.as_ptr(),
|
||||
obj.len(),
|
||||
section_name.as_ptr(),
|
||||
section_name.len(),
|
||||
&mut len,
|
||||
)
|
||||
};
|
||||
if !data.is_null() {
|
||||
assert!(len != 0);
|
||||
let bc = unsafe { slice::from_raw_parts(data, len) };
|
||||
|
||||
// `bc` must be a sub-slice of `obj`.
|
||||
assert!(obj.as_ptr() <= bc.as_ptr());
|
||||
assert!(bc[bc.len()..bc.len()].as_ptr() <= obj[obj.len()..obj.len()].as_ptr());
|
||||
let obj =
|
||||
object::File::parse(obj).map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })?;
|
||||
|
||||
Ok(bc)
|
||||
} else {
|
||||
assert!(len == 0);
|
||||
Err(LtoBitcodeFromRlib {
|
||||
llvm_err: llvm::last_error().unwrap_or_else(|| "unknown LLVM error".to_string()),
|
||||
})
|
||||
}
|
||||
let section = obj
|
||||
.section_by_name(section_name)
|
||||
.ok_or_else(|| LtoBitcodeFromRlib { err: format!("Can't find section {section_name}") })?;
|
||||
|
||||
section.data().map_err(|err| LtoBitcodeFromRlib { err: err.to_string() })
|
||||
}
|
||||
|
||||
/// Performs fat LTO by merging all modules into a single one and returning it
|
||||
|
|
|
|||
|
|
@ -796,29 +796,6 @@ pub(crate) fn optimize(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn link(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
|
||||
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
|
||||
use super::lto::{Linker, ModuleBuffer};
|
||||
// Sort the modules by name to ensure deterministic behavior.
|
||||
modules.sort_by(|a, b| a.name.cmp(&b.name));
|
||||
let (first, elements) =
|
||||
modules.split_first().expect("Bug! modules must contain at least one module.");
|
||||
|
||||
let mut linker = Linker::new(first.module_llvm.llmod());
|
||||
for module in elements {
|
||||
let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", &*module.name);
|
||||
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
|
||||
linker
|
||||
.add(buffer.data())
|
||||
.map_err(|()| llvm_err(dcx, LlvmError::SerializeModule { name: &module.name }))?;
|
||||
}
|
||||
drop(linker);
|
||||
Ok(modules.remove(0))
|
||||
}
|
||||
|
||||
pub(crate) fn codegen(
|
||||
cgcx: &CodegenContext<LlvmCodegenBackend>,
|
||||
module: ModuleCodegen<ModuleLlvm>,
|
||||
|
|
|
|||
|
|
@ -46,21 +46,17 @@ pub(crate) fn finalize(cx: &mut CodegenCx<'_, '_>) {
|
|||
debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
|
||||
|
||||
// FIXME(#132395): Can this be none even when coverage is enabled?
|
||||
let instances_used = match cx.coverage_cx {
|
||||
Some(ref cx) => cx.instances_used.borrow(),
|
||||
None => return,
|
||||
};
|
||||
let Some(ref coverage_cx) = cx.coverage_cx else { return };
|
||||
|
||||
let mut covfun_records = instances_used
|
||||
.iter()
|
||||
.copied()
|
||||
let mut covfun_records = coverage_cx
|
||||
.instances_used()
|
||||
.into_iter()
|
||||
// Sort by symbol name, so that the global file table is built in an
|
||||
// order that doesn't depend on the stable-hash-based order in which
|
||||
// instances were visited during codegen.
|
||||
.sorted_by_cached_key(|&instance| tcx.symbol_name(instance).name)
|
||||
.filter_map(|instance| prepare_covfun_record(tcx, instance, true))
|
||||
.collect::<Vec<_>>();
|
||||
drop(instances_used);
|
||||
|
||||
// In a single designated CGU, also prepare covfun records for functions
|
||||
// in this crate that were instrumented for coverage, but are unused.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use rustc_abi::Size;
|
|||
use rustc_codegen_ssa::traits::{
|
||||
BuilderMethods, ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
|
||||
};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::ty::Instance;
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -20,9 +20,14 @@ mod mapgen;
|
|||
|
||||
/// Extra per-CGU context/state needed for coverage instrumentation.
|
||||
pub(crate) struct CguCoverageContext<'ll, 'tcx> {
|
||||
/// Coverage data for each instrumented function identified by DefId.
|
||||
pub(crate) instances_used: RefCell<FxIndexSet<Instance<'tcx>>>,
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
/// Associates function instances with an LLVM global that holds the
|
||||
/// function's symbol name, as needed by LLVM coverage intrinsics.
|
||||
///
|
||||
/// Instances in this map are also considered "used" for the purposes of
|
||||
/// emitting covfun records. Every covfun record holds a hash of its
|
||||
/// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
|
||||
/// hash back to an entry in the binary's `__llvm_prf_names` linker section.
|
||||
pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
|
||||
pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>,
|
||||
|
||||
covfun_section_name: OnceCell<CString>,
|
||||
|
|
@ -31,7 +36,6 @@ pub(crate) struct CguCoverageContext<'ll, 'tcx> {
|
|||
impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
instances_used: RefCell::<FxIndexSet<_>>::default(),
|
||||
pgo_func_name_var_map: Default::default(),
|
||||
mcdc_condition_bitmap_map: Default::default(),
|
||||
covfun_section_name: Default::default(),
|
||||
|
|
@ -53,6 +57,14 @@ impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
|
|||
.and_then(|bitmap_map| bitmap_map.get(decision_depth as usize))
|
||||
.copied() // Dereference Option<&&Value> to Option<&Value>
|
||||
}
|
||||
|
||||
/// Returns the list of instances considered "used" in this CGU, as
|
||||
/// inferred from the keys of `pgo_func_name_var_map`.
|
||||
pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
|
||||
// Collecting into a Vec is way easier than trying to juggle RefCell
|
||||
// projections, and this should only run once per CGU anyway.
|
||||
self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
||||
|
|
@ -78,7 +90,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||
/// string, to hold the function name passed to LLVM intrinsic
|
||||
/// `instrprof.increment()`. The `Value` is only created once per instance.
|
||||
/// Multiple invocations with the same instance return the same `Value`.
|
||||
fn get_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
|
||||
///
|
||||
/// This has the side-effect of causing coverage codegen to consider this
|
||||
/// function "used", making it eligible to emit an associated covfun record.
|
||||
fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
|
||||
debug!("getting pgo_func_name_var for instance={:?}", instance);
|
||||
let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
|
||||
pgo_func_name_var_map.entry(instance).or_insert_with(|| {
|
||||
|
|
@ -102,7 +117,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let fn_name = self.get_pgo_func_name_var(instance);
|
||||
let fn_name = self.ensure_pgo_func_name_var(instance);
|
||||
let hash = self.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
|
||||
self.mcdc_parameters(fn_name, hash, bitmap_bits);
|
||||
|
|
@ -151,11 +166,6 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
// Mark the instance as used in this CGU, for coverage purposes.
|
||||
// This includes functions that were not partitioned into this CGU,
|
||||
// but were MIR-inlined into one of this CGU's functions.
|
||||
coverage_cx.instances_used.borrow_mut().insert(instance);
|
||||
|
||||
match *kind {
|
||||
CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
|
||||
"marker statement {kind:?} should have been removed by CleanupPostBorrowck"
|
||||
|
|
@ -163,7 +173,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
CoverageKind::VirtualCounter { bcb }
|
||||
if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
|
||||
{
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let fn_name = bx.ensure_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let num_counters = bx.const_u32(ids_info.num_counters);
|
||||
let index = bx.const_u32(id.as_u32());
|
||||
|
|
@ -193,7 +203,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||
"bitmap index of the decision out of range"
|
||||
);
|
||||
|
||||
let fn_name = bx.get_pgo_func_name_var(instance);
|
||||
let fn_name = bx.ensure_pgo_func_name_var(instance);
|
||||
let hash = bx.const_u64(function_coverage_info.function_source_hash);
|
||||
let bitmap_index = bx.const_u32(bitmap_idx);
|
||||
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ pub(crate) struct AutoDiffWithoutEnable;
|
|||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_lto_bitcode_from_rlib)]
|
||||
pub(crate) struct LtoBitcodeFromRlib {
|
||||
pub llvm_err: String,
|
||||
pub err: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
|
|||
|
|
@ -168,13 +168,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
|
|||
let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap();
|
||||
print!("{stats}");
|
||||
}
|
||||
fn run_link(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
modules: Vec<ModuleCodegen<Self::Module>>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
|
||||
back::write::link(cgcx, dcx, modules)
|
||||
}
|
||||
fn run_and_optimize_fat_lto(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
exported_symbols_for_lto: &[String],
|
||||
|
|
|
|||
|
|
@ -2612,13 +2612,6 @@ unsafe extern "C" {
|
|||
len: usize,
|
||||
Identifier: *const c_char,
|
||||
) -> Option<&Module>;
|
||||
pub(crate) fn LLVMRustGetSliceFromObjectDataByName(
|
||||
data: *const u8,
|
||||
len: usize,
|
||||
name: *const u8,
|
||||
name_len: usize,
|
||||
out_len: &mut usize,
|
||||
) -> *const u8;
|
||||
|
||||
pub(crate) fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
|
||||
pub(crate) fn LLVMRustLinkerAdd(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use std::any::Any;
|
||||
use std::assert_matches::assert_matches;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -372,8 +371,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
/// The incremental compilation session directory, or None if we are not
|
||||
/// compiling incrementally
|
||||
pub incr_comp_session_dir: Option<PathBuf>,
|
||||
/// Channel back to the main control thread to send messages to
|
||||
pub coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
/// `true` if the codegen should be run in parallel.
|
||||
///
|
||||
/// Depends on [`ExtraBackendMethods::supports_parallel()`] and `-Zno_parallel_backend`.
|
||||
|
|
@ -800,10 +797,6 @@ pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
|
|||
/// The backend has finished compiling a CGU, nothing more required.
|
||||
Finished(CompiledModule),
|
||||
|
||||
/// The backend has finished compiling a CGU, which now needs linking
|
||||
/// because `-Zcombine-cgu` was specified.
|
||||
NeedsLink(ModuleCodegen<B::Module>),
|
||||
|
||||
/// The backend has finished compiling a CGU, which now needs to go through
|
||||
/// fat LTO.
|
||||
NeedsFatLto(FatLtoInput<B>),
|
||||
|
|
@ -887,7 +880,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
|
|||
};
|
||||
|
||||
match lto_type {
|
||||
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
|
||||
ComputedLtoType::No => {
|
||||
let module = B::codegen(cgcx, module, module_config)?;
|
||||
Ok(WorkItemResult::Finished(module))
|
||||
}
|
||||
ComputedLtoType::Thin => {
|
||||
let (name, thin_buffer) = B::prepare_thin(module, false);
|
||||
if let Some(path) = bitcode {
|
||||
|
|
@ -1027,20 +1023,8 @@ fn execute_thin_lto_work_item<B: ExtraBackendMethods>(
|
|||
module_config: &ModuleConfig,
|
||||
) -> Result<WorkItemResult<B>, FatalError> {
|
||||
let module = B::optimize_thin(cgcx, module)?;
|
||||
finish_intra_module_work(cgcx, module, module_config)
|
||||
}
|
||||
|
||||
fn finish_intra_module_work<B: ExtraBackendMethods>(
|
||||
cgcx: &CodegenContext<B>,
|
||||
module: ModuleCodegen<B::Module>,
|
||||
module_config: &ModuleConfig,
|
||||
) -> Result<WorkItemResult<B>, FatalError> {
|
||||
if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
|
||||
let module = B::codegen(cgcx, module, module_config)?;
|
||||
Ok(WorkItemResult::Finished(module))
|
||||
} else {
|
||||
Ok(WorkItemResult::NeedsLink(module))
|
||||
}
|
||||
let module = B::codegen(cgcx, module, module_config)?;
|
||||
Ok(WorkItemResult::Finished(module))
|
||||
}
|
||||
|
||||
/// Messages sent to the coordinator.
|
||||
|
|
@ -1122,10 +1106,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
autodiff_items: &[AutoDiffItem],
|
||||
shared_emitter: SharedEmitter,
|
||||
codegen_worker_send: Sender<CguMessage>,
|
||||
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
||||
coordinator_receive: Receiver<Message<B>>,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
allocator_config: Arc<ModuleConfig>,
|
||||
tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
|
||||
tx_to_llvm_workers: Sender<Message<B>>,
|
||||
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
|
||||
let coordinator_send = tx_to_llvm_workers;
|
||||
let sess = tcx.sess;
|
||||
|
|
@ -1153,7 +1137,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let coordinator_send2 = coordinator_send.clone();
|
||||
let helper = jobserver::client()
|
||||
.into_helper_thread(move |token| {
|
||||
drop(coordinator_send2.send(Box::new(Message::Token::<B>(token))));
|
||||
drop(coordinator_send2.send(Message::Token::<B>(token)));
|
||||
})
|
||||
.expect("failed to spawn helper thread");
|
||||
|
||||
|
|
@ -1187,7 +1171,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
remark: sess.opts.cg.remark.clone(),
|
||||
remark_dir,
|
||||
incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
|
||||
coordinator_send,
|
||||
expanded_args: tcx.sess.expanded_args.clone(),
|
||||
diag_emitter: shared_emitter.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
|
|
@ -1347,7 +1330,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// through codegen and LLVM.
|
||||
let mut compiled_modules = vec![];
|
||||
let mut compiled_allocator_module = None;
|
||||
let mut needs_link = Vec::new();
|
||||
let mut needs_fat_lto = Vec::new();
|
||||
let mut needs_thin_lto = Vec::new();
|
||||
let mut lto_import_only_modules = Vec::new();
|
||||
|
|
@ -1423,7 +1405,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
let (item, _) =
|
||||
work_items.pop().expect("queue empty - queue_full_enough() broken?");
|
||||
main_thread_state = MainThreadState::Lending;
|
||||
spawn_work(&cgcx, &mut llvm_start_time, item);
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
}
|
||||
}
|
||||
} else if codegen_state == Completed {
|
||||
|
|
@ -1502,7 +1484,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
MainThreadState::Idle => {
|
||||
if let Some((item, _)) = work_items.pop() {
|
||||
main_thread_state = MainThreadState::Lending;
|
||||
spawn_work(&cgcx, &mut llvm_start_time, item);
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
} else {
|
||||
// There is no unstarted work, so let the main thread
|
||||
// take over for a running worker. Otherwise the
|
||||
|
|
@ -1538,7 +1520,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
while running_with_own_token < tokens.len()
|
||||
&& let Some((item, _)) = work_items.pop()
|
||||
{
|
||||
spawn_work(&cgcx, &mut llvm_start_time, item);
|
||||
spawn_work(&cgcx, coordinator_send.clone(), &mut llvm_start_time, item);
|
||||
running_with_own_token += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1546,8 +1528,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
// Relinquish accidentally acquired extra tokens.
|
||||
tokens.truncate(running_with_own_token);
|
||||
|
||||
let msg = coordinator_receive.recv().unwrap();
|
||||
match *msg.downcast::<Message<B>>().ok().unwrap() {
|
||||
match coordinator_receive.recv().unwrap() {
|
||||
// Save the token locally and the next turn of the loop will use
|
||||
// this to spawn a new unit of work, or it may get dropped
|
||||
// immediately if we have no more work to spawn.
|
||||
|
|
@ -1630,7 +1611,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
Ok(WorkItemResult::Finished(compiled_module)) => {
|
||||
match compiled_module.kind {
|
||||
ModuleKind::Regular => {
|
||||
assert!(needs_link.is_empty());
|
||||
compiled_modules.push(compiled_module);
|
||||
}
|
||||
ModuleKind::Allocator => {
|
||||
|
|
@ -1639,10 +1619,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
}
|
||||
}
|
||||
}
|
||||
Ok(WorkItemResult::NeedsLink(module)) => {
|
||||
assert!(compiled_modules.is_empty());
|
||||
needs_link.push(module);
|
||||
}
|
||||
Ok(WorkItemResult::NeedsFatLto(fat_lto_input)) => {
|
||||
assert!(!started_lto);
|
||||
assert!(needs_thin_lto.is_empty());
|
||||
|
|
@ -1679,17 +1655,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
return Err(());
|
||||
}
|
||||
|
||||
let needs_link = mem::take(&mut needs_link);
|
||||
if !needs_link.is_empty() {
|
||||
assert!(compiled_modules.is_empty());
|
||||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
let module = B::run_link(&cgcx, dcx, needs_link).map_err(|_| ())?;
|
||||
let module =
|
||||
B::codegen(&cgcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?;
|
||||
compiled_modules.push(module);
|
||||
}
|
||||
|
||||
// Drop to print timings
|
||||
drop(llvm_start_time);
|
||||
|
||||
|
|
@ -1769,6 +1734,7 @@ pub(crate) struct WorkerFatalError;
|
|||
|
||||
fn spawn_work<'a, B: ExtraBackendMethods>(
|
||||
cgcx: &'a CodegenContext<B>,
|
||||
coordinator_send: Sender<Message<B>>,
|
||||
llvm_start_time: &mut Option<VerboseTimingGuard<'a>>,
|
||||
work: WorkItem<B>,
|
||||
) {
|
||||
|
|
@ -1782,7 +1748,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
|
|||
// Set up a destructor which will fire off a message that we're done as
|
||||
// we exit.
|
||||
struct Bomb<B: ExtraBackendMethods> {
|
||||
coordinator_send: Sender<Box<dyn Any + Send>>,
|
||||
coordinator_send: Sender<Message<B>>,
|
||||
result: Option<Result<WorkItemResult<B>, FatalError>>,
|
||||
}
|
||||
impl<B: ExtraBackendMethods> Drop for Bomb<B> {
|
||||
|
|
@ -1794,11 +1760,11 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
|
|||
}
|
||||
None => Message::WorkItem::<B> { result: Err(None) },
|
||||
};
|
||||
drop(self.coordinator_send.send(Box::new(msg)));
|
||||
drop(self.coordinator_send.send(msg));
|
||||
}
|
||||
}
|
||||
|
||||
let mut bomb = Bomb::<B> { coordinator_send: cgcx.coordinator_send.clone(), result: None };
|
||||
let mut bomb = Bomb::<B> { coordinator_send, result: None };
|
||||
|
||||
// Execute the work itself, and if it finishes successfully then flag
|
||||
// ourselves as a success as well.
|
||||
|
|
@ -2003,7 +1969,7 @@ impl SharedEmitterMain {
|
|||
}
|
||||
|
||||
pub struct Coordinator<B: ExtraBackendMethods> {
|
||||
pub sender: Sender<Box<dyn Any + Send>>,
|
||||
sender: Sender<Message<B>>,
|
||||
future: Option<thread::JoinHandle<Result<CompiledModules, ()>>>,
|
||||
// Only used for the Message type.
|
||||
phantom: PhantomData<B>,
|
||||
|
|
@ -2020,7 +1986,7 @@ impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
|
|||
if let Some(future) = self.future.take() {
|
||||
// If we haven't joined yet, signal to the coordinator that it should spawn no more
|
||||
// work, and wait for worker threads to finish.
|
||||
drop(self.sender.send(Box::new(Message::CodegenAborted::<B>)));
|
||||
drop(self.sender.send(Message::CodegenAborted::<B>));
|
||||
drop(future.join());
|
||||
}
|
||||
}
|
||||
|
|
@ -2079,7 +2045,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
pub(crate) fn codegen_finished(&self, tcx: TyCtxt<'_>) {
|
||||
self.wait_for_signal_to_codegen_item();
|
||||
self.check_for_errors(tcx.sess);
|
||||
drop(self.coordinator.sender.send(Box::new(Message::CodegenComplete::<B>)));
|
||||
drop(self.coordinator.sender.send(Message::CodegenComplete::<B>));
|
||||
}
|
||||
|
||||
pub(crate) fn check_for_errors(&self, sess: &Session) {
|
||||
|
|
@ -2100,28 +2066,25 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
}
|
||||
|
||||
pub(crate) fn submit_codegened_module_to_llvm<B: ExtraBackendMethods>(
|
||||
_backend: &B,
|
||||
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
|
||||
coordinator: &Coordinator<B>,
|
||||
module: ModuleCodegen<B::Module>,
|
||||
cost: u64,
|
||||
) {
|
||||
let llvm_work_item = WorkItem::Optimize(module);
|
||||
drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost })));
|
||||
drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost }));
|
||||
}
|
||||
|
||||
pub(crate) fn submit_post_lto_module_to_llvm<B: ExtraBackendMethods>(
|
||||
_backend: &B,
|
||||
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
|
||||
coordinator: &Coordinator<B>,
|
||||
module: CachedModuleCodegen,
|
||||
) {
|
||||
let llvm_work_item = WorkItem::CopyPostLtoArtifacts(module);
|
||||
drop(tx_to_llvm_workers.send(Box::new(Message::CodegenDone::<B> { llvm_work_item, cost: 0 })));
|
||||
drop(coordinator.sender.send(Message::CodegenDone::<B> { llvm_work_item, cost: 0 }));
|
||||
}
|
||||
|
||||
pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
|
||||
_backend: &B,
|
||||
tcx: TyCtxt<'_>,
|
||||
tx_to_llvm_workers: &Sender<Box<dyn Any + Send>>,
|
||||
coordinator: &Coordinator<B>,
|
||||
module: CachedModuleCodegen,
|
||||
) {
|
||||
let filename = pre_lto_bitcode_filename(&module.name);
|
||||
|
|
@ -2135,10 +2098,10 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
|
|||
})
|
||||
};
|
||||
// Schedule the module to be loaded
|
||||
drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule::<B> {
|
||||
drop(coordinator.sender.send(Message::AddImportOnlyModule::<B> {
|
||||
module_data: SerializedModule::FromUncompressedFile(mmap),
|
||||
work_product: module.source,
|
||||
})));
|
||||
}));
|
||||
}
|
||||
|
||||
fn pre_lto_bitcode_filename(module_name: &str) -> String {
|
||||
|
|
|
|||
|
|
@ -702,8 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
// These modules are generally cheap and won't throw off scheduling.
|
||||
let cost = 0;
|
||||
submit_codegened_module_to_llvm(
|
||||
&backend,
|
||||
&ongoing_codegen.coordinator.sender,
|
||||
&ongoing_codegen.coordinator,
|
||||
ModuleCodegen::new_allocator(llmod_id, module_llvm),
|
||||
cost,
|
||||
);
|
||||
|
|
@ -800,18 +799,12 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
// compilation hang on post-monomorphization errors.
|
||||
tcx.dcx().abort_if_errors();
|
||||
|
||||
submit_codegened_module_to_llvm(
|
||||
&backend,
|
||||
&ongoing_codegen.coordinator.sender,
|
||||
module,
|
||||
cost,
|
||||
);
|
||||
submit_codegened_module_to_llvm(&ongoing_codegen.coordinator, module, cost);
|
||||
}
|
||||
CguReuse::PreLto => {
|
||||
submit_pre_lto_module_to_llvm(
|
||||
&backend,
|
||||
tcx,
|
||||
&ongoing_codegen.coordinator.sender,
|
||||
&ongoing_codegen.coordinator,
|
||||
CachedModuleCodegen {
|
||||
name: cgu.name().to_string(),
|
||||
source: cgu.previous_work_product(tcx),
|
||||
|
|
@ -820,8 +813,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
}
|
||||
CguReuse::PostLto => {
|
||||
submit_post_lto_module_to_llvm(
|
||||
&backend,
|
||||
&ongoing_codegen.coordinator.sender,
|
||||
&ongoing_codegen.coordinator,
|
||||
CachedModuleCodegen {
|
||||
name: cgu.name().to_string(),
|
||||
source: cgu.previous_work_product(tcx),
|
||||
|
|
|
|||
|
|
@ -16,12 +16,6 @@ pub trait WriteBackendMethods: Clone + 'static {
|
|||
type ThinData: Send + Sync;
|
||||
type ThinBuffer: ThinBufferMethods;
|
||||
|
||||
/// Merge all modules into main_module and returning it
|
||||
fn run_link(
|
||||
cgcx: &CodegenContext<Self>,
|
||||
dcx: DiagCtxtHandle<'_>,
|
||||
modules: Vec<ModuleCodegen<Self::Module>>,
|
||||
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
|
||||
/// Performs fat LTO by merging all modules into a single one, running autodiff
|
||||
/// if necessary and running any further optimizations
|
||||
fn run_and_optimize_fat_lto(
|
||||
|
|
|
|||
|
|
@ -1650,40 +1650,6 @@ extern "C" LLVMModuleRef LLVMRustParseBitcodeForLTO(LLVMContextRef Context,
|
|||
return wrap(std::move(*SrcOrError).release());
|
||||
}
|
||||
|
||||
// Find a section of an object file by name. Fail if the section is missing or
|
||||
// empty.
|
||||
extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data,
|
||||
size_t len,
|
||||
const char *name,
|
||||
size_t name_len,
|
||||
size_t *out_len) {
|
||||
*out_len = 0;
|
||||
auto Name = StringRef(name, name_len);
|
||||
auto Data = StringRef(data, len);
|
||||
auto Buffer = MemoryBufferRef(Data, ""); // The id is unused.
|
||||
file_magic Type = identify_magic(Buffer.getBuffer());
|
||||
Expected<std::unique_ptr<object::ObjectFile>> ObjFileOrError =
|
||||
object::ObjectFile::createObjectFile(Buffer, Type);
|
||||
if (!ObjFileOrError) {
|
||||
LLVMRustSetLastError(toString(ObjFileOrError.takeError()).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
for (const object::SectionRef &Sec : (*ObjFileOrError)->sections()) {
|
||||
Expected<StringRef> SecName = Sec.getName();
|
||||
if (SecName && *SecName == Name) {
|
||||
Expected<StringRef> SectionOrError = Sec.getContents();
|
||||
if (!SectionOrError) {
|
||||
LLVMRustSetLastError(toString(SectionOrError.takeError()).c_str());
|
||||
return nullptr;
|
||||
}
|
||||
*out_len = SectionOrError->size();
|
||||
return SectionOrError->data();
|
||||
}
|
||||
}
|
||||
LLVMRustSetLastError("could not find requested section");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
|
||||
// storing the result in 'KeyOut'.
|
||||
// Currently, this cache key is a SHA-1 hash of anything that could affect
|
||||
|
|
|
|||
|
|
@ -2168,8 +2168,6 @@ options! {
|
|||
"hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
|
||||
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||
"the backend to use"),
|
||||
combine_cgu: bool = (false, parse_bool, [TRACKED],
|
||||
"combine CGUs into a single one"),
|
||||
contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||
"emit runtime checks for contract pre- and post-conditions (default: no)"),
|
||||
coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
|
||||
|
|
|
|||
|
|
@ -407,17 +407,22 @@ impl str {
|
|||
/// ```
|
||||
#[unstable(feature = "round_char_boundary", issue = "93743")]
|
||||
#[inline]
|
||||
pub fn floor_char_boundary(&self, index: usize) -> usize {
|
||||
pub const fn floor_char_boundary(&self, index: usize) -> usize {
|
||||
if index >= self.len() {
|
||||
self.len()
|
||||
} else {
|
||||
let lower_bound = index.saturating_sub(3);
|
||||
let new_index = self.as_bytes()[lower_bound..=index]
|
||||
.iter()
|
||||
.rposition(|b| b.is_utf8_char_boundary());
|
||||
let mut i = index;
|
||||
while i > 0 {
|
||||
if self.as_bytes()[i].is_utf8_char_boundary() {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
// SAFETY: we know that the character boundary will be within four bytes
|
||||
unsafe { lower_bound + new_index.unwrap_unchecked() }
|
||||
// The character boundary will be within four bytes of the index
|
||||
debug_assert!(i >= index.saturating_sub(3));
|
||||
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -445,15 +450,22 @@ impl str {
|
|||
/// ```
|
||||
#[unstable(feature = "round_char_boundary", issue = "93743")]
|
||||
#[inline]
|
||||
pub fn ceil_char_boundary(&self, index: usize) -> usize {
|
||||
pub const fn ceil_char_boundary(&self, index: usize) -> usize {
|
||||
if index >= self.len() {
|
||||
self.len()
|
||||
} else {
|
||||
let upper_bound = Ord::min(index + 4, self.len());
|
||||
self.as_bytes()[index..upper_bound]
|
||||
.iter()
|
||||
.position(|b| b.is_utf8_char_boundary())
|
||||
.map_or(upper_bound, |pos| pos + index)
|
||||
let mut i = index;
|
||||
while i < self.len() {
|
||||
if self.as_bytes()[i].is_utf8_char_boundary() {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// The character boundary will be within four bytes of the index
|
||||
debug_assert!(i <= index + 3);
|
||||
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -563,8 +563,8 @@ impl AtomicBool {
|
|||
/// `align_of::<AtomicBool>() == 1`).
|
||||
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
|
||||
/// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
|
||||
/// without synchronization.
|
||||
/// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
|
||||
/// sizes, without synchronization.
|
||||
///
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
|
|
@ -1246,7 +1246,7 @@ impl AtomicBool {
|
|||
/// atomic types work with interior mutability. All modifications of an atomic change the value
|
||||
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
|
||||
/// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
|
||||
/// restriction: operations on it must be atomic.
|
||||
/// restriction in [Memory model for atomic accesses].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1264,6 +1264,8 @@ impl AtomicBool {
|
|||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[inline]
|
||||
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
|
|
@ -1519,8 +1521,8 @@ impl<T> AtomicPtr<T> {
|
|||
/// can be bigger than `align_of::<*mut T>()`).
|
||||
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
|
||||
/// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
|
||||
/// without synchronization.
|
||||
/// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
|
||||
/// sizes, without synchronization.
|
||||
///
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
|
|
@ -2488,7 +2490,7 @@ impl<T> AtomicPtr<T> {
|
|||
/// atomic types work with interior mutability. All modifications of an atomic change the value
|
||||
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
|
||||
/// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
|
||||
/// restriction: operations on it must be atomic.
|
||||
/// restriction in [Memory model for atomic accesses].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -2507,6 +2509,8 @@ impl<T> AtomicPtr<T> {
|
|||
/// my_atomic_op(atomic.as_ptr());
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[inline]
|
||||
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
|
|
@ -2698,8 +2702,8 @@ macro_rules! atomic_int {
|
|||
}]
|
||||
/// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
||||
/// * You must adhere to the [Memory model for atomic accesses]. In particular, it is not
|
||||
/// allowed to mix atomic and non-atomic accesses, or atomic accesses of different sizes,
|
||||
/// without synchronization.
|
||||
/// allowed to mix conflicting atomic and non-atomic accesses, or atomic accesses of different
|
||||
/// sizes, without synchronization.
|
||||
///
|
||||
/// [valid]: crate::ptr#safety
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
|
|
@ -3620,7 +3624,7 @@ macro_rules! atomic_int {
|
|||
/// atomic types work with interior mutability. All modifications of an atomic change the value
|
||||
/// through a shared reference, and can do so safely as long as they use atomic operations. Any
|
||||
/// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same
|
||||
/// restriction: operations on it must be atomic.
|
||||
/// restriction in [Memory model for atomic accesses].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -3640,6 +3644,8 @@ macro_rules! atomic_int {
|
|||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses
|
||||
#[inline]
|
||||
#[stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
#[rustc_const_stable(feature = "atomic_as_ptr", since = "1.70.0")]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ edition = "2024"
|
|||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
alloc = { path = "../alloc" }
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ edition = "2024"
|
|||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core", public = true }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ edition = "2024"
|
|||
|
||||
[lib]
|
||||
path = "lib.rs"
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
|
||||
[dependencies]
|
||||
std = { path = "../std" }
|
||||
|
|
|
|||
|
|
@ -131,14 +131,13 @@ macro_rules! features {
|
|||
};
|
||||
}
|
||||
|
||||
#[test] //tidy:skip
|
||||
#[deny(unexpected_cfgs)]
|
||||
#[deny(unfulfilled_lint_expectations)]
|
||||
fn unexpected_cfgs() {
|
||||
const _: () = {
|
||||
$(
|
||||
check_cfg_feature!($feature, $feature_lit $(, without cfg check: $feature_cfg_check)? $(: $($target_feature_lit),*)?);
|
||||
)*
|
||||
}
|
||||
};
|
||||
|
||||
/// Each variant denotes a position in a bitset for a particular feature.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -135,4 +135,5 @@ pub(crate) fn imply_features(mut value: cache::Initializer) -> cache::Initialize
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "riscv/tests.rs"]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ version = "0.0.0"
|
|||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
bench = false
|
||||
# make sure this crate isn't included in public standard library docs
|
||||
doc = false
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ description = "A drop-in replacement for the real windows-targets crate for use
|
|||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
test = false
|
||||
bench = false
|
||||
doc = false
|
||||
|
||||
[features]
|
||||
# Enable using raw-dylib for Windows imports.
|
||||
# This will eventually be the default.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "miropt-test-tools"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ fn output_file_suffix(testfile: &Path, bit_width: u32, panic_strategy: PanicStra
|
|||
|
||||
let mut suffix = String::new();
|
||||
if each_bit_width {
|
||||
suffix.push_str(&format!(".{}bit", bit_width));
|
||||
suffix.push_str(&format!(".{bit_width}bit"));
|
||||
}
|
||||
if each_panic_strategy {
|
||||
match panic_strategy {
|
||||
|
|
@ -51,7 +51,7 @@ pub fn files_for_miropt_test(
|
|||
panic_strategy: PanicStrategy,
|
||||
) -> MiroptTest {
|
||||
let mut out = Vec::new();
|
||||
let test_file_contents = fs::read_to_string(&testfile).unwrap();
|
||||
let test_file_contents = fs::read_to_string(testfile).unwrap();
|
||||
|
||||
let test_dir = testfile.parent().unwrap();
|
||||
let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace('-', "_");
|
||||
|
|
@ -76,10 +76,10 @@ pub fn files_for_miropt_test(
|
|||
|
||||
if test_name.ends_with(".diff") {
|
||||
let trimmed = test_name.trim_end_matches(".diff");
|
||||
passes.push(trimmed.split('.').last().unwrap().to_owned());
|
||||
let test_against = format!("{}.after.mir", trimmed);
|
||||
from_file = format!("{}.before.mir", trimmed);
|
||||
expected_file = format!("{}{}.diff", trimmed, suffix);
|
||||
passes.push(trimmed.split('.').next_back().unwrap().to_owned());
|
||||
let test_against = format!("{trimmed}.after.mir");
|
||||
from_file = format!("{trimmed}.before.mir");
|
||||
expected_file = format!("{trimmed}{suffix}.diff");
|
||||
assert!(test_names.next().is_none(), "two mir pass names specified for MIR diff");
|
||||
to_file = Some(test_against);
|
||||
} else if let Some(first_pass) = test_names.next() {
|
||||
|
|
@ -92,10 +92,9 @@ pub fn files_for_miropt_test(
|
|||
}
|
||||
assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
|
||||
|
||||
expected_file =
|
||||
format!("{}{}.{}-{}.diff", test_name, suffix, first_pass, second_pass);
|
||||
let second_file = format!("{}.{}.mir", test_name, second_pass);
|
||||
from_file = format!("{}.{}.mir", test_name, first_pass);
|
||||
expected_file = format!("{test_name}{suffix}.{first_pass}-{second_pass}.diff");
|
||||
let second_file = format!("{test_name}.{second_pass}.mir");
|
||||
from_file = format!("{test_name}.{first_pass}.mir");
|
||||
to_file = Some(second_file);
|
||||
} else {
|
||||
// Allow-list for file extensions that can be produced by MIR dumps.
|
||||
|
|
@ -112,7 +111,7 @@ pub fn files_for_miropt_test(
|
|||
)
|
||||
}
|
||||
|
||||
expected_file = format!("{}{}.{}", test_name_wo_ext, suffix, test_name_ext);
|
||||
expected_file = format!("{test_name_wo_ext}{suffix}.{test_name_ext}");
|
||||
from_file = test_name.to_string();
|
||||
assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
|
||||
to_file = None;
|
||||
|
|
@ -123,7 +122,7 @@ pub fn files_for_miropt_test(
|
|||
);
|
||||
};
|
||||
if !expected_file.starts_with(&test_crate) {
|
||||
expected_file = format!("{}.{}", test_crate, expected_file);
|
||||
expected_file = format!("{test_crate}.{expected_file}");
|
||||
}
|
||||
let expected_file = test_dir.join(expected_file);
|
||||
|
||||
|
|
|
|||
|
|
@ -128,9 +128,9 @@ fn main() {
|
|||
check!(pal, &library_path);
|
||||
|
||||
// Checks that need to be done for both the compiler and std libraries.
|
||||
check!(unit_tests, &src_path);
|
||||
check!(unit_tests, &compiler_path);
|
||||
check!(unit_tests, &library_path);
|
||||
check!(unit_tests, &src_path, false);
|
||||
check!(unit_tests, &compiler_path, false);
|
||||
check!(unit_tests, &library_path, true);
|
||||
|
||||
if bins::check_filesystem_support(&[&root_path], &output_directory) {
|
||||
check!(bins, &root_path);
|
||||
|
|
|
|||
|
|
@ -1,44 +1,60 @@
|
|||
//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
|
||||
//! `core` or `alloc`.
|
||||
//! of the standard library.
|
||||
//!
|
||||
//! `core` and `alloc` cannot be tested directly due to duplicating lang items.
|
||||
//! All tests and benchmarks must be written externally in
|
||||
//! `{coretests,alloctests}/{tests,benches}`.
|
||||
//!
|
||||
//! Outside of `core` and `alloc`, tests and benchmarks should be outlined into
|
||||
//! separate files named `tests.rs` or `benches.rs`, or directories named
|
||||
//! Outside of the standard library, tests and benchmarks should be outlined
|
||||
//! into separate files named `tests.rs` or `benches.rs`, or directories named
|
||||
//! `tests` or `benches` unconfigured during normal build.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use crate::walk::{filter_dirs, walk};
|
||||
|
||||
pub fn check(root_path: &Path, bad: &mut bool) {
|
||||
let core = root_path.join("core");
|
||||
let core_copy = core.clone();
|
||||
let is_core = move |path: &Path| path.starts_with(&core);
|
||||
let alloc = root_path.join("alloc");
|
||||
let alloc_copy = alloc.clone();
|
||||
let is_alloc = move |path: &Path| path.starts_with(&alloc);
|
||||
|
||||
pub fn check(root_path: &Path, stdlib: bool, bad: &mut bool) {
|
||||
let skip = move |path: &Path, is_dir| {
|
||||
let file_name = path.file_name().unwrap_or_default();
|
||||
|
||||
// Skip excluded directories and non-rust files
|
||||
if is_dir {
|
||||
filter_dirs(path)
|
||||
|| path.ends_with("src/doc")
|
||||
|| (file_name == "tests" || file_name == "benches")
|
||||
&& !is_core(path)
|
||||
&& !is_alloc(path)
|
||||
if filter_dirs(path) || path.ends_with("src/doc") {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
let extension = path.extension().unwrap_or_default();
|
||||
extension != "rs"
|
||||
|| (file_name == "tests.rs" || file_name == "benches.rs")
|
||||
&& !is_core(path)
|
||||
&& !is_alloc(path)
|
||||
// Tests which use non-public internals and, as such, need to
|
||||
// have the types in the same crate as the tests themselves. See
|
||||
// the comment in alloctests/lib.rs.
|
||||
|| path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs")
|
||||
if extension != "rs" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Tests in a separate package are always allowed
|
||||
if is_dir && file_name != "tests" && file_name.as_encoded_bytes().ends_with(b"tests") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !stdlib {
|
||||
// Outside of the standard library tests may also be in separate files in the same crate
|
||||
if is_dir {
|
||||
if file_name == "tests" || file_name == "benches" {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if file_name == "tests.rs" || file_name == "benches.rs" {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if is_dir {
|
||||
// FIXME remove those exceptions once no longer necessary
|
||||
file_name == "std_detect" || file_name == "std" || file_name == "test"
|
||||
} else {
|
||||
// Tests which use non-public internals and, as such, need to
|
||||
// have the types in the same crate as the tests themselves. See
|
||||
// the comment in alloctests/lib.rs.
|
||||
path.ends_with("library/alloc/src/collections/btree/borrow/tests.rs")
|
||||
|| path.ends_with("library/alloc/src/collections/btree/map/tests.rs")
|
||||
|| path.ends_with("library/alloc/src/collections/btree/node/tests.rs")
|
||||
|| path.ends_with("library/alloc/src/collections/btree/set/tests.rs")
|
||||
|
|
@ -50,22 +66,29 @@ pub fn check(root_path: &Path, bad: &mut bool) {
|
|||
|
||||
walk(root_path, skip, &mut |entry, contents| {
|
||||
let path = entry.path();
|
||||
let is_core = path.starts_with(&core_copy);
|
||||
let is_alloc = path.starts_with(&alloc_copy);
|
||||
let package = path
|
||||
.strip_prefix(root_path)
|
||||
.unwrap()
|
||||
.components()
|
||||
.next()
|
||||
.unwrap()
|
||||
.as_os_str()
|
||||
.to_str()
|
||||
.unwrap();
|
||||
for (i, line) in contents.lines().enumerate() {
|
||||
let line = line.trim();
|
||||
let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
|
||||
let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
|
||||
let manual_skip = line.contains("//tidy:skip");
|
||||
if !line.starts_with("//") && (is_test() || is_bench()) && !manual_skip {
|
||||
let explanation = if is_core {
|
||||
"`core` unit tests and benchmarks must be placed into `coretests`"
|
||||
} else if is_alloc {
|
||||
"`alloc` unit tests and benchmarks must be placed into `alloctests`"
|
||||
if !line.starts_with("//") && (is_test() || is_bench()) {
|
||||
let explanation = if stdlib {
|
||||
format!(
|
||||
"`{package}` unit tests and benchmarks must be placed into `{package}tests`"
|
||||
)
|
||||
} else {
|
||||
"unit tests and benchmarks must be placed into \
|
||||
separate files or directories named \
|
||||
`tests.rs`, `benches.rs`, `tests` or `benches`"
|
||||
.to_owned()
|
||||
};
|
||||
let name = if is_test() { "test" } else { "bench" };
|
||||
tidy_error!(
|
||||
|
|
|
|||
|
|
@ -412,6 +412,10 @@ These tests revolve around command-line flags which change the way error/warning
|
|||
|
||||
Exercises `#[diagnostic::*]` namespaced attributes. See [RFC 3368 Diagnostic attribute namespace](https://github.com/rust-lang/rfcs/blob/master/text/3368-diagnostic-attribute-namespace.md).
|
||||
|
||||
## `tests/ui/diagnostics-infra`
|
||||
|
||||
This directory contains tests and infrastructure related to the diagnostics system, including support for translatable diagnostics
|
||||
|
||||
## `tests/ui/diagnostic-width/`: `--diagnostic-width`
|
||||
|
||||
Everything to do with `--diagnostic-width`.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11192
|
||||
|
||||
struct Foo {
|
||||
x: isize
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as mutable
|
||||
--> $DIR/issue-11192.rs:20:10
|
||||
--> $DIR/closure-borrow-conflict-11192.rs:22:10
|
||||
|
|
||||
LL | let mut test = |foo: &Foo| {
|
||||
| ----------- mutable borrow occurs here
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11085
|
||||
|
||||
//@ run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11205
|
||||
|
||||
//@ run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
24
tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs
Normal file
24
tests/ui/diagnostics-infra/primary-fluent-bundle-missing.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/106755
|
||||
|
||||
//@ compile-flags:-Ztranslate-lang=en_US
|
||||
|
||||
#![feature(negative_impls)]
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
#[marker]
|
||||
trait MyTrait {}
|
||||
|
||||
struct TestType<T>(::std::marker::PhantomData<T>);
|
||||
|
||||
unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
|
||||
|
||||
impl<T: MyTrait> !Send for TestType<T> {}
|
||||
//~^ ERROR found both positive and negative implementation
|
||||
//~| ERROR `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not
|
||||
|
||||
unsafe impl<T: 'static> Send for TestType<T> {} //~ ERROR conflicting implementations
|
||||
|
||||
impl !Send for TestType<i32> {}
|
||||
//~^ ERROR `!Send` impls cannot be specialized
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
error[E0751]: found both positive and negative implementation of trait `Send` for type `TestType<_>`:
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:15:1
|
||||
|
|
||||
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
|
||||
| ------------------------------------------------------ positive implementation here
|
||||
LL |
|
||||
LL | impl<T: MyTrait> !Send for TestType<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ negative implementation here
|
||||
|
||||
error[E0119]: conflicting implementations of trait `Send` for type `TestType<_>`
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:19:1
|
||||
|
|
||||
LL | unsafe impl<T: MyTrait + 'static> Send for TestType<T> {}
|
||||
| ------------------------------------------------------ first implementation here
|
||||
...
|
||||
LL | unsafe impl<T: 'static> Send for TestType<T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `TestType<_>`
|
||||
|
||||
error[E0367]: `!Send` impl requires `T: MyTrait` but the struct it is implemented for does not
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:15:9
|
||||
|
|
||||
LL | impl<T: MyTrait> !Send for TestType<T> {}
|
||||
| ^^^^^^^
|
||||
|
|
||||
note: the implementor must specify the same requirement
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:11:1
|
||||
|
|
||||
LL | struct TestType<T>(::std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0366]: `!Send` impls cannot be specialized
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:21:1
|
||||
|
|
||||
LL | impl !Send for TestType<i32> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `i32` is not a generic parameter
|
||||
note: use the same sequence of generic lifetime, type and const parameters as the struct definition
|
||||
--> $DIR/primary-fluent-bundle-missing.rs:11:1
|
||||
|
|
||||
LL | struct TestType<T>(::std::marker::PhantomData<T>);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0119, E0366, E0367, E0751.
|
||||
For more information about an error, try `rustc --explain E0119`.
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10734
|
||||
|
||||
//@ run-pass
|
||||
#![allow(non_upper_case_globals)]
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10802
|
||||
|
||||
//@ run-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10764
|
||||
|
||||
fn f(_: extern "Rust" fn()) {}
|
||||
extern "C" fn bar() {}
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-10764.rs:4:15
|
||||
--> $DIR/extern-rust-fn-type-error-10764.rs:6:15
|
||||
|
|
||||
LL | fn main() { f(bar) }
|
||||
| - ^^^ expected "Rust" fn, found "C" fn
|
||||
|
|
@ -9,7 +9,7 @@ LL | fn main() { f(bar) }
|
|||
= note: expected fn pointer `fn()`
|
||||
found fn item `extern "C" fn() {bar}`
|
||||
note: function defined here
|
||||
--> $DIR/issue-10764.rs:1:4
|
||||
--> $DIR/extern-rust-fn-type-error-10764.rs:3:4
|
||||
|
|
||||
LL | fn f(_: extern "Rust" fn()) {}
|
||||
| ^ ---------------------
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10877
|
||||
|
||||
struct Foo {
|
||||
x: isize,
|
||||
}
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
error[E0130]: patterns aren't allowed in foreign function declarations
|
||||
--> $DIR/issue-10877.rs:5:12
|
||||
--> $DIR/foreign-fn-pattern-error-10877.rs:7:12
|
||||
|
|
||||
LL | fn foo(1: ());
|
||||
| ^ pattern not allowed in foreign function
|
||||
|
||||
error[E0130]: patterns aren't allowed in foreign function declarations
|
||||
--> $DIR/issue-10877.rs:7:12
|
||||
--> $DIR/foreign-fn-pattern-error-10877.rs:9:12
|
||||
|
|
||||
LL | fn bar((): isize);
|
||||
| ^^ pattern not allowed in foreign function
|
||||
|
||||
error[E0130]: patterns aren't allowed in foreign function declarations
|
||||
--> $DIR/issue-10877.rs:9:12
|
||||
--> $DIR/foreign-fn-pattern-error-10877.rs:11:12
|
||||
|
|
||||
LL | fn baz(Foo { x }: isize);
|
||||
| ^^^^^^^^^ pattern not allowed in foreign function
|
||||
|
||||
error[E0130]: patterns aren't allowed in foreign function declarations
|
||||
--> $DIR/issue-10877.rs:11:12
|
||||
--> $DIR/foreign-fn-pattern-error-10877.rs:13:12
|
||||
|
|
||||
LL | fn qux((x, y): ());
|
||||
| ^^^^^^ pattern not allowed in foreign function
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10806
|
||||
|
||||
//@ edition: 2015
|
||||
//@ run-pass
|
||||
#![allow(unused_imports)]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10718
|
||||
|
||||
//@ run-pass
|
||||
|
||||
fn f<F:FnOnce()>(p: F) {
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10436
|
||||
|
||||
//@ run-pass
|
||||
fn works<T>(x: T) -> Vec<T> { vec![x] }
|
||||
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
//@ run-pass
|
||||
|
||||
pub fn main() {
|
||||
fn f() {
|
||||
}
|
||||
let _: Box<fn()> = Box::new(f as fn());
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10396
|
||||
|
||||
//@ check-pass
|
||||
#![allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10291
|
||||
|
||||
fn test<'x>(x: &'x isize) {
|
||||
drop::<Box<dyn for<'z> FnMut(&'z isize) -> &'z isize>>(Box::new(|z| {
|
||||
x
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error: lifetime may not live long enough
|
||||
--> $DIR/issue-10291.rs:3:9
|
||||
--> $DIR/closure-lifetime-bounds-10291.rs:5:9
|
||||
|
|
||||
LL | fn test<'x>(x: &'x isize) {
|
||||
| -- lifetime `'x` defined here
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11374
|
||||
|
||||
use std::io::{self, Read};
|
||||
use std::vec;
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-11374.rs:27:15
|
||||
--> $DIR/container-lifetime-error-11374.rs:29:15
|
||||
|
|
||||
LL | c.read_to(v);
|
||||
| ------- ^ expected `&mut [u8]`, found `Vec<_>`
|
||||
|
|
@ -9,7 +9,7 @@ LL | c.read_to(v);
|
|||
= note: expected mutable reference `&mut [u8]`
|
||||
found struct `Vec<_>`
|
||||
note: method defined here
|
||||
--> $DIR/issue-11374.rs:13:12
|
||||
--> $DIR/container-lifetime-error-11374.rs:15:12
|
||||
|
|
||||
LL | pub fn read_to(&mut self, vec: &mut [u8]) {
|
||||
| ^^^^^^^ --------------
|
||||
|
|
@ -19,7 +19,7 @@ LL | c.read_to(&mut v);
|
|||
| ++++
|
||||
|
||||
error[E0515]: cannot return value referencing local variable `r`
|
||||
--> $DIR/issue-11374.rs:20:5
|
||||
--> $DIR/container-lifetime-error-11374.rs:22:5
|
||||
|
|
||||
LL | Container::wrap(&mut r as &mut dyn io::Read)
|
||||
| ^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10228
|
||||
|
||||
//@ run-pass
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_variables)]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10412
|
||||
|
||||
trait Serializable<'self, T> {
|
||||
//~^ ERROR lifetimes cannot use keyword names
|
||||
fn serialize(val: &'self T) -> Vec<u8>; //~ ERROR lifetimes cannot use keyword names
|
||||
|
|
@ -1,47 +1,47 @@
|
|||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:1:20
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:3:20
|
||||
|
|
||||
LL | trait Serializable<'self, T> {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:3:24
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:5:24
|
||||
|
|
||||
LL | fn serialize(val: &'self T) -> Vec<u8>;
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:4:37
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:6:37
|
||||
|
|
||||
LL | fn deserialize(repr: &[u8]) -> &'self T;
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:7:6
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:9:6
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:7:36
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:9:36
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:11:24
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:13:24
|
||||
|
|
||||
LL | fn serialize(val: &'self str) -> Vec<u8> {
|
||||
| ^^^^^
|
||||
|
||||
error: lifetimes cannot use keyword names
|
||||
--> $DIR/issue-10412.rs:15:37
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:17:37
|
||||
|
|
||||
LL | fn deserialize(repr: &[u8]) -> &'self str {
|
||||
| ^^^^^
|
||||
|
||||
error[E0726]: implicit elided lifetime not allowed here
|
||||
--> $DIR/issue-10412.rs:7:13
|
||||
--> $DIR/keyword-self-lifetime-error-10412.rs:9:13
|
||||
|
|
||||
LL | impl<'self> Serializable<str> for &'self str {
|
||||
| ^^^^^^^^^^^^^^^^^ expected lifetime parameter
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10902
|
||||
|
||||
//@ check-pass
|
||||
#![allow(dead_code)]
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10853
|
||||
|
||||
//@ check-pass
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10638
|
||||
|
||||
//@ run-pass
|
||||
|
||||
pub fn main() {
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10683
|
||||
|
||||
//@ run-pass
|
||||
|
||||
static NAME: &'static str = "hello world";
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10545
|
||||
|
||||
mod a {
|
||||
struct S;
|
||||
impl S { }
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
error[E0603]: struct `S` is private
|
||||
--> $DIR/issue-10545.rs:6:14
|
||||
--> $DIR/struct-field-and-impl-expose-10545.rs:8:14
|
||||
|
|
||||
LL | fn foo(_: a::S) {
|
||||
| ^ private struct
|
||||
|
|
||||
note: the struct `S` is defined here
|
||||
--> $DIR/issue-10545.rs:2:5
|
||||
--> $DIR/struct-field-and-impl-expose-10545.rs:4:5
|
||||
|
|
||||
LL | struct S;
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11267
|
||||
|
||||
//@ run-pass
|
||||
// Tests that unary structs can be mutably borrowed.
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10456
|
||||
|
||||
//@ check-pass
|
||||
|
||||
pub struct Foo;
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/10465
|
||||
|
||||
pub mod a {
|
||||
pub trait A {
|
||||
fn foo(&self);
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0599]: no method named `foo` found for reference `&B` in the current scope
|
||||
--> $DIR/issue-10465.rs:17:15
|
||||
--> $DIR/nested-mod-trait-method-lookup-leak-10465.rs:19:15
|
||||
|
|
||||
LL | b.foo();
|
||||
| ^^^ method not found in `&B`
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/102964
|
||||
|
||||
use std::rc::Rc;
|
||||
type Foo<'a, T> = &'a dyn Fn(&T);
|
||||
type RcFoo<'a, T> = Rc<Foo<'a, T>>;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/issue-102964.rs:5:41
|
||||
--> $DIR/dummy-binder-102964.rs:7:41
|
||||
|
|
||||
LL | fn bar_function<T>(function: Foo<T>) -> RcFoo<T> {
|
||||
| ------------ ^^^^^^^^ expected `Rc<&dyn Fn(&T)>`, found `()`
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11047
|
||||
|
||||
//@ run-pass
|
||||
// Test that static methods can be invoked on `type` aliases
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Regression test for https://github.com/rust-lang/rust/issues/11004
|
||||
|
||||
use std::mem;
|
||||
|
||||
struct A { x: i32, y: f64 }
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
error[E0609]: no field `x` on type `*mut A`
|
||||
--> $DIR/issue-11004.rs:7:21
|
||||
--> $DIR/raw-pointer-field-access-error.rs:9:21
|
||||
|
|
||||
LL | let x : i32 = n.x;
|
||||
| ^ unknown field
|
||||
|
|
@ -10,7 +10,7 @@ LL | let x : i32 = (*n).x;
|
|||
| ++ +
|
||||
|
||||
error[E0609]: no field `y` on type `*mut A`
|
||||
--> $DIR/issue-11004.rs:8:21
|
||||
--> $DIR/raw-pointer-field-access-error.rs:10:21
|
||||
|
|
||||
LL | let y : f64 = n.y;
|
||||
| ^ unknown field
|
||||
Loading…
Add table
Add a link
Reference in a new issue