Auto merge of #124034 - GuillaumeGomez:rollup-ayztp9l, r=GuillaumeGomez

Rollup of 7 pull requests

Successful merges:

 - #122811 (Move `SourceMap` initialization)
 - #123512 (Match ergonomics 2024: Implement eat-one-layer)
 - #123811 (Use queue-based `RwLock` on more platforms)
 - #123859 (Remove uneeded clones now that TrustedStep implies Copy)
 - #123979 (Subtype predicates only exist on inference types, so we can allow them to register opaque types within them.)
 - #124016 (Outline default query and hook provider function implementations)
 - #124023 (Allow workproducts without object files.)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-04-16 19:52:48 +00:00
commit 1cec373f65
39 changed files with 998 additions and 680 deletions

View File

@ -36,6 +36,7 @@ use rustc_macros::HashStable_Generic;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
use std::cmp;
use std::fmt;
use std::mem;
use thin_vec::{thin_vec, ThinVec};
@ -731,6 +732,13 @@ impl BindingAnnotation {
Self::MUT_REF_MUT => "mut ref mut ",
}
}
pub fn cap_ref_mutability(mut self, mutbl: Mutability) -> Self {
if let ByRef::Yes(old_mutbl) = &mut self.0 {
*old_mutbl = cmp::min(*old_mutbl, mutbl);
}
self
}
}
#[derive(Clone, Encodable, Decodable, Debug)]

View File

@ -907,8 +907,6 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
module: CachedModuleCodegen,
module_config: &ModuleConfig,
) -> WorkItemResult<B> {
assert!(module_config.emit_obj != EmitObj::None);
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
@ -928,12 +926,6 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
}
};
let object = load_from_incr_comp_dir(
cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name)),
module.source.saved_files.get("o").unwrap_or_else(|| {
cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
}),
);
let dwarf_object =
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
let dwarf_obj_out = cgcx
@ -955,9 +947,14 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
}
};
let should_emit_obj = module_config.emit_obj != EmitObj::None;
let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly);
let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly);
let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode);
let object = load_from_incr_cache(should_emit_obj, OutputType::Object);
if should_emit_obj && object.is_none() {
cgcx.create_dcx().emit_fatal(errors::NoSavedObjectFile { cgu_name: &module.name })
}
WorkItemResult::Finished(CompiledModule {
name: module.name,

View File

@ -575,6 +575,8 @@ declare_features! (
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(unstable, raw_ref_op, "1.41.0", Some(64490)),
/// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024.
(incomplete, ref_pat_eat_one_layer_2024, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
/// Allows using the `#[register_tool]` attribute.

View File

@ -14,7 +14,7 @@ fn def_path_hash_depends_on_crate_id() {
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).
create_session_globals_then(Edition::Edition2024, || {
create_session_globals_then(Edition::Edition2024, None, || {
let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");

View File

@ -80,6 +80,7 @@ struct TopInfo<'tcx> {
#[derive(Copy, Clone)]
struct PatInfo<'tcx, 'a> {
binding_mode: BindingAnnotation,
max_ref_mutbl: Mutability,
top_info: TopInfo<'tcx>,
decl_origin: Option<DeclOrigin<'a>>,
@ -161,8 +162,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
decl_origin: Option<DeclOrigin<'tcx>>,
) {
let info = TopInfo { expected, origin_expr, span };
let pat_info =
PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin, current_depth: 0 };
let pat_info = PatInfo {
binding_mode: INITIAL_BM,
max_ref_mutbl: Mutability::Mut,
top_info: info,
decl_origin,
current_depth: 0,
};
self.check_pat(pat, expected, pat_info);
}
@ -173,7 +179,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Conversely, inside this module, `check_pat_top` should never be used.
#[instrument(level = "debug", skip(self, pat_info))]
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
let PatInfo { binding_mode: def_bm, top_info: ti, current_depth, .. } = pat_info;
let PatInfo { binding_mode: def_bm, max_ref_mutbl, top_info: ti, current_depth, .. } =
pat_info;
let path_res = match &pat.kind {
PatKind::Path(qpath) => Some(
@ -182,10 +189,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => None,
};
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
let (expected, def_bm, ref_pattern_already_consumed) =
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) =
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl);
let pat_info = PatInfo {
binding_mode: def_bm,
max_ref_mutbl,
top_info: ti,
decl_origin: pat_info.decl_origin,
current_depth: current_depth + 1,
@ -290,16 +298,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
def_bm: BindingAnnotation,
adjust_mode: AdjustMode,
) -> (Ty<'tcx>, BindingAnnotation, bool) {
max_ref_mutbl: Mutability,
) -> (Ty<'tcx>, BindingAnnotation, Mutability, bool) {
if let ByRef::Yes(mutbl) = def_bm.0 {
debug_assert!(mutbl <= max_ref_mutbl);
}
match adjust_mode {
AdjustMode::Pass => (expected, def_bm, false),
AdjustMode::Reset => (expected, INITIAL_BM, false),
AdjustMode::ResetAndConsumeRef(mutbl) => {
(expected, INITIAL_BM, def_bm.0 == ByRef::Yes(mutbl))
AdjustMode::Pass => (expected, def_bm, max_ref_mutbl, false),
AdjustMode::Reset => (expected, INITIAL_BM, Mutability::Mut, false),
AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => {
let mutbls_match = def_bm.0 == ByRef::Yes(ref_pat_mutbl);
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
if mutbls_match {
debug!("consuming inherited reference");
(expected, INITIAL_BM, cmp::min(max_ref_mutbl, ref_pat_mutbl), true)
} else {
let (new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability::Mut {
self.peel_off_references(
pat,
expected,
def_bm,
Mutability::Not,
max_ref_mutbl,
)
} else {
(expected, def_bm.cap_ref_mutability(Mutability::Not), Mutability::Not)
};
(new_ty, new_bm, max_ref_mutbl, false)
}
} else {
(expected, INITIAL_BM, max_ref_mutbl, mutbls_match)
}
}
AdjustMode::Peel => {
let peeled = self.peel_off_references(pat, expected, def_bm);
(peeled.0, peeled.1, false)
let peeled =
self.peel_off_references(pat, expected, def_bm, Mutability::Mut, max_ref_mutbl);
(peeled.0, peeled.1, peeled.2, false)
}
}
}
@ -380,7 +414,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat: &'tcx Pat<'tcx>,
expected: Ty<'tcx>,
mut def_bm: BindingAnnotation,
) -> (Ty<'tcx>, BindingAnnotation) {
max_peelable_mutability: Mutability,
mut max_ref_mutability: Mutability,
) -> (Ty<'tcx>, BindingAnnotation, Mutability) {
let mut expected = self.try_structurally_resolve_type(pat.span, expected);
// Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
// for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@ -391,7 +427,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
//
// See the examples in `ui/match-defbm*.rs`.
let mut pat_adjustments = vec![];
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() {
while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
&& inner_mutability <= max_peelable_mutability
{
debug!("inspecting {:?}", expected);
debug!("current discriminant is Ref, inserting implicit deref");
@ -411,6 +449,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
}
if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
def_bm = def_bm.cap_ref_mutability(max_ref_mutability);
if def_bm.0 == ByRef::Yes(Mutability::Not) {
max_ref_mutability = Mutability::Not;
}
}
if !pat_adjustments.is_empty() {
debug!("default binding mode is now {:?}", def_bm);
self.typeck_results
@ -419,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.insert(pat.hir_id, pat_adjustments);
}
(expected, def_bm)
(expected, def_bm, max_ref_mutability)
}
fn check_pat_lit(
@ -1109,15 +1154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx, '_>,
) -> Ty<'tcx> {
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth } = pat_info;
let tcx = self.tcx;
let on_error = |e| {
for pat in subpats {
self.check_pat(
pat,
Ty::new_error(tcx, e),
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
);
self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
}
};
let report_unexpected_res = |res: Res| {
@ -1162,7 +1202,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
// Type-check the tuple struct pattern against the expected type.
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, ti);
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info);
let had_err = if let Some(err) = diag {
err.emit();
true
@ -1180,11 +1220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
let field = &variant.fields[FieldIdx::from_usize(i)];
let field_ty = self.field_ty(subpat.span, field, args);
self.check_pat(
subpat,
field_ty,
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
);
self.check_pat(subpat, field_ty, pat_info);
self.tcx.check_stability(
variant.fields[FieldIdx::from_usize(i)].did,
@ -2071,61 +2107,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pat_info: PatInfo<'tcx, '_>,
consumed_inherited_ref: bool,
) -> Ty<'tcx> {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
Ok(()) => {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
if consumed_inherited_ref
&& pat.span.at_least_rust_2024()
&& self.tcx.features().ref_pat_eat_one_layer_2024
{
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
self.check_pat(inner, expected, pat_info);
expected
} else {
let tcx = self.tcx;
let expected = self.shallow_resolve(expected);
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
Ok(()) => {
// `demand::subtype` would be good enough, but using `eqtype` turns
// out to be equally general. See (note_1) for details.
// Take region, inner-type from expected type if we can,
// to avoid creating needless variables. This also helps with
// the bad interactions of the given hack detailed in (note_1).
debug!("check_pat_ref: expected={:?}", expected);
match *expected.kind() {
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
_ => {
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
// We already matched against a match-ergonmics inserted reference,
// so we don't need to match against a reference from the original type.
// Save this infor for use in lowering later
self.typeck_results
.borrow_mut()
.skipped_ref_pats_mut()
.insert(pat.hir_id);
(expected, expected)
} else {
let inner_ty = self.next_ty_var(TypeVariableOrigin {
param_def_id: None,
span: inner.span,
});
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
let err = self.demand_eqtype_pat_diag(
pat.span,
expected,
ref_ty,
pat_info.top_info,
);
// Take region, inner-type from expected type if we can,
// to avoid creating needless variables. This also helps with
// the bad interactions of the given hack detailed in (note_1).
debug!("check_pat_ref: expected={:?}", expected);
match *expected.kind() {
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
_ => {
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
// We already matched against a match-ergonmics inserted reference,
// so we don't need to match against a reference from the original type.
// Save this infor for use in lowering later
self.typeck_results
.borrow_mut()
.skipped_ref_pats_mut()
.insert(pat.hir_id);
(expected, expected)
} else {
let inner_ty = self.next_ty_var(TypeVariableOrigin {
param_def_id: None,
span: inner.span,
});
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
let err = self.demand_eqtype_pat_diag(
pat.span,
expected,
ref_ty,
pat_info.top_info,
);
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
// Look for a case like `fn foo(&foo: u32)` and suggest
// `fn foo(foo: &u32)`
if let Some(mut err) = err {
self.borrow_pat_suggestion(&mut err, pat);
err.emit();
}
(ref_ty, inner_ty)
}
(ref_ty, inner_ty)
}
}
}
}
Err(guar) => {
let err = Ty::new_error(tcx, guar);
(err, err)
}
};
self.check_pat(inner, inner_ty, pat_info);
ref_ty
Err(guar) => {
let err = Ty::new_error(tcx, guar);
(err, err)
}
};
self.check_pat(inner, inner_ty, pat_info);
ref_ty
}
}
/// Create a reference type with a fresh region variable.

View File

@ -945,14 +945,27 @@ impl<'tcx> InferCtxt<'tcx> {
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
return Err((a_vid, b_vid));
}
// We don't silently want to constrain hidden types here, so we assert that either one side is
// an infer var, so it'll get constrained to whatever the other side is, or there are no opaque
// types involved.
// We don't expect this to actually get hit, but if it does, we now at least know how to write
// a test for it.
(_, ty::Infer(ty::TyVar(_))) => {}
(ty::Infer(ty::TyVar(_)), _) => {}
_ if (r_a, r_b).has_opaque_types() => {
span_bug!(
cause.span(),
"opaque types got hidden types registered from within subtype predicate: {r_a:?} vs {r_b:?}"
)
}
_ => {}
}
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
if a_is_expected {
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::No, a, b))
Ok(self.at(cause, param_env).sub(DefineOpaqueTypes::Yes, a, b))
} else {
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::No, b, a))
Ok(self.at(cause, param_env).sup(DefineOpaqueTypes::Yes, b, a))
}
})
}

View File

@ -5,6 +5,7 @@ use rustc_ast::{LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::jobserver;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::Lrc;
use rustc_errors::registry::Registry;
@ -21,7 +22,7 @@ use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileN
use rustc_session::filesearch::{self, sysroot_candidates};
use rustc_session::parse::ParseSess;
use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
use rustc_span::source_map::FileLoader;
use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs};
use rustc_span::symbol::sym;
use rustc_span::FileName;
use std::path::PathBuf;
@ -323,6 +324,18 @@ pub struct Config {
pub expanded_args: Vec<String>,
}
/// Initialize jobserver before getting `jobserver::client` and `build_session`.
pub(crate) fn initialize_checked_jobserver(early_dcx: &EarlyDiagCtxt) {
jobserver::initialize_checked(|err| {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
early_dcx
.early_struct_warn(err)
.with_note("the build environment is likely misconfigured")
.emit()
});
}
// JUSTIFICATION: before session exists, only config
#[allow(rustc::bad_opt_access)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
@ -334,20 +347,25 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
// Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
early_dcx.initialize_checked_jobserver();
initialize_checked_jobserver(&early_dcx);
crate::callbacks::setup_callbacks();
let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
let path_mapping = config.opts.file_path_mapping();
let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
util::run_in_thread_pool_with_globals(
config.opts.edition,
config.opts.unstable_opts.threads,
SourceMapInputs { file_loader, path_mapping, hash_kind },
|current_gcx| {
crate::callbacks::setup_callbacks();
// The previous `early_dcx` can't be reused here because it doesn't
// impl `Send`. Creating a new one is fine.
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
let codegen_backend = match config.make_codegen_backend {
None => util::get_codegen_backend(
&early_dcx,
@ -372,9 +390,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
config.opts.unstable_opts.translate_directionality_markers,
) {
Ok(bundle) => bundle,
Err(e) => {
early_dcx.early_fatal(format!("failed to load fluent bundle: {e}"));
}
Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
};
let mut locale_resources = Vec::from(config.locale_resources);
@ -393,7 +409,6 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
config.registry.clone(),
locale_resources,
config.lint_caps,
config.file_loader,
target,
sysroot,
util::rustc_version_str().unwrap_or("unknown"),
@ -440,45 +455,43 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
current_gcx,
};
rustc_span::set_source_map(compiler.sess.psess.clone_source_map(), move || {
// There are two paths out of `f`.
// - Normal exit.
// - Panic, e.g. triggered by `abort_if_errors`.
//
// We must run `finish_diagnostics` in both cases.
let res = {
// If `f` panics, `finish_diagnostics` will run during
// unwinding because of the `defer`.
let mut guar = None;
let sess_abort_guard = defer(|| {
guar = compiler.sess.finish_diagnostics(&config.registry);
});
// There are two paths out of `f`.
// - Normal exit.
// - Panic, e.g. triggered by `abort_if_errors`.
//
// We must run `finish_diagnostics` in both cases.
let res = {
// If `f` panics, `finish_diagnostics` will run during
// unwinding because of the `defer`.
let mut guar = None;
let sess_abort_guard = defer(|| {
guar = compiler.sess.finish_diagnostics(&config.registry);
});
let res = f(&compiler);
let res = f(&compiler);
// If `f` doesn't panic, `finish_diagnostics` will run
// normally when `sess_abort_guard` is dropped.
drop(sess_abort_guard);
// If `f` doesn't panic, `finish_diagnostics` will run
// normally when `sess_abort_guard` is dropped.
drop(sess_abort_guard);
// If `finish_diagnostics` emits errors (e.g. stashed
// errors) we can't return an error directly, because the
// return type of this function is `R`, not `Result<R, E>`.
// But we need to communicate the errors' existence to the
// caller, otherwise the caller might mistakenly think that
// no errors occurred and return a zero exit code. So we
// abort (panic) instead, similar to if `f` had panicked.
if guar.is_some() {
compiler.sess.dcx().abort_if_errors();
}
res
};
let prof = compiler.sess.prof.clone();
prof.generic_activity("drop_compiler").run(move || drop(compiler));
// If `finish_diagnostics` emits errors (e.g. stashed
// errors) we can't return an error directly, because the
// return type of this function is `R`, not `Result<R, E>`.
// But we need to communicate the errors' existence to the
// caller, otherwise the caller might mistakenly think that
// no errors occurred and return a zero exit code. So we
// abort (panic) instead, similar to if `f` had panicked.
if guar.is_some() {
compiler.sess.dcx().abort_if_errors();
}
res
})
};
let prof = compiler.sess.prof.clone();
prof.generic_activity("drop_compiler").run(move || drop(compiler));
res
},
)
}

View File

@ -1,5 +1,5 @@
#![allow(rustc::bad_opt_access)]
use crate::interface::parse_cfg;
use crate::interface::{initialize_checked_jobserver, parse_cfg};
use rustc_data_structures::profiling::TimePassesFormat;
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
use rustc_session::config::{
@ -16,6 +16,7 @@ use rustc_session::search_paths::SearchPath;
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
use rustc_span::symbol::sym;
use rustc_span::{FileName, SourceFileHashAlgorithm};
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
@ -25,42 +26,52 @@ use std::num::NonZero;
use std::path::{Path, PathBuf};
use std::sync::Arc;
fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
fn sess_and_cfg<F>(args: &[&'static str], f: F)
where
F: FnOnce(Session, Cfg),
{
let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
early_dcx.initialize_checked_jobserver();
initialize_checked_jobserver(&early_dcx);
let registry = registry::Registry::new(&[]);
let matches = optgroups().parse(args).unwrap();
let sessopts = build_session_options(&mut early_dcx, &matches);
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
output_dir: None,
output_file: None,
temps_dir,
};
let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target);
let sm_inputs = Some(SourceMapInputs {
file_loader: Box::new(RealFileLoader) as _,
path_mapping: sessopts.file_path_mapping(),
hash_kind,
});
let sess = build_session(
early_dcx,
sessopts,
io,
None,
registry,
vec![],
Default::default(),
None,
target,
sysroot,
"",
None,
Arc::default(),
Default::default(),
);
let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
(sess, cfg)
rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || {
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
let io = CompilerIO {
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
output_dir: None,
output_file: None,
temps_dir,
};
let sess = build_session(
early_dcx,
sessopts,
io,
None,
registry::Registry::new(&[]),
vec![],
Default::default(),
target,
sysroot,
"",
None,
Arc::default(),
Default::default(),
);
let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
let cfg = build_configuration(&sess, cfg);
f(sess, cfg)
});
}
fn new_public_extern_entry<S, I>(locations: I) -> ExternEntry
@ -125,21 +136,15 @@ fn assert_non_crate_hash_different(x: &Options, y: &Options) {
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, cfg);
sess_and_cfg(&["--test"], |_sess, cfg| {
assert!(cfg.contains(&(sym::test, None)));
});
})
}
// When the user supplies --test and --cfg test, don't implicitly add another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, cfg);
sess_and_cfg(&["--test", "--cfg=test"], |_sess, cfg| {
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
@ -148,22 +153,15 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
#[test]
fn test_can_print_warnings() {
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Awarnings"], |sess, _cfg| {
assert!(!sess.dcx().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches =
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Awarnings", "-Dwarnings"], |sess, _cfg| {
assert!(sess.dcx().can_emit_warnings());
});
rustc_span::create_default_session_globals_then(|| {
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
sess_and_cfg(&["-Adead_code"], |sess, _cfg| {
assert!(sess.dcx().can_emit_warnings());
});
}

View File

@ -14,6 +14,7 @@ use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
use rustc_session::{filesearch, Session};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::source_map::SourceMapInputs;
use rustc_span::symbol::sym;
use rustc_target::spec::Target;
use session::output::{categorize_crate_type, CRATE_TYPES};
@ -65,8 +66,9 @@ fn init_stack_size() -> usize {
})
}
pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
edition: Edition,
sm_inputs: SourceMapInputs,
f: F,
) -> R {
// The "thread pool" is a single spawned thread in the non-parallel
@ -84,7 +86,9 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: S
// name contains null bytes.
let r = builder
.spawn_scoped(s, move || {
rustc_span::create_session_globals_then(edition, || f(CurrentGcx::new()))
rustc_span::create_session_globals_then(edition, Some(sm_inputs), || {
f(CurrentGcx::new())
})
})
.unwrap()
.join();
@ -100,15 +104,17 @@ pub(crate) fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: S
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
edition: Edition,
_threads: usize,
sm_inputs: SourceMapInputs,
f: F,
) -> R {
run_in_thread_with_globals(edition, f)
run_in_thread_with_globals(edition, sm_inputs, f)
}
#[cfg(parallel_compiler)]
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
edition: Edition,
threads: usize,
sm_inputs: SourceMapInputs,
f: F,
) -> R {
use rustc_data_structures::{defer, jobserver, sync::FromDyn};
@ -120,7 +126,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
if !sync::is_dyn_thread_safe() {
return run_in_thread_with_globals(edition, |current_gcx| {
return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
// Register the thread for use with the `WorkerLocal` type.
registry.register();
@ -169,7 +175,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send,
// pool. Upon creation, each worker thread created gets a copy of the
// session globals in TLS. This is possible because `SessionGlobals` impls
// `Send` in the parallel compiler.
rustc_span::create_session_globals_then(edition, || {
rustc_span::create_session_globals_then(edition, Some(sm_inputs), || {
rustc_span::with_session_globals(|session_globals| {
let session_globals = FromDyn::from(session_globals);
builder

View File

@ -17,7 +17,7 @@
//! rustc_log::init_logger(rustc_log::LoggerConfig::from_env("LOG")).unwrap();
//!
//! let edition = rustc_span::edition::Edition::Edition2021;
//! rustc_span::create_session_globals_then(edition, || {
//! rustc_span::create_session_globals_then(edition, None, || {
//! /* ... */
//! });
//! }

View File

@ -47,12 +47,7 @@ macro_rules! declare_hooks {
impl Default for Providers {
fn default() -> Self {
Providers {
$($name: |_, $($arg,)*| bug!(
"`tcx.{}{:?}` cannot be called as `{}` was never assigned to a provider function.\n",
stringify!($name),
($($arg,)*),
stringify!($name),
),)*
$($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),*
}
}
}
@ -84,7 +79,6 @@ declare_hooks! {
/// via `mir_built`
hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
/// Imports all `SourceFile`s from the given crate into the current session.
/// This normally happens automatically when we decode a `Span` from
/// that crate's metadata - however, the incr comp cache needs
@ -109,3 +103,10 @@ declare_hooks! {
/// Create a list-like THIR representation for debugging.
hook thir_flat(key: LocalDefId) -> String;
}
#[cold]
fn default_hook(name: &str, args: &dyn std::fmt::Debug) -> ! {
bug!(
"`tcx.{name}{args:?}` cannot be called as `{name}` was never assigned to a provider function"
)
}

View File

@ -266,13 +266,7 @@ macro_rules! separate_provide_extern_default {
()
};
([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
|_, key| bug!(
"`tcx.{}({:?})` unsupported by its crate; \
perhaps the `{}` query was never assigned a provider function",
stringify!($name),
key,
stringify!($name),
)
|_, key| $crate::query::plumbing::default_extern_query(stringify!($name), &key)
};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
separate_provide_extern_default!([$($modifiers)*][$($args)*])
@ -462,15 +456,7 @@ macro_rules! define_callbacks {
impl Default for Providers {
fn default() -> Self {
Providers {
$($name: |_, key| bug!(
"`tcx.{}({:?})` is not supported for this key;\n\
hint: Queries can be either made to the local crate, or the external crate. \
This error means you tried to use it for one that's not supported.\n\
If that's not the case, {} was likely never assigned to a provider function.\n",
stringify!($name),
key,
stringify!($name),
),)*
$($name: |_, key| $crate::query::plumbing::default_query(stringify!($name), &key)),*
}
}
}
@ -661,3 +647,21 @@ use super::erase::EraseType;
#[derive(Copy, Clone, Debug, HashStable)]
pub struct CyclePlaceholder(pub ErrorGuaranteed);
#[cold]
pub(crate) fn default_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
bug!(
"`tcx.{name}({key:?})` is not supported for this key;\n\
hint: Queries can be either made to the local crate, or the external crate. \
This error means you tried to use it for one that's not supported.\n\
If that's not the case, {name} was likely never assigned to a provider function.\n",
)
}
#[cold]
pub(crate) fn default_extern_query(name: &str, key: &dyn std::fmt::Debug) -> ! {
bug!(
"`tcx.{name}({key:?})` unsupported by its crate; \
perhaps the `{name}` query was never assigned a provider function",
)
}

View File

@ -69,7 +69,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
hir::PatKind::Ref(inner, _)
if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
{
self.lower_pattern_unadjusted(inner)
self.lower_pattern(inner)
}
_ => self.lower_pattern_unadjusted(pat),
};

View File

@ -1125,7 +1125,7 @@ impl Options {
|| self.unstable_opts.query_dep_graph
}
pub(crate) fn file_path_mapping(&self) -> FilePathMapping {
pub fn file_path_mapping(&self) -> FilePathMapping {
file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
}
@ -1162,6 +1162,16 @@ impl UnstableOptions {
track_diagnostics: self.track_diagnostics,
}
}
pub fn src_hash_algorithm(&self, target: &Target) -> SourceFileHashAlgorithm {
self.src_hash_algorithm.unwrap_or_else(|| {
if target.is_like_msvc {
SourceFileHashAlgorithm::Sha256
} else {
SourceFileHashAlgorithm::Md5
}
})
}
}
// The type of entry function, so users can have their own entry functions

View File

@ -28,9 +28,9 @@ use rustc_errors::{
use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId;
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, FilePathMapping, RealFileLoader, SourceMap};
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::{FileNameDisplayPreference, RealFileName};
use rustc_span::{SourceFileHashAlgorithm, Span, Symbol};
use rustc_span::{Span, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{
@ -988,7 +988,6 @@ pub fn build_session(
registry: rustc_errors::registry::Registry,
fluent_resources: Vec<&'static str>,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target: Target,
sysroot: PathBuf,
cfg_version: &'static str,
@ -1015,24 +1014,11 @@ pub fn build_session(
early_dcx.early_warn(warning)
}
let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
let hash_kind = sopts.unstable_opts.src_hash_algorithm.unwrap_or_else(|| {
if target.is_like_msvc {
SourceFileHashAlgorithm::Sha256
} else {
SourceFileHashAlgorithm::Md5
}
});
let source_map = Lrc::new(SourceMap::with_file_loader_and_hash_kind(
loader,
sopts.file_path_mapping(),
hash_kind,
));
let fallback_bundle = fallback_fluent_bundle(
fluent_resources,
sopts.unstable_opts.translate_directionality_markers,
);
let source_map = rustc_span::source_map::get_source_map().unwrap();
let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
let mut dcx =
@ -1411,16 +1397,10 @@ impl EarlyDiagCtxt {
self.dcx.warn(msg)
}
pub fn initialize_checked_jobserver(&self) {
// initialize jobserver before getting `jobserver::client` and `build_session`.
jobserver::initialize_checked(|err| {
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
self.dcx
.struct_warn(err)
.with_note("the build environment is likely misconfigured")
.emit()
});
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
pub fn early_struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
self.dcx.struct_warn(msg)
}
}

View File

@ -49,7 +49,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
mod caching_source_map_view;
pub mod source_map;
pub use self::caching_source_map_view::CachingSourceMapView;
use source_map::SourceMap;
use source_map::{SourceMap, SourceMapInputs};
pub mod edition;
use edition::Edition;
@ -104,35 +104,35 @@ pub struct SessionGlobals {
metavar_spans: Lock<FxHashMap<Span, Span>>,
hygiene_data: Lock<hygiene::HygieneData>,
/// A reference to the source map in the `Session`. It's an `Option`
/// because it can't be initialized until `Session` is created, which
/// happens after `SessionGlobals`. `set_source_map` does the
/// initialization.
///
/// This field should only be used in places where the `Session` is truly
/// not available, such as `<Span as Debug>::fmt`.
source_map: Lock<Option<Lrc<SourceMap>>>,
/// The session's source map, if there is one. This field should only be
/// used in places where the `Session` is truly not available, such as
/// `<Span as Debug>::fmt`.
source_map: Option<Lrc<SourceMap>>,
}
impl SessionGlobals {
pub fn new(edition: Edition) -> SessionGlobals {
pub fn new(edition: Edition, sm_inputs: Option<SourceMapInputs>) -> SessionGlobals {
SessionGlobals {
symbol_interner: symbol::Interner::fresh(),
span_interner: Lock::new(span_encoding::SpanInterner::default()),
metavar_spans: Default::default(),
hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
source_map: Lock::new(None),
source_map: sm_inputs.map(|inputs| Lrc::new(SourceMap::with_inputs(inputs))),
}
}
}
pub fn create_session_globals_then<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
pub fn create_session_globals_then<R>(
edition: Edition,
sm_inputs: Option<SourceMapInputs>,
f: impl FnOnce() -> R,
) -> R {
assert!(
!SESSION_GLOBALS.is_set(),
"SESSION_GLOBALS should never be overwritten! \
Use another thread if you need another SessionGlobals"
);
let session_globals = SessionGlobals::new(edition);
let session_globals = SessionGlobals::new(edition, sm_inputs);
SESSION_GLOBALS.set(&session_globals, f)
}
@ -145,12 +145,13 @@ pub fn set_session_globals_then<R>(session_globals: &SessionGlobals, f: impl FnO
SESSION_GLOBALS.set(session_globals, f)
}
/// No source map.
pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
where
F: FnOnce(&SessionGlobals) -> R,
{
if !SESSION_GLOBALS.is_set() {
let session_globals = SessionGlobals::new(edition);
let session_globals = SessionGlobals::new(edition, None);
SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
} else {
SESSION_GLOBALS.with(f)
@ -164,8 +165,9 @@ where
SESSION_GLOBALS.with(f)
}
/// Default edition, no source map.
pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
create_session_globals_then(edition::DEFAULT_EDITION, f)
create_session_globals_then(edition::DEFAULT_EDITION, None, f)
}
// If this ever becomes non thread-local, `decode_syntax_context`
@ -1318,25 +1320,6 @@ impl<D: SpanDecoder> Decodable<D> for AttrId {
}
}
/// Insert `source_map` into the session globals for the duration of the
/// closure's execution.
pub fn set_source_map<T, F: FnOnce() -> T>(source_map: Lrc<SourceMap>, f: F) -> T {
with_session_globals(|session_globals| {
*session_globals.source_map.borrow_mut() = Some(source_map);
});
struct ClearSourceMap;
impl Drop for ClearSourceMap {
fn drop(&mut self) {
with_session_globals(|session_globals| {
session_globals.source_map.borrow_mut().take();
});
}
}
let _guard = ClearSourceMap;
f()
}
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Use the global `SourceMap` to print the span. If that's not
@ -1352,7 +1335,7 @@ impl fmt::Debug for Span {
if SESSION_GLOBALS.is_set() {
with_session_globals(|session_globals| {
if let Some(source_map) = &*session_globals.source_map.borrow() {
if let Some(source_map) = &session_globals.source_map {
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
} else {
fallback(*self, f)

View File

@ -167,9 +167,17 @@ struct SourceMapFiles {
stable_id_to_source_file: UnhashMap<StableSourceFileId, Lrc<SourceFile>>,
}
/// Used to construct a `SourceMap` with `SourceMap::with_inputs`.
pub struct SourceMapInputs {
pub file_loader: Box<dyn FileLoader + Send + Sync>,
pub path_mapping: FilePathMapping,
pub hash_kind: SourceFileHashAlgorithm,
}
pub struct SourceMap {
files: RwLock<SourceMapFiles>,
file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
// This is used to apply the file path remapping as specified via
// `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
path_mapping: FilePathMapping,
@ -180,17 +188,15 @@ pub struct SourceMap {
impl SourceMap {
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
Self::with_file_loader_and_hash_kind(
Box::new(RealFileLoader),
Self::with_inputs(SourceMapInputs {
file_loader: Box::new(RealFileLoader),
path_mapping,
SourceFileHashAlgorithm::Md5,
)
hash_kind: SourceFileHashAlgorithm::Md5,
})
}
pub fn with_file_loader_and_hash_kind(
file_loader: Box<dyn FileLoader + Sync + Send>,
path_mapping: FilePathMapping,
hash_kind: SourceFileHashAlgorithm,
pub fn with_inputs(
SourceMapInputs { file_loader, path_mapping, hash_kind }: SourceMapInputs,
) -> SourceMap {
SourceMap {
files: Default::default(),
@ -1054,6 +1060,10 @@ impl SourceMap {
}
}
pub fn get_source_map() -> Option<Lrc<SourceMap>> {
with_session_globals(|session_globals| session_globals.source_map.clone())
}
#[derive(Clone)]
pub struct FilePathMapping {
mapping: Vec<(PathBuf, PathBuf)>,

View File

@ -1462,6 +1462,7 @@ symbols! {
receiver,
recursion_limit,
reexport_test_harness_main,
ref_pat_eat_one_layer_2024,
ref_pat_everywhere,
ref_unwind_safe_trait,
reference,

View File

@ -1156,11 +1156,11 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
let is_iterating = self.start < self.end;
Some(if is_iterating {
// SAFETY: just checked precondition
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
let n = unsafe { Step::forward_unchecked(self.start, 1) };
mem::replace(&mut self.start, n)
} else {
self.exhausted = true;
self.start.clone()
self.start
})
}
@ -1179,7 +1179,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
while self.start < self.end {
// SAFETY: just checked precondition
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
let n = unsafe { Step::forward_unchecked(self.start, 1) };
let n = mem::replace(&mut self.start, n);
accum = f(accum, n)?;
}
@ -1187,7 +1187,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
self.exhausted = true;
if self.start == self.end {
accum = f(accum, self.start.clone())?;
accum = f(accum, self.start)?;
}
try { accum }
@ -1201,11 +1201,11 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
let is_iterating = self.start < self.end;
Some(if is_iterating {
// SAFETY: just checked precondition
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
let n = unsafe { Step::backward_unchecked(self.end, 1) };
mem::replace(&mut self.end, n)
} else {
self.exhausted = true;
self.end.clone()
self.end
})
}
@ -1224,7 +1224,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
while self.start < self.end {
// SAFETY: just checked precondition
let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) };
let n = unsafe { Step::backward_unchecked(self.end, 1) };
let n = mem::replace(&mut self.end, n);
accum = f(accum, n)?;
}
@ -1232,7 +1232,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
self.exhausted = true;
if self.start == self.end {
accum = f(accum, self.start.clone())?;
accum = f(accum, self.start)?;
}
try { accum }

View File

@ -0,0 +1,46 @@
//! The functions in this module are needed by libunwind. These symbols are named
//! in pre-link args for the target specification, so keep that in sync.
#![cfg(not(test))]
use crate::sys::sync::RwLock;
// Verify that the byte pattern libunwind uses to initialize an RwLock is
// equivalent to the value of RwLock::new(). If the value changes,
// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
const _: () = unsafe {
let bits_rust: usize = crate::mem::transmute(RwLock::new());
assert!(bits_rust == 0);
};
const EINVAL: i32 = 22;
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
// We cannot differentiate between reads an writes in unlock and therefore
// always use a write-lock. Unwinding isn't really in the hot path anyway.
unsafe { (*p).write() };
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
unsafe { (*p).write() };
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
unsafe { (*p).write_unlock() };
return 0;
}

View File

@ -17,6 +17,7 @@ pub mod fd;
pub mod fs;
#[path = "../unsupported/io.rs"]
pub mod io;
mod libunwind_integration;
pub mod net;
pub mod os;
#[path = "../unsupported/pipe.rs"]

View File

@ -52,10 +52,6 @@ impl<T> WaitVariable<T> {
WaitVariable { queue: WaitQueue::new(), lock: var }
}
pub fn queue_empty(&self) -> bool {
self.queue.is_empty()
}
pub fn lock_var(&self) -> &T {
&self.lock
}
@ -68,7 +64,7 @@ impl<T> WaitVariable<T> {
#[derive(Copy, Clone)]
pub enum NotifiedTcs {
Single(Tcs),
All { count: NonZero<usize> },
All { _count: NonZero<usize> },
}
/// An RAII guard that will notify a set of target threads as well as unlock
@ -98,19 +94,6 @@ impl Default for WaitQueue {
}
}
impl<'a, T> WaitGuard<'a, T> {
/// Returns which TCSes will be notified when this guard drops.
pub fn notified_tcs(&self) -> NotifiedTcs {
self.notified_tcs
}
/// Drop this `WaitGuard`, after dropping another `guard`.
pub fn drop_after<U>(self, guard: U) {
drop(guard);
drop(self);
}
}
impl<'a, T> Deref for WaitGuard<'a, T> {
type Target = SpinMutexGuard<'a, WaitVariable<T>>;
@ -141,10 +124,6 @@ impl WaitQueue {
WaitQueue { inner: UnsafeList::new() }
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
/// until a wakeup event.
///
@ -253,7 +232,10 @@ impl WaitQueue {
}
if let Some(count) = NonZero::new(count) {
Ok(WaitGuard { mutex_guard: Some(guard), notified_tcs: NotifiedTcs::All { count } })
Ok(WaitGuard {
mutex_guard: Some(guard),
notified_tcs: NotifiedTcs::All { _count: count },
})
} else {
Err(guard)
}

View File

@ -12,24 +12,20 @@ cfg_if::cfg_if! {
))] {
mod futex;
pub use futex::RwLock;
} else if #[cfg(target_family = "unix")] {
} else if #[cfg(any(
target_family = "unix",
all(target_os = "windows", target_vendor = "win7"),
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "xous",
))] {
mod queue;
pub use queue::RwLock;
} else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] {
mod windows7;
pub use windows7::RwLock;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use sgx::RwLock;
} else if #[cfg(target_os = "solid_asp3")] {
mod solid;
pub use solid::RwLock;
} else if #[cfg(target_os = "teeos")] {
mod teeos;
pub use teeos::RwLock;
} else if #[cfg(target_os = "xous")] {
mod xous;
pub use xous::RwLock;
} else {
mod no_threads;
pub use no_threads::RwLock;

View File

@ -1,219 +0,0 @@
#[cfg(test)]
mod tests;
use crate::alloc::Layout;
use crate::num::NonZero;
use crate::sys::pal::waitqueue::{
try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
};
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
struct AllocatedRwLock {
readers: SpinMutex<WaitVariable<Option<NonZero<usize>>>>,
writer: SpinMutex<WaitVariable<bool>>,
}
pub struct RwLock {
inner: LazyBox<AllocatedRwLock>,
}
impl LazyInit for AllocatedRwLock {
fn init() -> Box<Self> {
Box::new(AllocatedRwLock {
readers: SpinMutex::new(WaitVariable::new(None)),
writer: SpinMutex::new(WaitVariable::new(false)),
})
}
}
// Check at compile time that RwLock's size and alignment matches the C definition
// in libunwind (see also `test_c_rwlock_initializer` in `tests`).
const _: () = {
let rust = Layout::new::<RwLock>();
let c = Layout::new::<*mut ()>();
assert!(rust.size() == c.size());
assert!(rust.align() == c.align());
};
impl RwLock {
pub const fn new() -> RwLock {
RwLock { inner: LazyBox::new() }
}
#[inline]
pub fn read(&self) {
let lock = &*self.inner;
let mut rguard = lock.readers.lock();
let wguard = lock.writer.lock();
if *wguard.lock_var() || !wguard.queue_empty() {
// Another thread has or is waiting for the write lock, wait
drop(wguard);
WaitQueue::wait(rguard, || {});
// Another thread has passed the lock to us
} else {
// No waiting writers, acquire the read lock
*rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
}
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
let lock = &*self.inner;
let mut rguard = try_lock_or_false!(lock.readers);
let wguard = try_lock_or_false!(lock.writer);
if *wguard.lock_var() || !wguard.queue_empty() {
// Another thread has or is waiting for the write lock
false
} else {
// No waiting writers, acquire the read lock
*rguard.lock_var_mut() = NonZero::new(rguard.lock_var().map_or(0, |n| n.get()) + 1);
true
}
}
#[inline]
pub fn write(&self) {
let lock = &*self.inner;
let rguard = lock.readers.lock();
let mut wguard = lock.writer.lock();
if *wguard.lock_var() || rguard.lock_var().is_some() {
// Another thread has the lock, wait
drop(rguard);
WaitQueue::wait(wguard, || {});
// Another thread has passed the lock to us
} else {
// We are just now obtaining the lock
*wguard.lock_var_mut() = true;
}
}
#[inline]
pub fn try_write(&self) -> bool {
let lock = &*self.inner;
let rguard = try_lock_or_false!(lock.readers);
let mut wguard = try_lock_or_false!(lock.writer);
if *wguard.lock_var() || rguard.lock_var().is_some() {
// Another thread has the lock
false
} else {
// We are just now obtaining the lock
*wguard.lock_var_mut() = true;
true
}
}
#[inline]
unsafe fn __read_unlock(
&self,
mut rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
) {
*rguard.lock_var_mut() = NonZero::new(rguard.lock_var().unwrap().get() - 1);
if rguard.lock_var().is_some() {
// There are other active readers
} else {
if let Ok(mut wguard) = WaitQueue::notify_one(wguard) {
// A writer was waiting, pass the lock
*wguard.lock_var_mut() = true;
wguard.drop_after(rguard);
} else {
// No writers were waiting, the lock is released
rtassert!(rguard.queue_empty());
}
}
}
#[inline]
pub unsafe fn read_unlock(&self) {
let lock = &*self.inner;
let rguard = lock.readers.lock();
let wguard = lock.writer.lock();
unsafe { self.__read_unlock(rguard, wguard) };
}
#[inline]
unsafe fn __write_unlock(
&self,
rguard: SpinMutexGuard<'_, WaitVariable<Option<NonZero<usize>>>>,
wguard: SpinMutexGuard<'_, WaitVariable<bool>>,
) {
match WaitQueue::notify_one(wguard) {
Err(mut wguard) => {
// No writers waiting, release the write lock
*wguard.lock_var_mut() = false;
if let Ok(mut rguard) = WaitQueue::notify_all(rguard) {
// One or more readers were waiting, pass the lock to them
if let NotifiedTcs::All { count } = rguard.notified_tcs() {
*rguard.lock_var_mut() = Some(count)
} else {
unreachable!() // called notify_all
}
rguard.drop_after(wguard);
} else {
// No readers waiting, the lock is released
}
}
Ok(wguard) => {
// There was a thread waiting for write, just pass the lock
wguard.drop_after(rguard);
}
}
}
#[inline]
pub unsafe fn write_unlock(&self) {
let lock = &*self.inner;
let rguard = lock.readers.lock();
let wguard = lock.writer.lock();
unsafe { self.__write_unlock(rguard, wguard) };
}
// only used by __rust_rwlock_unlock below
#[inline]
#[cfg_attr(test, allow(dead_code))]
unsafe fn unlock(&self) {
let lock = &*self.inner;
let rguard = lock.readers.lock();
let wguard = lock.writer.lock();
if *wguard.lock_var() == true {
unsafe { self.__write_unlock(rguard, wguard) };
} else {
unsafe { self.__read_unlock(rguard, wguard) };
}
}
}
// The following functions are needed by libunwind. These symbols are named
// in pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
const EINVAL: i32 = 22;
#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
unsafe { (*p).read() };
return 0;
}
#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
unsafe { (*p).write() };
return 0;
}
#[cfg(not(test))]
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
if p.is_null() {
return EINVAL;
}
unsafe { (*p).unlock() };
return 0;
}

View File

@ -1,21 +0,0 @@
use super::*;
use crate::ptr;
// Verify that the byte pattern libunwind uses to initialize an RwLock is
// equivalent to the value of RwLock::new(). If the value changes,
// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
#[test]
fn test_c_rwlock_initializer() {
const C_RWLOCK_INIT: *mut () = ptr::null_mut();
// For the test to work, we need the padding/unused bytes in RwLock to be
// initialized as 0. In practice, this is the case with statics.
static RUST_RWLOCK_INIT: RwLock = RwLock::new();
unsafe {
// If the assertion fails, that not necessarily an issue with the value
// of C_RWLOCK_INIT. It might just be an issue with the way padding
// bytes are initialized in the test code.
assert_eq!(crate::mem::transmute_copy::<_, *mut ()>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
};
}

View File

@ -1,40 +0,0 @@
use crate::cell::UnsafeCell;
use crate::sys::c;
pub struct RwLock {
inner: UnsafeCell<c::SRWLOCK>,
}
unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {}
impl RwLock {
#[inline]
pub const fn new() -> RwLock {
RwLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) }
}
#[inline]
pub fn read(&self) {
unsafe { c::AcquireSRWLockShared(self.inner.get()) }
}
#[inline]
pub fn try_read(&self) -> bool {
unsafe { c::TryAcquireSRWLockShared(self.inner.get()) != 0 }
}
#[inline]
pub fn write(&self) {
unsafe { c::AcquireSRWLockExclusive(self.inner.get()) }
}
#[inline]
pub fn try_write(&self) -> bool {
unsafe { c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 }
}
#[inline]
pub unsafe fn read_unlock(&self) {
c::ReleaseSRWLockShared(self.inner.get())
}
#[inline]
pub unsafe fn write_unlock(&self) {
c::ReleaseSRWLockExclusive(self.inner.get())
}
}

View File

@ -1,74 +0,0 @@
use crate::sync::atomic::{AtomicIsize, Ordering::Acquire};
use crate::thread::yield_now;
pub struct RwLock {
/// The "mode" value indicates how many threads are waiting on this
/// Mutex. Possible values are:
/// -1: The lock is locked for writing
/// 0: The lock is unlocked
/// >=1: The lock is locked for reading
///
/// This currently spins waiting for the lock to be freed. An
/// optimization would be to involve the ticktimer server to
/// coordinate unlocks.
mode: AtomicIsize,
}
const RWLOCK_WRITING: isize = -1;
const RWLOCK_FREE: isize = 0;
unsafe impl Send for RwLock {}
unsafe impl Sync for RwLock {}
impl RwLock {
#[inline]
#[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
pub const fn new() -> RwLock {
RwLock { mode: AtomicIsize::new(RWLOCK_FREE) }
}
#[inline]
pub unsafe fn read(&self) {
while !unsafe { self.try_read() } {
yield_now();
}
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
self.mode
.fetch_update(
Acquire,
Acquire,
|v| if v == RWLOCK_WRITING { None } else { Some(v + 1) },
)
.is_ok()
}
#[inline]
pub unsafe fn write(&self) {
while !unsafe { self.try_write() } {
yield_now();
}
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
self.mode.compare_exchange(RWLOCK_FREE, RWLOCK_WRITING, Acquire, Acquire).is_ok()
}
#[inline]
pub unsafe fn read_unlock(&self) {
let previous = self.mode.fetch_sub(1, Acquire);
assert!(previous != RWLOCK_FREE);
assert!(previous != RWLOCK_WRITING);
}
#[inline]
pub unsafe fn write_unlock(&self) {
assert_eq!(
self.mode.compare_exchange(RWLOCK_WRITING, RWLOCK_FREE, Acquire, Acquire),
Ok(RWLOCK_WRITING)
);
}
}

View File

@ -38,7 +38,7 @@ pub fn check(
// of all `#[test]` attributes in not ignored code examples
fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
rustc_driver::catch_fatal_errors(|| {
rustc_span::create_session_globals_then(edition, || {
rustc_span::create_session_globals_then(edition, None, || {
let mut test_attr_spans = vec![];
let filename = FileName::anon_source_code(&code);

View File

@ -0,0 +1,6 @@
#![crate_name = "foo"]
#[inline(never)]
pub fn add(a: u32, b: u32) -> u32 {
a + b
}

View File

@ -0,0 +1,23 @@
// emitting an object file is not necessary if user didn't ask for one
//
// This test is similar to run-make/artifact-incr-cache but it doesn't
// require to emit an object file
//
// Fixes: rust-lang/rust#123234
extern crate run_make_support;
use run_make_support::{rustc, tmp_dir};
fn main() {
let inc_dir = tmp_dir();
for _ in 0..=1 {
rustc()
.input("lib.rs")
.crate_type("lib")
.emit("asm,dep-info,link,mir,llvm-ir,llvm-bc")
.incremental(&inc_dir)
.run();
}
}

View File

@ -0,0 +1,37 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
//~^ ERROR: mismatched types
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
}

View File

@ -0,0 +1,128 @@
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:5:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:10:23
|
LL | let _: &u32 = x;
| ---- ^ expected `&u32`, found integer
| |
| expected due to this
|
help: consider borrowing here
|
LL | let _: &u32 = &x;
| +
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:13:23
|
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - if let Some(Some(&&x)) = &Some(Some(&0)) {
LL + if let Some(Some(&x)) = &Some(Some(&0)) {
|
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:17:17
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&_`
|
= note: expected enum `Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:25:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:29:27
|
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/feature-gate-ref_pat_eat_one_layer_2024.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
| ~
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,37 @@
//@ edition: 2021
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
//~^ ERROR: mismatched types
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
//~^ ERROR: mismatched types
let _: u32 = x;
}
}

View File

@ -0,0 +1,128 @@
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:5:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:10:23
|
LL | let _: &u32 = x;
| ---- ^ expected `&u32`, found integer
| |
| expected due to this
|
help: consider borrowing here
|
LL | let _: &u32 = &x;
| +
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:13:23
|
LL | if let Some(Some(&&x)) = &Some(Some(&0)) {
| ^^ --------------- this expression has type `&Option<Option<&{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL - if let Some(Some(&&x)) = &Some(Some(&0)) {
LL + if let Some(Some(&x)) = &Some(Some(&0)) {
|
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:17:17
|
LL | if let Some(&Some(x)) = &Some(Some(0)) {
| ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&_`
|
= note: expected enum `Option<{integer}>`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/ref_pat_eat_one_layer_2021.rs:21:22
|
LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:25:22
|
LL | if let Some(Some(&x)) = &Some(&Some(0)) {
| ^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(Some(x)) = &Some(&Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:29:27
|
LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
| ^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&_`
|
= note: expected type `{integer}`
found reference `&_`
help: consider removing `&` from the pattern
|
LL | if let Some(&mut Some(x)) = &Some(&mut Some(0)) {
| ~
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
note: to declare a mutable binding use: `mut x`
--> $DIR/ref_pat_eat_one_layer_2021.rs:33:23
|
LL | if let Some(&Some(&mut x)) = &mut Some(&Some(0)) {
| ^^^^^^
help: consider removing `&mut` from the pattern
|
LL | if let Some(&Some(x)) = &mut Some(&Some(0)) {
| ~
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,65 @@
//@ run-pass
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(Some(&0)) {
let _: &u32 = x;
}
if let Some(Some(&&x)) = &Some(Some(&0)) {
let _: u32 = x;
}
if let Some(&Some(x)) = &Some(Some(0)) {
let _: u32 = x;
}
if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(&mut Some(&x)) = &Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(&Some(&x)) = &mut Some(&Some(0)) {
let _: u32 = x;
}
if let Some(&Some(x)) = &mut Some(&Some(0)) {
let _: &u32 = x;
}
if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) {
let _: &u32 = x;
}
if let Some(Some(&mut x)) = &Some(Some(&mut 0)) {
let _: &u32 = x;
}
if let &Some(Some(x)) = &Some(&mut Some(0)) {
let _: &u32 = x;
}
if let Some(&Some(&x)) = &Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(&Some(&x)) = &Some(&Some(0)) {
let _: u32 = x;
}
if let Some(&Some(&x)) = &Some(&mut Some(0)) {
let _: u32 = x;
}
if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
let _: u32 = x;
}
let &mut x = &&mut 0;
let _: &u32 = x;
let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0;
let _: &u32 = x;
let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &mut 0;
let _: &u32 = x;
}

View File

@ -0,0 +1,33 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(&mut Some(&_)) = &Some(&Some(0)) {
//~^ ERROR: mismatched types
}
if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
//~^ ERROR: mismatched types
}
if let Some(&Some(x)) = &mut Some(&Some(0)) {
let _: &mut u32 = x;
//~^ ERROR: mismatched types
}
if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
//~^ ERROR: mismatched types
}
if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
//~^ ERROR: mismatched types
}
if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
//~^ ERROR: mismatched types
}
let &mut _= &&0;
//~^ ERROR: mismatched types
let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
//~^ ERROR: mismatched types
}

View File

@ -0,0 +1,91 @@
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17
|
LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) {
| ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>`
| |
| expected `Option<{integer}>`, found `&mut _`
|
= note: expected enum `Option<{integer}>`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23
|
LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) {
| ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:14:27
|
LL | let _: &mut u32 = x;
| -------- ^ types differ in mutability
| |
| expected due to this
|
= note: expected mutable reference `&mut u32`
found reference `&{integer}`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23
|
LL | if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
| ^^ ------------------- this expression has type `Option<&Option<&mut {integer}>>`
| |
| types differ in mutability
|
= note: expected mutable reference `&mut {integer}`
found reference `&_`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:23
|
LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
| ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:29
|
LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
| ^^^^^^ ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:9
|
LL | let &mut _= &&0;
| ^^^^^^ --- this expression has type `&&{integer}`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
error[E0308]: mismatched types
--> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
|
LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
| ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
| |
| expected integer, found `&mut _`
|
= note: expected type `{integer}`
found mutable reference `&mut _`
error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,11 @@
//@ edition: 2024
//@ compile-flags: -Zunstable-options
#![allow(incomplete_features)]
#![feature(ref_pat_eat_one_layer_2024)]
pub fn main() {
if let Some(&Some(x)) = Some(&Some(&mut 0)) {
//~^ ERROR: cannot move out of a shared reference [E0507]
let _: &u32 = x;
}
}

View File

@ -0,0 +1,17 @@
error[E0507]: cannot move out of a shared reference
--> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:7:29
|
LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) {
| - ^^^^^^^^^^^^^^^^^^^
| |
| data moved here
| move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait
|
help: consider borrowing the pattern binding
|
LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
| +++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0507`.