Merge ref 'e96bb7e44f' from rust-lang/rust
Pull recent changes from https://github.com/rust-lang/rust via Josh.
Upstream ref: rust-lang/rust@e96bb7e44f
Filtered ref: rust-lang/miri@4304ab0a87
Upstream diff: 873d4682c7...e96bb7e44f
This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
commit
db1d1abba1
372 changed files with 10849 additions and 9237 deletions
86
Cargo.lock
86
Cargo.lock
|
|
@ -857,7 +857,7 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
"unified-diff",
|
||||
"walkdir",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2038,7 +2038,7 @@ dependencies = [
|
|||
"serde",
|
||||
"tempfile",
|
||||
"uuid",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3698,7 +3698,7 @@ dependencies = [
|
|||
"thorin-dwp",
|
||||
"tracing",
|
||||
"wasm-encoder 0.219.2",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3756,7 +3756,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3822,7 +3822,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"shlex",
|
||||
"tracing",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3873,7 +3873,7 @@ dependencies = [
|
|||
"serde_json",
|
||||
"termize",
|
||||
"tracing",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4170,6 +4170,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_parsing",
|
||||
|
|
@ -4664,7 +4665,7 @@ dependencies = [
|
|||
"rustc_target",
|
||||
"termize",
|
||||
"tracing",
|
||||
"windows",
|
||||
"windows 0.61.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5438,14 +5439,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.37.2"
|
||||
version = "0.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f"
|
||||
checksum = "fe840c5b1afe259a5657392a4dbb74473a14c8db999c3ec2f4ae812e028a94da"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
"objc2-io-kit",
|
||||
"windows",
|
||||
"windows 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6398,22 +6399,34 @@ version = "0.61.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
|
||||
dependencies = [
|
||||
"windows-collections",
|
||||
"windows-collections 0.2.0",
|
||||
"windows-core 0.61.2",
|
||||
"windows-future",
|
||||
"windows-future 0.2.1",
|
||||
"windows-link 0.1.3",
|
||||
"windows-numerics",
|
||||
"windows-numerics 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
|
||||
dependencies = [
|
||||
"windows-collections 0.3.2",
|
||||
"windows-core 0.62.2",
|
||||
"windows-future 0.3.2",
|
||||
"windows-numerics 0.3.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.61.1"
|
||||
version = "0.66.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
|
||||
checksum = "81b7ec123a4eadd44d1f44f76804316b477b2537abed9a2ab950b3c54afa1fcf"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows-threading",
|
||||
"windows-threading 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6425,6 +6438,15 @@ dependencies = [
|
|||
"windows-core 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.2"
|
||||
|
|
@ -6459,7 +6481,18 @@ checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
|||
dependencies = [
|
||||
"windows-core 0.61.2",
|
||||
"windows-link 0.1.3",
|
||||
"windows-threading",
|
||||
"windows-threading 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-link 0.2.1",
|
||||
"windows-threading 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6506,6 +6539,16 @@ dependencies = [
|
|||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
|
||||
dependencies = [
|
||||
"windows-core 0.62.2",
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.4"
|
||||
|
|
@ -6611,6 +6654,15 @@ dependencies = [
|
|||
"windows-link 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
|
||||
dependencies = [
|
||||
"windows-link 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ path = [
|
|||
]
|
||||
precedence = "override"
|
||||
SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)"
|
||||
SPDX-License-Identifier = "MIT or Apache-2.0"
|
||||
SPDX-License-Identifier = "MIT OR Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::LoongArch32
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
| asm::InlineAsmArch::PowerPC
|
||||
| asm::InlineAsmArch::PowerPC64
|
||||
);
|
||||
if !is_stable
|
||||
&& !self.tcx.features().asm_experimental_arch()
|
||||
|
|
|
|||
|
|
@ -343,8 +343,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
// FIXME: Ideally MIR types are normalized, but this is not always true.
|
||||
let mir_ty = self.normalize(mir_ty, Locations::All(span));
|
||||
// This is a hack. `body.local_decls` are not necessarily normalized in the old
|
||||
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
|
||||
//
|
||||
// I am not sure of a test case where this actually matters. There is a similar
|
||||
// hack in `equate_inputs_and_outputs` which does have associated test cases.
|
||||
let mir_ty = match self.infcx.next_trait_solver() {
|
||||
true => mir_ty,
|
||||
false => self.normalize(mir_ty, Locations::All(span)),
|
||||
};
|
||||
|
||||
let cause = ObligationCause::dummy_with_span(span);
|
||||
let param_env = self.infcx.param_env;
|
||||
|
|
@ -353,6 +360,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ConstraintCategory::Boring,
|
||||
type_op::custom::CustomTypeOp::new(
|
||||
|ocx| {
|
||||
// The `AscribeUserType` query would normally emit a wf
|
||||
// obligation for the unnormalized user_ty here. This is
|
||||
// where the "incorrectly skips the WF checks we normally do"
|
||||
// happens
|
||||
let user_ty = ocx.normalize(&cause, param_env, user_ty);
|
||||
ocx.eq(&cause, param_env, user_ty, mir_ty)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -126,6 +126,31 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
// FIXME(BoxyUwU): This should probably be part of a larger borrowck dev-guide chapter
|
||||
//
|
||||
/// Enforce that the types of the locals corresponding to the inputs and output of
|
||||
/// the body are equal to those of the (normalized) signature.
|
||||
///
|
||||
/// This is necessary for two reasons:
|
||||
/// - Locals in the MIR all start out with `'erased` regions and then are replaced
|
||||
/// with unconstrained nll vars. If we have a function returning `&'a u32` then
|
||||
/// the local `_0: &'?10 u32` needs to have its region var equated with the nll
|
||||
/// var representing `'a`. i.e. borrow check must uphold that `'?10 = 'a`.
|
||||
/// - When computing the normalized signature we may introduce new unconstrained nll
|
||||
/// vars due to higher ranked where clauses ([#136547]). We then wind up with implied
|
||||
/// bounds involving these vars.
|
||||
///
|
||||
/// For this reason it is important that we equate with the *normalized* signature
|
||||
/// which was produced when computing implied bounds. If we do not do so then we will
|
||||
/// wind up with implied bounds on nll vars which cannot actually be used as the nll
|
||||
/// var never gets related to anything.
|
||||
///
|
||||
/// For 'closure-like' bodies this function effectively relates the *inferred* signature
|
||||
/// of the closure against the locals corresponding to the closure's inputs/output. It *does
|
||||
/// not* relate the user provided types for the signature to the locals, this is handled
|
||||
/// separately by: [`TypeChecker::check_signature_annotation`].
|
||||
///
|
||||
/// [#136547]: <https://www.github.com/rust-lang/rust/issues/136547>
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) {
|
||||
let (&normalized_output_ty, normalized_input_tys) =
|
||||
|
|
@ -173,38 +198,44 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
// Return types are a bit more complex. They may contain opaque `impl Trait` types.
|
||||
let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty;
|
||||
// Equate expected output ty with the type of the RETURN_PLACE in MIR
|
||||
let mir_output_ty = self.body.return_ty();
|
||||
let output_span = self.body.local_decls[RETURN_PLACE].source_info.span;
|
||||
self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span);
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) {
|
||||
if self.infcx.next_trait_solver() {
|
||||
return self
|
||||
.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
||||
.unwrap_or_else(|terr| {
|
||||
span_mirbug!(
|
||||
self,
|
||||
Location::START,
|
||||
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// This is a hack. `body.local_decls` are not necessarily normalized in the old
|
||||
// solver due to not deeply normalizing in writeback. So we must re-normalize here.
|
||||
//
|
||||
// However, in most cases normalizing is unnecessary so we only do so if it may be
|
||||
// necessary for type equality to hold. This leads to some (very minor) performance
|
||||
// wins.
|
||||
if let Err(_) =
|
||||
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
||||
{
|
||||
// FIXME(jackh726): This is a hack. It's somewhat like
|
||||
// `rustc_traits::normalize_after_erasing_regions`. Ideally, we'd
|
||||
// like to normalize *before* inserting into `local_decls`, but
|
||||
// doing so ends up causing some other trouble.
|
||||
let b = self.normalize(b, Locations::All(span));
|
||||
|
||||
// Note: if we have to introduce new placeholders during normalization above, then we
|
||||
// won't have added those universes to the universe info, which we would want in
|
||||
// `relate_tys`.
|
||||
if let Err(terr) =
|
||||
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
Location::START,
|
||||
"equate_normalized_input_or_output: `{:?}=={:?}` failed with `{:?}`",
|
||||
a,
|
||||
b,
|
||||
terr
|
||||
);
|
||||
}
|
||||
}
|
||||
self.eq_types(a, b, Locations::All(span), ConstraintCategory::BoringNoLocation)
|
||||
.unwrap_or_else(|terr| {
|
||||
span_mirbug!(
|
||||
self,
|
||||
Location::START,
|
||||
"equate_normalized_input_or_output: `{a:?}=={b:?}` failed with `{terr:?}`",
|
||||
);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,16 +123,19 @@ pub(crate) fn type_check<'tcx>(
|
|||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(infcx, universal_regions, &mut constraints);
|
||||
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
pre_obligations.is_empty(),
|
||||
"there should be no incoming region obligations = {pre_obligations:#?}",
|
||||
);
|
||||
let pre_assumptions = infcx.take_registered_region_assumptions();
|
||||
assert!(
|
||||
pre_assumptions.is_empty(),
|
||||
"there should be no incoming region assumptions = {pre_assumptions:#?}",
|
||||
);
|
||||
{
|
||||
// Scope these variables so it's clear they're not used later
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
pre_obligations.is_empty(),
|
||||
"there should be no incoming region obligations = {pre_obligations:#?}",
|
||||
);
|
||||
let pre_assumptions = infcx.take_registered_region_assumptions();
|
||||
assert!(
|
||||
pre_assumptions.is_empty(),
|
||||
"there should be no incoming region assumptions = {pre_assumptions:#?}",
|
||||
);
|
||||
}
|
||||
|
||||
debug!(?normalized_inputs_and_output);
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,15 @@ fn load_binary_file(
|
|||
}
|
||||
};
|
||||
match cx.source_map().load_binary_file(&resolved_path) {
|
||||
Ok(data) => Ok(data),
|
||||
Ok(data) => {
|
||||
cx.sess
|
||||
.psess
|
||||
.file_depinfo
|
||||
.borrow_mut()
|
||||
.insert(Symbol::intern(&resolved_path.to_string_lossy()));
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
Err(io_err) => {
|
||||
let mut err = cx.dcx().struct_span_err(
|
||||
macro_span,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
|
||||
|
||||
#![no_std]
|
||||
#![feature(allocator_api, rustc_private)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use std::hash::BuildHasherDefault;
|
||||
|
||||
pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
|
||||
|
||||
pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>;
|
||||
|
||||
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub type FxIndexMap<K, V> = indexmap::IndexMap<K, V, FxBuildHasher>;
|
||||
pub type FxIndexSet<V> = indexmap::IndexSet<V, FxBuildHasher>;
|
||||
pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
|
||||
pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ use std::hash::Hash;
|
|||
use std::iter::{Product, Sum};
|
||||
use std::ops::Index;
|
||||
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
use rustc_macros::{Decodable_NoContext, Encodable_NoContext};
|
||||
|
||||
use crate::fingerprint::Fingerprint;
|
||||
use crate::fx::{FxBuildHasher, FxHashMap, FxHashSet};
|
||||
use crate::stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey};
|
||||
|
||||
/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
|
||||
|
|
|
|||
|
|
@ -849,6 +849,9 @@ pub struct SyntaxExtension {
|
|||
/// Should debuginfo for the macro be collapsed to the outermost expansion site (in other
|
||||
/// words, was the macro definition annotated with `#[collapse_debuginfo]`)?
|
||||
pub collapse_debuginfo: bool,
|
||||
/// Suppresses the "this error originates in the macro" note when a diagnostic points at this
|
||||
/// macro.
|
||||
pub hide_backtrace: bool,
|
||||
}
|
||||
|
||||
impl SyntaxExtension {
|
||||
|
|
@ -882,6 +885,7 @@ impl SyntaxExtension {
|
|||
allow_internal_unsafe: false,
|
||||
local_inner_macros: false,
|
||||
collapse_debuginfo: false,
|
||||
hide_backtrace: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -912,6 +916,12 @@ impl SyntaxExtension {
|
|||
collapse_table[flag as usize][attr as usize]
|
||||
}
|
||||
|
||||
fn get_hide_backtrace(attrs: &[hir::Attribute]) -> bool {
|
||||
// FIXME(estebank): instead of reusing `#[rustc_diagnostic_item]` as a proxy, introduce a
|
||||
// new attribute purely for this under the `#[diagnostic]` namespace.
|
||||
ast::attr::find_by_name(attrs, sym::rustc_diagnostic_item).is_some()
|
||||
}
|
||||
|
||||
/// Constructs a syntax extension with the given properties
|
||||
/// and other properties converted from attributes.
|
||||
pub fn new(
|
||||
|
|
@ -948,6 +958,7 @@ impl SyntaxExtension {
|
|||
// Not a built-in macro
|
||||
None => (None, helper_attrs),
|
||||
};
|
||||
let hide_backtrace = builtin_name.is_some() || Self::get_hide_backtrace(attrs);
|
||||
|
||||
let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability);
|
||||
|
||||
|
|
@ -982,6 +993,7 @@ impl SyntaxExtension {
|
|||
allow_internal_unsafe,
|
||||
local_inner_macros,
|
||||
collapse_debuginfo,
|
||||
hide_backtrace,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1061,7 +1073,7 @@ impl SyntaxExtension {
|
|||
self.allow_internal_unsafe,
|
||||
self.local_inner_macros,
|
||||
self.collapse_debuginfo,
|
||||
self.builtin_name.is_some(),
|
||||
self.hide_backtrace,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -458,13 +458,11 @@ impl<'a, 'b> Rustc<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl server::Types for Rustc<'_, '_> {
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
type TokenStream = TokenStream;
|
||||
type Span = Span;
|
||||
type Symbol = Symbol;
|
||||
}
|
||||
|
||||
impl server::Server for Rustc<'_, '_> {
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span> {
|
||||
ExpnGlobals {
|
||||
def_site: self.def_site,
|
||||
|
|
|
|||
|
|
@ -415,10 +415,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
infcx.instantiate_canonical(span, &query_input.canonical);
|
||||
let query::MethodAutoderefSteps { predefined_opaques_in_body: _, self_ty } = value;
|
||||
debug!(?self_ty, ?query_input, "probe_op: Mode::Path");
|
||||
let prev_opaque_entries = self.inner.borrow_mut().opaque_types().num_entries();
|
||||
MethodAutoderefStepsResult {
|
||||
steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
|
||||
self_ty: self
|
||||
.make_query_response_ignoring_pending_obligations(var_values, self_ty),
|
||||
self_ty: self.make_query_response_ignoring_pending_obligations(
|
||||
var_values,
|
||||
self_ty,
|
||||
prev_opaque_entries,
|
||||
),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs: 0,
|
||||
from_unsafe_deref: false,
|
||||
|
|
@ -607,6 +611,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_types_storage`");
|
||||
}
|
||||
}
|
||||
let prev_opaque_entries = infcx.inner.borrow_mut().opaque_types().num_entries();
|
||||
|
||||
// We accept not-yet-defined opaque types in the autoderef
|
||||
// chain to support recursive calls. We do error if the final
|
||||
|
|
@ -650,8 +655,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
.zip(reachable_via_deref)
|
||||
.map(|((ty, d), reachable_via_deref)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
ty,
|
||||
prev_opaque_entries,
|
||||
),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
|
|
@ -671,8 +679,11 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
.by_ref()
|
||||
.map(|(ty, d)| {
|
||||
let step = CandidateStep {
|
||||
self_ty: infcx
|
||||
.make_query_response_ignoring_pending_obligations(inference_vars, ty),
|
||||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
ty,
|
||||
prev_opaque_entries,
|
||||
),
|
||||
self_ty_is_opaque: self_ty_is_opaque(ty),
|
||||
autoderefs: d,
|
||||
from_unsafe_deref: reached_raw_pointer,
|
||||
|
|
@ -692,11 +703,19 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
let opt_bad_ty = match final_ty.kind() {
|
||||
ty::Infer(ty::TyVar(_)) if !self_ty_is_opaque(final_ty) => Some(MethodAutoderefBadTy {
|
||||
reached_raw_pointer,
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
final_ty,
|
||||
prev_opaque_entries,
|
||||
),
|
||||
}),
|
||||
ty::Error(_) => Some(MethodAutoderefBadTy {
|
||||
reached_raw_pointer,
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(inference_vars, final_ty),
|
||||
ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
final_ty,
|
||||
prev_opaque_entries,
|
||||
),
|
||||
}),
|
||||
ty::Array(elem_ty, _) => {
|
||||
let autoderefs = steps.iter().filter(|s| s.reachable_via_deref).count() - 1;
|
||||
|
|
@ -704,6 +723,7 @@ pub(crate) fn method_autoderef_steps<'tcx>(
|
|||
self_ty: infcx.make_query_response_ignoring_pending_obligations(
|
||||
inference_vars,
|
||||
Ty::new_slice(infcx.tcx, *elem_ty),
|
||||
prev_opaque_entries,
|
||||
),
|
||||
self_ty_is_opaque: false,
|
||||
autoderefs,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,8 @@ use crate::infer::canonical::{
|
|||
};
|
||||
use crate::infer::region_constraints::RegionConstraintData;
|
||||
use crate::infer::{
|
||||
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, SubregionOrigin, TypeOutlivesConstraint,
|
||||
DefineOpaqueTypes, InferCtxt, InferOk, InferResult, OpaqueTypeStorageEntries, SubregionOrigin,
|
||||
TypeOutlivesConstraint,
|
||||
};
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{ObligationCause, PredicateObligations, ScrubbedTraitError, TraitEngine};
|
||||
|
|
@ -81,6 +82,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
inference_vars: CanonicalVarValues<'tcx>,
|
||||
answer: T,
|
||||
prev_entries: OpaqueTypeStorageEntries,
|
||||
) -> Canonical<'tcx, QueryResponse<'tcx, T>>
|
||||
where
|
||||
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
|
||||
|
|
@ -96,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
self.inner
|
||||
.borrow_mut()
|
||||
.opaque_type_storage
|
||||
.iter_opaque_types()
|
||||
.opaque_types_added_since(prev_entries)
|
||||
.map(|(k, v)| (k, v.ty))
|
||||
.collect()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use rustc_ast::{self as ast, CRATE_NODE_ID};
|
|||
use rustc_attr_parsing::{AttributeParser, Early, ShouldEmit};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, CrateInfo};
|
||||
use rustc_data_structures::indexmap::IndexMap;
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
|
||||
|
|
@ -584,7 +585,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
let result: io::Result<()> = try {
|
||||
// Build a list of files used to compile the output and
|
||||
// write Makefile-compatible dependency rules
|
||||
let mut files: Vec<(String, u64, Option<SourceFileHash>)> = sess
|
||||
let mut files: IndexMap<String, (u64, Option<SourceFileHash>)> = sess
|
||||
.source_map()
|
||||
.files()
|
||||
.iter()
|
||||
|
|
@ -593,10 +594,12 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
.map(|fmap| {
|
||||
(
|
||||
escape_dep_filename(&fmap.name.prefer_local_unconditionally().to_string()),
|
||||
// This needs to be unnormalized,
|
||||
// as external tools wouldn't know how rustc normalizes them
|
||||
fmap.unnormalized_source_len as u64,
|
||||
fmap.checksum_hash,
|
||||
(
|
||||
// This needs to be unnormalized,
|
||||
// as external tools wouldn't know how rustc normalizes them
|
||||
fmap.unnormalized_source_len as u64,
|
||||
fmap.checksum_hash,
|
||||
),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
|
@ -614,7 +617,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
fn hash_iter_files<P: AsRef<Path>>(
|
||||
it: impl Iterator<Item = P>,
|
||||
checksum_hash_algo: Option<SourceFileHashAlgorithm>,
|
||||
) -> impl Iterator<Item = (P, u64, Option<SourceFileHash>)> {
|
||||
) -> impl Iterator<Item = (P, (u64, Option<SourceFileHash>))> {
|
||||
it.map(move |path| {
|
||||
match checksum_hash_algo.and_then(|algo| {
|
||||
fs::File::open(path.as_ref())
|
||||
|
|
@ -630,8 +633,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
})
|
||||
.ok()
|
||||
}) {
|
||||
Some((file_len, checksum)) => (path, file_len, Some(checksum)),
|
||||
None => (path, 0, None),
|
||||
Some((file_len, checksum)) => (path, (file_len, Some(checksum))),
|
||||
None => (path, (0, None)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -705,18 +708,14 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
file,
|
||||
"{}: {}\n",
|
||||
path.display(),
|
||||
files
|
||||
.iter()
|
||||
.map(|(path, _file_len, _checksum_hash_algo)| path.as_str())
|
||||
.intersperse(" ")
|
||||
.collect::<String>()
|
||||
files.keys().map(String::as_str).intersperse(" ").collect::<String>()
|
||||
)?;
|
||||
}
|
||||
|
||||
// Emit a fake target for each input file to the compilation. This
|
||||
// prevents `make` from spitting out an error if a file is later
|
||||
// deleted. For more info see #28735
|
||||
for (path, _file_len, _checksum_hash_algo) in &files {
|
||||
for path in files.keys() {
|
||||
writeln!(file, "{path}:")?;
|
||||
}
|
||||
|
||||
|
|
@ -745,7 +744,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
if sess.opts.unstable_opts.checksum_hash_algorithm().is_some() {
|
||||
files
|
||||
.iter()
|
||||
.filter_map(|(path, file_len, hash_algo)| {
|
||||
.filter_map(|(path, (file_len, hash_algo))| {
|
||||
hash_algo.map(|hash_algo| (path, file_len, hash_algo))
|
||||
})
|
||||
.try_for_each(|(path, file_len, checksum_hash)| {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ edition = "2024"
|
|||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_apfloat = "0.2.0"
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use hir::{ExprKind, Node};
|
||||
use rustc_abi::{Integer, Size};
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, Semantics, SingleS};
|
||||
use rustc_hir::{HirId, attrs};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use crate::LateContext;
|
||||
|
|
@ -383,6 +385,13 @@ fn lint_uint_literal<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// `None` if `v` does not parse as the float type, otherwise indicates whether a literal rounds
|
||||
/// to infinity.
|
||||
fn float_is_infinite<S: Semantics>(v: Symbol) -> Option<bool> {
|
||||
let x: IeeeFloat<S> = v.as_str().parse().ok()?;
|
||||
Some(x.is_infinite())
|
||||
}
|
||||
|
||||
pub(crate) fn lint_literal<'tcx>(
|
||||
cx: &LateContext<'tcx>,
|
||||
type_limits: &TypeLimits,
|
||||
|
|
@ -405,18 +414,18 @@ pub(crate) fn lint_literal<'tcx>(
|
|||
lint_uint_literal(cx, hir_id, span, lit, t)
|
||||
}
|
||||
ty::Float(t) => {
|
||||
let (is_infinite, sym) = match lit.node {
|
||||
ast::LitKind::Float(v, _) => match t {
|
||||
// FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
|
||||
// issues resolved).
|
||||
ty::FloatTy::F16 => (Ok(false), v),
|
||||
ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v),
|
||||
ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v),
|
||||
ty::FloatTy::F128 => (Ok(false), v),
|
||||
},
|
||||
_ => bug!(),
|
||||
let ast::LitKind::Float(v, _) = lit.node else {
|
||||
bug!();
|
||||
};
|
||||
if is_infinite == Ok(true) {
|
||||
|
||||
let is_infinite = match t {
|
||||
ty::FloatTy::F16 => float_is_infinite::<HalfS>(v),
|
||||
ty::FloatTy::F32 => float_is_infinite::<SingleS>(v),
|
||||
ty::FloatTy::F64 => float_is_infinite::<DoubleS>(v),
|
||||
ty::FloatTy::F128 => float_is_infinite::<QuadS>(v),
|
||||
};
|
||||
|
||||
if is_infinite == Some(true) {
|
||||
cx.emit_span_lint(
|
||||
OVERFLOWING_LITERALS,
|
||||
span,
|
||||
|
|
@ -426,7 +435,7 @@ pub(crate) fn lint_literal<'tcx>(
|
|||
.sess()
|
||||
.source_map()
|
||||
.span_to_snippet(lit.span)
|
||||
.unwrap_or_else(|_| sym.to_string()),
|
||||
.unwrap_or_else(|_| v.to_string()),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -365,6 +365,33 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn hir_owner_parent_impl(self, owner_id: OwnerId) -> HirId {
|
||||
self.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
|
||||
let parent_owner_id = self.local_def_id_to_hir_id(parent_def_id).owner;
|
||||
HirId {
|
||||
owner: parent_owner_id,
|
||||
local_id: self.hir_crate(()).owners[parent_owner_id.def_id]
|
||||
.unwrap()
|
||||
.parenting
|
||||
.get(&owner_id.def_id)
|
||||
.copied()
|
||||
.unwrap_or(ItemLocalId::ZERO),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Optimization of `hir_owner_parent` query as an inlined function
|
||||
/// in case of non-incremental build. The query itself renamed to `hir_owner_parent_q`.
|
||||
#[inline]
|
||||
pub fn hir_owner_parent(self, owner_id: OwnerId) -> HirId {
|
||||
if self.dep_graph.is_fully_enabled() {
|
||||
self.hir_owner_parent_q(owner_id)
|
||||
} else {
|
||||
self.hir_owner_parent_impl(owner_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hashes computed by [`TyCtxt::hash_owner_nodes`] if necessary.
|
||||
|
|
@ -386,20 +413,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
};
|
||||
providers.opt_hir_owner_nodes =
|
||||
|tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
|
||||
providers.hir_owner_parent = |tcx, owner_id| {
|
||||
tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
|
||||
let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
|
||||
HirId {
|
||||
owner: parent_owner_id,
|
||||
local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id]
|
||||
.unwrap()
|
||||
.parenting
|
||||
.get(&owner_id.def_id)
|
||||
.copied()
|
||||
.unwrap_or(ItemLocalId::ZERO),
|
||||
}
|
||||
})
|
||||
};
|
||||
providers.hir_owner_parent_q = |tcx, owner_id| tcx.hir_owner_parent_impl(owner_id);
|
||||
providers.hir_attr_map = |tcx, id| {
|
||||
tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@
|
|||
use std::ffi::OsStr;
|
||||
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId, ModDefId};
|
||||
use rustc_hir::hir_id::{HirId, OwnerId};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
use rustc_query_system::dep_graph::DepNodeIndex;
|
||||
use rustc_query_system::query::{DefIdCache, DefaultCache, SingleCache, VecCache};
|
||||
use rustc_span::{DUMMY_SP, Ident, LocalExpnId, Span, Symbol};
|
||||
|
|
@ -12,7 +12,7 @@ use rustc_span::{DUMMY_SP, Ident, LocalExpnId, Span, Symbol};
|
|||
use crate::infer::canonical::CanonicalQueryInput;
|
||||
use crate::mir::mono::CollectionMode;
|
||||
use crate::ty::fast_reject::SimplifiedType;
|
||||
use crate::ty::layout::{TyAndLayout, ValidityRequirement};
|
||||
use crate::ty::layout::ValidityRequirement;
|
||||
use crate::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
|
||||
use crate::{mir, traits};
|
||||
|
||||
|
|
@ -29,15 +29,7 @@ pub trait Key: Sized {
|
|||
/// constraint is not enforced here.
|
||||
///
|
||||
/// [`QueryCache`]: rustc_query_system::query::QueryCache
|
||||
// N.B. Most of the keys down below have `type Cache<V> = DefaultCache<Self, V>;`,
|
||||
// it would be reasonable to use associated type defaults, to remove the duplication...
|
||||
//
|
||||
// ...But r-a doesn't support them yet and using a default here causes r-a to not infer
|
||||
// return types of queries which is very annoying. Thus, until r-a support associated
|
||||
// type defaults, please restrain from using them here <3
|
||||
//
|
||||
// r-a issue: <https://github.com/rust-lang/rust-analyzer/issues/13693>
|
||||
type Cache<V>;
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
/// In the event that a cycle occurs, if no explicit span has been
|
||||
/// given for a query with key `self`, what span should we use?
|
||||
|
|
@ -72,49 +64,30 @@ impl Key for () {
|
|||
}
|
||||
|
||||
impl<'tcx> Key for ty::InstanceKind<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> AsLocalKey for ty::InstanceKind<'tcx> {
|
||||
type LocalKey = Self;
|
||||
|
||||
#[inline(always)]
|
||||
fn as_local_key(&self) -> Option<Self::LocalKey> {
|
||||
self.def_id().is_local().then(|| *self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::Instance<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.instance.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (Ty<'tcx>, Option<ty::ExistentialTraitRef<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
|
|
@ -184,8 +157,6 @@ impl AsLocalKey for DefId {
|
|||
}
|
||||
|
||||
impl Key for LocalModDefId {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(*self)
|
||||
}
|
||||
|
|
@ -196,79 +167,19 @@ impl Key for LocalModDefId {
|
|||
}
|
||||
}
|
||||
|
||||
impl Key for ModDefId {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(*self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn key_as_def_id(&self) -> Option<DefId> {
|
||||
Some(self.to_def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsLocalKey for ModDefId {
|
||||
type LocalKey = LocalModDefId;
|
||||
|
||||
#[inline(always)]
|
||||
fn as_local_key(&self) -> Option<Self::LocalKey> {
|
||||
self.as_local()
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for SimplifiedType {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (DefId, DefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.1.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::Instance<'tcx>, LocalDefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (DefId, LocalDefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.1.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (LocalDefId, DefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (LocalDefId, LocalDefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (DefId, Ident) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.0)
|
||||
}
|
||||
|
|
@ -280,16 +191,12 @@ impl Key for (DefId, Ident) {
|
|||
}
|
||||
|
||||
impl Key for (LocalDefId, LocalDefId, Ident) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.1.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (CrateNum, DefId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.1.default_span(tcx)
|
||||
}
|
||||
|
|
@ -305,8 +212,6 @@ impl AsLocalKey for (CrateNum, DefId) {
|
|||
}
|
||||
|
||||
impl Key for (CrateNum, SimplifiedType) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
|
|
@ -321,121 +226,37 @@ impl AsLocalKey for (CrateNum, SimplifiedType) {
|
|||
}
|
||||
}
|
||||
|
||||
impl Key for (DefId, SimplifiedType) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (DefId, ty::SizedTraitKind) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for GenericArgsRef<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (DefId, GenericArgsRef<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
(self.0).def.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (LocalDefId, DefId, GenericArgsRef<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::TraitRef<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.1.def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::TraitRef<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.def_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::PolyExistentialTraitRef<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::PolyTraitRef<'tcx>, ty::PolyTraitRef<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.def_span(self.0.def_id())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for GenericArg<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::Const<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for Ty<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
|
|
@ -449,41 +270,19 @@ impl<'tcx> Key for Ty<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for TyAndLayout<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::Clauses<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::ParamEnv<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.value.default_span(tcx)
|
||||
}
|
||||
|
|
@ -494,24 +293,18 @@ impl<'tcx, T: Key> Key for ty::PseudoCanonicalInput<'tcx, T> {
|
|||
}
|
||||
|
||||
impl Key for Symbol {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for Option<Symbol> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for &'tcx OsStr {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
|
|
@ -520,119 +313,54 @@ impl<'tcx> Key for &'tcx OsStr {
|
|||
/// Canonical query goals correspond to abstract trait operations that
|
||||
/// are not tied to any crate in particular.
|
||||
impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T: Clone> Key for (CanonicalQueryInput<'tcx, T>, bool) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (Symbol, u32, u32) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (DefId, Ty<'tcx>, GenericArgsRef<'tcx>, ty::ParamEnv<'tcx>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (Ty<'tcx>, rustc_abi::VariantIdx) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for ty::Value<'tcx> {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for HirId {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.hir_span(*self)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn key_as_def_id(&self) -> Option<DefId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Key for (LocalDefId, HirId) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
tcx.hir_span(self.1)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn key_as_def_id(&self) -> Option<DefId> {
|
||||
Some(self.0.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (LocalExpnId, &'tcx TokenStream) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.expn_data().call_site
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn key_as_def_id(&self) -> Option<DefId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
// Just forward to `Ty<'tcx>`
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
|
|
@ -648,8 +376,6 @@ impl<'tcx> Key for (ValidityRequirement, ty::PseudoCanonicalInput<'tcx, Ty<'tcx>
|
|||
}
|
||||
|
||||
impl<'tcx> Key for (ty::Instance<'tcx>, CollectionMode) {
|
||||
type Cache<V> = DefaultCache<Self, V>;
|
||||
|
||||
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
|
||||
self.0.default_span(tcx)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_lint_defs::LintId;
|
||||
use rustc_macros::rustc_queries;
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{QueryMode, QueryState};
|
||||
use rustc_query_system::query::{QueryMode, QueryStackDeferred, QueryState};
|
||||
use rustc_session::Limits;
|
||||
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
|
||||
use rustc_session::cstore::{
|
||||
|
|
@ -266,7 +266,7 @@ rustc_queries! {
|
|||
///
|
||||
/// This can be conveniently accessed by `tcx.hir_*` methods.
|
||||
/// Avoid calling this query directly.
|
||||
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
|
||||
query hir_owner_parent_q(key: hir::OwnerId) -> hir::HirId {
|
||||
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -427,7 +427,7 @@ macro_rules! define_callbacks {
|
|||
#[derive(Default)]
|
||||
pub struct QueryStates<'tcx> {
|
||||
$(
|
||||
pub $name: QueryState<$($K)*>,
|
||||
pub $name: QueryState<$($K)*, QueryStackDeferred<'tcx>>,
|
||||
)*
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -159,9 +159,7 @@ pub macro with_types_for_signature($e:expr) {{
|
|||
/// Avoids running any queries during prints.
|
||||
pub macro with_no_queries($e:expr) {{
|
||||
$crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!(
|
||||
$crate::ty::print::with_no_trimmed_paths!($crate::ty::print::with_no_visible_paths!(
|
||||
$crate::ty::print::with_forced_impl_filename_line!($e)
|
||||
))
|
||||
$crate::ty::print::with_no_trimmed_paths!($crate::ty::print::with_no_visible_paths!($e))
|
||||
))
|
||||
}}
|
||||
|
||||
|
|
|
|||
|
|
@ -609,9 +609,8 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
/// have the same `DefKind`.
|
||||
///
|
||||
/// Note that closures have a `DefId`, but the closure *expression* also has a
|
||||
/// `HirId` that is located within the context where the closure appears (and, sadly,
|
||||
/// a corresponding `NodeId`, since those are not yet phased out). The parent of
|
||||
/// the closure's `DefId` will also be the context where it appears.
|
||||
/// `HirId` that is located within the context where the closure appears. The
|
||||
/// parent of the closure's `DefId` will also be the context where it appears.
|
||||
pub fn is_closure_like(self, def_id: DefId) -> bool {
|
||||
matches!(self.def_kind(def_id), DefKind::Closure)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
|
|||
if info.query.dep_kind == dep_kinds::representability
|
||||
&& let Some(field_id) = info.query.def_id
|
||||
&& let Some(field_id) = field_id.as_local()
|
||||
&& let Some(DefKind::Field) = info.query.def_kind
|
||||
&& let Some(DefKind::Field) = info.query.info.def_kind
|
||||
{
|
||||
let parent_id = tcx.parent(field_id.to_def_id());
|
||||
let item_id = match tcx.def_kind(parent_id) {
|
||||
|
|
@ -224,7 +224,7 @@ impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>>
|
|||
continue;
|
||||
};
|
||||
let frame_span =
|
||||
frame.query.default_span(cycle[(i + 1) % cycle.len()].span);
|
||||
frame.query.info.default_span(cycle[(i + 1) % cycle.len()].span);
|
||||
if frame_span.is_dummy() {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_const_eval::check_consts::{ConstCx, qualifs};
|
|||
use rustc_data_structures::assert_matches;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
|
|
@ -329,6 +330,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
if let TempState::Defined { location: loc, .. } = self.temps[local]
|
||||
&& let Left(statement) = self.body.stmt_at(loc)
|
||||
&& let Some((_, Rvalue::Use(Operand::Constant(c)))) = statement.kind.as_assign()
|
||||
&& self.should_evaluate_for_promotion_checks(c.const_)
|
||||
&& let Some(idx) = c.const_.try_eval_target_usize(self.tcx, self.typing_env)
|
||||
// Determine the type of the thing we are indexing.
|
||||
&& let ty::Array(_, len) = place_base.ty(self.body, self.tcx).ty.kind()
|
||||
|
|
@ -484,7 +486,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
let sz = lhs_ty.primitive_size(self.tcx);
|
||||
// Integer division: the RHS must be a non-zero const.
|
||||
let rhs_val = match rhs {
|
||||
Operand::Constant(c) => {
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(c.const_) =>
|
||||
{
|
||||
c.const_.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -502,9 +506,14 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// The RHS is -1 or unknown, so we have to be careful.
|
||||
// But is the LHS int::MIN?
|
||||
let lhs_val = match lhs {
|
||||
Operand::Constant(c) => c
|
||||
.const_
|
||||
.try_eval_scalar_int(self.tcx, self.typing_env),
|
||||
Operand::Constant(c)
|
||||
if self.should_evaluate_for_promotion_checks(
|
||||
c.const_,
|
||||
) =>
|
||||
{
|
||||
c.const_
|
||||
.try_eval_scalar_int(self.tcx, self.typing_env)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let lhs_min = sz.signed_int_min();
|
||||
|
|
@ -683,6 +692,28 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
// This passed all checks, so let's accept.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Can we try to evaluate a given constant at this point in compilation? Attempting to evaluate
|
||||
/// a const block before borrow-checking will result in a query cycle (#150464).
|
||||
fn should_evaluate_for_promotion_checks(&self, constant: Const<'tcx>) -> bool {
|
||||
match constant {
|
||||
// `Const::Ty` is always a `ConstKind::Param` right now and that can never be turned
|
||||
// into a mir value for promotion
|
||||
// FIXME(mgca): do we want uses of type_const to be normalized during promotion?
|
||||
Const::Ty(..) => false,
|
||||
Const::Val(..) => true,
|
||||
// Evaluating a MIR constant requires borrow-checking it. For inline consts, as of
|
||||
// #138499, this means borrow-checking its typeck root. Since borrow-checking the
|
||||
// typeck root requires promoting its constants, trying to evaluate an inline const here
|
||||
// will result in a query cycle. To avoid the cycle, we can't evaluate const blocks yet.
|
||||
// Other kinds of unevaluated's can cause query cycles too when they arise from
|
||||
// self-reference in user code; e.g. evaluating a constant can require evaluating a
|
||||
// const function that uses that constant, again requiring evaluation of the constant.
|
||||
// However, this form of cycle renders both the constant and function unusable in
|
||||
// general, so we don't need to special-case it here.
|
||||
Const::Unevaluated(uc, _) => self.tcx.def_kind(uc.def) != DefKind::InlineConst,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_candidates(
|
||||
|
|
|
|||
|
|
@ -822,9 +822,19 @@ parse_struct_literal_body_without_path =
|
|||
struct literal body without path
|
||||
.suggestion = you might have forgotten to add the struct literal inside the block
|
||||
|
||||
parse_struct_literal_body_without_path_late =
|
||||
struct literal body without path
|
||||
.label = struct name missing for struct literal
|
||||
.suggestion = add the correct type
|
||||
|
||||
parse_struct_literal_not_allowed_here = struct literals are not allowed here
|
||||
.suggestion = surround the struct literal with parentheses
|
||||
|
||||
parse_struct_literal_placeholder_path =
|
||||
placeholder `_` is not allowed for the path in struct literals
|
||||
.label = not allowed in struct literals
|
||||
.suggestion = replace it with the correct type
|
||||
|
||||
parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
|
||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||
|
||||
|
|
|
|||
|
|
@ -3684,3 +3684,22 @@ pub(crate) struct ImplReuseInherentImpl {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_struct_literal_placeholder_path)]
|
||||
pub(crate) struct StructLiteralPlaceholderPath {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
#[suggestion(applicability = "has-placeholders", code = "/* Type */", style = "verbose")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_struct_literal_body_without_path_late)]
|
||||
pub(crate) struct StructLiteralWithoutPathLate {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[suggestion(applicability = "has-placeholders", code = "/* Type */ ", style = "verbose")]
|
||||
pub suggestion_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1468,6 +1468,9 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check(exp!(OpenParen)) {
|
||||
this.parse_expr_tuple_parens(restrictions)
|
||||
} else if this.check(exp!(OpenBrace)) {
|
||||
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(false)? {
|
||||
return Ok(expr);
|
||||
}
|
||||
this.parse_expr_block(None, lo, BlockCheckMode::Default)
|
||||
} else if this.check(exp!(Or)) || this.check(exp!(OrOr)) {
|
||||
this.parse_expr_closure().map_err(|mut err| {
|
||||
|
|
@ -1542,6 +1545,9 @@ impl<'a> Parser<'a> {
|
|||
} else if this.check_keyword(exp!(Let)) {
|
||||
this.parse_expr_let(restrictions)
|
||||
} else if this.eat_keyword(exp!(Underscore)) {
|
||||
if let Some(expr) = this.maybe_recover_bad_struct_literal_path(true)? {
|
||||
return Ok(expr);
|
||||
}
|
||||
Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
|
||||
} else if this.token_uninterpolated_span().at_least_rust_2018() {
|
||||
// `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
|
||||
|
|
@ -3698,6 +3704,45 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_recover_bad_struct_literal_path(
|
||||
&mut self,
|
||||
is_underscore_entry_point: bool,
|
||||
) -> PResult<'a, Option<Box<Expr>>> {
|
||||
if self.may_recover()
|
||||
&& self.check_noexpect(&token::OpenBrace)
|
||||
&& (!self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
|
||||
&& self.is_likely_struct_lit())
|
||||
{
|
||||
let span = if is_underscore_entry_point {
|
||||
self.prev_token.span
|
||||
} else {
|
||||
self.token.span.shrink_to_lo()
|
||||
};
|
||||
|
||||
self.bump(); // {
|
||||
let expr = self.parse_expr_struct(
|
||||
None,
|
||||
Path::from_ident(Ident::new(kw::Underscore, span)),
|
||||
false,
|
||||
)?;
|
||||
|
||||
let guar = if is_underscore_entry_point {
|
||||
self.dcx().create_err(errors::StructLiteralPlaceholderPath { span }).emit()
|
||||
} else {
|
||||
self.dcx()
|
||||
.create_err(errors::StructLiteralWithoutPathLate {
|
||||
span: expr.span,
|
||||
suggestion_span: expr.span.shrink_to_lo(),
|
||||
})
|
||||
.emit()
|
||||
};
|
||||
|
||||
Ok(Some(self.mk_expr_err(expr.span, guar)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_struct_fields(
|
||||
&mut self,
|
||||
pth: ast::Path,
|
||||
|
|
|
|||
|
|
@ -188,10 +188,27 @@ pub enum VariantsShape {
|
|||
tag: Scalar,
|
||||
tag_encoding: TagEncoding,
|
||||
tag_field: usize,
|
||||
variants: Vec<LayoutShape>,
|
||||
variants: Vec<VariantFields>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
|
||||
pub struct VariantFields {
|
||||
/// Offsets for the first byte of each field,
|
||||
/// ordered to match the source definition order.
|
||||
/// I.e.: It follows the same order as [super::ty::VariantDef::fields()].
|
||||
/// This vector does not go in increasing order.
|
||||
pub offsets: Vec<Size>,
|
||||
}
|
||||
|
||||
impl VariantFields {
|
||||
pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
|
||||
let mut indices = (0..self.offsets.len()).collect::<Vec<_>>();
|
||||
indices.sort_by_key(|idx| self.offsets[*idx]);
|
||||
indices
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)]
|
||||
pub enum TagEncoding {
|
||||
/// The tag directly stores the discriminant, but possibly with a smaller layout
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use rustc_target::callconv;
|
|||
use crate::abi::{
|
||||
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength,
|
||||
IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar,
|
||||
TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange,
|
||||
TagEncoding, TyAndLayout, ValueAbi, VariantFields, VariantsShape, WrappingRange,
|
||||
};
|
||||
use crate::compiler_interface::BridgeTys;
|
||||
use crate::target::MachineSize as Size;
|
||||
|
|
@ -213,7 +213,15 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants<rustc_abi::FieldIdx, rustc_abi::
|
|||
tag: tag.stable(tables, cx),
|
||||
tag_encoding: tag_encoding.stable(tables, cx),
|
||||
tag_field: tag_field.stable(tables, cx),
|
||||
variants: variants.iter().as_slice().stable(tables, cx),
|
||||
variants: variants
|
||||
.iter()
|
||||
.map(|v| match &v.fields {
|
||||
rustc_abi::FieldsShape::Arbitrary { offsets, .. } => VariantFields {
|
||||
offsets: offsets.iter().as_slice().stable(tables, cx),
|
||||
},
|
||||
_ => panic!("variant layout should be Arbitrary"),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex;
|
|||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
CycleError, CycleErrorHandling, HashResult, QueryCache, QueryConfig, QueryMap, QueryMode,
|
||||
QueryState, get_query_incr, get_query_non_incr,
|
||||
QueryStackDeferred, QueryState, get_query_incr, get_query_non_incr,
|
||||
};
|
||||
use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
||||
|
|
@ -79,7 +79,10 @@ where
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key>
|
||||
fn query_state<'a>(
|
||||
self,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
) -> &'a QueryState<Self::Key, QueryStackDeferred<'tcx>>
|
||||
where
|
||||
QueryCtxt<'tcx>: 'a,
|
||||
{
|
||||
|
|
@ -88,7 +91,7 @@ where
|
|||
unsafe {
|
||||
&*(&qcx.tcx.query_system.states as *const QueryStates<'tcx>)
|
||||
.byte_add(self.dynamic.query_state)
|
||||
.cast::<QueryState<Self::Key>>()
|
||||
.cast::<QueryState<Self::Key, QueryStackDeferred<'tcx>>>()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::num::NonZero;
|
|||
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_hashes::Hash64;
|
||||
use rustc_hir::limit::Limit;
|
||||
|
|
@ -26,8 +27,8 @@ use rustc_middle::ty::{self, TyCtxt};
|
|||
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
|
||||
use rustc_query_system::ich::StableHashingContext;
|
||||
use rustc_query_system::query::{
|
||||
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect, QueryStackFrame,
|
||||
force_query,
|
||||
QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffect,
|
||||
QueryStackDeferred, QueryStackFrame, QueryStackFrameExtra, force_query,
|
||||
};
|
||||
use rustc_query_system::{QueryOverflow, QueryOverflowNote};
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
|
|
@ -35,6 +36,8 @@ use rustc_span::def_id::LOCAL_CRATE;
|
|||
|
||||
use crate::QueryConfigRestored;
|
||||
|
||||
/// Implements [`QueryContext`] for use by [`rustc_query_system`], since that
|
||||
/// crate does not have direct access to [`TyCtxt`].
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct QueryCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
|
|
@ -47,15 +50,6 @@ impl<'tcx> QueryCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
|
||||
type Target = TyCtxt<'tcx>;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tcx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
|
||||
type Deps = rustc_middle::dep_graph::DepsType;
|
||||
type DepContext = TyCtxt<'tcx>;
|
||||
|
|
@ -66,17 +60,21 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl QueryContext for QueryCtxt<'_> {
|
||||
impl<'tcx> QueryContext for QueryCtxt<'tcx> {
|
||||
type QueryInfo = QueryStackDeferred<'tcx>;
|
||||
|
||||
#[inline]
|
||||
fn jobserver_proxy(&self) -> &Proxy {
|
||||
&*self.jobserver_proxy
|
||||
&self.tcx.jobserver_proxy
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn next_job_id(self) -> QueryJobId {
|
||||
QueryJobId(
|
||||
NonZero::new(self.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed))
|
||||
.unwrap(),
|
||||
NonZero::new(
|
||||
self.tcx.query_system.jobs.fetch_add(1, std::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +93,10 @@ impl QueryContext for QueryCtxt<'_> {
|
|||
/// Prefer passing `false` to `require_complete` to avoid potential deadlocks,
|
||||
/// especially when called from within a deadlock handler, unless a
|
||||
/// complete map is needed and no deadlock is possible at this call site.
|
||||
fn collect_active_jobs(self, require_complete: bool) -> Result<QueryMap, QueryMap> {
|
||||
fn collect_active_jobs(
|
||||
self,
|
||||
require_complete: bool,
|
||||
) -> Result<QueryMap<QueryStackDeferred<'tcx>>, QueryMap<QueryStackDeferred<'tcx>>> {
|
||||
let mut jobs = QueryMap::default();
|
||||
let mut complete = true;
|
||||
|
||||
|
|
@ -108,12 +109,20 @@ impl QueryContext for QueryCtxt<'_> {
|
|||
if complete { Ok(jobs) } else { Err(jobs) }
|
||||
}
|
||||
|
||||
fn lift_query_info(
|
||||
self,
|
||||
info: &QueryStackDeferred<'tcx>,
|
||||
) -> rustc_query_system::query::QueryStackFrameExtra {
|
||||
info.extract()
|
||||
}
|
||||
|
||||
// Interactions with on_disk_cache
|
||||
fn load_side_effect(
|
||||
self,
|
||||
prev_dep_node_index: SerializedDepNodeIndex,
|
||||
) -> Option<QuerySideEffect> {
|
||||
self.query_system
|
||||
self.tcx
|
||||
.query_system
|
||||
.on_disk_cache
|
||||
.as_ref()
|
||||
.and_then(|c| c.load_side_effect(self.tcx, prev_dep_node_index))
|
||||
|
|
@ -122,7 +131,7 @@ impl QueryContext for QueryCtxt<'_> {
|
|||
#[inline(never)]
|
||||
#[cold]
|
||||
fn store_side_effect(self, dep_node_index: DepNodeIndex, side_effect: QuerySideEffect) {
|
||||
if let Some(c) = self.query_system.on_disk_cache.as_ref() {
|
||||
if let Some(c) = self.tcx.query_system.on_disk_cache.as_ref() {
|
||||
c.store_side_effect(dep_node_index, side_effect)
|
||||
}
|
||||
}
|
||||
|
|
@ -140,7 +149,9 @@ impl QueryContext for QueryCtxt<'_> {
|
|||
// as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
|
||||
// when accessing the `ImplicitCtxt`.
|
||||
tls::with_related_context(self.tcx, move |current_icx| {
|
||||
if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
|
||||
if depth_limit
|
||||
&& !self.tcx.recursion_limit().value_within_limit(current_icx.query_depth)
|
||||
{
|
||||
self.depth_limit_error(token);
|
||||
}
|
||||
|
||||
|
|
@ -161,16 +172,19 @@ impl QueryContext for QueryCtxt<'_> {
|
|||
let query_map = self.collect_active_jobs(true).expect("failed to collect active queries");
|
||||
let (info, depth) = job.find_dep_kind_root(query_map);
|
||||
|
||||
let suggested_limit = match self.recursion_limit() {
|
||||
let suggested_limit = match self.tcx.recursion_limit() {
|
||||
Limit(0) => Limit(2),
|
||||
limit => limit * 2,
|
||||
};
|
||||
|
||||
self.sess.dcx().emit_fatal(QueryOverflow {
|
||||
self.tcx.sess.dcx().emit_fatal(QueryOverflow {
|
||||
span: info.job.span,
|
||||
note: QueryOverflowNote { desc: info.query.description, depth },
|
||||
note: QueryOverflowNote {
|
||||
desc: self.lift_query_info(&info.query.info).description,
|
||||
depth,
|
||||
},
|
||||
suggested_limit,
|
||||
crate_name: self.crate_name(LOCAL_CRATE),
|
||||
crate_name: self.tcx.crate_name(LOCAL_CRATE),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -305,16 +319,17 @@ macro_rules! should_ever_cache_on_disk {
|
|||
};
|
||||
}
|
||||
|
||||
pub(crate) fn create_query_frame<
|
||||
'tcx,
|
||||
K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
|
||||
>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
do_describe: fn(TyCtxt<'tcx>, K) -> String,
|
||||
key: K,
|
||||
kind: DepKind,
|
||||
name: &'static str,
|
||||
) -> QueryStackFrame {
|
||||
fn create_query_frame_extra<'tcx, K: Key + Copy + 'tcx>(
|
||||
(tcx, key, kind, name, do_describe): (
|
||||
TyCtxt<'tcx>,
|
||||
K,
|
||||
DepKind,
|
||||
&'static str,
|
||||
fn(TyCtxt<'tcx>, K) -> String,
|
||||
),
|
||||
) -> QueryStackFrameExtra {
|
||||
let def_id = key.key_as_def_id();
|
||||
|
||||
// If reduced queries are requested, we may be printing a query stack due
|
||||
// to a panic. Avoid using `default_span` and `def_kind` in that case.
|
||||
let reduce_queries = with_reduced_queries();
|
||||
|
|
@ -326,36 +341,49 @@ pub(crate) fn create_query_frame<
|
|||
} else {
|
||||
description
|
||||
};
|
||||
|
||||
let span = if reduce_queries {
|
||||
let span = if kind == dep_graph::dep_kinds::def_span || reduce_queries {
|
||||
// The `def_span` query is used to calculate `default_span`,
|
||||
// so exit to avoid infinite recursion.
|
||||
None
|
||||
} else {
|
||||
Some(tcx.with_reduced_queries(|| key.default_span(tcx)))
|
||||
Some(key.default_span(tcx))
|
||||
};
|
||||
|
||||
let def_id = key.key_as_def_id();
|
||||
|
||||
let def_kind = if reduce_queries {
|
||||
let def_kind = if kind == dep_graph::dep_kinds::def_kind || reduce_queries {
|
||||
// Try to avoid infinite recursion.
|
||||
None
|
||||
} else {
|
||||
def_id
|
||||
.and_then(|def_id| def_id.as_local())
|
||||
.map(|def_id| tcx.with_reduced_queries(|| tcx.def_kind(def_id)))
|
||||
def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id))
|
||||
};
|
||||
QueryStackFrameExtra::new(description, span, def_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn create_query_frame<
|
||||
'tcx,
|
||||
K: Copy + DynSend + DynSync + Key + for<'a> HashStable<StableHashingContext<'a>> + 'tcx,
|
||||
>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
do_describe: fn(TyCtxt<'tcx>, K) -> String,
|
||||
key: K,
|
||||
kind: DepKind,
|
||||
name: &'static str,
|
||||
) -> QueryStackFrame<QueryStackDeferred<'tcx>> {
|
||||
let def_id = key.key_as_def_id();
|
||||
|
||||
let hash = || {
|
||||
tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
kind.as_usize().hash_stable(&mut hcx, &mut hasher);
|
||||
key.hash_stable(&mut hcx, &mut hasher);
|
||||
hasher.finish::<Hash64>()
|
||||
})
|
||||
};
|
||||
let def_id_for_ty_in_cycle = key.def_id_for_ty_in_cycle();
|
||||
|
||||
let hash = tcx.with_stable_hashing_context(|mut hcx| {
|
||||
let mut hasher = StableHasher::new();
|
||||
kind.as_usize().hash_stable(&mut hcx, &mut hasher);
|
||||
key.hash_stable(&mut hcx, &mut hasher);
|
||||
hasher.finish::<Hash64>()
|
||||
});
|
||||
let info =
|
||||
QueryStackDeferred::new((tcx, key, kind, name, do_describe), create_query_frame_extra);
|
||||
|
||||
QueryStackFrame::new(description, span, def_id, def_kind, kind, def_id_for_ty_in_cycle, hash)
|
||||
QueryStackFrame::new(info, kind, hash, def_id, def_id_for_ty_in_cycle)
|
||||
}
|
||||
|
||||
pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
||||
|
|
@ -367,7 +395,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>(
|
|||
Q: super::QueryConfigRestored<'tcx>,
|
||||
Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
|
||||
{
|
||||
let _timer = qcx.profiler().generic_activity_with_arg("encode_query_results_for", query.name());
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("encode_query_results_for", query.name());
|
||||
|
||||
assert!(query.query_state(qcx).all_inactive());
|
||||
let cache = query.query_cache(qcx);
|
||||
|
|
@ -389,8 +417,7 @@ pub(crate) fn query_key_hash_verify<'tcx>(
|
|||
query: impl QueryConfig<QueryCtxt<'tcx>>,
|
||||
qcx: QueryCtxt<'tcx>,
|
||||
) {
|
||||
let _timer =
|
||||
qcx.profiler().generic_activity_with_arg("query_key_hash_verify_for", query.name());
|
||||
let _timer = qcx.tcx.prof.generic_activity_with_arg("query_key_hash_verify_for", query.name());
|
||||
|
||||
let mut map = UnordMap::default();
|
||||
|
||||
|
|
@ -710,7 +737,7 @@ macro_rules! define_queries {
|
|||
|
||||
pub(crate) fn collect_active_jobs<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
qmap: &mut QueryMap,
|
||||
qmap: &mut QueryMap<QueryStackDeferred<'tcx>>,
|
||||
require_complete: bool,
|
||||
) -> Option<()> {
|
||||
let make_query = |tcx, key| {
|
||||
|
|
@ -794,7 +821,7 @@ macro_rules! define_queries {
|
|||
// These arrays are used for iteration and can't be indexed by `DepKind`.
|
||||
|
||||
const COLLECT_ACTIVE_JOBS: &[
|
||||
for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap, bool) -> Option<()>
|
||||
for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<QueryStackDeferred<'tcx>>, bool) -> Option<()>
|
||||
] =
|
||||
&[$(query_impl::$name::collect_active_jobs),*];
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::hash::Hash;
|
|||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
|
||||
use super::QueryStackFrameExtra;
|
||||
use crate::dep_graph::{DepKind, DepNode, DepNodeParams, SerializedDepNodeIndex};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::query::caches::QueryCache;
|
||||
|
|
@ -26,7 +27,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
|
|||
fn format_value(self) -> fn(&Self::Value) -> String;
|
||||
|
||||
// Don't use this method to access query results, instead use the methods on TyCtxt
|
||||
fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key>
|
||||
fn query_state<'a>(self, tcx: Qcx) -> &'a QueryState<Self::Key, Qcx::QueryInfo>
|
||||
where
|
||||
Qcx: 'a;
|
||||
|
||||
|
|
@ -56,7 +57,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
|
|||
fn value_from_cycle_error(
|
||||
self,
|
||||
tcx: Qcx::DepContext,
|
||||
cycle_error: &CycleError,
|
||||
cycle_error: &CycleError<QueryStackFrameExtra>,
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self::Value;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::io::Write;
|
||||
use std::iter;
|
||||
|
|
@ -11,6 +12,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
|
||||
use super::QueryStackFrameExtra;
|
||||
use crate::dep_graph::DepContext;
|
||||
use crate::error::CycleStack;
|
||||
use crate::query::plumbing::CycleError;
|
||||
|
|
@ -18,45 +20,54 @@ use crate::query::{QueryContext, QueryStackFrame};
|
|||
|
||||
/// Represents a span and a query key.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryInfo {
|
||||
pub struct QueryInfo<I> {
|
||||
/// The span corresponding to the reason for which this query was required.
|
||||
pub span: Span,
|
||||
pub query: QueryStackFrame,
|
||||
pub query: QueryStackFrame<I>,
|
||||
}
|
||||
|
||||
pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
|
||||
impl<I> QueryInfo<I> {
|
||||
pub(crate) fn lift<Qcx: QueryContext<QueryInfo = I>>(
|
||||
&self,
|
||||
qcx: Qcx,
|
||||
) -> QueryInfo<QueryStackFrameExtra> {
|
||||
QueryInfo { span: self.span, query: self.query.lift(qcx) }
|
||||
}
|
||||
}
|
||||
|
||||
pub type QueryMap<I> = FxHashMap<QueryJobId, QueryJobInfo<I>>;
|
||||
|
||||
/// A value uniquely identifying an active query job.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct QueryJobId(pub NonZero<u64>);
|
||||
|
||||
impl QueryJobId {
|
||||
fn query(self, map: &QueryMap) -> QueryStackFrame {
|
||||
fn query<I: Clone>(self, map: &QueryMap<I>) -> QueryStackFrame<I> {
|
||||
map.get(&self).unwrap().query.clone()
|
||||
}
|
||||
|
||||
fn span(self, map: &QueryMap) -> Span {
|
||||
fn span<I>(self, map: &QueryMap<I>) -> Span {
|
||||
map.get(&self).unwrap().job.span
|
||||
}
|
||||
|
||||
fn parent(self, map: &QueryMap) -> Option<QueryJobId> {
|
||||
fn parent<I>(self, map: &QueryMap<I>) -> Option<QueryJobId> {
|
||||
map.get(&self).unwrap().job.parent
|
||||
}
|
||||
|
||||
fn latch(self, map: &QueryMap) -> Option<&QueryLatch> {
|
||||
fn latch<I>(self, map: &QueryMap<I>) -> Option<&QueryLatch<I>> {
|
||||
map.get(&self).unwrap().job.latch.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryJobInfo {
|
||||
pub query: QueryStackFrame,
|
||||
pub job: QueryJob,
|
||||
pub struct QueryJobInfo<I> {
|
||||
pub query: QueryStackFrame<I>,
|
||||
pub job: QueryJob<I>,
|
||||
}
|
||||
|
||||
/// Represents an active query job.
|
||||
#[derive(Debug)]
|
||||
pub struct QueryJob {
|
||||
pub struct QueryJob<I> {
|
||||
pub id: QueryJobId,
|
||||
|
||||
/// The span corresponding to the reason for which this query was required.
|
||||
|
|
@ -66,23 +77,23 @@ pub struct QueryJob {
|
|||
pub parent: Option<QueryJobId>,
|
||||
|
||||
/// The latch that is used to wait on this job.
|
||||
latch: Option<QueryLatch>,
|
||||
latch: Option<QueryLatch<I>>,
|
||||
}
|
||||
|
||||
impl Clone for QueryJob {
|
||||
impl<I> Clone for QueryJob<I> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { id: self.id, span: self.span, parent: self.parent, latch: self.latch.clone() }
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryJob {
|
||||
impl<I> QueryJob<I> {
|
||||
/// Creates a new query job.
|
||||
#[inline]
|
||||
pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
|
||||
QueryJob { id, span, parent, latch: None }
|
||||
}
|
||||
|
||||
pub(super) fn latch(&mut self) -> QueryLatch {
|
||||
pub(super) fn latch(&mut self) -> QueryLatch<I> {
|
||||
if self.latch.is_none() {
|
||||
self.latch = Some(QueryLatch::new());
|
||||
}
|
||||
|
|
@ -102,12 +113,12 @@ impl QueryJob {
|
|||
}
|
||||
|
||||
impl QueryJobId {
|
||||
pub(super) fn find_cycle_in_stack(
|
||||
pub(super) fn find_cycle_in_stack<I: Clone>(
|
||||
&self,
|
||||
query_map: QueryMap,
|
||||
query_map: QueryMap<I>,
|
||||
current_job: &Option<QueryJobId>,
|
||||
span: Span,
|
||||
) -> CycleError {
|
||||
) -> CycleError<I> {
|
||||
// Find the waitee amongst `current_job` parents
|
||||
let mut cycle = Vec::new();
|
||||
let mut current_job = Option::clone(current_job);
|
||||
|
|
@ -141,7 +152,7 @@ impl QueryJobId {
|
|||
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
pub fn find_dep_kind_root(&self, query_map: QueryMap) -> (QueryJobInfo, usize) {
|
||||
pub fn find_dep_kind_root<I: Clone>(&self, query_map: QueryMap<I>) -> (QueryJobInfo<I>, usize) {
|
||||
let mut depth = 1;
|
||||
let info = query_map.get(&self).unwrap();
|
||||
let dep_kind = info.query.dep_kind;
|
||||
|
|
@ -161,31 +172,31 @@ impl QueryJobId {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct QueryWaiter {
|
||||
struct QueryWaiter<I> {
|
||||
query: Option<QueryJobId>,
|
||||
condvar: Condvar,
|
||||
span: Span,
|
||||
cycle: Mutex<Option<CycleError>>,
|
||||
cycle: Mutex<Option<CycleError<I>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct QueryLatchInfo {
|
||||
struct QueryLatchInfo<I> {
|
||||
complete: bool,
|
||||
waiters: Vec<Arc<QueryWaiter>>,
|
||||
waiters: Vec<Arc<QueryWaiter<I>>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct QueryLatch {
|
||||
info: Arc<Mutex<QueryLatchInfo>>,
|
||||
pub(super) struct QueryLatch<I> {
|
||||
info: Arc<Mutex<QueryLatchInfo<I>>>,
|
||||
}
|
||||
|
||||
impl Clone for QueryLatch {
|
||||
impl<I> Clone for QueryLatch<I> {
|
||||
fn clone(&self) -> Self {
|
||||
Self { info: Arc::clone(&self.info) }
|
||||
}
|
||||
}
|
||||
|
||||
impl QueryLatch {
|
||||
impl<I> QueryLatch<I> {
|
||||
fn new() -> Self {
|
||||
QueryLatch {
|
||||
info: Arc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
|
||||
|
|
@ -198,7 +209,7 @@ impl QueryLatch {
|
|||
qcx: impl QueryContext,
|
||||
query: Option<QueryJobId>,
|
||||
span: Span,
|
||||
) -> Result<(), CycleError> {
|
||||
) -> Result<(), CycleError<I>> {
|
||||
let waiter =
|
||||
Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() });
|
||||
self.wait_on_inner(qcx, &waiter);
|
||||
|
|
@ -213,7 +224,7 @@ impl QueryLatch {
|
|||
}
|
||||
|
||||
/// Awaits the caller on this latch by blocking the current thread.
|
||||
fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc<QueryWaiter>) {
|
||||
fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc<QueryWaiter<I>>) {
|
||||
let mut info = self.info.lock();
|
||||
if !info.complete {
|
||||
// We push the waiter on to the `waiters` list. It can be accessed inside
|
||||
|
|
@ -249,7 +260,7 @@ impl QueryLatch {
|
|||
|
||||
/// Removes a single waiter from the list of waiters.
|
||||
/// This is used to break query cycles.
|
||||
fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter> {
|
||||
fn extract_waiter(&self, waiter: usize) -> Arc<QueryWaiter<I>> {
|
||||
let mut info = self.info.lock();
|
||||
debug_assert!(!info.complete);
|
||||
// Remove the waiter from the list of waiters
|
||||
|
|
@ -269,7 +280,11 @@ type Waiter = (QueryJobId, usize);
|
|||
/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the
|
||||
/// required information to resume the waiter.
|
||||
/// If all `visit` calls returns None, this function also returns None.
|
||||
fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>>
|
||||
fn visit_waiters<I, F>(
|
||||
query_map: &QueryMap<I>,
|
||||
query: QueryJobId,
|
||||
mut visit: F,
|
||||
) -> Option<Option<Waiter>>
|
||||
where
|
||||
F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
|
||||
{
|
||||
|
|
@ -299,8 +314,8 @@ where
|
|||
/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP.
|
||||
/// If a cycle is detected, this initial value is replaced with the span causing
|
||||
/// the cycle.
|
||||
fn cycle_check(
|
||||
query_map: &QueryMap,
|
||||
fn cycle_check<I>(
|
||||
query_map: &QueryMap<I>,
|
||||
query: QueryJobId,
|
||||
span: Span,
|
||||
stack: &mut Vec<(Span, QueryJobId)>,
|
||||
|
|
@ -339,8 +354,8 @@ fn cycle_check(
|
|||
/// Finds out if there's a path to the compiler root (aka. code which isn't in a query)
|
||||
/// from `query` without going through any of the queries in `visited`.
|
||||
/// This is achieved with a depth first search.
|
||||
fn connected_to_root(
|
||||
query_map: &QueryMap,
|
||||
fn connected_to_root<I>(
|
||||
query_map: &QueryMap<I>,
|
||||
query: QueryJobId,
|
||||
visited: &mut FxHashSet<QueryJobId>,
|
||||
) -> bool {
|
||||
|
|
@ -361,7 +376,7 @@ fn connected_to_root(
|
|||
}
|
||||
|
||||
// Deterministically pick an query from a list
|
||||
fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T
|
||||
fn pick_query<'a, I: Clone, T, F>(query_map: &QueryMap<I>, queries: &'a [T], f: F) -> &'a T
|
||||
where
|
||||
F: Fn(&T) -> (Span, QueryJobId),
|
||||
{
|
||||
|
|
@ -386,10 +401,10 @@ where
|
|||
/// the function return true.
|
||||
/// If a cycle was not found, the starting query is removed from `jobs` and
|
||||
/// the function returns false.
|
||||
fn remove_cycle(
|
||||
query_map: &QueryMap,
|
||||
fn remove_cycle<I: Clone>(
|
||||
query_map: &QueryMap<I>,
|
||||
jobs: &mut Vec<QueryJobId>,
|
||||
wakelist: &mut Vec<Arc<QueryWaiter>>,
|
||||
wakelist: &mut Vec<Arc<QueryWaiter<I>>>,
|
||||
) -> bool {
|
||||
let mut visited = FxHashSet::default();
|
||||
let mut stack = Vec::new();
|
||||
|
|
@ -490,7 +505,10 @@ fn remove_cycle(
|
|||
/// uses a query latch and then resuming that waiter.
|
||||
/// There may be multiple cycles involved in a deadlock, so this searches
|
||||
/// all active queries for cycles before finally resuming all the waiters at once.
|
||||
pub fn break_query_cycles(query_map: QueryMap, registry: &rustc_thread_pool::Registry) {
|
||||
pub fn break_query_cycles<I: Clone + Debug>(
|
||||
query_map: QueryMap<I>,
|
||||
registry: &rustc_thread_pool::Registry,
|
||||
) {
|
||||
let mut wakelist = Vec::new();
|
||||
// It is OK per the comments:
|
||||
// - https://github.com/rust-lang/rust/pull/131200#issuecomment-2798854932
|
||||
|
|
@ -541,7 +559,7 @@ pub fn report_cycle<'a>(
|
|||
) -> Diag<'a> {
|
||||
assert!(!stack.is_empty());
|
||||
|
||||
let span = stack[0].query.default_span(stack[1 % stack.len()].span);
|
||||
let span = stack[0].query.info.default_span(stack[1 % stack.len()].span);
|
||||
|
||||
let mut cycle_stack = Vec::new();
|
||||
|
||||
|
|
@ -550,31 +568,31 @@ pub fn report_cycle<'a>(
|
|||
|
||||
for i in 1..stack.len() {
|
||||
let query = &stack[i].query;
|
||||
let span = query.default_span(stack[(i + 1) % stack.len()].span);
|
||||
cycle_stack.push(CycleStack { span, desc: query.description.to_owned() });
|
||||
let span = query.info.default_span(stack[(i + 1) % stack.len()].span);
|
||||
cycle_stack.push(CycleStack { span, desc: query.info.description.to_owned() });
|
||||
}
|
||||
|
||||
let mut cycle_usage = None;
|
||||
if let Some((span, ref query)) = *usage {
|
||||
cycle_usage = Some(crate::error::CycleUsage {
|
||||
span: query.default_span(span),
|
||||
usage: query.description.to_string(),
|
||||
span: query.info.default_span(span),
|
||||
usage: query.info.description.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
let alias = if stack.iter().all(|entry| matches!(entry.query.def_kind, Some(DefKind::TyAlias)))
|
||||
{
|
||||
Some(crate::error::Alias::Ty)
|
||||
} else if stack.iter().all(|entry| entry.query.def_kind == Some(DefKind::TraitAlias)) {
|
||||
Some(crate::error::Alias::Trait)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let alias =
|
||||
if stack.iter().all(|entry| matches!(entry.query.info.def_kind, Some(DefKind::TyAlias))) {
|
||||
Some(crate::error::Alias::Ty)
|
||||
} else if stack.iter().all(|entry| entry.query.info.def_kind == Some(DefKind::TraitAlias)) {
|
||||
Some(crate::error::Alias::Trait)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let cycle_diag = crate::error::Cycle {
|
||||
span,
|
||||
cycle_stack,
|
||||
stack_bottom: stack[0].query.description.to_owned(),
|
||||
stack_bottom: stack[0].query.info.description.to_owned(),
|
||||
alias,
|
||||
cycle_usage,
|
||||
stack_count,
|
||||
|
|
@ -610,11 +628,12 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
let Some(query_info) = query_map.get(&query) else {
|
||||
break;
|
||||
};
|
||||
let query_extra = qcx.lift_query_info(&query_info.query.info);
|
||||
if Some(count_printed) < limit_frames || limit_frames.is_none() {
|
||||
// Only print to stderr as many stack frames as `num_frames` when present.
|
||||
dcx.struct_failure_note(format!(
|
||||
"#{} [{:?}] {}",
|
||||
count_printed, query_info.query.dep_kind, query_info.query.description
|
||||
count_printed, query_info.query.dep_kind, query_extra.description
|
||||
))
|
||||
.with_span(query_info.job.span)
|
||||
.emit();
|
||||
|
|
@ -627,7 +646,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
|
|||
"#{} [{}] {}",
|
||||
count_total,
|
||||
qcx.dep_context().dep_kind_vtable(query_info.query.dep_kind).name,
|
||||
query_info.query.description
|
||||
query_extra.description
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::transmute;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_data_structures::jobserver::Proxy;
|
||||
use rustc_data_structures::sync::{DynSend, DynSync};
|
||||
use rustc_errors::DiagInner;
|
||||
use rustc_hashes::Hash64;
|
||||
use rustc_hir::def::DefKind;
|
||||
|
|
@ -36,31 +42,59 @@ pub enum CycleErrorHandling {
|
|||
///
|
||||
/// This is mostly used in case of cycles for error reporting.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryStackFrame {
|
||||
pub description: String,
|
||||
span: Option<Span>,
|
||||
pub def_id: Option<DefId>,
|
||||
pub def_kind: Option<DefKind>,
|
||||
/// A def-id that is extracted from a `Ty` in a query key
|
||||
pub def_id_for_ty_in_cycle: Option<DefId>,
|
||||
pub struct QueryStackFrame<I> {
|
||||
/// This field initially stores a `QueryStackDeferred` during collection,
|
||||
/// but can later be changed to `QueryStackFrameExtra` containing concrete information
|
||||
/// by calling `lift`. This is done so that collecting query does not need to invoke
|
||||
/// queries, instead `lift` will call queries in a more appropriate location.
|
||||
pub info: I,
|
||||
|
||||
pub dep_kind: DepKind,
|
||||
/// This hash is used to deterministically pick
|
||||
/// a query to remove cycles in the parallel compiler.
|
||||
hash: Hash64,
|
||||
pub def_id: Option<DefId>,
|
||||
/// A def-id that is extracted from a `Ty` in a query key
|
||||
pub def_id_for_ty_in_cycle: Option<DefId>,
|
||||
}
|
||||
|
||||
impl QueryStackFrame {
|
||||
impl<I> QueryStackFrame<I> {
|
||||
#[inline]
|
||||
pub fn new(
|
||||
description: String,
|
||||
span: Option<Span>,
|
||||
def_id: Option<DefId>,
|
||||
def_kind: Option<DefKind>,
|
||||
info: I,
|
||||
dep_kind: DepKind,
|
||||
hash: impl FnOnce() -> Hash64,
|
||||
def_id: Option<DefId>,
|
||||
def_id_for_ty_in_cycle: Option<DefId>,
|
||||
hash: Hash64,
|
||||
) -> Self {
|
||||
Self { description, span, def_id, def_kind, def_id_for_ty_in_cycle, dep_kind, hash }
|
||||
Self { info, def_id, dep_kind, hash: hash(), def_id_for_ty_in_cycle }
|
||||
}
|
||||
|
||||
fn lift<Qcx: QueryContext<QueryInfo = I>>(
|
||||
&self,
|
||||
qcx: Qcx,
|
||||
) -> QueryStackFrame<QueryStackFrameExtra> {
|
||||
QueryStackFrame {
|
||||
info: qcx.lift_query_info(&self.info),
|
||||
dep_kind: self.dep_kind,
|
||||
hash: self.hash,
|
||||
def_id: self.def_id,
|
||||
def_id_for_ty_in_cycle: self.def_id_for_ty_in_cycle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryStackFrameExtra {
|
||||
pub description: String,
|
||||
span: Option<Span>,
|
||||
pub def_kind: Option<DefKind>,
|
||||
}
|
||||
|
||||
impl QueryStackFrameExtra {
|
||||
#[inline]
|
||||
pub fn new(description: String, span: Option<Span>, def_kind: Option<DefKind>) -> Self {
|
||||
Self { description, span, def_kind }
|
||||
}
|
||||
|
||||
// FIXME(eddyb) Get more valid `Span`s on queries.
|
||||
|
|
@ -73,6 +107,40 @@ impl QueryStackFrame {
|
|||
}
|
||||
}
|
||||
|
||||
/// Track a 'side effect' for a particular query.
|
||||
/// This is used to hold a closure which can create `QueryStackFrameExtra`.
|
||||
#[derive(Clone)]
|
||||
pub struct QueryStackDeferred<'tcx> {
|
||||
_dummy: PhantomData<&'tcx ()>,
|
||||
|
||||
// `extract` may contain references to 'tcx, but we can't tell drop checking that it won't
|
||||
// access it in the destructor.
|
||||
extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend>,
|
||||
}
|
||||
|
||||
impl<'tcx> QueryStackDeferred<'tcx> {
|
||||
pub fn new<C: Copy + DynSync + DynSend + 'tcx>(
|
||||
context: C,
|
||||
extract: fn(C) -> QueryStackFrameExtra,
|
||||
) -> Self {
|
||||
let extract: Arc<dyn Fn() -> QueryStackFrameExtra + DynSync + DynSend + 'tcx> =
|
||||
Arc::new(move || extract(context));
|
||||
// SAFETY: The `extract` closure does not access 'tcx in its destructor as the only
|
||||
// captured variable is `context` which is Copy and cannot have a destructor.
|
||||
Self { _dummy: PhantomData, extract: unsafe { transmute(extract) } }
|
||||
}
|
||||
|
||||
pub fn extract(&self) -> QueryStackFrameExtra {
|
||||
(self.extract)()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for QueryStackDeferred<'tcx> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str("QueryStackDeferred")
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks 'side effects' for a particular query.
|
||||
/// This struct is saved to disk along with the query result,
|
||||
/// and loaded from disk if we mark the query as green.
|
||||
|
|
@ -92,6 +160,8 @@ pub enum QuerySideEffect {
|
|||
}
|
||||
|
||||
pub trait QueryContext: HasDepContext {
|
||||
type QueryInfo: Clone;
|
||||
|
||||
/// Gets a jobserver reference which is used to release then acquire
|
||||
/// a token while waiting on a query.
|
||||
fn jobserver_proxy(&self) -> &Proxy;
|
||||
|
|
@ -101,7 +171,12 @@ pub trait QueryContext: HasDepContext {
|
|||
/// Get the query information from the TLS context.
|
||||
fn current_query_job(self) -> Option<QueryJobId>;
|
||||
|
||||
fn collect_active_jobs(self, require_complete: bool) -> Result<QueryMap, QueryMap>;
|
||||
fn collect_active_jobs(
|
||||
self,
|
||||
require_complete: bool,
|
||||
) -> Result<QueryMap<Self::QueryInfo>, QueryMap<Self::QueryInfo>>;
|
||||
|
||||
fn lift_query_info(self, info: &Self::QueryInfo) -> QueryStackFrameExtra;
|
||||
|
||||
/// Load a side effect associated to the node in the previous session.
|
||||
fn load_side_effect(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_errors::{Diag, FatalError, StashKey};
|
|||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::instrument;
|
||||
|
||||
use super::QueryConfig;
|
||||
use super::{QueryConfig, QueryStackFrameExtra};
|
||||
use crate::dep_graph::{DepContext, DepGraphData, DepNode, DepNodeIndex, DepNodeParams};
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::query::caches::QueryCache;
|
||||
|
|
@ -32,23 +32,23 @@ fn equivalent_key<K: Eq, V>(k: &K) -> impl Fn(&(K, V)) -> bool + '_ {
|
|||
move |x| x.0 == *k
|
||||
}
|
||||
|
||||
pub struct QueryState<K> {
|
||||
active: Sharded<hashbrown::HashTable<(K, QueryResult)>>,
|
||||
pub struct QueryState<K, I> {
|
||||
active: Sharded<hashbrown::HashTable<(K, QueryResult<I>)>>,
|
||||
}
|
||||
|
||||
/// Indicates the state of a query for a given key in a query map.
|
||||
enum QueryResult {
|
||||
enum QueryResult<I> {
|
||||
/// An already executing query. The query job can be used to await for its completion.
|
||||
Started(QueryJob),
|
||||
Started(QueryJob<I>),
|
||||
|
||||
/// The query panicked. Queries trying to wait on this will raise a fatal error which will
|
||||
/// silently panic.
|
||||
Poisoned,
|
||||
}
|
||||
|
||||
impl QueryResult {
|
||||
impl<I> QueryResult<I> {
|
||||
/// Unwraps the query job expecting that it has started.
|
||||
fn expect_job(self) -> QueryJob {
|
||||
fn expect_job(self) -> QueryJob<I> {
|
||||
match self {
|
||||
Self::Started(job) => job,
|
||||
Self::Poisoned => {
|
||||
|
|
@ -58,7 +58,7 @@ impl QueryResult {
|
|||
}
|
||||
}
|
||||
|
||||
impl<K> QueryState<K>
|
||||
impl<K, I> QueryState<K, I>
|
||||
where
|
||||
K: Eq + Hash + Copy + Debug,
|
||||
{
|
||||
|
|
@ -69,13 +69,13 @@ where
|
|||
pub fn collect_active_jobs<Qcx: Copy>(
|
||||
&self,
|
||||
qcx: Qcx,
|
||||
make_query: fn(Qcx, K) -> QueryStackFrame,
|
||||
jobs: &mut QueryMap,
|
||||
make_query: fn(Qcx, K) -> QueryStackFrame<I>,
|
||||
jobs: &mut QueryMap<I>,
|
||||
require_complete: bool,
|
||||
) -> Option<()> {
|
||||
let mut active = Vec::new();
|
||||
|
||||
let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult)>>| {
|
||||
let mut collect = |iter: LockGuard<'_, HashTable<(K, QueryResult<I>)>>| {
|
||||
for (k, v) in iter.iter() {
|
||||
if let QueryResult::Started(ref job) = *v {
|
||||
active.push((*k, job.clone()));
|
||||
|
|
@ -106,19 +106,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<K> Default for QueryState<K> {
|
||||
fn default() -> QueryState<K> {
|
||||
impl<K, I> Default for QueryState<K, I> {
|
||||
fn default() -> QueryState<K, I> {
|
||||
QueryState { active: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
/// A type representing the responsibility to execute the job in the `job` field.
|
||||
/// This will poison the relevant query if dropped.
|
||||
struct JobOwner<'tcx, K>
|
||||
struct JobOwner<'tcx, K, I>
|
||||
where
|
||||
K: Eq + Hash + Copy,
|
||||
{
|
||||
state: &'tcx QueryState<K>,
|
||||
state: &'tcx QueryState<K, I>,
|
||||
key: K,
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ where
|
|||
}
|
||||
CycleErrorHandling::Stash => {
|
||||
let guar = if let Some(root) = cycle_error.cycle.first()
|
||||
&& let Some(span) = root.query.span
|
||||
&& let Some(span) = root.query.info.span
|
||||
{
|
||||
error.stash(span, StashKey::Cycle).unwrap()
|
||||
} else {
|
||||
|
|
@ -170,7 +170,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, K> JobOwner<'tcx, K>
|
||||
impl<'tcx, K, I> JobOwner<'tcx, K, I>
|
||||
where
|
||||
K: Eq + Hash + Copy,
|
||||
{
|
||||
|
|
@ -207,7 +207,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx, K> Drop for JobOwner<'tcx, K>
|
||||
impl<'tcx, K, I> Drop for JobOwner<'tcx, K, I>
|
||||
where
|
||||
K: Eq + Hash + Copy,
|
||||
{
|
||||
|
|
@ -235,10 +235,19 @@ where
|
|||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CycleError {
|
||||
pub struct CycleError<I = QueryStackFrameExtra> {
|
||||
/// The query and related span that uses the cycle.
|
||||
pub usage: Option<(Span, QueryStackFrame)>,
|
||||
pub cycle: Vec<QueryInfo>,
|
||||
pub usage: Option<(Span, QueryStackFrame<I>)>,
|
||||
pub cycle: Vec<QueryInfo<I>>,
|
||||
}
|
||||
|
||||
impl<I> CycleError<I> {
|
||||
fn lift<Qcx: QueryContext<QueryInfo = I>>(&self, qcx: Qcx) -> CycleError<QueryStackFrameExtra> {
|
||||
CycleError {
|
||||
usage: self.usage.as_ref().map(|(span, frame)| (*span, frame.lift(qcx))),
|
||||
cycle: self.cycle.iter().map(|info| info.lift(qcx)).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether there is already a value for this key in the in-memory
|
||||
|
|
@ -275,10 +284,10 @@ where
|
|||
{
|
||||
// Ensure there was no errors collecting all active jobs.
|
||||
// We need the complete map to ensure we find a cycle to break.
|
||||
let query_map = qcx.collect_active_jobs(false).expect("failed to collect active queries");
|
||||
let query_map = qcx.collect_active_jobs(false).ok().expect("failed to collect active queries");
|
||||
|
||||
let error = try_execute.find_cycle_in_stack(query_map, &qcx.current_query_job(), span);
|
||||
(mk_cycle(query, qcx, error), None)
|
||||
(mk_cycle(query, qcx, error.lift(qcx)), None)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -287,7 +296,7 @@ fn wait_for_query<Q, Qcx>(
|
|||
qcx: Qcx,
|
||||
span: Span,
|
||||
key: Q::Key,
|
||||
latch: QueryLatch,
|
||||
latch: QueryLatch<Qcx::QueryInfo>,
|
||||
current: Option<QueryJobId>,
|
||||
) -> (Q::Value, Option<DepNodeIndex>)
|
||||
where
|
||||
|
|
@ -327,7 +336,7 @@ where
|
|||
|
||||
(v, Some(index))
|
||||
}
|
||||
Err(cycle) => (mk_cycle(query, qcx, cycle), None),
|
||||
Err(cycle) => (mk_cycle(query, qcx, cycle.lift(qcx)), None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -405,7 +414,7 @@ where
|
|||
fn execute_job<Q, Qcx, const INCR: bool>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
state: &QueryState<Q::Key>,
|
||||
state: &QueryState<Q::Key, Qcx::QueryInfo>,
|
||||
key: Q::Key,
|
||||
key_hash: u64,
|
||||
id: QueryJobId,
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
orig_ctxt: Span,
|
||||
derive_fallback_lint_id: Option<NodeId>,
|
||||
mut visitor: impl FnMut(
|
||||
&mut CmResolver<'r, 'ra, 'tcx>,
|
||||
CmResolver<'_, 'ra, 'tcx>,
|
||||
Scope<'ra>,
|
||||
UsePrelude,
|
||||
Span,
|
||||
|
|
@ -165,7 +165,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
if visit {
|
||||
let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No };
|
||||
if let ControlFlow::Break(break_result) =
|
||||
visitor(&mut self, scope, use_prelude, ctxt)
|
||||
visitor(self.reborrow(), scope, use_prelude, ctxt)
|
||||
{
|
||||
return Some(break_result);
|
||||
}
|
||||
|
|
@ -438,7 +438,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
parent_scope,
|
||||
orig_ident.span,
|
||||
derive_fallback_lint_id,
|
||||
|this, scope, use_prelude, ctxt| {
|
||||
|mut this, scope, use_prelude, ctxt| {
|
||||
let ident = Ident::new(orig_ident.name, ctxt);
|
||||
// The passed `ctxt` is already normalized, so avoid expensive double normalization.
|
||||
let ident = Macros20NormalizedIdent(ident);
|
||||
|
|
|
|||
|
|
@ -893,7 +893,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
};
|
||||
|
||||
let mut indeterminate_count = 0;
|
||||
self.per_ns_cm(|this, ns| {
|
||||
self.per_ns_cm(|mut this, ns| {
|
||||
if !type_ns_only || ns == TypeNS {
|
||||
if bindings[ns].get() != PendingDecl::Pending {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1831,13 +1831,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
f(self, MacroNS);
|
||||
}
|
||||
|
||||
fn per_ns_cm<'r, F: FnMut(&mut CmResolver<'r, 'ra, 'tcx>, Namespace)>(
|
||||
fn per_ns_cm<'r, F: FnMut(CmResolver<'_, 'ra, 'tcx>, Namespace)>(
|
||||
mut self: CmResolver<'r, 'ra, 'tcx>,
|
||||
mut f: F,
|
||||
) {
|
||||
f(&mut self, TypeNS);
|
||||
f(&mut self, ValueNS);
|
||||
f(&mut self, MacroNS);
|
||||
f(self.reborrow(), TypeNS);
|
||||
f(self.reborrow(), ValueNS);
|
||||
f(self, MacroNS);
|
||||
}
|
||||
|
||||
fn is_builtin_macro(&self, res: Res) -> bool {
|
||||
|
|
@ -1902,7 +1902,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
}
|
||||
|
||||
let scope_set = ScopeSet::All(TypeNS);
|
||||
self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |this, scope, _, _| {
|
||||
self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |mut this, scope, _, _| {
|
||||
match scope {
|
||||
Scope::ModuleNonGlobs(module, _) => {
|
||||
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
|
||||
|
|
|
|||
|
|
@ -1322,6 +1322,7 @@ impl OutputFilenames {
|
|||
pub(crate) fn parse_remap_path_scope(
|
||||
early_dcx: &EarlyDiagCtxt,
|
||||
matches: &getopts::Matches,
|
||||
unstable_opts: &UnstableOptions,
|
||||
) -> RemapPathScopeComponents {
|
||||
if let Some(v) = matches.opt_str("remap-path-scope") {
|
||||
let mut slot = RemapPathScopeComponents::empty();
|
||||
|
|
@ -1329,11 +1330,18 @@ pub(crate) fn parse_remap_path_scope(
|
|||
slot |= match s {
|
||||
"macro" => RemapPathScopeComponents::MACRO,
|
||||
"diagnostics" => RemapPathScopeComponents::DIAGNOSTICS,
|
||||
"documentation" => {
|
||||
if !unstable_opts.unstable_options {
|
||||
early_dcx.early_fatal("remapping `documentation` path scope requested but `-Zunstable-options` not specified");
|
||||
}
|
||||
|
||||
RemapPathScopeComponents::DOCUMENTATION
|
||||
},
|
||||
"debuginfo" => RemapPathScopeComponents::DEBUGINFO,
|
||||
"coverage" => RemapPathScopeComponents::COVERAGE,
|
||||
"object" => RemapPathScopeComponents::OBJECT,
|
||||
"all" => RemapPathScopeComponents::all(),
|
||||
_ => early_dcx.early_fatal("argument for `--remap-path-scope` must be a comma separated list of scopes: `macro`, `diagnostics`, `debuginfo`, `coverage`, `object`, `all`"),
|
||||
_ => early_dcx.early_fatal("argument for `--remap-path-scope` must be a comma separated list of scopes: `macro`, `diagnostics`, `documentation`, `debuginfo`, `coverage`, `object`, `all`"),
|
||||
}
|
||||
}
|
||||
slot
|
||||
|
|
@ -2677,7 +2685,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
|
|||
let externs = parse_externs(early_dcx, matches, &unstable_opts);
|
||||
|
||||
let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
|
||||
let remap_path_scope = parse_remap_path_scope(early_dcx, matches);
|
||||
let remap_path_scope = parse_remap_path_scope(early_dcx, matches, &unstable_opts);
|
||||
|
||||
let pretty = parse_pretty(early_dcx, &unstable_opts);
|
||||
|
||||
|
|
|
|||
|
|
@ -233,6 +233,8 @@ bitflags::bitflags! {
|
|||
const DEBUGINFO = 1 << 3;
|
||||
/// Apply remappings to coverage information
|
||||
const COVERAGE = 1 << 4;
|
||||
/// Apply remappings to documentation information
|
||||
const DOCUMENTATION = 1 << 5;
|
||||
|
||||
/// An alias for `macro`, `debuginfo` and `coverage`. This ensures all paths in compiled
|
||||
/// executables, libraries and objects are remapped but not elsewhere.
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@ symbols! {
|
|||
Into,
|
||||
IntoFuture,
|
||||
IntoIterator,
|
||||
IntoIteratorItem,
|
||||
IoBufRead,
|
||||
IoLines,
|
||||
IoRead,
|
||||
|
|
|
|||
|
|
@ -1709,6 +1709,8 @@ supported_targets! {
|
|||
("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
|
||||
("aarch64_be-unknown-none-softfloat", aarch64_be_unknown_none_softfloat),
|
||||
("aarch64-unknown-nuttx", aarch64_unknown_nuttx),
|
||||
("aarch64v8r-unknown-none", aarch64v8r_unknown_none),
|
||||
("aarch64v8r-unknown-none-softfloat", aarch64v8r_unknown_none_softfloat),
|
||||
|
||||
("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
use crate::spec::{
|
||||
Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
|
||||
TargetMetadata, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let opts = TargetOptions {
|
||||
// based off the aarch64-unknown-none target at time of addition
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(128),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
default_uwtable: true,
|
||||
|
||||
// deviations from aarch64-unknown-none: `+v8a` -> `+v8r`; `+v8r` implies `+neon`
|
||||
features: "+v8r,+strict-align".into(),
|
||||
..Default::default()
|
||||
};
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-none".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("Bare Armv8-R AArch64, hardfloat".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
},
|
||||
pointer_width: 64,
|
||||
// $ clang-21 -S -emit-llvm -target aarch64 -mcpu=cortex-r82 stub.c
|
||||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: Arch::AArch64,
|
||||
options: opts,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
use crate::spec::{
|
||||
Abi, Arch, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType,
|
||||
Target, TargetMetadata, TargetOptions,
|
||||
};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
let opts = TargetOptions {
|
||||
abi: Abi::SoftFloat,
|
||||
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
|
||||
linker: Some("rust-lld".into()),
|
||||
relocation_model: RelocModel::Static,
|
||||
disable_redzone: true,
|
||||
max_atomic_width: Some(128),
|
||||
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
|
||||
stack_probes: StackProbeType::Inline,
|
||||
panic_strategy: PanicStrategy::Abort,
|
||||
default_uwtable: true,
|
||||
|
||||
// deviations from aarch64-unknown-none: `+v8a` -> `+v8r`
|
||||
features: "+v8r,+strict-align,-neon".into(),
|
||||
..Default::default()
|
||||
};
|
||||
Target {
|
||||
llvm_target: "aarch64-unknown-none".into(),
|
||||
metadata: TargetMetadata {
|
||||
description: Some("Bare Armv8-R AArch64, softfloat".into()),
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(false),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
arch: Arch::AArch64,
|
||||
options: opts,
|
||||
}
|
||||
}
|
||||
|
|
@ -4390,6 +4390,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
path_segment: &hir::PathSegment<'_>,
|
||||
args: &[hir::Expr<'_>],
|
||||
prev_ty: Ty<'_>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let tcx = self.tcx;
|
||||
|
|
@ -4403,6 +4404,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
let TypeError::Sorts(expected_found) = diff else {
|
||||
continue;
|
||||
};
|
||||
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::iter
|
||||
&& self.can_eq(
|
||||
param_env,
|
||||
Ty::new_ref(
|
||||
tcx,
|
||||
tcx.lifetimes.re_erased,
|
||||
expected_found.found,
|
||||
ty::Mutability::Not,
|
||||
),
|
||||
*ty,
|
||||
)
|
||||
&& let [] = args
|
||||
{
|
||||
// Used `.iter()` when `.into_iter()` was likely meant.
|
||||
err.span_suggestion_verbose(
|
||||
path_segment.ident.span,
|
||||
format!("consider consuming the `{prev_ty}` to construct the `Iterator`"),
|
||||
"into_iter".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if tcx.is_diagnostic_item(sym::IntoIteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::into_iter
|
||||
&& self.can_eq(
|
||||
param_env,
|
||||
expected_found.found,
|
||||
Ty::new_ref(tcx, tcx.lifetimes.re_erased, *ty, ty::Mutability::Not),
|
||||
)
|
||||
&& let [] = args
|
||||
{
|
||||
// Used `.into_iter()` when `.iter()` was likely meant.
|
||||
err.span_suggestion_verbose(
|
||||
path_segment.ident.span,
|
||||
format!(
|
||||
"consider not consuming the `{prev_ty}` to construct the `Iterator`"
|
||||
),
|
||||
"iter".to_string(),
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
if tcx.is_diagnostic_item(sym::IteratorItem, *def_id)
|
||||
&& path_segment.ident.name == sym::map
|
||||
&& self.can_eq(param_env, expected_found.found, *ty)
|
||||
|
|
@ -4515,6 +4557,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
expr = rcvr_expr;
|
||||
let assocs_in_this_method =
|
||||
self.probe_assoc_types_at_expr(&type_diffs, span, prev_ty, expr.hir_id, param_env);
|
||||
prev_ty = self.resolve_vars_if_possible(
|
||||
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
|
||||
);
|
||||
self.look_for_iterator_item_mistakes(
|
||||
&assocs_in_this_method,
|
||||
typeck_results,
|
||||
|
|
@ -4522,12 +4567,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
param_env,
|
||||
path_segment,
|
||||
args,
|
||||
prev_ty,
|
||||
err,
|
||||
);
|
||||
assocs.push(assocs_in_this_method);
|
||||
prev_ty = self.resolve_vars_if_possible(
|
||||
typeck_results.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(tcx)),
|
||||
);
|
||||
|
||||
if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
|
||||
&& let hir::Path { res: Res::Local(hir_id), .. } = path
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use std::hash::BuildHasherDefault;
|
||||
|
||||
pub use ena::unify::{NoError, UnifyKey, UnifyValue};
|
||||
use rustc_hash::FxHasher;
|
||||
use rustc_hash::FxBuildHasher;
|
||||
pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
|
||||
|
||||
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, BuildHasherDefault<FxHasher>>;
|
||||
pub type IndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
|
||||
pub type IndexMap<K, V> = indexmap::IndexMap<K, V, FxBuildHasher>;
|
||||
pub type IndexSet<V> = indexmap::IndexSet<V, FxBuildHasher>;
|
||||
|
||||
mod delayed_map;
|
||||
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ dependencies = [
|
|||
"vex-sdk",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi 0.14.4+wasi-0.2.4",
|
||||
"windows-targets 0.0.0",
|
||||
"windows-link 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -427,6 +427,10 @@ dependencies = [
|
|||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
|
|
@ -439,20 +443,16 @@ version = "0.60.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.5",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows-link 0.2.1",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ members = [
|
|||
exclude = [
|
||||
# stdarch has its own Cargo workspace
|
||||
"stdarch",
|
||||
"windows_targets"
|
||||
"windows_link"
|
||||
]
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ use alloc::rc::Rc;
|
|||
use alloc::sync::Arc;
|
||||
use core::assert_matches;
|
||||
use core::ffi::{CStr, FromBytesUntilNulError, c_char};
|
||||
#[allow(deprecated)]
|
||||
use core::hash::SipHasher13 as DefaultHasher;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::hash::{Hash, Hasher, SipHasher13 as DefaultHasher};
|
||||
|
||||
#[test]
|
||||
fn c_to_rust() {
|
||||
|
|
@ -57,11 +55,9 @@ fn equal_hash() {
|
|||
let ptr = data.as_ptr() as *const c_char;
|
||||
let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
|
||||
|
||||
#[allow(deprecated)]
|
||||
let mut s = DefaultHasher::new();
|
||||
cstr.hash(&mut s);
|
||||
let cstr_hash = s.finish();
|
||||
#[allow(deprecated)]
|
||||
let mut s = DefaultHasher::new();
|
||||
CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s);
|
||||
let cstring_hash = s.finish();
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit b65ab935fb2e0d59dba8966ffca09c9cc5a5f57c
|
||||
Subproject commit 28ec93b503bf0410745bc3d571bf3dc1caac3019
|
||||
|
|
@ -13,8 +13,14 @@ macro_rules! impl_general_format {
|
|||
($($t:ident)*) => {
|
||||
$(impl GeneralFormat for $t {
|
||||
fn already_rounded_value_should_use_exponential(&self) -> bool {
|
||||
// `max_abs` rounds to infinity for `f16`. This is fine to save us from a more
|
||||
// complex macro, it just means a positive-exponent `f16` will never print as
|
||||
// scientific notation by default (reasonably, the max is 65504.0).
|
||||
#[allow(overflowing_literals)]
|
||||
let max_abs = 1e+16;
|
||||
|
||||
let abs = $t::abs(*self);
|
||||
(abs != 0.0 && abs < 1e-4) || abs >= 1e+16
|
||||
(abs != 0.0 && abs < 1e-4) || abs >= max_abs
|
||||
}
|
||||
})*
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@
|
|||
#[allow(deprecated)]
|
||||
pub use self::sip::SipHasher;
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
#[allow(deprecated)]
|
||||
#[doc(hidden)]
|
||||
pub use self::sip::SipHasher13;
|
||||
use crate::{fmt, marker};
|
||||
|
|
|
|||
|
|
@ -11,8 +11,11 @@ use crate::{cmp, ptr};
|
|||
/// (e.g., `collections::HashMap` uses it by default).
|
||||
///
|
||||
/// See: <https://github.com/veorq/SipHash>
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
|
||||
#[unstable(
|
||||
feature = "hashmap_internals",
|
||||
issue = "none",
|
||||
reason = "use `std::hash::DefaultHasher` instead"
|
||||
)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
#[doc(hidden)]
|
||||
pub struct SipHasher13 {
|
||||
|
|
@ -23,7 +26,6 @@ pub struct SipHasher13 {
|
|||
///
|
||||
/// See: <https://github.com/veorq/SipHash>
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
struct SipHasher24 {
|
||||
hasher: Hasher<Sip24Rounds>,
|
||||
|
|
@ -137,8 +139,7 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
|||
out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
//FIXME(fee1-dead): use debug_assert_eq
|
||||
debug_assert!(i == len);
|
||||
debug_assert_eq!(i, len);
|
||||
out
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +168,6 @@ impl SipHasher13 {
|
|||
#[inline]
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
|
||||
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
|
||||
pub const fn new() -> SipHasher13 {
|
||||
SipHasher13::new_with_keys(0, 0)
|
||||
}
|
||||
|
|
@ -176,7 +176,6 @@ impl SipHasher13 {
|
|||
#[inline]
|
||||
#[unstable(feature = "hashmap_internals", issue = "none")]
|
||||
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
|
||||
#[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
|
||||
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
|
||||
SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ pub const fn must_use<T>(value: T) -> T {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "likely_unlikely", issue = "136873")]
|
||||
#[unstable(feature = "likely_unlikely", issue = "151619")]
|
||||
#[inline(always)]
|
||||
pub const fn likely(b: bool) -> bool {
|
||||
crate::intrinsics::likely(b)
|
||||
|
|
@ -708,7 +708,7 @@ pub const fn likely(b: bool) -> bool {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "likely_unlikely", issue = "136873")]
|
||||
#[unstable(feature = "likely_unlikely", issue = "151619")]
|
||||
#[inline(always)]
|
||||
pub const fn unlikely(b: bool) -> bool {
|
||||
crate::intrinsics::unlikely(b)
|
||||
|
|
@ -717,6 +717,10 @@ pub const fn unlikely(b: bool) -> bool {
|
|||
/// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may
|
||||
/// choose to optimize paths that are not cold at the expense of paths that are cold.
|
||||
///
|
||||
/// Note that like all hints, the exact effect to codegen is not guaranteed. Using `cold_path`
|
||||
/// can actually *decrease* performance if the branch is called more than expected. It is advisable
|
||||
/// to perform benchmarks to tell if this function is useful.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -741,6 +745,38 @@ pub const fn unlikely(b: bool) -> bool {
|
|||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// This can also be used to implement `likely` and `unlikely` helpers to hint the condition rather
|
||||
/// than the branch:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(cold_path)]
|
||||
/// use core::hint::cold_path;
|
||||
///
|
||||
/// #[inline(always)]
|
||||
/// pub const fn likely(b: bool) -> bool {
|
||||
/// if !b {
|
||||
/// cold_path();
|
||||
/// }
|
||||
/// b
|
||||
/// }
|
||||
///
|
||||
/// #[inline(always)]
|
||||
/// pub const fn unlikely(b: bool) -> bool {
|
||||
/// if b {
|
||||
/// cold_path();
|
||||
/// }
|
||||
/// b
|
||||
/// }
|
||||
///
|
||||
/// fn foo(x: i32) {
|
||||
/// if likely(x > 0) {
|
||||
/// println!("this branch is likely to be taken");
|
||||
/// } else {
|
||||
/// println!("this branch is unlikely to be taken");
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "cold_path", issue = "136873")]
|
||||
#[inline(always)]
|
||||
pub const fn cold_path() {
|
||||
|
|
|
|||
|
|
@ -281,6 +281,7 @@ pub trait FromIterator<A>: Sized {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait IntoIterator {
|
||||
/// The type of the elements being iterated over.
|
||||
#[rustc_diagnostic_item = "IntoIteratorItem"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type Item;
|
||||
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(target_feature_inline_always)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(transparent_unions)]
|
||||
#![feature(try_blocks)]
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
//! Implementations for `uN::gather_bits` and `uN::scatter_bits`
|
||||
//! Implementations for `uN::extract_bits` and `uN::deposit_bits`
|
||||
//!
|
||||
//! For the purposes of this implementation, the operations can be thought
|
||||
//! of as operating on the input bits as a list, starting from the least
|
||||
//! significant bit. Gathering is like `Vec::retain` that deletes bits
|
||||
//! where the mask has a zero. Scattering is like doing the inverse by
|
||||
//! inserting the zeros that gathering would delete.
|
||||
//! significant bit. Extraction is like `Vec::retain` that deletes bits
|
||||
//! where the mask has a zero. Deposition is like doing the inverse by
|
||||
//! inserting the zeros that extraction would delete.
|
||||
//!
|
||||
//! Key observation: Each bit that is gathered/scattered needs to be
|
||||
//! Key observation: Each extracted or deposited bit needs to be
|
||||
//! shifted by the count of zeros up to the corresponding mask bit.
|
||||
//!
|
||||
//! With that in mind, the general idea is to decompose the operation into
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
//! of the bits by `n = 1 << stage`. The masks for each stage are computed
|
||||
//! via prefix counts of zeros in the mask.
|
||||
//!
|
||||
//! # Gathering
|
||||
//! # Extraction
|
||||
//!
|
||||
//! Consider the input as a sequence of runs of data (bitstrings A,B,C,...),
|
||||
//! split by fixed-width groups of zeros ('.'), initially at width `n = 1`.
|
||||
|
|
@ -36,9 +36,9 @@
|
|||
//! ........abbbcccccddeghh
|
||||
//! ```
|
||||
//!
|
||||
//! # Scattering
|
||||
//! # Deposition
|
||||
//!
|
||||
//! For `scatter_bits`, the stages are reversed. We start with a single run of
|
||||
//! For `deposit_bits`, the stages are reversed. We start with a single run of
|
||||
//! data in the low bits. Each stage then splits each run of data in two by
|
||||
//! shifting part of it left by `n`, which is halved each stage.
|
||||
//! ```text
|
||||
|
|
@ -100,7 +100,7 @@ macro_rules! uint_impl {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(in super::super) const fn gather_impl(mut x: $U, sparse: $U) -> $U {
|
||||
pub(in super::super) const fn extract_impl(mut x: $U, sparse: $U) -> $U {
|
||||
let masks = prepare(sparse);
|
||||
x &= sparse;
|
||||
let mut stage = 0;
|
||||
|
|
@ -131,7 +131,7 @@ macro_rules! uint_impl {
|
|||
x
|
||||
}
|
||||
#[inline(always)]
|
||||
pub(in super::super) const fn scatter_impl(mut x: $U, sparse: $U) -> $U {
|
||||
pub(in super::super) const fn deposit_impl(mut x: $U, sparse: $U) -> $U {
|
||||
let masks = prepare(sparse);
|
||||
let mut stage = STAGES;
|
||||
while stage > 0 {
|
||||
|
|
|
|||
|
|
@ -507,15 +507,15 @@ macro_rules! uint_impl {
|
|||
/// #![feature(uint_gather_scatter_bits)]
|
||||
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b1011_1100;")]
|
||||
///
|
||||
/// assert_eq!(n.gather_bits(0b0010_0100), 0b0000_0011);
|
||||
/// assert_eq!(n.gather_bits(0xF0), 0b0000_1011);
|
||||
/// assert_eq!(n.extract_bits(0b0010_0100), 0b0000_0011);
|
||||
/// assert_eq!(n.extract_bits(0xF0), 0b0000_1011);
|
||||
/// ```
|
||||
#[unstable(feature = "uint_gather_scatter_bits", issue = "149069")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn gather_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::gather_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
pub const fn extract_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::extract_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
}
|
||||
|
||||
/// Returns an integer with the least significant bits of `self`
|
||||
|
|
@ -524,15 +524,15 @@ macro_rules! uint_impl {
|
|||
/// #![feature(uint_gather_scatter_bits)]
|
||||
#[doc = concat!("let n: ", stringify!($SelfT), " = 0b1010_1101;")]
|
||||
///
|
||||
/// assert_eq!(n.scatter_bits(0b0101_0101), 0b0101_0001);
|
||||
/// assert_eq!(n.scatter_bits(0xF0), 0b1101_0000);
|
||||
/// assert_eq!(n.deposit_bits(0b0101_0101), 0b0101_0001);
|
||||
/// assert_eq!(n.deposit_bits(0xF0), 0b1101_0000);
|
||||
/// ```
|
||||
#[unstable(feature = "uint_gather_scatter_bits", issue = "149069")]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub const fn scatter_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::scatter_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
pub const fn deposit_bits(self, mask: Self) -> Self {
|
||||
crate::num::int_bits::$ActualT::deposit_impl(self as $ActualT, mask as $ActualT) as $SelfT
|
||||
}
|
||||
|
||||
/// Reverses the order of bits in the integer. The least significant bit becomes the most significant bit,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! OS-specific functionality.
|
||||
|
||||
#![unstable(feature = "darwin_objc", issue = "145496")]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
#[cfg(all(
|
||||
doc,
|
||||
|
|
|
|||
|
|
@ -831,15 +831,13 @@
|
|||
//! <code>fn get_pin_mut(self: [Pin]<[`&mut Self`]>) -> [Pin]<[`&mut T`]></code>.
|
||||
//! Then we could do the following:
|
||||
//! ```compile_fail
|
||||
//! # use std::cell::RefCell;
|
||||
//! # use std::pin::Pin;
|
||||
//! fn exploit_ref_cell<T>(rc: Pin<&mut RefCell<T>>) {
|
||||
//! fn exploit_ref_cell<T>(mut rc: Pin<&mut RefCell<T>>) {
|
||||
//! // Here we get pinned access to the `T`.
|
||||
//! let _: Pin<&mut T> = rc.as_mut().get_pin_mut();
|
||||
//!
|
||||
//! // And here we have `&mut T` to the same data.
|
||||
//! let shared: &RefCell<T> = rc.into_ref().get_ref();
|
||||
//! let borrow = shared.borrow_mut();
|
||||
//! let mut borrow = shared.borrow_mut();
|
||||
//! let content = &mut *borrow;
|
||||
//! }
|
||||
//! ```
|
||||
|
|
|
|||
|
|
@ -1354,7 +1354,7 @@ impl<T, E> Result<T, E> {
|
|||
/// let s: String = only_good_news().into_ok();
|
||||
/// println!("{s}");
|
||||
/// ```
|
||||
#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
|
||||
#[unstable(feature = "unwrap_infallible", issue = "61695")]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
|
||||
|
|
@ -1391,7 +1391,7 @@ impl<T, E> Result<T, E> {
|
|||
/// let error: String = only_bad_news().into_err();
|
||||
/// println!("{error}");
|
||||
/// ```
|
||||
#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
|
||||
#[unstable(feature = "unwrap_infallible", issue = "61695")]
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_precise_live_drops)]
|
||||
#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
|
||||
|
|
|
|||
|
|
@ -62,6 +62,25 @@ impl [u8] {
|
|||
return false;
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
|
||||
{
|
||||
const CHUNK_SIZE: usize = 16;
|
||||
// The following function has two invariants:
|
||||
// 1. The slice lengths must be equal, which we checked above.
|
||||
// 2. The slice lengths must greater than or equal to N, which this
|
||||
// if-statement is checking.
|
||||
if self.len() >= CHUNK_SIZE {
|
||||
return self.eq_ignore_ascii_case_chunks::<CHUNK_SIZE>(other);
|
||||
}
|
||||
}
|
||||
|
||||
self.eq_ignore_ascii_case_simple(other)
|
||||
}
|
||||
|
||||
/// ASCII case-insensitive equality check without chunk-at-a-time
|
||||
/// optimization.
|
||||
#[inline]
|
||||
const fn eq_ignore_ascii_case_simple(&self, other: &[u8]) -> bool {
|
||||
// FIXME(const-hack): This implementation can be reverted when
|
||||
// `core::iter::zip` is allowed in const. The original implementation:
|
||||
// self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
|
||||
|
|
@ -80,6 +99,65 @@ impl [u8] {
|
|||
true
|
||||
}
|
||||
|
||||
/// Optimized version of `eq_ignore_ascii_case` to process chunks at a time.
|
||||
///
|
||||
/// Platforms that have SIMD instructions may benefit from this
|
||||
/// implementation over `eq_ignore_ascii_case_simple`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// The caller must guarantee that the slices are equal in length, and the
|
||||
/// slice lengths are greater than or equal to `N` bytes.
|
||||
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
|
||||
#[inline]
|
||||
const fn eq_ignore_ascii_case_chunks<const N: usize>(&self, other: &[u8]) -> bool {
|
||||
// FIXME(const-hack): The while-loops that follow should be replaced by
|
||||
// for-loops when available in const.
|
||||
|
||||
let (self_chunks, self_rem) = self.as_chunks::<N>();
|
||||
let (other_chunks, _) = other.as_chunks::<N>();
|
||||
|
||||
// Branchless check to encourage auto-vectorization
|
||||
#[inline(always)]
|
||||
const fn eq_ignore_ascii_inner<const L: usize>(lhs: &[u8; L], rhs: &[u8; L]) -> bool {
|
||||
let mut equal_ascii = true;
|
||||
let mut j = 0;
|
||||
while j < L {
|
||||
equal_ascii &= lhs[j].eq_ignore_ascii_case(&rhs[j]);
|
||||
j += 1;
|
||||
}
|
||||
|
||||
equal_ascii
|
||||
}
|
||||
|
||||
// Process the chunks, returning early if an inequality is found
|
||||
let mut i = 0;
|
||||
while i < self_chunks.len() && i < other_chunks.len() {
|
||||
if !eq_ignore_ascii_inner(&self_chunks[i], &other_chunks[i]) {
|
||||
return false;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Check the length invariant which is necessary for the tail-handling
|
||||
// logic to be correct. This should have been upheld by the caller,
|
||||
// otherwise lengths less than N will compare as true without any
|
||||
// checking.
|
||||
debug_assert!(self.len() >= N);
|
||||
|
||||
// If there are remaining tails, load the last N bytes in the slices to
|
||||
// avoid falling back to per-byte checking.
|
||||
if !self_rem.is_empty() {
|
||||
if let (Some(a_rem), Some(b_rem)) = (self.last_chunk::<N>(), other.last_chunk::<N>()) {
|
||||
if !eq_ignore_ascii_inner(a_rem, b_rem) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Converts this slice to its ASCII upper case equivalent in-place.
|
||||
///
|
||||
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
|
||||
|
|
@ -460,56 +538,38 @@ const fn is_ascii(s: &[u8]) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
/// Chunk size for vectorized ASCII checking (two 16-byte SSE registers).
|
||||
/// Chunk size for SSE2 vectorized ASCII checking (4x 16-byte loads).
|
||||
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
|
||||
const CHUNK_SIZE: usize = 32;
|
||||
const SSE2_CHUNK_SIZE: usize = 64;
|
||||
|
||||
/// SSE2 implementation using `_mm_movemask_epi8` (compiles to `pmovmskb`) to
|
||||
/// avoid LLVM's broken AVX-512 auto-vectorization of counting loops.
|
||||
///
|
||||
/// FIXME(llvm#176906): Remove this workaround once LLVM generates efficient code.
|
||||
#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
|
||||
#[inline]
|
||||
fn is_ascii_sse2(bytes: &[u8]) -> bool {
|
||||
use crate::arch::x86_64::{__m128i, _mm_loadu_si128, _mm_movemask_epi8, _mm_or_si128};
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
while i + CHUNK_SIZE <= bytes.len() {
|
||||
// SAFETY: We have verified that `i + CHUNK_SIZE <= bytes.len()`.
|
||||
let ptr = unsafe { bytes.as_ptr().add(i) };
|
||||
|
||||
// Load two 16-byte chunks and combine them.
|
||||
// SAFETY: We verified `i + 32 <= len`, so ptr is valid for 32 bytes.
|
||||
// `_mm_loadu_si128` allows unaligned loads.
|
||||
let chunk1 = unsafe { _mm_loadu_si128(ptr as *const __m128i) };
|
||||
// SAFETY: Same as above - ptr.add(16) is within the valid 32-byte range.
|
||||
let chunk2 = unsafe { _mm_loadu_si128(ptr.add(16) as *const __m128i) };
|
||||
|
||||
// OR them together - if any byte has the high bit set, the result will too.
|
||||
// SAFETY: SSE2 is guaranteed by the cfg predicate.
|
||||
let combined = unsafe { _mm_or_si128(chunk1, chunk2) };
|
||||
|
||||
// Create a mask from the MSBs of each byte.
|
||||
// If any byte is >= 128, its MSB is 1, so the mask will be non-zero.
|
||||
// SAFETY: SSE2 is guaranteed by the cfg predicate.
|
||||
let mask = unsafe { _mm_movemask_epi8(combined) };
|
||||
let (chunks, rest) = bytes.as_chunks::<SSE2_CHUNK_SIZE>();
|
||||
|
||||
for chunk in chunks {
|
||||
let ptr = chunk.as_ptr();
|
||||
// SAFETY: chunk is 64 bytes. SSE2 is baseline on x86_64.
|
||||
let mask = unsafe {
|
||||
let a1 = _mm_loadu_si128(ptr as *const __m128i);
|
||||
let a2 = _mm_loadu_si128(ptr.add(16) as *const __m128i);
|
||||
let b1 = _mm_loadu_si128(ptr.add(32) as *const __m128i);
|
||||
let b2 = _mm_loadu_si128(ptr.add(48) as *const __m128i);
|
||||
// OR all chunks - if any byte has high bit set, combined will too.
|
||||
let combined = _mm_or_si128(_mm_or_si128(a1, a2), _mm_or_si128(b1, b2));
|
||||
// Create a mask from the MSBs of each byte.
|
||||
// If any byte is >= 128, its MSB is 1, so the mask will be non-zero.
|
||||
_mm_movemask_epi8(combined)
|
||||
};
|
||||
if mask != 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
i += CHUNK_SIZE;
|
||||
}
|
||||
|
||||
// Handle remaining bytes with simple loop
|
||||
while i < bytes.len() {
|
||||
if !bytes[i].is_ascii() {
|
||||
return false;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
true
|
||||
// Handle remaining bytes
|
||||
rest.iter().all(|b| b.is_ascii())
|
||||
}
|
||||
|
||||
/// ASCII test optimized to use the `pmovmskb` instruction on `x86-64`.
|
||||
|
|
@ -529,7 +589,7 @@ const fn is_ascii(bytes: &[u8]) -> bool {
|
|||
is_ascii_simple(bytes)
|
||||
} else {
|
||||
// For small inputs, use usize-at-a-time processing to avoid SSE2 call overhead.
|
||||
if bytes.len() < CHUNK_SIZE {
|
||||
if bytes.len() < SSE2_CHUNK_SIZE {
|
||||
let chunks = bytes.chunks_exact(USIZE_SIZE);
|
||||
let remainder = chunks.remainder();
|
||||
for chunk in chunks {
|
||||
|
|
|
|||
|
|
@ -2520,7 +2520,7 @@ impl<T> [T] {
|
|||
/// )));
|
||||
/// assert_eq!(s.split_once(|&x| x == 0), None);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")]
|
||||
#[unstable(feature = "slice_split_once", issue = "112811")]
|
||||
#[inline]
|
||||
pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
|
||||
where
|
||||
|
|
@ -2548,7 +2548,7 @@ impl<T> [T] {
|
|||
/// )));
|
||||
/// assert_eq!(s.rsplit_once(|&x| x == 0), None);
|
||||
/// ```
|
||||
#[unstable(feature = "slice_split_once", reason = "newly added", issue = "112811")]
|
||||
#[unstable(feature = "slice_split_once", issue = "112811")]
|
||||
#[inline]
|
||||
pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ macro_rules! bench_mask_kind {
|
|||
($mask_kind:ident, $mask:expr) => {
|
||||
mod $mask_kind {
|
||||
use super::{Data, ITERATIONS, U};
|
||||
bench_template!(U::gather_bits, gather_bits, $mask);
|
||||
bench_template!(U::scatter_bits, scatter_bits, $mask);
|
||||
bench_template!(U::extract_bits, extract_bits, $mask);
|
||||
bench_template!(U::deposit_bits, deposit_bits, $mask);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use test::{Bencher, black_box};
|
|||
mod char_count;
|
||||
mod corpora;
|
||||
mod debug;
|
||||
mod eq_ignore_ascii_case;
|
||||
mod iter;
|
||||
|
||||
#[bench]
|
||||
|
|
|
|||
45
library/coretests/benches/str/eq_ignore_ascii_case.rs
Normal file
45
library/coretests/benches/str/eq_ignore_ascii_case.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
use test::{Bencher, black_box};
|
||||
|
||||
use super::corpora::*;
|
||||
|
||||
#[bench]
|
||||
fn bench_str_under_8_bytes_eq(b: &mut Bencher) {
|
||||
let s = black_box("foo");
|
||||
let other = black_box("foo");
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_str_of_8_bytes_eq(b: &mut Bencher) {
|
||||
let s = black_box(en::TINY);
|
||||
let other = black_box(en::TINY);
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_str_17_bytes_eq(b: &mut Bencher) {
|
||||
let s = black_box(&en::SMALL[..17]);
|
||||
let other = black_box(&en::SMALL[..17]);
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_str_31_bytes_eq(b: &mut Bencher) {
|
||||
let s = black_box(&en::SMALL[..31]);
|
||||
let other = black_box(&en::SMALL[..31]);
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_medium_str_eq(b: &mut Bencher) {
|
||||
let s = black_box(en::MEDIUM);
|
||||
let other = black_box(en::MEDIUM);
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_large_str_eq(b: &mut Bencher) {
|
||||
let s = black_box(en::LARGE);
|
||||
let other = black_box(en::LARGE);
|
||||
b.iter(|| assert!(s.eq_ignore_ascii_case(other)))
|
||||
}
|
||||
|
|
@ -127,50 +127,50 @@ macro_rules! uint_module {
|
|||
assert_eq_const_safe!($T: _1.swap_bytes(), _1);
|
||||
}
|
||||
|
||||
fn test_gather_bits() {
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_0011), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_0110), 0b_0010);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0000_1100), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0001_1000), 0b_0000);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0011_0000), 0b_0010);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b0110_0000), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::gather_bits(0b1010_0101, 0b1100_0000), 0b_0010);
|
||||
fn test_extract_bits() {
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_0011), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_0110), 0b_0010);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0000_1100), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0001_1000), 0b_0000);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0011_0000), 0b_0010);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b0110_0000), 0b_0001);
|
||||
assert_eq_const_safe!($T: $T::extract_bits(0b1010_0101, 0b1100_0000), 0b_0010);
|
||||
|
||||
assert_eq_const_safe!($T: A.gather_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: B.gather_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: C.gather_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: _0.gather_bits(A), 0);
|
||||
assert_eq_const_safe!($T: _0.gather_bits(B), 0);
|
||||
assert_eq_const_safe!($T: _0.gather_bits(C), 0);
|
||||
assert_eq_const_safe!($T: A.extract_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: B.extract_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: C.extract_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: _0.extract_bits(A), 0);
|
||||
assert_eq_const_safe!($T: _0.extract_bits(B), 0);
|
||||
assert_eq_const_safe!($T: _0.extract_bits(C), 0);
|
||||
|
||||
assert_eq_const_safe!($T: A.gather_bits(_1), A);
|
||||
assert_eq_const_safe!($T: B.gather_bits(_1), B);
|
||||
assert_eq_const_safe!($T: C.gather_bits(_1), C);
|
||||
assert_eq_const_safe!($T: _1.gather_bits(0b0010_0001), 0b0000_0011);
|
||||
assert_eq_const_safe!($T: _1.gather_bits(0b0010_1100), 0b0000_0111);
|
||||
assert_eq_const_safe!($T: _1.gather_bits(0b0111_1001), 0b0001_1111);
|
||||
assert_eq_const_safe!($T: A.extract_bits(_1), A);
|
||||
assert_eq_const_safe!($T: B.extract_bits(_1), B);
|
||||
assert_eq_const_safe!($T: C.extract_bits(_1), C);
|
||||
assert_eq_const_safe!($T: _1.extract_bits(0b0010_0001), 0b0000_0011);
|
||||
assert_eq_const_safe!($T: _1.extract_bits(0b0010_1100), 0b0000_0111);
|
||||
assert_eq_const_safe!($T: _1.extract_bits(0b0111_1001), 0b0001_1111);
|
||||
}
|
||||
|
||||
fn test_scatter_bits() {
|
||||
assert_eq_const_safe!($T: $T::scatter_bits(0b1111, 0b1001_0110), 0b1001_0110);
|
||||
assert_eq_const_safe!($T: $T::scatter_bits(0b0001, 0b1001_0110), 0b0000_0010);
|
||||
assert_eq_const_safe!($T: $T::scatter_bits(0b0010, 0b1001_0110), 0b0000_0100);
|
||||
assert_eq_const_safe!($T: $T::scatter_bits(0b0100, 0b1001_0110), 0b0001_0000);
|
||||
assert_eq_const_safe!($T: $T::scatter_bits(0b1000, 0b1001_0110), 0b1000_0000);
|
||||
fn test_deposit_bits() {
|
||||
assert_eq_const_safe!($T: $T::deposit_bits(0b1111, 0b1001_0110), 0b1001_0110);
|
||||
assert_eq_const_safe!($T: $T::deposit_bits(0b0001, 0b1001_0110), 0b0000_0010);
|
||||
assert_eq_const_safe!($T: $T::deposit_bits(0b0010, 0b1001_0110), 0b0000_0100);
|
||||
assert_eq_const_safe!($T: $T::deposit_bits(0b0100, 0b1001_0110), 0b0001_0000);
|
||||
assert_eq_const_safe!($T: $T::deposit_bits(0b1000, 0b1001_0110), 0b1000_0000);
|
||||
|
||||
assert_eq_const_safe!($T: A.scatter_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: B.scatter_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: C.scatter_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: _0.scatter_bits(A), 0);
|
||||
assert_eq_const_safe!($T: _0.scatter_bits(B), 0);
|
||||
assert_eq_const_safe!($T: _0.scatter_bits(C), 0);
|
||||
assert_eq_const_safe!($T: A.deposit_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: B.deposit_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: C.deposit_bits(_0), 0);
|
||||
assert_eq_const_safe!($T: _0.deposit_bits(A), 0);
|
||||
assert_eq_const_safe!($T: _0.deposit_bits(B), 0);
|
||||
assert_eq_const_safe!($T: _0.deposit_bits(C), 0);
|
||||
|
||||
assert_eq_const_safe!($T: A.scatter_bits(_1), A);
|
||||
assert_eq_const_safe!($T: B.scatter_bits(_1), B);
|
||||
assert_eq_const_safe!($T: C.scatter_bits(_1), C);
|
||||
assert_eq_const_safe!($T: _1.scatter_bits(A), A);
|
||||
assert_eq_const_safe!($T: _1.scatter_bits(B), B);
|
||||
assert_eq_const_safe!($T: _1.scatter_bits(C), C);
|
||||
assert_eq_const_safe!($T: A.deposit_bits(_1), A);
|
||||
assert_eq_const_safe!($T: B.deposit_bits(_1), B);
|
||||
assert_eq_const_safe!($T: C.deposit_bits(_1), C);
|
||||
assert_eq_const_safe!($T: _1.deposit_bits(A), A);
|
||||
assert_eq_const_safe!($T: _1.deposit_bits(B), B);
|
||||
assert_eq_const_safe!($T: _1.deposit_bits(C), C);
|
||||
}
|
||||
|
||||
fn test_reverse_bits() {
|
||||
|
|
@ -389,7 +389,7 @@ macro_rules! uint_module {
|
|||
|
||||
#[cfg(not(miri))] // Miri is too slow
|
||||
#[test]
|
||||
fn test_lots_of_gather_scatter() {
|
||||
fn test_lots_of_extract_deposit() {
|
||||
// Generate a handful of bit patterns to use as inputs
|
||||
let xs = {
|
||||
let mut xs = vec![];
|
||||
|
|
@ -414,7 +414,7 @@ macro_rules! uint_module {
|
|||
|
||||
for sparse in sparse_masks {
|
||||
// Collect the set bits to sequential low bits
|
||||
let dense = sparse.gather_bits(sparse);
|
||||
let dense = sparse.extract_bits(sparse);
|
||||
let count = sparse.count_ones();
|
||||
assert_eq!(count, dense.count_ones());
|
||||
assert_eq!(count, dense.trailing_ones());
|
||||
|
|
@ -424,27 +424,27 @@ macro_rules! uint_module {
|
|||
let mut bit = 1 as $T;
|
||||
for _ in 0..count {
|
||||
let lowest_one = t.isolate_lowest_one();
|
||||
assert_eq!(lowest_one, bit.scatter_bits(sparse));
|
||||
assert_eq!(bit, lowest_one.gather_bits(sparse));
|
||||
assert_eq!(lowest_one, bit.deposit_bits(sparse));
|
||||
assert_eq!(bit, lowest_one.extract_bits(sparse));
|
||||
t ^= lowest_one;
|
||||
bit <<= 1;
|
||||
}
|
||||
// Other bits are ignored
|
||||
assert_eq!(0, bit.wrapping_neg().scatter_bits(sparse));
|
||||
assert_eq!(0, (!sparse).gather_bits(sparse));
|
||||
assert_eq!(0, bit.wrapping_neg().deposit_bits(sparse));
|
||||
assert_eq!(0, (!sparse).extract_bits(sparse));
|
||||
|
||||
for &x in &xs {
|
||||
// Gather bits from `x & sparse` to `dense`
|
||||
let dx = x.gather_bits(sparse);
|
||||
let dx = x.extract_bits(sparse);
|
||||
assert_eq!(dx & !dense, 0);
|
||||
|
||||
// Scatter bits from `x & dense` to `sparse`
|
||||
let sx = x.scatter_bits(sparse);
|
||||
let sx = x.deposit_bits(sparse);
|
||||
assert_eq!(sx & !sparse, 0);
|
||||
|
||||
// The other recovers the input (within the mask)
|
||||
assert_eq!(dx.scatter_bits(sparse), x & sparse);
|
||||
assert_eq!(sx.gather_bits(sparse), x & dense);
|
||||
assert_eq!(dx.deposit_bits(sparse), x & sparse);
|
||||
assert_eq!(sx.extract_bits(sparse), x & dense);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,19 +30,19 @@ impl Drop for TokenStream {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
mem::ManuallyDrop::new(self).handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &TokenStream {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for TokenStream {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
TokenStream { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
|
|
@ -56,23 +56,17 @@ impl !Send for Span {}
|
|||
impl !Sync for Span {}
|
||||
|
||||
impl<S> Encode<S> for Span {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.handle.encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for Span {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Span { handle: handle::Handle::decode(r, s) }
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) generate these impls by pattern-matching on the
|
||||
// names of methods - also could use the presence of `fn drop`
|
||||
// to distinguish between 'owned and 'interned, above.
|
||||
// Alternatively, special "modes" could be listed of types in with_api
|
||||
// instead of pattern matching on methods, here and in server decl.
|
||||
|
||||
impl Clone for TokenStream {
|
||||
fn clone(&self) -> Self {
|
||||
Methods::ts_clone(self)
|
||||
|
|
@ -104,10 +98,7 @@ pub(crate) use super::symbol::Symbol;
|
|||
|
||||
macro_rules! define_client_side {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
impl Methods {
|
||||
$(pub(crate) fn $method($($arg: $arg_ty),*) $(-> $ret_ty)? {
|
||||
|
|
@ -115,7 +106,7 @@ macro_rules! define_client_side {
|
|||
let mut buf = bridge.cached_buffer.take();
|
||||
|
||||
buf.clear();
|
||||
api_tags::Method::$method.encode(&mut buf, &mut ());
|
||||
ApiTags::$method.encode(&mut buf, &mut ());
|
||||
$($arg.encode(&mut buf, &mut ());)*
|
||||
|
||||
buf = bridge.dispatch.call(buf);
|
||||
|
|
@ -130,7 +121,7 @@ macro_rules! define_client_side {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(self, self, define_client_side);
|
||||
with_api!(self, define_client_side);
|
||||
|
||||
struct Bridge<'a> {
|
||||
/// Reusable buffer (only `clear`-ed, never shrunk), primarily
|
||||
|
|
|
|||
|
|
@ -13,92 +13,76 @@ use std::ops::{Bound, Range};
|
|||
use std::sync::Once;
|
||||
use std::{fmt, marker, mem, panic, thread};
|
||||
|
||||
use crate::{Delimiter, Level, Spacing};
|
||||
use crate::{Delimiter, Level};
|
||||
|
||||
/// Higher-order macro describing the server RPC API, allowing automatic
|
||||
/// generation of type-safe Rust APIs, both client-side and server-side.
|
||||
///
|
||||
/// `with_api!(MySelf, my_self, my_macro)` expands to:
|
||||
/// `with_api!(MySelf, my_macro)` expands to:
|
||||
/// ```rust,ignore (pseudo-code)
|
||||
/// my_macro! {
|
||||
/// Methods {
|
||||
/// // ...
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// // ...
|
||||
/// fn lit_span(my_self: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(my_self: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// },
|
||||
/// Literal,
|
||||
/// Span,
|
||||
/// fn lit_character(ch: char) -> MySelf::Literal;
|
||||
/// fn lit_span(lit: &MySelf::Literal) -> MySelf::Span;
|
||||
/// fn lit_set_span(lit: &mut MySelf::Literal, span: MySelf::Span);
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// The first two arguments serve to customize the arguments names
|
||||
/// and argument/return types, to enable several different usecases:
|
||||
///
|
||||
/// If `my_self` is just `self`, then each `fn` signature can be used
|
||||
/// as-is for a method. If it's anything else (`self_` in practice),
|
||||
/// then the signatures don't have a special `self` argument, and
|
||||
/// can, therefore, have a different one introduced.
|
||||
/// The first argument serves to customize the argument/return types,
|
||||
/// to enable several different usecases:
|
||||
///
|
||||
/// If `MySelf` is just `Self`, then the types are only valid inside
|
||||
/// a trait or a trait impl, where the trait has associated types
|
||||
/// for each of the API types. If non-associated types are desired,
|
||||
/// a module name (`self` in practice) can be used instead of `Self`.
|
||||
macro_rules! with_api {
|
||||
($S:ident, $self:ident, $m:ident) => {
|
||||
($S:ident, $m:ident) => {
|
||||
$m! {
|
||||
Methods {
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
fn injected_env_var(var: &str) -> Option<String>;
|
||||
fn track_env_var(var: &str, value: Option<&str>);
|
||||
fn track_path(path: &str);
|
||||
fn literal_from_str(s: &str) -> Result<Literal<$S::Span, $S::Symbol>, ()>;
|
||||
fn emit_diagnostic(diagnostic: Diagnostic<$S::Span>);
|
||||
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
fn ts_drop(stream: $S::TokenStream);
|
||||
fn ts_clone(stream: &$S::TokenStream) -> $S::TokenStream;
|
||||
fn ts_is_empty(stream: &$S::TokenStream) -> bool;
|
||||
fn ts_expand_expr(stream: &$S::TokenStream) -> Result<$S::TokenStream, ()>;
|
||||
fn ts_from_str(src: &str) -> $S::TokenStream;
|
||||
fn ts_to_string(stream: &$S::TokenStream) -> String;
|
||||
fn ts_from_token_tree(
|
||||
tree: TokenTree<$S::TokenStream, $S::Span, $S::Symbol>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_trees(
|
||||
base: Option<$S::TokenStream>,
|
||||
trees: Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_concat_streams(
|
||||
base: Option<$S::TokenStream>,
|
||||
streams: Vec<$S::TokenStream>,
|
||||
) -> $S::TokenStream;
|
||||
fn ts_into_trees(
|
||||
stream: $S::TokenStream
|
||||
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
|
||||
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
fn span_debug(span: $S::Span) -> String;
|
||||
fn span_parent(span: $S::Span) -> Option<$S::Span>;
|
||||
fn span_source(span: $S::Span) -> $S::Span;
|
||||
fn span_byte_range(span: $S::Span) -> Range<usize>;
|
||||
fn span_start(span: $S::Span) -> $S::Span;
|
||||
fn span_end(span: $S::Span) -> $S::Span;
|
||||
fn span_line(span: $S::Span) -> usize;
|
||||
fn span_column(span: $S::Span) -> usize;
|
||||
fn span_file(span: $S::Span) -> String;
|
||||
fn span_local_file(span: $S::Span) -> Option<String>;
|
||||
fn span_join(span: $S::Span, other: $S::Span) -> Option<$S::Span>;
|
||||
fn span_subspan(span: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
|
||||
fn span_resolved_at(span: $S::Span, at: $S::Span) -> $S::Span;
|
||||
fn span_source_text(span: $S::Span) -> Option<String>;
|
||||
fn span_save_span(span: $S::Span) -> usize;
|
||||
fn span_recover_proc_macro_span(id: usize) -> $S::Span;
|
||||
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
},
|
||||
TokenStream,
|
||||
Span,
|
||||
Symbol,
|
||||
fn symbol_normalize_and_validate_ident(string: &str) -> Result<$S::Symbol, ()>;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -129,7 +113,7 @@ mod symbol;
|
|||
|
||||
use buffer::Buffer;
|
||||
pub use rpc::PanicMessage;
|
||||
use rpc::{Decode, Encode, Reader, Writer};
|
||||
use rpc::{Decode, Encode};
|
||||
|
||||
/// Configuration for establishing an active connection between a server and a
|
||||
/// client. The server creates the bridge config (`run_server` in `server.rs`),
|
||||
|
|
@ -151,26 +135,18 @@ pub struct BridgeConfig<'a> {
|
|||
impl !Send for BridgeConfig<'_> {}
|
||||
impl !Sync for BridgeConfig<'_> {}
|
||||
|
||||
#[forbid(unsafe_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
mod api_tags {
|
||||
use super::rpc::{Decode, Encode, Reader, Writer};
|
||||
|
||||
macro_rules! declare_tags {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
pub(super) enum Method {
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum Method { $($method),* });
|
||||
macro_rules! declare_tags {
|
||||
(
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
pub(super) enum ApiTags {
|
||||
$($method),*
|
||||
}
|
||||
rpc_encode_decode!(enum ApiTags { $($method),* });
|
||||
}
|
||||
with_api!(self, self, declare_tags);
|
||||
}
|
||||
with_api!(self, declare_tags);
|
||||
|
||||
/// Helper to wrap associated types to allow trait impl dispatch.
|
||||
/// That is, normally a pair of impls for `T::Foo` and `T::Bar`
|
||||
|
|
@ -179,11 +155,6 @@ mod api_tags {
|
|||
trait Mark {
|
||||
type Unmarked;
|
||||
fn mark(unmarked: Self::Unmarked) -> Self;
|
||||
}
|
||||
|
||||
/// Unwrap types wrapped by `Mark::mark` (see `Mark` for details).
|
||||
trait Unmark {
|
||||
type Unmarked;
|
||||
fn unmark(self) -> Self::Unmarked;
|
||||
}
|
||||
|
||||
|
|
@ -198,25 +169,19 @@ impl<T, M> Mark for Marked<T, M> {
|
|||
fn mark(unmarked: Self::Unmarked) -> Self {
|
||||
Marked { value: unmarked, _marker: marker::PhantomData }
|
||||
}
|
||||
}
|
||||
impl<T, M> Unmark for Marked<T, M> {
|
||||
type Unmarked = T;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
impl<'a, T, M> Unmark for &'a Marked<T, M> {
|
||||
impl<'a, T, M> Mark for &'a Marked<T, M> {
|
||||
type Unmarked = &'a T;
|
||||
fn mark(_: Self::Unmarked) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
impl<'a, T, M> Unmark for &'a mut Marked<T, M> {
|
||||
type Unmarked = &'a mut T;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
&mut self.value
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Mark> Mark for Vec<T> {
|
||||
type Unmarked = Vec<T::Unmarked>;
|
||||
|
|
@ -224,9 +189,6 @@ impl<T: Mark> Mark for Vec<T> {
|
|||
// Should be a no-op due to std's in-place collect optimizations.
|
||||
unmarked.into_iter().map(T::mark).collect()
|
||||
}
|
||||
}
|
||||
impl<T: Unmark> Unmark for Vec<T> {
|
||||
type Unmarked = Vec<T::Unmarked>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
// Should be a no-op due to std's in-place collect optimizations.
|
||||
self.into_iter().map(T::unmark).collect()
|
||||
|
|
@ -241,9 +203,6 @@ macro_rules! mark_noop {
|
|||
fn mark(unmarked: Self::Unmarked) -> Self {
|
||||
unmarked
|
||||
}
|
||||
}
|
||||
impl Unmark for $ty {
|
||||
type Unmarked = Self;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
self
|
||||
}
|
||||
|
|
@ -254,8 +213,6 @@ macro_rules! mark_noop {
|
|||
mark_noop! {
|
||||
(),
|
||||
bool,
|
||||
char,
|
||||
&'_ [u8],
|
||||
&'_ str,
|
||||
String,
|
||||
u8,
|
||||
|
|
@ -263,7 +220,6 @@ mark_noop! {
|
|||
Delimiter,
|
||||
LitKind,
|
||||
Level,
|
||||
Spacing,
|
||||
}
|
||||
|
||||
rpc_encode_decode!(
|
||||
|
|
@ -282,12 +238,6 @@ rpc_encode_decode!(
|
|||
Help,
|
||||
}
|
||||
);
|
||||
rpc_encode_decode!(
|
||||
enum Spacing {
|
||||
Alone,
|
||||
Joint,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum LitKind {
|
||||
|
|
@ -333,13 +283,9 @@ macro_rules! mark_compound {
|
|||
$($field: Mark::mark(unmarked.$field)),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($T: Unmark),+> Unmark for $name <$($T),+> {
|
||||
type Unmarked = $name <$($T::Unmarked),+>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
$name {
|
||||
$($field: Unmark::unmark(self.$field)),*
|
||||
$($field: Mark::unmark(self.$field)),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -354,14 +300,10 @@ macro_rules! mark_compound {
|
|||
})*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<$($T: Unmark),+> Unmark for $name <$($T),+> {
|
||||
type Unmarked = $name <$($T::Unmarked),+>;
|
||||
fn unmark(self) -> Self::Unmarked {
|
||||
match self {
|
||||
$($name::$variant $(($field))? => {
|
||||
$name::$variant $((Unmark::unmark($field)))?
|
||||
$name::$variant $((Mark::unmark($field)))?
|
||||
})*
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,28 +4,26 @@ use std::any::Any;
|
|||
use std::io::Write;
|
||||
use std::num::NonZero;
|
||||
|
||||
pub(super) type Writer = super::buffer::Buffer;
|
||||
use super::buffer::Buffer;
|
||||
|
||||
pub(super) trait Encode<S>: Sized {
|
||||
fn encode(self, w: &mut Writer, s: &mut S);
|
||||
fn encode(self, w: &mut Buffer, s: &mut S);
|
||||
}
|
||||
|
||||
pub(super) type Reader<'a> = &'a [u8];
|
||||
|
||||
pub(super) trait Decode<'a, 's, S>: Sized {
|
||||
fn decode(r: &mut Reader<'a>, s: &'s mut S) -> Self;
|
||||
fn decode(r: &mut &'a [u8], s: &'s mut S) -> Self;
|
||||
}
|
||||
|
||||
macro_rules! rpc_encode_decode {
|
||||
(le $ty:ty) => {
|
||||
impl<S> Encode<S> for $ty {
|
||||
fn encode(self, w: &mut Writer, _: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, _: &mut S) {
|
||||
w.extend_from_array(&self.to_le_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for $ty {
|
||||
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], _: &mut S) -> Self {
|
||||
const N: usize = size_of::<$ty>();
|
||||
|
||||
let mut bytes = [0; N];
|
||||
|
|
@ -38,7 +36,7 @@ macro_rules! rpc_encode_decode {
|
|||
};
|
||||
(struct $name:ident $(<$($T:ident),+>)? { $($field:ident),* $(,)? }) => {
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
$(self.$field.encode(w, s);)*
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +44,7 @@ macro_rules! rpc_encode_decode {
|
|||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
$name {
|
||||
$($field: Decode::decode(r, s)),*
|
||||
}
|
||||
|
|
@ -55,10 +53,12 @@ macro_rules! rpc_encode_decode {
|
|||
};
|
||||
(enum $name:ident $(<$($T:ident),+>)? { $($variant:ident $(($field:ident))*),* $(,)? }) => {
|
||||
impl<S, $($($T: Encode<S>),+)?> Encode<S> for $name $(<$($T),+>)? {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u8)]
|
||||
enum Tag { $($variant),* }
|
||||
|
||||
match self {
|
||||
$($name::$variant $(($field))* => {
|
||||
|
|
@ -72,10 +72,10 @@ macro_rules! rpc_encode_decode {
|
|||
impl<'a, S, $($($T: for<'s> Decode<'a, 's, S>),+)?> Decode<'a, '_, S>
|
||||
for $name $(<$($T),+>)?
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
// HACK(eddyb): `Tag` enum duplicated between the
|
||||
// two impls as there's no other place to stash it.
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[allow(non_upper_case_globals, non_camel_case_types)]
|
||||
mod tag {
|
||||
#[repr(u8)] enum Tag { $($variant),* }
|
||||
|
||||
|
|
@ -95,21 +95,21 @@ macro_rules! rpc_encode_decode {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for () {
|
||||
fn encode(self, _: &mut Writer, _: &mut S) {}
|
||||
fn encode(self, _: &mut Buffer, _: &mut S) {}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for () {
|
||||
fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {}
|
||||
fn decode(_: &mut &[u8], _: &mut S) -> Self {}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for u8 {
|
||||
fn encode(self, w: &mut Writer, _: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, _: &mut S) {
|
||||
w.push(self);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for u8 {
|
||||
fn decode(r: &mut Reader<'_>, _: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], _: &mut S) -> Self {
|
||||
let x = r[0];
|
||||
*r = &r[1..];
|
||||
x
|
||||
|
|
@ -120,13 +120,13 @@ rpc_encode_decode!(le u32);
|
|||
rpc_encode_decode!(le usize);
|
||||
|
||||
impl<S> Encode<S> for bool {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
(self as u8).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for bool {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
match u8::decode(r, s) {
|
||||
0 => false,
|
||||
1 => true,
|
||||
|
|
@ -135,32 +135,20 @@ impl<S> Decode<'_, '_, S> for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for char {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
(self as u32).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for char {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
char::from_u32(u32::decode(r, s)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for NonZero<u32> {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.get().encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for NonZero<u32> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Self::new(u32::decode(r, s)).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.0.encode(w, s);
|
||||
self.1.encode(w, s);
|
||||
}
|
||||
|
|
@ -169,53 +157,42 @@ impl<S, A: Encode<S>, B: Encode<S>> Encode<S> for (A, B) {
|
|||
impl<'a, S, A: for<'s> Decode<'a, 's, S>, B: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S>
|
||||
for (A, B)
|
||||
{
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
(Decode::decode(r, s), Decode::decode(r, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &[u8] {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.len().encode(w, s);
|
||||
w.write_all(self).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Decode<'a, '_, S> for &'a [u8] {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let xs = &r[..len];
|
||||
*r = &r[len..];
|
||||
xs
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for &str {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
self.as_bytes().encode(w, s);
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
let bytes = self.as_bytes();
|
||||
bytes.len().encode(w, s);
|
||||
w.write_all(bytes).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S> Decode<'a, '_, S> for &'a str {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
str::from_utf8(<&[u8]>::decode(r, s)).unwrap()
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let xs = &r[..len];
|
||||
*r = &r[len..];
|
||||
str::from_utf8(xs).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Encode<S> for String {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self[..].encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for String {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
<&str>::decode(r, s).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T: Encode<S>> Encode<S> for Vec<T> {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.len().encode(w, s);
|
||||
for x in self {
|
||||
x.encode(w, s);
|
||||
|
|
@ -224,7 +201,7 @@ impl<S, T: Encode<S>> Encode<S> for Vec<T> {
|
|||
}
|
||||
|
||||
impl<'a, S, T: for<'s> Decode<'a, 's, S>> Decode<'a, '_, S> for Vec<T> {
|
||||
fn decode(r: &mut Reader<'a>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &'a [u8], s: &mut S) -> Self {
|
||||
let len = usize::decode(r, s);
|
||||
let mut vec = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
|
|
@ -278,13 +255,13 @@ impl PanicMessage {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for PanicMessage {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.as_str().encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for PanicMessage {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
match Option::<String>::decode(r, s) {
|
||||
Some(s) => PanicMessage::String(s),
|
||||
None => PanicMessage::Unknown,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ use std::marker::PhantomData;
|
|||
|
||||
use super::*;
|
||||
|
||||
pub(super) struct HandleStore<S: Types> {
|
||||
token_stream: handle::OwnedStore<Marked<S::TokenStream, client::TokenStream>>,
|
||||
span: handle::InternedStore<Marked<S::Span, client::Span>>,
|
||||
pub(super) struct HandleStore<S: Server> {
|
||||
token_stream: handle::OwnedStore<MarkedTokenStream<S>>,
|
||||
span: handle::InternedStore<MarkedSpan<S>>,
|
||||
}
|
||||
|
||||
impl<S: Types> HandleStore<S> {
|
||||
impl<S: Server> HandleStore<S> {
|
||||
fn new(handle_counters: &'static client::HandleCounters) -> Self {
|
||||
HandleStore {
|
||||
token_stream: handle::OwnedStore::new(&handle_counters.token_stream),
|
||||
|
|
@ -19,52 +19,54 @@ impl<S: Types> HandleStore<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
pub(super) type MarkedTokenStream<S> = Marked<<S as Server>::TokenStream, client::TokenStream>;
|
||||
pub(super) type MarkedSpan<S> = Marked<<S as Server>::Span, client::Span>;
|
||||
pub(super) type MarkedSymbol<S> = Marked<<S as Server>::Symbol, client::Symbol>;
|
||||
|
||||
impl<S: Server> Encode<HandleStore<S>> for MarkedTokenStream<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut HandleStore<S>) {
|
||||
s.token_stream.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::TokenStream, client::TokenStream> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
impl<S: Server> Decode<'_, '_, HandleStore<S>> for MarkedTokenStream<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut HandleStore<S>) -> Self {
|
||||
s.token_stream.take(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: Types> Decode<'_, 's, HandleStore<S>>
|
||||
for &'s Marked<S::TokenStream, client::TokenStream>
|
||||
{
|
||||
fn decode(r: &mut Reader<'_>, s: &'s mut HandleStore<S>) -> Self {
|
||||
impl<'s, S: Server> Decode<'_, 's, HandleStore<S>> for &'s MarkedTokenStream<S> {
|
||||
fn decode(r: &mut &[u8], s: &'s mut HandleStore<S>) -> Self {
|
||||
&s.token_stream[handle::Handle::decode(r, &mut ())]
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Encode<HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn encode(self, w: &mut Writer, s: &mut HandleStore<S>) {
|
||||
impl<S: Server> Encode<HandleStore<S>> for MarkedSpan<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut HandleStore<S>) {
|
||||
s.span.alloc(self).encode(w, s);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Types> Decode<'_, '_, HandleStore<S>> for Marked<S::Span, client::Span> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut HandleStore<S>) -> Self {
|
||||
impl<S: Server> Decode<'_, '_, HandleStore<S>> for MarkedSpan<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut HandleStore<S>) -> Self {
|
||||
s.span.copy(handle::Handle::decode(r, &mut ()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Types {
|
||||
type TokenStream: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
struct Dispatcher<S: Server> {
|
||||
handle_store: HandleStore<S>,
|
||||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! declare_server_traits {
|
||||
macro_rules! define_server_dispatcher_impl {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
) => {
|
||||
pub trait Server: Types {
|
||||
pub trait Server {
|
||||
type TokenStream: 'static + Clone;
|
||||
type Span: 'static + Copy + Eq + Hash;
|
||||
type Symbol: 'static;
|
||||
|
||||
fn globals(&mut self) -> ExpnGlobals<Self::Span>;
|
||||
|
||||
/// Intern a symbol received from RPC
|
||||
|
|
@ -75,39 +77,28 @@ macro_rules! declare_server_traits {
|
|||
|
||||
$(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?;)*
|
||||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, declare_server_traits);
|
||||
|
||||
struct Dispatcher<S: Types> {
|
||||
handle_store: HandleStore<S>,
|
||||
server: S,
|
||||
}
|
||||
|
||||
macro_rules! define_dispatcher_impl {
|
||||
(
|
||||
Methods {
|
||||
$(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)*;)*
|
||||
},
|
||||
$($name:ident),* $(,)?
|
||||
) => {
|
||||
// FIXME(eddyb) `pub` only for `ExecutionStrategy` below.
|
||||
pub trait DispatcherTrait {
|
||||
// HACK(eddyb) these are here to allow `Self::$name` to work below.
|
||||
$(type $name;)*
|
||||
type TokenStream;
|
||||
type Span;
|
||||
type Symbol;
|
||||
|
||||
fn dispatch(&mut self, buf: Buffer) -> Buffer;
|
||||
}
|
||||
|
||||
impl<S: Server> DispatcherTrait for Dispatcher<S> {
|
||||
$(type $name = Marked<S::$name, client::$name>;)*
|
||||
type TokenStream = MarkedTokenStream<S>;
|
||||
type Span = MarkedSpan<S>;
|
||||
type Symbol = MarkedSymbol<S>;
|
||||
|
||||
fn dispatch(&mut self, mut buf: Buffer) -> Buffer {
|
||||
let Dispatcher { handle_store, server } = self;
|
||||
|
||||
let mut reader = &buf[..];
|
||||
match api_tags::Method::decode(&mut reader, &mut ()) {
|
||||
$(api_tags::Method::$method => {
|
||||
match ApiTags::decode(&mut reader, &mut ()) {
|
||||
$(ApiTags::$method => {
|
||||
let mut call_method = || {
|
||||
$(let $arg = <$arg_ty>::decode(&mut reader, handle_store).unmark();)*
|
||||
let r = server.$method($($arg),*);
|
||||
|
|
@ -136,7 +127,7 @@ macro_rules! define_dispatcher_impl {
|
|||
}
|
||||
}
|
||||
}
|
||||
with_api!(Self, self_, define_dispatcher_impl);
|
||||
with_api!(Self, define_server_dispatcher_impl);
|
||||
|
||||
pub trait ExecutionStrategy {
|
||||
fn run_bridge_and_client(
|
||||
|
|
@ -303,7 +294,7 @@ fn run_server<
|
|||
let globals = dispatcher.server.globals();
|
||||
|
||||
let mut buf = Buffer::new();
|
||||
(<ExpnGlobals<Marked<S::Span, client::Span>> as Mark>::mark(globals), input)
|
||||
(<ExpnGlobals<MarkedSpan<S>> as Mark>::mark(globals), input)
|
||||
.encode(&mut buf, &mut dispatcher.handle_store);
|
||||
|
||||
buf = strategy.run_bridge_and_client(&mut dispatcher, buf, run_client, force_show_panics);
|
||||
|
|
@ -328,13 +319,11 @@ impl client::Client<crate::TokenStream, crate::TokenStream> {
|
|||
strategy,
|
||||
handle_counters,
|
||||
server,
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
<MarkedTokenStream<S>>::mark(input),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
.map(|s| <Option<MarkedTokenStream<S>>>::unmark(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -356,15 +345,10 @@ impl client::Client<(crate::TokenStream, crate::TokenStream), crate::TokenStream
|
|||
strategy,
|
||||
handle_counters,
|
||||
server,
|
||||
(
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input),
|
||||
<Marked<S::TokenStream, client::TokenStream>>::mark(input2),
|
||||
),
|
||||
(<MarkedTokenStream<S>>::mark(input), <MarkedTokenStream<S>>::mark(input2)),
|
||||
run,
|
||||
force_show_panics,
|
||||
)
|
||||
.map(|s| {
|
||||
<Option<Marked<S::TokenStream, client::TokenStream>>>::unmark(s).unwrap_or_default()
|
||||
})
|
||||
.map(|s| <Option<MarkedTokenStream<S>>>::unmark(s).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,25 +94,25 @@ impl fmt::Display for Symbol {
|
|||
}
|
||||
|
||||
impl<S> Encode<S> for Symbol {
|
||||
fn encode(self, w: &mut Writer, s: &mut S) {
|
||||
fn encode(self, w: &mut Buffer, s: &mut S) {
|
||||
self.with(|sym| sym.encode(w, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut server::HandleStore<S>) -> Self {
|
||||
impl<S: server::Server> Decode<'_, '_, server::HandleStore<S>> for server::MarkedSymbol<S> {
|
||||
fn decode(r: &mut &[u8], s: &mut server::HandleStore<S>) -> Self {
|
||||
Mark::mark(S::intern_symbol(<&str>::decode(r, s)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: server::Server> Encode<server::HandleStore<S>> for Marked<S::Symbol, Symbol> {
|
||||
fn encode(self, w: &mut Writer, s: &mut server::HandleStore<S>) {
|
||||
impl<S: server::Server> Encode<server::HandleStore<S>> for server::MarkedSymbol<S> {
|
||||
fn encode(self, w: &mut Buffer, s: &mut server::HandleStore<S>) {
|
||||
S::with_symbol_string(&self.unmark(), |sym| sym.encode(w, s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> Decode<'_, '_, S> for Symbol {
|
||||
fn decode(r: &mut Reader<'_>, s: &mut S) -> Self {
|
||||
fn decode(r: &mut &[u8], s: &mut S) -> Self {
|
||||
Symbol::new(<&str>::decode(r, s))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ object = { version = "0.37.1", default-features = false, optional = true, featur
|
|||
'archive',
|
||||
] }
|
||||
|
||||
[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies.windows-targets]
|
||||
path = "../windows_targets"
|
||||
[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies.windows-link]
|
||||
path = "../windows_link"
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.9.0", default-features = false, features = ["alloc"] }
|
||||
|
|
@ -130,7 +130,7 @@ llvm_enzyme = ["core/llvm_enzyme"]
|
|||
|
||||
# Enable using raw-dylib for Windows imports.
|
||||
# This will eventually be the default.
|
||||
windows_raw_dylib = ["windows-targets/windows_raw_dylib"]
|
||||
windows_raw_dylib = ["windows-link/windows_raw_dylib"]
|
||||
|
||||
[package.metadata.fortanix-sgx]
|
||||
# Maximum possible number of threads when testing
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
//!
|
||||
//! [`collections`]: crate::collections
|
||||
|
||||
#[allow(deprecated)]
|
||||
use super::{BuildHasher, Hasher, SipHasher13};
|
||||
use crate::cell::Cell;
|
||||
use crate::fmt;
|
||||
|
|
@ -81,7 +80,6 @@ impl RandomState {
|
|||
impl BuildHasher for RandomState {
|
||||
type Hasher = DefaultHasher;
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
fn build_hasher(&self) -> DefaultHasher {
|
||||
DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
|
||||
}
|
||||
|
|
@ -91,7 +89,6 @@ impl BuildHasher for RandomState {
|
|||
///
|
||||
/// The internal algorithm is not specified, and so it and its hashes should
|
||||
/// not be relied upon over releases.
|
||||
#[allow(deprecated)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
pub struct DefaultHasher(SipHasher13);
|
||||
|
|
@ -104,7 +101,6 @@ impl DefaultHasher {
|
|||
/// instances created through `new` or `default`.
|
||||
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
|
||||
#[inline]
|
||||
#[allow(deprecated)]
|
||||
#[rustc_const_unstable(feature = "const_default", issue = "143894")]
|
||||
#[must_use]
|
||||
pub const fn new() -> DefaultHasher {
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@
|
|||
#![feature(staged_api)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(strict_provenance_lints)]
|
||||
#![feature(target_feature_inline_always)]
|
||||
#![feature(thread_local)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(try_trait_v2)]
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const HEAP_ZERO_MEMORY: u32 = 0x00000008;
|
|||
// always return the same handle, which remains valid for the entire lifetime of the process.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-getprocessheap
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE);
|
||||
|
||||
// Allocate a block of `dwBytes` bytes of memory from a given heap `hHeap`.
|
||||
// The allocated memory may be uninitialized, or zeroed if `dwFlags` is
|
||||
|
|
@ -36,7 +36,7 @@ windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> c::HANDLE)
|
|||
// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapalloc
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut c_void);
|
||||
windows_link::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dwflags: u32, dwbytes: usize) -> *mut c_void);
|
||||
|
||||
// Reallocate a block of memory behind a given pointer `lpMem` from a given heap `hHeap`,
|
||||
// to a block of at least `dwBytes` bytes, either shrinking the block in place,
|
||||
|
|
@ -57,7 +57,7 @@ windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap: c::HANDLE, dw
|
|||
// Note that `dwBytes` is allowed to be zero, contrary to some other allocators.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heaprealloc
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
|
||||
windows_link::link!("kernel32.dll" "system" fn HeapReAlloc(
|
||||
hheap: c::HANDLE,
|
||||
dwflags : u32,
|
||||
lpmem: *const c_void,
|
||||
|
|
@ -78,7 +78,7 @@ windows_targets::link!("kernel32.dll" "system" fn HeapReAlloc(
|
|||
// Note that `lpMem` is allowed to be null, which will not cause the operation to fail.
|
||||
//
|
||||
// See https://docs.microsoft.com/windows/win32/api/heapapi/nf-heapapi-heapfree
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn HeapFree(hheap: c::HANDLE, dwflags: u32, lpmem: *const c_void) -> c::BOOL);
|
||||
|
||||
fn get_process_heap() -> *mut c_void {
|
||||
// SAFETY: GetProcessHeap simply returns a valid handle or NULL so is always safe to call.
|
||||
|
|
|
|||
|
|
@ -580,7 +580,8 @@ mod uefi_fs {
|
|||
use crate::path::Path;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::sys::pal::helpers::{self, UefiBox};
|
||||
use crate::sys::time::{self, SystemTime};
|
||||
use crate::sys::pal::system_time;
|
||||
use crate::sys::time::SystemTime;
|
||||
|
||||
pub(crate) struct File {
|
||||
protocol: NonNull<file::Protocol>,
|
||||
|
|
@ -879,7 +880,7 @@ mod uefi_fs {
|
|||
/// conversion to SystemTime, we use the current time to get the timezone in such cases.
|
||||
pub(crate) fn uefi_to_systemtime(mut time: r_efi::efi::Time) -> Option<SystemTime> {
|
||||
time.timezone = if time.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
time::system_time_internal::now().timezone
|
||||
system_time::now().timezone
|
||||
} else {
|
||||
time.timezone
|
||||
};
|
||||
|
|
@ -888,7 +889,7 @@ mod uefi_fs {
|
|||
|
||||
/// Convert to UEFI Time with the current timezone.
|
||||
pub(crate) fn systemtime_to_uefi(time: SystemTime) -> r_efi::efi::Time {
|
||||
let now = time::system_time_internal::now();
|
||||
let now = system_time::now();
|
||||
time.to_uefi_loose(now.timezone, now.daylight)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1822,7 +1822,7 @@ impl File {
|
|||
_ => {
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
@ -2258,7 +2258,7 @@ fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Resu
|
|||
let flags = if follow_symlinks { 0 } else { libc::AT_SYMLINK_NOFOLLOW };
|
||||
#[cfg(all(target_os = "linux", target_env = "gnu", target_pointer_width = "32", not(target_arch = "riscv32")))]
|
||||
{
|
||||
use crate::sys::{time::__timespec64, weak::weak};
|
||||
use crate::sys::pal::{time::__timespec64, weak::weak};
|
||||
|
||||
// Added in glibc 2.34
|
||||
weak!(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ pub mod stdio;
|
|||
pub mod sync;
|
||||
pub mod thread;
|
||||
pub mod thread_local;
|
||||
pub mod time;
|
||||
|
||||
// FIXME(117276): remove this, move feature implementations into individual
|
||||
// submodules.
|
||||
|
|
|
|||
|
|
@ -9,10 +9,9 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
|
|||
use crate::net::{Shutdown, SocketAddr};
|
||||
use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
|
||||
use crate::sys::fd::FileDesc;
|
||||
use crate::sys::time::Instant;
|
||||
use crate::sys::{AsInner, FromInner, IntoInner};
|
||||
pub use crate::sys::{cvt, cvt_r};
|
||||
use crate::time::Duration;
|
||||
use crate::time::{Duration, Instant};
|
||||
use crate::{cmp, mem};
|
||||
|
||||
#[expect(non_camel_case_types)]
|
||||
|
|
|
|||
|
|
@ -1,35 +1,32 @@
|
|||
#![allow(dead_code)]
|
||||
use hermit_abi::{self, timespec};
|
||||
|
||||
use core::hash::{Hash, Hasher};
|
||||
|
||||
use super::hermit_abi::{self, CLOCK_MONOTONIC, CLOCK_REALTIME, timespec};
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::{Add, AddAssign, Sub, SubAssign};
|
||||
use crate::hash::{Hash, Hasher};
|
||||
use crate::time::Duration;
|
||||
|
||||
const NSEC_PER_SEC: i32 = 1_000_000_000;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
struct Timespec {
|
||||
t: timespec,
|
||||
pub struct Timespec {
|
||||
pub t: timespec,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
|
||||
pub const MAX: Timespec = Self::new(i64::MAX, 1_000_000_000 - 1);
|
||||
|
||||
const MIN: Timespec = Self::new(i64::MIN, 0);
|
||||
pub const MIN: Timespec = Self::new(i64::MIN, 0);
|
||||
|
||||
const fn zero() -> Timespec {
|
||||
pub const fn zero() -> Timespec {
|
||||
Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
|
||||
pub const fn new(tv_sec: i64, tv_nsec: i32) -> Timespec {
|
||||
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC);
|
||||
// SAFETY: The assert above checks tv_nsec is within the valid range
|
||||
Timespec { t: timespec { tv_sec, tv_nsec } }
|
||||
}
|
||||
|
||||
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
|
||||
fn sub_ge_to_unsigned(a: i64, b: i64) -> u64 {
|
||||
debug_assert!(a >= b);
|
||||
a.wrapping_sub(b).cast_unsigned()
|
||||
|
|
@ -57,7 +54,7 @@ impl Timespec {
|
|||
}
|
||||
}
|
||||
|
||||
fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
|
||||
|
||||
// Nano calculations can't overflow because nanos are <1B which fit
|
||||
|
|
@ -70,7 +67,7 @@ impl Timespec {
|
|||
Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
|
||||
}
|
||||
|
||||
fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
|
||||
let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
|
||||
|
||||
// Similar to above, nanos can't overflow.
|
||||
|
|
@ -111,132 +108,3 @@ impl Hash for Timespec {
|
|||
self.t.tv_nsec.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(Timespec);
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) };
|
||||
|
||||
Instant(time)
|
||||
}
|
||||
|
||||
#[stable(feature = "time2", since = "1.8.0")]
|
||||
pub fn elapsed(&self) -> Duration {
|
||||
Instant::now() - *self
|
||||
}
|
||||
|
||||
pub fn duration_since(&self, earlier: Instant) -> Duration {
|
||||
self.checked_duration_since(earlier).unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
|
||||
self.checked_sub_instant(&earlier)
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.sub_timespec(&other.0).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
|
||||
self.0.checked_add_duration(&duration).map(Instant)
|
||||
}
|
||||
|
||||
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
|
||||
self.0.checked_sub_duration(&duration).map(Instant)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
|
||||
/// # Panics
|
||||
///
|
||||
/// This function may panic if the resulting point in time cannot be represented by the
|
||||
/// underlying data structure. See [`Instant::checked_add`] for a version without panic.
|
||||
fn add(self, other: Duration) -> Instant {
|
||||
self.checked_add(other).expect("overflow when adding duration to instant")
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign<Duration> for Instant {
|
||||
fn add_assign(&mut self, other: Duration) {
|
||||
*self = *self + other;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
|
||||
fn sub(self, other: Duration) -> Instant {
|
||||
self.checked_sub(other).expect("overflow when subtracting duration from instant")
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign<Duration> for Instant {
|
||||
fn sub_assign(&mut self, other: Duration) {
|
||||
*self = *self - other;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub<Instant> for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
/// Returns the amount of time elapsed from another instant to this one,
|
||||
/// or zero duration if that instant is later than this one.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Previous Rust versions panicked when `other` was later than `self`. Currently this
|
||||
/// method saturates. Future versions may reintroduce the panic in some circumstances.
|
||||
/// See [Monotonicity].
|
||||
///
|
||||
/// [Monotonicity]: Instant#monotonicity
|
||||
fn sub(self, other: Instant) -> Duration {
|
||||
self.duration_since(other)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||
pub struct SystemTime(Timespec);
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime(Timespec::MAX);
|
||||
|
||||
pub const MIN: SystemTime = SystemTime(Timespec::MIN);
|
||||
|
||||
pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime {
|
||||
SystemTime(Timespec::new(tv_sec, tv_nsec))
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
let mut time: Timespec = Timespec::zero();
|
||||
let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) };
|
||||
|
||||
SystemTime(time)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.0.sub_timespec(&other.0)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_add_duration(other)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime(self.0.checked_sub_duration(other)?))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,38 +3,16 @@ use super::error::expect_success;
|
|||
use crate::mem::MaybeUninit;
|
||||
use crate::time::Duration;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Instant(abi::SYSTIM);
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
// Safety: The provided pointer is valid
|
||||
unsafe {
|
||||
let mut out = MaybeUninit::uninit();
|
||||
expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
|
||||
Instant(out.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.0.checked_sub(other.0).map(|ticks| {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
Duration::from_micros(ticks)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
// `SYSTIM` is measured in microseconds
|
||||
let ticks = other.as_micros();
|
||||
|
||||
Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
|
||||
#[inline]
|
||||
pub fn get_tim() -> abi::SYSTIM {
|
||||
// Safety: The provided pointer is valid
|
||||
unsafe {
|
||||
let mut out = MaybeUninit::uninit();
|
||||
expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
|
||||
out.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +76,7 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -
|
|||
// a problem in practice. (`u64::MAX` μs ≈ 584942 years)
|
||||
let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
|
||||
|
||||
let start = Instant::now().0;
|
||||
let start = get_tim();
|
||||
let mut elapsed = 0;
|
||||
let mut er = abi::E_TMOUT;
|
||||
while elapsed <= ticks {
|
||||
|
|
@ -106,11 +84,8 @@ pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -
|
|||
if er != abi::E_TMOUT {
|
||||
break;
|
||||
}
|
||||
elapsed = Instant::now().0.wrapping_sub(start);
|
||||
elapsed = get_tim().wrapping_sub(start);
|
||||
}
|
||||
|
||||
er
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
pub use moto_rt::futex;
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
pub use moto_rt::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||
|
|
@ -12,7 +12,6 @@ pub mod abi;
|
|||
mod libunwind_integration;
|
||||
pub mod os;
|
||||
pub mod thread_parking;
|
||||
pub mod time;
|
||||
pub mod waitqueue;
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ pub mod itron {
|
|||
pub(crate) mod error;
|
||||
pub mod os;
|
||||
pub use self::itron::thread_parking;
|
||||
pub mod time;
|
||||
|
||||
// SAFETY: must be called only once during runtime initialization.
|
||||
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
pub mod os;
|
||||
#[allow(non_upper_case_globals)]
|
||||
#[path = "../unix/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,5 @@
|
|||
mod common;
|
||||
#[path = "../unsupported/os.rs"]
|
||||
pub mod os;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
pub use common::*;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
pub mod helpers;
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
pub mod system_time;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
|
|
|||
151
library/std/src/sys/pal/uefi/system_time.rs
Normal file
151
library/std/src/sys/pal/uefi/system_time.rs
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
use r_efi::efi::{RuntimeServices, Time};
|
||||
|
||||
use super::helpers;
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::ptr::NonNull;
|
||||
use crate::time::Duration;
|
||||
|
||||
const SECS_IN_MINUTE: u64 = 60;
|
||||
const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
|
||||
const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
|
||||
const SYSTEMTIME_TIMEZONE: i64 = -1440 * SECS_IN_MINUTE as i64;
|
||||
|
||||
pub(crate) fn now() -> Time {
|
||||
let runtime_services: NonNull<RuntimeServices> =
|
||||
helpers::runtime_services().expect("Runtime services are not available");
|
||||
let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
|
||||
let r =
|
||||
unsafe { ((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut()) };
|
||||
if r.is_error() {
|
||||
panic!("time not implemented on this platform");
|
||||
}
|
||||
|
||||
unsafe { t.assume_init() }
|
||||
}
|
||||
|
||||
/// This algorithm is a modified form of the one described in the post
|
||||
/// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn from_uefi(t: &Time) -> Option<Duration> {
|
||||
if !(t.month <= 12
|
||||
&& t.month != 0
|
||||
&& t.year >= 1900
|
||||
&& t.year <= 9999
|
||||
&& t.day <= 31
|
||||
&& t.day != 0
|
||||
&& t.second < 60
|
||||
&& t.minute <= 60
|
||||
&& t.hour < 24
|
||||
&& t.nanosecond < 1_000_000_000
|
||||
&& ((t.timezone <= 1440 && t.timezone >= -1440)
|
||||
|| t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE))
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
|
||||
|
||||
// Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
|
||||
// time.
|
||||
// Use 1 March as the start
|
||||
let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
|
||||
let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
|
||||
let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
|
||||
let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
|
||||
let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
|
||||
let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
|
||||
|
||||
let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
|
||||
+ (t.second as u64)
|
||||
+ (t.minute as u64) * SECS_IN_MINUTE
|
||||
+ (t.hour as u64) * SECS_IN_HOUR;
|
||||
|
||||
let normalized_timezone = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
|
||||
-SYSTEMTIME_TIMEZONE
|
||||
} else {
|
||||
(t.timezone as i64) * SECS_IN_MINUTE as i64 - SYSTEMTIME_TIMEZONE
|
||||
};
|
||||
|
||||
// Calculate the offset from 1/1/1900 at timezone -1440 min
|
||||
let epoch = localtime_epoch.checked_add_signed(normalized_timezone).unwrap();
|
||||
|
||||
Some(Duration::new(epoch, t.nanosecond))
|
||||
}
|
||||
|
||||
/// This algorithm is a modified version of the one described in the post:
|
||||
/// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
|
||||
///
|
||||
/// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
|
||||
/// epoch used in the original algorithm.
|
||||
pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Result<Time, i16> {
|
||||
const MIN_IN_HOUR: u64 = 60;
|
||||
const MIN_IN_DAY: u64 = MIN_IN_HOUR * 24;
|
||||
|
||||
// Check timezone validity
|
||||
assert!(timezone <= 1440 && timezone >= -1440);
|
||||
|
||||
// Convert to seconds since 1900-01-01-00:00:00 in timezone.
|
||||
let Some(secs) = dur
|
||||
.as_secs()
|
||||
.checked_add_signed(SYSTEMTIME_TIMEZONE - (timezone as i64 * SECS_IN_MINUTE as i64))
|
||||
else {
|
||||
// If the current timezone cannot be used, find the closest timezone that will allow the
|
||||
// conversion to succeed.
|
||||
let new_tz = (dur.as_secs() / SECS_IN_MINUTE) as i16
|
||||
+ (SYSTEMTIME_TIMEZONE / SECS_IN_MINUTE as i64) as i16;
|
||||
return Err(new_tz);
|
||||
};
|
||||
|
||||
let days = secs / SECS_IN_DAY;
|
||||
let remaining_secs = secs % SECS_IN_DAY;
|
||||
|
||||
let z = days + 693901;
|
||||
let era = z / 146097;
|
||||
let doe = z - (era * 146097);
|
||||
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
|
||||
let mut y = yoe + era * 400;
|
||||
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
|
||||
let mp = (5 * doy + 2) / 153;
|
||||
let d = doy - (153 * mp + 2) / 5 + 1;
|
||||
let m = if mp < 10 { mp + 3 } else { mp - 9 };
|
||||
|
||||
if m <= 2 {
|
||||
y += 1;
|
||||
}
|
||||
|
||||
let hour = (remaining_secs / SECS_IN_HOUR) as u8;
|
||||
let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
|
||||
let second = (remaining_secs % SECS_IN_MINUTE) as u8;
|
||||
|
||||
// At this point, invalid time will be greater than MAX representable time. It cannot be less
|
||||
// than minimum time since we already take care of that case above.
|
||||
if y <= 9999 {
|
||||
Ok(Time {
|
||||
year: y as u16,
|
||||
month: m as u8,
|
||||
day: d as u8,
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
nanosecond: dur.subsec_nanos(),
|
||||
timezone,
|
||||
daylight,
|
||||
pad1: 0,
|
||||
pad2: 0,
|
||||
})
|
||||
} else {
|
||||
assert!(y == 10000);
|
||||
assert!(m == 1);
|
||||
|
||||
let delta = ((d - 1) as u64 * MIN_IN_DAY
|
||||
+ hour as u64 * MIN_IN_HOUR
|
||||
+ minute as u64
|
||||
+ if second == 0 { 0 } else { 1 }) as i16;
|
||||
let new_tz = timezone + delta;
|
||||
|
||||
assert!(new_tz <= 1440 && new_tz >= -1440);
|
||||
Err(new_tz)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
use core::num::niche_types::Nanoseconds;
|
||||
|
||||
use crate::sys::AsInner;
|
||||
use crate::io;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, io};
|
||||
|
||||
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
|
||||
|
||||
#[allow(dead_code)] // Used for pthread condvar timeouts
|
||||
pub const TIMESPEC_MAX: libc::timespec =
|
||||
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
|
||||
|
|
@ -18,60 +17,19 @@ pub(in crate::sys) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
|
|||
tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct SystemTime {
|
||||
pub(crate) t: Timespec,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub(crate) struct Timespec {
|
||||
tv_sec: i64,
|
||||
tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime { t: Timespec::MAX };
|
||||
|
||||
pub const MIN: SystemTime = SystemTime { t: Timespec::MIN };
|
||||
|
||||
#[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
|
||||
pub fn new(tv_sec: i64, tv_nsec: i64) -> Result<SystemTime, io::Error> {
|
||||
Ok(SystemTime { t: Timespec::new(tv_sec, tv_nsec)? })
|
||||
}
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
self.t.sub_timespec(&other.t)
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
Some(SystemTime { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
pub tv_sec: i64,
|
||||
pub tv_nsec: Nanoseconds,
|
||||
}
|
||||
|
||||
impl Timespec {
|
||||
const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
pub const MAX: Timespec = unsafe { Self::new_unchecked(i64::MAX, 1_000_000_000 - 1) };
|
||||
|
||||
// As described below, on Apple OS, dates before epoch are represented differently.
|
||||
// This is not an issue here however, because we are using tv_sec = i64::MIN,
|
||||
// which will cause the compatibility wrapper to not be executed at all.
|
||||
const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
pub const MIN: Timespec = unsafe { Self::new_unchecked(i64::MIN, 0) };
|
||||
|
||||
const unsafe fn new_unchecked(tv_sec: i64, tv_nsec: i64) -> Timespec {
|
||||
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds::new_unchecked(tv_nsec as u32) } }
|
||||
|
|
@ -81,7 +39,7 @@ impl Timespec {
|
|||
unsafe { Self::new_unchecked(0, 0) }
|
||||
}
|
||||
|
||||
const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
pub const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
|
||||
// On Apple OS, dates before epoch are represented differently than on other
|
||||
// Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
|
||||
// and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
|
||||
|
|
@ -263,98 +221,3 @@ impl __timespec64 {
|
|||
Self { tv_sec, tv_nsec, _padding: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct Instant {
|
||||
t: Timespec,
|
||||
}
|
||||
|
||||
impl Instant {
|
||||
// CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
|
||||
// ner as CLOCK_MONOTONIC_RAW, but that does not incre-
|
||||
// ment while the system is asleep. The returned value
|
||||
// is identical to the result of mach_absolute_time()
|
||||
// after the appropriate mach_timebase conversion is
|
||||
// applied.
|
||||
//
|
||||
// We use `CLOCK_UPTIME_RAW` instead of `CLOCK_MONOTONIC` since
|
||||
// `CLOCK_UPTIME_RAW` is based on `mach_absolute_time`, which is the
|
||||
// clock that all timeouts and deadlines are measured against inside
|
||||
// the kernel.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
|
||||
|
||||
#[cfg(not(target_vendor = "apple"))]
|
||||
pub(crate) const CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
|
||||
|
||||
pub fn now() -> Instant {
|
||||
// https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html
|
||||
Instant { t: Timespec::now(Self::CLOCK_ID) }
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
self.t.sub_timespec(&other.t).ok()
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add_duration(other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub_duration(other)? })
|
||||
}
|
||||
|
||||
#[cfg_attr(
|
||||
not(target_os = "linux"),
|
||||
allow(unused, reason = "needed by the `sleep_until` on some unix platforms")
|
||||
)]
|
||||
pub(crate) fn into_timespec(self) -> Timespec {
|
||||
self.t
|
||||
}
|
||||
|
||||
/// Returns `self` converted into units of `mach_absolute_time`, or `None`
|
||||
/// if `self` is before the system boot time. If the conversion cannot be
|
||||
/// performed precisely, this ceils the result up to the nearest
|
||||
/// representable value.
|
||||
#[cfg(target_vendor = "apple")]
|
||||
pub fn into_mach_absolute_time_ceil(self) -> Option<u128> {
|
||||
#[repr(C)]
|
||||
struct mach_timebase_info {
|
||||
numer: u32,
|
||||
denom: u32,
|
||||
}
|
||||
|
||||
unsafe extern "C" {
|
||||
unsafe fn mach_timebase_info(info: *mut mach_timebase_info) -> libc::kern_return_t;
|
||||
}
|
||||
|
||||
let secs = u64::try_from(self.t.tv_sec).ok()?;
|
||||
|
||||
let mut timebase = mach_timebase_info { numer: 0, denom: 0 };
|
||||
assert_eq!(unsafe { mach_timebase_info(&mut timebase) }, libc::KERN_SUCCESS);
|
||||
|
||||
// Since `tv_sec` is 64-bit and `tv_nsec` is smaller than 1 billion,
|
||||
// this cannot overflow. The resulting number needs at most 94 bits.
|
||||
let nanos =
|
||||
u128::from(secs) * u128::from(NSEC_PER_SEC) + u128::from(self.t.tv_nsec.as_inner());
|
||||
// This multiplication cannot overflow since multiplying a 94-bit
|
||||
// number by a 32-bit number yields a number that needs at most
|
||||
// 126 bits.
|
||||
Some((nanos * u128::from(timebase.denom)).div_ceil(u128::from(timebase.numer)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<Timespec> for Instant {
|
||||
fn as_inner(&self) -> &Timespec {
|
||||
&self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Instant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Instant")
|
||||
.field("tv_sec", &self.t.tv_sec)
|
||||
.field("tv_nsec", &self.t.tv_nsec)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
mod common;
|
||||
pub use common::*;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[path = "../unsupported/common.rs"]
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@
|
|||
|
||||
#[path = "../unsupported/os.rs"]
|
||||
pub mod os;
|
||||
#[path = "../unsupported/time.rs"]
|
||||
pub mod time;
|
||||
|
||||
#[cfg(target_feature = "atomics")]
|
||||
#[path = "atomics/futex.rs"]
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ unsafe extern "system" {
|
|||
pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
|
||||
}
|
||||
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
|
||||
windows_link::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
|
||||
filehandle: *mut HANDLE,
|
||||
desiredaccess: FILE_ACCESS_RIGHTS,
|
||||
objectattributes: *const OBJECT_ATTRIBUTES,
|
||||
|
|
@ -229,15 +229,15 @@ compat_fn_with_fallback! {
|
|||
|
||||
cfg_select! {
|
||||
target_vendor = "uwp" => {
|
||||
windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
|
||||
windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
|
||||
windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
|
||||
windows_link::link_raw_dylib!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
|
||||
windows_link::link_raw_dylib!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
|
||||
windows_link::link_raw_dylib!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_link::link_raw_dylib!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_link::link_raw_dylib!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Only available starting with Windows 8.
|
||||
#[cfg(not(target_vendor = "win7"))]
|
||||
windows_targets::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn GetHostNameW(name : PWSTR, namelen : i32) -> i32);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
--flat
|
||||
--sys
|
||||
--no-deps
|
||||
--link windows_targets
|
||||
--link windows_link
|
||||
--filter
|
||||
!INVALID_HANDLE_VALUE
|
||||
ABOVE_NORMAL_PRIORITY_CLASS
|
||||
|
|
|
|||
|
|
@ -1,147 +1,147 @@
|
|||
// Bindings generated by `windows-bindgen` 0.61.1
|
||||
// Bindings generated by `windows-bindgen` 0.66.0
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
|
||||
|
||||
windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn AddVectoredExceptionHandler(first : u32, handler : PVECTORED_EXCEPTION_HANDLER) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : COPYFILE_FLAGS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreatePipe(hreadpipe : *mut HANDLE, hwritepipe : *mut HANDLE, lppipeattributes : *const SECURITY_ATTRIBUTES, nsize : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> bool);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST));
|
||||
windows_targets::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindFirstFileExW(lpfilename : PCWSTR, finfolevelid : FINDEX_INFO_LEVELS, lpfindfiledata : *mut core::ffi::c_void, fsearchop : FINDEX_SEARCH_OPS, lpsearchfilter : *const core::ffi::c_void, dwadditionalflags : FIND_FIRST_EX_FLAGS) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetConsoleOutputCP() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetCurrentThreadId() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetModuleHandleW(lpmodulename : PCWSTR) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetOverlappedResult(hfile : HANDLE, lpoverlapped : *const OVERLAPPED, lpnumberofbytestransferred : *mut u32, bwait : BOOL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_targets::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_targets::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_targets::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> bool);
|
||||
windows_targets::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR));
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32));
|
||||
windows_targets::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsAlloc() -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> bool);
|
||||
windows_targets::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> bool);
|
||||
windows_targets::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSACleanup() -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested : u16, lpwsadata : *mut WSADATA) -> i32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WakeAllConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_targets::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_targets::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA));
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn lstrlenW(lpstring : PCWSTR) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn send(s : SOCKET, buf : PCSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn sendto(s : SOCKET, buf : PCSTR, len : i32, flags : i32, to : *const SOCKADDR, tolen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i32, optname : i32, optval : PCSTR, optlen : i32) -> i32);
|
||||
windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32);
|
||||
windows_link::link!("kernel32.dll" "system" fn AcquireSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_link::link!("kernel32.dll" "system" fn AcquireSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_link::link!("kernel32.dll" "system" fn AddVectoredExceptionHandler(first : u32, handler : PVECTORED_EXCEPTION_HANDLER) -> *mut core::ffi::c_void);
|
||||
windows_link::link!("kernel32.dll" "system" fn CancelIo(hfile : HANDLE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CompareStringOrdinal(lpstring1 : PCWSTR, cchcount1 : i32, lpstring2 : PCWSTR, cchcount2 : i32, bignorecase : BOOL) -> COMPARESTRING_RESULT);
|
||||
windows_link::link!("kernel32.dll" "system" fn CopyFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, lpprogressroutine : LPPROGRESS_ROUTINE, lpdata : *const core::ffi::c_void, pbcancel : *mut BOOL, dwcopyflags : COPYFILE_FLAGS) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateDirectoryW(lppathname : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateFileW(lpfilename : PCWSTR, dwdesiredaccess : u32, dwsharemode : FILE_SHARE_MODE, lpsecurityattributes : *const SECURITY_ATTRIBUTES, dwcreationdisposition : FILE_CREATION_DISPOSITION, dwflagsandattributes : FILE_FLAGS_AND_ATTRIBUTES, htemplatefile : HANDLE) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateHardLinkW(lpfilename : PCWSTR, lpexistingfilename : PCWSTR, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateNamedPipeW(lpname : PCWSTR, dwopenmode : FILE_FLAGS_AND_ATTRIBUTES, dwpipemode : NAMED_PIPE_MODE, nmaxinstances : u32, noutbuffersize : u32, ninbuffersize : u32, ndefaulttimeout : u32, lpsecurityattributes : *const SECURITY_ATTRIBUTES) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreatePipe(hreadpipe : *mut HANDLE, hwritepipe : *mut HANDLE, lppipeattributes : *const SECURITY_ATTRIBUTES, nsize : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateProcessW(lpapplicationname : PCWSTR, lpcommandline : PWSTR, lpprocessattributes : *const SECURITY_ATTRIBUTES, lpthreadattributes : *const SECURITY_ATTRIBUTES, binherithandles : BOOL, dwcreationflags : PROCESS_CREATION_FLAGS, lpenvironment : *const core::ffi::c_void, lpcurrentdirectory : PCWSTR, lpstartupinfo : *const STARTUPINFOW, lpprocessinformation : *mut PROCESS_INFORMATION) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateSymbolicLinkW(lpsymlinkfilename : PCWSTR, lptargetfilename : PCWSTR, dwflags : SYMBOLIC_LINK_FLAGS) -> bool);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateThread(lpthreadattributes : *const SECURITY_ATTRIBUTES, dwstacksize : usize, lpstartaddress : LPTHREAD_START_ROUTINE, lpparameter : *const core::ffi::c_void, dwcreationflags : THREAD_CREATION_FLAGS, lpthreadid : *mut u32) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn CreateWaitableTimerExW(lptimerattributes : *const SECURITY_ATTRIBUTES, lptimername : PCWSTR, dwflags : u32, dwdesiredaccess : u32) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn DeleteFileW(lpfilename : PCWSTR) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn DeleteProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST));
|
||||
windows_link::link!("kernel32.dll" "system" fn DeviceIoControl(hdevice : HANDLE, dwiocontrolcode : u32, lpinbuffer : *const core::ffi::c_void, ninbuffersize : u32, lpoutbuffer : *mut core::ffi::c_void, noutbuffersize : u32, lpbytesreturned : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn DuplicateHandle(hsourceprocesshandle : HANDLE, hsourcehandle : HANDLE, htargetprocesshandle : HANDLE, lptargethandle : *mut HANDLE, dwdesiredaccess : u32, binherithandle : BOOL, dwoptions : DUPLICATE_HANDLE_OPTIONS) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn ExitProcess(uexitcode : u32) -> !);
|
||||
windows_link::link!("kernel32.dll" "system" fn FindClose(hfindfile : HANDLE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn FindFirstFileExW(lpfilename : PCWSTR, finfolevelid : FINDEX_INFO_LEVELS, lpfindfiledata : *mut core::ffi::c_void, fsearchop : FINDEX_SEARCH_OPS, lpsearchfilter : *const core::ffi::c_void, dwadditionalflags : FIND_FIRST_EX_FLAGS) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn FindNextFileW(hfindfile : HANDLE, lpfindfiledata : *mut WIN32_FIND_DATAW) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn FlushFileBuffers(hfile : HANDLE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv : PCWSTR) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetConsoleOutputCP() -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCurrentThread() -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetCurrentThreadId() -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetEnvironmentStringsW() -> PWSTR);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetEnvironmentVariableW(lpname : PCWSTR, lpbuffer : PWSTR, nsize : u32) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetExitCodeProcess(hprocess : HANDLE, lpexitcode : *mut u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFileAttributesW(lpfilename : PCWSTR) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFileInformationByHandle(hfile : HANDLE, lpfileinformation : *mut BY_HANDLE_FILE_INFORMATION) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFileInformationByHandleEx(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *mut core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFileSizeEx(hfile : HANDLE, lpfilesize : *mut i64) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFileType(hfile : HANDLE) -> FILE_TYPE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFinalPathNameByHandleW(hfile : HANDLE, lpszfilepath : PWSTR, cchfilepath : u32, dwflags : GETFINALPATHNAMEBYHANDLE_FLAGS) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetFullPathNameW(lpfilename : PCWSTR, nbufferlength : u32, lpbuffer : PWSTR, lpfilepart : *mut PWSTR) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetModuleFileNameW(hmodule : HMODULE, lpfilename : PWSTR, nsize : u32) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetModuleHandleA(lpmodulename : PCSTR) -> HMODULE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetModuleHandleW(lpmodulename : PCWSTR) -> HMODULE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetOverlappedResult(hfile : HANDLE, lpoverlapped : *const OVERLAPPED, lpnumberofbytestransferred : *mut u32, bwait : BOOL) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetProcessId(process : HANDLE) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetStdHandle(nstdhandle : STD_HANDLE) -> HANDLE);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetSystemDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetSystemInfo(lpsysteminfo : *mut SYSTEM_INFO));
|
||||
windows_link::link!("kernel32.dll" "system" fn GetSystemTimeAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_link::link!("kernel32.dll" "system" fn GetSystemTimePreciseAsFileTime(lpsystemtimeasfiletime : *mut FILETIME));
|
||||
windows_link::link!("kernel32.dll" "system" fn GetTempPathW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
|
||||
windows_link::link!("userenv.dll" "system" fn GetUserProfileDirectoryW(htoken : HANDLE, lpprofiledir : PWSTR, lpcchsize : *mut u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn GetWindowsDirectoryW(lpbuffer : PWSTR, usize : u32) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn InitOnceBeginInitialize(lpinitonce : *mut INIT_ONCE, dwflags : u32, fpending : *mut BOOL, lpcontext : *mut *mut core::ffi::c_void) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn InitOnceComplete(lpinitonce : *mut INIT_ONCE, dwflags : u32, lpcontext : *const core::ffi::c_void) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn InitializeProcThreadAttributeList(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwattributecount : u32, dwflags : u32, lpsize : *mut usize) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn LocalFree(hmem : HLOCAL) -> HLOCAL);
|
||||
windows_link::link!("kernel32.dll" "system" fn LockFileEx(hfile : HANDLE, dwflags : LOCK_FILE_FLAGS, dwreserved : u32, nnumberofbytestolocklow : u32, nnumberofbytestolockhigh : u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn MoveFileExW(lpexistingfilename : PCWSTR, lpnewfilename : PCWSTR, dwflags : MOVE_FILE_FLAGS) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn MultiByteToWideChar(codepage : u32, dwflags : MULTI_BYTE_TO_WIDE_CHAR_FLAGS, lpmultibytestr : PCSTR, cbmultibyte : i32, lpwidecharstr : PWSTR, cchwidechar : i32) -> i32);
|
||||
windows_link::link!("ntdll.dll" "system" fn NtCreateFile(filehandle : *mut HANDLE, desiredaccess : FILE_ACCESS_RIGHTS, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, allocationsize : *const i64, fileattributes : FILE_FLAGS_AND_ATTRIBUTES, shareaccess : FILE_SHARE_MODE, createdisposition : NTCREATEFILE_CREATE_DISPOSITION, createoptions : NTCREATEFILE_CREATE_OPTIONS, eabuffer : *const core::ffi::c_void, ealength : u32) -> NTSTATUS);
|
||||
windows_link::link!("ntdll.dll" "system" fn NtOpenFile(filehandle : *mut HANDLE, desiredaccess : u32, objectattributes : *const OBJECT_ATTRIBUTES, iostatusblock : *mut IO_STATUS_BLOCK, shareaccess : u32, openoptions : u32) -> NTSTATUS);
|
||||
windows_link::link!("ntdll.dll" "system" fn NtReadFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *mut core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_link::link!("ntdll.dll" "system" fn NtWriteFile(filehandle : HANDLE, event : HANDLE, apcroutine : PIO_APC_ROUTINE, apccontext : *const core::ffi::c_void, iostatusblock : *mut IO_STATUS_BLOCK, buffer : *const core::ffi::c_void, length : u32, byteoffset : *const i64, key : *const u32) -> NTSTATUS);
|
||||
windows_link::link!("advapi32.dll" "system" fn OpenProcessToken(processhandle : HANDLE, desiredaccess : TOKEN_ACCESS_MASK, tokenhandle : *mut HANDLE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn QueryPerformanceCounter(lpperformancecount : *mut i64) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn QueryPerformanceFrequency(lpfrequency : *mut i64) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn ReadConsoleW(hconsoleinput : HANDLE, lpbuffer : *mut core::ffi::c_void, nnumberofcharstoread : u32, lpnumberofcharsread : *mut u32, pinputcontrol : *const CONSOLE_READCONSOLE_CONTROL) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn ReadFile(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpnumberofbytesread : *mut u32, lpoverlapped : *mut OVERLAPPED) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn ReadFileEx(hfile : HANDLE, lpbuffer : *mut u8, nnumberofbytestoread : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn ReleaseSRWLockExclusive(srwlock : *mut SRWLOCK));
|
||||
windows_link::link!("kernel32.dll" "system" fn ReleaseSRWLockShared(srwlock : *mut SRWLOCK));
|
||||
windows_link::link!("kernel32.dll" "system" fn RemoveDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_link::link!("advapi32.dll" "system" "SystemFunction036" fn RtlGenRandom(randombuffer : *mut core::ffi::c_void, randombufferlength : u32) -> bool);
|
||||
windows_link::link!("ntdll.dll" "system" fn RtlNtStatusToDosError(status : NTSTATUS) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetCurrentDirectoryW(lppathname : PCWSTR) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetEnvironmentVariableW(lpname : PCWSTR, lpvalue : PCWSTR) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetFileAttributesW(lpfilename : PCWSTR, dwfileattributes : FILE_FLAGS_AND_ATTRIBUTES) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetFileInformationByHandle(hfile : HANDLE, fileinformationclass : FILE_INFO_BY_HANDLE_CLASS, lpfileinformation : *const core::ffi::c_void, dwbuffersize : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetFilePointerEx(hfile : HANDLE, lidistancetomove : i64, lpnewfilepointer : *mut i64, dwmovemethod : SET_FILE_POINTER_MOVE_METHOD) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetFileTime(hfile : HANDLE, lpcreationtime : *const FILETIME, lplastaccesstime : *const FILETIME, lplastwritetime : *const FILETIME) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetHandleInformation(hobject : HANDLE, dwmask : u32, dwflags : HANDLE_FLAGS) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetLastError(dwerrcode : WIN32_ERROR));
|
||||
windows_link::link!("kernel32.dll" "system" fn SetThreadStackGuarantee(stacksizeinbytes : *mut u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SetWaitableTimer(htimer : HANDLE, lpduetime : *const i64, lperiod : i32, pfncompletionroutine : PTIMERAPCROUTINE, lpargtocompletionroutine : *const core::ffi::c_void, fresume : BOOL) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32));
|
||||
windows_link::link!("kernel32.dll" "system" fn SleepConditionVariableSRW(conditionvariable : *mut CONDITION_VARIABLE, srwlock : *mut SRWLOCK, dwmilliseconds : u32, flags : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn SleepEx(dwmilliseconds : u32, balertable : BOOL) -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn SwitchToThread() -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn TerminateProcess(hprocess : HANDLE, uexitcode : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn TlsAlloc() -> u32);
|
||||
windows_link::link!("kernel32.dll" "system" fn TlsFree(dwtlsindex : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn TlsGetValue(dwtlsindex : u32) -> *mut core::ffi::c_void);
|
||||
windows_link::link!("kernel32.dll" "system" fn TlsSetValue(dwtlsindex : u32, lptlsvalue : *const core::ffi::c_void) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn TryAcquireSRWLockExclusive(srwlock : *mut SRWLOCK) -> bool);
|
||||
windows_link::link!("kernel32.dll" "system" fn TryAcquireSRWLockShared(srwlock : *mut SRWLOCK) -> bool);
|
||||
windows_link::link!("kernel32.dll" "system" fn UnlockFile(hfile : HANDLE, dwfileoffsetlow : u32, dwfileoffsethigh : u32, nnumberofbytestounlocklow : u32, nnumberofbytestounlockhigh : u32) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn UpdateProcThreadAttribute(lpattributelist : LPPROC_THREAD_ATTRIBUTE_LIST, dwflags : u32, attribute : usize, lpvalue : *const core::ffi::c_void, cbsize : usize, lppreviousvalue : *mut core::ffi::c_void, lpreturnsize : *const usize) -> BOOL);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSACleanup() -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSADuplicateSocketW(s : SOCKET, dwprocessid : u32, lpprotocolinfo : *mut WSAPROTOCOL_INFOW) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSAGetLastError() -> WSA_ERROR);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSARecv(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytesrecvd : *mut u32, lpflags : *mut u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSASend(s : SOCKET, lpbuffers : *const WSABUF, dwbuffercount : u32, lpnumberofbytessent : *mut u32, dwflags : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSASocketW(af : i32, r#type : i32, protocol : i32, lpprotocolinfo : *const WSAPROTOCOL_INFOW, g : u32, dwflags : u32) -> SOCKET);
|
||||
windows_link::link!("ws2_32.dll" "system" fn WSAStartup(wversionrequested : u16, lpwsadata : *mut WSADATA) -> i32);
|
||||
windows_link::link!("kernel32.dll" "system" fn WaitForMultipleObjects(ncount : u32, lphandles : *const HANDLE, bwaitall : BOOL, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_link::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_link::link!("kernel32.dll" "system" fn WakeAllConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_link::link!("kernel32.dll" "system" fn WakeConditionVariable(conditionvariable : *mut CONDITION_VARIABLE));
|
||||
windows_link::link!("kernel32.dll" "system" fn WideCharToMultiByte(codepage : u32, dwflags : u32, lpwidecharstr : PCWSTR, cchwidechar : i32, lpmultibytestr : PSTR, cbmultibyte : i32, lpdefaultchar : PCSTR, lpuseddefaultchar : *mut BOOL) -> i32);
|
||||
windows_link::link!("kernel32.dll" "system" fn WriteConsoleW(hconsoleoutput : HANDLE, lpbuffer : PCWSTR, nnumberofcharstowrite : u32, lpnumberofcharswritten : *mut u32, lpreserved : *const core::ffi::c_void) -> BOOL);
|
||||
windows_link::link!("kernel32.dll" "system" fn WriteFileEx(hfile : HANDLE, lpbuffer : *const u8, nnumberofbytestowrite : u32, lpoverlapped : *mut OVERLAPPED, lpcompletionroutine : LPOVERLAPPED_COMPLETION_ROUTINE) -> BOOL);
|
||||
windows_link::link!("ws2_32.dll" "system" fn accept(s : SOCKET, addr : *mut SOCKADDR, addrlen : *mut i32) -> SOCKET);
|
||||
windows_link::link!("ws2_32.dll" "system" fn bind(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn closesocket(s : SOCKET) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn connect(s : SOCKET, name : *const SOCKADDR, namelen : i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn freeaddrinfo(paddrinfo : *const ADDRINFOA));
|
||||
windows_link::link!("ws2_32.dll" "system" fn getaddrinfo(pnodename : PCSTR, pservicename : PCSTR, phints : *const ADDRINFOA, ppresult : *mut *mut ADDRINFOA) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn getpeername(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn getsockname(s : SOCKET, name : *mut SOCKADDR, namelen : *mut i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn getsockopt(s : SOCKET, level : i32, optname : i32, optval : PSTR, optlen : *mut i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn ioctlsocket(s : SOCKET, cmd : i32, argp : *mut u32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn listen(s : SOCKET, backlog : i32) -> i32);
|
||||
windows_link::link!("kernel32.dll" "system" fn lstrlenW(lpstring : PCWSTR) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn recv(s : SOCKET, buf : PSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn recvfrom(s : SOCKET, buf : PSTR, len : i32, flags : i32, from : *mut SOCKADDR, fromlen : *mut i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn select(nfds : i32, readfds : *mut FD_SET, writefds : *mut FD_SET, exceptfds : *mut FD_SET, timeout : *const TIMEVAL) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn send(s : SOCKET, buf : PCSTR, len : i32, flags : SEND_RECV_FLAGS) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn sendto(s : SOCKET, buf : PCSTR, len : i32, flags : i32, to : *const SOCKADDR, tolen : i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn setsockopt(s : SOCKET, level : i32, optname : i32, optval : PCSTR, optlen : i32) -> i32);
|
||||
windows_link::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32);
|
||||
pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
|
|
|
|||
|
|
@ -1,170 +1,12 @@
|
|||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::Neg;
|
||||
|
||||
use crate::cmp::Ordering;
|
||||
use crate::ops::Neg;
|
||||
use crate::ptr::null;
|
||||
use crate::sys::{IntoInner, c};
|
||||
use crate::sys::pal::c;
|
||||
use crate::time::Duration;
|
||||
use crate::{fmt, mem};
|
||||
|
||||
const NANOS_PER_SEC: u64 = 1_000_000_000;
|
||||
const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
|
||||
pub const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
|
||||
pub struct Instant {
|
||||
// This duration is relative to an arbitrary microsecond epoch
|
||||
// from the winapi QueryPerformanceCounter function.
|
||||
t: Duration,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SystemTime {
|
||||
t: c::FILETIME,
|
||||
}
|
||||
|
||||
const INTERVALS_TO_UNIX_EPOCH: u64 = 11_644_473_600 * INTERVALS_PER_SEC;
|
||||
|
||||
pub const UNIX_EPOCH: SystemTime = SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: INTERVALS_TO_UNIX_EPOCH as u32,
|
||||
dwHighDateTime: (INTERVALS_TO_UNIX_EPOCH >> 32) as u32,
|
||||
},
|
||||
};
|
||||
|
||||
impl Instant {
|
||||
pub fn now() -> Instant {
|
||||
// High precision timing on windows operates in "Performance Counter"
|
||||
// units, as returned by the WINAPI QueryPerformanceCounter function.
|
||||
// These relate to seconds by a factor of QueryPerformanceFrequency.
|
||||
// In order to keep unit conversions out of normal interval math, we
|
||||
// measure in QPC units and immediately convert to nanoseconds.
|
||||
perf_counter::PerformanceCounterInstant::now().into()
|
||||
}
|
||||
|
||||
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
|
||||
// On windows there's a threshold below which we consider two timestamps
|
||||
// equivalent due to measurement error. For more details + doc link,
|
||||
// check the docs on epsilon.
|
||||
let epsilon = perf_counter::PerformanceCounterInstant::epsilon();
|
||||
if other.t > self.t && other.t - self.t <= epsilon {
|
||||
Some(Duration::new(0, 0))
|
||||
} else {
|
||||
self.t.checked_sub(other.t)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_add(*other)? })
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
|
||||
Some(Instant { t: self.t.checked_sub(*other)? })
|
||||
}
|
||||
}
|
||||
|
||||
impl SystemTime {
|
||||
pub const MAX: SystemTime = SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: (i64::MAX & 0xFFFFFFFF) as u32,
|
||||
dwHighDateTime: (i64::MAX >> 32) as u32,
|
||||
},
|
||||
};
|
||||
|
||||
pub const MIN: SystemTime =
|
||||
SystemTime { t: c::FILETIME { dwLowDateTime: 0, dwHighDateTime: 0 } };
|
||||
|
||||
pub fn now() -> SystemTime {
|
||||
unsafe {
|
||||
let mut t: SystemTime = mem::zeroed();
|
||||
c::GetSystemTimePreciseAsFileTime(&mut t.t);
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
fn from_intervals(intervals: i64) -> SystemTime {
|
||||
SystemTime {
|
||||
t: c::FILETIME {
|
||||
dwLowDateTime: intervals as u32,
|
||||
dwHighDateTime: (intervals >> 32) as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn intervals(&self) -> i64 {
|
||||
(self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
|
||||
}
|
||||
|
||||
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
|
||||
let me = self.intervals();
|
||||
let other = other.intervals();
|
||||
if me >= other {
|
||||
Ok(intervals2dur((me - other) as u64))
|
||||
} else {
|
||||
Err(intervals2dur((other - me) as u64))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
|
||||
Some(SystemTime::from_intervals(intervals))
|
||||
}
|
||||
|
||||
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
|
||||
// Windows does not support times before 1601, hence why we don't
|
||||
// support negatives. In order to tackle this, we try to convert the
|
||||
// resulting value into an u64, which should obviously fail in the case
|
||||
// that the value is below zero.
|
||||
let intervals: u64 =
|
||||
self.intervals().checked_sub(checked_dur2intervals(other)?)?.try_into().ok()?;
|
||||
Some(SystemTime::from_intervals(intervals as i64))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for SystemTime {
|
||||
fn eq(&self, other: &SystemTime) -> bool {
|
||||
self.intervals() == other.intervals()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SystemTime {}
|
||||
|
||||
impl PartialOrd for SystemTime {
|
||||
fn partial_cmp(&self, other: &SystemTime) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for SystemTime {
|
||||
fn cmp(&self, other: &SystemTime) -> Ordering {
|
||||
self.intervals().cmp(&other.intervals())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SystemTime {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SystemTime").field("intervals", &self.intervals()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<c::FILETIME> for SystemTime {
|
||||
fn from(t: c::FILETIME) -> SystemTime {
|
||||
SystemTime { t }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<c::FILETIME> for SystemTime {
|
||||
fn into_inner(self) -> c::FILETIME {
|
||||
self.t
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for SystemTime {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.intervals().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
||||
pub fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
||||
dur.as_secs()
|
||||
.checked_mul(INTERVALS_PER_SEC)?
|
||||
.checked_add(dur.subsec_nanos() as u64 / 100)?
|
||||
|
|
@ -172,43 +14,23 @@ fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
|
|||
.ok()
|
||||
}
|
||||
|
||||
fn intervals2dur(intervals: u64) -> Duration {
|
||||
pub fn intervals2dur(intervals: u64) -> Duration {
|
||||
Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
|
||||
}
|
||||
|
||||
mod perf_counter {
|
||||
pub mod perf_counter {
|
||||
use super::NANOS_PER_SEC;
|
||||
use crate::sync::atomic::{Atomic, AtomicU64, Ordering};
|
||||
use crate::sys::helpers::mul_div_u64;
|
||||
use crate::sys::{c, cvt};
|
||||
use crate::time::Duration;
|
||||
|
||||
pub struct PerformanceCounterInstant {
|
||||
ts: i64,
|
||||
}
|
||||
impl PerformanceCounterInstant {
|
||||
pub fn now() -> Self {
|
||||
Self { ts: query() }
|
||||
}
|
||||
|
||||
// Per microsoft docs, the margin of error for cross-thread time comparisons
|
||||
// using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
|
||||
// /acquiring-high-resolution-time-stamps
|
||||
pub fn epsilon() -> Duration {
|
||||
let epsilon = NANOS_PER_SEC / (frequency() as u64);
|
||||
Duration::from_nanos(epsilon)
|
||||
}
|
||||
}
|
||||
impl From<PerformanceCounterInstant> for super::Instant {
|
||||
fn from(other: PerformanceCounterInstant) -> Self {
|
||||
let freq = frequency() as u64;
|
||||
let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq);
|
||||
Self { t: Duration::from_nanos(instant_nsec) }
|
||||
}
|
||||
pub fn now() -> i64 {
|
||||
let mut qpc_value: i64 = 0;
|
||||
cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
|
||||
qpc_value
|
||||
}
|
||||
|
||||
fn frequency() -> i64 {
|
||||
pub fn frequency() -> i64 {
|
||||
// Either the cached result of `QueryPerformanceFrequency` or `0` for
|
||||
// uninitialized. Storing this as a single `AtomicU64` allows us to use
|
||||
// `Relaxed` operations, as we are only interested in the effects on a
|
||||
|
|
@ -230,10 +52,13 @@ mod perf_counter {
|
|||
frequency
|
||||
}
|
||||
|
||||
fn query() -> i64 {
|
||||
let mut qpc_value: i64 = 0;
|
||||
cvt(unsafe { c::QueryPerformanceCounter(&mut qpc_value) }).unwrap();
|
||||
qpc_value
|
||||
// Per microsoft docs, the margin of error for cross-thread time comparisons
|
||||
// using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
|
||||
// /acquiring-high-resolution-time-stamps
|
||||
pub fn epsilon() -> Duration {
|
||||
let epsilon = NANOS_PER_SEC / (frequency() as u64);
|
||||
Duration::from_nanos(epsilon)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -241,6 +66,7 @@ mod perf_counter {
|
|||
pub(crate) struct WaitableTimer {
|
||||
handle: c::HANDLE,
|
||||
}
|
||||
|
||||
impl WaitableTimer {
|
||||
/// Creates a high-resolution timer. Will fail before Windows 10, version 1803.
|
||||
pub fn high_resolution() -> Result<Self, ()> {
|
||||
|
|
@ -254,6 +80,7 @@ impl WaitableTimer {
|
|||
};
|
||||
if !handle.is_null() { Ok(Self { handle }) } else { Err(()) }
|
||||
}
|
||||
|
||||
pub fn set(&self, duration: Duration) -> Result<(), ()> {
|
||||
// Convert the Duration to a format similar to FILETIME.
|
||||
// Negative values are relative times whereas positive values are absolute.
|
||||
|
|
@ -262,11 +89,13 @@ impl WaitableTimer {
|
|||
let result = unsafe { c::SetWaitableTimer(self.handle, &time, 0, None, null(), c::FALSE) };
|
||||
if result != 0 { Ok(()) } else { Err(()) }
|
||||
}
|
||||
|
||||
pub fn wait(&self) -> Result<(), ()> {
|
||||
let result = unsafe { c::WaitForSingleObject(self.handle, c::INFINITE) };
|
||||
if result != c::WAIT_FAILED { Ok(()) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WaitableTimer {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::CloseHandle(self.handle) };
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
pub mod os;
|
||||
pub mod time;
|
||||
|
||||
#[path = "../unsupported/common.rs"]
|
||||
mod common;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue