Merge from rustc

This commit is contained in:
The Miri Conjob Bot 2023-10-25 05:40:45 +00:00
commit 3751fb09c3
212 changed files with 3162 additions and 1413 deletions

View File

@ -4525,6 +4525,7 @@ dependencies = [
"rustc_middle", "rustc_middle",
"rustc_span", "rustc_span",
"rustc_target", "rustc_target",
"scoped-tls",
"stable_mir", "stable_mir",
"tracing", "tracing",
] ]

View File

@ -58,6 +58,9 @@ attr_invalid_repr_hint_no_paren =
attr_invalid_repr_hint_no_value = attr_invalid_repr_hint_no_value =
invalid representation hint: `{$name}` does not take a value invalid representation hint: `{$name}` does not take a value
attr_invalid_since =
'since' must be a Rust version number, such as "1.31.0"
attr_missing_feature = attr_missing_feature =
missing 'feature' missing 'feature'

View File

@ -3,6 +3,7 @@
use rustc_ast::{self as ast, attr}; use rustc_ast::{self as ast, attr};
use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId}; use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedMetaItem, NodeId};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::ErrorGuaranteed;
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use rustc_session::config::ExpectedValues; use rustc_session::config::ExpectedValues;
@ -361,25 +362,32 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
} }
} }
if let Some(s) = since let feature = match feature {
&& s.as_str() == VERSION_PLACEHOLDER Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
{ Some(_bad_feature) => {
since = Some(rust_version_symbol()); Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
} }
None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
};
let since = if let Some(since) = since {
if since.as_str() == VERSION_PLACEHOLDER {
Ok(rust_version_symbol())
} else if parse_version(since.as_str(), false).is_some() {
Ok(since)
} else {
Err(sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }))
}
} else {
Err(sess.emit_err(session_diagnostics::MissingSince { span: attr.span }))
};
match (feature, since) { match (feature, since) {
(Some(feature), Some(since)) => { (Ok(feature), Ok(since)) => {
let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false }; let level = StabilityLevel::Stable { since, allowed_through_unstable_modules: false };
Some((feature, level)) Some((feature, level))
} }
(None, _) => { (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
None
}
_ => {
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
None
}
} }
} }
@ -451,12 +459,19 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
} }
} }
match (feature, reason, issue) { let feature = match feature {
(Some(feature), reason, Some(_)) => { Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
if !rustc_lexer::is_ident(feature.as_str()) { Some(_bad_feature) => {
sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }); Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
return None; }
} None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
};
let issue =
issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
match (feature, issue) {
(Ok(feature), Ok(_)) => {
let level = StabilityLevel::Unstable { let level = StabilityLevel::Unstable {
reason: UnstableReason::from_opt_reason(reason), reason: UnstableReason::from_opt_reason(reason),
issue: issue_num, issue: issue_num,
@ -465,14 +480,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
}; };
Some((feature, level)) Some((feature, level))
} }
(None, _, _) => { (Err(ErrorGuaranteed { .. }), _) | (_, Err(ErrorGuaranteed { .. })) => None,
sess.emit_err(session_diagnostics::MissingFeature { span: attr.span });
return None;
}
_ => {
sess.emit_err(session_diagnostics::MissingIssue { span: attr.span });
return None;
}
} }
} }

View File

@ -370,6 +370,13 @@ pub(crate) struct ExpectsFeatures {
pub name: String, pub name: String,
} }
#[derive(Diagnostic)]
#[diag(attr_invalid_since)]
pub(crate) struct InvalidSince {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(attr_soft_no_args)] #[diag(attr_soft_no_args)]
pub(crate) struct SoftNoArgs { pub(crate) struct SoftNoArgs {

View File

@ -81,6 +81,10 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) { fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
if matches!(ty_context, TyContext::ReturnTy(_)) {
// We will renumber the return ty when called again with `TyContext::LocalDecl`
return;
}
*ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context)); *ty = self.renumber_regions(*ty, || RegionCtxt::TyContext(ty_context));
debug!(?ty); debug!(?ty);

View File

@ -33,7 +33,7 @@
] ]
}, },
{ {
"sysroot_src": "./download/sysroot/sysroot_src/library", "sysroot_src": "./build/stdlib/library",
"crates": [ "crates": [
{ {
"root_module": "./example/std_example.rs", "root_module": "./example/std_example.rs",

View File

@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cranelift-bforest" name = "cranelift-bforest"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5e1df0da8488dd03b34afc134ba84b754d61862cc465932a9e5d07952f661e" checksum = "c1512c3bb6b13018e7109fc3ac964bc87b329eaf3a77825d337558d0c7f6f1be"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
] ]
[[package]] [[package]]
name = "cranelift-codegen" name = "cranelift-codegen"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a17ca4e699a0aaf49a0c88f6311a864f321048aa63f6b787cab20eb5f93f10" checksum = "16cb8fb9220a6ea7a226705a273ab905309ee546267bdf34948d57932d7f0396"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"cranelift-bforest", "cranelift-bforest",
@ -75,39 +75,39 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-codegen-meta" name = "cranelift-codegen-meta"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "022f2793cdade1d37a1f755ac42938a3f832f533eac6cafc8b26b209544c3c06" checksum = "ab3a8d3b0d4745b183da5ea0792b13d79f5c23d6e69ac04761728e2532b56649"
dependencies = [ dependencies = [
"cranelift-codegen-shared", "cranelift-codegen-shared",
] ]
[[package]] [[package]]
name = "cranelift-codegen-shared" name = "cranelift-codegen-shared"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4d72dbb83c2ad788dec4ad0843070973cb48c35a3ca19b1e7437ac40834fd9c" checksum = "524141c8e68f2abc2043de4c2b31f6d9dd42432738c246431d0572a1422a4a84"
[[package]] [[package]]
name = "cranelift-control" name = "cranelift-control"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae07cf26dcc90d546826d747ac63b6c40c916f34b03e92a6ae0422c28d771b8a" checksum = "97513b57c961c713789a03886a57b43e14ebcd204cbaa8ae50ca6c70a8e716b3"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
] ]
[[package]] [[package]]
name = "cranelift-entity" name = "cranelift-entity"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2fe6b7e49820893691aea497f36257e9d6f52061d8c4758d61d802d5f101a3d" checksum = "e3f23d3cf3afa7e45f239702612c76d87964f652a55e28d13ed6d7e20f3479dd"
[[package]] [[package]]
name = "cranelift-frontend" name = "cranelift-frontend"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44f497576ca3674581581601b6a55ccc1b43447217648c880e5bce70db3cf659" checksum = "554cd4947ec9209b58bf9ae5bf83581b5ddf9128bd967208e334b504a57db54e"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"log", "log",
@ -117,15 +117,15 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-isle" name = "cranelift-isle"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b96aa02eac00fffee13b0cd37d17874ccdb3d5458983041accd825ef78ce6454" checksum = "6c1892a439696b6413cb54083806f5fd9fc431768b8de74864b3d9e8b93b124f"
[[package]] [[package]]
name = "cranelift-jit" name = "cranelift-jit"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d6e0e308c873eefc185745a6b21daec2a10f7554c9fb67e334c2d7d756d979" checksum = "32209252fb38acaf1662ccd0397907bbe0e92bdb13b6ddbfd2f74e437f83e685"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -143,9 +143,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-module" name = "cranelift-module"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1aa8ebb06eced4e478c3f94f1d65d4e7c93493f4640057912b27a3e34b84841" checksum = "bf42656f5f6df7bfafc4dd7b63a1888b0627c07b43b2cb9aa54e13843fed39eb"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -154,9 +154,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-native" name = "cranelift-native"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2870170ca44054b202c737626607b87be6e35655084bd94a6ff807a5812ba7df" checksum = "e0c2d3badd4b9690865f5bb68a71fa94de592fa2df3f3d11a5a062c60c0a107a"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"libc", "libc",
@ -165,9 +165,9 @@ dependencies = [
[[package]] [[package]]
name = "cranelift-object" name = "cranelift-object"
version = "0.101.0" version = "0.101.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20647761742d17dabac8205da958910ede78599550e06418a16711a3ee2fc897" checksum = "88eca54bbecea3170035168357306e9c779d4a63d8bf036c9e16bd21fdaa69b5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cranelift-codegen", "cranelift-codegen",
@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "wasmtime-jit-icache-coherence" name = "wasmtime-jit-icache-coherence"
version = "14.0.0" version = "14.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a5dda53ad6993f9b0a2d65fb49e0348a7232a27a8794064122870d6ee19eb2" checksum = "9aaf2fa8fd2d6b65abae9b92edfe69254cc5d6b166e342364036c3e347de8da9"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",

View File

@ -8,12 +8,12 @@ crate-type = ["dylib"]
[dependencies] [dependencies]
# These have to be in sync with each other # These have to be in sync with each other
cranelift-codegen = { version = "0.101", features = ["unwind", "all-arch"] } cranelift-codegen = { version = "0.101.1", features = ["unwind", "all-arch"] }
cranelift-frontend = { version = "0.101" } cranelift-frontend = { version = "0.101.1" }
cranelift-module = { version = "0.101" } cranelift-module = { version = "0.101.1" }
cranelift-native = { version = "0.101" } cranelift-native = { version = "0.101.1" }
cranelift-jit = { version = "0.101", optional = true } cranelift-jit = { version = "0.101.1", optional = true }
cranelift-object = { version = "0.101" } cranelift-object = { version = "0.101.1" }
target-lexicon = "0.12.0" target-lexicon = "0.12.0"
gimli = { version = "0.28", default-features = false, features = ["write"]} gimli = { version = "0.28", default-features = false, features = ["write"]}
object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }

View File

@ -8,7 +8,7 @@ If not please open an issue.
## Building and testing ## Building and testing
```bash ```bash
$ git clone https://github.com/bjorn3/rustc_codegen_cranelift $ git clone https://github.com/rust-lang/rustc_codegen_cranelift
$ cd rustc_codegen_cranelift $ cd rustc_codegen_cranelift
$ ./y.sh prepare $ ./y.sh prepare
$ ./y.sh build $ ./y.sh build
@ -29,7 +29,7 @@ Extract the `dist` directory in the archive anywhere you want.
If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`. If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`.
(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)). (tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)).
[releases]: https://github.com/bjorn3/rustc_codegen_cranelift/releases/tag/dev [releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev
## Usage ## Usage
@ -78,7 +78,7 @@ configuration options.
* Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041)) * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
* On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`. * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported) * SIMD ([tracked here](https://github.com/rust-lang/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default) * Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default)
## License ## License

View File

@ -353,6 +353,17 @@ fn main() {
let f = V([0.0, 1.0]); let f = V([0.0, 1.0]);
let _a = f.0[0]; let _a = f.0[0];
stack_val_align();
}
#[inline(never)]
fn stack_val_align() {
#[repr(align(8192))]
struct Foo(u8);
let a = Foo(0);
assert_eq!(&a as *const Foo as usize % 8192, 0);
} }
#[cfg(all( #[cfg(all(

View File

@ -1,25 +0,0 @@
From 5d4afb8d807d181038b6a004d17ed055a8d191b2 Mon Sep 17 00:00:00 2001
From: bjorn3 <17426603+bjorn3@users.noreply.github.com>
Date: Mon, 2 Oct 2023 13:59:00 +0000
Subject: [PATCH] Ignore test which gets miscompiled with llvm sysroot
---
regex-automata/src/util/pool.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/regex-automata/src/util/pool.rs b/regex-automata/src/util/pool.rs
index c03d7b0..28b233b 100644
--- a/regex-automata/src/util/pool.rs
+++ b/regex-automata/src/util/pool.rs
@@ -1081,6 +1081,8 @@ mod tests {
// into the pool. This in turn resulted in this test producing a data race.
#[cfg(feature = "std")]
#[test]
+ // FIXME(rustc_codegen_cranelift#1395) miscompilation of thread::scope with LLVM sysroot
+ #[ignore]
fn thread_owner_sync() {
let pool = Pool::new(|| vec!['a']);
{
--
2.34.1

View File

@ -120,32 +120,25 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
args: &[Value], args: &[Value],
) -> Cow<'_, [Value]> { ) -> Cow<'_, [Value]> {
if self.tcx.sess.target.is_like_windows { if self.tcx.sess.target.is_like_windows {
let (mut params, mut args): (Vec<_>, Vec<_>) = let (mut params, mut args): (Vec<_>, Vec<_>) = params
params .into_iter()
.into_iter() .zip(args)
.zip(args) .map(|(param, &arg)| {
.map(|(param, &arg)| { if param.value_type == types::I128 {
if param.value_type == types::I128 { let arg_ptr = self.create_stack_slot(16, 16);
let arg_ptr = Pointer::stack_slot(self.bcx.create_sized_stack_slot( arg_ptr.store(self, arg, MemFlags::trusted());
StackSlotData { kind: StackSlotKind::ExplicitSlot, size: 16 }, (AbiParam::new(self.pointer_type), arg_ptr.get_addr(self))
)); } else {
arg_ptr.store(self, arg, MemFlags::trusted()); (param, arg)
(AbiParam::new(self.pointer_type), arg_ptr.get_addr(self)) }
} else { })
(param, arg) .unzip();
}
})
.unzip();
let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128; let indirect_ret_val = returns.len() == 1 && returns[0].value_type == types::I128;
if indirect_ret_val { if indirect_ret_val {
params.insert(0, AbiParam::new(self.pointer_type)); params.insert(0, AbiParam::new(self.pointer_type));
let ret_ptr = let ret_ptr = self.create_stack_slot(16, 16);
Pointer::stack_slot(self.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
size: 16,
}));
args.insert(0, ret_ptr.get_addr(self)); args.insert(0, ret_ptr.get_addr(self));
self.lib_call_unadjusted(name, params, vec![], &args); self.lib_call_unadjusted(name, params, vec![], &args);
return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]); return Cow::Owned(vec![ret_ptr.load(self, types::I128, MemFlags::trusted())]);

View File

@ -189,16 +189,13 @@ pub(super) fn from_casted_value<'tcx>(
let abi_params = cast_target_to_abi_params(cast); let abi_params = cast_target_to_abi_params(cast);
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum(); let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
let layout_size = u32::try_from(layout.size.bytes()).unwrap(); let layout_size = u32::try_from(layout.size.bytes()).unwrap();
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { let ptr = fx.create_stack_slot(
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`. // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
// It may also be smaller for example when the type is a wrapper around an integer with a // It may also be smaller for example when the type is a wrapper around an integer with a
// larger alignment than the integer. // larger alignment than the integer.
size: (std::cmp::max(abi_param_size, layout_size) + 15) / 16 * 16, std::cmp::max(abi_param_size, layout_size),
}); u32::try_from(layout.align.pref.bytes()).unwrap(),
let ptr = Pointer::stack_slot(stack_slot); );
let mut offset = 0; let mut offset = 0;
let mut block_params_iter = block_params.iter().copied(); let mut block_params_iter = block_params.iter().copied();
for param in abi_params { for param in abi_params {

View File

@ -104,11 +104,7 @@ pub(crate) fn clif_int_or_float_cast(
&[from], &[from],
)[0]; )[0];
// FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128 // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { let ret_ptr = fx.create_stack_slot(16, 16);
kind: StackSlotKind::ExplicitSlot,
size: 16,
});
let ret_ptr = Pointer::stack_slot(stack_slot);
ret_ptr.store(fx, ret, MemFlags::trusted()); ret_ptr.store(fx, ret, MemFlags::trusted());
ret_ptr.load(fx, types::I128, MemFlags::trusted()) ret_ptr.load(fx, types::I128, MemFlags::trusted())
} else { } else {

View File

@ -383,6 +383,25 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
}) })
} }
pub(crate) fn create_stack_slot(&mut self, size: u32, align: u32) -> Pointer {
if align <= 16 {
let stack_slot = self.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
size: (size + 15) / 16 * 16,
});
Pointer::stack_slot(stack_slot)
} else {
// Alignment is too big to handle using the above hack. Dynamically realign a stack slot
// instead. This wastes some space for the realignment.
let base_ptr = self.create_stack_slot(size + align, 16).get_addr(self);
let misalign_offset = self.bcx.ins().urem_imm(base_ptr, i64::from(align));
let realign_offset = self.bcx.ins().irsub_imm(misalign_offset, i64::from(align));
Pointer::new(self.bcx.ins().iadd(base_ptr, realign_offset))
}
}
pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) { pub(crate) fn set_debug_loc(&mut self, source_info: mir::SourceInfo) {
if let Some(debug_context) = &mut self.cx.debug_context { if let Some(debug_context) = &mut self.cx.debug_context {
let (file, line, column) = let (file, line, column) =

View File

@ -361,12 +361,26 @@ pub(crate) fn run_aot(
metadata: EncodedMetadata, metadata: EncodedMetadata,
need_metadata_module: bool, need_metadata_module: bool,
) -> Box<OngoingCodegen> { ) -> Box<OngoingCodegen> {
// FIXME handle `-Ctarget-cpu=native`
let target_cpu = match tcx.sess.opts.cg.target_cpu {
Some(ref name) => name,
None => tcx.sess.target.cpu.as_ref(),
}
.to_owned();
let cgus = if tcx.sess.opts.output_types.should_codegen() { let cgus = if tcx.sess.opts.output_types.should_codegen() {
tcx.collect_and_partition_mono_items(()).1 tcx.collect_and_partition_mono_items(()).1
} else { } else {
// If only `--emit metadata` is used, we shouldn't perform any codegen. // If only `--emit metadata` is used, we shouldn't perform any codegen.
// Also `tcx.collect_and_partition_mono_items` may panic in that case. // Also `tcx.collect_and_partition_mono_items` may panic in that case.
&[] return Box::new(OngoingCodegen {
modules: vec![],
allocator_module: None,
metadata_module: None,
metadata,
crate_info: CrateInfo::new(tcx, target_cpu),
concurrency_limiter: ConcurrencyLimiter::new(tcx.sess, 0),
});
}; };
if tcx.dep_graph.is_fully_enabled() { if tcx.dep_graph.is_fully_enabled() {
@ -481,13 +495,6 @@ pub(crate) fn run_aot(
None None
}; };
// FIXME handle `-Ctarget-cpu=native`
let target_cpu = match tcx.sess.opts.cg.target_cpu {
Some(ref name) => name,
None => tcx.sess.target.cpu.as_ref(),
}
.to_owned();
Box::new(OngoingCodegen { Box::new(OngoingCodegen {
modules, modules,
allocator_module, allocator_module,

View File

@ -878,13 +878,7 @@ fn call_inline_asm<'tcx>(
inputs: Vec<(Size, Value)>, inputs: Vec<(Size, Value)>,
outputs: Vec<(Size, CPlace<'tcx>)>, outputs: Vec<(Size, CPlace<'tcx>)>,
) { ) {
let stack_slot = fx.bcx.func.create_sized_stack_slot(StackSlotData { let stack_slot = fx.create_stack_slot(u32::try_from(slot_size.bytes()).unwrap(), 16);
kind: StackSlotKind::ExplicitSlot,
size: u32::try_from(slot_size.bytes()).unwrap(),
});
if fx.clif_comments.enabled() {
fx.add_comment(stack_slot, "inline asm scratch slot");
}
let inline_asm_func = fx let inline_asm_func = fx
.module .module
@ -904,15 +898,23 @@ fn call_inline_asm<'tcx>(
} }
for (offset, value) in inputs { for (offset, value) in inputs {
fx.bcx.ins().stack_store(value, stack_slot, i32::try_from(offset.bytes()).unwrap()); stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).store(
fx,
value,
MemFlags::trusted(),
);
} }
let stack_slot_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0); let stack_slot_addr = stack_slot.get_addr(fx);
fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]); fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]);
for (offset, place) in outputs { for (offset, place) in outputs {
let ty = fx.clif_type(place.layout().ty).unwrap(); let ty = fx.clif_type(place.layout().ty).unwrap();
let value = fx.bcx.ins().stack_load(ty, stack_slot, i32::try_from(offset.bytes()).unwrap()); let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load(
fx,
ty,
MemFlags::trusted(),
);
place.write_cvalue(fx, CValue::by_val(value, place.layout())); place.write_cvalue(fx, CValue::by_val(value, place.layout()));
} }
} }

View File

@ -310,6 +310,143 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
let val = CValue::by_val_pair(cb_out, c, layout); let val = CValue::by_val_pair(cb_out, c, layout);
ret.write_cvalue(fx, val); ret.write_cvalue(fx, val);
} }
"llvm.x86.sse2.pavg.b" | "llvm.x86.sse2.pavg.w" => {
intrinsic_args!(fx, args => (a, b); intrinsic);
// FIXME use vector instructions when possible
simd_pair_for_each_lane(
fx,
a,
b,
ret,
&|fx, _lane_ty, _res_lane_ty, a_lane, b_lane| {
// (a + b + 1) >> 1
let lane_ty = fx.bcx.func.dfg.value_type(a_lane);
let a_lane = fx.bcx.ins().uextend(lane_ty.double_width().unwrap(), a_lane);
let b_lane = fx.bcx.ins().uextend(lane_ty.double_width().unwrap(), b_lane);
let sum = fx.bcx.ins().iadd(a_lane, b_lane);
let num_plus_one = fx.bcx.ins().iadd_imm(sum, 1);
let res = fx.bcx.ins().ushr_imm(num_plus_one, 1);
fx.bcx.ins().ireduce(lane_ty, res)
},
);
}
"llvm.x86.sse2.psra.w" => {
intrinsic_args!(fx, args => (a, count); intrinsic);
let count_lane = count.force_stack(fx).0.load(fx, types::I64, MemFlags::trusted());
let lane_ty = fx.clif_type(a.layout().ty.simd_size_and_type(fx.tcx).1).unwrap();
let max_count = fx.bcx.ins().iconst(types::I64, i64::from(lane_ty.bits() - 1));
let saturated_count = fx.bcx.ins().umin(count_lane, max_count);
// FIXME use vector instructions when possible
simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, a_lane| {
fx.bcx.ins().sshr(a_lane, saturated_count)
});
}
"llvm.x86.sse2.psad.bw" => {
intrinsic_args!(fx, args => (a, b); intrinsic);
assert_eq!(a.layout(), b.layout());
let layout = a.layout();
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_ty, fx.tcx.types.u8);
assert_eq!(ret_lane_ty, fx.tcx.types.u64);
assert_eq!(lane_count, ret_lane_count * 8);
let ret_lane_layout = fx.layout_of(fx.tcx.types.u64);
for out_lane_idx in 0..lane_count / 8 {
let mut lane_diff_acc = fx.bcx.ins().iconst(types::I64, 0);
for lane_idx in out_lane_idx * 8..out_lane_idx * 8 + 1 {
let a_lane = a.value_lane(fx, lane_idx).load_scalar(fx);
let b_lane = b.value_lane(fx, lane_idx).load_scalar(fx);
let lane_diff = fx.bcx.ins().isub(a_lane, b_lane);
let abs_lane_diff = fx.bcx.ins().iabs(lane_diff);
let abs_lane_diff = fx.bcx.ins().uextend(types::I64, abs_lane_diff);
lane_diff_acc = fx.bcx.ins().iadd(lane_diff_acc, abs_lane_diff);
}
let res_lane = CValue::by_val(lane_diff_acc, ret_lane_layout);
ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
}
}
"llvm.x86.ssse3.pmadd.ub.sw.128" => {
intrinsic_args!(fx, args => (a, b); intrinsic);
let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_ty, fx.tcx.types.u8);
assert_eq!(ret_lane_ty, fx.tcx.types.i16);
assert_eq!(lane_count, ret_lane_count * 2);
let ret_lane_layout = fx.layout_of(fx.tcx.types.i16);
for out_lane_idx in 0..lane_count / 2 {
let a_lane0 = a.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
let a_lane0 = fx.bcx.ins().uextend(types::I16, a_lane0);
let b_lane0 = b.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
let b_lane0 = fx.bcx.ins().sextend(types::I16, b_lane0);
let a_lane1 = a.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
let a_lane1 = fx.bcx.ins().uextend(types::I16, a_lane1);
let b_lane1 = b.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
let b_lane1 = fx.bcx.ins().sextend(types::I16, b_lane1);
let mul0: Value = fx.bcx.ins().imul(a_lane0, b_lane0);
let mul1 = fx.bcx.ins().imul(a_lane1, b_lane1);
let (val, has_overflow) = fx.bcx.ins().sadd_overflow(mul0, mul1);
let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, mul1, 0);
let min = fx.bcx.ins().iconst(types::I16, i64::from(i16::MIN as u16));
let max = fx.bcx.ins().iconst(types::I16, i64::from(i16::MAX as u16));
let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
let res_lane = fx.bcx.ins().select(has_overflow, sat_val, val);
let res_lane = CValue::by_val(res_lane, ret_lane_layout);
ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
}
}
"llvm.x86.sse2.pmadd.wd" => {
intrinsic_args!(fx, args => (a, b); intrinsic);
assert_eq!(a.layout(), b.layout());
let layout = a.layout();
let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
assert_eq!(lane_ty, fx.tcx.types.i16);
assert_eq!(ret_lane_ty, fx.tcx.types.i32);
assert_eq!(lane_count, ret_lane_count * 2);
let ret_lane_layout = fx.layout_of(fx.tcx.types.i32);
for out_lane_idx in 0..lane_count / 2 {
let a_lane0 = a.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
let a_lane0 = fx.bcx.ins().uextend(types::I32, a_lane0);
let b_lane0 = b.value_lane(fx, out_lane_idx * 2).load_scalar(fx);
let b_lane0 = fx.bcx.ins().sextend(types::I32, b_lane0);
let a_lane1 = a.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
let a_lane1 = fx.bcx.ins().uextend(types::I32, a_lane1);
let b_lane1 = b.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx);
let b_lane1 = fx.bcx.ins().sextend(types::I32, b_lane1);
let mul0: Value = fx.bcx.ins().imul(a_lane0, b_lane0);
let mul1 = fx.bcx.ins().imul(a_lane1, b_lane1);
let res_lane = fx.bcx.ins().iadd(mul0, mul1);
let res_lane = CValue::by_val(res_lane, ret_lane_layout);
ret.place_lane(fx, out_lane_idx).write_cvalue(fx, res_lane);
}
}
_ => { _ => {
fx.tcx fx.tcx
.sess .sess

View File

@ -132,18 +132,11 @@ impl<'tcx> CValue<'tcx> {
(ptr.get_addr(fx), vtable) (ptr.get_addr(fx), vtable)
} }
CValueInner::ByValPair(data, vtable) => { CValueInner::ByValPair(data, vtable) => {
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { let data_ptr = fx.create_stack_slot(
kind: StackSlotKind::ExplicitSlot, u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(),
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to u32::try_from(fx.target_config.pointer_type().bytes()).unwrap(),
// specify stack slot alignment. );
size: (u32::try_from(fx.target_config.pointer_type().bytes()).unwrap() + 15) data_ptr.store(fx, data, MemFlags::trusted());
/ 16
* 16,
});
let data_ptr = Pointer::stack_slot(stack_slot);
let mut flags = MemFlags::new();
flags.set_notrap();
data_ptr.store(fx, data, flags);
(data_ptr.get_addr(fx), vtable) (data_ptr.get_addr(fx), vtable)
} }
@ -372,13 +365,11 @@ impl<'tcx> CPlace<'tcx> {
.fatal(format!("values of type {} are too big to store on the stack", layout.ty)); .fatal(format!("values of type {} are too big to store on the stack", layout.ty));
} }
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { let stack_slot = fx.create_stack_slot(
kind: StackSlotKind::ExplicitSlot, u32::try_from(layout.size.bytes()).unwrap(),
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to u32::try_from(layout.align.pref.bytes()).unwrap(),
// specify stack slot alignment. );
size: (u32::try_from(layout.size.bytes()).unwrap() + 15) / 16 * 16, CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout }
});
CPlace { inner: CPlaceInner::Addr(Pointer::stack_slot(stack_slot), None), layout }
} }
pub(crate) fn new_var( pub(crate) fn new_var(
@ -543,13 +534,7 @@ impl<'tcx> CPlace<'tcx> {
_ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data), _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
_ if src_ty.is_vector() || dst_ty.is_vector() => { _ if src_ty.is_vector() || dst_ty.is_vector() => {
// FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers. // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers.
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData { let ptr = fx.create_stack_slot(src_ty.bytes(), src_ty.bytes());
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
// specify stack slot alignment.
size: (src_ty.bytes() + 15) / 16 * 16,
});
let ptr = Pointer::stack_slot(stack_slot);
ptr.store(fx, data, MemFlags::trusted()); ptr.store(fx, data, MemFlags::trusted());
ptr.load(fx, dst_ty, MemFlags::trusted()) ptr.load(fx, dst_ty, MemFlags::trusted())
} }

View File

@ -342,6 +342,19 @@ const CSKY_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("hard-float-abi", Some(sym::csky_target_feature)), ("hard-float-abi", Some(sym::csky_target_feature)),
// tidy-alphabetical-end // tidy-alphabetical-end
]; ];
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// tidy-alphabetical-start
("d", Some(sym::loongarch_target_feature)),
("f", Some(sym::loongarch_target_feature)),
("lasx", Some(sym::loongarch_target_feature)),
("lbt", Some(sym::loongarch_target_feature)),
("lsx", Some(sym::loongarch_target_feature)),
("lvz", Some(sym::loongarch_target_feature)),
("ual", Some(sym::loongarch_target_feature)),
// tidy-alphabetical-end
];
/// When rustdoc is running, provide a list of all known features so that all their respective /// When rustdoc is running, provide a list of all known features so that all their respective
/// primitives may be documented. /// primitives may be documented.
/// ///
@ -358,6 +371,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol
.chain(WASM_ALLOWED_FEATURES.iter()) .chain(WASM_ALLOWED_FEATURES.iter())
.chain(BPF_ALLOWED_FEATURES.iter()) .chain(BPF_ALLOWED_FEATURES.iter())
.chain(CSKY_ALLOWED_FEATURES) .chain(CSKY_ALLOWED_FEATURES)
.chain(LOONGARCH_ALLOWED_FEATURES)
.cloned() .cloned()
} }
@ -373,6 +387,7 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
"wasm32" | "wasm64" => WASM_ALLOWED_FEATURES, "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
"bpf" => BPF_ALLOWED_FEATURES, "bpf" => BPF_ALLOWED_FEATURES,
"csky" => CSKY_ALLOWED_FEATURES, "csky" => CSKY_ALLOWED_FEATURES,
"loongarch64" => LOONGARCH_ALLOWED_FEATURES,
_ => &[], _ => &[],
} }
} }
@ -445,6 +460,7 @@ pub fn from_target_feature(
Some(sym::bpf_target_feature) => rust_features.bpf_target_feature, Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature, Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
Some(sym::csky_target_feature) => rust_features.csky_target_feature, Some(sym::csky_target_feature) => rust_features.csky_target_feature,
Some(sym::loongarch_target_feature) => rust_features.loongarch_target_feature,
Some(name) => bug!("unknown target feature gate {}", name), Some(name) => bug!("unknown target feature gate {}", name),
None => true, None => true,
}; };

View File

@ -1010,7 +1010,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Just make this an efficient immediate. // Just make this an efficient immediate.
// Note that not calling `layout_of` here does have one real consequence: // Note that not calling `layout_of` here does have one real consequence:
// if the type is too big, we'll only notice this when the local is actually initialized, // if the type is too big, we'll only notice this when the local is actually initialized,
// which is a bit too late -- we should ideally notice this alreayd here, when the memory // which is a bit too late -- we should ideally notice this already here, when the memory
// is conceptually allocated. But given how rare that error is and that this is a hot function, // is conceptually allocated. But given how rare that error is and that this is a hot function,
// we accept this downside for now. // we accept this downside for now.
Operand::Immediate(Immediate::Uninit) Operand::Immediate(Immediate::Uninit)

View File

@ -825,6 +825,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_hidden_type_of_opaques, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),

View File

@ -288,6 +288,7 @@ declare_features! (
(unstable, csky_target_feature, "1.73.0", Some(44839), None), (unstable, csky_target_feature, "1.73.0", Some(44839), None),
(unstable, ermsb_target_feature, "1.49.0", Some(44839), None), (unstable, ermsb_target_feature, "1.49.0", Some(44839), None),
(unstable, hexagon_target_feature, "1.27.0", Some(44839), None), (unstable, hexagon_target_feature, "1.27.0", Some(44839), None),
(unstable, loongarch_target_feature, "1.73.0", Some(44839), None),
(unstable, mips_target_feature, "1.27.0", Some(44839), None), (unstable, mips_target_feature, "1.27.0", Some(44839), None),
(unstable, powerpc_target_feature, "1.27.0", Some(44839), None), (unstable, powerpc_target_feature, "1.27.0", Some(44839), None),
(unstable, riscv_target_feature, "1.45.0", Some(44839), None), (unstable, riscv_target_feature, "1.45.0", Some(44839), None),

View File

@ -72,6 +72,12 @@ hir_analysis_copy_impl_on_type_with_dtor =
the trait `Copy` cannot be implemented for this type; the type has a destructor the trait `Copy` cannot be implemented for this type; the type has a destructor
.label = `Copy` not allowed on types with destructors .label = `Copy` not allowed on types with destructors
hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type, not `{$self_ty}`
.label = can't implement cross-crate trait with a default impl for non-struct/enum type
hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
.label = can't implement cross-crate trait for type in another crate
hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
.note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
.coercions_note = currently, {$number} fields need coercions: {$coercions} .coercions_note = currently, {$number} fields need coercions: {$coercions}
@ -237,6 +243,28 @@ hir_analysis_must_implement_not_function_span_note = required by this annotation
hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
hir_analysis_only_current_traits_arbitrary = only traits defined in the current crate can be implemented for arbitrary types
hir_analysis_only_current_traits_foreign = this is not defined in the current crate because this is a foreign trait
hir_analysis_only_current_traits_label = impl doesn't use only types from inside the current crate
hir_analysis_only_current_traits_name = this is not defined in the current crate because {$name} are always foreign
hir_analysis_only_current_traits_note = define and implement a trait or new type instead
hir_analysis_only_current_traits_opaque = type alias impl trait is treated as if it were foreign, because its hidden type could be from a foreign crate
hir_analysis_only_current_traits_outside = only traits defined in the current crate can be implemented for types defined outside of the crate
hir_analysis_only_current_traits_pointer = `{$pointer}` is not defined in the current crate because raw pointers are always foreign
hir_analysis_only_current_traits_pointer_sugg = consider introducing a new wrapper type
hir_analysis_only_current_traits_primitive = only traits defined in the current crate can be implemented for primitive types
hir_analysis_only_current_traits_ty = `{$ty}` is not defined in the current crate
hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
.help = add `#![feature(unboxed_closures)]` to the crate attributes to use it .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
@ -326,6 +354,9 @@ hir_analysis_trait_object_declared_with_no_traits =
at least one trait is required for an object type at least one trait is required for an object type
.alias_span = this alias does not contain a trait .alias_span = this alias does not contain a trait
hir_analysis_traits_with_defualt_impl = traits with a default impl, like `{$traits}`, cannot be implemented for {$problematic_kind} `{$self_ty}`
.note = a trait object implements `{$traits}` if and only if `{$traits}` is one of the trait object's trait bounds
hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number} hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
.label = needs exactly one variant, but has {$number} .label = needs exactly one variant, but has {$number}
.many_label = too many variants in `{$path}` .many_label = too many variants in `{$path}`
@ -339,6 +370,18 @@ hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$de
.label = needs at most one field with non-trivial size or alignment, but has {$field_count} .label = needs at most one field with non-trivial size or alignment, but has {$field_count}
.labels = this field has non-zero size or requires alignment .labels = this field has non-zero size or requires alignment
hir_analysis_ty_param_first_local = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
.label = type parameter `{$param_ty}` must be covered by another type when it appears before the first local type (`{$local_type}`)
.note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type
.case_note = in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
hir_analysis_ty_param_some = type parameter `{$param_ty}` must be used as the type parameter for some local type (e.g., `MyStruct<{$param_ty}>`)
.label = type parameter `{$param_ty}` must be used as the type parameter for some local type
.note = implementing a foreign trait is only possible if at least one of the types for which it is implemented is local
.only_note = only traits defined in the current crate can be implemented for a type parameter
hir_analysis_type_of = {$type_of}
hir_analysis_typeof_reserved_keyword_used = hir_analysis_typeof_reserved_keyword_used =
`typeof` is a reserved keyword but unimplemented `typeof` is a reserved keyword but unimplemented
.suggestion = consider replacing `typeof(...)` with an actual type .suggestion = consider replacing `typeof(...)` with an actual type

View File

@ -2,8 +2,7 @@
//! crate or pertains to a type defined in this crate. //! crate or pertains to a type defined in this crate.
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, DelayDm}; use rustc_errors::{DelayDm, ErrorGuaranteed};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::GenericArgs; use rustc_middle::ty::GenericArgs;
@ -17,6 +16,8 @@ use rustc_span::Span;
use rustc_trait_selection::traits; use rustc_trait_selection::traits;
use std::ops::ControlFlow; use std::ops::ControlFlow;
use crate::errors;
#[instrument(skip(tcx), level = "debug")] #[instrument(skip(tcx), level = "debug")]
pub(crate) fn orphan_check_impl( pub(crate) fn orphan_check_impl(
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
@ -259,49 +260,30 @@ fn do_orphan_check_impl<'tcx>(
match local_impl { match local_impl {
LocalImpl::Allow => {} LocalImpl::Allow => {}
LocalImpl::Disallow { problematic_kind } => { LocalImpl::Disallow { problematic_kind } => {
let msg = format!( return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl {
"traits with a default impl, like `{trait}`, \ span: tcx.def_span(def_id),
cannot be implemented for {problematic_kind} `{self_ty}`", traits: tcx.def_path_str(trait_def_id),
trait = tcx.def_path_str(trait_def_id), problematic_kind,
); self_ty,
let label = format!( }));
"a trait object implements `{trait}` if and only if `{trait}` \
is one of the trait object's trait bounds",
trait = tcx.def_path_str(trait_def_id),
);
let sp = tcx.def_span(def_id);
let reported =
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).note(label).emit();
return Err(reported);
} }
} }
} else { } else {
if let Some((msg, label)) = match nonlocal_impl { match nonlocal_impl {
NonlocalImpl::Allow => None, NonlocalImpl::Allow => {}
NonlocalImpl::DisallowBecauseNonlocal => Some(( NonlocalImpl::DisallowBecauseNonlocal => {
format!( return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined {
"cross-crate traits with a default impl, like `{}`, \ span: tcx.def_span(def_id),
can only be implemented for a struct/enum type \ traits: tcx.def_path_str(trait_def_id),
defined in the current crate", }));
tcx.def_path_str(trait_def_id) }
), NonlocalImpl::DisallowOther => {
"can't implement cross-crate trait for type in another crate", return Err(tcx.sess.emit_err(errors::CrossCrateTraits {
)), span: tcx.def_span(def_id),
NonlocalImpl::DisallowOther => Some(( traits: tcx.def_path_str(trait_def_id),
format!( self_ty,
"cross-crate traits with a default impl, like `{}`, can \ }));
only be implemented for a struct/enum type, not `{}`", }
tcx.def_path_str(trait_def_id),
self_ty
),
"can't implement cross-crate trait with a default impl for \
non-struct/enum type",
)),
} {
let sp = tcx.def_span(def_id);
let reported =
struct_span_err!(tcx.sess, sp, E0321, "{}", msg).span_label(sp, label).emit();
return Err(reported);
} }
} }
} }
@ -322,19 +304,18 @@ fn emit_orphan_check_error<'tcx>(
let self_ty = trait_ref.self_ty(); let self_ty = trait_ref.self_ty();
Err(match err { Err(match err {
traits::OrphanCheckErr::NonLocalInputType(tys) => { traits::OrphanCheckErr::NonLocalInputType(tys) => {
let msg = match self_ty.kind() { let (mut opaque, mut foreign, mut name, mut pointer, mut ty_diag) =
ty::Adt(..) => "can be implemented for types defined outside of the crate", (Vec::new(), Vec::new(), Vec::new(), Vec::new(), Vec::new());
_ if self_ty.is_primitive() => "can be implemented for primitive types", let mut sugg = None;
_ => "can be implemented for arbitrary types",
};
let mut err = struct_span_err!(
tcx.sess,
sp,
E0117,
"only traits defined in the current crate {msg}"
);
err.span_label(sp, "impl doesn't use only types from inside the current crate");
for &(mut ty, is_target_ty) in &tys { for &(mut ty, is_target_ty) in &tys {
let span = if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
self_ty_span
} else {
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
trait_span
};
ty = tcx.erase_regions(ty); ty = tcx.erase_regions(ty);
ty = match ty.kind() { ty = match ty.kind() {
// Remove the type arguments from the output, as they are not relevant. // Remove the type arguments from the output, as they are not relevant.
@ -345,50 +326,103 @@ fn emit_orphan_check_error<'tcx>(
ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()), ty::Adt(def, _) => Ty::new_adt(tcx, *def, ty::List::empty()),
_ => ty, _ => ty,
}; };
let msg = |ty: &str, postfix: &str| {
format!("{ty} is not defined in the current crate{postfix}")
};
let this = |name: &str| { fn push_to_foreign_or_name<'tcx>(
if !trait_ref.def_id.is_local() && !is_target_ty { is_foreign: bool,
msg("this", " because this is a foreign trait") foreign: &mut Vec<errors::OnlyCurrentTraitsForeign>,
name: &mut Vec<errors::OnlyCurrentTraitsName<'tcx>>,
span: Span,
sname: &'tcx str,
) {
if is_foreign {
foreign.push(errors::OnlyCurrentTraitsForeign { span })
} else { } else {
msg("this", &format!(" because {name} are always foreign")) name.push(errors::OnlyCurrentTraitsName { span, name: sname });
}
}
let is_foreign = !trait_ref.def_id.is_local() && !is_target_ty;
match &ty.kind() {
ty::Slice(_) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"slices",
);
}
ty::Array(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"arrays",
);
}
ty::Tuple(..) => {
push_to_foreign_or_name(
is_foreign,
&mut foreign,
&mut name,
span,
"tuples",
);
} }
};
let msg = match &ty.kind() {
ty::Slice(_) => this("slices"),
ty::Array(..) => this("arrays"),
ty::Tuple(..) => this("tuples"),
ty::Alias(ty::Opaque, ..) => { ty::Alias(ty::Opaque, ..) => {
"type alias impl trait is treated as if it were foreign, \ opaque.push(errors::OnlyCurrentTraitsOpaque { span })
because its hidden type could be from a foreign crate"
.to_string()
} }
ty::RawPtr(ptr_ty) => { ty::RawPtr(ptr_ty) => {
emit_newtype_suggestion_for_raw_ptr( if !self_ty.has_param() {
full_impl_span, let mut_key = ptr_ty.mutbl.prefix_str();
self_ty, sugg = Some(errors::OnlyCurrentTraitsPointerSugg {
self_ty_span, wrapper_span: self_ty_span,
ptr_ty, struct_span: full_impl_span.shrink_to_lo(),
&mut err, mut_key,
); ptr_ty: ptr_ty.ty,
});
msg(&format!("`{ty}`"), " because raw pointers are always foreign") }
pointer.push(errors::OnlyCurrentTraitsPointer { span, pointer: ty });
} }
_ => msg(&format!("`{ty}`"), ""), _ => ty_diag.push(errors::OnlyCurrentTraitsTy { span, ty }),
};
if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
err.span_label(self_ty_span, msg);
} else {
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
err.span_label(trait_span, msg);
} }
} }
err.note("define and implement a trait or new type instead");
err.emit() let err_struct = match self_ty.kind() {
ty::Adt(..) => errors::OnlyCurrentTraits::Outside {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
_ if self_ty.is_primitive() => errors::OnlyCurrentTraits::Primitive {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
_ => errors::OnlyCurrentTraits::Arbitrary {
span: sp,
note: (),
opaque,
foreign,
name,
pointer,
ty: ty_diag,
sugg,
},
};
tcx.sess.emit_err(err_struct)
} }
traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => { traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
let mut sp = sp; let mut sp = sp;
@ -399,85 +433,18 @@ fn emit_orphan_check_error<'tcx>(
} }
match local_type { match local_type {
Some(local_type) => struct_span_err!( Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal {
tcx.sess, span: sp,
sp, note: (),
E0210,
"type parameter `{}` must be covered by another type \
when it appears before the first local type (`{}`)",
param_ty, param_ty,
local_type local_type,
) }),
.span_label( None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
sp,
format!(
"type parameter `{param_ty}` must be covered by another type \
when it appears before the first local type (`{local_type}`)"
),
)
.note(
"implementing a foreign trait is only possible if at \
least one of the types for which it is implemented is local, \
and no uncovered type parameters appear before that first \
local type",
)
.note(
"in this case, 'before' refers to the following order: \
`impl<..> ForeignTrait<T1, ..., Tn> for T0`, \
where `T0` is the first and `Tn` is the last",
)
.emit(),
None => struct_span_err!(
tcx.sess,
sp,
E0210,
"type parameter `{}` must be used as the type parameter for some \
local type (e.g., `MyStruct<{}>`)",
param_ty,
param_ty
)
.span_label(
sp,
format!(
"type parameter `{param_ty}` must be used as the type parameter for some \
local type",
),
)
.note(
"implementing a foreign trait is only possible if at \
least one of the types for which it is implemented is local",
)
.note(
"only traits defined in the current crate can be \
implemented for a type parameter",
)
.emit(),
} }
} }
}) })
} }
fn emit_newtype_suggestion_for_raw_ptr(
full_impl_span: Span,
self_ty: Ty<'_>,
self_ty_span: Span,
ptr_ty: &ty::TypeAndMut<'_>,
diag: &mut Diagnostic,
) {
if !self_ty.has_param() {
let mut_key = ptr_ty.mutbl.prefix_str();
let msg_sugg = "consider introducing a new wrapper type".to_owned();
let sugg = vec![
(
full_impl_span.shrink_to_lo(),
format!("struct WrapperType(*{}{});\n\n", mut_key, ptr_ty.ty),
),
(self_ty_span, "WrapperType".to_owned()),
];
diag.multipart_suggestion(msg_sugg, sugg, rustc_errors::Applicability::MaybeIncorrect);
}
}
/// Lint impls of auto traits if they are likely to have /// Lint impls of auto traits if they are likely to have
/// unsound or surprising effects on auto impls. /// unsound or surprising effects on auto impls.
fn lint_auto_trait_impl<'tcx>( fn lint_auto_trait_impl<'tcx>(

View File

@ -14,14 +14,11 @@
//! At present, however, we do run collection across all items in the //! At present, however, we do run collection across all items in the
//! crate as a kind of pass. This should eventually be factored away. //! crate as a kind of pass. This should eventually be factored away.
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
use hir::def::DefKind;
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{GenericParamKind, Node}; use rustc_hir::{GenericParamKind, Node};
@ -40,6 +37,11 @@ use rustc_trait_selection::traits::ObligationCtxt;
use std::iter; use std::iter;
use std::ops::Bound; use std::ops::Bound;
use crate::astconv::AstConv;
use crate::check::intrinsic::intrinsic_operation_unsafety;
use crate::errors;
pub use type_of::test_opaque_hidden_types;
mod generics_of; mod generics_of;
mod item_bounds; mod item_bounds;
mod predicates_of; mod predicates_of;

View File

@ -11,6 +11,7 @@ use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt; use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty}; use super::{bad_placeholder, is_suggestable_infer_ty};
pub use opaque::test_opaque_hidden_types;
mod opaque; mod opaque;

View File

@ -1,12 +1,25 @@
use rustc_errors::StashKey; use rustc_errors::StashKey;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem}; use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP; use rustc_span::{sym, DUMMY_SP};
use crate::errors::{TaitForwardCompat, UnconstrainedOpaqueType}; use crate::errors::{TaitForwardCompat, TypeOf, UnconstrainedOpaqueType};
pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
let type_of = tcx.type_of(id.owner_id).instantiate_identity();
tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
}
}
}
}
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions /// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
/// laid for "higher-order pattern unification". /// laid for "higher-order pattern unification".

View File

@ -467,6 +467,14 @@ pub(crate) struct VariancesOf {
pub variances_of: String, pub variances_of: String,
} }
#[derive(Diagnostic)]
#[diag(hir_analysis_type_of)]
pub(crate) struct TypeOf<'tcx> {
#[primary_span]
pub span: Span,
pub type_of: Ty<'tcx>,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(hir_analysis_pass_to_variadic_function, code = "E0617")] #[diag(hir_analysis_pass_to_variadic_function, code = "E0617")]
pub(crate) struct PassToVariadicFunction<'tcx, 'a> { pub(crate) struct PassToVariadicFunction<'tcx, 'a> {
@ -675,7 +683,6 @@ pub(crate) struct SIMDFFIHighlyExperimental {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
pub enum ImplNotMarkedDefault { pub enum ImplNotMarkedDefault {
#[diag(hir_analysis_impl_not_marked_default, code = "E0520")] #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
#[note] #[note]
@ -1151,3 +1158,174 @@ pub struct ImplForTyRequires {
pub trait_name: String, pub trait_name: String,
pub ty: String, pub ty: String,
} }
#[derive(Diagnostic)]
#[diag(hir_analysis_traits_with_defualt_impl, code = "E0321")]
#[note]
pub struct TraitsWithDefaultImpl<'a> {
#[primary_span]
pub span: Span,
pub traits: String,
pub problematic_kind: &'a str,
pub self_ty: Ty<'a>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_cross_crate_traits, code = "E0321")]
pub struct CrossCrateTraits<'a> {
#[primary_span]
#[label]
pub span: Span,
pub traits: String,
pub self_ty: Ty<'a>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_cross_crate_traits_defined, code = "E0321")]
pub struct CrossCrateTraitsDefined {
#[primary_span]
#[label]
pub span: Span,
pub traits: String,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_ty_param_first_local, code = "E0210")]
#[note]
pub struct TyParamFirstLocal<'a> {
#[primary_span]
#[label]
pub span: Span,
#[note(hir_analysis_case_note)]
pub note: (),
pub param_ty: Ty<'a>,
pub local_type: Ty<'a>,
}
#[derive(Diagnostic)]
#[diag(hir_analysis_ty_param_some, code = "E0210")]
#[note]
pub struct TyParamSome<'a> {
#[primary_span]
#[label]
pub span: Span,
#[note(hir_analysis_only_note)]
pub note: (),
pub param_ty: Ty<'a>,
}
#[derive(Diagnostic)]
pub enum OnlyCurrentTraits<'a> {
#[diag(hir_analysis_only_current_traits_outside, code = "E0117")]
Outside {
#[primary_span]
#[label(hir_analysis_only_current_traits_label)]
span: Span,
#[note(hir_analysis_only_current_traits_note)]
note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
},
#[diag(hir_analysis_only_current_traits_primitive, code = "E0117")]
Primitive {
#[primary_span]
#[label(hir_analysis_only_current_traits_label)]
span: Span,
#[note(hir_analysis_only_current_traits_note)]
note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
},
#[diag(hir_analysis_only_current_traits_arbitrary, code = "E0117")]
Arbitrary {
#[primary_span]
#[label(hir_analysis_only_current_traits_label)]
span: Span,
#[note(hir_analysis_only_current_traits_note)]
note: (),
#[subdiagnostic]
opaque: Vec<OnlyCurrentTraitsOpaque>,
#[subdiagnostic]
foreign: Vec<OnlyCurrentTraitsForeign>,
#[subdiagnostic]
name: Vec<OnlyCurrentTraitsName<'a>>,
#[subdiagnostic]
pointer: Vec<OnlyCurrentTraitsPointer<'a>>,
#[subdiagnostic]
ty: Vec<OnlyCurrentTraitsTy<'a>>,
#[subdiagnostic]
sugg: Option<OnlyCurrentTraitsPointerSugg<'a>>,
},
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_opaque)]
pub struct OnlyCurrentTraitsOpaque {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_foreign)]
pub struct OnlyCurrentTraitsForeign {
#[primary_span]
pub span: Span,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_name)]
pub struct OnlyCurrentTraitsName<'a> {
#[primary_span]
pub span: Span,
pub name: &'a str,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_pointer)]
pub struct OnlyCurrentTraitsPointer<'a> {
#[primary_span]
pub span: Span,
pub pointer: Ty<'a>,
}
#[derive(Subdiagnostic)]
#[label(hir_analysis_only_current_traits_ty)]
pub struct OnlyCurrentTraitsTy<'a> {
#[primary_span]
pub span: Span,
pub ty: Ty<'a>,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
hir_analysis_only_current_traits_pointer_sugg,
applicability = "maybe-incorrect"
)]
pub struct OnlyCurrentTraitsPointerSugg<'a> {
#[suggestion_part(code = "WrapperType")]
pub wrapper_span: Span,
#[suggestion_part(code = "struct WrapperType(*{mut_key}{ptr_ty});\n\n")]
pub struct_span: Span,
pub mut_key: &'a str,
pub ptr_ty: Ty<'a>,
}

View File

@ -214,6 +214,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module)) tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
}); });
if tcx.features().rustc_attrs {
tcx.sess.track_errors(|| collect::test_opaque_hidden_types(tcx))?;
}
// Freeze definitions as we don't add new ones at this point. This improves performance by // Freeze definitions as we don't add new ones at this point. This improves performance by
// allowing lock-free access to them. // allowing lock-free access to them.
tcx.untracked().definitions.freeze(); tcx.untracked().definitions.freeze();

View File

@ -58,7 +58,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_into(err, expr, expr_ty, expected) || self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected) || self.suggest_floating_point_literal(err, expr, expected)
|| self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected) || self.suggest_null_ptr_for_literal_zero_given_to_ptr_arg(err, expr, expected)
|| self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty); || self.suggest_coercing_result_via_try_operator(err, expr, expected, expr_ty)
|| self.suggest_missing_unwrap_expect(err, expr, expected, expr_ty);
if !suggested { if !suggested {
self.note_source_of_type_mismatch_constraint( self.note_source_of_type_mismatch_constraint(

View File

@ -6,6 +6,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX}; use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_hir::{ use rustc_hir::{
@ -1738,4 +1739,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the field is hygienic it must come from the same syntax context. // If the field is hygienic it must come from the same syntax context.
&& self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span) && self.tcx.def_ident_span(field.did).unwrap().normalize_to_macros_2_0().eq_ctxt(span)
} }
pub(crate) fn suggest_missing_unwrap_expect(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
let ty::Adt(adt, args) = found.kind() else { return false };
let ret_ty_matches = |diagnostic_item| {
if let Some(ret_ty) = self
.ret_coercion
.as_ref()
.map(|c| self.resolve_vars_if_possible(c.borrow().expected_ty()))
&& let ty::Adt(kind, _) = ret_ty.kind()
&& self.tcx.get_diagnostic_item(diagnostic_item) == Some(kind.did())
{
true
} else {
false
}
};
// don't suggest anything like `Ok(ok_val).unwrap()` , `Some(some_val).unwrap()`,
// `None.unwrap()` etc.
let is_ctor = matches!(
expr.kind,
hir::ExprKind::Call(
hir::Expr {
kind: hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
)),
..
},
..,
) | hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: Res::Def(hir::def::DefKind::Ctor(_, _), _), .. },
)),
);
let (article, kind, variant, sugg_operator) =
if self.tcx.is_diagnostic_item(sym::Result, adt.did()) {
("a", "Result", "Err", ret_ty_matches(sym::Result))
} else if self.tcx.is_diagnostic_item(sym::Option, adt.did()) {
("an", "Option", "None", ret_ty_matches(sym::Option))
} else {
return false;
};
if is_ctor || !self.can_coerce(args.type_at(0), expected) {
return false;
}
let (msg, sugg) = if sugg_operator {
(
format!(
"use the `?` operator to extract the `{found}` value, propagating \
{article} `{kind}::{variant}` value to the caller"
),
"?",
)
} else {
(
format!(
"consider using `{kind}::expect` to unwrap the `{found}` value, \
panicking if the value is {article} `{kind}::{variant}`"
),
".expect(\"REASON\")",
)
};
err.span_suggestion_verbose(
expr.span.shrink_to_hi(),
msg,
sugg,
Applicability::HasPlaceholders,
);
return true;
}
} }

View File

@ -152,7 +152,7 @@ impl<'tcx> InferCtxt<'tcx> {
) )
.into(), .into(),
CanonicalVarKind::Effect => { CanonicalVarKind::Effect => {
let vid = self.inner.borrow_mut().effect_unification_table().new_key(None); let vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool)
.into() .into()
} }

View File

@ -320,7 +320,7 @@ impl<'tcx> InferCtxt<'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", skip(self))]
fn unify_const_variable( fn unify_const_variable(
&self, &self,
target_vid: ty::ConstVid<'tcx>, target_vid: ty::ConstVid,
ct: ty::Const<'tcx>, ct: ty::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> { ) -> RelateResult<'tcx, ty::Const<'tcx>> {
@ -381,7 +381,7 @@ impl<'tcx> InferCtxt<'tcx> {
fn unify_effect_variable( fn unify_effect_variable(
&self, &self,
vid_is_expected: bool, vid_is_expected: bool,
vid: ty::EffectVid<'tcx>, vid: ty::EffectVid,
val: EffectVarValue<'tcx>, val: EffectVarValue<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> { ) -> RelateResult<'tcx, ty::Const<'tcx>> {
self.inner self.inner

View File

@ -42,7 +42,7 @@ pub struct TypeFreshener<'a, 'tcx> {
ty_freshen_count: u32, ty_freshen_count: u32,
const_freshen_count: u32, const_freshen_count: u32,
ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>, const_freshen_map: FxHashMap<ty::InferConst, ty::Const<'tcx>>,
} }
impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
@ -79,12 +79,12 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> {
fn freshen_const<F>( fn freshen_const<F>(
&mut self, &mut self,
opt_ct: Option<ty::Const<'tcx>>, opt_ct: Option<ty::Const<'tcx>>,
key: ty::InferConst<'tcx>, key: ty::InferConst,
freshener: F, freshener: F,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> ty::Const<'tcx> ) -> ty::Const<'tcx>
where where
F: FnOnce(u32) -> ty::InferConst<'tcx>, F: FnOnce(u32) -> ty::InferConst,
{ {
if let Some(ct) = opt_ct { if let Some(ct) = opt_ct {
return ct.fold_with(self); return ct.fold_with(self);

View File

@ -1,3 +1,4 @@
use rustc_middle::infer::unify_key::ConstVidKey;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid};
@ -23,14 +24,14 @@ where
} }
fn const_vars_since_snapshot<'tcx>( fn const_vars_since_snapshot<'tcx>(
table: &mut UnificationTable<'_, 'tcx, ConstVid<'tcx>>, table: &mut UnificationTable<'_, 'tcx, ConstVidKey<'tcx>>,
snapshot_var_len: usize, snapshot_var_len: usize,
) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) { ) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
let range = vars_since_snapshot(table, snapshot_var_len); let range = vars_since_snapshot(table, snapshot_var_len);
( (
range.start..range.end, range.start.vid..range.end.vid,
(range.start.index..range.end.index) (range.start.index()..range.end.index())
.map(|index| table.probe_value(ConstVid::from_index(index)).origin) .map(|index| table.probe_value(ConstVid::from_u32(index)).origin)
.collect(), .collect(),
) )
} }
@ -172,7 +173,7 @@ pub struct InferenceFudger<'a, 'tcx> {
int_vars: Range<IntVid>, int_vars: Range<IntVid>,
float_vars: Range<FloatVid>, float_vars: Range<FloatVid>,
region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>), region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>),
const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>), const_vars: (Range<ConstVid>, Vec<ConstVariableOrigin>),
} }
impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> { impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
@ -235,7 +236,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for InferenceFudger<'a, 'tcx> {
if self.const_vars.0.contains(&vid) { if self.const_vars.0.contains(&vid) {
// This variable was created during the fudging. // This variable was created during the fudging.
// Recreate it with a fresh variable here. // Recreate it with a fresh variable here.
let idx = (vid.index - self.const_vars.0.start.index) as usize; let idx = (vid.index() - self.const_vars.0.start.index()) as usize;
let origin = self.const_vars.1[idx]; let origin = self.const_vars.1[idx];
self.infcx.next_const_var(ct.ty(), origin) self.infcx.next_const_var(ct.ty(), origin)
} else { } else {

View File

@ -17,7 +17,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
infcx: &InferCtxt<'tcx>, infcx: &InferCtxt<'tcx>,
delegate: &mut D, delegate: &mut D,
term: T, term: T,
for_vid: impl Into<ty::TermVid<'tcx>>, for_vid: impl Into<ty::TermVid>,
ambient_variance: ty::Variance, ambient_variance: ty::Variance,
) -> RelateResult<'tcx, Generalization<T>> { ) -> RelateResult<'tcx, Generalization<T>> {
let (for_universe, root_vid) = match for_vid.into() { let (for_universe, root_vid) = match for_vid.into() {
@ -27,7 +27,7 @@ pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>>
), ),
ty::TermVid::Const(ct_vid) => ( ty::TermVid::Const(ct_vid) => (
infcx.probe_const_var(ct_vid).unwrap_err(), infcx.probe_const_var(ct_vid).unwrap_err(),
ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)), ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid).vid),
), ),
}; };
@ -127,7 +127,7 @@ struct Generalizer<'me, 'tcx, D> {
/// The vid of the type variable that is in the process of being /// The vid of the type variable that is in the process of being
/// instantiated. If we find this within the value we are folding, /// instantiated. If we find this within the value we are folding,
/// that means we would have created a cyclic value. /// that means we would have created a cyclic value.
root_vid: ty::TermVid<'tcx>, root_vid: ty::TermVid,
/// The universe of the type variable that is in the process of being /// The universe of the type variable that is in the process of being
/// instantiated. If we find anything that this universe cannot name, /// instantiated. If we find anything that this universe cannot name,
@ -376,7 +376,7 @@ where
// `vid` are related and we'd be inferring an infinitely // `vid` are related and we'd be inferring an infinitely
// deep const. // deep const.
if ty::TermVid::Const( if ty::TermVid::Const(
self.infcx.inner.borrow_mut().const_unification_table().find(vid), self.infcx.inner.borrow_mut().const_unification_table().find(vid).vid,
) == self.root_vid ) == self.root_vid
{ {
return Err(self.cyclic_term_error()); return Err(self.cyclic_term_error());
@ -394,10 +394,14 @@ where
if self.for_universe.can_name(universe) { if self.for_universe.can_name(universe) {
Ok(c) Ok(c)
} else { } else {
let new_var_id = variable_table.new_key(ConstVarValue { let new_var_id = variable_table
origin: var_value.origin, .new_key(ConstVarValue {
val: ConstVariableValue::Unknown { universe: self.for_universe }, origin: var_value.origin,
}); val: ConstVariableValue::Unknown {
universe: self.for_universe,
},
})
.vid;
Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty()))
} }
} }

View File

@ -6,7 +6,9 @@ pub use self::RegionVariableOrigin::*;
pub use self::SubregionOrigin::*; pub use self::SubregionOrigin::*;
pub use self::ValuePairs::*; pub use self::ValuePairs::*;
pub use combine::ObligationEmittingRelation; pub use combine::ObligationEmittingRelation;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey};
use self::opaque_types::OpaqueTypeStorage; use self::opaque_types::OpaqueTypeStorage;
pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog}; pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
@ -40,7 +42,6 @@ use rustc_span::{Span, DUMMY_SP};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::fmt; use std::fmt;
use std::marker::PhantomData;
use self::combine::CombineFields; use self::combine::CombineFields;
use self::error_reporting::TypeErrCtxt; use self::error_reporting::TypeErrCtxt;
@ -85,7 +86,7 @@ pub struct InferOk<'tcx, T> {
pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>; pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result" pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable< pub(crate) type UnificationTable<'a, 'tcx, T> = ut::UnificationTable<
ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>, ut::InPlace<T, &'a mut ut::UnificationStorage<T>, &'a mut InferCtxtUndoLogs<'tcx>>,
@ -108,7 +109,7 @@ pub struct InferCtxtInner<'tcx> {
type_variable_storage: type_variable::TypeVariableStorage<'tcx>, type_variable_storage: type_variable::TypeVariableStorage<'tcx>,
/// Map from const parameter variable to the kind of const it represents. /// Map from const parameter variable to the kind of const it represents.
const_unification_storage: ut::UnificationTableStorage<ty::ConstVid<'tcx>>, const_unification_storage: ut::UnificationTableStorage<ConstVidKey<'tcx>>,
/// Map from integral variable to the kind of integer it represents. /// Map from integral variable to the kind of integer it represents.
int_unification_storage: ut::UnificationTableStorage<ty::IntVid>, int_unification_storage: ut::UnificationTableStorage<ty::IntVid>,
@ -117,7 +118,7 @@ pub struct InferCtxtInner<'tcx> {
float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>, float_unification_storage: ut::UnificationTableStorage<ty::FloatVid>,
/// Map from effect variable to the effect param it represents. /// Map from effect variable to the effect param it represents.
effect_unification_storage: ut::UnificationTableStorage<ty::EffectVid<'tcx>>, effect_unification_storage: ut::UnificationTableStorage<EffectVidKey<'tcx>>,
/// Tracks the set of region variables and the constraints between them. /// Tracks the set of region variables and the constraints between them.
/// ///
@ -224,11 +225,11 @@ impl<'tcx> InferCtxtInner<'tcx> {
} }
#[inline] #[inline]
fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::ConstVid<'tcx>> { fn const_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ConstVidKey<'tcx>> {
self.const_unification_storage.with_log(&mut self.undo_log) self.const_unification_storage.with_log(&mut self.undo_log)
} }
fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, ty::EffectVid<'tcx>> { fn effect_unification_table(&mut self) -> UnificationTable<'_, 'tcx, EffectVidKey<'tcx>> {
self.effect_unification_storage.with_log(&mut self.undo_log) self.effect_unification_storage.with_log(&mut self.undo_log)
} }
@ -341,7 +342,9 @@ pub struct InferCtxt<'tcx> {
next_trait_solver: bool, next_trait_solver: bool,
} }
impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> { impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> {
type Interner = TyCtxt<'tcx>;
fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> { fn universe_of_ty(&self, ty: ty::InferTy) -> Option<ty::UniverseIndex> {
use InferTy::*; use InferTy::*;
match ty { match ty {
@ -357,7 +360,7 @@ impl<'tcx> ty::InferCtxtLike<TyCtxt<'tcx>> for InferCtxt<'tcx> {
} }
} }
fn universe_of_ct(&self, ct: ty::InferConst<'tcx>) -> Option<ty::UniverseIndex> { fn universe_of_ct(&self, ct: ty::InferConst) -> Option<ty::UniverseIndex> {
use ty::InferConst::*; use ty::InferConst::*;
match ct { match ct {
// Same issue as with `universe_of_ty` // Same issue as with `universe_of_ty`
@ -546,11 +549,11 @@ pub enum NllRegionVariableOrigin {
// FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum FixupError<'tcx> { pub enum FixupError {
UnresolvedIntTy(IntVid), UnresolvedIntTy(IntVid),
UnresolvedFloatTy(FloatVid), UnresolvedFloatTy(FloatVid),
UnresolvedTy(TyVid), UnresolvedTy(TyVid),
UnresolvedConst(ConstVid<'tcx>), UnresolvedConst(ConstVid),
} }
/// See the `region_obligations` field for more information. /// See the `region_obligations` field for more information.
@ -561,7 +564,7 @@ pub struct RegionObligation<'tcx> {
pub origin: SubregionOrigin<'tcx>, pub origin: SubregionOrigin<'tcx>,
} }
impl<'tcx> fmt::Display for FixupError<'tcx> { impl fmt::Display for FixupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::FixupError::*; use self::FixupError::*;
@ -792,7 +795,7 @@ impl<'tcx> InferCtxt<'tcx> {
let mut table = inner.effect_unification_table(); let mut table = inner.effect_unification_table();
(0..table.len()) (0..table.len())
.map(|i| ty::EffectVid { index: i as u32, phantom: PhantomData }) .map(|i| ty::EffectVid::from_usize(i))
.filter(|&vid| table.probe_value(vid).is_none()) .filter(|&vid| table.probe_value(vid).is_none())
.map(|v| { .map(|v| {
ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool)
@ -1070,15 +1073,20 @@ impl<'tcx> InferCtxt<'tcx> {
.inner .inner
.borrow_mut() .borrow_mut()
.const_unification_table() .const_unification_table()
.new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } })
.vid;
ty::Const::new_var(self.tcx, vid, ty) ty::Const::new_var(self.tcx, vid, ty)
} }
pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { self.inner
origin, .borrow_mut()
val: ConstVariableValue::Unknown { universe: self.universe() }, .const_unification_table()
}) .new_key(ConstVarValue {
origin,
val: ConstVariableValue::Unknown { universe: self.universe() },
})
.vid
} }
fn next_int_var_id(&self) -> IntVid { fn next_int_var_id(&self) -> IntVid {
@ -1192,11 +1200,15 @@ impl<'tcx> InferCtxt<'tcx> {
), ),
span, span,
}; };
let const_var_id = let const_var_id = self
self.inner.borrow_mut().const_unification_table().new_key(ConstVarValue { .inner
.borrow_mut()
.const_unification_table()
.new_key(ConstVarValue {
origin, origin,
val: ConstVariableValue::Unknown { universe: self.universe() }, val: ConstVariableValue::Unknown { universe: self.universe() },
}); })
.vid;
ty::Const::new_var( ty::Const::new_var(
self.tcx, self.tcx,
const_var_id, const_var_id,
@ -1211,7 +1223,7 @@ impl<'tcx> InferCtxt<'tcx> {
} }
pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> { pub fn var_for_effect(&self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None); let effect_vid = self.inner.borrow_mut().effect_unification_table().new_key(None).vid;
let ty = self let ty = self
.tcx .tcx
.type_of(param.def_id) .type_of(param.def_id)
@ -1331,12 +1343,12 @@ impl<'tcx> InferCtxt<'tcx> {
self.inner.borrow_mut().type_variables().root_var(var) self.inner.borrow_mut().type_variables().root_var(var)
} }
pub fn root_const_var(&self, var: ty::ConstVid<'tcx>) -> ty::ConstVid<'tcx> { pub fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid {
self.inner.borrow_mut().const_unification_table().find(var) self.inner.borrow_mut().const_unification_table().find(var).vid
} }
pub fn root_effect_var(&self, var: ty::EffectVid<'tcx>) -> ty::EffectVid<'tcx> { pub fn root_effect_var(&self, var: ty::EffectVid) -> ty::EffectVid {
self.inner.borrow_mut().effect_unification_table().find(var) self.inner.borrow_mut().effect_unification_table().find(var).vid
} }
/// Resolves an int var to a rigid int type, if it was constrained to one, /// Resolves an int var to a rigid int type, if it was constrained to one,
@ -1400,17 +1412,14 @@ impl<'tcx> InferCtxt<'tcx> {
value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value() value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value()
} }
pub fn probe_const_var( pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
&self,
vid: ty::ConstVid<'tcx>,
) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
ConstVariableValue::Known { value } => Ok(value), ConstVariableValue::Known { value } => Ok(value),
ConstVariableValue::Unknown { universe } => Err(universe), ConstVariableValue::Unknown { universe } => Err(universe),
} }
} }
pub fn probe_effect_var(&self, vid: EffectVid<'tcx>) -> Option<EffectVarValue<'tcx>> { pub fn probe_effect_var(&self, vid: EffectVid) -> Option<EffectVarValue<'tcx>> {
self.inner.borrow_mut().effect_unification_table().probe_value(vid) self.inner.borrow_mut().effect_unification_table().probe_value(vid)
} }
@ -1421,7 +1430,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// ///
/// This method is idempotent, but it not typically not invoked /// This method is idempotent, but it not typically not invoked
/// except during the writeback phase. /// except during the writeback phase.
pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> { pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<T> {
match resolve::fully_resolve(self, value) { match resolve::fully_resolve(self, value) {
Ok(value) => { Ok(value) => {
if value.has_non_region_infer() { if value.has_non_region_infer() {
@ -1645,11 +1654,11 @@ impl<'tcx> InferCtxt<'tcx> {
#[inline] #[inline]
pub fn is_ty_infer_var_definitely_unchanged<'a>( pub fn is_ty_infer_var_definitely_unchanged<'a>(
&'a self, &'a self,
) -> (impl Fn(TyOrConstInferVar<'tcx>) -> bool + 'a) { ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) {
// This hoists the borrow/release out of the loop body. // This hoists the borrow/release out of the loop body.
let inner = self.inner.try_borrow(); let inner = self.inner.try_borrow();
return move |infer_var: TyOrConstInferVar<'tcx>| match (infer_var, &inner) { return move |infer_var: TyOrConstInferVar| match (infer_var, &inner) {
(TyOrConstInferVar::Ty(ty_var), Ok(inner)) => { (TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
use self::type_variable::TypeVariableValue; use self::type_variable::TypeVariableValue;
@ -1672,7 +1681,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// inference variables), and it handles both `Ty` and `ty::Const` without /// inference variables), and it handles both `Ty` and `ty::Const` without
/// having to resort to storing full `GenericArg`s in `stalled_on`. /// having to resort to storing full `GenericArg`s in `stalled_on`.
#[inline(always)] #[inline(always)]
pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar<'tcx>) -> bool { pub fn ty_or_const_infer_var_changed(&self, infer_var: TyOrConstInferVar) -> bool {
match infer_var { match infer_var {
TyOrConstInferVar::Ty(v) => { TyOrConstInferVar::Ty(v) => {
use self::type_variable::TypeVariableValue; use self::type_variable::TypeVariableValue;
@ -1779,7 +1788,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
/// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently
/// used only for `traits::fulfill`'s list of `stalled_on` inference variables. /// used only for `traits::fulfill`'s list of `stalled_on` inference variables.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum TyOrConstInferVar<'tcx> { pub enum TyOrConstInferVar {
/// Equivalent to `ty::Infer(ty::TyVar(_))`. /// Equivalent to `ty::Infer(ty::TyVar(_))`.
Ty(TyVid), Ty(TyVid),
/// Equivalent to `ty::Infer(ty::IntVar(_))`. /// Equivalent to `ty::Infer(ty::IntVar(_))`.
@ -1788,12 +1797,12 @@ pub enum TyOrConstInferVar<'tcx> {
TyFloat(FloatVid), TyFloat(FloatVid),
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`. /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::Var(_))`.
Const(ConstVid<'tcx>), Const(ConstVid),
/// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`. /// Equivalent to `ty::ConstKind::Infer(ty::InferConst::EffectVar(_))`.
Effect(EffectVid<'tcx>), Effect(EffectVid),
} }
impl<'tcx> TyOrConstInferVar<'tcx> { impl<'tcx> TyOrConstInferVar {
/// Tries to extract an inference variable from a type or a constant, returns `None` /// Tries to extract an inference variable from a type or a constant, returns `None`
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`) and
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).

View File

@ -192,7 +192,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for UnresolvedTypeOrConstFinder<'a, 'tc
/// Full type resolution replaces all type and region variables with /// Full type resolution replaces all type and region variables with
/// their concrete results. If any variable cannot be replaced (never unified, etc) /// their concrete results. If any variable cannot be replaced (never unified, etc)
/// then an `Err` result is returned. /// then an `Err` result is returned.
pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<'tcx, T> pub fn fully_resolve<'tcx, T>(infcx: &InferCtxt<'tcx>, value: T) -> FixupResult<T>
where where
T: TypeFoldable<TyCtxt<'tcx>>, T: TypeFoldable<TyCtxt<'tcx>>,
{ {
@ -206,7 +206,7 @@ struct FullTypeResolver<'a, 'tcx> {
} }
impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
type Error = FixupError<'tcx>; type Error = FixupError;
fn interner(&self) -> TyCtxt<'tcx> { fn interner(&self) -> TyCtxt<'tcx> {
self.infcx.tcx self.infcx.tcx

View File

@ -3,7 +3,7 @@ use std::marker::PhantomData;
use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::snapshot_vec as sv;
use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::undo_log::{Rollback, UndoLogs};
use rustc_data_structures::unify as ut; use rustc_data_structures::unify as ut;
use rustc_middle::infer::unify_key::RegionVidKey; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey, RegionVidKey};
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey}; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey};
use crate::{ use crate::{
@ -21,10 +21,10 @@ pub struct Snapshot<'tcx> {
pub(crate) enum UndoLog<'tcx> { pub(crate) enum UndoLog<'tcx> {
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>), OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
TypeVariables(type_variable::UndoLog<'tcx>), TypeVariables(type_variable::UndoLog<'tcx>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>), EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
RegionConstraintCollector(region_constraints::UndoLog<'tcx>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>), ProjectionCache(traits::UndoLog<'tcx>),
@ -56,9 +56,9 @@ impl_from! {
IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>),
FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>),
EffectUnificationTable(sv::UndoLog<ut::Delegate<ty::EffectVid<'tcx>>>), EffectUnificationTable(sv::UndoLog<ut::Delegate<EffectVidKey<'tcx>>>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>),
ProjectionCache(traits::UndoLog<'tcx>), ProjectionCache(traits::UndoLog<'tcx>),

View File

@ -775,12 +775,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
rustc_hir_analysis::check_crate(tcx)?; rustc_hir_analysis::check_crate(tcx)?;
sess.time("MIR_borrow_checking", || { sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id)); tcx.hir().par_body_owners(|def_id| {
// Run THIR unsafety check because it's responsible for stealing
// and deallocating THIR when enabled.
tcx.ensure().thir_check_unsafety(def_id);
tcx.ensure().mir_borrowck(def_id)
});
}); });
sess.time("MIR_effect_checking", || { sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() { for def_id in tcx.hir().body_owners() {
tcx.ensure().thir_check_unsafety(def_id);
if !tcx.sess.opts.unstable_opts.thir_unsafeck { if !tcx.sess.opts.unstable_opts.thir_unsafeck {
rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id); rustc_mir_transform::check_unsafety::check_unsafety(tcx, def_id);
} }

View File

@ -141,18 +141,30 @@ pub struct ConstVarValue<'tcx> {
pub val: ConstVariableValue<'tcx>, pub val: ConstVariableValue<'tcx>,
} }
impl<'tcx> UnifyKey for ty::ConstVid<'tcx> { #[derive(PartialEq, Copy, Clone, Debug)]
pub struct ConstVidKey<'tcx> {
pub vid: ty::ConstVid,
pub phantom: PhantomData<ty::Const<'tcx>>,
}
impl<'tcx> From<ty::ConstVid> for ConstVidKey<'tcx> {
fn from(vid: ty::ConstVid) -> Self {
ConstVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
type Value = ConstVarValue<'tcx>; type Value = ConstVarValue<'tcx>;
#[inline] #[inline]
fn index(&self) -> u32 { fn index(&self) -> u32 {
self.index self.vid.as_u32()
} }
#[inline] #[inline]
fn from_index(i: u32) -> Self { fn from_index(i: u32) -> Self {
ty::ConstVid { index: i, phantom: PhantomData } ConstVidKey::from(ty::ConstVid::from_u32(i))
} }
fn tag() -> &'static str { fn tag() -> &'static str {
"ConstVid" "ConstVidKey"
} }
} }
@ -224,17 +236,29 @@ impl<'tcx> UnifyValue for EffectVarValue<'tcx> {
} }
} }
impl<'tcx> UnifyKey for ty::EffectVid<'tcx> { #[derive(PartialEq, Copy, Clone, Debug)]
pub struct EffectVidKey<'tcx> {
pub vid: ty::EffectVid,
pub phantom: PhantomData<EffectVarValue<'tcx>>,
}
impl<'tcx> From<ty::EffectVid> for EffectVidKey<'tcx> {
fn from(vid: ty::EffectVid) -> Self {
EffectVidKey { vid, phantom: PhantomData }
}
}
impl<'tcx> UnifyKey for EffectVidKey<'tcx> {
type Value = Option<EffectVarValue<'tcx>>; type Value = Option<EffectVarValue<'tcx>>;
#[inline] #[inline]
fn index(&self) -> u32 { fn index(&self) -> u32 {
self.index self.vid.as_u32()
} }
#[inline] #[inline]
fn from_index(i: u32) -> Self { fn from_index(i: u32) -> Self {
ty::EffectVid { index: i, phantom: PhantomData } EffectVidKey::from(ty::EffectVid::from_u32(i))
} }
fn tag() -> &'static str { fn tag() -> &'static str {
"EffectVid" "EffectVidKey"
} }
} }

View File

@ -636,7 +636,8 @@ impl<'tcx> Pat<'tcx> {
Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} Wild | Range(..) | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {}
AscribeUserType { subpattern, .. } AscribeUserType { subpattern, .. }
| Binding { subpattern: Some(subpattern), .. } | Binding { subpattern: Some(subpattern), .. }
| Deref { subpattern } => subpattern.walk_(it), | Deref { subpattern }
| InlineConstant { subpattern, .. } => subpattern.walk_(it),
Leaf { subpatterns } | Variant { subpatterns, .. } => { Leaf { subpatterns } | Variant { subpatterns, .. } => {
subpatterns.iter().for_each(|field| field.pattern.walk_(it)) subpatterns.iter().for_each(|field| field.pattern.walk_(it))
} }
@ -764,6 +765,22 @@ pub enum PatKind<'tcx> {
value: mir::Const<'tcx>, value: mir::Const<'tcx>,
}, },
/// Inline constant found while lowering a pattern.
InlineConstant {
/// [LocalDefId] of the constant, we need this so that we have a
/// reference that can be used by unsafety checking to visit nested
/// unevaluated constants.
def: LocalDefId,
/// If the inline constant is used in a range pattern, this subpattern
/// represents the range (if both ends are inline constants, there will
/// be multiple InlineConstant wrappers).
///
/// Otherwise, the actual pattern that the constant lowered to. As with
/// other constants, inline constants are matched structurally where
/// possible.
subpattern: Box<Pat<'tcx>>,
},
Range(Box<PatRange<'tcx>>), Range(Box<PatRange<'tcx>>),
/// Matches against a slice, checking the length and extracting elements. /// Matches against a slice, checking the length and extracting elements.
@ -924,6 +941,9 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
write!(f, "{subpattern}") write!(f, "{subpattern}")
} }
PatKind::Constant { value } => write!(f, "{value}"), PatKind::Constant { value } => write!(f, "{value}"),
PatKind::InlineConstant { def: _, ref subpattern } => {
write!(f, "{} (from inline const)", subpattern)
}
PatKind::Range(box PatRange { lo, hi, end }) => { PatKind::Range(box PatRange { lo, hi, end }) => {
write!(f, "{lo}")?; write!(f, "{lo}")?;
write!(f, "{end}")?; write!(f, "{end}")?;

View File

@ -233,16 +233,17 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
} }
} }
Constant { value: _ } => {} Constant { value: _ } => {}
InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern),
Range(_) => {} Range(_) => {}
Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => {
for subpattern in prefix.iter() { for subpattern in prefix.iter() {
visitor.visit_pat(&subpattern); visitor.visit_pat(subpattern);
} }
if let Some(pat) = slice { if let Some(pat) = slice {
visitor.visit_pat(&pat); visitor.visit_pat(pat);
} }
for subpattern in suffix.iter() { for subpattern in suffix.iter() {
visitor.visit_pat(&subpattern); visitor.visit_pat(subpattern);
} }
} }
Or { pats } => { Or { pats } => {

View File

@ -57,7 +57,7 @@ impl<'tcx> Const<'tcx> {
} }
#[inline] #[inline]
pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty)
} }
@ -67,7 +67,7 @@ impl<'tcx> Const<'tcx> {
} }
#[inline] #[inline]
pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> {
Const::new(tcx, ty::ConstKind::Infer(infer), ty) Const::new(tcx, ty::ConstKind::Infer(infer), ty)
} }

View File

@ -80,19 +80,19 @@ static_assert_size!(super::ConstKind<'_>, 32);
/// An inference variable for a const, for use in const generics. /// An inference variable for a const, for use in const generics.
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
pub enum InferConst<'tcx> { pub enum InferConst {
/// Infer the value of the const. /// Infer the value of the const.
Var(ty::ConstVid<'tcx>), Var(ty::ConstVid),
/// Infer the value of the effect. /// Infer the value of the effect.
/// ///
/// For why this is separate from the `Var` variant above, see the /// For why this is separate from the `Var` variant above, see the
/// documentation on `EffectVid`. /// documentation on `EffectVid`.
EffectVar(ty::EffectVid<'tcx>), EffectVar(ty::EffectVid),
/// A fresh const variable. See `infer::freshen` for more details. /// A fresh const variable. See `infer::freshen` for more details.
Fresh(u32), Fresh(u32),
} }
impl<CTX> HashStable<CTX> for InferConst<'_> { impl<CTX> HashStable<CTX> for InferConst {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
match self { match self {
InferConst::Var(_) | InferConst::EffectVar(_) => { InferConst::Var(_) | InferConst::EffectVar(_) => {

View File

@ -100,7 +100,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type PolyFnSig = PolyFnSig<'tcx>; type PolyFnSig = PolyFnSig<'tcx>;
type AllocId = crate::mir::interpret::AllocId; type AllocId = crate::mir::interpret::AllocId;
type Const = ty::Const<'tcx>; type Const = ty::Const<'tcx>;
type InferConst = ty::InferConst<'tcx>; type InferConst = ty::InferConst;
type AliasConst = ty::UnevaluatedConst<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>;
type PlaceholderConst = ty::PlaceholderConst<'tcx>; type PlaceholderConst = ty::PlaceholderConst<'tcx>;
type ParamConst = ty::ParamConst; type ParamConst = ty::ParamConst;

View File

@ -1,7 +1,7 @@
use crate::arena::Arena; use crate::arena::Arena;
use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_data_structures::aligned::{align_of, Aligned};
use rustc_serialize::{Encodable, Encoder}; use rustc_serialize::{Encodable, Encoder};
use rustc_type_ir::{InferCtxtLike, OptWithInfcx}; use rustc_type_ir::{InferCtxtLike, WithInfcx};
use std::alloc::Layout; use std::alloc::Layout;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
@ -121,8 +121,8 @@ impl<T: fmt::Debug> fmt::Debug for List<T> {
} }
} }
impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
fmt::Debug::fmt(&this.map(|this| this.as_slice()), f) fmt::Debug::fmt(&this.map(|this| this.as_slice()), f)

View File

@ -54,7 +54,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_span::{ExpnId, ExpnKind, Span};
use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx};
pub use rustc_target::abi::{ReprFlags, ReprOptions}; pub use rustc_target::abi::{ReprFlags, ReprOptions};
pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx};
pub use vtable::*; pub use vtable::*;
use std::fmt::Debug; use std::fmt::Debug;
@ -1084,19 +1084,19 @@ impl ParamTerm {
} }
#[derive(Copy, Clone, Eq, PartialEq, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum TermVid<'tcx> { pub enum TermVid {
Ty(ty::TyVid), Ty(ty::TyVid),
Const(ty::ConstVid<'tcx>), Const(ty::ConstVid),
} }
impl From<ty::TyVid> for TermVid<'_> { impl From<ty::TyVid> for TermVid {
fn from(value: ty::TyVid) -> Self { fn from(value: ty::TyVid) -> Self {
TermVid::Ty(value) TermVid::Ty(value)
} }
} }
impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> { impl From<ty::ConstVid> for TermVid {
fn from(value: ty::ConstVid<'tcx>) -> Self { fn from(value: ty::ConstVid) -> Self {
TermVid::Const(value) TermVid::Const(value)
} }
} }

View File

@ -1194,7 +1194,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
None None
} }
fn const_infer_name(&self, _: ty::ConstVid<'tcx>) -> Option<Symbol> { fn const_infer_name(&self, _: ty::ConstVid) -> Option<Symbol> {
None None
} }
@ -1742,7 +1742,7 @@ pub struct FmtPrinterData<'a, 'tcx> {
pub region_highlight_mode: RegionHighlightMode<'tcx>, pub region_highlight_mode: RegionHighlightMode<'tcx>,
pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>, pub ty_infer_name_resolver: Option<Box<dyn Fn(ty::TyVid) -> Option<Symbol> + 'a>>,
pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid<'tcx>) -> Option<Symbol> + 'a>>, pub const_infer_name_resolver: Option<Box<dyn Fn(ty::ConstVid) -> Option<Symbol> + 'a>>,
} }
impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> { impl<'a, 'tcx> Deref for FmtPrinter<'a, 'tcx> {
@ -2082,7 +2082,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
self.printed_type_count = 0; self.printed_type_count = 0;
} }
fn const_infer_name(&self, id: ty::ConstVid<'tcx>) -> Option<Symbol> { fn const_infer_name(&self, id: ty::ConstVid) -> Option<Symbol> {
self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id)) self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
} }

View File

@ -10,7 +10,7 @@ use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_target::abi::TyAndLayout; use rustc_target::abi::TyAndLayout;
use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; use rustc_type_ir::{ConstKind, DebugWithInfcx, InferCtxtLike, WithInfcx};
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -87,12 +87,12 @@ impl fmt::Debug for ty::FreeRegion {
impl<'tcx> fmt::Debug for ty::FnSig<'tcx> { impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
let sig = this.data; let sig = this.data;
@ -128,18 +128,6 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
} }
} }
impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "?{}c", self.index)
}
}
impl fmt::Debug for ty::EffectVid<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "?{}e", self.index)
}
}
impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
with_no_trimmed_paths!(fmt::Display::fmt(self, f)) with_no_trimmed_paths!(fmt::Display::fmt(self, f))
@ -147,8 +135,8 @@ impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
} }
impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> { impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
this.data.fmt(f) this.data.fmt(f)
@ -236,12 +224,12 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
impl<'tcx> fmt::Debug for AliasTy<'tcx> { impl<'tcx> fmt::Debug for AliasTy<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
f.debug_struct("AliasTy") f.debug_struct("AliasTy")
@ -251,7 +239,7 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
} }
} }
impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { impl fmt::Debug for ty::InferConst {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
InferConst::Var(var) => write!(f, "{var:?}"), InferConst::Var(var) => write!(f, "{var:?}"),
@ -260,17 +248,17 @@ impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
} }
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
use ty::InferConst::*; use ty::InferConst::*;
match this.infcx.and_then(|infcx| infcx.universe_of_ct(*this.data)) { match this.infcx.universe_of_ct(*this.data) {
None => write!(f, "{:?}", this.data), None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data { Some(universe) => match *this.data {
Var(vid) => write!(f, "?{}_{}c", vid.index, universe.index()), Var(vid) => write!(f, "?{}_{}c", vid.index(), universe.index()),
EffectVar(vid) => write!(f, "?{}_{}e", vid.index, universe.index()), EffectVar(vid) => write!(f, "?{}_{}e", vid.index(), universe.index()),
Fresh(_) => { Fresh(_) => {
unreachable!() unreachable!()
} }
@ -281,12 +269,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::InferConst<'tcx> {
impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
match this.data { match this.data {
@ -314,12 +302,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> {
impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> { impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
f.debug_struct("UnevaluatedConst") f.debug_struct("UnevaluatedConst")
@ -331,12 +319,12 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
impl<'tcx> fmt::Debug for ty::Const<'tcx> { impl<'tcx> fmt::Debug for ty::Const<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
// If this is a value, we spend some effort to make it look nice. // If this is a value, we spend some effort to make it look nice.
@ -392,8 +380,8 @@ impl<'tcx> fmt::Debug for GenericArg<'tcx> {
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for GenericArg<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
match this.data.unpack() { match this.data.unpack() {
@ -410,8 +398,8 @@ impl<'tcx> fmt::Debug for Region<'tcx> {
} }
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
write!(f, "{:?}", &this.map(|data| data.kind())) write!(f, "{:?}", &this.map(|data| data.kind()))
@ -419,11 +407,11 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Region<'tcx> {
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
match this.infcx.and_then(|infcx| infcx.universe_of_lt(*this.data)) { match this.infcx.universe_of_lt(*this.data) {
Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()), Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
None => write!(f, "{:?}", this.data), None => write!(f, "{:?}", this.data),
} }
@ -431,8 +419,8 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
} }
impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> { impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
fn fmt<InfCtx: InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
f.debug_tuple("Binder") f.debug_tuple("Binder")
@ -862,7 +850,7 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
} }
} }
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> { impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self, self,
_folder: &mut F, _folder: &mut F,
@ -871,7 +859,7 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst<'tcx> {
} }
} }
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst<'tcx> { impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>( fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
&self, &self,
_visitor: &mut V, _visitor: &mut V,

View File

@ -29,7 +29,6 @@ use std::assert_matches::debug_assert_matches;
use std::borrow::Cow; use std::borrow::Cow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fmt; use std::fmt;
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref, Range}; use std::ops::{ControlFlow, Deref, Range};
use ty::util::IntTypeExt; use ty::util::IntTypeExt;
@ -683,8 +682,8 @@ pub enum ExistentialPredicate<'tcx> {
} }
impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> { impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
fn fmt<InfCtx: rustc_type_ir::InferCtxtLike<TyCtxt<'tcx>>>( fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>(
this: rustc_type_ir::OptWithInfcx<'_, TyCtxt<'tcx>, InfCtx, &Self>, this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
fmt::Debug::fmt(&this.data, f) fmt::Debug::fmt(&this.data, f)
@ -1583,26 +1582,22 @@ impl fmt::Debug for EarlyBoundRegion {
} }
} }
/// A **`const`** **v**ariable **ID**. rustc_index::newtype_index! {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] /// A **`const`** **v**ariable **ID**.
#[derive(HashStable, TyEncodable, TyDecodable)] #[debug_format = "?{}c"]
pub struct ConstVid<'tcx> { pub struct ConstVid {}
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
} }
/// An **effect** **v**ariable **ID**. rustc_index::newtype_index! {
/// /// An **effect** **v**ariable **ID**.
/// Handling effect infer variables happens separately from const infer variables ///
/// because we do not want to reuse any of the const infer machinery. If we try to /// Handling effect infer variables happens separately from const infer variables
/// relate an effect variable with a normal one, we would ICE, which can catch bugs /// because we do not want to reuse any of the const infer machinery. If we try to
/// where we are not correctly using the effect var for an effect param. Fallback /// relate an effect variable with a normal one, we would ICE, which can catch bugs
/// is also implemented on top of having separate effect and normal const variables. /// where we are not correctly using the effect var for an effect param. Fallback
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] /// is also implemented on top of having separate effect and normal const variables.
#[derive(TyEncodable, TyDecodable)] #[debug_format = "?{}e"]
pub struct EffectVid<'tcx> { pub struct EffectVid {}
pub index: u32,
pub phantom: PhantomData<&'tcx ()>,
} }
rustc_index::newtype_index! { rustc_index::newtype_index! {

View File

@ -847,6 +847,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.visit_primary_bindings(subpattern, subpattern_user_ty, f) self.visit_primary_bindings(subpattern, subpattern_user_ty, f)
} }
PatKind::InlineConstant { ref subpattern, .. } => {
self.visit_primary_bindings(subpattern, pattern_user_ty.clone(), f)
}
PatKind::Leaf { ref subpatterns } => { PatKind::Leaf { ref subpatterns } => {
for subpattern in subpatterns { for subpattern in subpatterns {
let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field); let subpattern_user_ty = pattern_user_ty.clone().leaf(subpattern.field);

View File

@ -204,6 +204,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Err(match_pair) Err(match_pair)
} }
PatKind::InlineConstant { subpattern: ref pattern, def: _ } => {
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
Ok(())
}
PatKind::Range(box PatRange { lo, hi, end }) => { PatKind::Range(box PatRange { lo, hi, end }) => {
let (range, bias) = match *lo.ty().kind() { let (range, bias) = match *lo.ty().kind() {
ty::Char => { ty::Char => {
@ -229,8 +235,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// correct the comparison. This is achieved by XORing with a bias (see // correct the comparison. This is achieved by XORing with a bias (see
// pattern/_match.rs for another pertinent example of this pattern). // pattern/_match.rs for another pertinent example of this pattern).
// //
// Also, for performance, it's important to only do the second `try_to_bits` if // Also, for performance, it's important to only do the second
// necessary. // `try_to_bits` if necessary.
let lo = lo.try_to_bits(sz).unwrap() ^ bias; let lo = lo.try_to_bits(sz).unwrap() ^ bias;
if lo <= min { if lo <= min {
let hi = hi.try_to_bits(sz).unwrap() ^ bias; let hi = hi.try_to_bits(sz).unwrap() ^ bias;

View File

@ -73,6 +73,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
PatKind::Or { .. } => bug!("or-patterns should have already been handled"), PatKind::Or { .. } => bug!("or-patterns should have already been handled"),
PatKind::AscribeUserType { .. } PatKind::AscribeUserType { .. }
| PatKind::InlineConstant { .. }
| PatKind::Array { .. } | PatKind::Array { .. }
| PatKind::Wild | PatKind::Wild
| PatKind::Binding { .. } | PatKind::Binding { .. }
@ -111,6 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Or { .. } | PatKind::Or { .. }
| PatKind::Binding { .. } | PatKind::Binding { .. }
| PatKind::AscribeUserType { .. } | PatKind::AscribeUserType { .. }
| PatKind::InlineConstant { .. }
| PatKind::Leaf { .. } | PatKind::Leaf { .. }
| PatKind::Deref { .. } | PatKind::Deref { .. }
| PatKind::Error(_) => { | PatKind::Error(_) => {

View File

@ -53,10 +53,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>(
} }
/// Construct the MIR for a given `DefId`. /// Construct the MIR for a given `DefId`.
fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
tcx.ensure_with_value()
.thir_check_unsafety(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
tcx.ensure_with_value().thir_abstract_const(def); tcx.ensure_with_value().thir_abstract_const(def);
if let Err(e) = tcx.check_match(def) { if let Err(e) = tcx.check_match(def) {
return construct_error(tcx, def, e); return construct_error(tcx, def, e);
@ -65,20 +62,27 @@ fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
let body = match tcx.thir_body(def) { let body = match tcx.thir_body(def) {
Err(error_reported) => construct_error(tcx, def, error_reported), Err(error_reported) => construct_error(tcx, def, error_reported),
Ok((thir, expr)) => { Ok((thir, expr)) => {
// We ran all queries that depended on THIR at the beginning let build_mir = |thir: &Thir<'tcx>| match thir.body_type {
// of `mir_build`, so now we can steal it thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig),
let thir = thir.steal(); thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
};
tcx.ensure().check_match(def);
// this must run before MIR dump, because // this must run before MIR dump, because
// "not all control paths return a value" is reported here. // "not all control paths return a value" is reported here.
// //
// maybe move the check to a MIR pass? // maybe move the check to a MIR pass?
tcx.ensure().check_liveness(def); tcx.ensure().check_liveness(def);
match thir.body_type { if tcx.sess.opts.unstable_opts.thir_unsafeck {
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig), // Don't steal here if THIR unsafeck is being used. Instead
thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty), // steal in unsafeck. This is so that pattern inline constants
// can be evaluated as part of building the THIR of the parent
// function without a cycle.
build_mir(&thir.borrow())
} else {
// We ran all queries that depended on THIR at the beginning
// of `mir_build`, so now we can steal it
build_mir(&thir.steal())
} }
} }
}; };

View File

@ -124,7 +124,9 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
/// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body. /// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body.
fn visit_inner_body(&mut self, def: LocalDefId) { fn visit_inner_body(&mut self, def: LocalDefId) {
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) { if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
let inner_thir = &inner_thir.borrow(); // Runs all other queries that depend on THIR.
self.tcx.ensure_with_value().mir_built(def);
let inner_thir = &inner_thir.steal();
let hir_context = self.tcx.hir().local_def_id_to_hir_id(def); let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self }; let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
inner_visitor.visit_expr(&inner_thir[expr]); inner_visitor.visit_expr(&inner_thir[expr]);
@ -224,6 +226,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
PatKind::Wild | PatKind::Wild |
// these just wrap other patterns // these just wrap other patterns
PatKind::Or { .. } | PatKind::Or { .. } |
PatKind::InlineConstant { .. } |
PatKind::AscribeUserType { .. } | PatKind::AscribeUserType { .. } |
PatKind::Error(_) => {} PatKind::Error(_) => {}
} }
@ -277,6 +280,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
visit::walk_pat(self, pat); visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt; self.inside_adt = old_inside_adt;
} }
PatKind::InlineConstant { def, .. } => {
self.visit_inner_body(*def);
}
_ => { _ => {
visit::walk_pat(self, pat); visit::walk_pat(self, pat);
} }
@ -788,7 +794,9 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
} }
let Ok((thir, expr)) = tcx.thir_body(def) else { return }; let Ok((thir, expr)) = tcx.thir_body(def) else { return };
let thir = &thir.borrow(); // Runs all other queries that depend on THIR.
tcx.ensure_with_value().mir_built(def);
let thir = &thir.steal();
// If `thir` is empty, a type error occurred, skip this body. // If `thir` is empty, a type error occurred, skip this body.
if thir.exprs.is_empty() { if thir.exprs.is_empty() {
return; return;

View File

@ -1326,7 +1326,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let ctor; let ctor;
let fields; let fields;
match &pat.kind { match &pat.kind {
PatKind::AscribeUserType { subpattern, .. } => return mkpat(subpattern), PatKind::AscribeUserType { subpattern, .. }
| PatKind::InlineConstant { subpattern, .. } => return mkpat(subpattern),
PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat), PatKind::Binding { subpattern: Some(subpat), .. } => return mkpat(subpat),
PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { PatKind::Binding { subpattern: None, .. } | PatKind::Wild => {
ctor = Wildcard; ctor = Wildcard;

View File

@ -27,6 +27,7 @@ use rustc_middle::ty::{
self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt,
TypeVisitableExt, UserType, TypeVisitableExt, UserType,
}; };
use rustc_span::def_id::LocalDefId;
use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_span::{ErrorGuaranteed, Span, Symbol};
use rustc_target::abi::{FieldIdx, Integer}; use rustc_target::abi::{FieldIdx, Integer};
@ -88,15 +89,21 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range_endpoint( fn lower_pattern_range_endpoint(
&mut self, &mut self,
expr: Option<&'tcx hir::Expr<'tcx>>, expr: Option<&'tcx hir::Expr<'tcx>>,
) -> Result<(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>), ErrorGuaranteed> { ) -> Result<
(Option<mir::Const<'tcx>>, Option<Ascription<'tcx>>, Option<LocalDefId>),
ErrorGuaranteed,
> {
match expr { match expr {
None => Ok((None, None)), None => Ok((None, None, None)),
Some(expr) => { Some(expr) => {
let (kind, ascr) = match self.lower_lit(expr) { let (kind, ascr, inline_const) = match self.lower_lit(expr) {
PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { PatKind::InlineConstant { subpattern, def } => {
(kind, Some(ascription)) (subpattern.kind, None, Some(def))
} }
kind => (kind, None), PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => {
(kind, Some(ascription), None)
}
kind => (kind, None, None),
}; };
let value = if let PatKind::Constant { value } = kind { let value = if let PatKind::Constant { value } = kind {
value value
@ -106,7 +113,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
); );
return Err(self.tcx.sess.delay_span_bug(expr.span, msg)); return Err(self.tcx.sess.delay_span_bug(expr.span, msg));
}; };
Ok((Some(value), ascr)) Ok((Some(value), ascr, inline_const))
} }
} }
} }
@ -177,8 +184,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
return Err(self.tcx.sess.delay_span_bug(span, msg)); return Err(self.tcx.sess.delay_span_bug(span, msg));
} }
let (lo, lo_ascr) = self.lower_pattern_range_endpoint(lo_expr)?; let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
let (hi, hi_ascr) = self.lower_pattern_range_endpoint(hi_expr)?; let (hi, hi_ascr, hi_inline) = self.lower_pattern_range_endpoint(hi_expr)?;
let lo = lo.unwrap_or_else(|| { let lo = lo.unwrap_or_else(|| {
// Unwrap is ok because the type is known to be numeric. // Unwrap is ok because the type is known to be numeric.
@ -237,6 +244,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}; };
} }
} }
for inline_const in [lo_inline, hi_inline] {
if let Some(def) = inline_const {
kind =
PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) };
}
}
Ok(kind) Ok(kind)
} }
@ -599,11 +612,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
// const eval path below. // const eval path below.
// FIXME: investigate the performance impact of removing this. // FIXME: investigate the performance impact of removing this.
let lit_input = match expr.kind { let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { hir::ExprKind::Unary(hir::UnOp::Neg, expr) => match expr.kind {
hir::ExprKind::Lit(ref lit) => { hir::ExprKind::Lit(lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: true }),
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None, _ => None,
}, },
_ => None, _ => None,
@ -633,13 +644,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Ok(Some(valtree)) = if let Ok(Some(valtree)) =
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span)) self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
{ {
self.const_to_pat( let subpattern = self.const_to_pat(
Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
id, id,
span, span,
None, None,
) );
.kind PatKind::InlineConstant { subpattern, def: def_id }
} else { } else {
// If that fails, convert it to an opaque constant pattern. // If that fails, convert it to an opaque constant pattern.
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) { match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
@ -822,6 +833,9 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
PatKind::Deref { subpattern: subpattern.fold_with(folder) } PatKind::Deref { subpattern: subpattern.fold_with(folder) }
} }
PatKind::Constant { value } => PatKind::Constant { value }, PatKind::Constant { value } => PatKind::Constant { value },
PatKind::InlineConstant { def, subpattern: ref pattern } => {
PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) }
}
PatKind::Range(ref range) => PatKind::Range(range.clone()), PatKind::Range(ref range) => PatKind::Range(range.clone()),
PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice {
prefix: prefix.fold_with(folder), prefix: prefix.fold_with(folder),

View File

@ -692,7 +692,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
} }
PatKind::Deref { subpattern } => { PatKind::Deref { subpattern } => {
print_indented!(self, "Deref { ", depth_lvl + 1); print_indented!(self, "Deref { ", depth_lvl + 1);
print_indented!(self, "subpattern: ", depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1);
} }
@ -701,6 +701,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1);
} }
PatKind::InlineConstant { def, subpattern } => {
print_indented!(self, "InlineConstant {", depth_lvl + 1);
print_indented!(self, format!("def: {:?}", def), depth_lvl + 2);
print_indented!(self, "subpattern:", depth_lvl + 2);
self.print_pat(subpattern, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
PatKind::Range(pat_range) => { PatKind::Range(pat_range) => {
print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1); print_indented!(self, format!("Range ( {:?} )", pat_range), depth_lvl + 1);
} }

View File

@ -2,13 +2,13 @@
//! //!
//! Currently, this pass only propagates scalar values. //! Currently, this pass only propagates scalar values.
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable}; use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind; use rustc_hir::def::DefKind;
use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar}; use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_mir_dataflow::value_analysis::{ use rustc_mir_dataflow::value_analysis::{
Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace,
@ -16,8 +16,9 @@ use rustc_mir_dataflow::value_analysis::{
use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor}; use rustc_mir_dataflow::{lattice::FlatSet, Analysis, Results, ResultsVisitor};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::DUMMY_SP; use rustc_span::DUMMY_SP;
use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
use crate::const_prop::throw_machine_stop_str;
use crate::MirPass; use crate::MirPass;
// These constants are somewhat random guesses and have not been optimized. // These constants are somewhat random guesses and have not been optimized.
@ -553,18 +554,153 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
fn try_make_constant( fn try_make_constant(
&self, &self,
ecx: &mut InterpCx<'tcx, 'tcx, DummyMachine>,
place: Place<'tcx>, place: Place<'tcx>,
state: &State<FlatSet<Scalar>>, state: &State<FlatSet<Scalar>>,
map: &Map, map: &Map,
) -> Option<Const<'tcx>> { ) -> Option<Const<'tcx>> {
let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
return None;
};
let ty = place.ty(self.local_decls, self.patch.tcx).ty; let ty = place.ty(self.local_decls, self.patch.tcx).ty;
Some(Const::Val(ConstValue::Scalar(value.into()), ty)) let layout = ecx.layout_of(ty).ok()?;
if layout.is_zst() {
return Some(Const::zero_sized(ty));
}
if layout.is_unsized() {
return None;
}
let place = map.find(place.as_ref())?;
if layout.abi.is_scalar()
&& let Some(value) = propagatable_scalar(place, state, map)
{
return Some(Const::Val(ConstValue::Scalar(value), ty));
}
if matches!(layout.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
let alloc_id = ecx
.intern_with_temp_alloc(layout, |ecx, dest| {
try_write_constant(ecx, dest, place, ty, state, map)
})
.ok()?;
return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty));
}
None
} }
} }
fn propagatable_scalar(
place: PlaceIndex,
state: &State<FlatSet<Scalar>>,
map: &Map,
) -> Option<Scalar> {
if let FlatSet::Elem(value) = state.get_idx(place, map) && value.try_to_int().is_ok() {
// Do not attempt to propagate pointers, as we may fail to preserve their identity.
Some(value)
} else {
None
}
}
#[instrument(level = "trace", skip(ecx, state, map))]
fn try_write_constant<'tcx>(
ecx: &mut InterpCx<'_, 'tcx, DummyMachine>,
dest: &PlaceTy<'tcx>,
place: PlaceIndex,
ty: Ty<'tcx>,
state: &State<FlatSet<Scalar>>,
map: &Map,
) -> InterpResult<'tcx> {
let layout = ecx.layout_of(ty)?;
// Fast path for ZSTs.
if layout.is_zst() {
return Ok(());
}
// Fast path for scalars.
if layout.abi.is_scalar()
&& let Some(value) = propagatable_scalar(place, state, map)
{
return ecx.write_immediate(Immediate::Scalar(value), dest);
}
match ty.kind() {
// ZSTs. Nothing to do.
ty::FnDef(..) => {}
// Those are scalars, must be handled above.
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => throw_machine_stop_str!("primitive type with provenance"),
ty::Tuple(elem_tys) => {
for (i, elem) in elem_tys.iter().enumerate() {
let Some(field) = map.apply(place, TrackElem::Field(FieldIdx::from_usize(i))) else {
throw_machine_stop_str!("missing field in tuple")
};
let field_dest = ecx.project_field(dest, i)?;
try_write_constant(ecx, &field_dest, field, elem, state, map)?;
}
}
ty::Adt(def, args) => {
if def.is_union() {
throw_machine_stop_str!("cannot propagate unions")
}
let (variant_idx, variant_def, variant_place, variant_dest) = if def.is_enum() {
let Some(discr) = map.apply(place, TrackElem::Discriminant) else {
throw_machine_stop_str!("missing discriminant for enum")
};
let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else {
throw_machine_stop_str!("discriminant with provenance")
};
let discr_bits = discr.assert_bits(discr.size());
let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else {
throw_machine_stop_str!("illegal discriminant for enum")
};
let Some(variant_place) = map.apply(place, TrackElem::Variant(variant)) else {
throw_machine_stop_str!("missing variant for enum")
};
let variant_dest = ecx.project_downcast(dest, variant)?;
(variant, def.variant(variant), variant_place, variant_dest)
} else {
(FIRST_VARIANT, def.non_enum_variant(), place, dest.clone())
};
for (i, field) in variant_def.fields.iter_enumerated() {
let ty = field.ty(*ecx.tcx, args);
let Some(field) = map.apply(variant_place, TrackElem::Field(i)) else {
throw_machine_stop_str!("missing field in ADT")
};
let field_dest = ecx.project_field(&variant_dest, i.as_usize())?;
try_write_constant(ecx, &field_dest, field, ty, state, map)?;
}
ecx.write_discriminant(variant_idx, dest)?;
}
// Unsupported for now.
ty::Array(_, _)
// Do not attempt to support indirection in constants.
| ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_)
| ty::Never
| ty::Foreign(..)
| ty::Alias(..)
| ty::Param(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Closure(..)
| ty::Coroutine(..)
| ty::Dynamic(..) => throw_machine_stop_str!("unsupported type"),
ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(),
}
Ok(())
}
impl<'mir, 'tcx> impl<'mir, 'tcx>
ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>> ResultsVisitor<'mir, 'tcx, Results<'tcx, ValueAnalysisWrapper<ConstAnalysis<'_, 'tcx>>>>
for Collector<'tcx, '_> for Collector<'tcx, '_>
@ -580,8 +716,13 @@ impl<'mir, 'tcx>
) { ) {
match &statement.kind { match &statement.kind {
StatementKind::Assign(box (_, rvalue)) => { StatementKind::Assign(box (_, rvalue)) => {
OperandCollector { state, visitor: self, map: &results.analysis.0.map } OperandCollector {
.visit_rvalue(rvalue, location); state,
visitor: self,
ecx: &mut results.analysis.0.ecx,
map: &results.analysis.0.map,
}
.visit_rvalue(rvalue, location);
} }
_ => (), _ => (),
} }
@ -599,7 +740,12 @@ impl<'mir, 'tcx>
// Don't overwrite the assignment if it already uses a constant (to keep the span). // Don't overwrite the assignment if it already uses a constant (to keep the span).
} }
StatementKind::Assign(box (place, _)) => { StatementKind::Assign(box (place, _)) => {
if let Some(value) = self.try_make_constant(place, state, &results.analysis.0.map) { if let Some(value) = self.try_make_constant(
&mut results.analysis.0.ecx,
place,
state,
&results.analysis.0.map,
) {
self.patch.assignments.insert(location, value); self.patch.assignments.insert(location, value);
} }
} }
@ -614,8 +760,13 @@ impl<'mir, 'tcx>
terminator: &'mir Terminator<'tcx>, terminator: &'mir Terminator<'tcx>,
location: Location, location: Location,
) { ) {
OperandCollector { state, visitor: self, map: &results.analysis.0.map } OperandCollector {
.visit_terminator(terminator, location); state,
visitor: self,
ecx: &mut results.analysis.0.ecx,
map: &results.analysis.0.map,
}
.visit_terminator(terminator, location);
} }
} }
@ -670,6 +821,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> {
struct OperandCollector<'tcx, 'map, 'locals, 'a> { struct OperandCollector<'tcx, 'map, 'locals, 'a> {
state: &'a State<FlatSet<Scalar>>, state: &'a State<FlatSet<Scalar>>,
visitor: &'a mut Collector<'tcx, 'locals>, visitor: &'a mut Collector<'tcx, 'locals>,
ecx: &'map mut InterpCx<'tcx, 'tcx, DummyMachine>,
map: &'map Map, map: &'map Map,
} }
@ -682,7 +834,7 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
location: Location, location: Location,
) { ) {
if let PlaceElem::Index(local) = elem if let PlaceElem::Index(local) = elem
&& let Some(value) = self.visitor.try_make_constant(local.into(), self.state, self.map) && let Some(value) = self.visitor.try_make_constant(self.ecx, local.into(), self.state, self.map)
{ {
self.visitor.patch.before_effect.insert((location, local.into()), value); self.visitor.patch.before_effect.insert((location, local.into()), value);
} }
@ -690,7 +842,9 @@ impl<'tcx> Visitor<'tcx> for OperandCollector<'tcx, '_, '_, '_> {
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
if let Some(place) = operand.place() { if let Some(place) = operand.place() {
if let Some(value) = self.visitor.try_make_constant(place, self.state, self.map) { if let Some(value) =
self.visitor.try_make_constant(self.ecx, place, self.state, self.map)
{
self.visitor.patch.before_effect.insert((location, place), value); self.visitor.patch.before_effect.insert((location, place), value);
} else if !place.projection.is_empty() { } else if !place.projection.is_empty() {
// Try to propagate into `Index` projections. // Try to propagate into `Index` projections.
@ -713,7 +867,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
} }
fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool { fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>, _layout: TyAndLayout<'tcx>) -> bool {
unimplemented!() false
} }
fn before_access_global( fn before_access_global(
@ -725,13 +879,13 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
is_write: bool, is_write: bool,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
if is_write { if is_write {
crate::const_prop::throw_machine_stop_str!("can't write to global"); throw_machine_stop_str!("can't write to global");
} }
// If the static allocation is mutable, then we can't const prop it as its content // If the static allocation is mutable, then we can't const prop it as its content
// might be different at runtime. // might be different at runtime.
if alloc.inner().mutability.is_mut() { if alloc.inner().mutability.is_mut() {
crate::const_prop::throw_machine_stop_str!("can't access mutable globals in ConstProp"); throw_machine_stop_str!("can't access mutable globals in ConstProp");
} }
Ok(()) Ok(())
@ -781,7 +935,7 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
_left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
_right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>, _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> { ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
crate::const_prop::throw_machine_stop_str!("can't do pointer arithmetic"); throw_machine_stop_str!("can't do pointer arithmetic");
} }
fn expose_ptr( fn expose_ptr(

View File

@ -169,6 +169,9 @@ pub enum MirSpanview {
pub enum InstrumentCoverage { pub enum InstrumentCoverage {
/// Default `-C instrument-coverage` or `-C instrument-coverage=statement` /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
All, All,
/// Additionally, instrument branches and output branch coverage.
/// `-Zunstable-options -C instrument-coverage=branch`
Branch,
/// `-Zunstable-options -C instrument-coverage=except-unused-generics` /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
ExceptUnusedGenerics, ExceptUnusedGenerics,
/// `-Zunstable-options -C instrument-coverage=except-unused-functions` /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
@ -2747,7 +2750,10 @@ pub fn build_session_options(
} }
(Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {} (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
(Some(_), _) if !unstable_opts.unstable_options => { (Some(_), _) if !unstable_opts.unstable_options => {
handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`"); handler.early_error(
"`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
require `-Z unstable-options`",
);
} }
(None, None) => {} (None, None) => {}
(None, ic) => { (None, ic) => {

View File

@ -389,7 +389,7 @@ mod desc {
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
pub const parse_instrument_coverage: &str = pub const parse_instrument_coverage: &str =
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; "`all` (default), `branch`, `except-unused-generics`, `except-unused-functions`, or `off`";
pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`";
pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number";
@ -931,6 +931,7 @@ mod parse {
*slot = Some(match v { *slot = Some(match v {
"all" => InstrumentCoverage::All, "all" => InstrumentCoverage::All,
"branch" => InstrumentCoverage::Branch,
"except-unused-generics" | "except_unused_generics" => { "except-unused-generics" | "except_unused_generics" => {
InstrumentCoverage::ExceptUnusedGenerics InstrumentCoverage::ExceptUnusedGenerics
} }
@ -1356,6 +1357,7 @@ options! {
reports (note, the compiler build config must include `profiler = true`); \ reports (note, the compiler build config must include `profiler = true`); \
implies `-C symbol-mangling-version=v0`. Optional values are: implies `-C symbol-mangling-version=v0`. Optional values are:
`=all` (implicit value) `=all` (implicit value)
`=branch`
`=except-unused-generics` `=except-unused-generics`
`=except-unused-functions` `=except-unused-functions`
`=off` (default)"), `=off` (default)"),
@ -1597,6 +1599,7 @@ options! {
reports (note, the compiler build config must include `profiler = true`); \ reports (note, the compiler build config must include `profiler = true`); \
implies `-C symbol-mangling-version=v0`. Optional values are: implies `-C symbol-mangling-version=v0`. Optional values are:
`=all` (implicit value) `=all` (implicit value)
`=branch`
`=except-unused-generics` `=except-unused-generics`
`=except-unused-functions` `=except-unused-functions`
`=off` (default)"), `=off` (default)"),

View File

@ -702,6 +702,10 @@ impl Session {
self.opts.cg.instrument_coverage() != InstrumentCoverage::Off self.opts.cg.instrument_coverage() != InstrumentCoverage::Off
} }
pub fn instrument_coverage_branch(&self) -> bool {
self.opts.cg.instrument_coverage() == InstrumentCoverage::Branch
}
pub fn instrument_coverage_except_unused_generics(&self) -> bool { pub fn instrument_coverage_except_unused_generics(&self) -> bool {
self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedGenerics
} }

View File

@ -9,6 +9,7 @@ rustc_hir = { path = "../rustc_hir" }
rustc_middle = { path = "../rustc_middle" } rustc_middle = { path = "../rustc_middle" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
scoped-tls = "1.0"
stable_mir = {path = "../stable_mir" } stable_mir = {path = "../stable_mir" }
tracing = "0.1" tracing = "0.1"

View File

@ -3,7 +3,7 @@
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs //! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
//! until stable MIR is complete. //! until stable MIR is complete.
use crate::rustc_smir::Tables; use crate::rustc_smir::{Stable, Tables, TablesWrapper};
use rustc_data_structures::fx; use rustc_data_structures::fx;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::interpret::AllocId;
@ -11,13 +11,24 @@ use rustc_middle::ty;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::def_id::{CrateNum, DefId};
use rustc_span::Span; use rustc_span::Span;
use scoped_tls::scoped_thread_local;
use stable_mir::ty::IndexedVal; use stable_mir::ty::IndexedVal;
use std::cell::Cell;
use std::cell::RefCell;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::ops::Index; use std::ops::Index;
mod internal; mod internal;
pub fn stable<'tcx, S: Stable<'tcx>>(item: &S) -> S::T {
with_tables(|tables| item.stable(tables))
}
pub fn internal<'tcx, S: RustcInternal<'tcx>>(item: &S) -> S::T {
with_tables(|tables| item.internal(tables))
}
impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> { impl<'tcx> Index<stable_mir::DefId> for Tables<'tcx> {
type Output = DefId; type Output = DefId;
@ -125,18 +136,41 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
item.id.into() item.id.into()
} }
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
// datastructures and stable MIR datastructures
scoped_thread_local! (static TLV: Cell<*const ()>);
pub(crate) fn init<'tcx>(tables: &TablesWrapper<'tcx>, f: impl FnOnce()) {
assert!(!TLV.is_set());
let ptr = tables as *const _ as *const ();
TLV.set(&Cell::new(ptr), || {
f();
});
}
/// Loads the current context and calls a function with it.
/// Do not nest these, as that will ICE.
pub(crate) fn with_tables<'tcx, R>(f: impl FnOnce(&mut Tables<'tcx>) -> R) -> R {
assert!(TLV.is_set());
TLV.with(|tlv| {
let ptr = tlv.get();
assert!(!ptr.is_null());
let wrapper = ptr as *const TablesWrapper<'tcx>;
let mut tables = unsafe { (*wrapper).0.borrow_mut() };
f(&mut *tables)
})
}
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) { pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
stable_mir::run( let tables = TablesWrapper(RefCell::new(Tables {
Tables { tcx,
tcx, def_ids: IndexMap::default(),
def_ids: IndexMap::default(), alloc_ids: IndexMap::default(),
alloc_ids: IndexMap::default(), spans: IndexMap::default(),
spans: IndexMap::default(), types: vec![],
types: vec![], instances: IndexMap::default(),
instances: IndexMap::default(), }));
}, stable_mir::run(&tables, || init(&tables, f));
f,
);
} }
#[macro_export] #[macro_export]
@ -251,7 +285,7 @@ impl<K: PartialEq + Hash + Eq, V: Copy + Debug + PartialEq + IndexedVal> Index<V
/// Trait used to translate a stable construct to its rustc counterpart. /// Trait used to translate a stable construct to its rustc counterpart.
/// ///
/// This is basically a mirror of [crate::rustc_smir::Stable]. /// This is basically a mirror of [crate::rustc_smir::Stable].
pub(crate) trait RustcInternal<'tcx> { pub trait RustcInternal<'tcx> {
type T; type T;
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T; fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T;
} }

View File

@ -23,27 +23,31 @@ use stable_mir::ty::{
FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy, FloatTy, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, TyKind, UintTy,
}; };
use stable_mir::{self, opaque, Context, Filename}; use stable_mir::{self, opaque, Context, Filename};
use std::cell::RefCell;
use tracing::debug; use tracing::debug;
mod alloc; mod alloc;
mod builder; mod builder;
impl<'tcx> Context for Tables<'tcx> { impl<'tcx> Context for TablesWrapper<'tcx> {
fn local_crate(&self) -> stable_mir::Crate { fn local_crate(&self) -> stable_mir::Crate {
smir_crate(self.tcx, LOCAL_CRATE) let tables = self.0.borrow();
smir_crate(tables.tcx, LOCAL_CRATE)
} }
fn external_crates(&self) -> Vec<stable_mir::Crate> { fn external_crates(&self) -> Vec<stable_mir::Crate> {
self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect() let tables = self.0.borrow();
tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect()
} }
fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> { fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> {
let tables = self.0.borrow();
let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE] let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE]
.iter() .iter()
.chain(self.tcx.crates(()).iter()) .chain(tables.tcx.crates(()).iter())
.map(|crate_num| { .map(|crate_num| {
let crate_name = self.tcx.crate_name(*crate_num).to_string(); let crate_name = tables.tcx.crate_name(*crate_num).to_string();
(name == crate_name).then(|| smir_crate(self.tcx, *crate_num)) (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num))
}) })
.into_iter() .into_iter()
.filter_map(|c| c) .filter_map(|c| c)
@ -52,163 +56,197 @@ impl<'tcx> Context for Tables<'tcx> {
} }
fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String { fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
self.tcx.def_path_str(self[def_id]) let tables = self.0.borrow();
tables.tcx.def_path_str(tables[def_id])
} }
fn span_to_string(&self, span: stable_mir::ty::Span) -> String { fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
self.tcx.sess.source_map().span_to_diagnostic_string(self[span]) let tables = self.0.borrow();
tables.tcx.sess.source_map().span_to_diagnostic_string(tables[span])
} }
fn get_filename(&self, span: &Span) -> Filename { fn get_filename(&self, span: &Span) -> Filename {
let tables = self.0.borrow();
opaque( opaque(
&self &tables
.tcx .tcx
.sess .sess
.source_map() .source_map()
.span_to_filename(self[*span]) .span_to_filename(tables[*span])
.display(rustc_span::FileNameDisplayPreference::Local) .display(rustc_span::FileNameDisplayPreference::Local)
.to_string(), .to_string(),
) )
} }
fn get_lines(&self, span: &Span) -> LineInfo { fn get_lines(&self, span: &Span) -> LineInfo {
let lines = &self.tcx.sess.source_map().span_to_location_info(self[*span]); let tables = self.0.borrow();
let lines = &tables.tcx.sess.source_map().span_to_location_info(tables[*span]);
LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 } LineInfo { start_line: lines.1, start_col: lines.2, end_line: lines.3, end_col: lines.4 }
} }
fn def_kind(&mut self, def_id: stable_mir::DefId) -> stable_mir::DefKind { fn def_kind(&self, def_id: stable_mir::DefId) -> stable_mir::DefKind {
self.tcx.def_kind(self[def_id]).stable(self) let mut tables = self.0.borrow_mut();
tables.tcx.def_kind(tables[def_id]).stable(&mut *tables)
} }
fn span_of_an_item(&mut self, def_id: stable_mir::DefId) -> Span { fn span_of_an_item(&self, def_id: stable_mir::DefId) -> Span {
self.tcx.def_span(self[def_id]).stable(self) let mut tables = self.0.borrow_mut();
tables.tcx.def_span(tables[def_id]).stable(&mut *tables)
} }
fn all_local_items(&mut self) -> stable_mir::CrateItems { fn all_local_items(&self) -> stable_mir::CrateItems {
self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect() let mut tables = self.0.borrow_mut();
tables.tcx.mir_keys(()).iter().map(|item| tables.crate_item(item.to_def_id())).collect()
} }
fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> { fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
Some(self.crate_item(self.tcx.entry_fn(())?.0)) let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
Some(tables.crate_item(tcx.entry_fn(())?.0))
} }
fn all_trait_decls(&mut self) -> stable_mir::TraitDecls { fn all_trait_decls(&self) -> stable_mir::TraitDecls {
self.tcx let mut tables = self.0.borrow_mut();
tables
.tcx
.traits(LOCAL_CRATE) .traits(LOCAL_CRATE)
.iter() .iter()
.map(|trait_def_id| self.trait_def(*trait_def_id)) .map(|trait_def_id| tables.trait_def(*trait_def_id))
.collect() .collect()
} }
fn trait_decl(&mut self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl { fn trait_decl(&self, trait_def: &stable_mir::ty::TraitDef) -> stable_mir::ty::TraitDecl {
let def_id = self[trait_def.0]; let mut tables = self.0.borrow_mut();
let trait_def = self.tcx.trait_def(def_id); let def_id = tables[trait_def.0];
trait_def.stable(self) let trait_def = tables.tcx.trait_def(def_id);
trait_def.stable(&mut *tables)
} }
fn all_trait_impls(&mut self) -> stable_mir::ImplTraitDecls { fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
self.tcx let mut tables = self.0.borrow_mut();
tables
.tcx
.trait_impls_in_crate(LOCAL_CRATE) .trait_impls_in_crate(LOCAL_CRATE)
.iter() .iter()
.map(|impl_def_id| self.impl_def(*impl_def_id)) .map(|impl_def_id| tables.impl_def(*impl_def_id))
.collect() .collect()
} }
fn trait_impl(&mut self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait { fn trait_impl(&self, impl_def: &stable_mir::ty::ImplDef) -> stable_mir::ty::ImplTrait {
let def_id = self[impl_def.0]; let mut tables = self.0.borrow_mut();
let impl_trait = self.tcx.impl_trait_ref(def_id).unwrap(); let def_id = tables[impl_def.0];
impl_trait.stable(self) let impl_trait = tables.tcx.impl_trait_ref(def_id).unwrap();
impl_trait.stable(&mut *tables)
} }
fn mir_body(&mut self, item: stable_mir::DefId) -> stable_mir::mir::Body { fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
let def_id = self[item]; let mut tables = self.0.borrow_mut();
self.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(self) let def_id = tables[item];
tables.tcx.instance_mir(ty::InstanceDef::Item(def_id)).stable(&mut tables)
} }
fn ty_kind(&mut self, ty: stable_mir::ty::Ty) -> TyKind { fn ty_kind(&self, ty: stable_mir::ty::Ty) -> TyKind {
self.types[ty.0].clone().stable(self) let mut tables = self.0.borrow_mut();
tables.types[ty.0].clone().stable(&mut *tables)
} }
fn mk_ty(&mut self, kind: TyKind) -> stable_mir::ty::Ty { fn mk_ty(&self, kind: TyKind) -> stable_mir::ty::Ty {
let n = self.types.len(); let mut tables = self.0.borrow_mut();
self.types.push(MaybeStable::Stable(kind)); let n = tables.types.len();
tables.types.push(MaybeStable::Stable(kind));
stable_mir::ty::Ty(n) stable_mir::ty::Ty(n)
} }
fn generics_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics { fn generics_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::Generics {
let def_id = self[def_id]; let mut tables = self.0.borrow_mut();
let generics = self.tcx.generics_of(def_id); let def_id = tables[def_id];
generics.stable(self) let generics = tables.tcx.generics_of(def_id);
generics.stable(&mut *tables)
} }
fn predicates_of(&mut self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates { fn predicates_of(&self, def_id: stable_mir::DefId) -> stable_mir::ty::GenericPredicates {
let def_id = self[def_id]; let mut tables = self.0.borrow_mut();
let ty::GenericPredicates { parent, predicates } = self.tcx.predicates_of(def_id); let def_id = tables[def_id];
let ty::GenericPredicates { parent, predicates } = tables.tcx.predicates_of(def_id);
stable_mir::ty::GenericPredicates { stable_mir::ty::GenericPredicates {
parent: parent.map(|did| self.trait_def(did)), parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates predicates: predicates
.iter() .iter()
.map(|(clause, span)| { .map(|(clause, span)| {
(clause.as_predicate().kind().skip_binder().stable(self), span.stable(self)) (
clause.as_predicate().kind().skip_binder().stable(&mut *tables),
span.stable(&mut *tables),
)
}) })
.collect(), .collect(),
} }
} }
fn explicit_predicates_of( fn explicit_predicates_of(
&mut self, &self,
def_id: stable_mir::DefId, def_id: stable_mir::DefId,
) -> stable_mir::ty::GenericPredicates { ) -> stable_mir::ty::GenericPredicates {
let def_id = self[def_id]; let mut tables = self.0.borrow_mut();
let ty::GenericPredicates { parent, predicates } = self.tcx.explicit_predicates_of(def_id); let def_id = tables[def_id];
let ty::GenericPredicates { parent, predicates } =
tables.tcx.explicit_predicates_of(def_id);
stable_mir::ty::GenericPredicates { stable_mir::ty::GenericPredicates {
parent: parent.map(|did| self.trait_def(did)), parent: parent.map(|did| tables.trait_def(did)),
predicates: predicates predicates: predicates
.iter() .iter()
.map(|(clause, span)| { .map(|(clause, span)| {
(clause.as_predicate().kind().skip_binder().stable(self), span.stable(self)) (
clause.as_predicate().kind().skip_binder().stable(&mut *tables),
span.stable(&mut *tables),
)
}) })
.collect(), .collect(),
} }
} }
fn instance_body(&mut self, def: InstanceDef) -> Body { fn instance_body(&self, def: InstanceDef) -> Body {
let instance = self.instances[def]; let mut tables = self.0.borrow_mut();
builder::BodyBuilder::new(self.tcx, instance).build(self) let instance = tables.instances[def];
builder::BodyBuilder::new(tables.tcx, instance).build(&mut *tables)
} }
fn instance_ty(&mut self, def: InstanceDef) -> stable_mir::ty::Ty { fn instance_ty(&self, def: InstanceDef) -> stable_mir::ty::Ty {
let instance = self.instances[def]; let mut tables = self.0.borrow_mut();
let ty = instance.ty(self.tcx, ParamEnv::empty()); let instance = tables.instances[def];
self.intern_ty(ty) let ty = instance.ty(tables.tcx, ParamEnv::empty());
tables.intern_ty(ty)
} }
fn instance_def_id(&mut self, def: InstanceDef) -> stable_mir::DefId { fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
let def_id = self.instances[def].def_id(); let mut tables = self.0.borrow_mut();
self.create_def_id(def_id) let def_id = tables.instances[def].def_id();
tables.create_def_id(def_id)
} }
fn mono_instance(&mut self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance { fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
let def_id = self[item.0]; let mut tables = self.0.borrow_mut();
Instance::mono(self.tcx, def_id).stable(self) let def_id = tables[item.0];
Instance::mono(tables.tcx, def_id).stable(&mut *tables)
} }
fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool { fn requires_monomorphization(&self, def_id: stable_mir::DefId) -> bool {
let def_id = self[def_id]; let tables = self.0.borrow();
let generics = self.tcx.generics_of(def_id); let def_id = tables[def_id];
let result = generics.requires_monomorphization(self.tcx); let generics = tables.tcx.generics_of(def_id);
let result = generics.requires_monomorphization(tables.tcx);
result result
} }
fn resolve_instance( fn resolve_instance(
&mut self, &self,
def: stable_mir::ty::FnDef, def: stable_mir::ty::FnDef,
args: &stable_mir::ty::GenericArgs, args: &stable_mir::ty::GenericArgs,
) -> Option<stable_mir::mir::mono::Instance> { ) -> Option<stable_mir::mir::mono::Instance> {
let def_id = def.0.internal(self); let mut tables = self.0.borrow_mut();
let args_ref = args.internal(self); let def_id = def.0.internal(&mut *tables);
match Instance::resolve(self.tcx, ParamEnv::reveal_all(), def_id, args_ref) { let args_ref = args.internal(&mut *tables);
Ok(Some(instance)) => Some(instance.stable(self)), match Instance::resolve(tables.tcx, ParamEnv::reveal_all(), def_id, args_ref) {
Ok(Some(instance)) => Some(instance.stable(&mut *tables)),
Ok(None) | Err(_) => None, Ok(None) | Err(_) => None,
} }
} }
@ -241,13 +279,15 @@ impl<S, R: PartialEq> PartialEq<R> for MaybeStable<S, R> {
} }
} }
pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell<Tables<'tcx>>);
pub struct Tables<'tcx> { pub struct Tables<'tcx> {
pub tcx: TyCtxt<'tcx>, pub(crate) tcx: TyCtxt<'tcx>,
pub def_ids: IndexMap<DefId, stable_mir::DefId>, pub(crate) def_ids: IndexMap<DefId, stable_mir::DefId>,
pub alloc_ids: IndexMap<AllocId, stable_mir::AllocId>, pub(crate) alloc_ids: IndexMap<AllocId, stable_mir::AllocId>,
pub spans: IndexMap<rustc_span::Span, Span>, pub(crate) spans: IndexMap<rustc_span::Span, Span>,
pub types: Vec<MaybeStable<TyKind, Ty<'tcx>>>, pub(crate) types: Vec<MaybeStable<TyKind, Ty<'tcx>>>,
pub instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
} }
impl<'tcx> Tables<'tcx> { impl<'tcx> Tables<'tcx> {
@ -270,7 +310,7 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
} }
/// Trait used to convert between an internal MIR type to a Stable MIR type. /// Trait used to convert between an internal MIR type to a Stable MIR type.
pub(crate) trait Stable<'tcx> { pub trait Stable<'tcx> {
/// The stable representation of the type implementing Stable. /// The stable representation of the type implementing Stable.
type T; type T;
/// Converts an object to the equivalent Stable MIR representation. /// Converts an object to the equivalent Stable MIR representation.

View File

@ -957,6 +957,7 @@ symbols! {
log_syntax, log_syntax,
logf32, logf32,
logf64, logf64,
loongarch_target_feature,
loop_break_value, loop_break_value,
lt, lt,
macro_at_most_once_rep, macro_at_most_once_rep,
@ -1369,6 +1370,7 @@ symbols! {
rustc_evaluate_where_clauses, rustc_evaluate_where_clauses,
rustc_expected_cgu_reuse, rustc_expected_cgu_reuse,
rustc_has_incoherent_inherent_impls, rustc_has_incoherent_inherent_impls,
rustc_hidden_type_of_opaques,
rustc_host, rustc_host,
rustc_if_this_changed, rustc_if_this_changed,
rustc_inherit_overflow_checks, rustc_inherit_overflow_checks,

View File

@ -224,12 +224,20 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'_, 'tcx> {
let kind = match *r { let kind = match *r {
ty::ReLateBound(..) => return r, ty::ReLateBound(..) => return r,
ty::ReStatic => match self.canonicalize_mode { // We may encounter `ReStatic` in item signatures or the hidden type
// of an opaque. `ReErased` should only be encountered in the hidden
// type of an opaque for regions that are ignored for the purposes of
// captures.
//
// FIXME: We should investigate the perf implications of not uniquifying
// `ReErased`. We may be able to short-circuit registering region
// obligations if we encounter a `ReErased` on one side, for example.
ty::ReStatic | ty::ReErased => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => return r, CanonicalizeMode::Response { .. } => return r,
}, },
ty::ReErased | ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode { ty::ReFree(_) | ty::ReEarlyBound(_) => match self.canonicalize_mode {
CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT),
CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"), CanonicalizeMode::Response { .. } => bug!("unexpected region in response: {r:?}"),
}, },

View File

@ -1,4 +1,5 @@
use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::infer::{InferCtxt, TyOrConstInferVar};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
@ -68,7 +69,7 @@ pub struct PendingPredicateObligation<'tcx> {
// should mostly optimize for reading speed, while modifying is not as relevant. // should mostly optimize for reading speed, while modifying is not as relevant.
// //
// For whatever reason using a boxed slice is slower than using a `Vec` here. // For whatever reason using a boxed slice is slower than using a `Vec` here.
pub stalled_on: Vec<TyOrConstInferVar<'tcx>>, pub stalled_on: Vec<TyOrConstInferVar>,
} }
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@ -669,7 +670,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
&mut self, &mut self,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
trait_obligation: PolyTraitObligation<'tcx>, trait_obligation: PolyTraitObligation<'tcx>,
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx; let infcx = self.selcx.infcx;
if obligation.predicate.is_global() && !self.selcx.is_intercrate() { if obligation.predicate.is_global() && !self.selcx.is_intercrate() {
@ -722,7 +723,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
&mut self, &mut self,
obligation: &PredicateObligation<'tcx>, obligation: &PredicateObligation<'tcx>,
project_obligation: PolyProjectionObligation<'tcx>, project_obligation: PolyProjectionObligation<'tcx>,
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, stalled_on: &mut Vec<TyOrConstInferVar>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx(); let tcx = self.selcx.tcx();
@ -775,7 +776,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
fn args_infer_vars<'a, 'tcx>( fn args_infer_vars<'a, 'tcx>(
selcx: &SelectionContext<'a, 'tcx>, selcx: &SelectionContext<'a, 'tcx>,
args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> { ) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
selcx selcx
.infcx .infcx
.resolve_vars_if_possible(args) .resolve_vars_if_possible(args)

View File

@ -5,8 +5,8 @@ use std::fmt;
use std::hash; use std::hash;
use crate::{ use crate::{
DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx, DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
TyDecoder, TyEncoder, TyEncoder, WithInfcx,
}; };
use self::ConstKind::*; use self::ConstKind::*;
@ -231,13 +231,13 @@ impl<I: Interner> Clone for ConstKind<I> {
impl<I: Interner> fmt::Debug for ConstKind<I> { impl<I: Interner> fmt::Debug for ConstKind<I> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
use ConstKind::*; use ConstKind::*;

View File

@ -3,38 +3,48 @@ use crate::{Interner, UniverseIndex};
use core::fmt; use core::fmt;
use std::marker::PhantomData; use std::marker::PhantomData;
pub trait InferCtxtLike<I: Interner> { pub trait InferCtxtLike {
fn universe_of_ty(&self, ty: I::InferTy) -> Option<UniverseIndex>; type Interner: Interner;
fn universe_of_lt(&self, lt: I::InferRegion) -> Option<UniverseIndex>; fn universe_of_ty(&self, ty: <Self::Interner as Interner>::InferTy) -> Option<UniverseIndex>;
fn universe_of_ct(&self, ct: I::InferConst) -> Option<UniverseIndex>; fn universe_of_lt(
&self,
lt: <Self::Interner as Interner>::InferRegion,
) -> Option<UniverseIndex>;
fn universe_of_ct(&self, ct: <Self::Interner as Interner>::InferConst)
-> Option<UniverseIndex>;
} }
impl<I: Interner> InferCtxtLike<I> for core::convert::Infallible { pub struct NoInfcx<I>(PhantomData<I>);
impl<I: Interner> InferCtxtLike for NoInfcx<I> {
type Interner = I;
fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> { fn universe_of_ty(&self, _ty: <I as Interner>::InferTy) -> Option<UniverseIndex> {
match *self {} None
} }
fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> { fn universe_of_ct(&self, _ct: <I as Interner>::InferConst) -> Option<UniverseIndex> {
match *self {} None
} }
fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> { fn universe_of_lt(&self, _lt: <I as Interner>::InferRegion) -> Option<UniverseIndex> {
match *self {} None
} }
} }
pub trait DebugWithInfcx<I: Interner>: fmt::Debug { pub trait DebugWithInfcx<I: Interner>: fmt::Debug {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
) -> fmt::Result; ) -> fmt::Result;
} }
impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T { impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
) -> fmt::Result { ) -> fmt::Result {
<T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f) <T as DebugWithInfcx<I>>::fmt(this.map(|&data| data), f)
@ -42,8 +52,8 @@ impl<I: Interner, T: DebugWithInfcx<I> + ?Sized> DebugWithInfcx<I> for &'_ T {
} }
impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] { impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
) -> fmt::Result { ) -> fmt::Result {
match f.alternate() { match f.alternate() {
@ -70,46 +80,45 @@ impl<I: Interner, T: DebugWithInfcx<I>> DebugWithInfcx<I> for [T] {
} }
} }
pub struct OptWithInfcx<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> { pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> {
pub data: T, pub data: T,
pub infcx: Option<&'a InfCtx>, pub infcx: &'a Infcx,
_interner: PhantomData<I>,
} }
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Copy> Copy for OptWithInfcx<'_, I, InfCtx, T> {} impl<Infcx: InferCtxtLike, T: Copy> Copy for WithInfcx<'_, Infcx, T> {}
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: Clone> Clone for OptWithInfcx<'_, I, InfCtx, T> { impl<Infcx: InferCtxtLike, T: Clone> Clone for WithInfcx<'_, Infcx, T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { data: self.data.clone(), infcx: self.infcx, _interner: self._interner } Self { data: self.data.clone(), infcx: self.infcx }
} }
} }
impl<'a, I: Interner, T> OptWithInfcx<'a, I, core::convert::Infallible, T> { impl<'a, I: Interner, T> WithInfcx<'a, NoInfcx<I>, T> {
pub fn new_no_ctx(data: T) -> Self { pub fn with_no_infcx(data: T) -> Self {
Self { data, infcx: None, _interner: PhantomData } Self { data, infcx: &NoInfcx(PhantomData) }
} }
} }
impl<'a, I: Interner, InfCtx: InferCtxtLike<I>, T> OptWithInfcx<'a, I, InfCtx, T> { impl<'a, Infcx: InferCtxtLike, T> WithInfcx<'a, Infcx, T> {
pub fn new(data: T, infcx: &'a InfCtx) -> Self { pub fn new(data: T, infcx: &'a Infcx) -> Self {
Self { data, infcx: Some(infcx), _interner: PhantomData } Self { data, infcx }
} }
pub fn wrap<U>(self, u: U) -> OptWithInfcx<'a, I, InfCtx, U> { pub fn wrap<U>(self, u: U) -> WithInfcx<'a, Infcx, U> {
OptWithInfcx { data: u, infcx: self.infcx, _interner: PhantomData } WithInfcx { data: u, infcx: self.infcx }
} }
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> OptWithInfcx<'a, I, InfCtx, U> { pub fn map<U>(self, f: impl FnOnce(T) -> U) -> WithInfcx<'a, Infcx, U> {
OptWithInfcx { data: f(self.data), infcx: self.infcx, _interner: PhantomData } WithInfcx { data: f(self.data), infcx: self.infcx }
} }
pub fn as_ref(&self) -> OptWithInfcx<'a, I, InfCtx, &T> { pub fn as_ref(&self) -> WithInfcx<'a, Infcx, &T> {
OptWithInfcx { data: &self.data, infcx: self.infcx, _interner: PhantomData } WithInfcx { data: &self.data, infcx: self.infcx }
} }
} }
impl<I: Interner, InfCtx: InferCtxtLike<I>, T: DebugWithInfcx<I>> fmt::Debug impl<Infcx: InferCtxtLike, T: DebugWithInfcx<Infcx::Interner>> fmt::Debug
for OptWithInfcx<'_, I, InfCtx, T> for WithInfcx<'_, Infcx, T>
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DebugWithInfcx::fmt(self.as_ref(), f) DebugWithInfcx::fmt(self.as_ref(), f)

View File

@ -34,7 +34,7 @@ mod region_kind;
pub use codec::*; pub use codec::*;
pub use const_kind::*; pub use const_kind::*;
pub use debug::{DebugWithInfcx, InferCtxtLike, OptWithInfcx}; pub use debug::{DebugWithInfcx, InferCtxtLike, WithInfcx};
pub use flags::*; pub use flags::*;
pub use interner::*; pub use interner::*;
pub use region_kind::*; pub use region_kind::*;

View File

@ -5,8 +5,8 @@ use std::fmt;
use std::hash; use std::hash;
use crate::{ use crate::{
DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, OptWithInfcx, DebruijnIndex, DebugWithInfcx, HashStableContext, InferCtxtLike, Interner, TyDecoder,
TyDecoder, TyEncoder, TyEncoder, WithInfcx,
}; };
use self::RegionKind::*; use self::RegionKind::*;
@ -274,8 +274,8 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
} }
impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> { impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> core::fmt::Result { ) -> core::fmt::Result {
match this.data { match this.data {
@ -301,7 +301,7 @@ impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
} }
impl<I: Interner> fmt::Debug for RegionKind<I> { impl<I: Interner> fmt::Debug for RegionKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }

View File

@ -11,7 +11,7 @@ use crate::HashStableContext;
use crate::Interner; use crate::Interner;
use crate::TyDecoder; use crate::TyDecoder;
use crate::TyEncoder; use crate::TyEncoder;
use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, OptWithInfcx}; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
use self::TyKind::*; use self::TyKind::*;
@ -534,8 +534,8 @@ impl<I: Interner> hash::Hash for TyKind<I> {
} }
impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut core::fmt::Formatter<'_>, f: &mut core::fmt::Formatter<'_>,
) -> fmt::Result { ) -> fmt::Result {
match this.data { match this.data {
@ -617,7 +617,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
// This is manually implemented because a derive would require `I: Debug` // This is manually implemented because a derive would require `I: Debug`
impl<I: Interner> fmt::Debug for TyKind<I> { impl<I: Interner> fmt::Debug for TyKind<I> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
OptWithInfcx::new_no_ctx(self).fmt(f) WithInfcx::with_no_infcx(self).fmt(f)
} }
} }
@ -1239,12 +1239,12 @@ impl fmt::Debug for InferTy {
} }
impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy { impl<I: Interner<InferTy = InferTy>> DebugWithInfcx<I> for InferTy {
fn fmt<InfCtx: InferCtxtLike<I>>( fn fmt<Infcx: InferCtxtLike<Interner = I>>(
this: OptWithInfcx<'_, I, InfCtx, &Self>, this: WithInfcx<'_, Infcx, &Self>,
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
) -> fmt::Result { ) -> fmt::Result {
use InferTy::*; use InferTy::*;
match this.infcx.and_then(|infcx| infcx.universe_of_ty(*this.data)) { match this.infcx.universe_of_ty(*this.data) {
None => write!(f, "{:?}", this.data), None => write!(f, "{:?}", this.data),
Some(universe) => match *this.data { Some(universe) => match *this.data {
TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()), TyVar(ty_vid) => write!(f, "?{}_{}t", ty_vid.index(), universe.index()),

View File

@ -175,17 +175,17 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
} }
pub trait Context { pub trait Context {
fn entry_fn(&mut self) -> Option<CrateItem>; fn entry_fn(&self) -> Option<CrateItem>;
/// Retrieve all items of the local crate that have a MIR associated with them. /// Retrieve all items of the local crate that have a MIR associated with them.
fn all_local_items(&mut self) -> CrateItems; fn all_local_items(&self) -> CrateItems;
fn mir_body(&mut self, item: DefId) -> mir::Body; fn mir_body(&self, item: DefId) -> mir::Body;
fn all_trait_decls(&mut self) -> TraitDecls; fn all_trait_decls(&self) -> TraitDecls;
fn trait_decl(&mut self, trait_def: &TraitDef) -> TraitDecl; fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
fn all_trait_impls(&mut self) -> ImplTraitDecls; fn all_trait_impls(&self) -> ImplTraitDecls;
fn trait_impl(&mut self, trait_impl: &ImplDef) -> ImplTrait; fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
fn generics_of(&mut self, def_id: DefId) -> Generics; fn generics_of(&self, def_id: DefId) -> Generics;
fn predicates_of(&mut self, def_id: DefId) -> GenericPredicates; fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
fn explicit_predicates_of(&mut self, def_id: DefId) -> GenericPredicates; fn explicit_predicates_of(&self, def_id: DefId) -> GenericPredicates;
/// Get information about the local crate. /// Get information about the local crate.
fn local_crate(&self) -> Crate; fn local_crate(&self) -> Crate;
/// Retrieve a list of all external crates. /// Retrieve a list of all external crates.
@ -207,61 +207,58 @@ pub trait Context {
fn get_lines(&self, span: &Span) -> LineInfo; fn get_lines(&self, span: &Span) -> LineInfo;
/// Returns the `kind` of given `DefId` /// Returns the `kind` of given `DefId`
fn def_kind(&mut self, def_id: DefId) -> DefKind; fn def_kind(&self, def_id: DefId) -> DefKind;
/// `Span` of an item /// `Span` of an item
fn span_of_an_item(&mut self, def_id: DefId) -> Span; fn span_of_an_item(&self, def_id: DefId) -> Span;
/// Obtain the representation of a type. /// Obtain the representation of a type.
fn ty_kind(&mut self, ty: Ty) -> TyKind; fn ty_kind(&self, ty: Ty) -> TyKind;
/// Create a new `Ty` from scratch without information from rustc. /// Create a new `Ty` from scratch without information from rustc.
fn mk_ty(&mut self, kind: TyKind) -> Ty; fn mk_ty(&self, kind: TyKind) -> Ty;
/// Get the body of an Instance. /// Get the body of an Instance.
/// FIXME: Monomorphize the body. /// FIXME: Monomorphize the body.
fn instance_body(&mut self, instance: InstanceDef) -> Body; fn instance_body(&self, instance: InstanceDef) -> Body;
/// Get the instance type with generic substitutions applied and lifetimes erased. /// Get the instance type with generic substitutions applied and lifetimes erased.
fn instance_ty(&mut self, instance: InstanceDef) -> Ty; fn instance_ty(&self, instance: InstanceDef) -> Ty;
/// Get the instance. /// Get the instance.
fn instance_def_id(&mut self, instance: InstanceDef) -> DefId; fn instance_def_id(&self, instance: InstanceDef) -> DefId;
/// Convert a non-generic crate item into an instance. /// Convert a non-generic crate item into an instance.
/// This function will panic if the item is generic. /// This function will panic if the item is generic.
fn mono_instance(&mut self, item: CrateItem) -> Instance; fn mono_instance(&self, item: CrateItem) -> Instance;
/// Item requires monomorphization. /// Item requires monomorphization.
fn requires_monomorphization(&self, def_id: DefId) -> bool; fn requires_monomorphization(&self, def_id: DefId) -> bool;
/// Resolve an instance from the given function definition and generic arguments. /// Resolve an instance from the given function definition and generic arguments.
fn resolve_instance(&mut self, def: FnDef, args: &GenericArgs) -> Option<Instance>; fn resolve_instance(&self, def: FnDef, args: &GenericArgs) -> Option<Instance>;
} }
// A thread local variable that stores a pointer to the tables mapping between TyCtxt // A thread local variable that stores a pointer to the tables mapping between TyCtxt
// datastructures and stable MIR datastructures // datastructures and stable MIR datastructures
scoped_thread_local! (static TLV: Cell<*mut ()>); scoped_thread_local! (static TLV: Cell<*const ()>);
pub fn run(mut context: impl Context, f: impl FnOnce()) { pub fn run(context: &dyn Context, f: impl FnOnce()) {
assert!(!TLV.is_set()); assert!(!TLV.is_set());
fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) { let ptr: *const () = &context as *const &_ as _;
let ptr: *mut () = &mut context as *mut &mut _ as _; TLV.set(&Cell::new(ptr), || {
TLV.set(&Cell::new(ptr), || { f();
f(); });
});
}
g(&mut context, f);
} }
/// Loads the current context and calls a function with it. /// Loads the current context and calls a function with it.
/// Do not nest these, as that will ICE. /// Do not nest these, as that will ICE.
pub fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R { pub fn with<R>(f: impl FnOnce(&dyn Context) -> R) -> R {
assert!(TLV.is_set()); assert!(TLV.is_set());
TLV.with(|tlv| { TLV.with(|tlv| {
let ptr = tlv.get(); let ptr = tlv.get();
assert!(!ptr.is_null()); assert!(!ptr.is_null());
f(unsafe { *(ptr as *mut &mut dyn Context) }) f(unsafe { *(ptr as *const &dyn Context) })
}) })
} }

View File

@ -6,7 +6,7 @@
//! match those defined by C, so that code that interacts with C will //! match those defined by C, so that code that interacts with C will
//! refer to the correct types. //! refer to the correct types.
#![stable(feature = "", since = "1.30.0")] #![stable(feature = "core_ffi", since = "1.30.0")]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
use crate::fmt; use crate::fmt;

View File

@ -1,6 +1,4 @@
use crate::cmp::Ordering;
use crate::fmt::{self, Write}; use crate::fmt::{self, Write};
use crate::hash;
use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use super::display_buffer::DisplayBuffer; use super::display_buffer::DisplayBuffer;
@ -63,7 +61,7 @@ pub enum SocketAddr {
/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1)); /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
/// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.port(), 8080);
/// ``` /// ```
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct SocketAddrV4 { pub struct SocketAddrV4 {
ip: Ipv4Addr, ip: Ipv4Addr,
@ -96,7 +94,7 @@ pub struct SocketAddrV4 {
/// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)); /// assert_eq!(socket.ip(), &Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1));
/// assert_eq!(socket.port(), 8080); /// assert_eq!(socket.port(), 8080);
/// ``` /// ```
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct SocketAddrV6 { pub struct SocketAddrV6 {
ip: Ipv6Addr, ip: Ipv6Addr,
@ -644,48 +642,3 @@ impl fmt::Debug for SocketAddrV6 {
fmt::Display::fmt(self, fmt) fmt::Display::fmt(self, fmt)
} }
} }
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl PartialOrd for SocketAddrV4 {
#[inline]
fn partial_cmp(&self, other: &SocketAddrV4) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl PartialOrd for SocketAddrV6 {
#[inline]
fn partial_cmp(&self, other: &SocketAddrV6) -> Option<Ordering> {
Some(self.cmp(other))
}
}
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl Ord for SocketAddrV4 {
#[inline]
fn cmp(&self, other: &SocketAddrV4) -> Ordering {
self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
}
}
#[stable(feature = "socketaddr_ordering", since = "1.45.0")]
impl Ord for SocketAddrV6 {
#[inline]
fn cmp(&self, other: &SocketAddrV6) -> Ordering {
self.ip().cmp(other.ip()).then(self.port().cmp(&other.port()))
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for SocketAddrV4 {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
(self.port, self.ip).hash(s)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl hash::Hash for SocketAddrV6 {
fn hash<H: hash::Hasher>(&self, s: &mut H) {
(self.port, &self.ip, self.flowinfo, self.scope_id).hash(s)
}
}

View File

@ -114,7 +114,7 @@ macro_rules! midpoint_impl {
without modifying the original"] without modifying the original"]
#[inline] #[inline]
pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { pub const fn midpoint(self, rhs: $SelfT) -> $SelfT {
// Use the well known branchless algorthim from Hacker's Delight to compute // Use the well known branchless algorithm from Hacker's Delight to compute
// `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`. // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`.
((self ^ rhs) >> 1) + (self & rhs) ((self ^ rhs) >> 1) + (self & rhs)
} }

View File

@ -199,6 +199,9 @@ fn compare() {
let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap(); let v6_1 = "[2001:db8:f00::1002]:23456".parse::<SocketAddrV6>().unwrap();
let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap(); let v6_2 = "[2001:db8:f00::2001]:12345".parse::<SocketAddrV6>().unwrap();
let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap(); let v6_3 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
let v6_4 = "[2001:db8:f00::2001%42]:23456".parse::<SocketAddrV6>().unwrap();
let mut v6_5 = "[2001:db8:f00::2001]:23456".parse::<SocketAddrV6>().unwrap();
v6_5.set_flowinfo(17);
// equality // equality
assert_eq!(v4_1, v4_1); assert_eq!(v4_1, v4_1);
@ -207,6 +210,8 @@ fn compare() {
assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1));
assert!(v4_1 != v4_2); assert!(v4_1 != v4_2);
assert!(v6_1 != v6_2); assert!(v6_1 != v6_2);
assert!(v6_3 != v6_4);
assert!(v6_3 != v6_5);
// compare different addresses // compare different addresses
assert!(v4_1 < v4_2); assert!(v4_1 < v4_2);
@ -226,6 +231,12 @@ fn compare() {
assert!(v4_3 > v4_1); assert!(v4_3 > v4_1);
assert!(v6_3 > v6_1); assert!(v6_3 > v6_1);
// compare the same address with different scope_id
assert!(v6_3 < v6_4);
// compare the same address with different flowinfo
assert!(v6_3 < v6_5);
// compare with an inferred right-hand side // compare with an inferred right-hand side
assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap());
assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap());

View File

@ -1140,10 +1140,10 @@ pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
#[repr(transparent)] #[repr(transparent)]
pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>); pub struct IoSliceMut<'a>(sys::io::IoSliceMut<'a>);
#[stable(feature = "iovec-send-sync", since = "1.44.0")] #[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSliceMut<'a> {} unsafe impl<'a> Send for IoSliceMut<'a> {}
#[stable(feature = "iovec-send-sync", since = "1.44.0")] #[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSliceMut<'a> {} unsafe impl<'a> Sync for IoSliceMut<'a> {}
#[stable(feature = "iovec", since = "1.36.0")] #[stable(feature = "iovec", since = "1.36.0")]
@ -1283,10 +1283,10 @@ impl<'a> DerefMut for IoSliceMut<'a> {
#[repr(transparent)] #[repr(transparent)]
pub struct IoSlice<'a>(sys::io::IoSlice<'a>); pub struct IoSlice<'a>(sys::io::IoSlice<'a>);
#[stable(feature = "iovec-send-sync", since = "1.44.0")] #[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSlice<'a> {} unsafe impl<'a> Send for IoSlice<'a> {}
#[stable(feature = "iovec-send-sync", since = "1.44.0")] #[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSlice<'a> {} unsafe impl<'a> Sync for IoSlice<'a> {}
#[stable(feature = "iovec", since = "1.36.0")] #[stable(feature = "iovec", since = "1.36.0")]

View File

@ -415,7 +415,6 @@ cfg_if::cfg_if! {
} else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] { } else if #[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))] {
#[link(name = "System")] #[link(name = "System")]
#[link(name = "objc")] #[link(name = "objc")]
#[link(name = "Security", kind = "framework")]
#[link(name = "Foundation", kind = "framework")] #[link(name = "Foundation", kind = "framework")]
extern "C" {} extern "C" {}
} else if #[cfg(target_os = "fuchsia")] { } else if #[cfg(target_os = "fuchsia")] {

View File

@ -151,40 +151,65 @@ mod imp {
} }
} }
#[cfg(target_os = "macos")] #[cfg(target_vendor = "apple")]
mod imp { mod imp {
use crate::fs::File; use crate::io;
use crate::io::Read;
use crate::sys::os::errno;
use crate::sys::weak::weak;
use libc::{c_int, c_void, size_t}; use libc::{c_int, c_void, size_t};
fn getentropy_fill_bytes(v: &mut [u8]) -> bool { #[inline(always)]
weak!(fn getentropy(*mut c_void, size_t) -> c_int); fn random_failure() -> ! {
panic!("unexpected random generation error: {}", io::Error::last_os_error());
}
getentropy #[cfg(target_os = "macos")]
.get() fn getentropy_fill_bytes(v: &mut [u8]) {
.map(|f| { extern "C" {
// getentropy(2) permits a maximum buffer size of 256 bytes fn getentropy(bytes: *mut c_void, count: size_t) -> c_int;
for s in v.chunks_mut(256) { }
let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) };
if ret == -1 { // getentropy(2) permits a maximum buffer size of 256 bytes
panic!("unexpected getentropy error: {}", errno()); for s in v.chunks_mut(256) {
} let ret = unsafe { getentropy(s.as_mut_ptr().cast(), s.len()) };
} if ret == -1 {
true random_failure()
}) }
.unwrap_or(false) }
}
#[cfg(not(target_os = "macos"))]
fn ccrandom_fill_bytes(v: &mut [u8]) {
extern "C" {
fn CCRandomGenerateBytes(bytes: *mut c_void, count: size_t) -> c_int;
}
let ret = unsafe { CCRandomGenerateBytes(v.as_mut_ptr().cast(), v.len()) };
if ret == -1 {
random_failure()
}
} }
pub fn fill_bytes(v: &mut [u8]) { pub fn fill_bytes(v: &mut [u8]) {
if getentropy_fill_bytes(v) { // All supported versions of macOS (10.12+) support getentropy.
return; //
} // `getentropy` is measurably faster (via Divan) then the other alternatives so its preferred
// when usable.
#[cfg(target_os = "macos")]
getentropy_fill_bytes(v);
// for older macos which doesn't support getentropy // On Apple platforms, `CCRandomGenerateBytes` and `SecRandomCopyBytes` simply
let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); // call into `CCRandomCopyBytes` with `kCCRandomDefault`. `CCRandomCopyBytes`
file.read_exact(v).expect("failed to read /dev/urandom") // manages a CSPRNG which is seeded from the kernel's CSPRNG and which runs on
// its own thread accessed via GCD. This seems needlessly heavyweight for our purposes
// so we only use it on non-Mac OSes where the better entrypoints are blocked.
//
// `CCRandomGenerateBytes` is used instead of `SecRandomCopyBytes` because the former is accessible
// via `libSystem` (libc) while the other needs to link to `Security.framework`.
//
// Note that while `getentropy` has a available attribute in the macOS headers, the lack
// of a header in the iOS (and others) SDK means that its can cause app store rejections.
// Just use `CCRandomGenerateBytes` instead.
#[cfg(not(target_os = "macos"))]
ccrandom_fill_bytes(v);
} }
} }
@ -203,36 +228,6 @@ mod imp {
} }
} }
// On iOS and MacOS `SecRandomCopyBytes` calls `CCRandomCopyBytes` with
// `kCCRandomDefault`. `CCRandomCopyBytes` manages a CSPRNG which is seeded
// from `/dev/random` and which runs on its own thread accessed via GCD.
// This seems needlessly heavyweight for the purposes of generating two u64s
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "watchos"))]
mod imp {
use crate::io;
use crate::ptr;
use libc::{c_int, size_t};
enum SecRandom {}
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = ptr::null();
extern "C" {
fn SecRandomCopyBytes(rnd: *const SecRandom, count: size_t, bytes: *mut u8) -> c_int;
}
pub fn fill_bytes(v: &mut [u8]) {
let ret = unsafe { SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) };
if ret == -1 {
panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
}
}
}
// FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification. // FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
#[cfg(target_os = "netbsd")] #[cfg(target_os = "netbsd")]
mod imp { mod imp {

View File

@ -1,8 +1,6 @@
use crate::fmt; use crate::fmt;
use crate::time::Duration; use crate::time::Duration;
pub use self::inner::Instant;
const NSEC_PER_SEC: u64 = 1_000_000_000; const NSEC_PER_SEC: u64 = 1_000_000_000;
pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() }; pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
#[allow(dead_code)] // Used for pthread condvar timeouts #[allow(dead_code)] // Used for pthread condvar timeouts
@ -40,6 +38,10 @@ impl SystemTime {
SystemTime { t: Timespec::new(tv_sec, tv_nsec) } 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> { pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.t.sub_timespec(&other.t) self.t.sub_timespec(&other.t)
} }
@ -79,6 +81,36 @@ impl Timespec {
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } } Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }
} }
pub fn now(clock: libc::clockid_t) -> Timespec {
use crate::mem::MaybeUninit;
use crate::sys::cvt;
// Try to use 64-bit time in preparation for Y2038.
#[cfg(all(
target_os = "linux",
target_env = "gnu",
target_pointer_width = "32",
not(target_arch = "riscv32")
))]
{
use crate::sys::weak::weak;
// __clock_gettime64 was added to 32-bit arches in glibc 2.34,
// and it handles both vDSO calls and ENOSYS fallbacks itself.
weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int);
if let Some(clock_gettime64) = __clock_gettime64.get() {
let mut t = MaybeUninit::uninit();
cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
return Timespec::from(unsafe { t.assume_init() });
}
}
let mut t = MaybeUninit::uninit();
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
Timespec::from(unsafe { t.assume_init() })
}
pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other { if self >= other {
// NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
@ -216,209 +248,59 @@ impl From<__timespec64> for Timespec {
} }
} }
#[cfg(any( #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
all(target_os = "macos", any(not(target_arch = "aarch64"))), pub struct Instant {
target_os = "ios", t: Timespec,
target_os = "watchos", }
target_os = "tvos"
))]
mod inner {
use crate::sync::atomic::{AtomicU64, Ordering};
use crate::sys::cvt;
use crate::sys_common::mul_div_u64;
use crate::time::Duration;
use super::{SystemTime, Timespec, NSEC_PER_SEC}; impl Instant {
pub fn now() -> Instant {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] // https://www.manpagez.com/man/3/clock_gettime/
pub struct Instant {
t: u64,
}
#[repr(C)]
#[derive(Copy, Clone)]
struct mach_timebase_info {
numer: u32,
denom: u32,
}
type mach_timebase_info_t = *mut mach_timebase_info;
type kern_return_t = libc::c_int;
impl Instant {
pub fn now() -> Instant {
extern "C" {
fn mach_absolute_time() -> u64;
}
Instant { t: unsafe { mach_absolute_time() } }
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
let diff = self.t.checked_sub(other.t)?;
let info = info();
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
Some(Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32))
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_add(checked_dur2intervals(other)?)? })
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub(checked_dur2intervals(other)?)? })
}
}
impl SystemTime {
pub fn now() -> SystemTime {
use crate::ptr;
let mut s = libc::timeval { tv_sec: 0, tv_usec: 0 };
cvt(unsafe { libc::gettimeofday(&mut s, ptr::null_mut()) }).unwrap();
return SystemTime::from(s);
}
}
impl From<libc::timeval> for Timespec {
fn from(t: libc::timeval) -> Timespec {
Timespec::new(t.tv_sec as i64, 1000 * t.tv_usec as i64)
}
}
impl From<libc::timeval> for SystemTime {
fn from(t: libc::timeval) -> SystemTime {
SystemTime { t: Timespec::from(t) }
}
}
fn checked_dur2intervals(dur: &Duration) -> Option<u64> {
let nanos =
dur.as_secs().checked_mul(NSEC_PER_SEC)?.checked_add(dur.subsec_nanos() as u64)?;
let info = info();
Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
}
fn info() -> mach_timebase_info {
// INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do
// this in 64 bits because we know 0 is never a valid value for the
// `denom` field.
// //
// Encoding this as a single `AtomicU64` allows us to use `Relaxed` // CLOCK_UPTIME_RAW clock that increments monotonically, in the same man-
// operations, as we are only interested in the effects on a single // ner as CLOCK_MONOTONIC_RAW, but that does not incre-
// memory location. // ment while the system is asleep. The returned value
static INFO_BITS: AtomicU64 = AtomicU64::new(0); // is identical to the result of mach_absolute_time()
// after the appropriate mach_timebase conversion is
// If a previous thread has initialized `INFO_BITS`, use it. // applied.
let info_bits = INFO_BITS.load(Ordering::Relaxed); //
if info_bits != 0 { // Instant on macos was historically implemented using mach_absolute_time;
return info_from_bits(info_bits); // we preserve this value domain out of an abundance of caution.
} #[cfg(any(
target_os = "macos",
// ... otherwise learn for ourselves ... target_os = "ios",
extern "C" { target_os = "watchos",
fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; target_os = "tvos"
} ))]
const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
let mut info = info_from_bits(0); #[cfg(not(any(
unsafe { target_os = "macos",
mach_timebase_info(&mut info); target_os = "ios",
} target_os = "watchos",
INFO_BITS.store(info_to_bits(info), Ordering::Relaxed); target_os = "tvos"
info )))]
const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
Instant { t: Timespec::now(clock_id) }
} }
#[inline] pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
fn info_to_bits(info: mach_timebase_info) -> u64 { self.t.sub_timespec(&other.t).ok()
((info.denom as u64) << 32) | (info.numer as u64)
} }
#[inline] pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
fn info_from_bits(bits: u64) -> mach_timebase_info { Some(Instant { t: self.t.checked_add_duration(other)? })
mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 } }
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant { t: self.t.checked_sub_duration(other)? })
} }
} }
#[cfg(not(any( impl fmt::Debug for Instant {
all(target_os = "macos", any(not(target_arch = "aarch64"))), fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
target_os = "ios", f.debug_struct("Instant")
target_os = "watchos", .field("tv_sec", &self.t.tv_sec)
target_os = "tvos" .field("tv_nsec", &self.t.tv_nsec.0)
)))] .finish()
mod inner {
use crate::fmt;
use crate::mem::MaybeUninit;
use crate::sys::cvt;
use crate::time::Duration;
use super::{SystemTime, Timespec};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant {
t: Timespec,
}
impl Instant {
pub fn now() -> Instant {
#[cfg(target_os = "macos")]
const clock_id: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
#[cfg(not(target_os = "macos"))]
const clock_id: libc::clockid_t = libc::CLOCK_MONOTONIC;
Instant { t: Timespec::now(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)? })
}
}
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.0)
.finish()
}
}
impl SystemTime {
pub fn now() -> SystemTime {
SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
}
}
impl Timespec {
pub fn now(clock: libc::clockid_t) -> Timespec {
// Try to use 64-bit time in preparation for Y2038.
#[cfg(all(
target_os = "linux",
target_env = "gnu",
target_pointer_width = "32",
not(target_arch = "riscv32")
))]
{
use crate::sys::weak::weak;
// __clock_gettime64 was added to 32-bit arches in glibc 2.34,
// and it handles both vDSO calls and ENOSYS fallbacks itself.
weak!(fn __clock_gettime64(libc::clockid_t, *mut super::__timespec64) -> libc::c_int);
if let Some(clock_gettime64) = __clock_gettime64.get() {
let mut t = MaybeUninit::uninit();
cvt(unsafe { clock_gettime64(clock, t.as_mut_ptr()) }).unwrap();
return Timespec::from(unsafe { t.assume_init() });
}
}
let mut t = MaybeUninit::uninit();
cvt(unsafe { libc::clock_gettime(clock, t.as_mut_ptr()) }).unwrap();
Timespec::from(unsafe { t.assume_init() })
}
} }
} }

View File

@ -2505,9 +2505,12 @@ Windows.Win32.System.Threading.CREATE_SEPARATE_WOW_VDM
Windows.Win32.System.Threading.CREATE_SHARED_WOW_VDM Windows.Win32.System.Threading.CREATE_SHARED_WOW_VDM
Windows.Win32.System.Threading.CREATE_SUSPENDED Windows.Win32.System.Threading.CREATE_SUSPENDED
Windows.Win32.System.Threading.CREATE_UNICODE_ENVIRONMENT Windows.Win32.System.Threading.CREATE_UNICODE_ENVIRONMENT
Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
Windows.Win32.System.Threading.CREATE_WAITABLE_TIMER_MANUAL_RESET
Windows.Win32.System.Threading.CreateEventW Windows.Win32.System.Threading.CreateEventW
Windows.Win32.System.Threading.CreateProcessW Windows.Win32.System.Threading.CreateProcessW
Windows.Win32.System.Threading.CreateThread Windows.Win32.System.Threading.CreateThread
Windows.Win32.System.Threading.CreateWaitableTimerExW
Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
Windows.Win32.System.Threading.DEBUG_PROCESS Windows.Win32.System.Threading.DEBUG_PROCESS
Windows.Win32.System.Threading.DeleteProcThreadAttributeList Windows.Win32.System.Threading.DeleteProcThreadAttributeList
@ -2544,6 +2547,7 @@ Windows.Win32.System.Threading.REALTIME_PRIORITY_CLASS
Windows.Win32.System.Threading.ReleaseSRWLockExclusive Windows.Win32.System.Threading.ReleaseSRWLockExclusive
Windows.Win32.System.Threading.ReleaseSRWLockShared Windows.Win32.System.Threading.ReleaseSRWLockShared
Windows.Win32.System.Threading.SetThreadStackGuarantee Windows.Win32.System.Threading.SetThreadStackGuarantee
Windows.Win32.System.Threading.SetWaitableTimer
Windows.Win32.System.Threading.Sleep Windows.Win32.System.Threading.Sleep
Windows.Win32.System.Threading.SleepConditionVariableSRW Windows.Win32.System.Threading.SleepConditionVariableSRW
Windows.Win32.System.Threading.SleepEx Windows.Win32.System.Threading.SleepEx
@ -2570,6 +2574,8 @@ Windows.Win32.System.Threading.TerminateProcess
Windows.Win32.System.Threading.THREAD_CREATE_RUN_IMMEDIATELY Windows.Win32.System.Threading.THREAD_CREATE_RUN_IMMEDIATELY
Windows.Win32.System.Threading.THREAD_CREATE_SUSPENDED Windows.Win32.System.Threading.THREAD_CREATE_SUSPENDED
Windows.Win32.System.Threading.THREAD_CREATION_FLAGS Windows.Win32.System.Threading.THREAD_CREATION_FLAGS
Windows.Win32.System.Threading.TIMER_ALL_ACCESS
Windows.Win32.System.Threading.TIMER_MODIFY_STATE
Windows.Win32.System.Threading.TLS_OUT_OF_INDEXES Windows.Win32.System.Threading.TLS_OUT_OF_INDEXES
Windows.Win32.System.Threading.TlsAlloc Windows.Win32.System.Threading.TlsAlloc
Windows.Win32.System.Threading.TlsFree Windows.Win32.System.Threading.TlsFree

View File

@ -151,6 +151,15 @@ extern "system" {
) -> HANDLE; ) -> HANDLE;
} }
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" {
pub fn CreateWaitableTimerExW(
lptimerattributes: *const SECURITY_ATTRIBUTES,
lptimername: PCWSTR,
dwflags: u32,
dwdesiredaccess: u32,
) -> HANDLE;
}
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL; pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
} }
@ -508,6 +517,17 @@ extern "system" {
pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL; pub fn SetThreadStackGuarantee(stacksizeinbytes: *mut u32) -> BOOL;
} }
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" {
pub fn SetWaitableTimer(
htimer: HANDLE,
lpduetime: *const i64,
lperiod: i32,
pfncompletionroutine: PTIMERAPCROUTINE,
lpargtocompletionroutine: *const ::core::ffi::c_void,
fresume: BOOL,
) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn Sleep(dwmilliseconds: u32) -> (); pub fn Sleep(dwmilliseconds: u32) -> ();
} }
@ -1165,6 +1185,8 @@ pub const CREATE_SEPARATE_WOW_VDM: PROCESS_CREATION_FLAGS = 2048u32;
pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32; pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32;
pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32; pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32; pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
pub const CREATE_WAITABLE_TIMER_HIGH_RESOLUTION: u32 = 2u32;
pub const CREATE_WAITABLE_TIMER_MANUAL_RESET: u32 = 1u32;
pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32; pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32; pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32; pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
@ -3775,6 +3797,13 @@ pub const PROFILE_SERVER: PROCESS_CREATION_FLAGS = 1073741824u32;
pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32; pub const PROFILE_USER: PROCESS_CREATION_FLAGS = 268435456u32;
pub const PROGRESS_CONTINUE: u32 = 0u32; pub const PROGRESS_CONTINUE: u32 = 0u32;
pub type PSTR = *mut u8; pub type PSTR = *mut u8;
pub type PTIMERAPCROUTINE = ::core::option::Option<
unsafe extern "system" fn(
lpargtocompletionroutine: *const ::core::ffi::c_void,
dwtimerlowvalue: u32,
dwtimerhighvalue: u32,
) -> (),
>;
pub type PWSTR = *mut u16; pub type PWSTR = *mut u16;
pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32; pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32; pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
@ -3922,6 +3951,7 @@ pub type SYMBOLIC_LINK_FLAGS = u32;
pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: SYMBOLIC_LINK_FLAGS = 2u32; pub const SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: SYMBOLIC_LINK_FLAGS = 2u32;
pub const SYMBOLIC_LINK_FLAG_DIRECTORY: SYMBOLIC_LINK_FLAGS = 1u32; pub const SYMBOLIC_LINK_FLAG_DIRECTORY: SYMBOLIC_LINK_FLAGS = 1u32;
pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32; pub const SYMLINK_FLAG_RELATIVE: u32 = 1u32;
pub type SYNCHRONIZATION_ACCESS_RIGHTS = u32;
pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32; pub const SYNCHRONIZE: FILE_ACCESS_RIGHTS = 1048576u32;
#[repr(C)] #[repr(C)]
pub struct SYSTEM_INFO { pub struct SYSTEM_INFO {
@ -3968,6 +3998,8 @@ pub const TCP_NODELAY: i32 = 1i32;
pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32; pub const THREAD_CREATE_RUN_IMMEDIATELY: THREAD_CREATION_FLAGS = 0u32;
pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32; pub const THREAD_CREATE_SUSPENDED: THREAD_CREATION_FLAGS = 4u32;
pub type THREAD_CREATION_FLAGS = u32; pub type THREAD_CREATION_FLAGS = u32;
pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32;
pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
#[repr(C)] #[repr(C)]
pub struct TIMEVAL { pub struct TIMEVAL {
pub tv_sec: i32, pub tv_sec: i32,

View File

@ -12,6 +12,7 @@ use crate::time::Duration;
use core::ffi::c_void; use core::ffi::c_void;
use super::time::WaitableTimer;
use super::to_u16s; use super::to_u16s;
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@ -87,7 +88,17 @@ impl Thread {
} }
pub fn sleep(dur: Duration) { pub fn sleep(dur: Duration) {
unsafe { c::Sleep(super::dur2timeout(dur)) } fn high_precision_sleep(dur: Duration) -> Result<(), ()> {
let timer = WaitableTimer::high_resolution()?;
timer.set(dur)?;
timer.wait()
}
// Attempt to use high-precision sleep (Windows 10, version 1803+).
// On error fallback to the standard `Sleep` function.
// Also preserves the zero duration behaviour of `Sleep`.
if dur.is_zero() || high_precision_sleep(dur).is_err() {
unsafe { c::Sleep(super::dur2timeout(dur)) }
}
} }
pub fn handle(&self) -> &Handle { pub fn handle(&self) -> &Handle {

View File

@ -1,11 +1,13 @@
use crate::cmp::Ordering; use crate::cmp::Ordering;
use crate::fmt; use crate::fmt;
use crate::mem; use crate::mem;
use crate::ptr::{null, null_mut};
use crate::sys::c; use crate::sys::c;
use crate::sys_common::IntoInner; use crate::sys_common::IntoInner;
use crate::time::Duration; use crate::time::Duration;
use core::hash::{Hash, Hasher}; use core::hash::{Hash, Hasher};
use core::ops::Neg;
const NANOS_PER_SEC: u64 = 1_000_000_000; const NANOS_PER_SEC: u64 = 1_000_000_000;
const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100; const INTERVALS_PER_SEC: u64 = NANOS_PER_SEC / 100;
@ -222,3 +224,39 @@ mod perf_counter {
qpc_value qpc_value
} }
} }
/// A timer you can wait on.
pub(super) struct WaitableTimer {
handle: c::HANDLE,
}
impl WaitableTimer {
/// Create a high-resolution timer. Will fail before Windows 10, version 1803.
pub fn high_resolution() -> Result<Self, ()> {
let handle = unsafe {
c::CreateWaitableTimerExW(
null(),
null(),
c::CREATE_WAITABLE_TIMER_HIGH_RESOLUTION,
c::TIMER_ALL_ACCESS,
)
};
if handle != null_mut() { 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.
// Therefore we negate the relative duration.
let time = checked_dur2intervals(&duration).ok_or(())?.neg();
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) };
}
}

View File

@ -111,7 +111,7 @@ pub use core::time::TryFromFloatSecsError;
/// |-----------|----------------------------------------------------------------------| /// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Monotonic Clock)] | /// | UNIX | [clock_gettime (Monotonic Clock)] |
/// | Darwin | [mach_absolute_time] | /// | Darwin | [clock_gettime (Monotonic Clock)] |
/// | VXWorks | [clock_gettime (Monotonic Clock)] | /// | VXWorks | [clock_gettime (Monotonic Clock)] |
/// | SOLID | `get_tim` | /// | SOLID | `get_tim` |
/// | WASI | [__wasi_clock_time_get (Monotonic Clock)] | /// | WASI | [__wasi_clock_time_get (Monotonic Clock)] |
@ -123,7 +123,6 @@ pub use core::time::TryFromFloatSecsError;
/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
/// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get /// [__wasi_clock_time_get (Monotonic Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
/// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime /// [clock_gettime (Monotonic Clock)]: https://linux.die.net/man/3/clock_gettime
/// [mach_absolute_time]: https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/KernelProgramming/services/services.html
/// ///
/// **Disclaimer:** These system calls might change over time. /// **Disclaimer:** These system calls might change over time.
/// ///
@ -224,7 +223,7 @@ pub struct Instant(time::Instant);
/// |-----------|----------------------------------------------------------------------| /// |-----------|----------------------------------------------------------------------|
/// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] |
/// | UNIX | [clock_gettime (Realtime Clock)] | /// | UNIX | [clock_gettime (Realtime Clock)] |
/// | Darwin | [gettimeofday] | /// | Darwin | [clock_gettime (Realtime Clock)] |
/// | VXWorks | [clock_gettime (Realtime Clock)] | /// | VXWorks | [clock_gettime (Realtime Clock)] |
/// | SOLID | `SOLID_RTC_ReadTime` | /// | SOLID | `SOLID_RTC_ReadTime` |
/// | WASI | [__wasi_clock_time_get (Realtime Clock)] | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] |
@ -233,7 +232,6 @@ pub struct Instant(time::Instant);
/// [currently]: crate::io#platform-specific-behavior /// [currently]: crate::io#platform-specific-behavior
/// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time
/// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode /// [timekeeping in SGX]: https://edp.fortanix.com/docs/concepts/rust-std/#codestdtimecode
/// [gettimeofday]: https://man7.org/linux/man-pages/man2/gettimeofday.2.html
/// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime
/// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#clock_time_get
/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime /// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime

View File

@ -103,7 +103,6 @@ class GenerateAndParseConfig(unittest.TestCase):
"""Test that we can serialize and deserialize a config.toml file""" """Test that we can serialize and deserialize a config.toml file"""
def test_no_args(self): def test_no_args(self):
build = serialize_and_parse([]) build = serialize_and_parse([])
self.assertEqual(build.get_toml("change-id"), '116998')
self.assertEqual(build.get_toml("profile"), 'dist') self.assertEqual(build.get_toml("profile"), 'dist')
self.assertIsNone(build.get_toml("llvm.download-ci-llvm")) self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))

@ -1 +1 @@
Subproject commit 72187f5cd0beaaa9c6f584156bcd88f921871e83 Subproject commit 3dca2fc50b922a8efb94903b9fee8bb42ab48f38

@ -1 +1 @@
Subproject commit eac173690b8cc99094e1d88bd49dd61127fbd285 Subproject commit 22bca3d0f6e9b9b556689b54ce96f25b46ecd1b3

@ -1 +1 @@
Subproject commit ddfa4214487686e91b21aa29afb972c08a8f0d5b Subproject commit 1842257814919fa62e81bdecd5e8f95be2839dbb

@ -1 +1 @@
Subproject commit 142b2ed77d33f37a9973772bd95e6144ed9dce43 Subproject commit 16fd3c06d9e558dae2d52000818274ae70c9e90a

@ -1 +1 @@
Subproject commit 8eb3a01ab74c567b7174784892fb807f2c632d6b Subproject commit 6709beeb7d0fbc5ffc91ac4893a24434123b9bfa

@ -1 +1 @@
Subproject commit b98af7d661e4744baab81fb8dc7a049e44a4a998 Subproject commit b0ee9ec8fa59a6c7620165e061f4747202377a62

View File

@ -123,7 +123,7 @@ rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \
fn do_embedded() {} // and because names exhaustiveness was not disabled fn do_embedded() {} // and because names exhaustiveness was not disabled
#[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg() #[cfg(has_feathers)] // This is expected as "has_feathers" was provided in cfg()
fn do_features() {} // and because names exhaustiveness was not disbaled fn do_features() {} // and because names exhaustiveness was not disabled
#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg() #[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in cfg()
// and because no value checking was enable for "has_feathers" // and because no value checking was enable for "has_feathers"

View File

@ -1,8 +1,8 @@
// This file provides a const function that is unstably const forever. // This file provides a const function that is unstably const forever.
#![feature(staged_api)] #![feature(staged_api)]
#![stable(feature = "1", since = "1.0.0")] #![stable(feature = "clippytest", since = "1.0.0")]
#[stable(feature = "1", since = "1.0.0")] #[stable(feature = "clippytest", since = "1.0.0")]
#[rustc_const_unstable(feature = "foo", issue = "none")] #[rustc_const_unstable(feature = "foo", issue = "none")]
pub const fn unstably_const_fn() {} pub const fn unstably_const_fn() {}

View File

@ -272,6 +272,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
this.Sleep(timeout)?; this.Sleep(timeout)?;
} }
"CreateWaitableTimerExW" => {
let [attributes, name, flags, access] =
this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
this.read_pointer(attributes)?;
this.read_pointer(name)?;
this.read_scalar(flags)?.to_u32()?;
this.read_scalar(access)?.to_u32()?;
// Unimplemented. Always return failure.
let not_supported = this.eval_windows("c", "ERROR_NOT_SUPPORTED");
this.set_last_error(not_supported)?;
this.write_null(dest)?;
}
// Synchronization primitives // Synchronization primitives
"AcquireSRWLockExclusive" => { "AcquireSRWLockExclusive" => {

View File

@ -41,7 +41,8 @@
+ debug ((f: (bool, bool, u32)).2: u32) => const 123_u32; + debug ((f: (bool, bool, u32)).2: u32) => const 123_u32;
let _10: std::option::Option<u16>; let _10: std::option::Option<u16>;
scope 7 { scope 7 {
debug o => _10; - debug o => _10;
+ debug o => const Option::<u16>::Some(99_u16);
let _17: u32; let _17: u32;
let _18: u32; let _18: u32;
scope 8 { scope 8 {
@ -81,7 +82,7 @@
_15 = const false; _15 = const false;
_16 = const 123_u32; _16 = const 123_u32;
StorageLive(_10); StorageLive(_10);
_10 = Option::<u16>::Some(const 99_u16); _10 = const Option::<u16>::Some(99_u16);
_17 = const 32_u32; _17 = const 32_u32;
_18 = const 32_u32; _18 = const 32_u32;
StorageLive(_11); StorageLive(_11);
@ -97,3 +98,7 @@
} }
} }
ALLOC0 (size: 4, align: 2) {
01 00 63 00 │ ..c.
}

Some files were not shown because too many files have changed in this diff Show More