mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 11:07:42 +00:00
Auto merge of #130133 - workingjubilee:rollup-t5o827k, r=workingjubilee
Rollup of 14 pull requests Successful merges: - #119229 (Update mingw-w64 + GNU toolchain) - #128345 (added support for GNU/Hurd on x86_64) - #128667 (rustdoc: normalise type/field names) - #129876 (Use sysroot crates maximally in `rustc_codegen_gcc`.) - #130034 ( Fix enabling wasm-component-ld to match other tools ) - #130048 (run-make-support: Add llvm-pdbutil) - #130068 (Test codegen when setting deployment target) - #130070 (Rename variant `AddrOfRegion` of `RegionVariableOrigin` to `BorrowRegion`) - #130087 (remove 'const' from 'Option::iter') - #130090 (make Result::copied unstably const) - #130092 (Fixes typo in wasm32-wasip2 doc comment) - #130107 (const: make ptr.is_null() stop execution on ambiguity) - #130115 (Remove needless returns detected by clippy in libraries) - #130130 (Miri subtree update) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1f44f0a66f
@ -11,63 +11,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "1.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bitflags"
|
|
||||||
version = "2.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "boml"
|
name = "boml"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5"
|
checksum = "85fdb93f04c73bff54305fa437ffea5449c41edcaadfe882f35836206b166ac5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.79"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
|
||||||
dependencies = [
|
|
||||||
"errno-dragonfly",
|
|
||||||
"libc",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "errno-dragonfly"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fastrand"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fm"
|
name = "fm"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@ -132,12 +81,6 @@ version = "0.2.150"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "linux-raw-sys"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -154,24 +97,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "object"
|
|
||||||
version = "0.30.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.3.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 1.3.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.8.4"
|
version = "1.8.4"
|
||||||
@ -196,22 +121,6 @@ dependencies = [
|
|||||||
"boml",
|
"boml",
|
||||||
"gccjit",
|
"gccjit",
|
||||||
"lang_tester",
|
"lang_tester",
|
||||||
"object",
|
|
||||||
"smallvec",
|
|
||||||
"tempfile",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustix"
|
|
||||||
version = "0.38.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.4.0",
|
|
||||||
"errno",
|
|
||||||
"libc",
|
|
||||||
"linux-raw-sys",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -223,25 +132,6 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "smallvec"
|
|
||||||
version = "1.10.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tempfile"
|
|
||||||
version = "3.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"fastrand",
|
|
||||||
"redox_syscall",
|
|
||||||
"rustix",
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -315,69 +205,3 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.48.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
|
||||||
|
@ -23,21 +23,11 @@ default = ["master"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gccjit = "2.1"
|
gccjit = "2.1"
|
||||||
|
|
||||||
# Local copy.
|
# Local copy.
|
||||||
#gccjit = { path = "../gccjit.rs" }
|
#gccjit = { path = "../gccjit.rs" }
|
||||||
|
|
||||||
object = { version = "0.30.1", default-features = false, features = [
|
|
||||||
"std",
|
|
||||||
"read",
|
|
||||||
] }
|
|
||||||
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
|
|
||||||
# TODO(antoyo): make tempfile optional.
|
|
||||||
tempfile = "3.7.1"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lang_tester = "0.8.0"
|
lang_tester = "0.8.0"
|
||||||
tempfile = "3.1.0"
|
|
||||||
boml = "0.3.1"
|
boml = "0.3.1"
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
|
@ -24,6 +24,14 @@
|
|||||||
#![deny(clippy::pattern_type_mismatch)]
|
#![deny(clippy::pattern_type_mismatch)]
|
||||||
#![allow(clippy::needless_lifetimes)]
|
#![allow(clippy::needless_lifetimes)]
|
||||||
|
|
||||||
|
// Some "regular" crates we want to share with rustc
|
||||||
|
extern crate object;
|
||||||
|
extern crate smallvec;
|
||||||
|
extern crate tempfile;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
|
// The rustc crates we need
|
||||||
extern crate rustc_apfloat;
|
extern crate rustc_apfloat;
|
||||||
extern crate rustc_ast;
|
extern crate rustc_ast;
|
||||||
extern crate rustc_attr;
|
extern crate rustc_attr;
|
||||||
@ -42,8 +50,6 @@ extern crate rustc_middle;
|
|||||||
extern crate rustc_session;
|
extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
extern crate rustc_target;
|
extern crate rustc_target;
|
||||||
#[macro_use]
|
|
||||||
extern crate tracing;
|
|
||||||
|
|
||||||
// This prevents duplicating functions and statics that are already part of the host rustc process.
|
// This prevents duplicating functions and statics that are already part of the host rustc process.
|
||||||
#[allow(unused_extern_crates)]
|
#[allow(unused_extern_crates)]
|
||||||
|
@ -447,7 +447,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// this time with enough precision to check that the value
|
// this time with enough precision to check that the value
|
||||||
// whose address was taken can actually be made to live as long
|
// whose address was taken can actually be made to live as long
|
||||||
// as it needs to live.
|
// as it needs to live.
|
||||||
let region = self.next_region_var(infer::AddrOfRegion(expr.span));
|
let region = self.next_region_var(infer::BorrowRegion(expr.span));
|
||||||
Ty::new_ref(self.tcx, region, ty, mutbl)
|
Ty::new_ref(self.tcx, region, ty, mutbl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,8 +458,8 @@ pub enum RegionVariableOrigin {
|
|||||||
PatternRegion(Span),
|
PatternRegion(Span),
|
||||||
|
|
||||||
/// Regions created by `&` operator.
|
/// Regions created by `&` operator.
|
||||||
///
|
BorrowRegion(Span),
|
||||||
AddrOfRegion(Span),
|
|
||||||
/// Regions created as part of an autoref of a method receiver.
|
/// Regions created as part of an autoref of a method receiver.
|
||||||
Autoref(Span),
|
Autoref(Span),
|
||||||
|
|
||||||
@ -1741,7 +1741,7 @@ impl RegionVariableOrigin {
|
|||||||
match *self {
|
match *self {
|
||||||
MiscVariable(a)
|
MiscVariable(a)
|
||||||
| PatternRegion(a)
|
| PatternRegion(a)
|
||||||
| AddrOfRegion(a)
|
| BorrowRegion(a)
|
||||||
| Autoref(a)
|
| Autoref(a)
|
||||||
| Coercion(a)
|
| Coercion(a)
|
||||||
| RegionParameterDefinition(a, ..)
|
| RegionParameterDefinition(a, ..)
|
||||||
|
@ -1645,6 +1645,7 @@ supported_targets! {
|
|||||||
("x86_64-unknown-haiku", x86_64_unknown_haiku),
|
("x86_64-unknown-haiku", x86_64_unknown_haiku),
|
||||||
|
|
||||||
("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu),
|
("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu),
|
||||||
|
("x86_64-unknown-hurd-gnu", x86_64_unknown_hurd_gnu),
|
||||||
|
|
||||||
("aarch64-apple-darwin", aarch64_apple_darwin),
|
("aarch64-apple-darwin", aarch64_apple_darwin),
|
||||||
("arm64e-apple-darwin", arm64e_apple_darwin),
|
("arm64e-apple-darwin", arm64e_apple_darwin),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! The `wasm32-wasip2` target is the next evolution of the
|
//! The `wasm32-wasip2` target is the next evolution of the
|
||||||
//! wasm32-wasi target. While the wasi specification is still under
|
//! wasm32-wasi target. While the wasi specification is still under
|
||||||
//! active development, the {review 2 iteration is considered an "island
|
//! active development, the preview 2 iteration is considered an "island
|
||||||
//! of stability" that should allow users to rely on it indefinitely.
|
//! of stability" that should allow users to rely on it indefinitely.
|
||||||
//!
|
//!
|
||||||
//! The `wasi` target is a proposal to define a standardized set of WebAssembly
|
//! The `wasi` target is a proposal to define a standardized set of WebAssembly
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target};
|
||||||
|
|
||||||
|
pub(crate) fn target() -> Target {
|
||||||
|
let mut base = base::hurd_gnu::opts();
|
||||||
|
base.cpu = "x86-64".into();
|
||||||
|
base.plt_by_default = false;
|
||||||
|
base.max_atomic_width = Some(64);
|
||||||
|
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||||
|
base.stack_probes = StackProbeType::Inline;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
|
Target {
|
||||||
|
llvm_target: "x86_64-unknown-hurd-gnu".into(),
|
||||||
|
metadata: crate::spec::TargetMetadata {
|
||||||
|
description: Some("64-bit GNU/Hurd".into()),
|
||||||
|
tier: Some(3),
|
||||||
|
host_tools: Some(true),
|
||||||
|
std: Some(true),
|
||||||
|
},
|
||||||
|
pointer_width: 64,
|
||||||
|
data_layout:
|
||||||
|
"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
|
||||||
|
arch: "x86_64".into(),
|
||||||
|
options: base,
|
||||||
|
}
|
||||||
|
}
|
@ -1018,7 +1018,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
let var_description = match var_origin {
|
let var_description = match var_origin {
|
||||||
infer::MiscVariable(_) => String::new(),
|
infer::MiscVariable(_) => String::new(),
|
||||||
infer::PatternRegion(_) => " for pattern".to_string(),
|
infer::PatternRegion(_) => " for pattern".to_string(),
|
||||||
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
|
infer::BorrowRegion(_) => " for borrow expression".to_string(),
|
||||||
infer::Autoref(_) => " for autoref".to_string(),
|
infer::Autoref(_) => " for autoref".to_string(),
|
||||||
infer::Coercion(_) => " for automatic coercion".to_string(),
|
infer::Coercion(_) => " for automatic coercion".to_string(),
|
||||||
infer::BoundRegion(_, br, infer::FnCall) => {
|
infer::BoundRegion(_, br, infer::FnCall) => {
|
||||||
|
@ -73,7 +73,7 @@ impl<'a, T> Iterator for Iter<'a, T> {
|
|||||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||||
let remaining = self.i1.advance_by(n);
|
let remaining = self.i1.advance_by(n);
|
||||||
match remaining {
|
match remaining {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(n) => {
|
Err(n) => {
|
||||||
mem::swap(&mut self.i1, &mut self.i2);
|
mem::swap(&mut self.i1, &mut self.i2);
|
||||||
self.i1.advance_by(n.get())
|
self.i1.advance_by(n.get())
|
||||||
@ -144,7 +144,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
|
|||||||
|
|
||||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||||
match self.i2.advance_back_by(n) {
|
match self.i2.advance_back_by(n) {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(n) => {
|
Err(n) => {
|
||||||
mem::swap(&mut self.i1, &mut self.i2);
|
mem::swap(&mut self.i1, &mut self.i2);
|
||||||
self.i2.advance_back_by(n.get())
|
self.i2.advance_back_by(n.get())
|
||||||
|
@ -64,7 +64,7 @@ impl<'a, T> Iterator for IterMut<'a, T> {
|
|||||||
|
|
||||||
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||||
match self.i1.advance_by(n) {
|
match self.i1.advance_by(n) {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(remaining) => {
|
Err(remaining) => {
|
||||||
mem::swap(&mut self.i1, &mut self.i2);
|
mem::swap(&mut self.i1, &mut self.i2);
|
||||||
self.i1.advance_by(remaining.get())
|
self.i1.advance_by(remaining.get())
|
||||||
@ -135,7 +135,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
|
|||||||
|
|
||||||
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
|
||||||
match self.i2.advance_back_by(n) {
|
match self.i2.advance_back_by(n) {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(remaining) => {
|
Err(remaining) => {
|
||||||
mem::swap(&mut self.i1, &mut self.i2);
|
mem::swap(&mut self.i1, &mut self.i2);
|
||||||
self.i2.advance_back_by(remaining.get())
|
self.i2.advance_back_by(remaining.get())
|
||||||
|
@ -208,7 +208,7 @@ const fn needs_realloc<SRC, DEST>(src_cap: usize, dst_cap: usize) -> bool {
|
|||||||
|
|
||||||
// type layouts don't guarantee a fit, so do a runtime check to see if
|
// type layouts don't guarantee a fit, so do a runtime check to see if
|
||||||
// the allocations happen to match
|
// the allocations happen to match
|
||||||
return src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>();
|
src_cap > 0 && src_cap * mem::size_of::<SRC>() != dst_cap * mem::size_of::<DEST>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This provides a shorthand for the source type since local type aliases aren't a thing.
|
/// This provides a shorthand for the source type since local type aliases aren't a thing.
|
||||||
|
@ -288,11 +288,11 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
|
|
||||||
// Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
|
// Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
|
||||||
// the array.
|
// the array.
|
||||||
return unsafe {
|
unsafe {
|
||||||
ptr::copy_nonoverlapping(self.ptr.as_ptr(), raw_ary.as_mut_ptr() as *mut T, N);
|
ptr::copy_nonoverlapping(self.ptr.as_ptr(), raw_ary.as_mut_ptr() as *mut T, N);
|
||||||
self.ptr = self.ptr.add(N);
|
self.ptr = self.ptr.add(N);
|
||||||
Ok(raw_ary.transpose().assume_init())
|
Ok(raw_ary.transpose().assume_init())
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
|
fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
|
||||||
|
@ -1338,9 +1338,8 @@ impl<T> Option<T> {
|
|||||||
/// assert_eq!(x.iter().next(), None);
|
/// assert_eq!(x.iter().next(), None);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub const fn iter(&self) -> Iter<'_, T> {
|
pub fn iter(&self) -> Iter<'_, T> {
|
||||||
Iter { inner: Item { opt: self.as_ref() } }
|
Iter { inner: Item { opt: self.as_ref() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1894,7 +1893,7 @@ impl<T> Option<&T> {
|
|||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
{
|
{
|
||||||
// FIXME: this implementation, which sidesteps using `Option::map` since it's not const
|
// FIXME(const-hack): this implementation, which sidesteps using `Option::map` since it's not const
|
||||||
// ready yet, should be reverted when possible to avoid code repetition
|
// ready yet, should be reverted when possible to avoid code repetition
|
||||||
match self {
|
match self {
|
||||||
Some(&v) => Some(v),
|
Some(&v) => Some(v),
|
||||||
@ -1942,7 +1941,7 @@ impl<T> Option<&mut T> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[must_use = "`self` will be dropped if the result is not used"]
|
#[must_use = "`self` will be dropped if the result is not used"]
|
||||||
#[stable(feature = "copied", since = "1.35.0")]
|
#[stable(feature = "copied", since = "1.35.0")]
|
||||||
#[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
|
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
|
||||||
pub const fn copied(self) -> Option<T>
|
pub const fn copied(self) -> Option<T>
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
|
@ -40,15 +40,17 @@ impl<T: ?Sized> *const T {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn const_impl(ptr: *const u8) -> bool {
|
const fn const_impl(ptr: *const u8) -> bool {
|
||||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
|
||||||
// considering their "data" part for null-ness.
|
|
||||||
match (ptr).guaranteed_eq(null_mut()) {
|
match (ptr).guaranteed_eq(null_mut()) {
|
||||||
None => false,
|
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
|
// To remain maximally convervative, we stop execution when we don't
|
||||||
|
// know whether the pointer is null or not.
|
||||||
|
// We can *not* return `false` here, that would be unsound in `NonNull::new`!
|
||||||
|
None => panic!("null-ness of this pointer cannot be determined in const context"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_unsafe)]
|
// Compare via a cast to a thin pointer, so fat pointers are only
|
||||||
|
// considering their "data" part for null-ness.
|
||||||
const_eval_select((self as *const u8,), const_impl, runtime_impl)
|
const_eval_select((self as *const u8,), const_impl, runtime_impl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,14 +187,14 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
|
|||||||
// Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
|
// Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the
|
||||||
// `Send` part!
|
// `Send` part!
|
||||||
// SAFETY: DynMetadata always contains a valid vtable pointer
|
// SAFETY: DynMetadata always contains a valid vtable pointer
|
||||||
return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) };
|
unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the alignment of the type associated with this vtable.
|
/// Returns the alignment of the type associated with this vtable.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn align_of(self) -> usize {
|
pub fn align_of(self) -> usize {
|
||||||
// SAFETY: DynMetadata always contains a valid vtable pointer
|
// SAFETY: DynMetadata always contains a valid vtable pointer
|
||||||
return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) };
|
unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the size and alignment together as a `Layout`
|
/// Returns the size and alignment together as a `Layout`
|
||||||
|
@ -33,22 +33,7 @@ impl<T: ?Sized> *mut T {
|
|||||||
#[rustc_diagnostic_item = "ptr_is_null"]
|
#[rustc_diagnostic_item = "ptr_is_null"]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn is_null(self) -> bool {
|
pub const fn is_null(self) -> bool {
|
||||||
#[inline]
|
self.cast_const().is_null()
|
||||||
fn runtime_impl(ptr: *mut u8) -> bool {
|
|
||||||
ptr.addr() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
const fn const_impl(ptr: *mut u8) -> bool {
|
|
||||||
// Compare via a cast to a thin pointer, so fat pointers are only
|
|
||||||
// considering their "data" part for null-ness.
|
|
||||||
match (ptr).guaranteed_eq(null_mut()) {
|
|
||||||
None => false,
|
|
||||||
Some(res) => res,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const_eval_select((self as *mut u8,), const_impl, runtime_impl)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts to a pointer of another type.
|
/// Casts to a pointer of another type.
|
||||||
|
@ -1535,11 +1535,17 @@ impl<T, E> Result<&T, E> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "result_copied", since = "1.59.0")]
|
#[stable(feature = "result_copied", since = "1.59.0")]
|
||||||
pub fn copied(self) -> Result<T, E>
|
#[rustc_const_unstable(feature = "const_result", issue = "82814")]
|
||||||
|
pub const fn copied(self) -> Result<T, E>
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
{
|
{
|
||||||
self.map(|&t| t)
|
// FIXME(const-hack): this implementation, which sidesteps using `Result::map` since it's not const
|
||||||
|
// ready yet, should be reverted when possible to avoid code repetition
|
||||||
|
match self {
|
||||||
|
Ok(&v) => Ok(v),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the
|
/// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the
|
||||||
@ -1579,11 +1585,17 @@ impl<T, E> Result<&mut T, E> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "result_copied", since = "1.59.0")]
|
#[stable(feature = "result_copied", since = "1.59.0")]
|
||||||
pub fn copied(self) -> Result<T, E>
|
#[rustc_const_unstable(feature = "const_result", issue = "82814")]
|
||||||
|
pub const fn copied(self) -> Result<T, E>
|
||||||
where
|
where
|
||||||
T: Copy,
|
T: Copy,
|
||||||
{
|
{
|
||||||
self.map(|&mut t| t)
|
// FIXME(const-hack): this implementation, which sidesteps using `Result::map` since it's not const
|
||||||
|
// ready yet, should be reverted when possible to avoid code repetition
|
||||||
|
match self {
|
||||||
|
Ok(&mut v) => Ok(v),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the
|
/// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the
|
||||||
|
@ -1814,7 +1814,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
|
|||||||
}
|
}
|
||||||
mask &= !(1 << trailing);
|
mask &= !(1 << trailing);
|
||||||
}
|
}
|
||||||
return false;
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let test_chunk = |idx| -> u16 {
|
let test_chunk = |idx| -> u16 {
|
||||||
@ -1830,7 +1830,7 @@ fn simd_contains(needle: &str, haystack: &str) -> Option<bool> {
|
|||||||
let both = eq_first.bitand(eq_last);
|
let both = eq_first.bitand(eq_last);
|
||||||
let mask = both.to_bitmask() as u16;
|
let mask = both.to_bitmask() as u16;
|
||||||
|
|
||||||
return mask;
|
mask
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
@ -13,7 +13,7 @@ pub(crate) struct PidFd(FileDesc);
|
|||||||
|
|
||||||
impl PidFd {
|
impl PidFd {
|
||||||
pub fn kill(&self) -> io::Result<()> {
|
pub fn kill(&self) -> io::Result<()> {
|
||||||
return cvt(unsafe {
|
cvt(unsafe {
|
||||||
libc::syscall(
|
libc::syscall(
|
||||||
libc::SYS_pidfd_send_signal,
|
libc::SYS_pidfd_send_signal,
|
||||||
self.0.as_raw_fd(),
|
self.0.as_raw_fd(),
|
||||||
@ -22,7 +22,7 @@ impl PidFd {
|
|||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(drop);
|
.map(drop)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait(&self) -> io::Result<ExitStatus> {
|
pub fn wait(&self) -> io::Result<ExitStatus> {
|
||||||
@ -30,7 +30,7 @@ impl PidFd {
|
|||||||
cvt(unsafe {
|
cvt(unsafe {
|
||||||
libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED)
|
libc::waitid(libc::P_PIDFD, self.0.as_raw_fd() as u32, &mut siginfo, libc::WEXITED)
|
||||||
})?;
|
})?;
|
||||||
return Ok(ExitStatus::from_waitid_siginfo(siginfo));
|
Ok(ExitStatus::from_waitid_siginfo(siginfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> {
|
pub fn try_wait(&self) -> io::Result<Option<ExitStatus>> {
|
||||||
@ -45,9 +45,10 @@ impl PidFd {
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
if unsafe { siginfo.si_pid() } == 0 {
|
if unsafe { siginfo.si_pid() } == 0 {
|
||||||
return Ok(None);
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(ExitStatus::from_waitid_siginfo(siginfo)))
|
||||||
}
|
}
|
||||||
return Ok(Some(ExitStatus::from_waitid_siginfo(siginfo)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ impl OpenOptions {
|
|||||||
pub fn new() -> OpenOptions {
|
pub fn new() -> OpenOptions {
|
||||||
let mut base = OpenOptions::default();
|
let mut base = OpenOptions::default();
|
||||||
base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW;
|
base.dirflags = wasi::LOOKUPFLAGS_SYMLINK_FOLLOW;
|
||||||
return base;
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, read: bool) {
|
pub fn read(&mut self, read: bool) {
|
||||||
@ -382,7 +382,7 @@ impl OpenOptions {
|
|||||||
base |= wasi::RIGHTS_PATH_UNLINK_FILE;
|
base |= wasi::RIGHTS_PATH_UNLINK_FILE;
|
||||||
base |= wasi::RIGHTS_POLL_FD_READWRITE;
|
base |= wasi::RIGHTS_POLL_FD_READWRITE;
|
||||||
|
|
||||||
return base;
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rights_inheriting(&self) -> wasi::Rights {
|
fn rights_inheriting(&self) -> wasi::Rights {
|
||||||
|
@ -115,7 +115,7 @@ pub fn hashmap_random_keys() -> (u64, u64) {
|
|||||||
let len = mem::size_of_val(&ret);
|
let len = mem::size_of_val(&ret);
|
||||||
wasi::random_get(base, len).expect("random_get failure");
|
wasi::random_get(base, len).expect("random_get failure");
|
||||||
}
|
}
|
||||||
return ret;
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1912,7 +1912,7 @@ impl Step for Assemble {
|
|||||||
// delegates to the `rust-lld` binary for linking and then runs
|
// delegates to the `rust-lld` binary for linking and then runs
|
||||||
// logic to create the final binary. This is used by the
|
// logic to create the final binary. This is used by the
|
||||||
// `wasm32-wasip2` target of Rust.
|
// `wasm32-wasip2` target of Rust.
|
||||||
if builder.build_wasm_component_ld() {
|
if builder.tool_enabled("wasm-component-ld") {
|
||||||
let wasm_component_ld_exe =
|
let wasm_component_ld_exe =
|
||||||
builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
|
builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
|
||||||
compiler: build_compiler,
|
compiler: build_compiler,
|
||||||
|
@ -473,7 +473,7 @@ impl Step for Rustc {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if builder.build_wasm_component_ld() {
|
if builder.tool_enabled("wasm-component-ld") {
|
||||||
let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
|
let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
|
||||||
let ld = exe("wasm-component-ld", compiler.host);
|
let ld = exe("wasm-component-ld", compiler.host);
|
||||||
builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld));
|
builder.copy_link(&src_dir.join(&ld), &dst_dir.join(&ld));
|
||||||
|
@ -693,14 +693,7 @@ impl Step for Cargo {
|
|||||||
|
|
||||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
let builder = run.builder;
|
let builder = run.builder;
|
||||||
run.path("src/tools/cargo").default_condition(
|
run.path("src/tools/cargo").default_condition(builder.tool_enabled("cargo"))
|
||||||
builder.config.extended
|
|
||||||
&& builder.config.tools.as_ref().map_or(
|
|
||||||
true,
|
|
||||||
// If `tools` is set, search list for this tool.
|
|
||||||
|tools| tools.iter().any(|tool| tool == "cargo"),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run(run: RunConfig<'_>) {
|
fn make_run(run: RunConfig<'_>) {
|
||||||
@ -772,14 +765,7 @@ impl Step for RustAnalyzer {
|
|||||||
|
|
||||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
let builder = run.builder;
|
let builder = run.builder;
|
||||||
run.path("src/tools/rust-analyzer").default_condition(
|
run.path("src/tools/rust-analyzer").default_condition(builder.tool_enabled("rust-analyzer"))
|
||||||
builder.config.extended
|
|
||||||
&& builder
|
|
||||||
.config
|
|
||||||
.tools
|
|
||||||
.as_ref()
|
|
||||||
.map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run(run: RunConfig<'_>) {
|
fn make_run(run: RunConfig<'_>) {
|
||||||
@ -821,12 +807,8 @@ impl Step for RustAnalyzerProcMacroSrv {
|
|||||||
run.path("src/tools/rust-analyzer")
|
run.path("src/tools/rust-analyzer")
|
||||||
.path("src/tools/rust-analyzer/crates/proc-macro-srv-cli")
|
.path("src/tools/rust-analyzer/crates/proc-macro-srv-cli")
|
||||||
.default_condition(
|
.default_condition(
|
||||||
builder.config.extended
|
builder.tool_enabled("rust-analyzer")
|
||||||
&& builder.config.tools.as_ref().map_or(true, |tools| {
|
|| builder.tool_enabled("rust-analyzer-proc-macro-srv"),
|
||||||
tools.iter().any(|tool| {
|
|
||||||
tool == "rust-analyzer" || tool == "rust-analyzer-proc-macro-srv"
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -874,16 +856,8 @@ impl Step for LlvmBitcodeLinker {
|
|||||||
|
|
||||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
let builder = run.builder;
|
let builder = run.builder;
|
||||||
run.path("src/tools/llvm-bitcode-linker").default_condition(
|
run.path("src/tools/llvm-bitcode-linker")
|
||||||
builder.config.extended
|
.default_condition(builder.tool_enabled("llvm-bitcode-linker"))
|
||||||
&& builder
|
|
||||||
.config
|
|
||||||
.tools
|
|
||||||
.as_ref()
|
|
||||||
.map_or(builder.build.unstable_features(), |tools| {
|
|
||||||
tools.iter().any(|tool| tool == "llvm-bitcode-linker")
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_run(run: RunConfig<'_>) {
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
@ -1407,16 +1407,17 @@ Executed at: {executed_at}"#,
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether it's requested that `wasm-component-ld` is built as part
|
/// Returns whether the specified tool is configured as part of this build.
|
||||||
/// of the sysroot. This is done either with the `extended` key in
|
///
|
||||||
/// `config.toml` or with the `tools` set.
|
/// This requires that both the `extended` key is set and the `tools` key is
|
||||||
fn build_wasm_component_ld(&self) -> bool {
|
/// either unset or specifically contains the specified tool.
|
||||||
if self.config.extended {
|
fn tool_enabled(&self, tool: &str) -> bool {
|
||||||
return true;
|
if !self.config.extended {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
match &self.config.tools {
|
match &self.config.tools {
|
||||||
Some(set) => set.contains("wasm-component-ld"),
|
Some(set) => set.contains(tool),
|
||||||
None => false,
|
None => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@ IFS=$'\n\t'
|
|||||||
|
|
||||||
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
|
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
|
||||||
|
|
||||||
MINGW_ARCHIVE_32="i686-12.2.0-release-posix-dwarf-rt_v10-rev0.7z"
|
MINGW_ARCHIVE_32="i686-14.1.0-release-posix-dwarf-msvcrt-rt_v12-rev0.7z"
|
||||||
MINGW_ARCHIVE_64="x86_64-12.2.0-release-posix-seh-rt_v10-rev0.7z"
|
MINGW_ARCHIVE_64="x86_64-14.1.0-release-posix-seh-msvcrt-rt_v12-rev0.7z"
|
||||||
|
|
||||||
if isWindows && isKnownToBeMingwBuild; then
|
if isWindows && isKnownToBeMingwBuild; then
|
||||||
case "${CI_JOB_NAME}" in
|
case "${CI_JOB_NAME}" in
|
||||||
|
@ -382,6 +382,7 @@ target | std | host | notes
|
|||||||
[`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.3
|
[`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl 1.2.3
|
||||||
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
|
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
|
||||||
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
|
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
|
||||||
|
[`x86_64-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 64-bit GNU/Hurd
|
||||||
[`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit
|
[`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit
|
||||||
`x86_64-unknown-l4re-uclibc` | ? | |
|
`x86_64-unknown-l4re-uclibc` | ? | |
|
||||||
[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
|
[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# `i686-unknown-hurd-gnu`
|
# `i686-unknown-hurd-gnu` and `x86_64-unknown-hurd-gnu`
|
||||||
|
|
||||||
**Tier: 3**
|
**Tier: 3**
|
||||||
|
|
||||||
@ -16,7 +16,8 @@ The GNU/Hurd target supports `std` and uses the standard ELF file format.
|
|||||||
|
|
||||||
## Building the target
|
## Building the target
|
||||||
|
|
||||||
This target can be built by adding `i686-unknown-hurd-gnu` as target in the rustc list.
|
This target can be built by adding `i686-unknown-hurd-gnu` and
|
||||||
|
`x86_64-unknown-hurd-gnu` as targets in the rustc list.
|
||||||
|
|
||||||
## Building Rust programs
|
## Building Rust programs
|
||||||
|
|
||||||
@ -32,4 +33,4 @@ Tests can be run in the same way as a regular binary.
|
|||||||
## Cross-compilation toolchains and C code
|
## Cross-compilation toolchains and C code
|
||||||
|
|
||||||
The target supports C code, the GNU toolchain calls the target
|
The target supports C code, the GNU toolchain calls the target
|
||||||
`i686-unknown-gnu`.
|
`i686-unknown-gnu` and `x86_64-unknown-gnu`.
|
||||||
|
@ -156,7 +156,7 @@ impl FromWithTcx<clean::GenericArgs> for GenericArgs {
|
|||||||
match args {
|
match args {
|
||||||
AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
|
AngleBracketed { args, constraints } => GenericArgs::AngleBracketed {
|
||||||
args: args.into_vec().into_tcx(tcx),
|
args: args.into_vec().into_tcx(tcx),
|
||||||
bindings: constraints.into_tcx(tcx),
|
constraints: constraints.into_tcx(tcx),
|
||||||
},
|
},
|
||||||
Parenthesized { inputs, output } => GenericArgs::Parenthesized {
|
Parenthesized { inputs, output } => GenericArgs::Parenthesized {
|
||||||
inputs: inputs.into_vec().into_tcx(tcx),
|
inputs: inputs.into_vec().into_tcx(tcx),
|
||||||
@ -198,9 +198,9 @@ impl FromWithTcx<clean::ConstantKind> for Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWithTcx<clean::AssocItemConstraint> for TypeBinding {
|
impl FromWithTcx<clean::AssocItemConstraint> for AssocItemConstraint {
|
||||||
fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(constraint: clean::AssocItemConstraint, tcx: TyCtxt<'_>) -> Self {
|
||||||
TypeBinding {
|
AssocItemConstraint {
|
||||||
name: constraint.assoc.name.to_string(),
|
name: constraint.assoc.name.to_string(),
|
||||||
args: constraint.assoc.args.into_tcx(tcx),
|
args: constraint.assoc.args.into_tcx(tcx),
|
||||||
binding: constraint.kind.into_tcx(tcx),
|
binding: constraint.kind.into_tcx(tcx),
|
||||||
@ -208,12 +208,12 @@ impl FromWithTcx<clean::AssocItemConstraint> for TypeBinding {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWithTcx<clean::AssocItemConstraintKind> for TypeBindingKind {
|
impl FromWithTcx<clean::AssocItemConstraintKind> for AssocItemConstraintKind {
|
||||||
fn from_tcx(kind: clean::AssocItemConstraintKind, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(kind: clean::AssocItemConstraintKind, tcx: TyCtxt<'_>) -> Self {
|
||||||
use clean::AssocItemConstraintKind::*;
|
use clean::AssocItemConstraintKind::*;
|
||||||
match kind {
|
match kind {
|
||||||
Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
|
Equality { term } => AssocItemConstraintKind::Equality(term.into_tcx(tcx)),
|
||||||
Bound { bounds } => TypeBindingKind::Constraint(bounds.into_tcx(tcx)),
|
Bound { bounds } => AssocItemConstraintKind::Constraint(bounds.into_tcx(tcx)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +314,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
|||||||
ModuleItem(m) => {
|
ModuleItem(m) => {
|
||||||
ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false })
|
ItemEnum::Module(Module { is_crate, items: ids(m.items, tcx), is_stripped: false })
|
||||||
}
|
}
|
||||||
ImportItem(i) => ItemEnum::Import(i.into_tcx(tcx)),
|
ImportItem(i) => ItemEnum::Use(i.into_tcx(tcx)),
|
||||||
StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
|
StructItem(s) => ItemEnum::Struct(s.into_tcx(tcx)),
|
||||||
UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
|
UnionItem(u) => ItemEnum::Union(u.into_tcx(tcx)),
|
||||||
StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
|
StructFieldItem(f) => ItemEnum::StructField(f.into_tcx(tcx)),
|
||||||
@ -331,7 +331,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
|||||||
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
|
ImplItem(i) => ItemEnum::Impl((*i).into_tcx(tcx)),
|
||||||
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||||
ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)),
|
ForeignStaticItem(s, _) => ItemEnum::Static(s.into_tcx(tcx)),
|
||||||
ForeignTypeItem => ItemEnum::ForeignType,
|
ForeignTypeItem => ItemEnum::ExternType,
|
||||||
TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)),
|
TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)),
|
||||||
// FIXME(generic_const_items): Add support for generic free consts
|
// FIXME(generic_const_items): Add support for generic free consts
|
||||||
ConstantItem(ci) => {
|
ConstantItem(ci) => {
|
||||||
@ -347,21 +347,19 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
|||||||
}
|
}
|
||||||
// FIXME(generic_const_items): Add support for generic associated consts.
|
// FIXME(generic_const_items): Add support for generic associated consts.
|
||||||
TyAssocConstItem(_generics, ty) => {
|
TyAssocConstItem(_generics, ty) => {
|
||||||
ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), default: None }
|
ItemEnum::AssocConst { type_: (*ty).into_tcx(tcx), value: None }
|
||||||
}
|
}
|
||||||
// FIXME(generic_const_items): Add support for generic associated consts.
|
// FIXME(generic_const_items): Add support for generic associated consts.
|
||||||
AssocConstItem(ci) => {
|
AssocConstItem(ci) => {
|
||||||
ItemEnum::AssocConst { type_: ci.type_.into_tcx(tcx), default: Some(ci.kind.expr(tcx)) }
|
ItemEnum::AssocConst { type_: ci.type_.into_tcx(tcx), value: Some(ci.kind.expr(tcx)) }
|
||||||
|
}
|
||||||
|
TyAssocTypeItem(g, b) => {
|
||||||
|
ItemEnum::AssocType { generics: g.into_tcx(tcx), bounds: b.into_tcx(tcx), type_: None }
|
||||||
}
|
}
|
||||||
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
|
|
||||||
generics: g.into_tcx(tcx),
|
|
||||||
bounds: b.into_tcx(tcx),
|
|
||||||
default: None,
|
|
||||||
},
|
|
||||||
AssocTypeItem(t, b) => ItemEnum::AssocType {
|
AssocTypeItem(t, b) => ItemEnum::AssocType {
|
||||||
generics: t.generics.into_tcx(tcx),
|
generics: t.generics.into_tcx(tcx),
|
||||||
bounds: b.into_tcx(tcx),
|
bounds: b.into_tcx(tcx),
|
||||||
default: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
|
type_: Some(t.item_type.unwrap_or(t.type_).into_tcx(tcx)),
|
||||||
},
|
},
|
||||||
// `convert_item` early returns `None` for stripped items and keywords.
|
// `convert_item` early returns `None` for stripped items and keywords.
|
||||||
KeywordItem => unreachable!(),
|
KeywordItem => unreachable!(),
|
||||||
@ -385,7 +383,7 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
|||||||
|
|
||||||
impl FromWithTcx<clean::Struct> for Struct {
|
impl FromWithTcx<clean::Struct> for Struct {
|
||||||
fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(struct_: clean::Struct, tcx: TyCtxt<'_>) -> Self {
|
||||||
let fields_stripped = struct_.has_stripped_entries();
|
let has_stripped_fields = struct_.has_stripped_entries();
|
||||||
let clean::Struct { ctor_kind, generics, fields } = struct_;
|
let clean::Struct { ctor_kind, generics, fields } = struct_;
|
||||||
|
|
||||||
let kind = match ctor_kind {
|
let kind = match ctor_kind {
|
||||||
@ -394,7 +392,7 @@ impl FromWithTcx<clean::Struct> for Struct {
|
|||||||
assert!(fields.is_empty());
|
assert!(fields.is_empty());
|
||||||
StructKind::Unit
|
StructKind::Unit
|
||||||
}
|
}
|
||||||
None => StructKind::Plain { fields: ids(fields, tcx), fields_stripped },
|
None => StructKind::Plain { fields: ids(fields, tcx), has_stripped_fields },
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct {
|
Struct {
|
||||||
@ -407,22 +405,22 @@ impl FromWithTcx<clean::Struct> for Struct {
|
|||||||
|
|
||||||
impl FromWithTcx<clean::Union> for Union {
|
impl FromWithTcx<clean::Union> for Union {
|
||||||
fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(union_: clean::Union, tcx: TyCtxt<'_>) -> Self {
|
||||||
let fields_stripped = union_.has_stripped_entries();
|
let has_stripped_fields = union_.has_stripped_entries();
|
||||||
let clean::Union { generics, fields } = union_;
|
let clean::Union { generics, fields } = union_;
|
||||||
Union {
|
Union {
|
||||||
generics: generics.into_tcx(tcx),
|
generics: generics.into_tcx(tcx),
|
||||||
fields_stripped,
|
has_stripped_fields,
|
||||||
fields: ids(fields, tcx),
|
fields: ids(fields, tcx),
|
||||||
impls: Vec::new(), // Added in JsonRenderer::item
|
impls: Vec::new(), // Added in JsonRenderer::item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> Header {
|
pub(crate) fn from_fn_header(header: &rustc_hir::FnHeader) -> FunctionHeader {
|
||||||
Header {
|
FunctionHeader {
|
||||||
async_: header.is_async(),
|
is_async: header.is_async(),
|
||||||
const_: header.is_const(),
|
is_const: header.is_const(),
|
||||||
unsafe_: header.is_unsafe(),
|
is_unsafe: header.is_unsafe(),
|
||||||
abi: convert_abi(header.abi),
|
abi: convert_abi(header.abi),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -474,7 +472,7 @@ impl FromWithTcx<clean::GenericParamDefKind> for GenericParamDefKind {
|
|||||||
Type { bounds, default, synthetic } => GenericParamDefKind::Type {
|
Type { bounds, default, synthetic } => GenericParamDefKind::Type {
|
||||||
bounds: bounds.into_tcx(tcx),
|
bounds: bounds.into_tcx(tcx),
|
||||||
default: default.map(|x| (*x).into_tcx(tcx)),
|
default: default.map(|x| (*x).into_tcx(tcx)),
|
||||||
synthetic,
|
is_synthetic: synthetic,
|
||||||
},
|
},
|
||||||
Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
|
Const { ty, default, synthetic: _ } => GenericParamDefKind::Const {
|
||||||
type_: (*ty).into_tcx(tcx),
|
type_: (*ty).into_tcx(tcx),
|
||||||
@ -508,7 +506,7 @@ impl FromWithTcx<clean::WherePredicate> for WherePredicate {
|
|||||||
.map(|bound| bound.into_tcx(tcx))
|
.map(|bound| bound.into_tcx(tcx))
|
||||||
.collect(),
|
.collect(),
|
||||||
default: default.map(|ty| (*ty).into_tcx(tcx)),
|
default: default.map(|ty| (*ty).into_tcx(tcx)),
|
||||||
synthetic,
|
is_synthetic: synthetic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => {
|
clean::GenericParamDefKind::Const { ty, default, synthetic: _ } => {
|
||||||
@ -602,12 +600,12 @@ impl FromWithTcx<clean::Type> for Type {
|
|||||||
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
|
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
|
||||||
Infer => Type::Infer,
|
Infer => Type::Infer,
|
||||||
RawPointer(mutability, type_) => Type::RawPointer {
|
RawPointer(mutability, type_) => Type::RawPointer {
|
||||||
mutable: mutability == ast::Mutability::Mut,
|
is_mutable: mutability == ast::Mutability::Mut,
|
||||||
type_: Box::new((*type_).into_tcx(tcx)),
|
type_: Box::new((*type_).into_tcx(tcx)),
|
||||||
},
|
},
|
||||||
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
|
BorrowedRef { lifetime, mutability, type_ } => Type::BorrowedRef {
|
||||||
lifetime: lifetime.map(convert_lifetime),
|
lifetime: lifetime.map(convert_lifetime),
|
||||||
mutable: mutability == ast::Mutability::Mut,
|
is_mutable: mutability == ast::Mutability::Mut,
|
||||||
type_: Box::new((*type_).into_tcx(tcx)),
|
type_: Box::new((*type_).into_tcx(tcx)),
|
||||||
},
|
},
|
||||||
QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
|
QPath(box clean::QPathData { assoc, self_type, trait_, .. }) => Type::QualifiedPath {
|
||||||
@ -643,29 +641,29 @@ impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
|
|||||||
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
|
||||||
let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
|
let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
|
||||||
FunctionPointer {
|
FunctionPointer {
|
||||||
header: Header {
|
header: FunctionHeader {
|
||||||
unsafe_: matches!(safety, rustc_hir::Safety::Unsafe),
|
is_unsafe: matches!(safety, rustc_hir::Safety::Unsafe),
|
||||||
const_: false,
|
is_const: false,
|
||||||
async_: false,
|
is_async: false,
|
||||||
abi: convert_abi(abi),
|
abi: convert_abi(abi),
|
||||||
},
|
},
|
||||||
generic_params: generic_params.into_tcx(tcx),
|
generic_params: generic_params.into_tcx(tcx),
|
||||||
decl: decl.into_tcx(tcx),
|
sig: decl.into_tcx(tcx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWithTcx<clean::FnDecl> for FnDecl {
|
impl FromWithTcx<clean::FnDecl> for FunctionSignature {
|
||||||
fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(decl: clean::FnDecl, tcx: TyCtxt<'_>) -> Self {
|
||||||
let clean::FnDecl { inputs, output, c_variadic } = decl;
|
let clean::FnDecl { inputs, output, c_variadic } = decl;
|
||||||
FnDecl {
|
FunctionSignature {
|
||||||
inputs: inputs
|
inputs: inputs
|
||||||
.values
|
.values
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx)))
|
.map(|arg| (arg.name.to_string(), arg.type_.into_tcx(tcx)))
|
||||||
.collect(),
|
.collect(),
|
||||||
output: if output.is_unit() { None } else { Some(output.into_tcx(tcx)) },
|
output: if output.is_unit() { None } else { Some(output.into_tcx(tcx)) },
|
||||||
c_variadic,
|
is_c_variadic: c_variadic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -702,12 +700,12 @@ impl FromWithTcx<clean::Impl> for Impl {
|
|||||||
let provided_trait_methods = impl_.provided_trait_methods(tcx);
|
let provided_trait_methods = impl_.provided_trait_methods(tcx);
|
||||||
let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
|
let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
|
||||||
// FIXME: use something like ImplKind in JSON?
|
// FIXME: use something like ImplKind in JSON?
|
||||||
let (synthetic, blanket_impl) = match kind {
|
let (is_synthetic, blanket_impl) = match kind {
|
||||||
clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
|
clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
|
||||||
clean::ImplKind::Auto => (true, None),
|
clean::ImplKind::Auto => (true, None),
|
||||||
clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
|
clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
|
||||||
};
|
};
|
||||||
let negative_polarity = match polarity {
|
let is_negative = match polarity {
|
||||||
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
|
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
|
||||||
ty::ImplPolarity::Negative => true,
|
ty::ImplPolarity::Negative => true,
|
||||||
};
|
};
|
||||||
@ -721,8 +719,8 @@ impl FromWithTcx<clean::Impl> for Impl {
|
|||||||
trait_: trait_.map(|path| path.into_tcx(tcx)),
|
trait_: trait_.map(|path| path.into_tcx(tcx)),
|
||||||
for_: for_.into_tcx(tcx),
|
for_: for_.into_tcx(tcx),
|
||||||
items: ids(items, tcx),
|
items: ids(items, tcx),
|
||||||
negative: negative_polarity,
|
is_negative,
|
||||||
synthetic,
|
is_synthetic,
|
||||||
blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
|
blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -736,7 +734,7 @@ pub(crate) fn from_function(
|
|||||||
) -> Function {
|
) -> Function {
|
||||||
let clean::Function { decl, generics } = *function;
|
let clean::Function { decl, generics } = *function;
|
||||||
Function {
|
Function {
|
||||||
decl: decl.into_tcx(tcx),
|
sig: decl.into_tcx(tcx),
|
||||||
generics: generics.into_tcx(tcx),
|
generics: generics.into_tcx(tcx),
|
||||||
header: from_fn_header(&header),
|
header: from_fn_header(&header),
|
||||||
has_body,
|
has_body,
|
||||||
@ -745,11 +743,11 @@ pub(crate) fn from_function(
|
|||||||
|
|
||||||
impl FromWithTcx<clean::Enum> for Enum {
|
impl FromWithTcx<clean::Enum> for Enum {
|
||||||
fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(enum_: clean::Enum, tcx: TyCtxt<'_>) -> Self {
|
||||||
let variants_stripped = enum_.has_stripped_entries();
|
let has_stripped_variants = enum_.has_stripped_entries();
|
||||||
let clean::Enum { variants, generics } = enum_;
|
let clean::Enum { variants, generics } = enum_;
|
||||||
Enum {
|
Enum {
|
||||||
generics: generics.into_tcx(tcx),
|
generics: generics.into_tcx(tcx),
|
||||||
variants_stripped,
|
has_stripped_variants,
|
||||||
variants: ids(variants, tcx),
|
variants: ids(variants, tcx),
|
||||||
impls: Vec::new(), // Added in JsonRenderer::item
|
impls: Vec::new(), // Added in JsonRenderer::item
|
||||||
}
|
}
|
||||||
@ -766,7 +764,7 @@ impl FromWithTcx<clean::Variant> for Variant {
|
|||||||
CLike => VariantKind::Plain,
|
CLike => VariantKind::Plain,
|
||||||
Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
|
Tuple(fields) => VariantKind::Tuple(ids_keeping_stripped(fields, tcx)),
|
||||||
Struct(s) => VariantKind::Struct {
|
Struct(s) => VariantKind::Struct {
|
||||||
fields_stripped: s.has_stripped_entries(),
|
has_stripped_fields: s.has_stripped_entries(),
|
||||||
fields: ids(s.fields, tcx),
|
fields: ids(s.fields, tcx),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -787,21 +785,21 @@ impl FromWithTcx<clean::Discriminant> for Discriminant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromWithTcx<clean::Import> for Import {
|
impl FromWithTcx<clean::Import> for Use {
|
||||||
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
|
||||||
use clean::ImportKind::*;
|
use clean::ImportKind::*;
|
||||||
let (name, glob) = match import.kind {
|
let (name, is_glob) = match import.kind {
|
||||||
Simple(s) => (s.to_string(), false),
|
Simple(s) => (s.to_string(), false),
|
||||||
Glob => (
|
Glob => (
|
||||||
import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
|
import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
Import {
|
Use {
|
||||||
source: import.source.path.whole_name(),
|
source: import.source.path.whole_name(),
|
||||||
name,
|
name,
|
||||||
id: import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)),
|
id: import.source.did.map(ItemId::from).map(|i| id_from_item_default(i, tcx)),
|
||||||
glob,
|
is_glob,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -835,7 +833,7 @@ impl FromWithTcx<clean::Static> for Static {
|
|||||||
fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
|
fn from_tcx(stat: clean::Static, tcx: TyCtxt<'_>) -> Self {
|
||||||
Static {
|
Static {
|
||||||
type_: (*stat.type_).into_tcx(tcx),
|
type_: (*stat.type_).into_tcx(tcx),
|
||||||
mutable: stat.mutability == ast::Mutability::Mut,
|
is_mutable: stat.mutability == ast::Mutability::Mut,
|
||||||
expr: stat
|
expr: stat
|
||||||
.expr
|
.expr
|
||||||
.map(|e| rendered_const(tcx, tcx.hir().body(e), tcx.hir().body_owner_def_id(e)))
|
.map(|e| rendered_const(tcx, tcx.hir().body(e), tcx.hir().body_owner_def_id(e)))
|
||||||
@ -856,7 +854,7 @@ impl FromWithTcx<ItemType> for ItemKind {
|
|||||||
match kind {
|
match kind {
|
||||||
Module => ItemKind::Module,
|
Module => ItemKind::Module,
|
||||||
ExternCrate => ItemKind::ExternCrate,
|
ExternCrate => ItemKind::ExternCrate,
|
||||||
Import => ItemKind::Import,
|
Import => ItemKind::Use,
|
||||||
Struct => ItemKind::Struct,
|
Struct => ItemKind::Struct,
|
||||||
Union => ItemKind::Union,
|
Union => ItemKind::Union,
|
||||||
Enum => ItemKind::Enum,
|
Enum => ItemKind::Enum,
|
||||||
@ -872,7 +870,7 @@ impl FromWithTcx<ItemType> for ItemKind {
|
|||||||
Primitive => ItemKind::Primitive,
|
Primitive => ItemKind::Primitive,
|
||||||
AssocConst => ItemKind::AssocConst,
|
AssocConst => ItemKind::AssocConst,
|
||||||
AssocType => ItemKind::AssocType,
|
AssocType => ItemKind::AssocType,
|
||||||
ForeignType => ItemKind::ForeignType,
|
ForeignType => ItemKind::ExternType,
|
||||||
Keyword => ItemKind::Keyword,
|
Keyword => ItemKind::Keyword,
|
||||||
TraitAlias => ItemKind::TraitAlias,
|
TraitAlias => ItemKind::TraitAlias,
|
||||||
ProcAttribute => ItemKind::ProcAttribute,
|
ProcAttribute => ItemKind::ProcAttribute,
|
||||||
|
@ -197,7 +197,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||||||
|
|
||||||
types::ItemEnum::Function(_)
|
types::ItemEnum::Function(_)
|
||||||
| types::ItemEnum::Module(_)
|
| types::ItemEnum::Module(_)
|
||||||
| types::ItemEnum::Import(_)
|
| types::ItemEnum::Use(_)
|
||||||
| types::ItemEnum::AssocConst { .. }
|
| types::ItemEnum::AssocConst { .. }
|
||||||
| types::ItemEnum::AssocType { .. } => true,
|
| types::ItemEnum::AssocType { .. } => true,
|
||||||
types::ItemEnum::ExternCrate { .. }
|
types::ItemEnum::ExternCrate { .. }
|
||||||
@ -208,7 +208,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||||||
| types::ItemEnum::TypeAlias(_)
|
| types::ItemEnum::TypeAlias(_)
|
||||||
| types::ItemEnum::Constant { .. }
|
| types::ItemEnum::Constant { .. }
|
||||||
| types::ItemEnum::Static(_)
|
| types::ItemEnum::Static(_)
|
||||||
| types::ItemEnum::ForeignType
|
| types::ItemEnum::ExternType
|
||||||
| types::ItemEnum::Macro(_)
|
| types::ItemEnum::Macro(_)
|
||||||
| types::ItemEnum::ProcMacro(_) => false,
|
| types::ItemEnum::ProcMacro(_) => false,
|
||||||
};
|
};
|
||||||
|
@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
/// This integer is incremented with every breaking change to the API,
|
/// This integer is incremented with every breaking change to the API,
|
||||||
/// and is returned along with the JSON blob as [`Crate::format_version`].
|
/// and is returned along with the JSON blob as [`Crate::format_version`].
|
||||||
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
/// Consuming code should assert that this value matches the format version(s) that it supports.
|
||||||
pub const FORMAT_VERSION: u32 = 33;
|
pub const FORMAT_VERSION: u32 = 34;
|
||||||
|
|
||||||
/// The root of the emitted JSON blob.
|
/// The root of the emitted JSON blob.
|
||||||
///
|
///
|
||||||
@ -194,7 +194,7 @@ pub enum GenericArgs {
|
|||||||
/// ```
|
/// ```
|
||||||
args: Vec<GenericArg>,
|
args: Vec<GenericArg>,
|
||||||
/// Associated type or constant bindings (e.g. `Item=i32` or `Item: Clone`) for this type.
|
/// Associated type or constant bindings (e.g. `Item=i32` or `Item: Clone`) for this type.
|
||||||
bindings: Vec<TypeBinding>,
|
constraints: Vec<AssocItemConstraint>,
|
||||||
},
|
},
|
||||||
/// `Fn(A, B) -> C`
|
/// `Fn(A, B) -> C`
|
||||||
Parenthesized {
|
Parenthesized {
|
||||||
@ -258,19 +258,19 @@ pub struct Constant {
|
|||||||
/// ^^^^^^^^^^ ^^^^^^^^^^^^^^^
|
/// ^^^^^^^^^^ ^^^^^^^^^^^^^^^
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct TypeBinding {
|
pub struct AssocItemConstraint {
|
||||||
/// The name of the associated type/constant.
|
/// The name of the associated type/constant.
|
||||||
pub name: String,
|
pub name: String,
|
||||||
/// Arguments provided to the associated type/constant.
|
/// Arguments provided to the associated type/constant.
|
||||||
pub args: GenericArgs,
|
pub args: GenericArgs,
|
||||||
/// The kind of bound applied to the associated type/constant.
|
/// The kind of bound applied to the associated type/constant.
|
||||||
pub binding: TypeBindingKind,
|
pub binding: AssocItemConstraintKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The way in which an associate type/constant is bound.
|
/// The way in which an associate type/constant is bound.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum TypeBindingKind {
|
pub enum AssocItemConstraintKind {
|
||||||
/// The required value/type is specified exactly. e.g.
|
/// The required value/type is specified exactly. e.g.
|
||||||
/// ```text
|
/// ```text
|
||||||
/// Iterator<Item = u32, IntoIter: DoubleEndedIterator>
|
/// Iterator<Item = u32, IntoIter: DoubleEndedIterator>
|
||||||
@ -311,7 +311,7 @@ pub enum ItemKind {
|
|||||||
/// A crate imported via the `extern crate` syntax.
|
/// A crate imported via the `extern crate` syntax.
|
||||||
ExternCrate,
|
ExternCrate,
|
||||||
/// An import of 1 or more items into scope, using the `use` keyword.
|
/// An import of 1 or more items into scope, using the `use` keyword.
|
||||||
Import,
|
Use,
|
||||||
/// A `struct` declaration.
|
/// A `struct` declaration.
|
||||||
Struct,
|
Struct,
|
||||||
/// A field of a struct.
|
/// A field of a struct.
|
||||||
@ -341,7 +341,7 @@ pub enum ItemKind {
|
|||||||
/// `type`s from an `extern` block.
|
/// `type`s from an `extern` block.
|
||||||
///
|
///
|
||||||
/// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
|
/// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
|
||||||
ForeignType,
|
ExternType,
|
||||||
/// A macro declaration.
|
/// A macro declaration.
|
||||||
///
|
///
|
||||||
/// Corresponds to either `ItemEnum::Macro(_)`
|
/// Corresponds to either `ItemEnum::Macro(_)`
|
||||||
@ -386,7 +386,7 @@ pub enum ItemEnum {
|
|||||||
rename: Option<String>,
|
rename: Option<String>,
|
||||||
},
|
},
|
||||||
/// An import of 1 or more items into scope, using the `use` keyword.
|
/// An import of 1 or more items into scope, using the `use` keyword.
|
||||||
Import(Import),
|
Use(Use),
|
||||||
|
|
||||||
/// A `union` declaration.
|
/// A `union` declaration.
|
||||||
Union(Union),
|
Union(Union),
|
||||||
@ -429,7 +429,7 @@ pub enum ItemEnum {
|
|||||||
/// `type`s from an `extern` block.
|
/// `type`s from an `extern` block.
|
||||||
///
|
///
|
||||||
/// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
|
/// See [the tracking issue](https://github.com/rust-lang/rust/issues/43467)
|
||||||
ForeignType,
|
ExternType,
|
||||||
|
|
||||||
/// A macro_rules! declarative macro. Contains a single string with the source
|
/// A macro_rules! declarative macro. Contains a single string with the source
|
||||||
/// representation of the macro with the patterns stripped.
|
/// representation of the macro with the patterns stripped.
|
||||||
@ -447,12 +447,19 @@ pub enum ItemEnum {
|
|||||||
/// The type of the constant.
|
/// The type of the constant.
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: Type,
|
type_: Type,
|
||||||
/// The stringified expression for the default value, if provided, e.g.
|
/// Inside a trait declaration, this is the default value for the associated constant,
|
||||||
|
/// if provided.
|
||||||
|
/// Inside an `impl` block, this is the value assigned to the associated constant,
|
||||||
|
/// and will always be present.
|
||||||
|
///
|
||||||
|
/// The representation is implementation-defined and not guaranteed to be representative of
|
||||||
|
/// either the resulting value or of the source code.
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// const X: usize = 640 * 1024;
|
/// const X: usize = 640 * 1024;
|
||||||
/// // ^^^^^^^^^^
|
/// // ^^^^^^^^^^
|
||||||
/// ```
|
/// ```
|
||||||
default: Option<String>,
|
value: Option<String>,
|
||||||
},
|
},
|
||||||
/// An associated type of a trait or a type.
|
/// An associated type of a trait or a type.
|
||||||
AssocType {
|
AssocType {
|
||||||
@ -467,12 +474,16 @@ pub enum ItemEnum {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
bounds: Vec<GenericBound>,
|
bounds: Vec<GenericBound>,
|
||||||
/// The default for this type, if provided, e.g.
|
/// Inside a trait declaration, this is the default for the associated type, if provided.
|
||||||
|
/// Inside an impl block, this is the type assigned to the associated type, and will always
|
||||||
|
/// be present.
|
||||||
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// type X = usize;
|
/// type X = usize;
|
||||||
/// // ^^^^^
|
/// // ^^^^^
|
||||||
/// ```
|
/// ```
|
||||||
default: Option<Type>,
|
#[serde(rename = "type")]
|
||||||
|
type_: Option<Type>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,7 +508,7 @@ pub struct Union {
|
|||||||
/// The generic parameters and where clauses on this union.
|
/// The generic parameters and where clauses on this union.
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
/// Whether any fields have been removed from the result, due to being private or hidden.
|
/// Whether any fields have been removed from the result, due to being private or hidden.
|
||||||
pub fields_stripped: bool,
|
pub has_stripped_fields: bool,
|
||||||
/// The list of fields in the union.
|
/// The list of fields in the union.
|
||||||
///
|
///
|
||||||
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
|
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
|
||||||
@ -554,7 +565,7 @@ pub enum StructKind {
|
|||||||
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
|
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::StructField`].
|
||||||
fields: Vec<Id>,
|
fields: Vec<Id>,
|
||||||
/// Whether any fields have been removed from the result, due to being private or hidden.
|
/// Whether any fields have been removed from the result, due to being private or hidden.
|
||||||
fields_stripped: bool,
|
has_stripped_fields: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,7 +575,7 @@ pub struct Enum {
|
|||||||
/// Information about the type parameters and `where` clauses of the enum.
|
/// Information about the type parameters and `where` clauses of the enum.
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
/// Whether any variants have been removed from the result, due to being private or hidden.
|
/// Whether any variants have been removed from the result, due to being private or hidden.
|
||||||
pub variants_stripped: bool,
|
pub has_stripped_variants: bool,
|
||||||
/// The list of variants in the enum.
|
/// The list of variants in the enum.
|
||||||
///
|
///
|
||||||
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`]
|
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`]
|
||||||
@ -621,7 +632,7 @@ pub enum VariantKind {
|
|||||||
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`].
|
/// All of the corresponding [`Item`]s are of kind [`ItemEnum::Variant`].
|
||||||
fields: Vec<Id>,
|
fields: Vec<Id>,
|
||||||
/// Whether any variants have been removed from the result, due to being private or hidden.
|
/// Whether any variants have been removed from the result, due to being private or hidden.
|
||||||
fields_stripped: bool,
|
has_stripped_fields: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,16 +656,13 @@ pub struct Discriminant {
|
|||||||
|
|
||||||
/// A set of fundamental properties of a function.
|
/// A set of fundamental properties of a function.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Header {
|
pub struct FunctionHeader {
|
||||||
/// Is this function marked as `const`?
|
/// Is this function marked as `const`?
|
||||||
#[serde(rename = "const")]
|
pub is_const: bool,
|
||||||
pub const_: bool,
|
|
||||||
/// Is this function unsafe?
|
/// Is this function unsafe?
|
||||||
#[serde(rename = "unsafe")]
|
pub is_unsafe: bool,
|
||||||
pub unsafe_: bool,
|
|
||||||
/// Is this function async?
|
/// Is this function async?
|
||||||
#[serde(rename = "async")]
|
pub is_async: bool,
|
||||||
pub async_: bool,
|
|
||||||
/// The ABI used by the function.
|
/// The ABI used by the function.
|
||||||
pub abi: Abi,
|
pub abi: Abi,
|
||||||
}
|
}
|
||||||
@ -697,11 +705,11 @@ pub enum Abi {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
/// Information about the function signature, or declaration.
|
/// Information about the function signature, or declaration.
|
||||||
pub decl: FnDecl,
|
pub sig: FunctionSignature,
|
||||||
/// Information about the function’s type parameters and `where` clauses.
|
/// Information about the function’s type parameters and `where` clauses.
|
||||||
pub generics: Generics,
|
pub generics: Generics,
|
||||||
/// Information about core properties of the function, e.g. whether it's `const`, its ABI, etc.
|
/// Information about core properties of the function, e.g. whether it's `const`, its ABI, etc.
|
||||||
pub header: Header,
|
pub header: FunctionHeader,
|
||||||
/// Whether the function has a body, i.e. an implementation.
|
/// Whether the function has a body, i.e. an implementation.
|
||||||
pub has_body: bool,
|
pub has_body: bool,
|
||||||
}
|
}
|
||||||
@ -784,7 +792,7 @@ pub enum GenericParamDefKind {
|
|||||||
/// In this example, the generic parameter named `impl Trait` (and which
|
/// In this example, the generic parameter named `impl Trait` (and which
|
||||||
/// is bound by `Trait`) is synthetic, because it was not originally in
|
/// is bound by `Trait`) is synthetic, because it was not originally in
|
||||||
/// the Rust source text.
|
/// the Rust source text.
|
||||||
synthetic: bool,
|
is_synthetic: bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Denotes a constant parameter.
|
/// Denotes a constant parameter.
|
||||||
@ -894,7 +902,7 @@ pub enum TraitBoundModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Either a type or a constant, usually stored as the right-hand side of an equation in places like
|
/// Either a type or a constant, usually stored as the right-hand side of an equation in places like
|
||||||
/// [`TypeBinding`]
|
/// [`AssocItemConstraint`]
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Term {
|
pub enum Term {
|
||||||
@ -963,7 +971,7 @@ pub enum Type {
|
|||||||
/// A raw pointer type, e.g. `*mut u32`, `*const u8`, etc.
|
/// A raw pointer type, e.g. `*mut u32`, `*const u8`, etc.
|
||||||
RawPointer {
|
RawPointer {
|
||||||
/// This is `true` for `*mut _` and `false` for `*const _`.
|
/// This is `true` for `*mut _` and `false` for `*const _`.
|
||||||
mutable: bool,
|
is_mutable: bool,
|
||||||
/// The type of the pointee.
|
/// The type of the pointee.
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: Box<Type>,
|
type_: Box<Type>,
|
||||||
@ -973,7 +981,7 @@ pub enum Type {
|
|||||||
/// The name of the lifetime of the reference, if provided.
|
/// The name of the lifetime of the reference, if provided.
|
||||||
lifetime: Option<String>,
|
lifetime: Option<String>,
|
||||||
/// This is `true` for `&mut i32` and `false` for `&i32`
|
/// This is `true` for `&mut i32` and `false` for `&i32`
|
||||||
mutable: bool,
|
is_mutable: bool,
|
||||||
/// The type of the pointee, e.g. the `i32` in `&'a mut i32`
|
/// The type of the pointee, e.g. the `i32` in `&'a mut i32`
|
||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
type_: Box<Type>,
|
type_: Box<Type>,
|
||||||
@ -1036,7 +1044,7 @@ pub struct Path {
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct FunctionPointer {
|
pub struct FunctionPointer {
|
||||||
/// The signature of the function.
|
/// The signature of the function.
|
||||||
pub decl: FnDecl,
|
pub sig: FunctionSignature,
|
||||||
/// Used for Higher-Rank Trait Bounds (HRTBs)
|
/// Used for Higher-Rank Trait Bounds (HRTBs)
|
||||||
///
|
///
|
||||||
/// ```ignore (incomplete expression)
|
/// ```ignore (incomplete expression)
|
||||||
@ -1045,12 +1053,12 @@ pub struct FunctionPointer {
|
|||||||
/// ```
|
/// ```
|
||||||
pub generic_params: Vec<GenericParamDef>,
|
pub generic_params: Vec<GenericParamDef>,
|
||||||
/// The core properties of the function, such as the ABI it conforms to, whether it's unsafe, etc.
|
/// The core properties of the function, such as the ABI it conforms to, whether it's unsafe, etc.
|
||||||
pub header: Header,
|
pub header: FunctionHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The signature of a function.
|
/// The signature of a function.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct FnDecl {
|
pub struct FunctionSignature {
|
||||||
/// List of argument names and their type.
|
/// List of argument names and their type.
|
||||||
///
|
///
|
||||||
/// Note that not all names will be valid identifiers, as some of
|
/// Note that not all names will be valid identifiers, as some of
|
||||||
@ -1063,7 +1071,7 @@ pub struct FnDecl {
|
|||||||
/// ```ignore (incomplete code)
|
/// ```ignore (incomplete code)
|
||||||
/// fn printf(fmt: &str, ...);
|
/// fn printf(fmt: &str, ...);
|
||||||
/// ```
|
/// ```
|
||||||
pub c_variadic: bool,
|
pub is_c_variadic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `trait` declaration.
|
/// A `trait` declaration.
|
||||||
@ -1127,10 +1135,10 @@ pub struct Impl {
|
|||||||
/// The list of associated items contained in this impl block.
|
/// The list of associated items contained in this impl block.
|
||||||
pub items: Vec<Id>,
|
pub items: Vec<Id>,
|
||||||
/// Whether this is a negative impl (e.g. `!Sized` or `!Send`).
|
/// Whether this is a negative impl (e.g. `!Sized` or `!Send`).
|
||||||
pub negative: bool,
|
pub is_negative: bool,
|
||||||
/// Whether this is an impl that’s implied by the compiler
|
/// Whether this is an impl that’s implied by the compiler
|
||||||
/// (for autotraits, e.g. `Send` or `Sync`).
|
/// (for autotraits, e.g. `Send` or `Sync`).
|
||||||
pub synthetic: bool,
|
pub is_synthetic: bool,
|
||||||
// FIXME: document this
|
// FIXME: document this
|
||||||
pub blanket_impl: Option<Type>,
|
pub blanket_impl: Option<Type>,
|
||||||
}
|
}
|
||||||
@ -1138,7 +1146,7 @@ pub struct Impl {
|
|||||||
/// A `use` statement.
|
/// A `use` statement.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct Import {
|
pub struct Use {
|
||||||
/// The full path being imported.
|
/// The full path being imported.
|
||||||
pub source: String,
|
pub source: String,
|
||||||
/// May be different from the last segment of `source` when renaming imports:
|
/// May be different from the last segment of `source` when renaming imports:
|
||||||
@ -1150,7 +1158,7 @@ pub struct Import {
|
|||||||
/// ```
|
/// ```
|
||||||
pub id: Option<Id>,
|
pub id: Option<Id>,
|
||||||
/// Whether this statement is a wildcard `use`, e.g. `use source::*;`
|
/// Whether this statement is a wildcard `use`, e.g. `use source::*;`
|
||||||
pub glob: bool,
|
pub is_glob: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A procedural macro.
|
/// A procedural macro.
|
||||||
@ -1205,7 +1213,7 @@ pub struct Static {
|
|||||||
#[serde(rename = "type")]
|
#[serde(rename = "type")]
|
||||||
pub type_: Type,
|
pub type_: Type,
|
||||||
/// This is `true` for mutable statics, declared as `static mut X: T = f();`
|
/// This is `true` for mutable statics, declared as `static mut X: T = f();`
|
||||||
pub mutable: bool,
|
pub is_mutable: bool,
|
||||||
/// The stringified expression for the initial value.
|
/// The stringified expression for the initial value.
|
||||||
///
|
///
|
||||||
/// It's not guaranteed that it'll match the actual source code for the initial value.
|
/// It's not guaranteed that it'll match the actual source code for the initial value.
|
||||||
|
@ -4,7 +4,7 @@ use super::*;
|
|||||||
fn test_struct_info_roundtrip() {
|
fn test_struct_info_roundtrip() {
|
||||||
let s = ItemEnum::Struct(Struct {
|
let s = ItemEnum::Struct(Struct {
|
||||||
generics: Generics { params: vec![], where_predicates: vec![] },
|
generics: Generics { params: vec![], where_predicates: vec![] },
|
||||||
kind: StructKind::Plain { fields: vec![], fields_stripped: false },
|
kind: StructKind::Plain { fields: vec![], has_stripped_fields: false },
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ fn test_struct_info_roundtrip() {
|
|||||||
fn test_union_info_roundtrip() {
|
fn test_union_info_roundtrip() {
|
||||||
let u = ItemEnum::Union(Union {
|
let u = ItemEnum::Union(Union {
|
||||||
generics: Generics { params: vec![], where_predicates: vec![] },
|
generics: Generics { params: vec![], where_predicates: vec![] },
|
||||||
fields_stripped: false,
|
has_stripped_fields: false,
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
impls: vec![],
|
impls: vec![],
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,7 @@ use rustdoc_json_types::{Item, ItemEnum, ItemKind, ItemSummary};
|
|||||||
pub(crate) enum Kind {
|
pub(crate) enum Kind {
|
||||||
Module,
|
Module,
|
||||||
ExternCrate,
|
ExternCrate,
|
||||||
Import,
|
Use,
|
||||||
Struct,
|
Struct,
|
||||||
StructField,
|
StructField,
|
||||||
Union,
|
Union,
|
||||||
@ -18,7 +18,7 @@ pub(crate) enum Kind {
|
|||||||
TraitAlias,
|
TraitAlias,
|
||||||
Impl,
|
Impl,
|
||||||
Static,
|
Static,
|
||||||
ForeignType,
|
ExternType,
|
||||||
Macro,
|
Macro,
|
||||||
ProcAttribute,
|
ProcAttribute,
|
||||||
ProcDerive,
|
ProcDerive,
|
||||||
@ -36,7 +36,7 @@ impl Kind {
|
|||||||
match self {
|
match self {
|
||||||
Module => true,
|
Module => true,
|
||||||
ExternCrate => true,
|
ExternCrate => true,
|
||||||
Import => true,
|
Use => true,
|
||||||
Union => true,
|
Union => true,
|
||||||
Struct => true,
|
Struct => true,
|
||||||
Enum => true,
|
Enum => true,
|
||||||
@ -50,7 +50,7 @@ impl Kind {
|
|||||||
Macro => true,
|
Macro => true,
|
||||||
ProcMacro => true,
|
ProcMacro => true,
|
||||||
Primitive => true,
|
Primitive => true,
|
||||||
ForeignType => true,
|
ExternType => true,
|
||||||
|
|
||||||
// FIXME(adotinthevoid): I'm not sure if these are correct
|
// FIXME(adotinthevoid): I'm not sure if these are correct
|
||||||
Keyword => false,
|
Keyword => false,
|
||||||
@ -69,7 +69,7 @@ impl Kind {
|
|||||||
pub fn can_appear_in_import(self) -> bool {
|
pub fn can_appear_in_import(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Kind::Variant => true,
|
Kind::Variant => true,
|
||||||
Kind::Import => false,
|
Kind::Use => false,
|
||||||
other => other.can_appear_in_mod(),
|
other => other.can_appear_in_mod(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ impl Kind {
|
|||||||
|
|
||||||
Kind::Module => false,
|
Kind::Module => false,
|
||||||
Kind::ExternCrate => false,
|
Kind::ExternCrate => false,
|
||||||
Kind::Import => false,
|
Kind::Use => false,
|
||||||
Kind::Struct => false,
|
Kind::Struct => false,
|
||||||
Kind::StructField => false,
|
Kind::StructField => false,
|
||||||
Kind::Union => false,
|
Kind::Union => false,
|
||||||
@ -102,7 +102,7 @@ impl Kind {
|
|||||||
Kind::TraitAlias => false,
|
Kind::TraitAlias => false,
|
||||||
Kind::Impl => false,
|
Kind::Impl => false,
|
||||||
Kind::Static => false,
|
Kind::Static => false,
|
||||||
Kind::ForeignType => false,
|
Kind::ExternType => false,
|
||||||
Kind::Macro => false,
|
Kind::Macro => false,
|
||||||
Kind::ProcAttribute => false,
|
Kind::ProcAttribute => false,
|
||||||
Kind::ProcDerive => false,
|
Kind::ProcDerive => false,
|
||||||
@ -135,7 +135,7 @@ impl Kind {
|
|||||||
use Kind::*;
|
use Kind::*;
|
||||||
match i.inner {
|
match i.inner {
|
||||||
ItemEnum::Module(_) => Module,
|
ItemEnum::Module(_) => Module,
|
||||||
ItemEnum::Import(_) => Import,
|
ItemEnum::Use(_) => Use,
|
||||||
ItemEnum::Union(_) => Union,
|
ItemEnum::Union(_) => Union,
|
||||||
ItemEnum::Struct(_) => Struct,
|
ItemEnum::Struct(_) => Struct,
|
||||||
ItemEnum::StructField(_) => StructField,
|
ItemEnum::StructField(_) => StructField,
|
||||||
@ -151,7 +151,7 @@ impl Kind {
|
|||||||
ItemEnum::Macro(_) => Macro,
|
ItemEnum::Macro(_) => Macro,
|
||||||
ItemEnum::ProcMacro(_) => ProcMacro,
|
ItemEnum::ProcMacro(_) => ProcMacro,
|
||||||
ItemEnum::Primitive(_) => Primitive,
|
ItemEnum::Primitive(_) => Primitive,
|
||||||
ItemEnum::ForeignType => ForeignType,
|
ItemEnum::ExternType => ExternType,
|
||||||
ItemEnum::ExternCrate { .. } => ExternCrate,
|
ItemEnum::ExternCrate { .. } => ExternCrate,
|
||||||
ItemEnum::AssocConst { .. } => AssocConst,
|
ItemEnum::AssocConst { .. } => AssocConst,
|
||||||
ItemEnum::AssocType { .. } => AssocType,
|
ItemEnum::AssocType { .. } => AssocType,
|
||||||
@ -166,10 +166,10 @@ impl Kind {
|
|||||||
ItemKind::Constant => Constant,
|
ItemKind::Constant => Constant,
|
||||||
ItemKind::Enum => Enum,
|
ItemKind::Enum => Enum,
|
||||||
ItemKind::ExternCrate => ExternCrate,
|
ItemKind::ExternCrate => ExternCrate,
|
||||||
ItemKind::ForeignType => ForeignType,
|
ItemKind::ExternType => ExternType,
|
||||||
ItemKind::Function => Function,
|
ItemKind::Function => Function,
|
||||||
ItemKind::Impl => Impl,
|
ItemKind::Impl => Impl,
|
||||||
ItemKind::Import => Import,
|
ItemKind::Use => Use,
|
||||||
ItemKind::Keyword => Keyword,
|
ItemKind::Keyword => Keyword,
|
||||||
ItemKind::Macro => Macro,
|
ItemKind::Macro => Macro,
|
||||||
ItemKind::Module => Module,
|
ItemKind::Module => Module,
|
||||||
|
@ -2,10 +2,11 @@ use std::collections::HashSet;
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use rustdoc_json_types::{
|
use rustdoc_json_types::{
|
||||||
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
|
AssocItemConstraint, AssocItemConstraintKind, Constant, Crate, DynTrait, Enum, Function,
|
||||||
GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module, Path,
|
FunctionPointer, FunctionSignature, GenericArg, GenericArgs, GenericBound, GenericParamDef,
|
||||||
Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeAlias,
|
Generics, Id, Impl, ItemEnum, ItemSummary, Module, Path, Primitive, ProcMacro, Static, Struct,
|
||||||
TypeBinding, TypeBindingKind, Union, Variant, VariantKind, WherePredicate,
|
StructKind, Term, Trait, TraitAlias, Type, TypeAlias, Union, Use, Variant, VariantKind,
|
||||||
|
WherePredicate,
|
||||||
};
|
};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
@ -90,7 +91,7 @@ impl<'a> Validator<'a> {
|
|||||||
item.links.values().for_each(|id| self.add_any_id(id));
|
item.links.values().for_each(|id| self.add_any_id(id));
|
||||||
|
|
||||||
match &item.inner {
|
match &item.inner {
|
||||||
ItemEnum::Import(x) => self.check_import(x),
|
ItemEnum::Use(x) => self.check_use(x),
|
||||||
ItemEnum::Union(x) => self.check_union(x),
|
ItemEnum::Union(x) => self.check_union(x),
|
||||||
ItemEnum::Struct(x) => self.check_struct(x),
|
ItemEnum::Struct(x) => self.check_struct(x),
|
||||||
ItemEnum::StructField(x) => self.check_struct_field(x),
|
ItemEnum::StructField(x) => self.check_struct_field(x),
|
||||||
@ -106,18 +107,18 @@ impl<'a> Validator<'a> {
|
|||||||
self.check_constant(const_);
|
self.check_constant(const_);
|
||||||
}
|
}
|
||||||
ItemEnum::Static(x) => self.check_static(x),
|
ItemEnum::Static(x) => self.check_static(x),
|
||||||
ItemEnum::ForeignType => {} // nop
|
ItemEnum::ExternType => {} // nop
|
||||||
ItemEnum::Macro(x) => self.check_macro(x),
|
ItemEnum::Macro(x) => self.check_macro(x),
|
||||||
ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
|
ItemEnum::ProcMacro(x) => self.check_proc_macro(x),
|
||||||
ItemEnum::Primitive(x) => self.check_primitive_type(x),
|
ItemEnum::Primitive(x) => self.check_primitive_type(x),
|
||||||
ItemEnum::Module(x) => self.check_module(x, id),
|
ItemEnum::Module(x) => self.check_module(x, id),
|
||||||
// FIXME: Why don't these have their own structs?
|
// FIXME: Why don't these have their own structs?
|
||||||
ItemEnum::ExternCrate { .. } => {}
|
ItemEnum::ExternCrate { .. } => {}
|
||||||
ItemEnum::AssocConst { type_, default: _ } => self.check_type(type_),
|
ItemEnum::AssocConst { type_, value: _ } => self.check_type(type_),
|
||||||
ItemEnum::AssocType { generics, bounds, default } => {
|
ItemEnum::AssocType { generics, bounds, type_ } => {
|
||||||
self.check_generics(generics);
|
self.check_generics(generics);
|
||||||
bounds.iter().for_each(|b| self.check_generic_bound(b));
|
bounds.iter().for_each(|b| self.check_generic_bound(b));
|
||||||
if let Some(ty) = default {
|
if let Some(ty) = type_ {
|
||||||
self.check_type(ty);
|
self.check_type(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,8 +134,8 @@ impl<'a> Validator<'a> {
|
|||||||
module.items.iter().for_each(|i| self.add_mod_item_id(i));
|
module.items.iter().for_each(|i| self.add_mod_item_id(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_import(&mut self, x: &'a Import) {
|
fn check_use(&mut self, x: &'a Use) {
|
||||||
if x.glob {
|
if x.is_glob {
|
||||||
self.add_glob_import_item_id(x.id.as_ref().unwrap());
|
self.add_glob_import_item_id(x.id.as_ref().unwrap());
|
||||||
} else if let Some(id) = &x.id {
|
} else if let Some(id) = &x.id {
|
||||||
self.add_import_item_id(id);
|
self.add_import_item_id(id);
|
||||||
@ -152,7 +153,7 @@ impl<'a> Validator<'a> {
|
|||||||
match &x.kind {
|
match &x.kind {
|
||||||
StructKind::Unit => {}
|
StructKind::Unit => {}
|
||||||
StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)),
|
StructKind::Tuple(fields) => fields.iter().flatten().for_each(|f| self.add_field_id(f)),
|
||||||
StructKind::Plain { fields, fields_stripped: _ } => {
|
StructKind::Plain { fields, has_stripped_fields: _ } => {
|
||||||
fields.iter().for_each(|f| self.add_field_id(f))
|
fields.iter().for_each(|f| self.add_field_id(f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,7 +188,7 @@ impl<'a> Validator<'a> {
|
|||||||
match kind {
|
match kind {
|
||||||
VariantKind::Plain => {}
|
VariantKind::Plain => {}
|
||||||
VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
|
VariantKind::Tuple(tys) => tys.iter().flatten().for_each(|t| self.add_field_id(t)),
|
||||||
VariantKind::Struct { fields, fields_stripped: _ } => {
|
VariantKind::Struct { fields, has_stripped_fields: _ } => {
|
||||||
fields.iter().for_each(|f| self.add_field_id(f))
|
fields.iter().for_each(|f| self.add_field_id(f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +196,7 @@ impl<'a> Validator<'a> {
|
|||||||
|
|
||||||
fn check_function(&mut self, x: &'a Function) {
|
fn check_function(&mut self, x: &'a Function) {
|
||||||
self.check_generics(&x.generics);
|
self.check_generics(&x.generics);
|
||||||
self.check_fn_decl(&x.decl);
|
self.check_function_signature(&x.sig);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_trait(&mut self, x: &'a Trait, id: &Id) {
|
fn check_trait(&mut self, x: &'a Trait, id: &Id) {
|
||||||
@ -267,8 +268,8 @@ impl<'a> Validator<'a> {
|
|||||||
Type::Array { type_, len: _ } => self.check_type(&**type_),
|
Type::Array { type_, len: _ } => self.check_type(&**type_),
|
||||||
Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)),
|
Type::ImplTrait(bounds) => bounds.iter().for_each(|b| self.check_generic_bound(b)),
|
||||||
Type::Infer => {}
|
Type::Infer => {}
|
||||||
Type::RawPointer { mutable: _, type_ } => self.check_type(&**type_),
|
Type::RawPointer { is_mutable: _, type_ } => self.check_type(&**type_),
|
||||||
Type::BorrowedRef { lifetime: _, mutable: _, type_ } => self.check_type(&**type_),
|
Type::BorrowedRef { lifetime: _, is_mutable: _, type_ } => self.check_type(&**type_),
|
||||||
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
|
Type::QualifiedPath { name: _, args, self_type, trait_ } => {
|
||||||
self.check_generic_args(&**args);
|
self.check_generic_args(&**args);
|
||||||
self.check_type(&**self_type);
|
self.check_type(&**self_type);
|
||||||
@ -279,7 +280,7 @@ impl<'a> Validator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_fn_decl(&mut self, x: &'a FnDecl) {
|
fn check_function_signature(&mut self, x: &'a FunctionSignature) {
|
||||||
x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty));
|
x.inputs.iter().for_each(|(_name, ty)| self.check_type(ty));
|
||||||
if let Some(output) = &x.output {
|
if let Some(output) = &x.output {
|
||||||
self.check_type(output);
|
self.check_type(output);
|
||||||
@ -309,9 +310,9 @@ impl<'a> Validator<'a> {
|
|||||||
|
|
||||||
fn check_generic_args(&mut self, x: &'a GenericArgs) {
|
fn check_generic_args(&mut self, x: &'a GenericArgs) {
|
||||||
match x {
|
match x {
|
||||||
GenericArgs::AngleBracketed { args, bindings } => {
|
GenericArgs::AngleBracketed { args, constraints } => {
|
||||||
args.iter().for_each(|arg| self.check_generic_arg(arg));
|
args.iter().for_each(|arg| self.check_generic_arg(arg));
|
||||||
bindings.iter().for_each(|bind| self.check_type_binding(bind));
|
constraints.iter().for_each(|bind| self.check_assoc_item_constraint(bind));
|
||||||
}
|
}
|
||||||
GenericArgs::Parenthesized { inputs, output } => {
|
GenericArgs::Parenthesized { inputs, output } => {
|
||||||
inputs.iter().for_each(|ty| self.check_type(ty));
|
inputs.iter().for_each(|ty| self.check_type(ty));
|
||||||
@ -325,7 +326,7 @@ impl<'a> Validator<'a> {
|
|||||||
fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) {
|
fn check_generic_param_def(&mut self, gpd: &'a GenericParamDef) {
|
||||||
match &gpd.kind {
|
match &gpd.kind {
|
||||||
rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {}
|
rustdoc_json_types::GenericParamDefKind::Lifetime { outlives: _ } => {}
|
||||||
rustdoc_json_types::GenericParamDefKind::Type { bounds, default, synthetic: _ } => {
|
rustdoc_json_types::GenericParamDefKind::Type { bounds, default, is_synthetic: _ } => {
|
||||||
bounds.iter().for_each(|b| self.check_generic_bound(b));
|
bounds.iter().for_each(|b| self.check_generic_bound(b));
|
||||||
if let Some(ty) = default {
|
if let Some(ty) = default {
|
||||||
self.check_type(ty);
|
self.check_type(ty);
|
||||||
@ -346,11 +347,11 @@ impl<'a> Validator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_type_binding(&mut self, bind: &'a TypeBinding) {
|
fn check_assoc_item_constraint(&mut self, bind: &'a AssocItemConstraint) {
|
||||||
self.check_generic_args(&bind.args);
|
self.check_generic_args(&bind.args);
|
||||||
match &bind.binding {
|
match &bind.binding {
|
||||||
TypeBindingKind::Equality(term) => self.check_term(term),
|
AssocItemConstraintKind::Equality(term) => self.check_term(term),
|
||||||
TypeBindingKind::Constraint(bounds) => {
|
AssocItemConstraintKind::Constraint(bounds) => {
|
||||||
bounds.iter().for_each(|b| self.check_generic_bound(b))
|
bounds.iter().for_each(|b| self.check_generic_bound(b))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,7 +389,7 @@ impl<'a> Validator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_function_pointer(&mut self, fp: &'a FunctionPointer) {
|
fn check_function_pointer(&mut self, fp: &'a FunctionPointer) {
|
||||||
self.check_fn_decl(&fp.decl);
|
self.check_function_signature(&fp.sig);
|
||||||
fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
|
fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,6 @@ features = ['unprefixed_malloc_on_supported_platforms']
|
|||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
|
||||||
libffi = "3.2.0"
|
libffi = "3.2.0"
|
||||||
libloading = "0.8"
|
libloading = "0.8"
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ to Miri failing to detect cases of undefined behavior in a program.
|
|||||||
file descriptors will be mixed up.
|
file descriptors will be mixed up.
|
||||||
This is **work in progress**; currently, only integer arguments and return values are
|
This is **work in progress**; currently, only integer arguments and return values are
|
||||||
supported (and no, pointer/integer casts to work around this limitation will not work;
|
supported (and no, pointer/integer casts to work around this limitation will not work;
|
||||||
they will fail horribly). It also only works on Linux hosts for now.
|
they will fail horribly). It also only works on Unix hosts for now.
|
||||||
* `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
|
* `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
|
||||||
This can be used to find which parts of your program are executing slowly under Miri.
|
This can be used to find which parts of your program are executing slowly under Miri.
|
||||||
The profile is written out to a file inside a directory called `<name>`, and can be processed
|
The profile is written out to a file inside a directory called `<name>`, and can be processed
|
||||||
|
@ -5,8 +5,8 @@ set MIRI_SCRIPT_TARGET_DIR=%0\..\miri-script\target
|
|||||||
|
|
||||||
:: If any other steps are added, the "|| exit /b" must be appended to early
|
:: If any other steps are added, the "|| exit /b" must be appended to early
|
||||||
:: return from the script. If not, it will continue execution.
|
:: return from the script. If not, it will continue execution.
|
||||||
cargo +stable build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^
|
cargo +nightly build %CARGO_EXTRA_FLAGS% -q --target-dir %MIRI_SCRIPT_TARGET_DIR% --manifest-path %0\..\miri-script\Cargo.toml ^
|
||||||
|| (echo Failed to build miri-script. Is the 'stable' toolchain installed? & exit /b)
|
|| (echo Failed to build miri-script. Is the 'nightly' toolchain installed? & exit /b)
|
||||||
|
|
||||||
:: Forwards all arguments to this file to the executable.
|
:: Forwards all arguments to this file to the executable.
|
||||||
:: We invoke the binary directly to avoid going through rustup, which would set some extra
|
:: We invoke the binary directly to avoid going through rustup, which would set some extra
|
||||||
|
@ -1 +1 @@
|
|||||||
0d634185dfddefe09047881175f35c65d68dcff1
|
54fdef7799d9ff9470bb5cabd29fde9471a99eaa
|
||||||
|
@ -5,7 +5,6 @@ mod reuse_pool;
|
|||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::collections::hash_map::Entry;
|
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
@ -151,6 +150,95 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addr_from_alloc_id_uncached(
|
||||||
|
&self,
|
||||||
|
global_state: &mut GlobalStateInner,
|
||||||
|
alloc_id: AllocId,
|
||||||
|
memory_kind: MemoryKind,
|
||||||
|
) -> InterpResult<'tcx, u64> {
|
||||||
|
let ecx = self.eval_context_ref();
|
||||||
|
let mut rng = ecx.machine.rng.borrow_mut();
|
||||||
|
let (size, align, kind) = ecx.get_alloc_info(alloc_id);
|
||||||
|
// This is either called immediately after allocation (and then cached), or when
|
||||||
|
// adjusting `tcx` pointers (which never get freed). So assert that we are looking
|
||||||
|
// at a live allocation. This also ensures that we never re-assign an address to an
|
||||||
|
// allocation that previously had an address, but then was freed and the address
|
||||||
|
// information was removed.
|
||||||
|
assert!(!matches!(kind, AllocKind::Dead));
|
||||||
|
|
||||||
|
// This allocation does not have a base address yet, pick or reuse one.
|
||||||
|
if ecx.machine.native_lib.is_some() {
|
||||||
|
// In native lib mode, we use the "real" address of the bytes for this allocation.
|
||||||
|
// This ensures the interpreted program and native code have the same view of memory.
|
||||||
|
let base_ptr = match kind {
|
||||||
|
AllocKind::LiveData => {
|
||||||
|
if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
|
||||||
|
// For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
|
||||||
|
let prepared_bytes = MiriAllocBytes::zeroed(size, align)
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes")
|
||||||
|
});
|
||||||
|
let ptr = prepared_bytes.as_ptr();
|
||||||
|
// Store prepared allocation space to be picked up for use later.
|
||||||
|
global_state
|
||||||
|
.prepared_alloc_bytes
|
||||||
|
.try_insert(alloc_id, prepared_bytes)
|
||||||
|
.unwrap();
|
||||||
|
ptr
|
||||||
|
} else {
|
||||||
|
ecx.get_alloc_bytes_unchecked_raw(alloc_id)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AllocKind::Function | AllocKind::VTable => {
|
||||||
|
// Allocate some dummy memory to get a unique address for this function/vtable.
|
||||||
|
let alloc_bytes =
|
||||||
|
MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap());
|
||||||
|
let ptr = alloc_bytes.as_ptr();
|
||||||
|
// Leak the underlying memory to ensure it remains unique.
|
||||||
|
std::mem::forget(alloc_bytes);
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
AllocKind::Dead => unreachable!(),
|
||||||
|
};
|
||||||
|
// Ensure this pointer's provenance is exposed, so that it can be used by FFI code.
|
||||||
|
return Ok(base_ptr.expose_provenance().try_into().unwrap());
|
||||||
|
}
|
||||||
|
// We are not in native lib mode, so we control the addresses ourselves.
|
||||||
|
if let Some((reuse_addr, clock)) =
|
||||||
|
global_state.reuse.take_addr(&mut *rng, size, align, memory_kind, ecx.active_thread())
|
||||||
|
{
|
||||||
|
if let Some(clock) = clock {
|
||||||
|
ecx.acquire_clock(&clock);
|
||||||
|
}
|
||||||
|
Ok(reuse_addr)
|
||||||
|
} else {
|
||||||
|
// We have to pick a fresh address.
|
||||||
|
// Leave some space to the previous allocation, to give it some chance to be less aligned.
|
||||||
|
// We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
|
||||||
|
let slack = rng.gen_range(0..16);
|
||||||
|
// From next_base_addr + slack, round up to adjust for alignment.
|
||||||
|
let base_addr = global_state
|
||||||
|
.next_base_addr
|
||||||
|
.checked_add(slack)
|
||||||
|
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||||
|
let base_addr = align_addr(base_addr, align.bytes());
|
||||||
|
|
||||||
|
// Remember next base address. If this allocation is zero-sized, leave a gap of at
|
||||||
|
// least 1 to avoid two allocations having the same base address. (The logic in
|
||||||
|
// `alloc_id_from_addr` assumes unique addresses, and different function/vtable pointers
|
||||||
|
// need to be distinguishable!)
|
||||||
|
global_state.next_base_addr = base_addr
|
||||||
|
.checked_add(max(size.bytes(), 1))
|
||||||
|
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
||||||
|
// Even if `Size` didn't overflow, we might still have filled up the address space.
|
||||||
|
if global_state.next_base_addr > ecx.target_usize_max() {
|
||||||
|
throw_exhaust!(AddressSpaceFull);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(base_addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn addr_from_alloc_id(
|
fn addr_from_alloc_id(
|
||||||
&self,
|
&self,
|
||||||
alloc_id: AllocId,
|
alloc_id: AllocId,
|
||||||
@ -160,98 +248,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
let mut global_state = ecx.machine.alloc_addresses.borrow_mut();
|
let mut global_state = ecx.machine.alloc_addresses.borrow_mut();
|
||||||
let global_state = &mut *global_state;
|
let global_state = &mut *global_state;
|
||||||
|
|
||||||
Ok(match global_state.base_addr.entry(alloc_id) {
|
match global_state.base_addr.get(&alloc_id) {
|
||||||
Entry::Occupied(entry) => *entry.get(),
|
Some(&addr) => Ok(addr),
|
||||||
Entry::Vacant(entry) => {
|
None => {
|
||||||
let mut rng = ecx.machine.rng.borrow_mut();
|
// First time we're looking for the absolute address of this allocation.
|
||||||
let (size, align, kind) = ecx.get_alloc_info(alloc_id);
|
let base_addr =
|
||||||
// This is either called immediately after allocation (and then cached), or when
|
self.addr_from_alloc_id_uncached(global_state, alloc_id, memory_kind)?;
|
||||||
// adjusting `tcx` pointers (which never get freed). So assert that we are looking
|
trace!("Assigning base address {:#x} to allocation {:?}", base_addr, alloc_id);
|
||||||
// at a live allocation. This also ensures that we never re-assign an address to an
|
|
||||||
// allocation that previously had an address, but then was freed and the address
|
|
||||||
// information was removed.
|
|
||||||
assert!(!matches!(kind, AllocKind::Dead));
|
|
||||||
|
|
||||||
// This allocation does not have a base address yet, pick or reuse one.
|
|
||||||
let base_addr = if ecx.machine.native_lib.is_some() {
|
|
||||||
// In native lib mode, we use the "real" address of the bytes for this allocation.
|
|
||||||
// This ensures the interpreted program and native code have the same view of memory.
|
|
||||||
match kind {
|
|
||||||
AllocKind::LiveData => {
|
|
||||||
let ptr = if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
|
|
||||||
// For new global allocations, we always pre-allocate the memory to be able use the machine address directly.
|
|
||||||
let prepared_bytes = MiriAllocBytes::zeroed(size, align)
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
panic!("Miri ran out of memory: cannot create allocation of {size:?} bytes")
|
|
||||||
});
|
|
||||||
let ptr = prepared_bytes.as_ptr();
|
|
||||||
// Store prepared allocation space to be picked up for use later.
|
|
||||||
global_state.prepared_alloc_bytes.try_insert(alloc_id, prepared_bytes).unwrap();
|
|
||||||
ptr
|
|
||||||
} else {
|
|
||||||
ecx.get_alloc_bytes_unchecked_raw(alloc_id)?
|
|
||||||
};
|
|
||||||
// Ensure this pointer's provenance is exposed, so that it can be used by FFI code.
|
|
||||||
ptr.expose_provenance().try_into().unwrap()
|
|
||||||
}
|
|
||||||
AllocKind::Function | AllocKind::VTable => {
|
|
||||||
// Allocate some dummy memory to get a unique address for this function/vtable.
|
|
||||||
let alloc_bytes = MiriAllocBytes::from_bytes(&[0u8; 1], Align::from_bytes(1).unwrap());
|
|
||||||
// We don't need to expose these bytes as nobody is allowed to access them.
|
|
||||||
let addr = alloc_bytes.as_ptr().addr().try_into().unwrap();
|
|
||||||
// Leak the underlying memory to ensure it remains unique.
|
|
||||||
std::mem::forget(alloc_bytes);
|
|
||||||
addr
|
|
||||||
}
|
|
||||||
AllocKind::Dead => unreachable!()
|
|
||||||
}
|
|
||||||
} else if let Some((reuse_addr, clock)) = global_state.reuse.take_addr(
|
|
||||||
&mut *rng,
|
|
||||||
size,
|
|
||||||
align,
|
|
||||||
memory_kind,
|
|
||||||
ecx.active_thread(),
|
|
||||||
) {
|
|
||||||
if let Some(clock) = clock {
|
|
||||||
ecx.acquire_clock(&clock);
|
|
||||||
}
|
|
||||||
reuse_addr
|
|
||||||
} else {
|
|
||||||
// We have to pick a fresh address.
|
|
||||||
// Leave some space to the previous allocation, to give it some chance to be less aligned.
|
|
||||||
// We ensure that `(global_state.next_base_addr + slack) % 16` is uniformly distributed.
|
|
||||||
let slack = rng.gen_range(0..16);
|
|
||||||
// From next_base_addr + slack, round up to adjust for alignment.
|
|
||||||
let base_addr = global_state
|
|
||||||
.next_base_addr
|
|
||||||
.checked_add(slack)
|
|
||||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
|
||||||
let base_addr = align_addr(base_addr, align.bytes());
|
|
||||||
|
|
||||||
// Remember next base address. If this allocation is zero-sized, leave a gap
|
|
||||||
// of at least 1 to avoid two allocations having the same base address.
|
|
||||||
// (The logic in `alloc_id_from_addr` assumes unique addresses, and different
|
|
||||||
// function/vtable pointers need to be distinguishable!)
|
|
||||||
global_state.next_base_addr = base_addr
|
|
||||||
.checked_add(max(size.bytes(), 1))
|
|
||||||
.ok_or_else(|| err_exhaust!(AddressSpaceFull))?;
|
|
||||||
// Even if `Size` didn't overflow, we might still have filled up the address space.
|
|
||||||
if global_state.next_base_addr > ecx.target_usize_max() {
|
|
||||||
throw_exhaust!(AddressSpaceFull);
|
|
||||||
}
|
|
||||||
|
|
||||||
base_addr
|
|
||||||
};
|
|
||||||
trace!(
|
|
||||||
"Assigning base address {:#x} to allocation {:?} (size: {}, align: {})",
|
|
||||||
base_addr,
|
|
||||||
alloc_id,
|
|
||||||
size.bytes(),
|
|
||||||
align.bytes(),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Store address in cache.
|
// Store address in cache.
|
||||||
entry.insert(base_addr);
|
global_state.base_addr.try_insert(alloc_id, base_addr).unwrap();
|
||||||
|
|
||||||
// Also maintain the opposite mapping in `int_to_ptr_map`, ensuring we keep it sorted.
|
// Also maintain the opposite mapping in `int_to_ptr_map`, ensuring we keep it sorted.
|
||||||
// We have a fast-path for the common case that this address is bigger than all previous ones.
|
// We have a fast-path for the common case that this address is bigger than all previous ones.
|
||||||
@ -269,9 +275,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
};
|
};
|
||||||
global_state.int_to_ptr_map.insert(pos, (base_addr, alloc_id));
|
global_state.int_to_ptr_map.insert(pos, (base_addr, alloc_id));
|
||||||
|
|
||||||
base_addr
|
Ok(base_addr)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,16 +365,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
|
|
||||||
// This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved
|
// This returns some prepared `MiriAllocBytes`, either because `addr_from_alloc_id` reserved
|
||||||
// memory space in the past, or by doing the pre-allocation right upon being called.
|
// memory space in the past, or by doing the pre-allocation right upon being called.
|
||||||
fn get_global_alloc_bytes(&self, id: AllocId, kind: MemoryKind, bytes: &[u8], align: Align) -> InterpResult<'tcx, MiriAllocBytes> {
|
fn get_global_alloc_bytes(
|
||||||
|
&self,
|
||||||
|
id: AllocId,
|
||||||
|
kind: MemoryKind,
|
||||||
|
bytes: &[u8],
|
||||||
|
align: Align,
|
||||||
|
) -> InterpResult<'tcx, MiriAllocBytes> {
|
||||||
let ecx = self.eval_context_ref();
|
let ecx = self.eval_context_ref();
|
||||||
Ok(if ecx.machine.native_lib.is_some() {
|
if ecx.machine.native_lib.is_some() {
|
||||||
// In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`.
|
// In native lib mode, MiriAllocBytes for global allocations are handled via `prepared_alloc_bytes`.
|
||||||
// This additional call ensures that some `MiriAllocBytes` are always prepared.
|
// This additional call ensures that some `MiriAllocBytes` are always prepared, just in case
|
||||||
|
// this function gets called before the first time `addr_from_alloc_id` gets called.
|
||||||
ecx.addr_from_alloc_id(id, kind)?;
|
ecx.addr_from_alloc_id(id, kind)?;
|
||||||
let mut global_state = ecx.machine.alloc_addresses.borrow_mut();
|
|
||||||
// The memory we need here will have already been allocated during an earlier call to
|
// The memory we need here will have already been allocated during an earlier call to
|
||||||
// `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead
|
// `addr_from_alloc_id` for this allocation. So don't create a new `MiriAllocBytes` here, instead
|
||||||
// fetch the previously prepared bytes from `prepared_alloc_bytes`.
|
// fetch the previously prepared bytes from `prepared_alloc_bytes`.
|
||||||
|
let mut global_state = ecx.machine.alloc_addresses.borrow_mut();
|
||||||
let mut prepared_alloc_bytes = global_state
|
let mut prepared_alloc_bytes = global_state
|
||||||
.prepared_alloc_bytes
|
.prepared_alloc_bytes
|
||||||
.remove(&id)
|
.remove(&id)
|
||||||
@ -378,10 +391,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
assert_eq!(prepared_alloc_bytes.len(), bytes.len());
|
assert_eq!(prepared_alloc_bytes.len(), bytes.len());
|
||||||
// Copy allocation contents into prepared memory.
|
// Copy allocation contents into prepared memory.
|
||||||
prepared_alloc_bytes.copy_from_slice(bytes);
|
prepared_alloc_bytes.copy_from_slice(bytes);
|
||||||
prepared_alloc_bytes
|
Ok(prepared_alloc_bytes)
|
||||||
} else {
|
} else {
|
||||||
MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(&*bytes), align)
|
Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When a pointer is used for a memory access, this computes where in which allocation the
|
/// When a pointer is used for a memory access, this computes where in which allocation the
|
||||||
|
@ -35,8 +35,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
offset: u64,
|
offset: u64,
|
||||||
) -> InterpResult<'tcx, InitOnceId> {
|
) -> InterpResult<'tcx, InitOnceId> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.init_onces)?
|
this.get_or_create_id(
|
||||||
.ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
|
lock_op,
|
||||||
|
lock_layout,
|
||||||
|
offset,
|
||||||
|
|ecx| &mut ecx.machine.sync.init_onces,
|
||||||
|
|_| Ok(Default::default()),
|
||||||
|
)?
|
||||||
|
.ok_or_else(|| err_ub_format!("init_once has invalid ID").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -66,6 +66,27 @@ pub(super) use declare_id;
|
|||||||
|
|
||||||
declare_id!(MutexId);
|
declare_id!(MutexId);
|
||||||
|
|
||||||
|
/// The mutex kind.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum MutexKind {
|
||||||
|
Invalid,
|
||||||
|
Normal,
|
||||||
|
Default,
|
||||||
|
Recursive,
|
||||||
|
ErrorCheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Additional data that may be used by shim implementations.
|
||||||
|
pub struct AdditionalMutexData {
|
||||||
|
/// The mutex kind, used by some mutex implementations like pthreads mutexes.
|
||||||
|
pub kind: MutexKind,
|
||||||
|
|
||||||
|
/// The address of the mutex.
|
||||||
|
pub address: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// The mutex state.
|
/// The mutex state.
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct Mutex {
|
struct Mutex {
|
||||||
@ -77,6 +98,9 @@ struct Mutex {
|
|||||||
queue: VecDeque<ThreadId>,
|
queue: VecDeque<ThreadId>,
|
||||||
/// Mutex clock. This tracks the moment of the last unlock.
|
/// Mutex clock. This tracks the moment of the last unlock.
|
||||||
clock: VClock,
|
clock: VClock,
|
||||||
|
|
||||||
|
/// Additional data that can be set by shim implementations.
|
||||||
|
data: Option<AdditionalMutexData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_id!(RwLockId);
|
declare_id!(RwLockId);
|
||||||
@ -168,13 +192,15 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
/// Returns `None` if memory stores a non-zero invalid ID.
|
/// Returns `None` if memory stores a non-zero invalid ID.
|
||||||
///
|
///
|
||||||
/// `get_objs` must return the `IndexVec` that stores all the objects of this type.
|
/// `get_objs` must return the `IndexVec` that stores all the objects of this type.
|
||||||
|
/// `create_obj` must create the new object if initialization is needed.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_or_create_id<Id: SyncId + Idx, T: Default>(
|
fn get_or_create_id<Id: SyncId + Idx, T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
lock_op: &OpTy<'tcx>,
|
lock_op: &OpTy<'tcx>,
|
||||||
lock_layout: TyAndLayout<'tcx>,
|
lock_layout: TyAndLayout<'tcx>,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
|
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
|
||||||
|
create_obj: impl for<'a> FnOnce(&'a mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, T>,
|
||||||
) -> InterpResult<'tcx, Option<Id>> {
|
) -> InterpResult<'tcx, Option<Id>> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
let value_place =
|
let value_place =
|
||||||
@ -196,7 +222,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
|
Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") {
|
||||||
// We set the in-memory ID to `next_index`, now also create this object in the machine
|
// We set the in-memory ID to `next_index`, now also create this object in the machine
|
||||||
// state.
|
// state.
|
||||||
let new_index = get_objs(this).push(T::default());
|
let obj = create_obj(this)?;
|
||||||
|
let new_index = get_objs(this).push(obj);
|
||||||
assert_eq!(next_index, new_index);
|
assert_eq!(next_index, new_index);
|
||||||
Some(new_index)
|
Some(new_index)
|
||||||
} else {
|
} else {
|
||||||
@ -210,6 +237,32 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Eagerly creates a Miri sync structure.
|
||||||
|
///
|
||||||
|
/// `create_id` will store the index of the sync_structure in the memory pointed to by
|
||||||
|
/// `lock_op`, so that future calls to `get_or_create_id` will see it as initialized.
|
||||||
|
/// - `lock_op` must hold a pointer to the sync structure.
|
||||||
|
/// - `lock_layout` must be the memory layout of the sync structure.
|
||||||
|
/// - `offset` must be the offset inside the sync structure where its miri id will be stored.
|
||||||
|
/// - `get_objs` is described in `get_or_create_id`.
|
||||||
|
/// - `obj` must be the new sync object.
|
||||||
|
fn create_id<Id: SyncId + Idx, T>(
|
||||||
|
&mut self,
|
||||||
|
lock_op: &OpTy<'tcx>,
|
||||||
|
lock_layout: TyAndLayout<'tcx>,
|
||||||
|
offset: u64,
|
||||||
|
get_objs: impl for<'a> Fn(&'a mut MiriInterpCx<'tcx>) -> &'a mut IndexVec<Id, T>,
|
||||||
|
obj: T,
|
||||||
|
) -> InterpResult<'tcx, Id> {
|
||||||
|
let this = self.eval_context_mut();
|
||||||
|
let value_place =
|
||||||
|
this.deref_pointer_and_offset(lock_op, offset, lock_layout, this.machine.layouts.u32)?;
|
||||||
|
|
||||||
|
let new_index = get_objs(this).push(obj);
|
||||||
|
this.write_scalar(Scalar::from_u32(new_index.to_u32()), &value_place)?;
|
||||||
|
Ok(new_index)
|
||||||
|
}
|
||||||
|
|
||||||
fn condvar_reacquire_mutex(
|
fn condvar_reacquire_mutex(
|
||||||
&mut self,
|
&mut self,
|
||||||
mutex: MutexId,
|
mutex: MutexId,
|
||||||
@ -236,15 +289,53 @@ pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
// situations.
|
// situations.
|
||||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||||
|
/// Eagerly create and initialize a new mutex.
|
||||||
|
fn mutex_create(
|
||||||
|
&mut self,
|
||||||
|
lock_op: &OpTy<'tcx>,
|
||||||
|
lock_layout: TyAndLayout<'tcx>,
|
||||||
|
offset: u64,
|
||||||
|
data: Option<AdditionalMutexData>,
|
||||||
|
) -> InterpResult<'tcx, MutexId> {
|
||||||
|
let this = self.eval_context_mut();
|
||||||
|
this.create_id(
|
||||||
|
lock_op,
|
||||||
|
lock_layout,
|
||||||
|
offset,
|
||||||
|
|ecx| &mut ecx.machine.sync.mutexes,
|
||||||
|
Mutex { data, ..Default::default() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lazily create a new mutex.
|
||||||
|
/// `initialize_data` must return any additional data that a user wants to associate with the mutex.
|
||||||
fn mutex_get_or_create_id(
|
fn mutex_get_or_create_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
lock_op: &OpTy<'tcx>,
|
lock_op: &OpTy<'tcx>,
|
||||||
lock_layout: TyAndLayout<'tcx>,
|
lock_layout: TyAndLayout<'tcx>,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
|
initialize_data: impl for<'a> FnOnce(
|
||||||
|
&'a mut MiriInterpCx<'tcx>,
|
||||||
|
) -> InterpResult<'tcx, Option<AdditionalMutexData>>,
|
||||||
) -> InterpResult<'tcx, MutexId> {
|
) -> InterpResult<'tcx, MutexId> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.mutexes)?
|
this.get_or_create_id(
|
||||||
.ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
|
lock_op,
|
||||||
|
lock_layout,
|
||||||
|
offset,
|
||||||
|
|ecx| &mut ecx.machine.sync.mutexes,
|
||||||
|
|ecx| initialize_data(ecx).map(|data| Mutex { data, ..Default::default() }),
|
||||||
|
)?
|
||||||
|
.ok_or_else(|| err_ub_format!("mutex has invalid ID").into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the additional data stored for a mutex.
|
||||||
|
fn mutex_get_data<'a>(&'a mut self, id: MutexId) -> Option<&'a AdditionalMutexData>
|
||||||
|
where
|
||||||
|
'tcx: 'a,
|
||||||
|
{
|
||||||
|
let this = self.eval_context_ref();
|
||||||
|
this.machine.sync.mutexes[id].data.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rwlock_get_or_create_id(
|
fn rwlock_get_or_create_id(
|
||||||
@ -254,8 +345,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
offset: u64,
|
offset: u64,
|
||||||
) -> InterpResult<'tcx, RwLockId> {
|
) -> InterpResult<'tcx, RwLockId> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.rwlocks)?
|
this.get_or_create_id(
|
||||||
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
|
lock_op,
|
||||||
|
lock_layout,
|
||||||
|
offset,
|
||||||
|
|ecx| &mut ecx.machine.sync.rwlocks,
|
||||||
|
|_| Ok(Default::default()),
|
||||||
|
)?
|
||||||
|
.ok_or_else(|| err_ub_format!("rwlock has invalid ID").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn condvar_get_or_create_id(
|
fn condvar_get_or_create_id(
|
||||||
@ -265,8 +362,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
offset: u64,
|
offset: u64,
|
||||||
) -> InterpResult<'tcx, CondvarId> {
|
) -> InterpResult<'tcx, CondvarId> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
this.get_or_create_id(lock_op, lock_layout, offset, |ecx| &mut ecx.machine.sync.condvars)?
|
this.get_or_create_id(
|
||||||
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
|
lock_op,
|
||||||
|
lock_layout,
|
||||||
|
offset,
|
||||||
|
|ecx| &mut ecx.machine.sync.condvars,
|
||||||
|
|_| Ok(Default::default()),
|
||||||
|
)?
|
||||||
|
.ok_or_else(|| err_ub_format!("condvar has invalid ID").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -888,8 +888,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
}
|
}
|
||||||
let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
|
||||||
// We make a full copy of this allocation.
|
// We make a full copy of this allocation.
|
||||||
let mut alloc =
|
let mut alloc = alloc.inner().adjust_from_tcx(
|
||||||
alloc.inner().adjust_from_tcx(&this.tcx, |bytes, align| Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align)), |ptr| this.global_root_pointer(ptr))?;
|
&this.tcx,
|
||||||
|
|bytes, align| {
|
||||||
|
Ok(MiriAllocBytes::from_bytes(std::borrow::Cow::Borrowed(bytes), align))
|
||||||
|
},
|
||||||
|
|ptr| this.global_root_pointer(ptr),
|
||||||
|
)?;
|
||||||
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
// This allocation will be deallocated when the thread dies, so it is not in read-only memory.
|
||||||
alloc.mutability = Mutability::Mut;
|
alloc.mutability = Mutability::Mut;
|
||||||
// Create a fresh allocation with this content.
|
// Create a fresh allocation with this content.
|
||||||
|
@ -133,7 +133,10 @@ pub use crate::concurrency::{
|
|||||||
cpu_affinity::MAX_CPUS,
|
cpu_affinity::MAX_CPUS,
|
||||||
data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
|
data_race::{AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as _},
|
||||||
init_once::{EvalContextExt as _, InitOnceId},
|
init_once::{EvalContextExt as _, InitOnceId},
|
||||||
sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects},
|
sync::{
|
||||||
|
AdditionalMutexData, CondvarId, EvalContextExt as _, MutexId, MutexKind, RwLockId,
|
||||||
|
SynchronizationObjects,
|
||||||
|
},
|
||||||
thread::{
|
thread::{
|
||||||
BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager,
|
BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager,
|
||||||
TimeoutAnchor, TimeoutClock, UnblockCallback,
|
TimeoutAnchor, TimeoutClock, UnblockCallback,
|
||||||
|
@ -535,9 +535,9 @@ pub struct MiriMachine<'tcx> {
|
|||||||
pub(crate) basic_block_count: u64,
|
pub(crate) basic_block_count: u64,
|
||||||
|
|
||||||
/// Handle of the optional shared object file for native functions.
|
/// Handle of the optional shared object file for native functions.
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(unix)]
|
||||||
pub native_lib: Option<(libloading::Library, std::path::PathBuf)>,
|
pub native_lib: Option<(libloading::Library, std::path::PathBuf)>,
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(unix))]
|
||||||
pub native_lib: Option<!>,
|
pub native_lib: Option<!>,
|
||||||
|
|
||||||
/// Run a garbage collector for BorTags every N basic blocks.
|
/// Run a garbage collector for BorTags every N basic blocks.
|
||||||
@ -678,7 +678,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||||||
report_progress: config.report_progress,
|
report_progress: config.report_progress,
|
||||||
basic_block_count: 0,
|
basic_block_count: 0,
|
||||||
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
|
clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(unix)]
|
||||||
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
|
native_lib: config.native_lib.as_ref().map(|lib_file_path| {
|
||||||
let target_triple = layout_cx.tcx.sess.opts.target_triple.triple();
|
let target_triple = layout_cx.tcx.sess.opts.target_triple.triple();
|
||||||
// Check if host target == the session target.
|
// Check if host target == the session target.
|
||||||
@ -700,9 +700,9 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||||||
lib_file_path.clone(),
|
lib_file_path.clone(),
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(unix))]
|
||||||
native_lib: config.native_lib.as_ref().map(|_| {
|
native_lib: config.native_lib.as_ref().map(|_| {
|
||||||
panic!("loading external .so files is only supported on Linux")
|
panic!("calling functions from native libraries via FFI is only supported on Unix")
|
||||||
}),
|
}),
|
||||||
gc_interval: config.gc_interval,
|
gc_interval: config.gc_interval,
|
||||||
since_gc: 0,
|
since_gc: 0,
|
||||||
@ -1277,12 +1277,12 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||||||
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
|
||||||
{
|
{
|
||||||
let kind = Self::GLOBAL_KIND.unwrap().into();
|
let kind = Self::GLOBAL_KIND.unwrap().into();
|
||||||
let alloc = alloc.adjust_from_tcx(&ecx.tcx,
|
let alloc = alloc.adjust_from_tcx(
|
||||||
|
&ecx.tcx,
|
||||||
|bytes, align| ecx.get_global_alloc_bytes(id, kind, bytes, align),
|
|bytes, align| ecx.get_global_alloc_bytes(id, kind, bytes, align),
|
||||||
|ptr| ecx.global_root_pointer(ptr),
|
|ptr| ecx.global_root_pointer(ptr),
|
||||||
)?;
|
)?;
|
||||||
let extra =
|
let extra = Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?;
|
||||||
Self::init_alloc_extra(ecx, id, kind, alloc.size(), alloc.align)?;
|
|
||||||
Ok(Cow::Owned(alloc.with_extra(extra)))
|
Ok(Cow::Owned(alloc.with_extra(extra)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
// First deal with any external C functions in linked .so file.
|
// First deal with any external C functions in linked .so file.
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(unix)]
|
||||||
if this.machine.native_lib.as_ref().is_some() {
|
if this.machine.native_lib.as_ref().is_some() {
|
||||||
use crate::shims::native_lib::EvalContextExt as _;
|
use crate::shims::native_lib::EvalContextExt as _;
|
||||||
// An Ok(false) here means that the function being called was not exported
|
// An Ok(false) here means that the function being called was not exported
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
mod alloc;
|
mod alloc;
|
||||||
mod backtrace;
|
mod backtrace;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(unix)]
|
||||||
mod native_lib;
|
mod native_lib;
|
||||||
mod unix;
|
mod unix;
|
||||||
mod wasi;
|
mod wasi;
|
||||||
|
@ -240,13 +240,16 @@ fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'t
|
|||||||
ty::RawPtr(_, mutability) => {
|
ty::RawPtr(_, mutability) => {
|
||||||
// Arbitrary mutable pointer accesses are not currently supported in Miri.
|
// Arbitrary mutable pointer accesses are not currently supported in Miri.
|
||||||
if mutability.is_mut() {
|
if mutability.is_mut() {
|
||||||
throw_unsup_format!("unsupported mutable pointer type for native call: {}", v.layout.ty);
|
throw_unsup_format!(
|
||||||
|
"unsupported mutable pointer type for native call: {}",
|
||||||
|
v.layout.ty
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let s = v.to_scalar().to_pointer(cx)?.addr();
|
let s = v.to_scalar().to_pointer(cx)?.addr();
|
||||||
// This relies on the `expose_provenance` in `addr_from_alloc_id`.
|
// This relies on the `expose_provenance` in `addr_from_alloc_id`.
|
||||||
CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize()))
|
CArg::RawPtr(std::ptr::with_exposed_provenance_mut(s.bytes_usize()))
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
|
_ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
// os_unfair_lock holds a 32-bit value, is initialized with zero and
|
// os_unfair_lock holds a 32-bit value, is initialized with zero and
|
||||||
// must be assumed to be opaque. Therefore, we can just store our
|
// must be assumed to be opaque. Therefore, we can just store our
|
||||||
// internal mutex ID in the structure without anyone noticing.
|
// internal mutex ID in the structure without anyone noticing.
|
||||||
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0)
|
this.mutex_get_or_create_id(lock_op, this.libc_ty_layout("os_unfair_lock"), 0, |_| Ok(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResu
|
|||||||
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
|
// pthread_mutex_t is between 24 and 48 bytes, depending on the platform.
|
||||||
// We ignore the platform layout and store our own fields:
|
// We ignore the platform layout and store our own fields:
|
||||||
// - id: u32
|
// - id: u32
|
||||||
// - kind: i32
|
|
||||||
|
|
||||||
fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
||||||
let offset = match &*ecx.tcx.sess.target.os {
|
let offset = match &*ecx.tcx.sess.target.os {
|
||||||
@ -74,6 +73,8 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
|||||||
|
|
||||||
// Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once):
|
// Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once):
|
||||||
// the id must start out as 0.
|
// the id must start out as 0.
|
||||||
|
// FIXME on some platforms (e.g linux) there are more static initializers for
|
||||||
|
// recursive or error checking mutexes. We should also add thme in this sanity check.
|
||||||
static SANITY: AtomicBool = AtomicBool::new(false);
|
static SANITY: AtomicBool = AtomicBool::new(false);
|
||||||
if !SANITY.swap(true, Ordering::Relaxed) {
|
if !SANITY.swap(true, Ordering::Relaxed) {
|
||||||
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]);
|
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]);
|
||||||
@ -90,79 +91,92 @@ fn mutex_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> {
|
|||||||
Ok(offset)
|
Ok(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutex_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 {
|
/// Eagerly create and initialize a new mutex.
|
||||||
// These offsets are picked for compatibility with Linux's static initializer
|
fn mutex_create<'tcx>(
|
||||||
// macros, e.g. PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP.)
|
ecx: &mut MiriInterpCx<'tcx>,
|
||||||
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
|
mutex_op: &OpTy<'tcx>,
|
||||||
|
kind: i32,
|
||||||
// Sanity-check this against PTHREAD_MUTEX_INITIALIZER (but only once):
|
) -> InterpResult<'tcx> {
|
||||||
// the kind must start out as PTHREAD_MUTEX_DEFAULT.
|
// FIXME: might be worth changing mutex_create to take the mplace
|
||||||
static SANITY: AtomicBool = AtomicBool::new(false);
|
// rather than the `OpTy`.
|
||||||
if !SANITY.swap(true, Ordering::Relaxed) {
|
let address = ecx.read_pointer(mutex_op)?.addr().bytes();
|
||||||
let static_initializer = ecx.eval_path(&["libc", "PTHREAD_MUTEX_INITIALIZER"]);
|
let kind = translate_kind(ecx, kind)?;
|
||||||
let kind_field = static_initializer
|
let data = Some(AdditionalMutexData { address, kind });
|
||||||
.offset(Size::from_bytes(mutex_kind_offset(ecx)), ecx.machine.layouts.i32, ecx)
|
ecx.mutex_create(mutex_op, ecx.libc_ty_layout("pthread_mutex_t"), mutex_id_offset(ecx)?, data)?;
|
||||||
.unwrap();
|
Ok(())
|
||||||
let kind = ecx.read_scalar(&kind_field).unwrap().to_i32().unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
kind,
|
|
||||||
ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"),
|
|
||||||
"PTHREAD_MUTEX_INITIALIZER is incompatible with our pthread_mutex layout: kind is not PTHREAD_MUTEX_DEFAULT"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
offset
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `MutexId` of the mutex stored at `mutex_op`.
|
||||||
|
///
|
||||||
|
/// `mutex_get_id` will also check if the mutex has been moved since its first use and
|
||||||
|
/// return an error if it has.
|
||||||
fn mutex_get_id<'tcx>(
|
fn mutex_get_id<'tcx>(
|
||||||
ecx: &mut MiriInterpCx<'tcx>,
|
ecx: &mut MiriInterpCx<'tcx>,
|
||||||
mutex_op: &OpTy<'tcx>,
|
mutex_op: &OpTy<'tcx>,
|
||||||
) -> InterpResult<'tcx, MutexId> {
|
) -> InterpResult<'tcx, MutexId> {
|
||||||
ecx.mutex_get_or_create_id(
|
let address = ecx.read_pointer(mutex_op)?.addr().bytes();
|
||||||
|
|
||||||
|
// FIXME: might be worth changing mutex_get_or_create_id to take the mplace
|
||||||
|
// rather than the `OpTy`.
|
||||||
|
let id = ecx.mutex_get_or_create_id(
|
||||||
mutex_op,
|
mutex_op,
|
||||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
ecx.libc_ty_layout("pthread_mutex_t"),
|
||||||
mutex_id_offset(ecx)?,
|
mutex_id_offset(ecx)?,
|
||||||
)
|
|ecx| {
|
||||||
|
// This is called if a static initializer was used and the lock has not been assigned
|
||||||
|
// an ID yet. We have to determine the mutex kind from the static initializer.
|
||||||
|
let kind = kind_from_static_initializer(ecx, mutex_op)?;
|
||||||
|
|
||||||
|
Ok(Some(AdditionalMutexData { kind, address }))
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Check that the mutex has not been moved since last use.
|
||||||
|
let data = ecx.mutex_get_data(id).expect("data should be always exist for pthreads");
|
||||||
|
if data.address != address {
|
||||||
|
throw_ub_format!("pthread_mutex_t can't be moved after first use")
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutex_reset_id<'tcx>(
|
/// Returns the kind of a static initializer.
|
||||||
ecx: &mut MiriInterpCx<'tcx>,
|
fn kind_from_static_initializer<'tcx>(
|
||||||
mutex_op: &OpTy<'tcx>,
|
|
||||||
) -> InterpResult<'tcx, ()> {
|
|
||||||
ecx.deref_pointer_and_write(
|
|
||||||
mutex_op,
|
|
||||||
mutex_id_offset(ecx)?,
|
|
||||||
Scalar::from_u32(0),
|
|
||||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
|
||||||
ecx.machine.layouts.u32,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mutex_get_kind<'tcx>(
|
|
||||||
ecx: &MiriInterpCx<'tcx>,
|
ecx: &MiriInterpCx<'tcx>,
|
||||||
mutex_op: &OpTy<'tcx>,
|
mutex_op: &OpTy<'tcx>,
|
||||||
) -> InterpResult<'tcx, i32> {
|
) -> InterpResult<'tcx, MutexKind> {
|
||||||
ecx.deref_pointer_and_read(
|
// Only linux has static initializers other than PTHREAD_MUTEX_DEFAULT.
|
||||||
mutex_op,
|
let kind = match &*ecx.tcx.sess.target.os {
|
||||||
mutex_kind_offset(ecx),
|
"linux" => {
|
||||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 };
|
||||||
ecx.machine.layouts.i32,
|
|
||||||
)?
|
ecx.deref_pointer_and_read(
|
||||||
.to_i32()
|
mutex_op,
|
||||||
|
offset,
|
||||||
|
ecx.libc_ty_layout("pthread_mutex_t"),
|
||||||
|
ecx.machine.layouts.i32,
|
||||||
|
)?
|
||||||
|
.to_i32()?
|
||||||
|
}
|
||||||
|
| "illumos" | "solaris" | "macos" => ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"),
|
||||||
|
os => throw_unsup_format!("`pthread_mutex` is not supported on {os}"),
|
||||||
|
};
|
||||||
|
|
||||||
|
translate_kind(ecx, kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mutex_set_kind<'tcx>(
|
fn translate_kind<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, MutexKind> {
|
||||||
ecx: &mut MiriInterpCx<'tcx>,
|
Ok(if is_mutex_kind_default(ecx, kind)? {
|
||||||
mutex_op: &OpTy<'tcx>,
|
MutexKind::Default
|
||||||
kind: i32,
|
} else if is_mutex_kind_normal(ecx, kind)? {
|
||||||
) -> InterpResult<'tcx, ()> {
|
MutexKind::Normal
|
||||||
ecx.deref_pointer_and_write(
|
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
|
||||||
mutex_op,
|
MutexKind::ErrorCheck
|
||||||
mutex_kind_offset(ecx),
|
} else if kind == ecx.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
||||||
Scalar::from_i32(kind),
|
MutexKind::Recursive
|
||||||
ecx.libc_ty_layout("pthread_mutex_t"),
|
} else {
|
||||||
ecx.machine.layouts.i32,
|
throw_unsup_format!("unsupported type of mutex: {kind}");
|
||||||
)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
|
// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform.
|
||||||
@ -452,10 +466,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
mutexattr_get_kind(this, attr_op)?
|
mutexattr_get_kind(this, attr_op)?
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write 0 to use the same code path as the static initializers.
|
mutex_create(this, mutex_op, kind)?;
|
||||||
mutex_reset_id(this, mutex_op)?;
|
|
||||||
|
|
||||||
mutex_set_kind(this, mutex_op, kind)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -467,8 +478,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
) -> InterpResult<'tcx> {
|
) -> InterpResult<'tcx> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
let kind = mutex_get_kind(this, mutex_op)?;
|
|
||||||
let id = mutex_get_id(this, mutex_op)?;
|
let id = mutex_get_id(this, mutex_op)?;
|
||||||
|
let kind =
|
||||||
|
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||||
|
|
||||||
let ret = if this.mutex_is_locked(id) {
|
let ret = if this.mutex_is_locked(id) {
|
||||||
let owner_thread = this.mutex_get_owner(id);
|
let owner_thread = this.mutex_get_owner(id);
|
||||||
@ -477,19 +489,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
// Trying to acquire the same mutex again.
|
// Trying to acquire the same mutex again.
|
||||||
if is_mutex_kind_default(this, kind)? {
|
match kind {
|
||||||
throw_ub_format!("trying to acquire already locked default mutex");
|
MutexKind::Default =>
|
||||||
} else if is_mutex_kind_normal(this, kind)? {
|
throw_ub_format!("trying to acquire already locked default mutex"),
|
||||||
throw_machine_stop!(TerminationInfo::Deadlock);
|
MutexKind::Normal => throw_machine_stop!(TerminationInfo::Deadlock),
|
||||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
|
MutexKind::ErrorCheck => this.eval_libc_i32("EDEADLK"),
|
||||||
this.eval_libc_i32("EDEADLK")
|
MutexKind::Recursive => {
|
||||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
this.mutex_lock(id);
|
||||||
this.mutex_lock(id);
|
0
|
||||||
0
|
}
|
||||||
} else {
|
_ =>
|
||||||
throw_unsup_format!(
|
throw_unsup_format!(
|
||||||
"called pthread_mutex_lock on an unsupported type of mutex"
|
"called pthread_mutex_lock on an unsupported type of mutex"
|
||||||
);
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -504,26 +516,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
let kind = mutex_get_kind(this, mutex_op)?;
|
|
||||||
let id = mutex_get_id(this, mutex_op)?;
|
let id = mutex_get_id(this, mutex_op)?;
|
||||||
|
let kind =
|
||||||
|
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||||
|
|
||||||
Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
|
Ok(Scalar::from_i32(if this.mutex_is_locked(id) {
|
||||||
let owner_thread = this.mutex_get_owner(id);
|
let owner_thread = this.mutex_get_owner(id);
|
||||||
if owner_thread != this.active_thread() {
|
if owner_thread != this.active_thread() {
|
||||||
this.eval_libc_i32("EBUSY")
|
this.eval_libc_i32("EBUSY")
|
||||||
} else {
|
} else {
|
||||||
if is_mutex_kind_default(this, kind)?
|
match kind {
|
||||||
|| is_mutex_kind_normal(this, kind)?
|
MutexKind::Default | MutexKind::Normal | MutexKind::ErrorCheck =>
|
||||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
this.eval_libc_i32("EBUSY"),
|
||||||
{
|
MutexKind::Recursive => {
|
||||||
this.eval_libc_i32("EBUSY")
|
this.mutex_lock(id);
|
||||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
0
|
||||||
this.mutex_lock(id);
|
}
|
||||||
0
|
_ =>
|
||||||
} else {
|
throw_unsup_format!(
|
||||||
throw_unsup_format!(
|
"called pthread_mutex_trylock on an unsupported type of mutex"
|
||||||
"called pthread_mutex_trylock on an unsupported type of mutex"
|
),
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -536,8 +548,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
|
||||||
let this = self.eval_context_mut();
|
let this = self.eval_context_mut();
|
||||||
|
|
||||||
let kind = mutex_get_kind(this, mutex_op)?;
|
|
||||||
let id = mutex_get_id(this, mutex_op)?;
|
let id = mutex_get_id(this, mutex_op)?;
|
||||||
|
let kind =
|
||||||
|
this.mutex_get_data(id).expect("data should always exist for pthread mutexes").kind;
|
||||||
|
|
||||||
if let Some(_old_locked_count) = this.mutex_unlock(id)? {
|
if let Some(_old_locked_count) = this.mutex_unlock(id)? {
|
||||||
// The mutex was locked by the current thread.
|
// The mutex was locked by the current thread.
|
||||||
@ -546,20 +559,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
// The mutex was locked by another thread or not locked at all. See
|
// The mutex was locked by another thread or not locked at all. See
|
||||||
// the “Unlock When Not Owner” column in
|
// the “Unlock When Not Owner” column in
|
||||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html.
|
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html.
|
||||||
if is_mutex_kind_default(this, kind)? {
|
match kind {
|
||||||
throw_ub_format!(
|
MutexKind::Default =>
|
||||||
"unlocked a default mutex that was not locked by the current thread"
|
throw_ub_format!(
|
||||||
);
|
"unlocked a default mutex that was not locked by the current thread"
|
||||||
} else if is_mutex_kind_normal(this, kind)? {
|
),
|
||||||
throw_ub_format!(
|
MutexKind::Normal =>
|
||||||
"unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread"
|
throw_ub_format!(
|
||||||
);
|
"unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread"
|
||||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
),
|
||||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
|
MutexKind::ErrorCheck | MutexKind::Recursive =>
|
||||||
{
|
Ok(Scalar::from_i32(this.eval_libc_i32("EPERM"))),
|
||||||
Ok(Scalar::from_i32(this.eval_libc_i32("EPERM")))
|
_ =>
|
||||||
} else {
|
throw_unsup_format!(
|
||||||
throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex");
|
"called pthread_mutex_unlock on an unsupported type of mutex"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,7 +588,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
|
// Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit.
|
||||||
mutex_get_kind(this, mutex_op)?;
|
|
||||||
mutex_get_id(this, mutex_op)?;
|
mutex_get_id(this, mutex_op)?;
|
||||||
|
|
||||||
// This might lead to false positives, see comment in pthread_mutexattr_destroy
|
// This might lead to false positives, see comment in pthread_mutexattr_destroy
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
error: Undefined Behavior: pthread_mutex_t can't be moved after first use
|
||||||
|
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | libc::pthread_mutex_lock(&mut m2 as *mut _);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use
|
||||||
|
|
|
||||||
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `check` at $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | check();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -0,0 +1,28 @@
|
|||||||
|
//@ignore-target-windows: No pthreads on Windows
|
||||||
|
//@revisions: static_initializer init
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(init)]
|
||||||
|
fn check() {
|
||||||
|
unsafe {
|
||||||
|
let mut m: libc::pthread_mutex_t = std::mem::zeroed();
|
||||||
|
assert_eq!(libc::pthread_mutex_init(&mut m as *mut _, std::ptr::null()), 0);
|
||||||
|
|
||||||
|
let mut m2 = m; // move the mutex
|
||||||
|
libc::pthread_mutex_lock(&mut m2 as *mut _); //~[init] ERROR: pthread_mutex_t can't be moved after first use
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(static_initializer)]
|
||||||
|
fn check() {
|
||||||
|
unsafe {
|
||||||
|
let mut m: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
libc::pthread_mutex_lock(&mut m as *mut _);
|
||||||
|
|
||||||
|
let mut m2 = m; // move the mutex
|
||||||
|
libc::pthread_mutex_unlock(&mut m2 as *mut _); //~[static_initializer] ERROR: pthread_mutex_t can't be moved after first use
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
error: Undefined Behavior: pthread_mutex_t can't be moved after first use
|
||||||
|
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | libc::pthread_mutex_unlock(&mut m2 as *mut _);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pthread_mutex_t can't be moved after first use
|
||||||
|
|
|
||||||
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||||
|
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `check` at $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
note: inside `main`
|
||||||
|
--> $DIR/libc_pthread_mutex_move.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | check();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,4 +1,6 @@
|
|||||||
//@only-target-linux
|
// Only works on Unix targets
|
||||||
|
//@ignore-target-windows
|
||||||
|
//@ignore-target-wasm
|
||||||
//@only-on-host
|
//@only-on-host
|
||||||
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
|
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
|
||||||
|
|
||||||
|
15
src/tools/miri/tests/native-lib/fail/private_function.rs
Normal file
15
src/tools/miri/tests/native-lib/fail/private_function.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Only works on Unix targets
|
||||||
|
//@ignore-target-windows
|
||||||
|
//@ignore-target-wasm
|
||||||
|
//@only-on-host
|
||||||
|
//@normalize-stderr-test: "OS `.*`" -> "$$OS"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn not_exported();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
unsafe {
|
||||||
|
not_exported(); //~ ERROR: unsupported operation: can't call foreign function `not_exported`
|
||||||
|
}
|
||||||
|
}
|
15
src/tools/miri/tests/native-lib/fail/private_function.stderr
Normal file
15
src/tools/miri/tests/native-lib/fail/private_function.stderr
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
error: unsupported operation: can't call foreign function `not_exported` on $OS
|
||||||
|
--> $DIR/private_function.rs:LL:CC
|
||||||
|
|
|
||||||
|
LL | not_exported();
|
||||||
|
| ^^^^^^^^^^^^^^ can't call foreign function `not_exported` on $OS
|
||||||
|
|
|
||||||
|
= help: if this is a basic API commonly used on this target, please report an issue with Miri
|
||||||
|
= help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases
|
||||||
|
= note: BACKTRACE:
|
||||||
|
= note: inside `main` at $DIR/private_function.rs:LL:CC
|
||||||
|
|
||||||
|
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
@ -1,20 +0,0 @@
|
|||||||
CODEABI_1.0 {
|
|
||||||
# Define which symbols to export.
|
|
||||||
global:
|
|
||||||
# scalar_arguments.c
|
|
||||||
add_one_int;
|
|
||||||
printer;
|
|
||||||
test_stack_spill;
|
|
||||||
get_unsigned_int;
|
|
||||||
add_int16;
|
|
||||||
add_short_to_long;
|
|
||||||
|
|
||||||
# ptr_read_access.c
|
|
||||||
print_pointer;
|
|
||||||
access_simple;
|
|
||||||
access_nested;
|
|
||||||
access_static;
|
|
||||||
|
|
||||||
# The rest remains private.
|
|
||||||
local: *;
|
|
||||||
};
|
|
@ -1,4 +1,6 @@
|
|||||||
//@only-target-linux
|
// Only works on Unix targets
|
||||||
|
//@ignore-target-windows
|
||||||
|
//@ignore-target-wasm
|
||||||
//@only-on-host
|
//@only-on-host
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -26,7 +28,7 @@ fn test_pointer() {
|
|||||||
fn test_simple() {
|
fn test_simple() {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Simple {
|
struct Simple {
|
||||||
field: i32
|
field: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -41,7 +43,7 @@ fn test_simple() {
|
|||||||
// Test function that dereferences nested struct pointers and accesses fields.
|
// Test function that dereferences nested struct pointers and accesses fields.
|
||||||
fn test_nested() {
|
fn test_nested() {
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Nested {
|
struct Nested {
|
||||||
@ -62,7 +64,6 @@ fn test_nested() {
|
|||||||
|
|
||||||
// Test function that dereferences static struct pointers and accesses fields.
|
// Test function that dereferences static struct pointers and accesses fields.
|
||||||
fn test_static() {
|
fn test_static() {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Static {
|
struct Static {
|
||||||
value: i32,
|
value: i32,
|
||||||
@ -72,11 +73,8 @@ fn test_static() {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
fn access_static(n_ptr: *const Static) -> i32;
|
fn access_static(n_ptr: *const Static) -> i32;
|
||||||
}
|
}
|
||||||
|
|
||||||
static STATIC: Static = Static {
|
static STATIC: Static = Static { value: 9001, recurse: &STATIC };
|
||||||
value: 9001,
|
|
||||||
recurse: &STATIC,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(unsafe { access_static(&STATIC) }, 9001);
|
assert_eq!(unsafe { access_static(&STATIC) }, 9001);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
//@only-target-linux
|
// Only works on Unix targets
|
||||||
|
//@ignore-target-windows
|
||||||
|
//@ignore-target-wasm
|
||||||
//@only-on-host
|
//@only-on-host
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// See comments in build_native_lib()
|
||||||
|
#define EXPORT __attribute__((visibility("default")))
|
||||||
|
|
||||||
/* Test: test_pointer */
|
/* Test: test_pointer */
|
||||||
|
|
||||||
void print_pointer(const int *ptr) {
|
EXPORT void print_pointer(const int *ptr) {
|
||||||
printf("printing pointer dereference from C: %d\n", *ptr);
|
printf("printing pointer dereference from C: %d\n", *ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12,7 +15,7 @@ typedef struct Simple {
|
|||||||
int field;
|
int field;
|
||||||
} Simple;
|
} Simple;
|
||||||
|
|
||||||
int access_simple(const Simple *s_ptr) {
|
EXPORT int access_simple(const Simple *s_ptr) {
|
||||||
return s_ptr->field;
|
return s_ptr->field;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +27,7 @@ typedef struct Nested {
|
|||||||
} Nested;
|
} Nested;
|
||||||
|
|
||||||
// Returns the innermost/last value of a Nested pointer chain.
|
// Returns the innermost/last value of a Nested pointer chain.
|
||||||
int access_nested(const Nested *n_ptr) {
|
EXPORT int access_nested(const Nested *n_ptr) {
|
||||||
// Edge case: `n_ptr == NULL` (i.e. first Nested is None).
|
// Edge case: `n_ptr == NULL` (i.e. first Nested is None).
|
||||||
if (!n_ptr) { return 0; }
|
if (!n_ptr) { return 0; }
|
||||||
|
|
||||||
@ -42,6 +45,6 @@ typedef struct Static {
|
|||||||
struct Static *recurse;
|
struct Static *recurse;
|
||||||
} Static;
|
} Static;
|
||||||
|
|
||||||
int access_static(const Static *s_ptr) {
|
EXPORT int access_static(const Static *s_ptr) {
|
||||||
return s_ptr->recurse->recurse->value;
|
return s_ptr->recurse->recurse->value;
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,35 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int add_one_int(int x) {
|
// See comments in build_native_lib()
|
||||||
|
#define EXPORT __attribute__((visibility("default")))
|
||||||
|
|
||||||
|
EXPORT int add_one_int(int x) {
|
||||||
return 2 + x;
|
return 2 + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printer() {
|
EXPORT void printer(void) {
|
||||||
printf("printing from C\n");
|
printf("printing from C\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// function with many arguments, to test functionality when some args are stored
|
// function with many arguments, to test functionality when some args are stored
|
||||||
// on the stack
|
// on the stack
|
||||||
int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) {
|
EXPORT int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) {
|
||||||
return a+b+c+d+e+f+g+h+i+j+k+l;
|
return a+b+c+d+e+f+g+h+i+j+k+l;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int get_unsigned_int() {
|
EXPORT unsigned int get_unsigned_int(void) {
|
||||||
return -10;
|
return -10;
|
||||||
}
|
}
|
||||||
|
|
||||||
short add_int16(short x) {
|
EXPORT short add_int16(short x) {
|
||||||
return x + 3;
|
return x + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
long add_short_to_long(short x, long y) {
|
EXPORT long add_short_to_long(short x, long y) {
|
||||||
return x + y;
|
return x + y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// To test that functions not marked with EXPORT cannot be called by Miri.
|
||||||
|
int not_exported(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -36,20 +36,21 @@ fn build_native_lib() -> PathBuf {
|
|||||||
// Create the directory if it does not already exist.
|
// Create the directory if it does not already exist.
|
||||||
std::fs::create_dir_all(&so_target_dir)
|
std::fs::create_dir_all(&so_target_dir)
|
||||||
.expect("Failed to create directory for shared object file");
|
.expect("Failed to create directory for shared object file");
|
||||||
let so_file_path = so_target_dir.join("native-lib.so");
|
// We use a platform-neutral file extension to avoid having to hard-code alternatives.
|
||||||
|
let native_lib_path = so_target_dir.join("native-lib.module");
|
||||||
let cc_output = Command::new(cc)
|
let cc_output = Command::new(cc)
|
||||||
.args([
|
.args([
|
||||||
"-shared",
|
"-shared",
|
||||||
|
"-fPIC",
|
||||||
|
// We hide all symbols by default and export just the ones we need
|
||||||
|
// This is to future-proof against a more complex shared object which eg defines its own malloc
|
||||||
|
// (but we wouldn't want miri to call that, as it would if it was exported).
|
||||||
|
"-fvisibility=hidden",
|
||||||
"-o",
|
"-o",
|
||||||
so_file_path.to_str().unwrap(),
|
native_lib_path.to_str().unwrap(),
|
||||||
// FIXME: Automate gathering of all relevant C source files in the directory.
|
// FIXME: Automate gathering of all relevant C source files in the directory.
|
||||||
"tests/native-lib/scalar_arguments.c",
|
"tests/native-lib/scalar_arguments.c",
|
||||||
"tests/native-lib/ptr_read_access.c",
|
"tests/native-lib/ptr_read_access.c",
|
||||||
// Only add the functions specified in libcode.version to the shared object file.
|
|
||||||
// This is to avoid automatically adding `malloc`, etc.
|
|
||||||
// Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
|
|
||||||
"-fPIC",
|
|
||||||
"-Wl,--version-script=tests/native-lib/native-lib.map",
|
|
||||||
// Ensure we notice serious problems in the C code.
|
// Ensure we notice serious problems in the C code.
|
||||||
"-Wall",
|
"-Wall",
|
||||||
"-Wextra",
|
"-Wextra",
|
||||||
@ -64,7 +65,7 @@ fn build_native_lib() -> PathBuf {
|
|||||||
String::from_utf8_lossy(&cc_output.stderr),
|
String::from_utf8_lossy(&cc_output.stderr),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
so_file_path
|
native_lib_path
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does *not* set any args or env vars, since it is shared between the test runner and
|
/// Does *not* set any args or env vars, since it is shared between the test runner and
|
||||||
@ -300,7 +301,7 @@ fn main() -> Result<()> {
|
|||||||
WithDependencies,
|
WithDependencies,
|
||||||
tmpdir.path(),
|
tmpdir.path(),
|
||||||
)?;
|
)?;
|
||||||
if cfg!(target_os = "linux") {
|
if cfg!(unix) {
|
||||||
ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?;
|
ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?;
|
||||||
ui(
|
ui(
|
||||||
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
|
||||||
|
@ -110,6 +110,13 @@ pub struct LlvmDwarfdump {
|
|||||||
cmd: Command,
|
cmd: Command,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A `llvm-pdbutil` invocation builder.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[must_use]
|
||||||
|
pub struct LlvmPdbutil {
|
||||||
|
cmd: Command,
|
||||||
|
}
|
||||||
|
|
||||||
crate::macros::impl_common_helpers!(LlvmReadobj);
|
crate::macros::impl_common_helpers!(LlvmReadobj);
|
||||||
crate::macros::impl_common_helpers!(LlvmProfdata);
|
crate::macros::impl_common_helpers!(LlvmProfdata);
|
||||||
crate::macros::impl_common_helpers!(LlvmFilecheck);
|
crate::macros::impl_common_helpers!(LlvmFilecheck);
|
||||||
@ -118,6 +125,7 @@ crate::macros::impl_common_helpers!(LlvmAr);
|
|||||||
crate::macros::impl_common_helpers!(LlvmNm);
|
crate::macros::impl_common_helpers!(LlvmNm);
|
||||||
crate::macros::impl_common_helpers!(LlvmBcanalyzer);
|
crate::macros::impl_common_helpers!(LlvmBcanalyzer);
|
||||||
crate::macros::impl_common_helpers!(LlvmDwarfdump);
|
crate::macros::impl_common_helpers!(LlvmDwarfdump);
|
||||||
|
crate::macros::impl_common_helpers!(LlvmPdbutil);
|
||||||
|
|
||||||
/// Generate the path to the bin directory of LLVM.
|
/// Generate the path to the bin directory of LLVM.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -360,3 +368,19 @@ impl LlvmDwarfdump {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl LlvmPdbutil {
|
||||||
|
/// Construct a new `llvm-pdbutil` invocation. This assumes that `llvm-pdbutil` is available
|
||||||
|
/// at `$LLVM_BIN_DIR/llvm-pdbutil`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let llvm_pdbutil = llvm_bin_dir().join("llvm-pdbutil");
|
||||||
|
let cmd = Command::new(llvm_pdbutil);
|
||||||
|
Self { cmd }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provide an input file.
|
||||||
|
pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
|
||||||
|
self.cmd.arg(path.as_ref());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -73,7 +73,7 @@ pub use env::{env_var, env_var_os, set_current_dir};
|
|||||||
pub use run::{cmd, run, run_fail, run_with_args};
|
pub use run::{cmd, run, run_fail, run_with_args};
|
||||||
|
|
||||||
/// Helpers for checking target information.
|
/// Helpers for checking target information.
|
||||||
pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname};
|
pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os};
|
||||||
|
|
||||||
/// Helpers for building names of output artifacts that are potentially target-specific.
|
/// Helpers for building names of output artifacts that are potentially target-specific.
|
||||||
pub use artifact_names::{
|
pub use artifact_names::{
|
||||||
|
@ -28,6 +28,24 @@ pub fn is_darwin() -> bool {
|
|||||||
target().contains("darwin")
|
target().contains("darwin")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the target OS on Apple operating systems.
|
||||||
|
#[must_use]
|
||||||
|
pub fn apple_os() -> &'static str {
|
||||||
|
if target().contains("darwin") {
|
||||||
|
"macos"
|
||||||
|
} else if target().contains("ios") {
|
||||||
|
"ios"
|
||||||
|
} else if target().contains("tvos") {
|
||||||
|
"tvos"
|
||||||
|
} else if target().contains("watchos") {
|
||||||
|
"watchos"
|
||||||
|
} else if target().contains("visionos") {
|
||||||
|
"visionos"
|
||||||
|
} else {
|
||||||
|
panic!("not an Apple OS")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if `component` is within `LLVM_COMPONENTS`
|
/// Check if `component` is within `LLVM_COMPONENTS`
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn llvm_components_contain(component: &str) -> bool {
|
pub fn llvm_components_contain(component: &str) -> bool {
|
||||||
|
@ -6,7 +6,6 @@ run-make/incr-add-rust-src-component/Makefile
|
|||||||
run-make/issue-84395-lto-embed-bitcode/Makefile
|
run-make/issue-84395-lto-embed-bitcode/Makefile
|
||||||
run-make/jobserver-error/Makefile
|
run-make/jobserver-error/Makefile
|
||||||
run-make/libs-through-symlinks/Makefile
|
run-make/libs-through-symlinks/Makefile
|
||||||
run-make/macos-deployment-target/Makefile
|
|
||||||
run-make/split-debuginfo/Makefile
|
run-make/split-debuginfo/Makefile
|
||||||
run-make/symbol-mangling-hashed/Makefile
|
run-make/symbol-mangling-hashed/Makefile
|
||||||
run-make/translation/Makefile
|
run-make/translation/Makefile
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# `wasm-component-ld`
|
# `wasm-component-ld`
|
||||||
|
|
||||||
This wrapper is a wrapper around the [`wasm-component-ld`] crates.io crate. That
|
This wrapper is a wrapper around the [`wasm-component-ld`] crates.io crate.
|
||||||
crate. That crate is itself a thin wrapper around two pieces:
|
That crate is itself a thin wrapper around two pieces:
|
||||||
|
|
||||||
* `wasm-ld` - the LLVM-based linker distributed as part of LLD and packaged in
|
* `wasm-ld` - the LLVM-based linker distributed as part of LLD and packaged in
|
||||||
Rust as `rust-lld`.
|
Rust as `rust-lld`.
|
||||||
|
@ -552,6 +552,9 @@
|
|||||||
//@ revisions: x86_64_unknown_haiku
|
//@ revisions: x86_64_unknown_haiku
|
||||||
//@ [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku
|
//@ [x86_64_unknown_haiku] compile-flags: --target x86_64-unknown-haiku
|
||||||
//@ [x86_64_unknown_haiku] needs-llvm-components: x86
|
//@ [x86_64_unknown_haiku] needs-llvm-components: x86
|
||||||
|
//@ revisions: x86_64_unknown_hurd_gnu
|
||||||
|
//@ [x86_64_unknown_hurd_gnu] compile-flags: --target x86_64-unknown-hurd-gnu
|
||||||
|
//@ [x86_64_unknown_hurd_gnu] needs-llvm-components: x86
|
||||||
//@ revisions: x86_64_unknown_hermit
|
//@ revisions: x86_64_unknown_hermit
|
||||||
//@ [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit
|
//@ [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit
|
||||||
//@ [x86_64_unknown_hermit] needs-llvm-components: x86
|
//@ [x86_64_unknown_hermit] needs-llvm-components: x86
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
//@ min-lldb-version: 1800
|
//@ min-lldb-version: 1800
|
||||||
//@ min-gdb-version: 13.0
|
//@ min-gdb-version: 13.0
|
||||||
//@ compile-flags:-g
|
//@ compile-flags:-g
|
||||||
|
//@ ignore-windows-gnu: #128973
|
||||||
|
|
||||||
// === GDB TESTS ===================================================================================
|
// === GDB TESTS ===================================================================================
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
//@ compile-flags:-g
|
//@ compile-flags:-g
|
||||||
|
|
||||||
|
//@ ignore-windows-gnu: #128973
|
||||||
|
|
||||||
// === GDB TESTS ===================================================================================
|
// === GDB TESTS ===================================================================================
|
||||||
|
|
||||||
// gdb-command:run
|
// gdb-command:run
|
||||||
|
1
tests/run-make/apple-deployment-target/foo.rs
Normal file
1
tests/run-make/apple-deployment-target/foo.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
fn main() {}
|
157
tests/run-make/apple-deployment-target/rmake.rs
Normal file
157
tests/run-make/apple-deployment-target/rmake.rs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
//! Test codegen when setting deployment targets on Apple platforms.
|
||||||
|
//!
|
||||||
|
//! This is important since its a compatibility hazard. The linker will
|
||||||
|
//! generate load commands differently based on what minimum OS it can assume.
|
||||||
|
//!
|
||||||
|
//! See https://github.com/rust-lang/rust/pull/105123.
|
||||||
|
|
||||||
|
//@ only-apple
|
||||||
|
|
||||||
|
use run_make_support::{apple_os, cmd, run_in_tmpdir, rustc, target};
|
||||||
|
|
||||||
|
/// Run vtool to check the `minos` field in LC_BUILD_VERSION.
|
||||||
|
///
|
||||||
|
/// On lower deployment targets, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS and similar
|
||||||
|
/// are used instead of LC_BUILD_VERSION - these have a `version` field, so also check that.
|
||||||
|
#[track_caller]
|
||||||
|
fn minos(file: &str, version: &str) {
|
||||||
|
cmd("vtool")
|
||||||
|
.arg("-show-build")
|
||||||
|
.arg(file)
|
||||||
|
.run()
|
||||||
|
.assert_stdout_contains_regex(format!("(minos|version) {version}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// These versions should generally be higher than the default versions
|
||||||
|
let (env_var, example_version, higher_example_version) = match apple_os() {
|
||||||
|
"macos" => ("MACOSX_DEPLOYMENT_TARGET", "12.0", "13.0"),
|
||||||
|
// armv7s-apple-ios and i386-apple-ios only supports iOS 10.0
|
||||||
|
"ios" if target() == "armv7s-apple-ios" || target() == "i386-apple-ios" => {
|
||||||
|
("IPHONEOS_DEPLOYMENT_TARGET", "10.0", "10.0")
|
||||||
|
}
|
||||||
|
"ios" => ("IPHONEOS_DEPLOYMENT_TARGET", "15.0", "16.0"),
|
||||||
|
"watchos" => ("WATCHOS_DEPLOYMENT_TARGET", "7.0", "9.0"),
|
||||||
|
"tvos" => ("TVOS_DEPLOYMENT_TARGET", "14.0", "15.0"),
|
||||||
|
"visionos" => ("XROS_DEPLOYMENT_TARGET", "1.1", "1.2"),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
let default_version =
|
||||||
|
rustc().target(target()).env_remove(env_var).print("deployment-target").run().stdout_utf8();
|
||||||
|
let default_version = default_version.strip_prefix("deployment_target=").unwrap().trim();
|
||||||
|
|
||||||
|
// Test that version makes it to the object file.
|
||||||
|
run_in_tmpdir(|| {
|
||||||
|
let rustc = || {
|
||||||
|
let mut rustc = rustc();
|
||||||
|
rustc.target(target());
|
||||||
|
rustc.crate_type("lib");
|
||||||
|
rustc.emit("obj");
|
||||||
|
rustc.input("foo.rs");
|
||||||
|
rustc.output("foo.o");
|
||||||
|
rustc
|
||||||
|
};
|
||||||
|
|
||||||
|
rustc().env(env_var, example_version).run();
|
||||||
|
minos("foo.o", example_version);
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Doesn't work on Mac Catalyst and the simulator.
|
||||||
|
if !target().contains("macabi") && !target().contains("sim") {
|
||||||
|
rustc().env_remove(env_var).run();
|
||||||
|
minos("foo.o", default_version);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that version makes it to the linker when linking dylibs.
|
||||||
|
run_in_tmpdir(|| {
|
||||||
|
// Certain watchOS targets don't support dynamic linking, so we disable the test on those.
|
||||||
|
if apple_os() == "watchos" {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rustc = || {
|
||||||
|
let mut rustc = rustc();
|
||||||
|
rustc.target(target());
|
||||||
|
rustc.crate_type("dylib");
|
||||||
|
rustc.input("foo.rs");
|
||||||
|
rustc.output("libfoo.dylib");
|
||||||
|
rustc
|
||||||
|
};
|
||||||
|
|
||||||
|
rustc().env(env_var, example_version).run();
|
||||||
|
minos("libfoo.dylib", example_version);
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Deployment target is not currently passed properly to linker
|
||||||
|
// rustc().env_remove(env_var).run();
|
||||||
|
// minos("libfoo.dylib", default_version);
|
||||||
|
|
||||||
|
// Test with ld64 instead
|
||||||
|
|
||||||
|
rustc().arg("-Clinker-flavor=ld").env(env_var, example_version).run();
|
||||||
|
minos("libfoo.dylib", example_version);
|
||||||
|
|
||||||
|
rustc().arg("-Clinker-flavor=ld").env_remove(env_var).run();
|
||||||
|
minos("libfoo.dylib", default_version);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that version makes it to the linker when linking executables.
|
||||||
|
run_in_tmpdir(|| {
|
||||||
|
let rustc = || {
|
||||||
|
let mut rustc = rustc();
|
||||||
|
rustc.target(target());
|
||||||
|
rustc.crate_type("bin");
|
||||||
|
rustc.input("foo.rs");
|
||||||
|
rustc.output("foo");
|
||||||
|
rustc
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Doesn't work on watchOS for some reason?
|
||||||
|
if !target().contains("watchos") {
|
||||||
|
rustc().env(env_var, example_version).run();
|
||||||
|
minos("foo", example_version);
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Deployment target is not currently passed properly to linker
|
||||||
|
// rustc().env_remove(env_var).run();
|
||||||
|
// minos("foo", default_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test with ld64 instead
|
||||||
|
|
||||||
|
rustc().arg("-Clinker-flavor=ld").env(env_var, example_version).run();
|
||||||
|
minos("foo", example_version);
|
||||||
|
|
||||||
|
rustc().arg("-Clinker-flavor=ld").env_remove(env_var).run();
|
||||||
|
minos("foo", default_version);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test that changing the deployment target busts the incremental cache.
|
||||||
|
run_in_tmpdir(|| {
|
||||||
|
let rustc = || {
|
||||||
|
let mut rustc = rustc();
|
||||||
|
rustc.target(target());
|
||||||
|
rustc.incremental("incremental");
|
||||||
|
rustc.crate_type("lib");
|
||||||
|
rustc.emit("obj");
|
||||||
|
rustc.input("foo.rs");
|
||||||
|
rustc.output("foo.o");
|
||||||
|
rustc
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Incremental cache is not yet busted
|
||||||
|
// https://github.com/rust-lang/rust/issues/118204
|
||||||
|
let higher_example_version = example_version;
|
||||||
|
let default_version = example_version;
|
||||||
|
|
||||||
|
rustc().env(env_var, example_version).run();
|
||||||
|
minos("foo.o", example_version);
|
||||||
|
|
||||||
|
rustc().env(env_var, higher_example_version).run();
|
||||||
|
minos("foo.o", higher_example_version);
|
||||||
|
|
||||||
|
// FIXME(madsmtm): Doesn't work on Mac Catalyst and the simulator.
|
||||||
|
if !target().contains("macabi") && !target().contains("sim") {
|
||||||
|
rustc().env_remove(env_var).run();
|
||||||
|
minos("foo.o", default_version);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -1,21 +0,0 @@
|
|||||||
# only-macos
|
|
||||||
#
|
|
||||||
# Check that a set deployment target actually makes it to the linker.
|
|
||||||
# This is important since its a compatibility hazard. The linker will
|
|
||||||
# generate load commands differently based on what minimum OS it can assume.
|
|
||||||
|
|
||||||
include ../tools.mk
|
|
||||||
|
|
||||||
ifeq ($(strip $(shell uname -m)),arm64)
|
|
||||||
GREP_PATTERN = "minos 11.0"
|
|
||||||
else
|
|
||||||
GREP_PATTERN = "version 10.13"
|
|
||||||
endif
|
|
||||||
|
|
||||||
OUT_FILE=$(TMPDIR)/with_deployment_target.dylib
|
|
||||||
all:
|
|
||||||
env MACOSX_DEPLOYMENT_TARGET=10.13 $(RUSTC) with_deployment_target.rs -o $(OUT_FILE)
|
|
||||||
# XXX: The check is for either the x86_64 minimum OR the aarch64 minimum (M1 starts at macOS 11).
|
|
||||||
# They also use different load commands, so we let that change with each too. The aarch64 check
|
|
||||||
# isn't as robust as the x86 one, but testing both seems unneeded.
|
|
||||||
vtool -show-build $(OUT_FILE) | $(CGREP) -e $(GREP_PATTERN)
|
|
@ -1,4 +0,0 @@
|
|||||||
#![crate_type = "cdylib"]
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn something_and_nothing() {}
|
|
@ -9,12 +9,12 @@ impl Simple {
|
|||||||
|
|
||||||
pub trait EasyToImpl {
|
pub trait EasyToImpl {
|
||||||
//@ has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type"
|
//@ has "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type"
|
||||||
//@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.default" null
|
//@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.type" null
|
||||||
//@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" []
|
//@ is "$.index[*][?(@.docs=='ToDeclare trait')].inner.assoc_type.bounds" []
|
||||||
/// ToDeclare trait
|
/// ToDeclare trait
|
||||||
type ToDeclare;
|
type ToDeclare;
|
||||||
//@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const"
|
//@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const"
|
||||||
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.default" null
|
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.value" null
|
||||||
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"'
|
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE trait')].inner.assoc_const.type.primitive" '"usize"'
|
||||||
/// AN_ATTRIBUTE trait
|
/// AN_ATTRIBUTE trait
|
||||||
const AN_ATTRIBUTE: usize;
|
const AN_ATTRIBUTE: usize;
|
||||||
@ -22,13 +22,13 @@ pub trait EasyToImpl {
|
|||||||
|
|
||||||
impl EasyToImpl for Simple {
|
impl EasyToImpl for Simple {
|
||||||
//@ has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type"
|
//@ has "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type"
|
||||||
//@ is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.default.primitive" \"usize\"
|
//@ is "$.index[*][?(@.docs=='ToDeclare impl')].inner.assoc_type.type.primitive" \"usize\"
|
||||||
/// ToDeclare impl
|
/// ToDeclare impl
|
||||||
type ToDeclare = usize;
|
type ToDeclare = usize;
|
||||||
|
|
||||||
//@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const"
|
//@ has "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const"
|
||||||
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\"
|
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.type.primitive" \"usize\"
|
||||||
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.default" \"12\"
|
//@ is "$.index[*][?(@.docs=='AN_ATTRIBUTE impl')].inner.assoc_const.value" \"12\"
|
||||||
/// AN_ATTRIBUTE impl
|
/// AN_ATTRIBUTE impl
|
||||||
const AN_ATTRIBUTE: usize = 12;
|
const AN_ATTRIBUTE: usize = 12;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type"
|
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type"
|
||||||
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path"
|
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path"
|
||||||
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.default.resolved_path.name" \"Infallible\"
|
//@ has "$.index[*][?(@.name=='Error')].inner.assoc_type.type.resolved_path.name" \"Infallible\"
|
||||||
pub struct ForBlanketTryFromImpl;
|
pub struct ForBlanketTryFromImpl;
|
||||||
|
@ -5,7 +5,7 @@ pub enum Foo {
|
|||||||
//@ is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"'
|
//@ is "$.index[*][?(@.name=='Unit')].inner.variant.kind" '"plain"'
|
||||||
Unit,
|
Unit,
|
||||||
//@ set Named = "$.index[*][?(@.name=='Named')].id"
|
//@ set Named = "$.index[*][?(@.name=='Named')].id"
|
||||||
//@ is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "fields_stripped": false}'
|
//@ is "$.index[*][?(@.name=='Named')].inner.variant.kind.struct" '{"fields": [], "has_stripped_fields": false}'
|
||||||
Named {},
|
Named {},
|
||||||
//@ set Tuple = "$.index[*][?(@.name=='Tuple')].id"
|
//@ set Tuple = "$.index[*][?(@.name=='Tuple')].id"
|
||||||
//@ is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" []
|
//@ is "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple" []
|
||||||
@ -13,7 +13,7 @@ pub enum Foo {
|
|||||||
//@ set NamedField = "$.index[*][?(@.name=='NamedField')].id"
|
//@ set NamedField = "$.index[*][?(@.name=='NamedField')].id"
|
||||||
//@ set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id"
|
//@ set x = "$.index[*][?(@.name=='x' && @.inner.struct_field)].id"
|
||||||
//@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x
|
//@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields[*]" $x
|
||||||
//@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.fields_stripped" false
|
//@ is "$.index[*][?(@.name=='NamedField')].inner.variant.kind.struct.has_stripped_fields" false
|
||||||
NamedField { x: i32 },
|
NamedField { x: i32 },
|
||||||
//@ set TupleField = "$.index[*][?(@.name=='TupleField')].id"
|
//@ set TupleField = "$.index[*][?(@.name=='TupleField')].id"
|
||||||
//@ set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id"
|
//@ set tup_field = "$.index[*][?(@.name=='0' && @.inner.struct_field)].id"
|
||||||
|
@ -9,7 +9,7 @@ pub enum Foo {
|
|||||||
//@ set y = "$.index[*][?(@.name=='y')].id"
|
//@ set y = "$.index[*][?(@.name=='y')].id"
|
||||||
y: i32,
|
y: i32,
|
||||||
},
|
},
|
||||||
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields_stripped" true
|
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.has_stripped_fields" true
|
||||||
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b
|
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[0]" $b
|
||||||
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y
|
//@ is "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[1]" $y
|
||||||
//@ count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2
|
//@ count "$.index[*][?(@.name=='Variant')].inner.variant.kind.struct.fields[*]" 2
|
||||||
|
@ -7,9 +7,9 @@ pub enum Color {
|
|||||||
Blue,
|
Blue,
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ set use_Color = "$.index[*][?(@.inner.import)].id"
|
//@ set use_Color = "$.index[*][?(@.inner.use)].id"
|
||||||
//@ is "$.index[*][?(@.inner.import)].inner.import.id" $Color
|
//@ is "$.index[*][?(@.inner.use)].inner.use.id" $Color
|
||||||
//@ is "$.index[*][?(@.inner.import)].inner.import.glob" true
|
//@ is "$.index[*][?(@.inner.use)].inner.use.is_glob" true
|
||||||
pub use Color::*;
|
pub use Color::*;
|
||||||
|
|
||||||
//@ ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color
|
//@ ismany "$.index[*][?(@.name == 'use_glob')].inner.module.items[*]" $Color $use_Color
|
||||||
|
@ -5,8 +5,8 @@ pub enum AlwaysNone {
|
|||||||
}
|
}
|
||||||
//@ is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None
|
//@ is "$.index[*][?(@.name == 'AlwaysNone')].inner.enum.variants[*]" $None
|
||||||
|
|
||||||
//@ set use_None = "$.index[*][?(@.inner.import)].id"
|
//@ set use_None = "$.index[*][?(@.inner.use)].id"
|
||||||
//@ is "$.index[*][?(@.inner.import)].inner.import.id" $None
|
//@ is "$.index[*][?(@.inner.use)].inner.use.id" $None
|
||||||
pub use AlwaysNone::None;
|
pub use AlwaysNone::None;
|
||||||
|
|
||||||
//@ ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None
|
//@ ismany "$.index[*][?(@.name == 'use_variant')].inner.module.items[*]" $AlwaysNone $use_None
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
extern crate color;
|
extern crate color;
|
||||||
|
|
||||||
//@ has "$.index[*].inner.import[?(@.name == 'Red')]"
|
//@ has "$.index[*].inner.use[?(@.name == 'Red')]"
|
||||||
pub use color::Color::Red;
|
pub use color::Color::Red;
|
||||||
|
|
||||||
//@ !has "$.index[*][?(@.name == 'Red')]"
|
//@ !has "$.index[*][?(@.name == 'Red')]"
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[*]" 1
|
//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][0]" '"val"'
|
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][0]" '"val"'
|
||||||
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.inputs[0][1].borrowed_ref.lifetime" \"\'c\"
|
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.inputs[0][1].borrowed_ref.lifetime" \"\'c\"
|
||||||
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.decl.output.primitive" \"i32\"
|
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.sig.output.primitive" \"i32\"
|
||||||
//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1
|
//@ count "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\"
|
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].name" \"\'c\"
|
||||||
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
|
//@ is "$.index[*][?(@.name=='WithHigherRankTraitBounds')].inner.type_alias.type.function_pointer.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }'
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.unsafe" false
|
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_unsafe" false
|
||||||
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.const" false
|
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.async" false
|
//@ is "$.index[*][?(@.name=='FnPointer')].inner.type_alias.type.function_pointer.header.is_async" false
|
||||||
pub type FnPointer = fn();
|
pub type FnPointer = fn();
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.unsafe" true
|
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_unsafe" true
|
||||||
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.const" false
|
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.async" false
|
//@ is "$.index[*][?(@.name=='UnsafePointer')].inner.type_alias.type.function_pointer.header.is_async" false
|
||||||
pub type UnsafePointer = unsafe fn();
|
pub type UnsafePointer = unsafe fn();
|
||||||
|
@ -5,30 +5,30 @@
|
|||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='get_int')].inner.function.decl.output.primitive" \"i32\"
|
//@ is "$.index[*][?(@.name=='get_int')].inner.function.sig.output.primitive" \"i32\"
|
||||||
//@ is "$.index[*][?(@.name=='get_int')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='get_int')].inner.function.header.is_async" false
|
||||||
pub fn get_int() -> i32 {
|
pub fn get_int() -> i32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.decl.output.primitive" \"i32\"
|
//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.sig.output.primitive" \"i32\"
|
||||||
//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.header.async" true
|
//@ is "$.index[*][?(@.name=='get_int_async')].inner.function.header.is_async" true
|
||||||
pub async fn get_int_async() -> i32 {
|
pub async fn get_int_async() -> i32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"'
|
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"'
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
|
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"'
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\"
|
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\"
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='get_int_future')].inner.function.header.is_async" false
|
||||||
pub fn get_int_future() -> impl Future<Output = i32> {
|
pub fn get_int_future() -> impl Future<Output = i32> {
|
||||||
async { 42 }
|
async { 42 }
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.name" '"Future"'
|
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.name" '"Future"'
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name" '"Output"'
|
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name" '"Output"'
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.decl.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive" \"i32\"
|
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.sig.output.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive" \"i32\"
|
||||||
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.async" true
|
//@ is "$.index[*][?(@.name=='get_int_future_async')].inner.function.header.is_async" true
|
||||||
pub async fn get_int_future_async() -> impl Future<Output = i32> {
|
pub async fn get_int_future_async() -> impl Future<Output = i32> {
|
||||||
async { 42 }
|
async { 42 }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
//@ is "$.index[*][?(@.name == 'not_variadic')].inner.function.decl.c_variadic" false
|
//@ is "$.index[*][?(@.name == 'not_variadic')].inner.function.sig.is_c_variadic" false
|
||||||
pub fn not_variadic(_: i32);
|
pub fn not_variadic(_: i32);
|
||||||
//@ is "$.index[*][?(@.name == 'variadic')].inner.function.decl.c_variadic" true
|
//@ is "$.index[*][?(@.name == 'variadic')].inner.function.sig.is_c_variadic" true
|
||||||
pub fn variadic(_: i32, ...);
|
pub fn variadic(_: i32, ...);
|
||||||
}
|
}
|
||||||
|
@ -12,27 +12,27 @@ pub trait GenericFoo<'a> {}
|
|||||||
//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null'
|
//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.default" 'null'
|
||||||
//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1
|
//@ count "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo'
|
//@ is "$.index[*][?(@.name=='generics')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" '$foo'
|
||||||
//@ count "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[*]" 1
|
//@ count "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][0]" '"f"'
|
//@ is "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[0][0]" '"f"'
|
||||||
//@ is "$.index[*][?(@.name=='generics')].inner.function.decl.inputs[0][1].generic" '"F"'
|
//@ is "$.index[*][?(@.name=='generics')].inner.function.sig.inputs[0][1].generic" '"F"'
|
||||||
pub fn generics<F: Foo>(f: F) {}
|
pub fn generics<F: Foo>(f: F) {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]"
|
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.where_predicates" "[]"
|
||||||
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1
|
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"'
|
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].name" '"impl Foo"'
|
||||||
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo
|
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $foo
|
||||||
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[*]" 1
|
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][0]" '"f"'
|
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][0]" '"f"'
|
||||||
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[*]" 1
|
//@ count "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo
|
//@ is "$.index[*][?(@.name=='impl_trait')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $foo
|
||||||
pub fn impl_trait(f: impl Foo) {}
|
pub fn impl_trait(f: impl Foo) {}
|
||||||
|
|
||||||
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3
|
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[*]" 3
|
||||||
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"'
|
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].name" '"F"'
|
||||||
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "synthetic": false}}'
|
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.params[0].kind" '{"type": {"bounds": [], "default": null, "is_synthetic": false}}'
|
||||||
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[*]" 3
|
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[*]" 3
|
||||||
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][0]" '"f"'
|
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[0][0]" '"f"'
|
||||||
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.decl.inputs[0][1].generic" '"F"'
|
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.sig.inputs[0][1].generic" '"F"'
|
||||||
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3
|
//@ count "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[*]" 3
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\"
|
//@ is "$.index[*][?(@.name=='where_clase')].inner.function.generics.where_predicates[0].bound_predicate.type.generic" \"F\"
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
//@ set foo = "$.index[*][?(@.name=='Foo')].id"
|
//@ set foo = "$.index[*][?(@.name=='Foo')].id"
|
||||||
pub trait Foo {}
|
pub trait Foo {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='get_foo')].inner.function.decl.inputs" []
|
//@ is "$.index[*][?(@.name=='get_foo')].inner.function.sig.inputs" []
|
||||||
//@ count "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[*]" 1
|
//@ count "$.index[*][?(@.name=='get_foo')].inner.function.sig.output.impl_trait[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='get_foo')].inner.function.decl.output.impl_trait[0].trait_bound.trait.id" $foo
|
//@ is "$.index[*][?(@.name=='get_foo')].inner.function.sig.output.impl_trait[0].trait_bound.trait.id" $foo
|
||||||
pub fn get_foo() -> impl Foo {
|
pub fn get_foo() -> impl Foo {
|
||||||
Fooer {}
|
Fooer {}
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,17 @@ pub trait Wham {}
|
|||||||
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" []
|
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.where_predicates" []
|
||||||
//@ count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1
|
//@ count "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"'
|
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].name" '"T"'
|
||||||
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" false
|
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" false
|
||||||
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
|
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
|
||||||
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.decl.inputs" '[["w", {"generic": "T"}]]'
|
//@ is "$.index[*][?(@.name=='one_generic_param_fn')].inner.function.sig.inputs" '[["w", {"generic": "T"}]]'
|
||||||
pub fn one_generic_param_fn<T: Wham>(w: T) {}
|
pub fn one_generic_param_fn<T: Wham>(w: T) {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" []
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.where_predicates" []
|
||||||
//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1
|
//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"'
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].name" '"impl Wham"'
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.synthetic" true
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.is_synthetic" true
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.generics.params[0].kind.type.bounds[0].trait_bound.trait.id" $wham_id
|
||||||
//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[*]" 1
|
//@ count "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][0]" '"w"'
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][0]" '"w"'
|
||||||
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.decl.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id
|
//@ is "$.index[*][?(@.name=='one_synthetic_generic_param_fn')].inner.function.sig.inputs[0][1].impl_trait[0].trait_bound.trait.id" $wham_id
|
||||||
pub fn one_synthetic_generic_param_fn(w: impl Wham) {}
|
pub fn one_synthetic_generic_param_fn(w: impl Wham) {}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//@ is "$.index[*][?(@.name=='fst')].inner.function.decl.inputs[0][0]" '"(x, _)"'
|
//@ is "$.index[*][?(@.name=='fst')].inner.function.sig.inputs[0][0]" '"(x, _)"'
|
||||||
pub fn fst<X, Y>((x, _): (X, Y)) -> X {
|
pub fn fst<X, Y>((x, _): (X, Y)) -> X {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='drop_int')].inner.function.decl.inputs[0][0]" '"_"'
|
//@ is "$.index[*][?(@.name=='drop_int')].inner.function.sig.inputs[0][0]" '"_"'
|
||||||
pub fn drop_int(_: i32) {}
|
pub fn drop_int(_: i32) {}
|
||||||
|
@ -1,33 +1,33 @@
|
|||||||
//@ edition:2018
|
//@ edition:2018
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_async" false
|
||||||
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.const" false
|
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.unsafe" false
|
//@ is "$.index[*][?(@.name=='nothing_fn')].inner.function.header.is_unsafe" false
|
||||||
pub fn nothing_fn() {}
|
pub fn nothing_fn() {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_async" false
|
||||||
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.const" false
|
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.unsafe" true
|
//@ is "$.index[*][?(@.name=='unsafe_fn')].inner.function.header.is_unsafe" true
|
||||||
pub unsafe fn unsafe_fn() {}
|
pub unsafe fn unsafe_fn() {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_async" false
|
||||||
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.const" true
|
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_const" true
|
||||||
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.unsafe" false
|
//@ is "$.index[*][?(@.name=='const_fn')].inner.function.header.is_unsafe" false
|
||||||
pub const fn const_fn() {}
|
pub const fn const_fn() {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.async" true
|
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_async" true
|
||||||
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.const" false
|
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.unsafe" false
|
//@ is "$.index[*][?(@.name=='async_fn')].inner.function.header.is_unsafe" false
|
||||||
pub async fn async_fn() {}
|
pub async fn async_fn() {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.async" true
|
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_async" true
|
||||||
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.const" false
|
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_const" false
|
||||||
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.unsafe" true
|
//@ is "$.index[*][?(@.name=='async_unsafe_fn')].inner.function.header.is_unsafe" true
|
||||||
pub async unsafe fn async_unsafe_fn() {}
|
pub async unsafe fn async_unsafe_fn() {}
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.async" false
|
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_async" false
|
||||||
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.const" true
|
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_const" true
|
||||||
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.unsafe" true
|
//@ is "$.index[*][?(@.name=='const_unsafe_fn')].inner.function.header.is_unsafe" true
|
||||||
pub const unsafe fn const_unsafe_fn() {}
|
pub const unsafe fn const_unsafe_fn() {}
|
||||||
|
|
||||||
// It's impossible for a function to be both const and async, so no test for that
|
// It's impossible for a function to be both const and async, so no test for that
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
///@ set foo = "$.index[*][?(@.name=='Foo')].id"
|
///@ set foo = "$.index[*][?(@.name=='Foo')].id"
|
||||||
pub type Foo = i32;
|
pub type Foo = i32;
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='demo')].inner.function.decl.output.resolved_path.id" $foo
|
//@ is "$.index[*][?(@.name=='demo')].inner.function.sig.output.resolved_path.id" $foo
|
||||||
pub fn demo() -> Foo {
|
pub fn demo() -> Foo {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,10 @@ pub trait LendingIterator {
|
|||||||
where
|
where
|
||||||
Self: 'a;
|
Self: 'a;
|
||||||
|
|
||||||
//@ count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 1
|
//@ count "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 1
|
||||||
//@ count "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0
|
//@ count "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0
|
||||||
//@ is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\"
|
//@ is "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\"
|
||||||
//@ is "$.index[*][?(@.name=='lending_next')].inner.function.decl.output.qualified_path.name" \"LendingItem\"
|
//@ is "$.index[*][?(@.name=='lending_next')].inner.function.sig.output.qualified_path.name" \"LendingItem\"
|
||||||
fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>;
|
fn lending_next<'a>(&'a self) -> Self::LendingItem<'a>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,9 +26,9 @@ pub trait Iterator {
|
|||||||
//@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1
|
//@ count "$.index[*][?(@.name=='Item')].inner.assoc_type.bounds[*]" 1
|
||||||
type Item: Display;
|
type Item: Display;
|
||||||
|
|
||||||
//@ count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.args[*]" 0
|
//@ count "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.args[*]" 0
|
||||||
//@ count "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.args.angle_bracketed.bindings[*]" 0
|
//@ count "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.args.angle_bracketed.bindings[*]" 0
|
||||||
//@ is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.self_type.generic" \"Self\"
|
//@ is "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.self_type.generic" \"Self\"
|
||||||
//@ is "$.index[*][?(@.name=='next')].inner.function.decl.output.qualified_path.name" \"Item\"
|
//@ is "$.index[*][?(@.name=='next')].inner.function.sig.output.qualified_path.name" \"Item\"
|
||||||
fn next<'a>(&'a self) -> Self::Item;
|
fn next<'a>(&'a self) -> Self::Item;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
//@ has "$.index[*][?(@.name=='glob')]"
|
//@ has "$.index[*][?(@.name=='glob')]"
|
||||||
//@ has "$.index[*][?(@.inner.import)].inner.import.name" \"*\"
|
//@ has "$.index[*][?(@.inner.use)].inner.use.name" \"*\"
|
||||||
|
|
||||||
mod m1 {
|
mod m1 {
|
||||||
pub fn f() {}
|
pub fn f() {}
|
||||||
|
@ -9,11 +9,11 @@ impl IntoIterator for AlwaysTrue {
|
|||||||
/// type Item
|
/// type Item
|
||||||
type Item = bool;
|
type Item = bool;
|
||||||
|
|
||||||
//@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.default.impl_trait[*]' 1
|
//@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[*]' 1
|
||||||
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.default.impl_trait[0].trait_bound.trait.name' '"Iterator"'
|
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.name' '"Iterator"'
|
||||||
//@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.default.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[*]' 1
|
//@ count '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[*]' 1
|
||||||
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.default.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].name' '"Item"'
|
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].name' '"Item"'
|
||||||
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.default.impl_trait[0].trait_bound.trait.args.angle_bracketed.bindings[0].binding.equality.type.primitive' '"bool"'
|
//@ is '$.index[*][?(@.docs=="type IntoIter")].inner.assoc_type.type.impl_trait[0].trait_bound.trait.args.angle_bracketed.constraints[0].binding.equality.type.primitive' '"bool"'
|
||||||
|
|
||||||
//@ set IntoIter = '$.index[*][?(@.docs=="type IntoIter")].id'
|
//@ set IntoIter = '$.index[*][?(@.docs=="type IntoIter")].id'
|
||||||
/// type IntoIter
|
/// type IntoIter
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[0]" \"\'a\"
|
//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[0]" \"\'a\"
|
||||||
//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[1]" \"T\"
|
//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[1]" \"T\"
|
||||||
//@ is "$.index[*][?(@.name=='hello')].inner.function.decl.output.impl_trait[1].use[2]" \"N\"
|
//@ is "$.index[*][?(@.name=='hello')].inner.function.sig.output.impl_trait[1].use[2]" \"N\"
|
||||||
pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
|
pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {}
|
||||||
|
@ -18,5 +18,5 @@ impl Foo {
|
|||||||
//@ is "$.index[*][?(@.docs=='has span')].span.begin" "[13, 0]"
|
//@ is "$.index[*][?(@.docs=='has span')].span.begin" "[13, 0]"
|
||||||
//@ is "$.index[*][?(@.docs=='has span')].span.end" "[15, 1]"
|
//@ is "$.index[*][?(@.docs=='has span')].span.end" "[15, 1]"
|
||||||
// FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91
|
// FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91
|
||||||
// is "$.index[*][?(@.inner.impl.synthetic==true)].span" null
|
// is "$.index[*][?(@.inner.impl.is_synthetic==true)].span" null
|
||||||
pub struct Foo;
|
pub struct Foo;
|
||||||
|
@ -3,7 +3,7 @@ extern crate foreign_trait;
|
|||||||
|
|
||||||
/// ForeignTrait id hack
|
/// ForeignTrait id hack
|
||||||
pub use foreign_trait::ForeignTrait as _;
|
pub use foreign_trait::ForeignTrait as _;
|
||||||
//@ set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.import.id"
|
//@ set ForeignTrait = "$.index[*][?(@.docs=='ForeignTrait id hack')].inner.use.id"
|
||||||
|
|
||||||
pub struct LocalStruct;
|
pub struct LocalStruct;
|
||||||
//@ set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id"
|
//@ set LocalStruct = "$.index[*][?(@.name=='LocalStruct')].id"
|
||||||
|
@ -11,10 +11,10 @@ mod bar {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//@ set import = "$.index[*][?(@.inner.import)].id"
|
//@ set import = "$.index[*][?(@.inner.use)].id"
|
||||||
pub use bar::Baz;
|
pub use bar::Baz;
|
||||||
|
|
||||||
//@ is "$.index[*].inner.module.items[*]" $import
|
//@ is "$.index[*].inner.module.items[*]" $import
|
||||||
//@ is "$.index[*].inner.import.id" $baz
|
//@ is "$.index[*].inner.use.id" $baz
|
||||||
//@ has "$.index[*][?(@.name == 'Baz')].inner.struct.impls[*]" $impl
|
//@ has "$.index[*][?(@.name == 'Baz')].inner.struct.impls[*]" $impl
|
||||||
//@ is "$.index[*][?(@.docs=='impl')].inner.impl.items[*]" $doit
|
//@ is "$.index[*][?(@.docs=='impl')].inner.impl.items[*]" $doit
|
||||||
|
@ -3,7 +3,7 @@ extern crate foreign_struct;
|
|||||||
|
|
||||||
/// ForeignStruct id hack
|
/// ForeignStruct id hack
|
||||||
pub use foreign_struct::ForeignStruct as _;
|
pub use foreign_struct::ForeignStruct as _;
|
||||||
//@ set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.import.id"
|
//@ set ForeignStruct = "$.index[*][?(@.docs=='ForeignStruct id hack')].inner.use.id"
|
||||||
|
|
||||||
pub trait LocalTrait {}
|
pub trait LocalTrait {}
|
||||||
//@ set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id"
|
//@ set LocalTrait = "$.index[*][?(@.name=='LocalTrait')].id"
|
||||||
|
@ -6,21 +6,21 @@
|
|||||||
//@ count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1
|
//@ count "$.index[*][?(@.name=='longest')].inner.function.generics.params[*]" 1
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" []
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.generics.where_predicates" []
|
||||||
|
|
||||||
//@ count "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[*]" 2
|
//@ count "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[*]" 2
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][0]" '"l"'
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][0]" '"l"'
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][0]" '"r"'
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][0]" '"r"'
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.lifetime" \"\'a\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.lifetime" \"\'a\"
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.mutable" false
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.is_mutable" false
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[0][1].borrowed_ref.type.primitive" \"str\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[0][1].borrowed_ref.type.primitive" \"str\"
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.lifetime" \"\'a\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.lifetime" \"\'a\"
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.mutable" false
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.is_mutable" false
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.inputs[1][1].borrowed_ref.type.primitive" \"str\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.inputs[1][1].borrowed_ref.type.primitive" \"str\"
|
||||||
|
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.lifetime" \"\'a\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.lifetime" \"\'a\"
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.mutable" false
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.is_mutable" false
|
||||||
//@ is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.type.primitive" \"str\"
|
//@ is "$.index[*][?(@.name=='longest')].inner.function.sig.output.borrowed_ref.type.primitive" \"str\"
|
||||||
|
|
||||||
pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str {
|
pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str {
|
||||||
if l.len() > r.len() { l } else { r }
|
if l.len() > r.len() { l } else { r }
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user