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:
commit
1cec373f65
@ -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)]
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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()], "");
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -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
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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, || {
|
||||
//! /* ... */
|
||||
//! });
|
||||
//! }
|
||||
|
@ -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"
|
||||
)
|
||||
}
|
||||
|
@ -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",
|
||||
)
|
||||
}
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)>,
|
||||
|
@ -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,
|
||||
|
@ -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 }
|
||||
|
46
library/std/src/sys/pal/sgx/libunwind_integration.rs
Normal file
46
library/std/src/sys/pal/sgx/libunwind_integration.rs
Normal 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;
|
||||
}
|
@ -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"]
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
};
|
||||
}
|
@ -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())
|
||||
}
|
||||
}
|
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
|
6
tests/run-make/artifact-incr-cache-no-obj/lib.rs
Normal file
6
tests/run-make/artifact-incr-cache-no-obj/lib.rs
Normal file
@ -0,0 +1,6 @@
|
||||
#![crate_name = "foo"]
|
||||
|
||||
#[inline(never)]
|
||||
pub fn add(a: u32, b: u32) -> u32 {
|
||||
a + b
|
||||
}
|
23
tests/run-make/artifact-incr-cache-no-obj/rmake.rs
Normal file
23
tests/run-make/artifact-incr-cache-no-obj/rmake.rs
Normal 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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;
|
||||
}
|
||||
}
|
@ -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`.
|
@ -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;
|
||||
}
|
@ -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
|
||||
}
|
@ -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`.
|
@ -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;
|
||||
}
|
||||
}
|
@ -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`.
|
Loading…
x
Reference in New Issue
Block a user