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
39 changed files with 998 additions and 680 deletions
|
@ -36,6 +36,7 @@ use rustc_macros::HashStable_Generic;
|
||||||
use rustc_span::source_map::{respan, Spanned};
|
use rustc_span::source_map::{respan, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
|
||||||
|
use std::cmp;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use thin_vec::{thin_vec, ThinVec};
|
use thin_vec::{thin_vec, ThinVec};
|
||||||
|
@ -731,6 +732,13 @@ impl BindingAnnotation {
|
||||||
Self::MUT_REF_MUT => "mut ref mut ",
|
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)]
|
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||||
|
|
|
@ -907,8 +907,6 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
||||||
module: CachedModuleCodegen,
|
module: CachedModuleCodegen,
|
||||||
module_config: &ModuleConfig,
|
module_config: &ModuleConfig,
|
||||||
) -> WorkItemResult<B> {
|
) -> WorkItemResult<B> {
|
||||||
assert!(module_config.emit_obj != EmitObj::None);
|
|
||||||
|
|
||||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
|
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| {
|
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 =
|
let dwarf_object =
|
||||||
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
|
module.source.saved_files.get("dwo").as_ref().and_then(|saved_dwarf_object_file| {
|
||||||
let dwarf_obj_out = cgcx
|
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 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 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 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 {
|
WorkItemResult::Finished(CompiledModule {
|
||||||
name: module.name,
|
name: module.name,
|
||||||
|
|
|
@ -575,6 +575,8 @@ declare_features! (
|
||||||
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
(unstable, proc_macro_hygiene, "1.30.0", Some(54727)),
|
||||||
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
|
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
|
||||||
(unstable, raw_ref_op, "1.41.0", Some(64490)),
|
(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.
|
/// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references.
|
||||||
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
|
(incomplete, ref_pat_everywhere, "CURRENT_RUSTC_VERSION", Some(123076)),
|
||||||
/// Allows using the `#[register_tool]` attribute.
|
/// 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
|
// the crate by changing the crate disambiguator (e.g. via bumping the
|
||||||
// crate's version number).
|
// 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 id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
|
||||||
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");
|
let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct TopInfo<'tcx> {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
struct PatInfo<'tcx, 'a> {
|
struct PatInfo<'tcx, 'a> {
|
||||||
binding_mode: BindingAnnotation,
|
binding_mode: BindingAnnotation,
|
||||||
|
max_ref_mutbl: Mutability,
|
||||||
top_info: TopInfo<'tcx>,
|
top_info: TopInfo<'tcx>,
|
||||||
decl_origin: Option<DeclOrigin<'a>>,
|
decl_origin: Option<DeclOrigin<'a>>,
|
||||||
|
|
||||||
|
@ -161,8 +162,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
decl_origin: Option<DeclOrigin<'tcx>>,
|
decl_origin: Option<DeclOrigin<'tcx>>,
|
||||||
) {
|
) {
|
||||||
let info = TopInfo { expected, origin_expr, span };
|
let info = TopInfo { expected, origin_expr, span };
|
||||||
let pat_info =
|
let pat_info = PatInfo {
|
||||||
PatInfo { binding_mode: INITIAL_BM, top_info: info, decl_origin, current_depth: 0 };
|
binding_mode: INITIAL_BM,
|
||||||
|
max_ref_mutbl: Mutability::Mut,
|
||||||
|
top_info: info,
|
||||||
|
decl_origin,
|
||||||
|
current_depth: 0,
|
||||||
|
};
|
||||||
self.check_pat(pat, expected, pat_info);
|
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.
|
/// Conversely, inside this module, `check_pat_top` should never be used.
|
||||||
#[instrument(level = "debug", skip(self, pat_info))]
|
#[instrument(level = "debug", skip(self, pat_info))]
|
||||||
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
|
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 {
|
let path_res = match &pat.kind {
|
||||||
PatKind::Path(qpath) => Some(
|
PatKind::Path(qpath) => Some(
|
||||||
|
@ -182,10 +189,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
|
||||||
let (expected, def_bm, ref_pattern_already_consumed) =
|
let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) =
|
||||||
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode);
|
self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl);
|
||||||
let pat_info = PatInfo {
|
let pat_info = PatInfo {
|
||||||
binding_mode: def_bm,
|
binding_mode: def_bm,
|
||||||
|
max_ref_mutbl,
|
||||||
top_info: ti,
|
top_info: ti,
|
||||||
decl_origin: pat_info.decl_origin,
|
decl_origin: pat_info.decl_origin,
|
||||||
current_depth: current_depth + 1,
|
current_depth: current_depth + 1,
|
||||||
|
@ -290,16 +298,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
def_bm: BindingAnnotation,
|
def_bm: BindingAnnotation,
|
||||||
adjust_mode: AdjustMode,
|
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 {
|
match adjust_mode {
|
||||||
AdjustMode::Pass => (expected, def_bm, false),
|
AdjustMode::Pass => (expected, def_bm, max_ref_mutbl, false),
|
||||||
AdjustMode::Reset => (expected, INITIAL_BM, false),
|
AdjustMode::Reset => (expected, INITIAL_BM, Mutability::Mut, false),
|
||||||
AdjustMode::ResetAndConsumeRef(mutbl) => {
|
AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => {
|
||||||
(expected, INITIAL_BM, def_bm.0 == ByRef::Yes(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 => {
|
AdjustMode::Peel => {
|
||||||
let peeled = self.peel_off_references(pat, expected, def_bm);
|
let peeled =
|
||||||
(peeled.0, peeled.1, false)
|
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>,
|
pat: &'tcx Pat<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
mut def_bm: BindingAnnotation,
|
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);
|
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,
|
// 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
|
// 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`.
|
// See the examples in `ui/match-defbm*.rs`.
|
||||||
let mut pat_adjustments = vec![];
|
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!("inspecting {:?}", expected);
|
||||||
|
|
||||||
debug!("current discriminant is Ref, inserting implicit deref");
|
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() {
|
if !pat_adjustments.is_empty() {
|
||||||
debug!("default binding mode is now {:?}", def_bm);
|
debug!("default binding mode is now {:?}", def_bm);
|
||||||
self.typeck_results
|
self.typeck_results
|
||||||
|
@ -419,7 +464,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.insert(pat.hir_id, pat_adjustments);
|
.insert(pat.hir_id, pat_adjustments);
|
||||||
}
|
}
|
||||||
|
|
||||||
(expected, def_bm)
|
(expected, def_bm, max_ref_mutability)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_pat_lit(
|
fn check_pat_lit(
|
||||||
|
@ -1109,15 +1154,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth } = pat_info;
|
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
let on_error = |e| {
|
let on_error = |e| {
|
||||||
for pat in subpats {
|
for pat in subpats {
|
||||||
self.check_pat(
|
self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
|
||||||
pat,
|
|
||||||
Ty::new_error(tcx, e),
|
|
||||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let report_unexpected_res = |res: Res| {
|
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");
|
let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
|
||||||
|
|
||||||
// Type-check the tuple struct pattern against the expected 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 {
|
let had_err = if let Some(err) = diag {
|
||||||
err.emit();
|
err.emit();
|
||||||
true
|
true
|
||||||
|
@ -1180,11 +1220,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
|
||||||
let field = &variant.fields[FieldIdx::from_usize(i)];
|
let field = &variant.fields[FieldIdx::from_usize(i)];
|
||||||
let field_ty = self.field_ty(subpat.span, field, args);
|
let field_ty = self.field_ty(subpat.span, field, args);
|
||||||
self.check_pat(
|
self.check_pat(subpat, field_ty, pat_info);
|
||||||
subpat,
|
|
||||||
field_ty,
|
|
||||||
PatInfo { binding_mode: def_bm, top_info: ti, decl_origin, current_depth },
|
|
||||||
);
|
|
||||||
|
|
||||||
self.tcx.check_stability(
|
self.tcx.check_stability(
|
||||||
variant.fields[FieldIdx::from_usize(i)].did,
|
variant.fields[FieldIdx::from_usize(i)].did,
|
||||||
|
@ -2071,61 +2107,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
pat_info: PatInfo<'tcx, '_>,
|
pat_info: PatInfo<'tcx, '_>,
|
||||||
consumed_inherited_ref: bool,
|
consumed_inherited_ref: bool,
|
||||||
) -> Ty<'tcx> {
|
) -> Ty<'tcx> {
|
||||||
let tcx = self.tcx;
|
if consumed_inherited_ref
|
||||||
let expected = self.shallow_resolve(expected);
|
&& pat.span.at_least_rust_2024()
|
||||||
let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
|
&& self.tcx.features().ref_pat_eat_one_layer_2024
|
||||||
Ok(()) => {
|
{
|
||||||
// `demand::subtype` would be good enough, but using `eqtype` turns
|
self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
|
||||||
// out to be equally general. See (note_1) for details.
|
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,
|
// Take region, inner-type from expected type if we can,
|
||||||
// to avoid creating needless variables. This also helps with
|
// to avoid creating needless variables. This also helps with
|
||||||
// the bad interactions of the given hack detailed in (note_1).
|
// the bad interactions of the given hack detailed in (note_1).
|
||||||
debug!("check_pat_ref: expected={:?}", expected);
|
debug!("check_pat_ref: expected={:?}", expected);
|
||||||
match *expected.kind() {
|
match *expected.kind() {
|
||||||
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
|
ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
|
||||||
_ => {
|
_ => {
|
||||||
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
|
if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
|
||||||
// We already matched against a match-ergonmics inserted reference,
|
// We already matched against a match-ergonmics inserted reference,
|
||||||
// so we don't need to match against a reference from the original type.
|
// so we don't need to match against a reference from the original type.
|
||||||
// Save this infor for use in lowering later
|
// Save this infor for use in lowering later
|
||||||
self.typeck_results
|
self.typeck_results
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.skipped_ref_pats_mut()
|
.skipped_ref_pats_mut()
|
||||||
.insert(pat.hir_id);
|
.insert(pat.hir_id);
|
||||||
(expected, expected)
|
(expected, expected)
|
||||||
} else {
|
} else {
|
||||||
let inner_ty = self.next_ty_var(TypeVariableOrigin {
|
let inner_ty = self.next_ty_var(TypeVariableOrigin {
|
||||||
param_def_id: None,
|
param_def_id: None,
|
||||||
span: inner.span,
|
span: inner.span,
|
||||||
});
|
});
|
||||||
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
|
||||||
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
|
||||||
let err = self.demand_eqtype_pat_diag(
|
let err = self.demand_eqtype_pat_diag(
|
||||||
pat.span,
|
pat.span,
|
||||||
expected,
|
expected,
|
||||||
ref_ty,
|
ref_ty,
|
||||||
pat_info.top_info,
|
pat_info.top_info,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Look for a case like `fn foo(&foo: u32)` and suggest
|
// Look for a case like `fn foo(&foo: u32)` and suggest
|
||||||
// `fn foo(foo: &u32)`
|
// `fn foo(foo: &u32)`
|
||||||
if let Some(mut err) = err {
|
if let Some(mut err) = err {
|
||||||
self.borrow_pat_suggestion(&mut err, pat);
|
self.borrow_pat_suggestion(&mut err, pat);
|
||||||
err.emit();
|
err.emit();
|
||||||
|
}
|
||||||
|
(ref_ty, inner_ty)
|
||||||
}
|
}
|
||||||
(ref_ty, inner_ty)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
Err(guar) => {
|
||||||
Err(guar) => {
|
let err = Ty::new_error(tcx, guar);
|
||||||
let err = Ty::new_error(tcx, guar);
|
(err, err)
|
||||||
(err, err)
|
}
|
||||||
}
|
};
|
||||||
};
|
self.check_pat(inner, inner_ty, pat_info);
|
||||||
self.check_pat(inner, inner_ty, pat_info);
|
ref_ty
|
||||||
ref_ty
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a reference type with a fresh region variable.
|
/// 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))) => {
|
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
|
||||||
return Err((a_vid, 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 }| {
|
self.enter_forall(predicate, |ty::SubtypePredicate { a_is_expected, a, b }| {
|
||||||
if a_is_expected {
|
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 {
|
} 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_codegen_ssa::traits::CodegenBackend;
|
||||||
use rustc_data_structures::defer;
|
use rustc_data_structures::defer;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
use rustc_data_structures::jobserver;
|
||||||
use rustc_data_structures::stable_hasher::StableHasher;
|
use rustc_data_structures::stable_hasher::StableHasher;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_errors::registry::Registry;
|
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::filesearch::{self, sysroot_candidates};
|
||||||
use rustc_session::parse::ParseSess;
|
use rustc_session::parse::ParseSess;
|
||||||
use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
|
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::symbol::sym;
|
||||||
use rustc_span::FileName;
|
use rustc_span::FileName;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -323,6 +324,18 @@ pub struct Config {
|
||||||
pub expanded_args: Vec<String>,
|
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
|
// JUSTIFICATION: before session exists, only config
|
||||||
#[allow(rustc::bad_opt_access)]
|
#[allow(rustc::bad_opt_access)]
|
||||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
#[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
|
// Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
|
||||||
let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
|
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(
|
util::run_in_thread_pool_with_globals(
|
||||||
config.opts.edition,
|
config.opts.edition,
|
||||||
config.opts.unstable_opts.threads,
|
config.opts.unstable_opts.threads,
|
||||||
|
SourceMapInputs { file_loader, path_mapping, hash_kind },
|
||||||
|current_gcx| {
|
|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 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 {
|
let codegen_backend = match config.make_codegen_backend {
|
||||||
None => util::get_codegen_backend(
|
None => util::get_codegen_backend(
|
||||||
&early_dcx,
|
&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,
|
config.opts.unstable_opts.translate_directionality_markers,
|
||||||
) {
|
) {
|
||||||
Ok(bundle) => bundle,
|
Ok(bundle) => bundle,
|
||||||
Err(e) => {
|
Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")),
|
||||||
early_dcx.early_fatal(format!("failed to load fluent bundle: {e}"));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut locale_resources = Vec::from(config.locale_resources);
|
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(),
|
config.registry.clone(),
|
||||||
locale_resources,
|
locale_resources,
|
||||||
config.lint_caps,
|
config.lint_caps,
|
||||||
config.file_loader,
|
|
||||||
target,
|
target,
|
||||||
sysroot,
|
sysroot,
|
||||||
util::rustc_version_str().unwrap_or("unknown"),
|
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,
|
current_gcx,
|
||||||
};
|
};
|
||||||
|
|
||||||
rustc_span::set_source_map(compiler.sess.psess.clone_source_map(), move || {
|
// There are two paths out of `f`.
|
||||||
// There are two paths out of `f`.
|
// - Normal exit.
|
||||||
// - Normal exit.
|
// - Panic, e.g. triggered by `abort_if_errors`.
|
||||||
// - Panic, e.g. triggered by `abort_if_errors`.
|
//
|
||||||
//
|
// We must run `finish_diagnostics` in both cases.
|
||||||
// We must run `finish_diagnostics` in both cases.
|
let res = {
|
||||||
let res = {
|
// If `f` panics, `finish_diagnostics` will run during
|
||||||
// If `f` panics, `finish_diagnostics` will run during
|
// unwinding because of the `defer`.
|
||||||
// unwinding because of the `defer`.
|
let mut guar = None;
|
||||||
let mut guar = None;
|
let sess_abort_guard = defer(|| {
|
||||||
let sess_abort_guard = defer(|| {
|
guar = compiler.sess.finish_diagnostics(&config.registry);
|
||||||
guar = compiler.sess.finish_diagnostics(&config.registry);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
let res = f(&compiler);
|
let res = f(&compiler);
|
||||||
|
|
||||||
// If `f` doesn't panic, `finish_diagnostics` will run
|
// If `f` doesn't panic, `finish_diagnostics` will run
|
||||||
// normally when `sess_abort_guard` is dropped.
|
// normally when `sess_abort_guard` is dropped.
|
||||||
drop(sess_abort_guard);
|
drop(sess_abort_guard);
|
||||||
|
|
||||||
// If `finish_diagnostics` emits errors (e.g. stashed
|
// If `finish_diagnostics` emits errors (e.g. stashed
|
||||||
// errors) we can't return an error directly, because the
|
// errors) we can't return an error directly, because the
|
||||||
// return type of this function is `R`, not `Result<R, E>`.
|
// return type of this function is `R`, not `Result<R, E>`.
|
||||||
// But we need to communicate the errors' existence to the
|
// But we need to communicate the errors' existence to the
|
||||||
// caller, otherwise the caller might mistakenly think that
|
// caller, otherwise the caller might mistakenly think that
|
||||||
// no errors occurred and return a zero exit code. So we
|
// no errors occurred and return a zero exit code. So we
|
||||||
// abort (panic) instead, similar to if `f` had panicked.
|
// abort (panic) instead, similar to if `f` had panicked.
|
||||||
if guar.is_some() {
|
if guar.is_some() {
|
||||||
compiler.sess.dcx().abort_if_errors();
|
compiler.sess.dcx().abort_if_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
|
||||||
};
|
|
||||||
|
|
||||||
let prof = compiler.sess.prof.clone();
|
|
||||||
prof.generic_activity("drop_compiler").run(move || drop(compiler));
|
|
||||||
|
|
||||||
res
|
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)]
|
#![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_data_structures::profiling::TimePassesFormat;
|
||||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
|
@ -16,6 +16,7 @@ use rustc_session::search_paths::SearchPath;
|
||||||
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
|
||||||
use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session};
|
use rustc_session::{build_session, filesearch, getopts, CompilerIO, EarlyDiagCtxt, Session};
|
||||||
use rustc_span::edition::{Edition, DEFAULT_EDITION};
|
use rustc_span::edition::{Edition, DEFAULT_EDITION};
|
||||||
|
use rustc_span::source_map::{RealFileLoader, SourceMapInputs};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{FileName, SourceFileHashAlgorithm};
|
use rustc_span::{FileName, SourceFileHashAlgorithm};
|
||||||
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
|
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, RelocModel};
|
||||||
|
@ -25,42 +26,52 @@ use std::num::NonZero;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
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());
|
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 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 sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
|
||||||
|
|
||||||
let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
|
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(
|
rustc_span::create_session_globals_then(DEFAULT_EDITION, sm_inputs, || {
|
||||||
early_dcx,
|
let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
|
||||||
sessopts,
|
let io = CompilerIO {
|
||||||
io,
|
input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
|
||||||
None,
|
output_dir: None,
|
||||||
registry,
|
output_file: None,
|
||||||
vec![],
|
temps_dir,
|
||||||
Default::default(),
|
};
|
||||||
None,
|
|
||||||
target,
|
let sess = build_session(
|
||||||
sysroot,
|
early_dcx,
|
||||||
"",
|
sessopts,
|
||||||
None,
|
io,
|
||||||
Arc::default(),
|
None,
|
||||||
Default::default(),
|
registry::Registry::new(&[]),
|
||||||
);
|
vec![],
|
||||||
let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
|
Default::default(),
|
||||||
(sess, cfg)
|
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
|
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
|
// When the user supplies --test we should implicitly supply --cfg test
|
||||||
#[test]
|
#[test]
|
||||||
fn test_switch_implies_cfg_test() {
|
fn test_switch_implies_cfg_test() {
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
sess_and_cfg(&["--test"], |_sess, cfg| {
|
||||||
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
|
|
||||||
let (sess, cfg) = mk_session(matches);
|
|
||||||
let cfg = build_configuration(&sess, cfg);
|
|
||||||
assert!(cfg.contains(&(sym::test, None)));
|
assert!(cfg.contains(&(sym::test, None)));
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the user supplies --test and --cfg test, don't implicitly add another --cfg test
|
// When the user supplies --test and --cfg test, don't implicitly add another --cfg test
|
||||||
#[test]
|
#[test]
|
||||||
fn test_switch_implies_cfg_test_unless_cfg_test() {
|
fn test_switch_implies_cfg_test_unless_cfg_test() {
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
sess_and_cfg(&["--test", "--cfg=test"], |_sess, cfg| {
|
||||||
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
|
|
||||||
let (sess, cfg) = mk_session(matches);
|
|
||||||
let cfg = build_configuration(&sess, cfg);
|
|
||||||
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
|
let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test);
|
||||||
assert!(test_items.next().is_some());
|
assert!(test_items.next().is_some());
|
||||||
assert!(test_items.next().is_none());
|
assert!(test_items.next().is_none());
|
||||||
|
@ -148,22 +153,15 @@ fn test_switch_implies_cfg_test_unless_cfg_test() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_can_print_warnings() {
|
fn test_can_print_warnings() {
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
sess_and_cfg(&["-Awarnings"], |sess, _cfg| {
|
||||||
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
|
|
||||||
let (sess, _) = mk_session(matches);
|
|
||||||
assert!(!sess.dcx().can_emit_warnings());
|
assert!(!sess.dcx().can_emit_warnings());
|
||||||
});
|
});
|
||||||
|
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
sess_and_cfg(&["-Awarnings", "-Dwarnings"], |sess, _cfg| {
|
||||||
let matches =
|
|
||||||
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
|
|
||||||
let (sess, _) = mk_session(matches);
|
|
||||||
assert!(sess.dcx().can_emit_warnings());
|
assert!(sess.dcx().can_emit_warnings());
|
||||||
});
|
});
|
||||||
|
|
||||||
rustc_span::create_default_session_globals_then(|| {
|
sess_and_cfg(&["-Adead_code"], |sess, _cfg| {
|
||||||
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
|
|
||||||
let (sess, _) = mk_session(matches);
|
|
||||||
assert!(sess.dcx().can_emit_warnings());
|
assert!(sess.dcx().can_emit_warnings());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
|
||||||
use rustc_session::{filesearch, Session};
|
use rustc_session::{filesearch, Session};
|
||||||
use rustc_span::edit_distance::find_best_match_for_name;
|
use rustc_span::edit_distance::find_best_match_for_name;
|
||||||
use rustc_span::edition::Edition;
|
use rustc_span::edition::Edition;
|
||||||
|
use rustc_span::source_map::SourceMapInputs;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_target::spec::Target;
|
use rustc_target::spec::Target;
|
||||||
use session::output::{categorize_crate_type, CRATE_TYPES};
|
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,
|
edition: Edition,
|
||||||
|
sm_inputs: SourceMapInputs,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R {
|
) -> R {
|
||||||
// The "thread pool" is a single spawned thread in the non-parallel
|
// 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.
|
// name contains null bytes.
|
||||||
let r = builder
|
let r = builder
|
||||||
.spawn_scoped(s, move || {
|
.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()
|
.unwrap()
|
||||||
.join();
|
.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>(
|
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
_threads: usize,
|
_threads: usize,
|
||||||
|
sm_inputs: SourceMapInputs,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R {
|
) -> R {
|
||||||
run_in_thread_with_globals(edition, f)
|
run_in_thread_with_globals(edition, sm_inputs, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(parallel_compiler)]
|
#[cfg(parallel_compiler)]
|
||||||
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
|
||||||
edition: Edition,
|
edition: Edition,
|
||||||
threads: usize,
|
threads: usize,
|
||||||
|
sm_inputs: SourceMapInputs,
|
||||||
f: F,
|
f: F,
|
||||||
) -> R {
|
) -> R {
|
||||||
use rustc_data_structures::{defer, jobserver, sync::FromDyn};
|
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());
|
let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
|
||||||
|
|
||||||
if !sync::is_dyn_thread_safe() {
|
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.
|
// Register the thread for use with the `WorkerLocal` type.
|
||||||
registry.register();
|
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
|
// pool. Upon creation, each worker thread created gets a copy of the
|
||||||
// session globals in TLS. This is possible because `SessionGlobals` impls
|
// session globals in TLS. This is possible because `SessionGlobals` impls
|
||||||
// `Send` in the parallel compiler.
|
// `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| {
|
rustc_span::with_session_globals(|session_globals| {
|
||||||
let session_globals = FromDyn::from(session_globals);
|
let session_globals = FromDyn::from(session_globals);
|
||||||
builder
|
builder
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
//! rustc_log::init_logger(rustc_log::LoggerConfig::from_env("LOG")).unwrap();
|
//! rustc_log::init_logger(rustc_log::LoggerConfig::from_env("LOG")).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let edition = rustc_span::edition::Edition::Edition2021;
|
//! 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 {
|
impl Default for Providers {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Providers {
|
Providers {
|
||||||
$($name: |_, $($arg,)*| bug!(
|
$($name: |_, $($arg,)*| default_hook(stringify!($name), &($($arg,)*))),*
|
||||||
"`tcx.{}{:?}` cannot be called as `{}` was never assigned to a provider function.\n",
|
|
||||||
stringify!($name),
|
|
||||||
($($arg,)*),
|
|
||||||
stringify!($name),
|
|
||||||
),)*
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +79,6 @@ declare_hooks! {
|
||||||
/// via `mir_built`
|
/// via `mir_built`
|
||||||
hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
|
hook build_mir(key: LocalDefId) -> mir::Body<'tcx>;
|
||||||
|
|
||||||
|
|
||||||
/// Imports all `SourceFile`s from the given crate into the current session.
|
/// Imports all `SourceFile`s from the given crate into the current session.
|
||||||
/// This normally happens automatically when we decode a `Span` from
|
/// This normally happens automatically when we decode a `Span` from
|
||||||
/// that crate's metadata - however, the incr comp cache needs
|
/// that crate's metadata - however, the incr comp cache needs
|
||||||
|
@ -109,3 +103,10 @@ declare_hooks! {
|
||||||
/// Create a list-like THIR representation for debugging.
|
/// Create a list-like THIR representation for debugging.
|
||||||
hook thir_flat(key: LocalDefId) -> String;
|
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]) => {
|
([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
|
||||||
|_, key| bug!(
|
|_, key| $crate::query::plumbing::default_extern_query(stringify!($name), &key)
|
||||||
"`tcx.{}({:?})` unsupported by its crate; \
|
|
||||||
perhaps the `{}` query was never assigned a provider function",
|
|
||||||
stringify!($name),
|
|
||||||
key,
|
|
||||||
stringify!($name),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
|
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
|
||||||
separate_provide_extern_default!([$($modifiers)*][$($args)*])
|
separate_provide_extern_default!([$($modifiers)*][$($args)*])
|
||||||
|
@ -462,15 +456,7 @@ macro_rules! define_callbacks {
|
||||||
impl Default for Providers {
|
impl Default for Providers {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Providers {
|
Providers {
|
||||||
$($name: |_, key| bug!(
|
$($name: |_, key| $crate::query::plumbing::default_query(stringify!($name), &key)),*
|
||||||
"`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),
|
|
||||||
),)*
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,3 +647,21 @@ use super::erase::EraseType;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, HashStable)]
|
#[derive(Copy, Clone, Debug, HashStable)]
|
||||||
pub struct CyclePlaceholder(pub ErrorGuaranteed);
|
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, _)
|
hir::PatKind::Ref(inner, _)
|
||||||
if self.typeck_results.skipped_ref_pats().contains(pat.hir_id) =>
|
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),
|
_ => self.lower_pattern_unadjusted(pat),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1125,7 +1125,7 @@ impl Options {
|
||||||
|| self.unstable_opts.query_dep_graph
|
|| 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)
|
file_path_mapping(self.remap_path_prefix.clone(), &self.unstable_opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1162,6 +1162,16 @@ impl UnstableOptions {
|
||||||
track_diagnostics: self.track_diagnostics,
|
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
|
// 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;
|
use rustc_macros::HashStable_Generic;
|
||||||
pub use rustc_span::def_id::StableCrateId;
|
pub use rustc_span::def_id::StableCrateId;
|
||||||
use rustc_span::edition::Edition;
|
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::{FileNameDisplayPreference, RealFileName};
|
||||||
use rustc_span::{SourceFileHashAlgorithm, Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::asm::InlineAsmArch;
|
use rustc_target::asm::InlineAsmArch;
|
||||||
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
|
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
|
||||||
use rustc_target::spec::{
|
use rustc_target::spec::{
|
||||||
|
@ -988,7 +988,6 @@ pub fn build_session(
|
||||||
registry: rustc_errors::registry::Registry,
|
registry: rustc_errors::registry::Registry,
|
||||||
fluent_resources: Vec<&'static str>,
|
fluent_resources: Vec<&'static str>,
|
||||||
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
|
||||||
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
|
|
||||||
target: Target,
|
target: Target,
|
||||||
sysroot: PathBuf,
|
sysroot: PathBuf,
|
||||||
cfg_version: &'static str,
|
cfg_version: &'static str,
|
||||||
|
@ -1015,24 +1014,11 @@ pub fn build_session(
|
||||||
early_dcx.early_warn(warning)
|
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(
|
let fallback_bundle = fallback_fluent_bundle(
|
||||||
fluent_resources,
|
fluent_resources,
|
||||||
sopts.unstable_opts.translate_directionality_markers,
|
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 emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
|
||||||
|
|
||||||
let mut dcx =
|
let mut dcx =
|
||||||
|
@ -1411,16 +1397,10 @@ impl EarlyDiagCtxt {
|
||||||
self.dcx.warn(msg)
|
self.dcx.warn(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initialize_checked_jobserver(&self) {
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
// initialize jobserver before getting `jobserver::client` and `build_session`.
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
jobserver::initialize_checked(|err| {
|
pub fn early_struct_warn(&self, msg: impl Into<DiagMessage>) -> Diag<'_, ()> {
|
||||||
#[allow(rustc::untranslatable_diagnostic)]
|
self.dcx.struct_warn(msg)
|
||||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
|
||||||
self.dcx
|
|
||||||
.struct_warn(err)
|
|
||||||
.with_note("the build environment is likely misconfigured")
|
|
||||||
.emit()
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||||
mod caching_source_map_view;
|
mod caching_source_map_view;
|
||||||
pub mod source_map;
|
pub mod source_map;
|
||||||
pub use self::caching_source_map_view::CachingSourceMapView;
|
pub use self::caching_source_map_view::CachingSourceMapView;
|
||||||
use source_map::SourceMap;
|
use source_map::{SourceMap, SourceMapInputs};
|
||||||
|
|
||||||
pub mod edition;
|
pub mod edition;
|
||||||
use edition::Edition;
|
use edition::Edition;
|
||||||
|
@ -104,35 +104,35 @@ pub struct SessionGlobals {
|
||||||
metavar_spans: Lock<FxHashMap<Span, Span>>,
|
metavar_spans: Lock<FxHashMap<Span, Span>>,
|
||||||
hygiene_data: Lock<hygiene::HygieneData>,
|
hygiene_data: Lock<hygiene::HygieneData>,
|
||||||
|
|
||||||
/// A reference to the source map in the `Session`. It's an `Option`
|
/// The session's source map, if there is one. This field should only be
|
||||||
/// because it can't be initialized until `Session` is created, which
|
/// used in places where the `Session` is truly not available, such as
|
||||||
/// happens after `SessionGlobals`. `set_source_map` does the
|
/// `<Span as Debug>::fmt`.
|
||||||
/// initialization.
|
source_map: Option<Lrc<SourceMap>>,
|
||||||
///
|
|
||||||
/// 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>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionGlobals {
|
impl SessionGlobals {
|
||||||
pub fn new(edition: Edition) -> SessionGlobals {
|
pub fn new(edition: Edition, sm_inputs: Option<SourceMapInputs>) -> SessionGlobals {
|
||||||
SessionGlobals {
|
SessionGlobals {
|
||||||
symbol_interner: symbol::Interner::fresh(),
|
symbol_interner: symbol::Interner::fresh(),
|
||||||
span_interner: Lock::new(span_encoding::SpanInterner::default()),
|
span_interner: Lock::new(span_encoding::SpanInterner::default()),
|
||||||
metavar_spans: Default::default(),
|
metavar_spans: Default::default(),
|
||||||
hygiene_data: Lock::new(hygiene::HygieneData::new(edition)),
|
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!(
|
assert!(
|
||||||
!SESSION_GLOBALS.is_set(),
|
!SESSION_GLOBALS.is_set(),
|
||||||
"SESSION_GLOBALS should never be overwritten! \
|
"SESSION_GLOBALS should never be overwritten! \
|
||||||
Use another thread if you need another SessionGlobals"
|
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)
|
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)
|
SESSION_GLOBALS.set(session_globals, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// No source map.
|
||||||
pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
|
pub fn create_session_if_not_set_then<R, F>(edition: Edition, f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&SessionGlobals) -> R,
|
F: FnOnce(&SessionGlobals) -> R,
|
||||||
{
|
{
|
||||||
if !SESSION_GLOBALS.is_set() {
|
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))
|
SESSION_GLOBALS.set(&session_globals, || SESSION_GLOBALS.with(f))
|
||||||
} else {
|
} else {
|
||||||
SESSION_GLOBALS.with(f)
|
SESSION_GLOBALS.with(f)
|
||||||
|
@ -164,8 +165,9 @@ where
|
||||||
SESSION_GLOBALS.with(f)
|
SESSION_GLOBALS.with(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Default edition, no source map.
|
||||||
pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R {
|
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`
|
// 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 {
|
impl fmt::Debug for Span {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
// Use the global `SourceMap` to print the span. If that's not
|
// 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() {
|
if SESSION_GLOBALS.is_set() {
|
||||||
with_session_globals(|session_globals| {
|
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())
|
write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
|
||||||
} else {
|
} else {
|
||||||
fallback(*self, f)
|
fallback(*self, f)
|
||||||
|
|
|
@ -167,9 +167,17 @@ struct SourceMapFiles {
|
||||||
stable_id_to_source_file: UnhashMap<StableSourceFileId, Lrc<SourceFile>>,
|
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 {
|
pub struct SourceMap {
|
||||||
files: RwLock<SourceMapFiles>,
|
files: RwLock<SourceMapFiles>,
|
||||||
file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
|
file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
|
||||||
|
|
||||||
// This is used to apply the file path remapping as specified via
|
// This is used to apply the file path remapping as specified via
|
||||||
// `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
|
// `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
|
||||||
path_mapping: FilePathMapping,
|
path_mapping: FilePathMapping,
|
||||||
|
@ -180,17 +188,15 @@ pub struct SourceMap {
|
||||||
|
|
||||||
impl SourceMap {
|
impl SourceMap {
|
||||||
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
|
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
|
||||||
Self::with_file_loader_and_hash_kind(
|
Self::with_inputs(SourceMapInputs {
|
||||||
Box::new(RealFileLoader),
|
file_loader: Box::new(RealFileLoader),
|
||||||
path_mapping,
|
path_mapping,
|
||||||
SourceFileHashAlgorithm::Md5,
|
hash_kind: SourceFileHashAlgorithm::Md5,
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_file_loader_and_hash_kind(
|
pub fn with_inputs(
|
||||||
file_loader: Box<dyn FileLoader + Sync + Send>,
|
SourceMapInputs { file_loader, path_mapping, hash_kind }: SourceMapInputs,
|
||||||
path_mapping: FilePathMapping,
|
|
||||||
hash_kind: SourceFileHashAlgorithm,
|
|
||||||
) -> SourceMap {
|
) -> SourceMap {
|
||||||
SourceMap {
|
SourceMap {
|
||||||
files: Default::default(),
|
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)]
|
#[derive(Clone)]
|
||||||
pub struct FilePathMapping {
|
pub struct FilePathMapping {
|
||||||
mapping: Vec<(PathBuf, PathBuf)>,
|
mapping: Vec<(PathBuf, PathBuf)>,
|
||||||
|
|
|
@ -1462,6 +1462,7 @@ symbols! {
|
||||||
receiver,
|
receiver,
|
||||||
recursion_limit,
|
recursion_limit,
|
||||||
reexport_test_harness_main,
|
reexport_test_harness_main,
|
||||||
|
ref_pat_eat_one_layer_2024,
|
||||||
ref_pat_everywhere,
|
ref_pat_everywhere,
|
||||||
ref_unwind_safe_trait,
|
ref_unwind_safe_trait,
|
||||||
reference,
|
reference,
|
||||||
|
|
|
@ -1156,11 +1156,11 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
|
||||||
let is_iterating = self.start < self.end;
|
let is_iterating = self.start < self.end;
|
||||||
Some(if is_iterating {
|
Some(if is_iterating {
|
||||||
// SAFETY: just checked precondition
|
// 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)
|
mem::replace(&mut self.start, n)
|
||||||
} else {
|
} else {
|
||||||
self.exhausted = true;
|
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 {
|
while self.start < self.end {
|
||||||
// SAFETY: just checked precondition
|
// 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);
|
let n = mem::replace(&mut self.start, n);
|
||||||
accum = f(accum, n)?;
|
accum = f(accum, n)?;
|
||||||
}
|
}
|
||||||
|
@ -1187,7 +1187,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
|
||||||
self.exhausted = true;
|
self.exhausted = true;
|
||||||
|
|
||||||
if self.start == self.end {
|
if self.start == self.end {
|
||||||
accum = f(accum, self.start.clone())?;
|
accum = f(accum, self.start)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
try { accum }
|
try { accum }
|
||||||
|
@ -1201,11 +1201,11 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
|
||||||
let is_iterating = self.start < self.end;
|
let is_iterating = self.start < self.end;
|
||||||
Some(if is_iterating {
|
Some(if is_iterating {
|
||||||
// SAFETY: just checked precondition
|
// 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)
|
mem::replace(&mut self.end, n)
|
||||||
} else {
|
} else {
|
||||||
self.exhausted = true;
|
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 {
|
while self.start < self.end {
|
||||||
// SAFETY: just checked precondition
|
// 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);
|
let n = mem::replace(&mut self.end, n);
|
||||||
accum = f(accum, n)?;
|
accum = f(accum, n)?;
|
||||||
}
|
}
|
||||||
|
@ -1232,7 +1232,7 @@ impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> {
|
||||||
self.exhausted = true;
|
self.exhausted = true;
|
||||||
|
|
||||||
if self.start == self.end {
|
if self.start == self.end {
|
||||||
accum = f(accum, self.start.clone())?;
|
accum = f(accum, self.start)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
try { accum }
|
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;
|
pub mod fs;
|
||||||
#[path = "../unsupported/io.rs"]
|
#[path = "../unsupported/io.rs"]
|
||||||
pub mod io;
|
pub mod io;
|
||||||
|
mod libunwind_integration;
|
||||||
pub mod net;
|
pub mod net;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
#[path = "../unsupported/pipe.rs"]
|
#[path = "../unsupported/pipe.rs"]
|
||||||
|
|
|
@ -52,10 +52,6 @@ impl<T> WaitVariable<T> {
|
||||||
WaitVariable { queue: WaitQueue::new(), lock: var }
|
WaitVariable { queue: WaitQueue::new(), lock: var }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queue_empty(&self) -> bool {
|
|
||||||
self.queue.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lock_var(&self) -> &T {
|
pub fn lock_var(&self) -> &T {
|
||||||
&self.lock
|
&self.lock
|
||||||
}
|
}
|
||||||
|
@ -68,7 +64,7 @@ impl<T> WaitVariable<T> {
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum NotifiedTcs {
|
pub enum NotifiedTcs {
|
||||||
Single(Tcs),
|
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
|
/// 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> {
|
impl<'a, T> Deref for WaitGuard<'a, T> {
|
||||||
type Target = SpinMutexGuard<'a, WaitVariable<T>>;
|
type Target = SpinMutexGuard<'a, WaitVariable<T>>;
|
||||||
|
|
||||||
|
@ -141,10 +124,6 @@ impl WaitQueue {
|
||||||
WaitQueue { inner: UnsafeList::new() }
|
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
|
/// Adds the calling thread to the `WaitVariable`'s wait queue, then wait
|
||||||
/// until a wakeup event.
|
/// until a wakeup event.
|
||||||
///
|
///
|
||||||
|
@ -253,7 +232,10 @@ impl WaitQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(count) = NonZero::new(count) {
|
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 {
|
} else {
|
||||||
Err(guard)
|
Err(guard)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,24 +12,20 @@ cfg_if::cfg_if! {
|
||||||
))] {
|
))] {
|
||||||
mod futex;
|
mod futex;
|
||||||
pub use futex::RwLock;
|
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;
|
mod queue;
|
||||||
pub use queue::RwLock;
|
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")] {
|
} else if #[cfg(target_os = "solid_asp3")] {
|
||||||
mod solid;
|
mod solid;
|
||||||
pub use solid::RwLock;
|
pub use solid::RwLock;
|
||||||
} else if #[cfg(target_os = "teeos")] {
|
} else if #[cfg(target_os = "teeos")] {
|
||||||
mod teeos;
|
mod teeos;
|
||||||
pub use teeos::RwLock;
|
pub use teeos::RwLock;
|
||||||
} else if #[cfg(target_os = "xous")] {
|
|
||||||
mod xous;
|
|
||||||
pub use xous::RwLock;
|
|
||||||
} else {
|
} else {
|
||||||
mod no_threads;
|
mod no_threads;
|
||||||
pub use no_threads::RwLock;
|
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
|
// of all `#[test]` attributes in not ignored code examples
|
||||||
fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
|
fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec<Range<usize>>) {
|
||||||
rustc_driver::catch_fatal_errors(|| {
|
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 mut test_attr_spans = vec![];
|
||||||
let filename = FileName::anon_source_code(&code);
|
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…
Add table
Add a link
Reference in a new issue