Merge from rustc
This commit is contained in:
commit
4bfde41afa
268 changed files with 4884 additions and 1765 deletions
124
.github/workflows/ci.yml
vendored
124
.github/workflows/ci.yml
vendored
|
|
@ -48,19 +48,19 @@ jobs:
|
|||
include:
|
||||
- name: mingw-check
|
||||
tidy: false
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: mingw-check-tidy
|
||||
tidy: true
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-llvm-14
|
||||
tidy: false
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-tools
|
||||
tidy: false
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
timeout-minutes: 600
|
||||
runs-on: "${{ matrix.os }}"
|
||||
|
|
@ -181,136 +181,136 @@ jobs:
|
|||
- ARM64
|
||||
- linux
|
||||
- name: arm-android
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: armhf-gnu
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-aarch64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-android
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-arm-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-armhf-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-armv7-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-i586-gnu-i586-i686-musl
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-i686-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-mips-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-mips64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-mips64el-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-mipsel-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-powerpc-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-powerpc64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-powerpc64le-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-riscv64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-s390x-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-various-1
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-various-2
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-x86_64-freebsd
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-x86_64-illumos
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-x86_64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-x86_64-linux-alt
|
||||
env:
|
||||
IMAGE: dist-x86_64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: dist-x86_64-musl
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: dist-x86_64-netbsd
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: i686-gnu
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: i686-gnu-nopt
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: mingw-check
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: test-various
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: wasm32
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-stable
|
||||
env:
|
||||
IMAGE: x86_64-gnu
|
||||
RUST_CI_OVERRIDE_RELEASE_CHANNEL: stable
|
||||
CI_ONLY_WHEN_CHANNEL: nightly
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: x86_64-gnu-aux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-debug
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-distcheck
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-llvm-15
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: x86_64-gnu-llvm-14
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: x86_64-gnu-llvm-14-stage1
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: x86_64-gnu-nopt
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
- name: x86_64-gnu-tools
|
||||
env:
|
||||
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
- name: dist-x86_64-apple
|
||||
env:
|
||||
SCRIPT: "./x.py dist bootstrap --include-default-paths --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
|
||||
|
|
@ -386,80 +386,80 @@ jobs:
|
|||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
||||
SCRIPT: make ci-subset-1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-msvc-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
|
||||
SCRIPT: make ci-subset-2
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-msvc-1
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
|
||||
SCRIPT: make ci-subset-1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-msvc-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc"
|
||||
SCRIPT: make ci-subset-2
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-msvc-cargo
|
||||
env:
|
||||
SCRIPT: python x.py --stage 2 test src/tools/cargotest src/tools/cargo
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-lld"
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-msvc-tools
|
||||
env:
|
||||
SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json"
|
||||
DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-mingw-1
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: i686-mingw-2
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-mingw-1
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-1
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: x86_64-mingw-2
|
||||
env:
|
||||
SCRIPT: make ci-mingw-subset-2
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
|
||||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-x86_64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler"
|
||||
SCRIPT: PGO_HOST=x86_64-pc-windows-msvc python src/ci/stage-build.py python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-i686-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler"
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-aarch64-msvc
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler"
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
WINDOWS_SDK_20348_HACK: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-i686-mingw
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
|
||||
|
|
@ -467,7 +467,7 @@ jobs:
|
|||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
CUSTOM_MINGW: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-x86_64-mingw
|
||||
env:
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
|
|
@ -475,12 +475,12 @@ jobs:
|
|||
NO_DOWNLOAD_CI_LLVM: 1
|
||||
CUSTOM_MINGW: 1
|
||||
DIST_REQUIRE_ALL_TOOLS: 1
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
- name: dist-x86_64-msvc-alt
|
||||
env:
|
||||
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-extended --enable-profiler"
|
||||
SCRIPT: python x.py dist bootstrap --include-default-paths
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
timeout-minutes: 600
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
|
|
@ -595,7 +595,7 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- name: dist-x86_64-linux
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
env: {}
|
||||
timeout-minutes: 600
|
||||
runs-on: "${{ matrix.os }}"
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -21,6 +21,7 @@ Session.vim
|
|||
.project
|
||||
.favorites.json
|
||||
.settings/
|
||||
.vs/
|
||||
|
||||
## Tool
|
||||
.valgrindrc
|
||||
|
|
|
|||
57
Cargo.lock
57
Cargo.lock
|
|
@ -898,7 +898,7 @@ dependencies = [
|
|||
"tracing-subscriber",
|
||||
"unified-diff",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2273,7 +2273,7 @@ dependencies = [
|
|||
"dirs",
|
||||
"gix-path",
|
||||
"libc",
|
||||
"windows",
|
||||
"windows 0.43.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3103,9 +3103,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.4.25"
|
||||
version = "0.4.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d1ed28d5903dde77bd5182645078a37ee57014cac6ccb2d54e1d6496386648e4"
|
||||
checksum = "764dcbfc2e5f868bc1b566eb179dff1a06458fd0cff846aae2579392dd3f01a0"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"anyhow",
|
||||
|
|
@ -4529,7 +4529,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"thin-vec",
|
||||
"tracing",
|
||||
"winapi",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4588,7 +4588,7 @@ dependencies = [
|
|||
"rustc_ty_utils",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"winapi",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4636,7 +4636,7 @@ dependencies = [
|
|||
"termize",
|
||||
"tracing",
|
||||
"unicode-width",
|
||||
"winapi",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5277,7 +5277,7 @@ dependencies = [
|
|||
"smallvec",
|
||||
"termize",
|
||||
"tracing",
|
||||
"winapi",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6908,6 +6908,15 @@ dependencies = [
|
|||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
|
@ -6934,9 +6943,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
|
|
@ -6949,45 +6958,45 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use rustc_errors::Applicability;
|
|||
use rustc_expand::base::*;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::{sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{FileNameDisplayPreference, Span};
|
||||
use std::iter;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
|
|
@ -33,7 +33,23 @@ pub fn expand_test_case(
|
|||
}
|
||||
|
||||
let sp = ecx.with_def_site_ctxt(attr_sp);
|
||||
let mut item = anno_item.expect_item();
|
||||
let (mut item, is_stmt) = match anno_item {
|
||||
Annotatable::Item(item) => (item, false),
|
||||
Annotatable::Stmt(stmt) if let ast::StmtKind::Item(_) = stmt.kind => if let ast::StmtKind::Item(i) = stmt.into_inner().kind {
|
||||
(i, true)
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
_ => {
|
||||
ecx.struct_span_err(
|
||||
anno_item.span(),
|
||||
"`#[test_case]` attribute is only allowed on items",
|
||||
)
|
||||
.emit();
|
||||
|
||||
return vec![];
|
||||
}
|
||||
};
|
||||
item = item.map(|mut item| {
|
||||
let test_path_symbol = Symbol::intern(&item_path(
|
||||
// skip the name of the root module
|
||||
|
|
@ -50,7 +66,13 @@ pub fn expand_test_case(
|
|||
item
|
||||
});
|
||||
|
||||
return vec![Annotatable::Item(item)];
|
||||
let ret = if is_stmt {
|
||||
Annotatable::Stmt(P(ecx.stmt_item(item.span, item)))
|
||||
} else {
|
||||
Annotatable::Item(item)
|
||||
};
|
||||
|
||||
vec![ret]
|
||||
}
|
||||
|
||||
pub fn expand_test(
|
||||
|
|
@ -231,6 +253,8 @@ pub fn expand_test_or_bench(
|
|||
&item.ident,
|
||||
));
|
||||
|
||||
let location_info = get_location_info(cx, &item);
|
||||
|
||||
let mut test_const = cx.item(
|
||||
sp,
|
||||
Ident::new(item.ident.name, sp),
|
||||
|
|
@ -280,6 +304,16 @@ pub fn expand_test_or_bench(
|
|||
cx.expr_none(sp)
|
||||
},
|
||||
),
|
||||
// source_file: <relative_path_of_source_file>
|
||||
field("source_file", cx.expr_str(sp, location_info.0)),
|
||||
// start_line: start line of the test fn identifier.
|
||||
field("start_line", cx.expr_usize(sp, location_info.1)),
|
||||
// start_col: start column of the test fn identifier.
|
||||
field("start_col", cx.expr_usize(sp, location_info.2)),
|
||||
// end_line: end line of the test fn identifier.
|
||||
field("end_line", cx.expr_usize(sp, location_info.3)),
|
||||
// end_col: end column of the test fn identifier.
|
||||
field("end_col", cx.expr_usize(sp, location_info.4)),
|
||||
// compile_fail: true | false
|
||||
field("compile_fail", cx.expr_bool(sp, false)),
|
||||
// no_run: true | false
|
||||
|
|
@ -364,6 +398,19 @@ pub fn expand_test_or_bench(
|
|||
}
|
||||
}
|
||||
|
||||
fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
|
||||
let span = item.ident.span;
|
||||
let (source_file, lo_line, lo_col, hi_line, hi_col) =
|
||||
cx.sess.source_map().span_to_location_info(span);
|
||||
|
||||
let file_name = match source_file {
|
||||
Some(sf) => sf.name.display(FileNameDisplayPreference::Remapped).to_string(),
|
||||
None => "no-location".to_string(),
|
||||
};
|
||||
|
||||
(Symbol::intern(&file_name), lo_line, lo_col, hi_line, hi_col)
|
||||
}
|
||||
|
||||
fn item_path(mod_path: &[Ident], item_ident: &Ident) -> String {
|
||||
mod_path
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -358,9 +358,9 @@ fn link_rlib<'a>(
|
|||
let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
|
||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
|
||||
packed_bundled_libs.push(wrapper_file);
|
||||
} else if let Some(name) = lib.name {
|
||||
} else {
|
||||
let path =
|
||||
find_native_static_library(name.as_str(), lib.verbatim, &lib_search_paths, sess);
|
||||
find_native_static_library(lib.name.as_str(), lib.verbatim, &lib_search_paths, sess);
|
||||
ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
|
||||
sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })});
|
||||
}
|
||||
|
|
@ -436,7 +436,7 @@ fn collate_raw_dylibs<'a, 'b>(
|
|||
for lib in used_libraries {
|
||||
if lib.kind == NativeLibKind::RawDylib {
|
||||
let ext = if lib.verbatim { "" } else { ".dll" };
|
||||
let name = format!("{}{}", lib.name.expect("unnamed raw-dylib library"), ext);
|
||||
let name = format!("{}{}", lib.name, ext);
|
||||
let imports = dylib_table.entry(name.clone()).or_default();
|
||||
for import in &lib.dll_imports {
|
||||
if let Some(old_import) = imports.insert(import.name, import) {
|
||||
|
|
@ -1296,7 +1296,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
|
|||
.iter()
|
||||
.filter(|l| relevant_lib(sess, l))
|
||||
.filter_map(|lib| {
|
||||
let name = lib.name?;
|
||||
let name = lib.name;
|
||||
match lib.kind {
|
||||
NativeLibKind::Static { bundle: Some(false), .. }
|
||||
| NativeLibKind::Dylib { .. }
|
||||
|
|
@ -1317,6 +1317,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
|
|||
// These are included, no need to print them
|
||||
NativeLibKind::Static { bundle: None | Some(true), .. }
|
||||
| NativeLibKind::LinkArg
|
||||
| NativeLibKind::WasmImportModule
|
||||
| NativeLibKind::RawDylib => None,
|
||||
}
|
||||
})
|
||||
|
|
@ -2275,21 +2276,18 @@ fn add_native_libs_from_crate(
|
|||
|
||||
let mut last = (None, NativeLibKind::Unspecified, false);
|
||||
for lib in native_libs {
|
||||
let Some(name) = lib.name else {
|
||||
continue;
|
||||
};
|
||||
if !relevant_lib(sess, lib) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if this library is the same as the last.
|
||||
last = if (lib.name, lib.kind, lib.verbatim) == last {
|
||||
last = if (Some(lib.name), lib.kind, lib.verbatim) == last {
|
||||
continue;
|
||||
} else {
|
||||
(lib.name, lib.kind, lib.verbatim)
|
||||
(Some(lib.name), lib.kind, lib.verbatim)
|
||||
};
|
||||
|
||||
let name = name.as_str();
|
||||
let name = lib.name.as_str();
|
||||
let verbatim = lib.verbatim;
|
||||
match lib.kind {
|
||||
NativeLibKind::Static { bundle, whole_archive } => {
|
||||
|
|
@ -2346,6 +2344,7 @@ fn add_native_libs_from_crate(
|
|||
NativeLibKind::RawDylib => {
|
||||
// Handled separately in `linker_with_args`.
|
||||
}
|
||||
NativeLibKind::WasmImportModule => {}
|
||||
NativeLibKind::LinkArg => {
|
||||
if link_static {
|
||||
cmd.arg(name);
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, S
|
|||
|
||||
let mut ret = FxHashMap::default();
|
||||
for (def_id, lib) in tcx.foreign_modules(cnum).iter() {
|
||||
let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module);
|
||||
let module = def_id_to_native_lib.get(&def_id).and_then(|s| s.wasm_import_module());
|
||||
let Some(module) = module else { continue };
|
||||
ret.extend(lib.foreign_items.iter().map(|id| {
|
||||
assert_eq!(id.krate, cnum);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ bitflags::bitflags! {
|
|||
#[derive(Clone, Debug, Encodable, Decodable, HashStable)]
|
||||
pub struct NativeLib {
|
||||
pub kind: NativeLibKind,
|
||||
pub name: Option<Symbol>,
|
||||
pub name: Symbol,
|
||||
pub filename: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
pub verbatim: bool,
|
||||
|
|
|
|||
|
|
@ -1475,7 +1475,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
) -> OperandRef<'tcx, Bx::Value> {
|
||||
let tcx = bx.tcx();
|
||||
|
||||
let mut span_to_caller_location = |span: Span| {
|
||||
let mut span_to_caller_location = |mut span: Span| {
|
||||
// Remove `Inlined` marks as they pollute `expansion_cause`.
|
||||
while span.is_inlined() {
|
||||
span.remove_mark();
|
||||
}
|
||||
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
|
||||
let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
|
||||
let const_loc = tcx.const_caller_location((
|
||||
|
|
|
|||
|
|
@ -111,7 +111,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
location
|
||||
}
|
||||
|
||||
pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
|
||||
pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) {
|
||||
// Remove `Inlined` marks as they pollute `expansion_cause`.
|
||||
while span.is_inlined() {
|
||||
span.remove_mark();
|
||||
}
|
||||
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
|
||||
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
|
||||
(
|
||||
|
|
|
|||
|
|
@ -36,8 +36,15 @@ elsa = "1.8"
|
|||
[dependencies.parking_lot]
|
||||
version = "0.11"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.46.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_IO",
|
||||
"Win32_System_ProcessStatus",
|
||||
"Win32_System_Threading",
|
||||
]
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
memmap2 = "0.2.1"
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
//! green/native threading. This is just a bare-bones enough solution for
|
||||
//! librustdoc, it is not production quality at all.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(nonstandard_style)]
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
mod linux;
|
||||
|
|
@ -16,7 +13,7 @@ cfg_if! {
|
|||
use unix as imp;
|
||||
} else if #[cfg(windows)] {
|
||||
mod windows;
|
||||
use windows as imp;
|
||||
use self::windows as imp;
|
||||
} else {
|
||||
mod unsupported;
|
||||
use unsupported as imp;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::os::windows::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
|
||||
use winapi::um::fileapi::LockFileEx;
|
||||
use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED};
|
||||
use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
|
||||
use windows::{
|
||||
Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE},
|
||||
Win32::Storage::FileSystem::{
|
||||
LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK,
|
||||
LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS,
|
||||
},
|
||||
Win32::System::IO::OVERLAPPED,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Lock {
|
||||
|
|
@ -25,7 +28,7 @@ impl Lock {
|
|||
let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||
|
||||
let mut open_options = OpenOptions::new();
|
||||
open_options.read(true).share_mode(share_mode);
|
||||
open_options.read(true).share_mode(share_mode.0);
|
||||
|
||||
if create {
|
||||
open_options.create(true).write(true);
|
||||
|
|
@ -43,33 +46,42 @@ impl Lock {
|
|||
}
|
||||
};
|
||||
|
||||
let ret = unsafe {
|
||||
let mut overlapped: OVERLAPPED = mem::zeroed();
|
||||
|
||||
let mut dwFlags = 0;
|
||||
if !wait {
|
||||
dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
|
||||
}
|
||||
|
||||
if exclusive {
|
||||
dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
}
|
||||
|
||||
debug!("attempting to acquire lock on lock file `{}`", p.display());
|
||||
LockFileEx(file.as_raw_handle(), dwFlags, 0, 0xFFFF_FFFF, 0xFFFF_FFFF, &mut overlapped)
|
||||
};
|
||||
if ret == 0 {
|
||||
let err = io::Error::last_os_error();
|
||||
debug!("failed acquiring file lock: {}", err);
|
||||
Err(err)
|
||||
} else {
|
||||
debug!("successfully acquired lock");
|
||||
Ok(Lock { _file: file })
|
||||
let mut flags = LOCK_FILE_FLAGS::default();
|
||||
if !wait {
|
||||
flags |= LOCKFILE_FAIL_IMMEDIATELY;
|
||||
}
|
||||
|
||||
if exclusive {
|
||||
flags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
}
|
||||
|
||||
let mut overlapped = OVERLAPPED::default();
|
||||
|
||||
debug!("attempting to acquire lock on lock file `{}`", p.display());
|
||||
|
||||
unsafe {
|
||||
LockFileEx(
|
||||
HANDLE(file.as_raw_handle() as isize),
|
||||
flags,
|
||||
0,
|
||||
u32::MAX,
|
||||
u32::MAX,
|
||||
&mut overlapped,
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.map_err(|e| {
|
||||
let err = io::Error::from_raw_os_error(e.code().0);
|
||||
debug!("failed acquiring file lock: {}", err);
|
||||
err
|
||||
})?;
|
||||
|
||||
debug!("successfully acquired lock");
|
||||
Ok(Lock { _file: file })
|
||||
}
|
||||
|
||||
pub fn error_unsupported(err: &io::Error) -> bool {
|
||||
err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
|
||||
err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -796,21 +796,26 @@ fn get_thread_id() -> u32 {
|
|||
cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
pub fn get_resident_set_size() -> Option<usize> {
|
||||
use std::mem::{self, MaybeUninit};
|
||||
use winapi::shared::minwindef::DWORD;
|
||||
use winapi::um::processthreadsapi::GetCurrentProcess;
|
||||
use winapi::um::psapi::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS};
|
||||
use std::mem;
|
||||
|
||||
let mut pmc = MaybeUninit::<PROCESS_MEMORY_COUNTERS>::uninit();
|
||||
match unsafe {
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), pmc.as_mut_ptr(), mem::size_of_val(&pmc) as DWORD)
|
||||
} {
|
||||
0 => None,
|
||||
_ => {
|
||||
let pmc = unsafe { pmc.assume_init() };
|
||||
Some(pmc.WorkingSetSize as usize)
|
||||
}
|
||||
use windows::{
|
||||
Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
|
||||
Win32::System::Threading::GetCurrentProcess,
|
||||
};
|
||||
|
||||
let mut pmc = PROCESS_MEMORY_COUNTERS::default();
|
||||
let pmc_size = mem::size_of_val(&pmc);
|
||||
unsafe {
|
||||
K32GetProcessMemoryInfo(
|
||||
GetCurrentProcess(),
|
||||
&mut pmc,
|
||||
pmc_size as u32,
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.ok()?;
|
||||
|
||||
Some(pmc.WorkingSetSize)
|
||||
}
|
||||
} else if #[cfg(target_os = "macos")] {
|
||||
pub fn get_resident_set_size() -> Option<usize> {
|
||||
|
|
|
|||
|
|
@ -54,8 +54,11 @@ rustc_hir_analysis = { path = "../rustc_hir_analysis" }
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] }
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.46.0"
|
||||
features = [
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
]
|
||||
|
||||
[features]
|
||||
llvm = ['rustc_interface/llvm']
|
||||
|
|
|
|||
|
|
@ -1246,11 +1246,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
|
|||
interface::try_print_query_stack(&handler, num_frames);
|
||||
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
|
||||
// Trigger a debugger if we crashed during bootstrap
|
||||
winapi::um::debugapi::DebugBreak();
|
||||
}
|
||||
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
|
||||
// Trigger a debugger if we crashed during bootstrap
|
||||
unsafe { windows::Win32::System::Diagnostics::Debug::DebugBreak() };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,8 +25,14 @@ termize = "0.1.1"
|
|||
serde = { version = "1.0.125", features = [ "derive" ] }
|
||||
serde_json = "1.0.59"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.46.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_WindowsProgramming",
|
||||
]
|
||||
|
||||
[features]
|
||||
rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler']
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
|
|||
use std::ffi::CString;
|
||||
use std::io;
|
||||
|
||||
use winapi::shared::ntdef::HANDLE;
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
|
||||
use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
|
||||
use windows::{
|
||||
core::PCSTR,
|
||||
Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
|
||||
Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject},
|
||||
Win32::System::WindowsProgramming::INFINITE,
|
||||
};
|
||||
|
||||
struct Handle(HANDLE);
|
||||
|
||||
|
|
@ -42,49 +44,38 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
|
|||
}
|
||||
|
||||
let cname = CString::new(name).unwrap();
|
||||
unsafe {
|
||||
// Create a named mutex, with no security attributes and also not
|
||||
// acquired when we create it.
|
||||
//
|
||||
// This will silently create one if it doesn't already exist, or it'll
|
||||
// open up a handle to one if it already exists.
|
||||
let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
|
||||
if mutex.is_null() {
|
||||
panic!(
|
||||
"failed to create global mutex named `{}`: {}",
|
||||
name,
|
||||
io::Error::last_os_error()
|
||||
);
|
||||
}
|
||||
let mutex = Handle(mutex);
|
||||
// Create a named mutex, with no security attributes and also not
|
||||
// acquired when we create it.
|
||||
//
|
||||
// This will silently create one if it doesn't already exist, or it'll
|
||||
// open up a handle to one if it already exists.
|
||||
let mutex = unsafe { CreateMutexA(None, false, PCSTR::from_raw(cname.as_ptr().cast())) }
|
||||
.unwrap_or_else(|_| panic!("failed to create global mutex named `{}`", name));
|
||||
let mutex = Handle(mutex);
|
||||
|
||||
// Acquire the lock through `WaitForSingleObject`.
|
||||
//
|
||||
// A return value of `WAIT_OBJECT_0` means we successfully acquired it.
|
||||
//
|
||||
// A return value of `WAIT_ABANDONED` means that the previous holder of
|
||||
// the thread exited without calling `ReleaseMutex`. This can happen,
|
||||
// for example, when the compiler crashes or is interrupted via ctrl-c
|
||||
// or the like. In this case, however, we are still transferred
|
||||
// ownership of the lock so we continue.
|
||||
//
|
||||
// If an error happens.. well... that's surprising!
|
||||
match WaitForSingleObject(mutex.0, INFINITE) {
|
||||
WAIT_OBJECT_0 | WAIT_ABANDONED => {}
|
||||
code => {
|
||||
panic!(
|
||||
"WaitForSingleObject failed on global mutex named \
|
||||
`{}`: {} (ret={:x})",
|
||||
name,
|
||||
io::Error::last_os_error(),
|
||||
code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a guard which will call `ReleaseMutex` when dropped.
|
||||
Box::new(Guard(mutex))
|
||||
// Acquire the lock through `WaitForSingleObject`.
|
||||
//
|
||||
// A return value of `WAIT_OBJECT_0` means we successfully acquired it.
|
||||
//
|
||||
// A return value of `WAIT_ABANDONED` means that the previous holder of
|
||||
// the thread exited without calling `ReleaseMutex`. This can happen,
|
||||
// for example, when the compiler crashes or is interrupted via ctrl-c
|
||||
// or the like. In this case, however, we are still transferred
|
||||
// ownership of the lock so we continue.
|
||||
//
|
||||
// If an error happens.. well... that's surprising!
|
||||
match unsafe { WaitForSingleObject(mutex.0, INFINITE) } {
|
||||
WAIT_OBJECT_0 | WAIT_ABANDONED => (),
|
||||
err => panic!(
|
||||
"WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})",
|
||||
name,
|
||||
io::Error::last_os_error(),
|
||||
err.0
|
||||
),
|
||||
}
|
||||
|
||||
// Return a guard which will call `ReleaseMutex` when dropped.
|
||||
Box::new(Guard(mutex))
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
|
|
|
|||
|
|
@ -3068,7 +3068,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
// generate the def_id of an associated type for the trait and return as
|
||||
// type a projection.
|
||||
let def_id = if in_trait && tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
tcx.associated_item_for_impl_trait_in_trait(local_def_id).to_def_id()
|
||||
tcx.associated_type_for_impl_trait_in_trait(local_def_id).to_def_id()
|
||||
} else {
|
||||
local_def_id.to_def_id()
|
||||
};
|
||||
|
|
@ -3152,8 +3152,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
|||
|
||||
debug!("impl_trait_ty_to_ty: generics={:?}", generics);
|
||||
let substs = InternalSubsts::for_item(tcx, def_id, |param, _| {
|
||||
if let Some(i) = (param.index as usize).checked_sub(generics.parent_count) {
|
||||
// Our own parameters are the resolved lifetimes.
|
||||
// We use `generics.count() - lifetimes.len()` here instead of `generics.parent_count`
|
||||
// since return-position impl trait in trait squashes all of the generics from its source fn
|
||||
// into its own generics, so the opaque's "own" params isn't always just lifetimes.
|
||||
if let Some(i) = (param.index as usize).checked_sub(generics.count() - lifetimes.len())
|
||||
{
|
||||
// Resolve our own lifetime parameters.
|
||||
let GenericParamDefKind::Lifetime { .. } = param.kind else { bug!() };
|
||||
let hir::GenericArg::Lifetime(lifetime) = &lifetimes[i] else { bug!() };
|
||||
self.ast_region_to_region(lifetime, None).into()
|
||||
|
|
|
|||
|
|
@ -278,8 +278,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
}
|
||||
TraitItemKind::Const(ty, body_id) => body_id
|
||||
.and_then(|body_id| {
|
||||
is_suggestable_infer_ty(ty)
|
||||
.then(|| infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant",))
|
||||
is_suggestable_infer_ty(ty).then(|| {
|
||||
infer_placeholder_type(
|
||||
tcx, def_id, body_id, ty.span, item.ident, "constant",
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| icx.to_ty(ty)),
|
||||
TraitItemKind::Type(_, Some(ty)) => icx.to_ty(ty),
|
||||
|
|
@ -335,14 +338,15 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
}
|
||||
}
|
||||
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
|
||||
ItemKind::Impl(hir::Impl { self_ty, .. }) => {
|
||||
match self_ty.find_self_aliases() {
|
||||
spans if spans.len() > 0 => {
|
||||
let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
|
||||
tcx.ty_error(guar)
|
||||
},
|
||||
_ => icx.to_ty(*self_ty),
|
||||
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
|
||||
spans if spans.len() > 0 => {
|
||||
let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
|
||||
span: spans.into(),
|
||||
note: (),
|
||||
});
|
||||
tcx.ty_error(guar)
|
||||
}
|
||||
_ => icx.to_ty(*self_ty),
|
||||
},
|
||||
ItemKind::Fn(..) => {
|
||||
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
|
||||
|
|
@ -364,7 +368,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
..
|
||||
}) => {
|
||||
if in_trait && !tcx.impl_defaultness(owner).has_value() {
|
||||
span_bug!(tcx.def_span(def_id), "tried to get type of this RPITIT with no definition");
|
||||
span_bug!(
|
||||
tcx.def_span(def_id),
|
||||
"tried to get type of this RPITIT with no definition"
|
||||
);
|
||||
}
|
||||
find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
|
||||
}
|
||||
|
|
@ -453,15 +460,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
|
||||
}
|
||||
|
||||
Node::TypeBinding(
|
||||
TypeBinding {
|
||||
hir_id: binding_id,
|
||||
kind: TypeBindingKind::Equality { term: Term::Const(e) },
|
||||
ident,
|
||||
..
|
||||
},
|
||||
) if let Node::TraitRef(trait_ref) =
|
||||
tcx.hir().get_parent(*binding_id)
|
||||
Node::TypeBinding(TypeBinding {
|
||||
hir_id: binding_id,
|
||||
kind: TypeBindingKind::Equality { term: Term::Const(e) },
|
||||
ident,
|
||||
..
|
||||
}) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
|
||||
&& e.hir_id == hir_id =>
|
||||
{
|
||||
let Some(trait_def_id) = trait_ref.trait_def_id() else {
|
||||
|
|
@ -475,7 +479,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
def_id.to_def_id(),
|
||||
);
|
||||
if let Some(assoc_item) = assoc_item {
|
||||
tcx.type_of(assoc_item.def_id).subst_identity()
|
||||
tcx.type_of(assoc_item.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic")
|
||||
} else {
|
||||
// FIXME(associated_const_equality): add a useful error message here.
|
||||
tcx.ty_error_with_message(
|
||||
|
|
@ -485,10 +491,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
}
|
||||
}
|
||||
|
||||
Node::TypeBinding(
|
||||
TypeBinding { hir_id: binding_id, gen_args, kind, ident, .. },
|
||||
) if let Node::TraitRef(trait_ref) =
|
||||
tcx.hir().get_parent(*binding_id)
|
||||
Node::TypeBinding(TypeBinding {
|
||||
hir_id: binding_id,
|
||||
gen_args,
|
||||
kind,
|
||||
ident,
|
||||
..
|
||||
}) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
|
||||
&& let Some((idx, _)) =
|
||||
gen_args.args.iter().enumerate().find(|(_, arg)| {
|
||||
if let GenericArg::Const(ct) = arg {
|
||||
|
|
@ -517,15 +526,18 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<Ty<'_>>
|
|||
},
|
||||
def_id.to_def_id(),
|
||||
);
|
||||
if let Some(param)
|
||||
= assoc_item.map(|item| &tcx.generics_of(item.def_id).params[idx]).filter(|param| param.kind.is_ty_or_const())
|
||||
if let Some(assoc_item) = assoc_item
|
||||
&& let param = &tcx.generics_of(assoc_item.def_id).params[idx]
|
||||
&& matches!(param.kind, ty::GenericParamDefKind::Const { .. })
|
||||
{
|
||||
tcx.type_of(param.def_id).subst_identity()
|
||||
tcx.type_of(param.def_id)
|
||||
.no_bound_vars()
|
||||
.expect("const parameter types cannot be generic")
|
||||
} else {
|
||||
// FIXME(associated_const_equality): add a useful error message here.
|
||||
tcx.ty_error_with_message(
|
||||
DUMMY_SP,
|
||||
"Could not find associated const on trait",
|
||||
"Could not find const param on associated item",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1028,6 +1028,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
true
|
||||
}
|
||||
})
|
||||
// ensure that we don't suggest unstable methods
|
||||
.filter(|candidate| {
|
||||
// note that `DUMMY_SP` is ok here because it is only used for
|
||||
// suggestions and macro stuff which isn't applicable here.
|
||||
!matches!(
|
||||
self.tcx.eval_stability(candidate.item.def_id, None, DUMMY_SP, None),
|
||||
stability::EvalResult::Deny { .. }
|
||||
)
|
||||
})
|
||||
.map(|candidate| candidate.item.ident(self.tcx))
|
||||
.filter(|&name| set.insert(name))
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -615,9 +615,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
}
|
||||
|
||||
let report_path_match = |err: &mut Diagnostic, did1: DefId, did2: DefId| {
|
||||
// Only external crates, if either is from a local
|
||||
// module we could have false positives
|
||||
if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate {
|
||||
// Only report definitions from different crates. If both definitions
|
||||
// are from a local module we could have false positives, e.g.
|
||||
// let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
|
||||
if did1.krate != did2.krate {
|
||||
let abs_path =
|
||||
|def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]);
|
||||
|
||||
|
|
@ -629,10 +630,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
};
|
||||
if same_path().unwrap_or(false) {
|
||||
let crate_name = self.tcx.crate_name(did1.krate);
|
||||
err.note(&format!(
|
||||
"perhaps two different versions of crate `{}` are being used?",
|
||||
crate_name
|
||||
));
|
||||
let msg = if did1.is_local() || did2.is_local() {
|
||||
format!(
|
||||
"the crate `{crate_name}` is compiled multiple times, possibly with different configurations"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"perhaps two different versions of crate `{crate_name}` are being used?"
|
||||
)
|
||||
};
|
||||
err.note(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -508,3 +508,6 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass
|
|||
.specifically = this associated type bound is unsatisfied for `{$proj_ty}`
|
||||
|
||||
lint_opaque_hidden_inferred_bound_sugg = add this bound
|
||||
|
||||
lint_useless_anonymous_reexport = useless anonymous re-export
|
||||
.note = only anonymous re-exports of traits are useful, this is {$article} `{$desc}`
|
||||
|
|
|
|||
|
|
@ -2781,8 +2781,7 @@ impl ClashingExternDeclarations {
|
|||
|
||||
// Given a transparent newtype, reach through and grab the inner
|
||||
// type unless the newtype makes the type non-null.
|
||||
let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> {
|
||||
let mut ty = ty;
|
||||
let non_transparent_ty = |mut ty: Ty<'tcx>| -> Ty<'tcx> {
|
||||
loop {
|
||||
if let ty::Adt(def, substs) = *ty.kind() {
|
||||
let is_transparent = def.repr().transparent();
|
||||
|
|
@ -2792,14 +2791,14 @@ impl ClashingExternDeclarations {
|
|||
ty, is_transparent, is_non_null
|
||||
);
|
||||
if is_transparent && !is_non_null {
|
||||
debug_assert!(def.variants().len() == 1);
|
||||
debug_assert_eq!(def.variants().len(), 1);
|
||||
let v = &def.variant(VariantIdx::new(0));
|
||||
ty = transparent_newtype_field(tcx, v)
|
||||
.expect(
|
||||
"single-variant transparent structure with zero-sized field",
|
||||
)
|
||||
.ty(tcx, substs);
|
||||
continue;
|
||||
// continue with `ty`'s non-ZST field,
|
||||
// otherwise `ty` is a ZST and we can return
|
||||
if let Some(field) = transparent_newtype_field(tcx, v) {
|
||||
ty = field.ty(tcx, substs);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("non_transparent_ty -> {:?}", ty);
|
||||
|
|
@ -2813,10 +2812,8 @@ impl ClashingExternDeclarations {
|
|||
if !seen_types.insert((a, b)) {
|
||||
// We've encountered a cycle. There's no point going any further -- the types are
|
||||
// structurally the same.
|
||||
return true;
|
||||
}
|
||||
let tcx = cx.tcx;
|
||||
if a == b {
|
||||
true
|
||||
} else if a == b {
|
||||
// All nominally-same types are structurally same, too.
|
||||
true
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ mod opaque_hidden_inferred_bound;
|
|||
mod pass_by_value;
|
||||
mod passes;
|
||||
mod redundant_semicolon;
|
||||
mod reexports;
|
||||
mod traits;
|
||||
mod types;
|
||||
mod unused;
|
||||
|
|
@ -111,6 +112,7 @@ use noop_method_call::*;
|
|||
use opaque_hidden_inferred_bound::*;
|
||||
use pass_by_value::*;
|
||||
use redundant_semicolon::*;
|
||||
use reexports::*;
|
||||
use traits::*;
|
||||
use types::*;
|
||||
use unused::*;
|
||||
|
|
@ -242,6 +244,7 @@ late_lint_methods!(
|
|||
OpaqueHiddenInferredBound: OpaqueHiddenInferredBound,
|
||||
MultipleSupertraitUpcastable: MultipleSupertraitUpcastable,
|
||||
MapUnitFn: MapUnitFn,
|
||||
UselessAnonymousReexport: UselessAnonymousReexport,
|
||||
]
|
||||
]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1528,3 +1528,11 @@ pub struct UnusedAllocationDiag;
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_unused_allocation_mut)]
|
||||
pub struct UnusedAllocationMutDiag;
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_useless_anonymous_reexport)]
|
||||
#[note]
|
||||
pub struct UselessAnonymousReexportDiag {
|
||||
pub article: &'static str,
|
||||
pub desc: &'static str,
|
||||
}
|
||||
|
|
|
|||
82
compiler/rustc_lint/src/reexports.rs
Normal file
82
compiler/rustc_lint/src/reexports.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use crate::lints::UselessAnonymousReexportDiag;
|
||||
use crate::{LateContext, LateLintPass, LintContext};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{Item, ItemKind, UseKind};
|
||||
use rustc_middle::ty::Visibility;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::Span;
|
||||
|
||||
declare_lint! {
|
||||
/// The `useless_anonymous_reexport` lint checks if anonymous re-exports
|
||||
/// are re-exports of traits.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust,compile_fail
|
||||
/// #![deny(useless_anonymous_reexport)]
|
||||
///
|
||||
/// mod sub {
|
||||
/// pub struct Bar;
|
||||
/// }
|
||||
///
|
||||
/// pub use self::sub::Bar as _;
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// Anonymous re-exports are only useful if it's a re-export of a trait
|
||||
/// in case you want to give access to it. If you re-export any other kind,
|
||||
/// you won't be able to use it since its name won't be accessible.
|
||||
pub USELESS_ANONYMOUS_REEXPORT,
|
||||
Warn,
|
||||
"useless anonymous re-export"
|
||||
}
|
||||
|
||||
declare_lint_pass!(UselessAnonymousReexport => [USELESS_ANONYMOUS_REEXPORT]);
|
||||
|
||||
fn emit_err(cx: &LateContext<'_>, span: Span, def_id: DefId) {
|
||||
let article = cx.tcx.def_descr_article(def_id);
|
||||
let desc = cx.tcx.def_descr(def_id);
|
||||
cx.emit_spanned_lint(
|
||||
USELESS_ANONYMOUS_REEXPORT,
|
||||
span,
|
||||
UselessAnonymousReexportDiag { article, desc },
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for UselessAnonymousReexport {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
|
||||
if let ItemKind::Use(path, kind) = item.kind &&
|
||||
!matches!(kind, UseKind::Glob) &&
|
||||
item.ident.name == kw::Underscore &&
|
||||
// We only want re-exports. If it's just a `use X;`, then we ignore it.
|
||||
match cx.tcx.local_visibility(item.owner_id.def_id) {
|
||||
Visibility::Public => true,
|
||||
Visibility::Restricted(level) => {
|
||||
level != cx.tcx.parent_module_from_def_id(item.owner_id.def_id)
|
||||
}
|
||||
}
|
||||
{
|
||||
for def_id in path.res.iter().filter_map(|r| r.opt_def_id()) {
|
||||
match cx.tcx.def_kind(def_id) {
|
||||
DefKind::Trait | DefKind::TraitAlias => {}
|
||||
DefKind::TyAlias => {
|
||||
let ty = cx.tcx.type_of(def_id);
|
||||
if !ty.0.is_trait() {
|
||||
emit_err(cx, item.span, def_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
emit_err(cx, item.span, def_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ pub fn find_native_static_library(
|
|||
}
|
||||
|
||||
fn find_bundled_library(
|
||||
name: Option<Symbol>,
|
||||
name: Symbol,
|
||||
verbatim: Option<bool>,
|
||||
kind: NativeLibKind,
|
||||
has_cfg: bool,
|
||||
|
|
@ -58,7 +58,7 @@ fn find_bundled_library(
|
|||
{
|
||||
let verbatim = verbatim.unwrap_or(false);
|
||||
let search_paths = &sess.target_filesearch(PathKind::Native).search_path_dirs();
|
||||
return find_native_static_library(name.unwrap().as_str(), verbatim, search_paths, sess)
|
||||
return find_native_static_library(name.as_str(), verbatim, search_paths, sess)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.map(Symbol::intern);
|
||||
|
|
@ -336,10 +336,16 @@ impl<'tcx> Collector<'tcx> {
|
|||
if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
|
||||
sess.emit_err(errors::IncompatibleWasmLink { span });
|
||||
}
|
||||
} else if name.is_none() {
|
||||
sess.emit_err(errors::LinkRequiresName { span: m.span });
|
||||
}
|
||||
|
||||
if wasm_import_module.is_some() {
|
||||
(name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
|
||||
}
|
||||
let Some((name, name_span)) = name else {
|
||||
sess.emit_err(errors::LinkRequiresName { span: m.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
// Do this outside of the loop so that `import_name_type` can be specified before `kind`.
|
||||
if let Some((_, span)) = import_name_type {
|
||||
if kind != Some(NativeLibKind::RawDylib) {
|
||||
|
|
@ -349,8 +355,8 @@ impl<'tcx> Collector<'tcx> {
|
|||
|
||||
let dll_imports = match kind {
|
||||
Some(NativeLibKind::RawDylib) => {
|
||||
if let Some((name, span)) = name && name.as_str().contains('\0') {
|
||||
sess.emit_err(errors::RawDylibNoNul { span });
|
||||
if name.as_str().contains('\0') {
|
||||
sess.emit_err(errors::RawDylibNoNul { span: name_span });
|
||||
}
|
||||
foreign_mod_items
|
||||
.iter()
|
||||
|
|
@ -389,7 +395,6 @@ impl<'tcx> Collector<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
let name = name.map(|(name, _)| name);
|
||||
let kind = kind.unwrap_or(NativeLibKind::Unspecified);
|
||||
let filename = find_bundled_library(name, verbatim, kind, cfg.is_some(), sess);
|
||||
self.libs.push(NativeLib {
|
||||
|
|
@ -398,7 +403,6 @@ impl<'tcx> Collector<'tcx> {
|
|||
kind,
|
||||
cfg,
|
||||
foreign_module: Some(it.owner_id.to_def_id()),
|
||||
wasm_import_module: wasm_import_module.map(|(name, _)| name),
|
||||
verbatim,
|
||||
dll_imports,
|
||||
});
|
||||
|
|
@ -415,11 +419,7 @@ impl<'tcx> Collector<'tcx> {
|
|||
self.tcx.sess.emit_err(errors::LibFrameworkApple);
|
||||
}
|
||||
if let Some(ref new_name) = lib.new_name {
|
||||
let any_duplicate = self
|
||||
.libs
|
||||
.iter()
|
||||
.filter_map(|lib| lib.name.as_ref())
|
||||
.any(|n| n.as_str() == lib.name);
|
||||
let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
|
||||
if new_name.is_empty() {
|
||||
self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
|
||||
} else if !any_duplicate {
|
||||
|
|
@ -444,33 +444,28 @@ impl<'tcx> Collector<'tcx> {
|
|||
let mut existing = self
|
||||
.libs
|
||||
.drain_filter(|lib| {
|
||||
if let Some(lib_name) = lib.name {
|
||||
if lib_name.as_str() == passed_lib.name {
|
||||
// FIXME: This whole logic is questionable, whether modifiers are
|
||||
// involved or not, library reordering and kind overriding without
|
||||
// explicit `:rename` in particular.
|
||||
if lib.has_modifiers() || passed_lib.has_modifiers() {
|
||||
match lib.foreign_module {
|
||||
Some(def_id) => {
|
||||
self.tcx.sess.emit_err(errors::NoLinkModOverride {
|
||||
span: Some(self.tcx.def_span(def_id)),
|
||||
})
|
||||
}
|
||||
None => self
|
||||
.tcx
|
||||
.sess
|
||||
.emit_err(errors::NoLinkModOverride { span: None }),
|
||||
};
|
||||
}
|
||||
if passed_lib.kind != NativeLibKind::Unspecified {
|
||||
lib.kind = passed_lib.kind;
|
||||
}
|
||||
if let Some(new_name) = &passed_lib.new_name {
|
||||
lib.name = Some(Symbol::intern(new_name));
|
||||
}
|
||||
lib.verbatim = passed_lib.verbatim;
|
||||
return true;
|
||||
if lib.name.as_str() == passed_lib.name {
|
||||
// FIXME: This whole logic is questionable, whether modifiers are
|
||||
// involved or not, library reordering and kind overriding without
|
||||
// explicit `:rename` in particular.
|
||||
if lib.has_modifiers() || passed_lib.has_modifiers() {
|
||||
match lib.foreign_module {
|
||||
Some(def_id) => self.tcx.sess.emit_err(errors::NoLinkModOverride {
|
||||
span: Some(self.tcx.def_span(def_id)),
|
||||
}),
|
||||
None => {
|
||||
self.tcx.sess.emit_err(errors::NoLinkModOverride { span: None })
|
||||
}
|
||||
};
|
||||
}
|
||||
if passed_lib.kind != NativeLibKind::Unspecified {
|
||||
lib.kind = passed_lib.kind;
|
||||
}
|
||||
if let Some(new_name) = &passed_lib.new_name {
|
||||
lib.name = Symbol::intern(new_name);
|
||||
}
|
||||
lib.verbatim = passed_lib.verbatim;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
})
|
||||
|
|
@ -478,7 +473,7 @@ impl<'tcx> Collector<'tcx> {
|
|||
if existing.is_empty() {
|
||||
// Add if not found
|
||||
let new_name: Option<&str> = passed_lib.new_name.as_deref();
|
||||
let name = Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name)));
|
||||
let name = Symbol::intern(new_name.unwrap_or(&passed_lib.name));
|
||||
let sess = self.tcx.sess;
|
||||
let filename =
|
||||
find_bundled_library(name, passed_lib.verbatim, passed_lib.kind, false, sess);
|
||||
|
|
@ -488,7 +483,6 @@ impl<'tcx> Collector<'tcx> {
|
|||
kind: passed_lib.kind,
|
||||
cfg: None,
|
||||
foreign_module: None,
|
||||
wasm_import_module: None,
|
||||
verbatim: passed_lib.verbatim,
|
||||
dll_imports: Vec::new(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -226,15 +226,7 @@ provide! { tcx, def_id, other, cdata,
|
|||
lookup_default_body_stability => { table }
|
||||
lookup_deprecation_entry => { table }
|
||||
params_in_repr => { table }
|
||||
// FIXME: Could be defaulted, but `LazyValue<UnusedGenericParams>` is not `FixedSizeEncoding`..
|
||||
unused_generic_params => {
|
||||
cdata
|
||||
.root
|
||||
.tables
|
||||
.unused_generic_params
|
||||
.get(cdata, def_id.index)
|
||||
.map_or_else(|| ty::UnusedGenericParams::new_all_used(), |lazy| lazy.decode((cdata, tcx)))
|
||||
}
|
||||
unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) }
|
||||
opt_def_kind => { table_direct }
|
||||
impl_parent => { table }
|
||||
impl_polarity => { table_direct }
|
||||
|
|
@ -262,7 +254,7 @@ provide! { tcx, def_id, other, cdata,
|
|||
.process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
|
||||
}
|
||||
|
||||
associated_items_for_impl_trait_in_trait => { table_defaulted_array }
|
||||
associated_types_for_impl_traits_in_associated_fn => { table_defaulted_array }
|
||||
|
||||
visibility => { cdata.get_visibility(def_id.index) }
|
||||
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
|
||||
|
|
|
|||
|
|
@ -609,10 +609,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
|
||||
_ = stat!("mir", || self.encode_mir());
|
||||
|
||||
_ = stat!("items", || {
|
||||
self.encode_def_ids();
|
||||
self.encode_info_for_items();
|
||||
});
|
||||
_ = stat!("def-ids", || self.encode_def_ids());
|
||||
|
||||
_ = stat!("items", || self.encode_info_for_items());
|
||||
|
||||
let interpret_alloc_index = stat!("interpret-alloc-index", || {
|
||||
let mut interpret_alloc_index = Vec::new();
|
||||
|
|
@ -1198,8 +1197,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
record!(self.tables.trait_impl_trait_tys[def_id] <- table);
|
||||
}
|
||||
if should_encode_fn_impl_trait_in_trait(tcx, def_id) {
|
||||
let table = tcx.associated_items_for_impl_trait_in_trait(def_id);
|
||||
record_defaulted_array!(self.tables.associated_items_for_impl_trait_in_trait[def_id] <- table);
|
||||
let table = tcx.associated_types_for_impl_traits_in_associated_fn(def_id);
|
||||
record_defaulted_array!(self.tables.associated_types_for_impl_traits_in_associated_fn[def_id] <- table);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1440,9 +1439,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
let instance =
|
||||
ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
|
||||
let unused = tcx.unused_generic_params(instance);
|
||||
if !unused.all_used() {
|
||||
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
|
||||
}
|
||||
self.tables.unused_generic_params.set(def_id.local_def_index, unused);
|
||||
}
|
||||
|
||||
// Encode all the deduced parameter attributes for everything that has MIR, even for items
|
||||
|
|
|
|||
|
|
@ -354,8 +354,9 @@ define_tables! {
|
|||
explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Predicate<'static>, Span)>>,
|
||||
inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
|
||||
inherent_impls: Table<DefIndex, LazyArray<DefIndex>>,
|
||||
associated_items_for_impl_trait_in_trait: Table<DefIndex, LazyArray<DefId>>,
|
||||
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
|
||||
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
|
||||
unused_generic_params: Table<DefIndex, UnusedGenericParams>,
|
||||
|
||||
- optional:
|
||||
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
|
||||
|
|
@ -398,7 +399,6 @@ define_tables! {
|
|||
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
|
||||
trait_item_def_id: Table<DefIndex, RawDefId>,
|
||||
expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
|
||||
unused_generic_params: Table<DefIndex, LazyValue<UnusedGenericParams>>,
|
||||
params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>,
|
||||
repr_options: Table<DefIndex, LazyValue<ReprOptions>>,
|
||||
// `def_keys` and `def_path_hashes` represent a lazy version of a
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use crate::rmeta::*;
|
|||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_hir::def::{CtorKind, CtorOf};
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_middle::ty::ParameterizedOverTcx;
|
||||
use rustc_middle::ty::{ParameterizedOverTcx, UnusedGenericParams};
|
||||
use rustc_serialize::opaque::FileEncoder;
|
||||
use rustc_serialize::Encoder as _;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
|
|
@ -50,6 +50,16 @@ impl IsDefault for DefPathHash {
|
|||
}
|
||||
}
|
||||
|
||||
impl IsDefault for UnusedGenericParams {
|
||||
fn is_default(&self) -> bool {
|
||||
// UnusedGenericParams encodes the *un*usedness as a bitset.
|
||||
// This means that 0 corresponds to all bits used, which is indeed the default.
|
||||
let is_default = self.bits() == 0;
|
||||
debug_assert_eq!(is_default, self.all_used());
|
||||
is_default
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
|
||||
/// Used mainly for Lazy positions and lengths.
|
||||
/// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
|
||||
|
|
@ -271,6 +281,21 @@ impl FixedSizeEncoding for bool {
|
|||
}
|
||||
}
|
||||
|
||||
impl FixedSizeEncoding for UnusedGenericParams {
|
||||
type ByteArray = [u8; 4];
|
||||
|
||||
#[inline]
|
||||
fn from_bytes(b: &[u8; 4]) -> Self {
|
||||
let x: u32 = u32::from_bytes(b);
|
||||
UnusedGenericParams::from_bits(x)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_to_bytes(self, b: &mut [u8; 4]) {
|
||||
self.bits().write_to_bytes(b);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(eddyb) there could be an impl for `usize`, which would enable a more
|
||||
// generic `LazyValue<T>` impl, but in the general case we might not need / want
|
||||
// to fit every `usize` in `u32`.
|
||||
|
|
|
|||
|
|
@ -785,7 +785,7 @@ rustc_queries! {
|
|||
/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it
|
||||
/// creates and returns the associated items that correspond to each impl trait in return position
|
||||
/// of the implemented trait.
|
||||
query associated_items_for_impl_trait_in_trait(fn_def_id: DefId) -> &'tcx [DefId] {
|
||||
query associated_types_for_impl_traits_in_associated_fn(fn_def_id: DefId) -> &'tcx [DefId] {
|
||||
desc { |tcx| "creating associated items for impl trait in trait returned by `{}`", tcx.def_path_str(fn_def_id) }
|
||||
cache_on_disk_if { fn_def_id.is_local() }
|
||||
separate_provide_extern
|
||||
|
|
@ -793,7 +793,7 @@ rustc_queries! {
|
|||
|
||||
/// Given an impl trait in trait `opaque_ty_def_id`, create and return the corresponding
|
||||
/// associated item.
|
||||
query associated_item_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
|
||||
query associated_type_for_impl_trait_in_trait(opaque_ty_def_id: LocalDefId) -> LocalDefId {
|
||||
desc { |tcx| "creates the associated item corresponding to the opaque type `{}`", tcx.def_path_str(opaque_ty_def_id.to_def_id()) }
|
||||
cache_on_disk_if { true }
|
||||
separate_provide_extern
|
||||
|
|
|
|||
|
|
@ -781,6 +781,12 @@ fn needs_fn_once_adapter_shim(
|
|||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Decodable, Encodable, HashStable)]
|
||||
pub struct UnusedGenericParams(FiniteBitSet<u32>);
|
||||
|
||||
impl Default for UnusedGenericParams {
|
||||
fn default() -> Self {
|
||||
UnusedGenericParams::new_all_used()
|
||||
}
|
||||
}
|
||||
|
||||
impl UnusedGenericParams {
|
||||
pub fn new_all_unused(amount: u32) -> Self {
|
||||
let mut bitset = FiniteBitSet::new_empty();
|
||||
|
|
@ -807,4 +813,12 @@ impl UnusedGenericParams {
|
|||
pub fn all_used(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
pub fn bits(&self) -> u32 {
|
||||
self.0.0
|
||||
}
|
||||
|
||||
pub fn from_bits(bits: u32) -> UnusedGenericParams {
|
||||
UnusedGenericParams(FiniteBitSet(bits))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2579,7 +2579,9 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let Some(trait_item_def_id) = item.trait_item_def_id else { return false; };
|
||||
|
||||
if self.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
return !self.associated_items_for_impl_trait_in_trait(trait_item_def_id).is_empty();
|
||||
return !self
|
||||
.associated_types_for_impl_traits_in_associated_fn(trait_item_def_id)
|
||||
.is_empty();
|
||||
}
|
||||
|
||||
// FIXME(RPITIT): This does a somewhat manual walk through the signature
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use rustc_data_structures::sharded::{self, Sharded};
|
|||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
|
||||
use rustc_data_structures::OnDrop;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
|
@ -54,6 +53,11 @@ impl From<DepNodeIndex> for QueryInvocationId {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct MarkFrame<'a> {
|
||||
index: SerializedDepNodeIndex,
|
||||
parent: Option<&'a MarkFrame<'a>>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum DepNodeColor {
|
||||
Red,
|
||||
|
|
@ -710,32 +714,26 @@ impl<K: DepKind> DepGraphData<K> {
|
|||
let prev_index = self.previous.node_to_index_opt(dep_node)?;
|
||||
|
||||
match self.colors.get(prev_index) {
|
||||
Some(DepNodeColor::Green(dep_node_index)) => return Some((prev_index, dep_node_index)),
|
||||
Some(DepNodeColor::Red) => return None,
|
||||
None => {}
|
||||
Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)),
|
||||
Some(DepNodeColor::Red) => None,
|
||||
None => {
|
||||
// This DepNode and the corresponding query invocation existed
|
||||
// in the previous compilation session too, so we can try to
|
||||
// mark it as green by recursively marking all of its
|
||||
// dependencies green.
|
||||
self.try_mark_previous_green(qcx, prev_index, &dep_node, None)
|
||||
.map(|dep_node_index| (prev_index, dep_node_index))
|
||||
}
|
||||
}
|
||||
|
||||
let backtrace = backtrace_printer(qcx.dep_context().sess(), self, prev_index);
|
||||
|
||||
// This DepNode and the corresponding query invocation existed
|
||||
// in the previous compilation session too, so we can try to
|
||||
// mark it as green by recursively marking all of its
|
||||
// dependencies green.
|
||||
let ret = self
|
||||
.try_mark_previous_green(qcx, prev_index, &dep_node)
|
||||
.map(|dep_node_index| (prev_index, dep_node_index));
|
||||
|
||||
// We succeeded, no backtrace.
|
||||
backtrace.disable();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#[instrument(skip(self, qcx, parent_dep_node_index), level = "debug")]
|
||||
#[instrument(skip(self, qcx, parent_dep_node_index, frame), level = "debug")]
|
||||
fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
|
||||
&self,
|
||||
qcx: Qcx,
|
||||
parent_dep_node_index: SerializedDepNodeIndex,
|
||||
dep_node: &DepNode<K>,
|
||||
frame: Option<&MarkFrame<'_>>,
|
||||
) -> Option<()> {
|
||||
let dep_dep_node_color = self.colors.get(parent_dep_node_index);
|
||||
let dep_dep_node = &self.previous.index_to_node(parent_dep_node_index);
|
||||
|
|
@ -767,7 +765,8 @@ impl<K: DepKind> DepGraphData<K> {
|
|||
dep_dep_node, dep_dep_node.hash,
|
||||
);
|
||||
|
||||
let node_index = self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node);
|
||||
let node_index =
|
||||
self.try_mark_previous_green(qcx, parent_dep_node_index, dep_dep_node, frame);
|
||||
|
||||
if node_index.is_some() {
|
||||
debug!("managed to MARK dependency {dep_dep_node:?} as green",);
|
||||
|
|
@ -777,7 +776,7 @@ impl<K: DepKind> DepGraphData<K> {
|
|||
|
||||
// We failed to mark it green, so we try to force the query.
|
||||
debug!("trying to force dependency {dep_dep_node:?}");
|
||||
if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
|
||||
if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node, frame) {
|
||||
// The DepNode could not be forced.
|
||||
debug!("dependency {dep_dep_node:?} could not be forced");
|
||||
return None;
|
||||
|
|
@ -816,13 +815,16 @@ impl<K: DepKind> DepGraphData<K> {
|
|||
}
|
||||
|
||||
/// Try to mark a dep-node which existed in the previous compilation session as green.
|
||||
#[instrument(skip(self, qcx, prev_dep_node_index), level = "debug")]
|
||||
#[instrument(skip(self, qcx, prev_dep_node_index, frame), level = "debug")]
|
||||
fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
|
||||
&self,
|
||||
qcx: Qcx,
|
||||
prev_dep_node_index: SerializedDepNodeIndex,
|
||||
dep_node: &DepNode<K>,
|
||||
frame: Option<&MarkFrame<'_>>,
|
||||
) -> Option<DepNodeIndex> {
|
||||
let frame = MarkFrame { index: prev_dep_node_index, parent: frame };
|
||||
|
||||
#[cfg(not(parallel_compiler))]
|
||||
{
|
||||
debug_assert!(!self.dep_node_exists(dep_node));
|
||||
|
|
@ -837,10 +839,7 @@ impl<K: DepKind> DepGraphData<K> {
|
|||
let prev_deps = self.previous.edge_targets_from(prev_dep_node_index);
|
||||
|
||||
for &dep_dep_node_index in prev_deps {
|
||||
let backtrace = backtrace_printer(qcx.dep_context().sess(), self, dep_dep_node_index);
|
||||
let success = self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node);
|
||||
backtrace.disable();
|
||||
success?;
|
||||
self.try_mark_parent_green(qcx, dep_dep_node_index, dep_node, Some(&frame))?;
|
||||
}
|
||||
|
||||
// If we got here without hitting a `return` that means that all
|
||||
|
|
@ -970,6 +969,7 @@ impl<K: DepKind> DepGraph<K> {
|
|||
}
|
||||
|
||||
pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex {
|
||||
debug_assert!(self.data.is_none());
|
||||
let index = self.virtual_dep_node_index.fetch_add(1, Relaxed);
|
||||
DepNodeIndex::from_u32(index)
|
||||
}
|
||||
|
|
@ -1414,25 +1414,25 @@ impl DepNodeColorMap {
|
|||
}
|
||||
}
|
||||
|
||||
fn backtrace_printer<'a, K: DepKind>(
|
||||
sess: &'a rustc_session::Session,
|
||||
graph: &'a DepGraphData<K>,
|
||||
node: SerializedDepNodeIndex,
|
||||
) -> OnDrop<impl Fn() + 'a> {
|
||||
OnDrop(
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
move || {
|
||||
let node = graph.previous.index_to_node(node);
|
||||
// Do not try to rely on DepNode's Debug implementation, since it may panic.
|
||||
let diag = rustc_errors::Diagnostic::new(
|
||||
rustc_errors::Level::FailureNote,
|
||||
&format!(
|
||||
"encountered while trying to mark dependency green: {:?}({})",
|
||||
node.kind, node.hash
|
||||
),
|
||||
);
|
||||
sess.diagnostic().force_print_diagnostic(diag);
|
||||
},
|
||||
)
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
pub(crate) fn print_markframe_trace<K: DepKind>(
|
||||
graph: &DepGraph<K>,
|
||||
frame: Option<&MarkFrame<'_>>,
|
||||
) {
|
||||
let data = graph.data.as_ref().unwrap();
|
||||
|
||||
eprintln!("there was a panic while trying to force a dep node");
|
||||
eprintln!("try_mark_green dep node stack:");
|
||||
|
||||
let mut i = 0;
|
||||
let mut current = frame;
|
||||
while let Some(frame) = current {
|
||||
let node = data.previous.index_to_node(frame.index);
|
||||
eprintln!("#{i} {:?}", node);
|
||||
current = frame.parent;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
eprintln!("end of try_mark_green dep node stack");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,10 @@ use rustc_data_structures::profiling::SelfProfilerRef;
|
|||
use rustc_serialize::{opaque::FileEncoder, Encodable};
|
||||
use rustc_session::Session;
|
||||
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::{fmt, panic};
|
||||
|
||||
use self::graph::{print_markframe_trace, MarkFrame};
|
||||
|
||||
pub trait DepContext: Copy {
|
||||
type DepKind: self::DepKind;
|
||||
|
|
@ -53,11 +55,23 @@ pub trait DepContext: Copy {
|
|||
}
|
||||
|
||||
/// Try to force a dep node to execute and see if it's green.
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
|
||||
#[inline]
|
||||
#[instrument(skip(self, frame), level = "debug")]
|
||||
fn try_force_from_dep_node(
|
||||
self,
|
||||
dep_node: DepNode<Self::DepKind>,
|
||||
frame: Option<&MarkFrame<'_>>,
|
||||
) -> bool {
|
||||
let cb = self.dep_kind_info(dep_node.kind);
|
||||
if let Some(f) = cb.force_from_dep_node {
|
||||
f(self, dep_node);
|
||||
if let Err(value) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||
f(self, dep_node);
|
||||
})) {
|
||||
if !value.is::<rustc_errors::FatalErrorMarker>() {
|
||||
print_markframe_trace(self.dep_graph(), frame);
|
||||
}
|
||||
panic::resume_unwind(value)
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -379,7 +379,11 @@ where
|
|||
|
||||
match JobOwner::<'_, Q::Key, Qcx::DepKind>::try_start(&qcx, state, state_lock, span, key) {
|
||||
TryGetJob::NotYetStarted(job) => {
|
||||
let (result, dep_node_index) = execute_job(query, qcx, key.clone(), dep_node, job.id);
|
||||
let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() {
|
||||
None => execute_job_non_incr(query, qcx, key, job.id),
|
||||
Some(data) => execute_job_incr(query, qcx, data, key, dep_node, job.id),
|
||||
};
|
||||
|
||||
let cache = query.query_cache(qcx);
|
||||
if query.feedable() {
|
||||
// We should not compute queries that also got a value via feeding.
|
||||
|
|
@ -413,11 +417,48 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// Fast path for when incr. comp. is off.
|
||||
#[inline(always)]
|
||||
fn execute_job<Q, Qcx>(
|
||||
fn execute_job_non_incr<Q, Qcx>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
key: Q::Key,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
where
|
||||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
|
||||
|
||||
// Fingerprint the key, just to assert that it doesn't
|
||||
// have anything we don't consider hashable
|
||||
if cfg!(debug_assertions) {
|
||||
let _ = key.to_fingerprint(*qcx.dep_context());
|
||||
}
|
||||
|
||||
let prof_timer = qcx.dep_context().profiler().query_provider();
|
||||
let result = qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key));
|
||||
let dep_node_index = qcx.dep_context().dep_graph().next_virtual_depnode_index();
|
||||
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
|
||||
|
||||
// Similarly, fingerprint the result to assert that
|
||||
// it doesn't have anything not considered hashable.
|
||||
if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result() {
|
||||
qcx.dep_context().with_stable_hashing_context(|mut hcx| {
|
||||
hash_result(&mut hcx, &result);
|
||||
});
|
||||
}
|
||||
|
||||
(result, dep_node_index)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn execute_job_incr<Q, Qcx>(
|
||||
query: Q,
|
||||
qcx: Qcx,
|
||||
dep_graph_data: &DepGraphData<Qcx::DepKind>,
|
||||
key: Q::Key,
|
||||
mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
|
||||
job_id: QueryJobId,
|
||||
) -> (Q::Value, DepNodeIndex)
|
||||
|
|
@ -425,36 +466,6 @@ where
|
|||
Q: QueryConfig<Qcx>,
|
||||
Qcx: QueryContext,
|
||||
{
|
||||
let dep_graph = qcx.dep_context().dep_graph();
|
||||
let dep_graph_data = match dep_graph.data() {
|
||||
// Fast path for when incr. comp. is off.
|
||||
None => {
|
||||
// Fingerprint the key, just to assert that it doesn't
|
||||
// have anything we don't consider hashable
|
||||
if cfg!(debug_assertions) {
|
||||
let _ = key.to_fingerprint(*qcx.dep_context());
|
||||
}
|
||||
|
||||
let prof_timer = qcx.dep_context().profiler().query_provider();
|
||||
let result =
|
||||
qcx.start_query(job_id, query.depth_limit(), None, || query.compute(qcx, key));
|
||||
let dep_node_index = dep_graph.next_virtual_depnode_index();
|
||||
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
|
||||
|
||||
// Similarly, fingerprint the result to assert that
|
||||
// it doesn't have anything not considered hashable.
|
||||
if cfg!(debug_assertions) && let Some(hash_result) = query.hash_result()
|
||||
{
|
||||
qcx.dep_context().with_stable_hashing_context(|mut hcx| {
|
||||
hash_result(&mut hcx, &result);
|
||||
});
|
||||
}
|
||||
|
||||
return (result, dep_node_index);
|
||||
}
|
||||
Some(data) => data,
|
||||
};
|
||||
|
||||
if !query.anon() && !query.eval_always() {
|
||||
// `to_dep_node` is expensive for some `DepKind`s.
|
||||
let dep_node =
|
||||
|
|
|
|||
|
|
@ -590,7 +590,6 @@ struct LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
|||
parent_scope: ParentScope<'a>,
|
||||
|
||||
/// The current set of local scopes for types and values.
|
||||
/// FIXME #4948: Reuse ribs to avoid allocation.
|
||||
ribs: PerNS<Vec<Rib<'a>>>,
|
||||
|
||||
/// Previous poped `rib`, only used for diagnostic.
|
||||
|
|
|
|||
|
|
@ -24,5 +24,9 @@ termize = "0.1.1"
|
|||
[target.'cfg(unix)'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", features = ["libloaderapi"] }
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.46.0"
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_System_LibraryLoader",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -67,12 +67,11 @@ pub enum LinkagePreference {
|
|||
#[derive(Debug, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct NativeLib {
|
||||
pub kind: NativeLibKind,
|
||||
pub name: Option<Symbol>,
|
||||
pub name: Symbol,
|
||||
/// If packed_bundled_libs enabled, actual filename of library is stored.
|
||||
pub filename: Option<Symbol>,
|
||||
pub cfg: Option<ast::MetaItem>,
|
||||
pub foreign_module: Option<DefId>,
|
||||
pub wasm_import_module: Option<Symbol>,
|
||||
pub verbatim: Option<bool>,
|
||||
pub dll_imports: Vec<DllImport>,
|
||||
}
|
||||
|
|
@ -81,6 +80,10 @@ impl NativeLib {
|
|||
pub fn has_modifiers(&self) -> bool {
|
||||
self.verbatim.is_some() || self.kind.has_modifiers()
|
||||
}
|
||||
|
||||
pub fn wasm_import_module(&self) -> Option<Symbol> {
|
||||
if self.kind == NativeLibKind::WasmImportModule { Some(self.name) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
/// Different ways that the PE Format can decorate a symbol name.
|
||||
|
|
|
|||
|
|
@ -87,35 +87,38 @@ fn current_dll_path() -> Result<PathBuf, String> {
|
|||
use std::ffi::OsString;
|
||||
use std::io;
|
||||
use std::os::windows::prelude::*;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::um::libloaderapi::{
|
||||
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
use windows::{
|
||||
core::PCWSTR,
|
||||
Win32::Foundation::HINSTANCE,
|
||||
Win32::System::LibraryLoader::{
|
||||
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
},
|
||||
};
|
||||
|
||||
let mut module = HINSTANCE::default();
|
||||
unsafe {
|
||||
let mut module = ptr::null_mut();
|
||||
let r = GetModuleHandleExW(
|
||||
GetModuleHandleExW(
|
||||
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
||||
current_dll_path as usize as *mut _,
|
||||
PCWSTR(current_dll_path as *mut u16),
|
||||
&mut module,
|
||||
);
|
||||
if r == 0 {
|
||||
return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
|
||||
}
|
||||
let mut space = Vec::with_capacity(1024);
|
||||
let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
|
||||
if r == 0 {
|
||||
return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
|
||||
}
|
||||
let r = r as usize;
|
||||
if r >= space.capacity() {
|
||||
return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
|
||||
}
|
||||
space.set_len(r);
|
||||
let os = OsString::from_wide(&space);
|
||||
Ok(PathBuf::from(os))
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let mut filename = vec![0; 1024];
|
||||
let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize;
|
||||
if n == 0 {
|
||||
return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
|
||||
}
|
||||
if n >= filename.capacity() {
|
||||
return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
filename.truncate(n);
|
||||
|
||||
Ok(OsString::from_wide(&filename).into())
|
||||
}
|
||||
|
||||
pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ pub enum NativeLibKind {
|
|||
/// Argument which is passed to linker, relative order with libraries and other arguments
|
||||
/// is preserved
|
||||
LinkArg,
|
||||
|
||||
/// Module imported from WebAssembly
|
||||
WasmImportModule,
|
||||
|
||||
/// The library kind wasn't specified, `Dylib` is currently used as a default.
|
||||
Unspecified,
|
||||
}
|
||||
|
|
@ -50,7 +54,10 @@ impl NativeLibKind {
|
|||
NativeLibKind::Dylib { as_needed } | NativeLibKind::Framework { as_needed } => {
|
||||
as_needed.is_some()
|
||||
}
|
||||
NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false,
|
||||
NativeLibKind::RawDylib
|
||||
| NativeLibKind::Unspecified
|
||||
| NativeLibKind::LinkArg
|
||||
| NativeLibKind::WasmImportModule => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -880,7 +880,7 @@ impl Span {
|
|||
pub fn fresh_expansion(self, expn_id: LocalExpnId) -> Span {
|
||||
HygieneData::with(|data| {
|
||||
self.with_ctxt(data.apply_mark(
|
||||
SyntaxContext::root(),
|
||||
self.ctxt(),
|
||||
expn_id.to_expn_id(),
|
||||
Transparency::Transparent,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -448,23 +448,34 @@ impl SourceMap {
|
|||
sp: Span,
|
||||
filename_display_pref: FileNameDisplayPreference,
|
||||
) -> String {
|
||||
let (source_file, lo_line, lo_col, hi_line, hi_col) = self.span_to_location_info(sp);
|
||||
|
||||
let file_name = match source_file {
|
||||
Some(sf) => sf.name.display(filename_display_pref).to_string(),
|
||||
None => return "no-location".to_string(),
|
||||
};
|
||||
|
||||
format!(
|
||||
"{file_name}:{lo_line}:{lo_col}{}",
|
||||
if let FileNameDisplayPreference::Short = filename_display_pref {
|
||||
String::new()
|
||||
} else {
|
||||
format!(": {hi_line}:{hi_col}")
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
pub fn span_to_location_info(
|
||||
&self,
|
||||
sp: Span,
|
||||
) -> (Option<Lrc<SourceFile>>, usize, usize, usize, usize) {
|
||||
if self.files.borrow().source_files.is_empty() || sp.is_dummy() {
|
||||
return "no-location".to_string();
|
||||
return (None, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
let lo = self.lookup_char_pos(sp.lo());
|
||||
let hi = self.lookup_char_pos(sp.hi());
|
||||
format!(
|
||||
"{}:{}:{}{}",
|
||||
lo.file.name.display(filename_display_pref),
|
||||
lo.line,
|
||||
lo.col.to_usize() + 1,
|
||||
if let FileNameDisplayPreference::Short = filename_display_pref {
|
||||
String::new()
|
||||
} else {
|
||||
format!(": {}:{}", hi.line, hi.col.to_usize() + 1)
|
||||
}
|
||||
)
|
||||
(Some(lo.file), lo.line, lo.col.to_usize() + 1, hi.line, hi.col.to_usize() + 1)
|
||||
}
|
||||
|
||||
/// Format the span location suitable for embedding in build artifacts
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ pub fn provide(providers: &mut ty::query::Providers) {
|
|||
associated_item,
|
||||
associated_item_def_ids,
|
||||
associated_items,
|
||||
associated_items_for_impl_trait_in_trait,
|
||||
associated_item_for_impl_trait_in_trait,
|
||||
associated_types_for_impl_traits_in_associated_fn,
|
||||
associated_type_for_impl_trait_in_trait,
|
||||
impl_item_implementor_ids,
|
||||
..*providers
|
||||
};
|
||||
|
|
@ -24,7 +24,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
|
|||
hir::ItemKind::Trait(.., ref trait_item_refs) => {
|
||||
if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
// We collect RPITITs for each trait method's return type and create a
|
||||
// corresponding associated item using associated_items_for_impl_trait_in_trait
|
||||
// corresponding associated item using associated_types_for_impl_traits_in_associated_fn
|
||||
// query.
|
||||
tcx.arena.alloc_from_iter(
|
||||
trait_item_refs
|
||||
|
|
@ -39,7 +39,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
|
|||
.flat_map(|trait_item_ref| {
|
||||
let trait_fn_def_id =
|
||||
trait_item_ref.id.owner_id.def_id.to_def_id();
|
||||
tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id)
|
||||
tcx.associated_types_for_impl_traits_in_associated_fn(
|
||||
trait_fn_def_id,
|
||||
)
|
||||
})
|
||||
.map(|def_id| *def_id),
|
||||
),
|
||||
|
|
@ -56,7 +58,7 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
|
|||
if tcx.lower_impl_trait_in_trait_to_assoc_ty() {
|
||||
// We collect RPITITs for each trait method's return type, on the impl side too and
|
||||
// create a corresponding associated item using
|
||||
// associated_items_for_impl_trait_in_trait query.
|
||||
// associated_types_for_impl_traits_in_associated_fn query.
|
||||
tcx.arena.alloc_from_iter(
|
||||
impl_
|
||||
.items
|
||||
|
|
@ -72,7 +74,9 @@ fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
|
|||
.flat_map(|impl_item_ref| {
|
||||
let impl_fn_def_id =
|
||||
impl_item_ref.id.owner_id.def_id.to_def_id();
|
||||
tcx.associated_items_for_impl_trait_in_trait(impl_fn_def_id)
|
||||
tcx.associated_types_for_impl_traits_in_associated_fn(
|
||||
impl_fn_def_id,
|
||||
)
|
||||
})
|
||||
.map(|def_id| *def_id)
|
||||
})),
|
||||
|
|
@ -176,13 +180,19 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A
|
|||
}
|
||||
}
|
||||
|
||||
/// Given an `fn_def_id` of a trait or of an impl that implements a given trait:
|
||||
/// if `fn_def_id` is the def id of a function defined inside a trait, then it creates and returns
|
||||
/// the associated items that correspond to each impl trait in return position for that trait.
|
||||
/// if `fn_def_id` is the def id of a function defined inside an impl that implements a trait, then it
|
||||
/// creates and returns the associated items that correspond to each impl trait in return position
|
||||
/// of the implemented trait.
|
||||
fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -> &'_ [DefId] {
|
||||
/// Given an `fn_def_id` of a trait or a trait implementation:
|
||||
///
|
||||
/// if `fn_def_id` is a function defined inside a trait, then it synthesizes
|
||||
/// a new def id corresponding to a new associated type for each return-
|
||||
/// position `impl Trait` in the signature.
|
||||
///
|
||||
/// if `fn_def_id` is a function inside of an impl, then for each synthetic
|
||||
/// associated type generated for the corresponding trait function described
|
||||
/// above, synthesize a corresponding associated type in the impl.
|
||||
fn associated_types_for_impl_traits_in_associated_fn(
|
||||
tcx: TyCtxt<'_>,
|
||||
fn_def_id: DefId,
|
||||
) -> &'_ [DefId] {
|
||||
let parent_def_id = tcx.parent(fn_def_id);
|
||||
|
||||
match tcx.def_kind(parent_def_id) {
|
||||
|
|
@ -206,7 +216,7 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
|
|||
visitor.visit_fn_ret_ty(output);
|
||||
|
||||
tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| {
|
||||
tcx.associated_item_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
|
||||
tcx.associated_type_for_impl_trait_in_trait(opaque_ty_def_id).to_def_id()
|
||||
}))
|
||||
} else {
|
||||
&[]
|
||||
|
|
@ -217,9 +227,9 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
|
|||
let Some(trait_fn_def_id) = tcx.associated_item(fn_def_id).trait_item_def_id else { return &[] };
|
||||
|
||||
tcx.arena.alloc_from_iter(
|
||||
tcx.associated_items_for_impl_trait_in_trait(trait_fn_def_id).iter().map(
|
||||
tcx.associated_types_for_impl_traits_in_associated_fn(trait_fn_def_id).iter().map(
|
||||
move |trait_assoc_def_id| {
|
||||
impl_associated_item_for_impl_trait_in_trait(
|
||||
associated_type_for_impl_trait_in_impl(
|
||||
tcx,
|
||||
trait_assoc_def_id.expect_local(),
|
||||
fn_def_id.expect_local(),
|
||||
|
|
@ -231,16 +241,17 @@ fn associated_items_for_impl_trait_in_trait(tcx: TyCtxt<'_>, fn_def_id: DefId) -
|
|||
}
|
||||
|
||||
def_kind => bug!(
|
||||
"associated_items_for_impl_trait_in_trait: {:?} should be Trait or Impl but is {:?}",
|
||||
"associated_types_for_impl_traits_in_associated_fn: {:?} should be Trait or Impl but is {:?}",
|
||||
parent_def_id,
|
||||
def_kind
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Given an `opaque_ty_def_id` corresponding to an impl trait in trait, create and return the
|
||||
/// corresponding associated item.
|
||||
fn associated_item_for_impl_trait_in_trait(
|
||||
/// Given an `opaque_ty_def_id` corresponding to an `impl Trait` in an associated
|
||||
/// function from a trait, synthesize an associated type for that `impl Trait`
|
||||
/// that inherits properties that we infer from the method and the opaque type.
|
||||
fn associated_type_for_impl_trait_in_trait(
|
||||
tcx: TyCtxt<'_>,
|
||||
opaque_ty_def_id: LocalDefId,
|
||||
) -> LocalDefId {
|
||||
|
|
@ -335,10 +346,12 @@ fn associated_item_for_impl_trait_in_trait(
|
|||
local_def_id
|
||||
}
|
||||
|
||||
/// Given an `trait_assoc_def_id` that corresponds to a previously synthesized impl trait in trait
|
||||
/// into an associated type and an `impl_def_id` corresponding to an impl block, create and return
|
||||
/// the corresponding associated item inside the impl block.
|
||||
fn impl_associated_item_for_impl_trait_in_trait(
|
||||
/// Given an `trait_assoc_def_id` corresponding to an associated item synthesized
|
||||
/// from an `impl Trait` in an associated function from a trait, and an
|
||||
/// `impl_fn_def_id` that represents an implementation of the associated function
|
||||
/// that the `impl Trait` comes from, synthesize an associated type for that `impl Trait`
|
||||
/// that inherits properties that we infer from the method and the associated type.
|
||||
fn associated_type_for_impl_trait_in_impl(
|
||||
tcx: TyCtxt<'_>,
|
||||
trait_assoc_def_id: LocalDefId,
|
||||
impl_fn_def_id: LocalDefId,
|
||||
|
|
@ -383,6 +396,8 @@ fn impl_associated_item_for_impl_trait_in_trait(
|
|||
impl_assoc_ty.impl_defaultness(tcx.impl_defaultness(impl_fn_def_id));
|
||||
|
||||
// Copy generics_of the trait's associated item but the impl as the parent.
|
||||
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty) resolves to the trait instead of the impl
|
||||
// generics.
|
||||
impl_assoc_ty.generics_of({
|
||||
let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
|
||||
let trait_assoc_parent_count = trait_assoc_generics.parent_count;
|
||||
|
|
@ -391,16 +406,10 @@ fn impl_associated_item_for_impl_trait_in_trait(
|
|||
let parent_generics = tcx.generics_of(impl_def_id);
|
||||
let parent_count = parent_generics.parent_count + parent_generics.params.len();
|
||||
|
||||
let mut impl_fn_params = tcx.generics_of(impl_fn_def_id).params.clone();
|
||||
|
||||
for param in &mut params {
|
||||
param.index = param.index + parent_count as u32 + impl_fn_params.len() as u32
|
||||
- trait_assoc_parent_count as u32;
|
||||
param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
|
||||
}
|
||||
|
||||
impl_fn_params.extend(params);
|
||||
params = impl_fn_params;
|
||||
|
||||
let param_def_id_to_index =
|
||||
params.iter().map(|param| (param.def_id, param.index)).collect();
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
//!
|
||||
//! The documentation for this module describes how to use this feature. If you are interested in
|
||||
//! hacking on the implementation, most of that documentation lives at
|
||||
//! `rustc_mir_building/src/build/custom/mod.rs`.
|
||||
//! `rustc_mir_build/src/build/custom/mod.rs`.
|
||||
//!
|
||||
//! Typical usage will look like this:
|
||||
//!
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::convert::TryFrom;
|
||||
use crate::marker::Destruct;
|
||||
use crate::mem;
|
||||
use crate::ops::{self, Try};
|
||||
|
||||
|
|
@ -20,7 +21,8 @@ unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usi
|
|||
/// The *successor* operation moves towards values that compare greater.
|
||||
/// The *predecessor* operation moves towards values that compare lesser.
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
pub trait Step: Clone + PartialOrd + Sized {
|
||||
#[const_trait]
|
||||
pub trait Step: ~const Clone + ~const PartialOrd + Sized {
|
||||
/// Returns the number of *successor* steps required to get from `start` to `end`.
|
||||
///
|
||||
/// Returns `None` if the number of steps would overflow `usize`
|
||||
|
|
@ -234,7 +236,8 @@ macro_rules! step_integer_impls {
|
|||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for $u_narrower {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl const Step for $u_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
|
|
@ -266,7 +269,8 @@ macro_rules! step_integer_impls {
|
|||
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for $i_narrower {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl const Step for $i_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
|
|
@ -330,7 +334,8 @@ macro_rules! step_integer_impls {
|
|||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for $u_wider {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl const Step for $u_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
|
|
@ -355,7 +360,8 @@ macro_rules! step_integer_impls {
|
|||
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for $i_wider {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl const Step for $i_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
|
|
@ -405,7 +411,8 @@ step_integer_impls! {
|
|||
}
|
||||
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
impl Step for char {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl const Step for char {
|
||||
#[inline]
|
||||
fn steps_between(&start: &char, &end: &char) -> Option<usize> {
|
||||
let start = start as u32;
|
||||
|
|
@ -423,6 +430,7 @@ impl Step for char {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_try)]
|
||||
fn forward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_checked(start, count)?;
|
||||
|
|
@ -439,6 +447,7 @@ impl Step for char {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[rustc_allow_const_fn_unstable(const_try)]
|
||||
fn backward_checked(start: char, count: usize) -> Option<char> {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_checked(start, count)?;
|
||||
|
|
@ -514,6 +523,7 @@ macro_rules! range_incl_exact_iter_impl {
|
|||
}
|
||||
|
||||
/// Specialization implementations for `Range`.
|
||||
#[const_trait]
|
||||
trait RangeIteratorImpl {
|
||||
type Item;
|
||||
|
||||
|
|
@ -528,7 +538,7 @@ trait RangeIteratorImpl {
|
|||
fn spec_advance_back_by(&mut self, n: usize) -> Result<(), usize>;
|
||||
}
|
||||
|
||||
impl<A: Step> RangeIteratorImpl for ops::Range<A> {
|
||||
impl<A: ~const Step + ~const Destruct> const RangeIteratorImpl for ops::Range<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -614,7 +624,7 @@ impl<A: Step> RangeIteratorImpl for ops::Range<A> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
|
||||
impl<T: ~const TrustedStep + ~const Destruct> const RangeIteratorImpl for ops::Range<T> {
|
||||
#[inline]
|
||||
fn spec_next(&mut self) -> Option<T> {
|
||||
if self.start < self.end {
|
||||
|
|
@ -702,7 +712,8 @@ impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> Iterator for ops::Range<A> {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl<A: ~const Step + ~const Destruct> const Iterator for ops::Range<A> {
|
||||
type Item = A;
|
||||
|
||||
#[inline]
|
||||
|
|
@ -812,7 +823,8 @@ range_incl_exact_iter_impl! {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
|
||||
impl<A: ~const Step + ~const Destruct> const DoubleEndedIterator for ops::Range<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
self.spec_next_back()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use crate::marker::Destruct;
|
||||
use crate::ops::{ControlFlow, Try};
|
||||
|
||||
/// An iterator able to yield elements from both ends.
|
||||
|
|
@ -37,6 +38,7 @@ use crate::ops::{ControlFlow, Try};
|
|||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")]
|
||||
#[const_trait]
|
||||
pub trait DoubleEndedIterator: Iterator {
|
||||
/// Removes and returns an element from the end of the iterator.
|
||||
///
|
||||
|
|
@ -131,7 +133,10 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
/// [`Err(k)`]: Err
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize>
|
||||
where
|
||||
Self::Item: ~const Destruct,
|
||||
{
|
||||
for i in 0..n {
|
||||
self.next_back().ok_or(i)?;
|
||||
}
|
||||
|
|
@ -181,6 +186,7 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_nth_back", since = "1.37.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||
self.advance_back_by(n).ok()?;
|
||||
self.next_back()
|
||||
|
|
@ -218,6 +224,7 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iterator_try_fold", since = "1.27.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
@ -289,6 +296,7 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
#[doc(alias = "foldr")]
|
||||
#[inline]
|
||||
#[stable(feature = "iter_rfold", since = "1.27.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn rfold<B, F>(mut self, init: B, mut f: F) -> B
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
@ -344,6 +352,7 @@ pub trait DoubleEndedIterator: Iterator {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "iter_rfind", since = "1.27.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
Self: Sized,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::array;
|
||||
use crate::cmp::{self, Ordering};
|
||||
use crate::marker::Destruct;
|
||||
use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
|
||||
|
||||
use super::super::try_process;
|
||||
|
|
@ -336,8 +337,10 @@ pub trait Iterator {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||
fn advance_by(&mut self, n: usize) -> Result<(), usize>
|
||||
where
|
||||
Self::Item: ~const Destruct,
|
||||
{
|
||||
for i in 0..n {
|
||||
self.next().ok_or(i)?;
|
||||
}
|
||||
|
|
@ -385,8 +388,10 @@ pub trait Iterator {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_do_not_const_check]
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||
fn nth(&mut self, n: usize) -> Option<Self::Item>
|
||||
where
|
||||
Self::Item: ~const Destruct,
|
||||
{
|
||||
self.advance_by(n).ok()?;
|
||||
self.next()
|
||||
}
|
||||
|
|
@ -1998,7 +2003,7 @@ pub trait Iterator {
|
|||
/// a.iter().map(|&x| x * 2).collect_into(&mut vec);
|
||||
/// a.iter().map(|&x| x * 10).collect_into(&mut vec);
|
||||
///
|
||||
/// assert_eq!(vec![0, 1, 2, 4, 6, 10, 20, 30], vec);
|
||||
/// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]);
|
||||
/// ```
|
||||
///
|
||||
/// `Vec` can have a manual set capacity to avoid reallocating it:
|
||||
|
|
@ -2013,7 +2018,7 @@ pub trait Iterator {
|
|||
/// a.iter().map(|&x| x * 10).collect_into(&mut vec);
|
||||
///
|
||||
/// assert_eq!(6, vec.capacity());
|
||||
/// println!("{:?}", vec);
|
||||
/// assert_eq!(vec, vec![2, 4, 6, 10, 20, 30]);
|
||||
/// ```
|
||||
///
|
||||
/// The returned mutable reference can be used to continue the call chain:
|
||||
|
|
@ -2027,12 +2032,12 @@ pub trait Iterator {
|
|||
/// let count = a.iter().collect_into(&mut vec).iter().count();
|
||||
///
|
||||
/// assert_eq!(count, vec.len());
|
||||
/// println!("Vec len is {}", count);
|
||||
/// assert_eq!(vec, vec![1, 2, 3]);
|
||||
///
|
||||
/// let count = a.iter().collect_into(&mut vec).iter().count();
|
||||
///
|
||||
/// assert_eq!(count, vec.len());
|
||||
/// println!("Vec len now is {}", count);
|
||||
/// assert_eq!(vec, vec![1, 2, 3, 1, 2, 3]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "iter_collect_into", reason = "new API", issue = "94780")]
|
||||
|
|
|
|||
|
|
@ -86,4 +86,5 @@ pub unsafe trait InPlaceIterable: Iterator {}
|
|||
/// for details. Consumers are free to rely on the invariants in unsafe code.
|
||||
#[unstable(feature = "trusted_step", issue = "85731")]
|
||||
#[rustc_specialization_trait]
|
||||
pub unsafe trait TrustedStep: Step {}
|
||||
#[const_trait]
|
||||
pub unsafe trait TrustedStep: ~const Step {}
|
||||
|
|
|
|||
|
|
@ -123,9 +123,11 @@
|
|||
#![feature(const_index_range_slice_index)]
|
||||
#![feature(const_inherent_unchecked_arith)]
|
||||
#![feature(const_int_unchecked_arith)]
|
||||
#![feature(const_intoiterator_identity)]
|
||||
#![feature(const_intrinsic_forget)]
|
||||
#![feature(const_ipv4)]
|
||||
#![feature(const_ipv6)]
|
||||
#![feature(const_iter)]
|
||||
#![feature(const_likely)]
|
||||
#![feature(const_maybe_uninit_uninit_array)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
|
|
|
|||
|
|
@ -340,9 +340,9 @@ pub macro debug_assert_matches($($arg:tt)*) {
|
|||
#[stable(feature = "matches_macro", since = "1.42.0")]
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")]
|
||||
macro_rules! matches {
|
||||
($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
|
||||
($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => {
|
||||
match $expression {
|
||||
$( $pattern )|+ $( if $guard )? => true,
|
||||
$pattern $(if $guard)? => true,
|
||||
_ => false
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ pub struct BiasedFp {
|
|||
}
|
||||
|
||||
impl BiasedFp {
|
||||
#[inline]
|
||||
pub const fn zero_pow2(e: i32) -> Self {
|
||||
Self { f: 0, e }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,11 +118,13 @@ impl RawFloat for f32 {
|
|||
const SMALLEST_POWER_OF_TEN: i32 = -65;
|
||||
const LARGEST_POWER_OF_TEN: i32 = 38;
|
||||
|
||||
#[inline]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
|
||||
v as _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u64_bits(v: u64) -> Self {
|
||||
f32::from_bits((v & 0xFFFFFFFF) as u32)
|
||||
}
|
||||
|
|
@ -169,11 +171,13 @@ impl RawFloat for f64 {
|
|||
const SMALLEST_POWER_OF_TEN: i32 = -342;
|
||||
const LARGEST_POWER_OF_TEN: i32 = 308;
|
||||
|
||||
#[inline]
|
||||
fn from_u64(v: u64) -> Self {
|
||||
debug_assert!(v <= Self::MAX_MANTISSA_FAST_PATH);
|
||||
v as _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_u64_bits(v: u64) -> Self {
|
||||
f64::from_bits(v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,10 +118,12 @@ pub fn compute_float<F: RawFloat>(q: i64, mut w: u64) -> BiasedFp {
|
|||
/// This uses a pre-computed integer approximation for
|
||||
/// log2(10), where 217706 / 2^16 is accurate for the
|
||||
/// entire range of non-finite decimal exponents.
|
||||
#[inline]
|
||||
fn power(q: i32) -> i32 {
|
||||
(q.wrapping_mul(152_170 + 65536) >> 16) + 63
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn full_multiplication(a: u64, b: u64) -> (u64, u64) {
|
||||
let r = (a as u128) * (b as u128);
|
||||
(r as u64, (r >> 64) as u64)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,13 @@ macro_rules! from_str_float_impl {
|
|||
/// representable floating-point number to the number represented
|
||||
/// by `src` (following the same rules for rounding as for the
|
||||
/// results of primitive operations).
|
||||
#[inline]
|
||||
// We add the `#[inline(never)]` attribute, since its content will
|
||||
// be filled with that of `dec2flt`, which has #[inline(always)].
|
||||
// Since `dec2flt` is generic, a normal inline attribute on this function
|
||||
// with `dec2flt` having no attributes results in heavily repeated
|
||||
// generation of `dec2flt`, despite the fact only a maximum of 2
|
||||
// possible instances can ever exist. Adding #[inline(never)] avoids this.
|
||||
#[inline(never)]
|
||||
fn from_str(src: &str) -> Result<Self, ParseFloatError> {
|
||||
dec2flt(src)
|
||||
}
|
||||
|
|
@ -202,12 +208,14 @@ impl fmt::Display for ParseFloatError {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(super) fn pfe_empty() -> ParseFloatError {
|
||||
ParseFloatError { kind: FloatErrorKind::Empty }
|
||||
}
|
||||
|
||||
// Used in unit tests, keep public.
|
||||
// This is much better than making FloatErrorKind and ParseFloatError::kind public.
|
||||
#[inline]
|
||||
pub fn pfe_invalid() -> ParseFloatError {
|
||||
ParseFloatError { kind: FloatErrorKind::Invalid }
|
||||
}
|
||||
|
|
@ -220,6 +228,7 @@ fn biased_fp_to_float<T: RawFloat>(x: BiasedFp) -> T {
|
|||
}
|
||||
|
||||
/// Converts a decimal string into a floating point number.
|
||||
#[inline(always)] // Will be inlined into a function with `#[inline(never)]`, see above
|
||||
pub fn dec2flt<F: RawFloat>(s: &str) -> Result<F, ParseFloatError> {
|
||||
let mut s = s.as_bytes();
|
||||
let c = if let Some(&c) = s.first() {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ pub struct Number {
|
|||
|
||||
impl Number {
|
||||
/// Detect if the float can be accurately reconstructed from native floats.
|
||||
#[inline]
|
||||
fn is_fast_path<F: RawFloat>(&self) -> bool {
|
||||
F::MIN_EXPONENT_FAST_PATH <= self.exponent
|
||||
&& self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH
|
||||
|
|
|
|||
|
|
@ -1003,22 +1003,25 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {}
|
|||
#[stable(feature = "pin", since = "1.33.0")]
|
||||
impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
|
||||
|
||||
/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2].
|
||||
/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning a `value: T` locally.
|
||||
///
|
||||
/// Unlike [`Box::pin`], this does not involve a heap allocation.
|
||||
/// Unlike [`Box::pin`], this does not create a new heap allocation. As explained
|
||||
/// below, the element might still end up on the heap however.
|
||||
///
|
||||
/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this
|
||||
/// effectively pins the `value` in memory, where it will be unable to be moved.
|
||||
/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such
|
||||
/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore,
|
||||
/// moving it.
|
||||
/// See [the `Unpin` section of the `pin` module][self#unpin] for more info.
|
||||
/// The local pinning performed by this macro is usually dubbed "stack"-pinning.
|
||||
/// Outside of `async` contexts locals do indeed get stored on the stack. In
|
||||
/// `async` functions or blocks however, any locals crossing an `.await` point
|
||||
/// are part of the state captured by the `Future`, and will use the storage of
|
||||
/// those. That storage can either be on the heap or on the stack. Therefore,
|
||||
/// local pinning is a more accurate term.
|
||||
///
|
||||
/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located
|
||||
/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside
|
||||
/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing
|
||||
/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by
|
||||
/// the `Generator`—, and thus will be stored wherever that one is.
|
||||
/// If the type of the given value does not implement [`Unpin`], then this macro
|
||||
/// pins the value in memory in a way that prevents moves. On the other hand,
|
||||
/// if the type does implement [`Unpin`], <code>[Pin]<[&mut] T></code> behaves
|
||||
/// like <code>[&mut] T</code>, and operations such as
|
||||
/// [`mem::replace()`][crate::mem::replace] or [`mem::take()`](crate::mem::take)
|
||||
/// will allow moves of the value.
|
||||
/// See [the `Unpin` section of the `pin` module][self#unpin] for details.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
|
|
@ -1158,9 +1161,9 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
|
|||
///
|
||||
/// If you really need to return a pinned value, consider using [`Box::pin`] instead.
|
||||
///
|
||||
/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be
|
||||
/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
|
||||
/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
|
||||
/// On the other hand, local pinning using [`pin!`] is likely to be cheaper than
|
||||
/// pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
|
||||
/// requiring an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
|
||||
/// constructor.
|
||||
///
|
||||
/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
|
||||
|
|
|
|||
|
|
@ -132,9 +132,7 @@ iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
|
|||
Self: Sized,
|
||||
F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
|
||||
{
|
||||
self.as_slice().windows(2).all(|w| {
|
||||
compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
|
||||
})
|
||||
self.as_slice().is_sorted_by(|a, b| compare(&a, &b))
|
||||
}
|
||||
}}
|
||||
|
||||
|
|
|
|||
|
|
@ -3822,7 +3822,7 @@ impl<T> [T] {
|
|||
where
|
||||
F: FnMut(&'a T, &'a T) -> Option<Ordering>,
|
||||
{
|
||||
self.iter().is_sorted_by(|a, b| compare(*a, *b))
|
||||
self.array_windows().all(|[a, b]| compare(a, b).map_or(false, Ordering::is_le))
|
||||
}
|
||||
|
||||
/// Checks if the elements of this slice are sorted using the given key extraction function.
|
||||
|
|
|
|||
36
library/core/tests/iter/consts.rs
Normal file
36
library/core/tests/iter/consts.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#[test]
|
||||
fn const_manual_iter() {
|
||||
struct S(bool);
|
||||
|
||||
impl const Iterator for S {
|
||||
type Item = ();
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.0 == false {
|
||||
self.0 = true;
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
const {
|
||||
let mut val = S(false);
|
||||
assert!(val.next().is_some());
|
||||
assert!(val.next().is_none());
|
||||
assert!(val.next().is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_range() {
|
||||
const {
|
||||
let mut arr = [0; 3];
|
||||
for i in 0..arr.len() {
|
||||
arr[i] = i;
|
||||
}
|
||||
assert!(arr[0] == 0);
|
||||
assert!(arr[1] == 1);
|
||||
assert!(arr[2] == 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ mod range;
|
|||
mod sources;
|
||||
mod traits;
|
||||
|
||||
mod consts;
|
||||
|
||||
use core::cell::Cell;
|
||||
use core::convert::TryFrom;
|
||||
use core::iter::*;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@
|
|||
#![feature(const_caller_location)]
|
||||
#![feature(const_cell_into_inner)]
|
||||
#![feature(const_convert)]
|
||||
#![feature(const_for)]
|
||||
#![feature(const_hash)]
|
||||
#![feature(const_heap)]
|
||||
#![feature(const_intoiterator_identity)]
|
||||
#![feature(const_iter)]
|
||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||
#![feature(const_maybe_uninit_assume_init_read)]
|
||||
#![feature(const_nonnull_new)]
|
||||
|
|
|
|||
|
|
@ -823,8 +823,22 @@ pub trait Read {
|
|||
|
||||
/// Read the exact number of bytes required to fill `cursor`.
|
||||
///
|
||||
/// This is equivalent to the [`read_exact`](Read::read_exact) method, except that it is passed a [`BorrowedCursor`] rather than `[u8]` to
|
||||
/// allow use with uninitialized buffers.
|
||||
/// This is similar to the [`read_exact`](Read::read_exact) method, except
|
||||
/// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
|
||||
/// with uninitialized buffers.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If this function encounters an error of the kind [`ErrorKind::Interrupted`]
|
||||
/// then the error is ignored and the operation will continue.
|
||||
///
|
||||
/// If this function encounters an "end of file" before completely filling
|
||||
/// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
|
||||
///
|
||||
/// If any other read error is encountered then this function immediately
|
||||
/// returns.
|
||||
///
|
||||
/// If this function returns an error, all bytes read will be appended to `cursor`.
|
||||
#[unstable(feature = "read_buf", issue = "78485")]
|
||||
fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> Result<()> {
|
||||
while cursor.capacity() > 0 {
|
||||
|
|
|
|||
|
|
@ -308,8 +308,7 @@ pub fn get_backtrace_style() -> Option<BacktraceStyle> {
|
|||
BacktraceStyle::Short
|
||||
}
|
||||
})
|
||||
.unwrap_or(if cfg!(target_os = "fuchsia") {
|
||||
// Fuchsia components default to full backtrace.
|
||||
.unwrap_or(if crate::sys::FULL_BACKTRACE_DEFAULT {
|
||||
BacktraceStyle::Full
|
||||
} else {
|
||||
BacktraceStyle::Off
|
||||
|
|
|
|||
|
|
@ -76,3 +76,12 @@ cfg_if::cfg_if! {
|
|||
pub mod c;
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
// Fuchsia components default to full backtrace.
|
||||
if #[cfg(target_os = "fuchsia")] {
|
||||
pub const FULL_BACKTRACE_DEFAULT: bool = true;
|
||||
} else {
|
||||
pub const FULL_BACKTRACE_DEFAULT: bool = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
|
|||
|
||||
pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
|
||||
pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
|
||||
pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
|
||||
|
||||
// Equivalent to the `NT_SUCCESS` C preprocessor macro.
|
||||
// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
|
||||
|
|
@ -1282,6 +1281,46 @@ extern "system" {
|
|||
) -> NTSTATUS;
|
||||
}
|
||||
|
||||
#[link(name = "ntdll")]
|
||||
extern "system" {
|
||||
pub fn NtCreateFile(
|
||||
FileHandle: *mut HANDLE,
|
||||
DesiredAccess: ACCESS_MASK,
|
||||
ObjectAttributes: *const OBJECT_ATTRIBUTES,
|
||||
IoStatusBlock: *mut IO_STATUS_BLOCK,
|
||||
AllocationSize: *mut i64,
|
||||
FileAttributes: ULONG,
|
||||
ShareAccess: ULONG,
|
||||
CreateDisposition: ULONG,
|
||||
CreateOptions: ULONG,
|
||||
EaBuffer: *mut c_void,
|
||||
EaLength: ULONG,
|
||||
) -> NTSTATUS;
|
||||
pub fn NtReadFile(
|
||||
FileHandle: BorrowedHandle<'_>,
|
||||
Event: HANDLE,
|
||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||
ApcContext: *mut c_void,
|
||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||
Buffer: *mut crate::mem::MaybeUninit<u8>,
|
||||
Length: ULONG,
|
||||
ByteOffset: Option<&LARGE_INTEGER>,
|
||||
Key: Option<&ULONG>,
|
||||
) -> NTSTATUS;
|
||||
pub fn NtWriteFile(
|
||||
FileHandle: BorrowedHandle<'_>,
|
||||
Event: HANDLE,
|
||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||
ApcContext: *mut c_void,
|
||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||
Buffer: *const u8,
|
||||
Length: ULONG,
|
||||
ByteOffset: Option<&LARGE_INTEGER>,
|
||||
Key: Option<&ULONG>,
|
||||
) -> NTSTATUS;
|
||||
pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG;
|
||||
}
|
||||
|
||||
// Functions that aren't available on every version of Windows that we support,
|
||||
// but we still use them and just provide some form of a fallback implementation.
|
||||
compat_fn_with_fallback! {
|
||||
|
|
@ -1322,52 +1361,6 @@ compat_fn_optional! {
|
|||
compat_fn_with_fallback! {
|
||||
pub static NTDLL: &CStr = ansi_str!("ntdll");
|
||||
|
||||
pub fn NtCreateFile(
|
||||
FileHandle: *mut HANDLE,
|
||||
DesiredAccess: ACCESS_MASK,
|
||||
ObjectAttributes: *const OBJECT_ATTRIBUTES,
|
||||
IoStatusBlock: *mut IO_STATUS_BLOCK,
|
||||
AllocationSize: *mut i64,
|
||||
FileAttributes: ULONG,
|
||||
ShareAccess: ULONG,
|
||||
CreateDisposition: ULONG,
|
||||
CreateOptions: ULONG,
|
||||
EaBuffer: *mut c_void,
|
||||
EaLength: ULONG
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
pub fn NtReadFile(
|
||||
FileHandle: BorrowedHandle<'_>,
|
||||
Event: HANDLE,
|
||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||
ApcContext: *mut c_void,
|
||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||
Buffer: *mut crate::mem::MaybeUninit<u8>,
|
||||
Length: ULONG,
|
||||
ByteOffset: Option<&LARGE_INTEGER>,
|
||||
Key: Option<&ULONG>
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
pub fn NtWriteFile(
|
||||
FileHandle: BorrowedHandle<'_>,
|
||||
Event: HANDLE,
|
||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||
ApcContext: *mut c_void,
|
||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||
Buffer: *const u8,
|
||||
Length: ULONG,
|
||||
ByteOffset: Option<&LARGE_INTEGER>,
|
||||
Key: Option<&ULONG>
|
||||
) -> NTSTATUS {
|
||||
STATUS_NOT_IMPLEMENTED
|
||||
}
|
||||
pub fn RtlNtStatusToDosError(
|
||||
Status: NTSTATUS
|
||||
) -> ULONG {
|
||||
Status as ULONG
|
||||
}
|
||||
pub fn NtCreateKeyedEvent(
|
||||
KeyedEventHandle: LPHANDLE,
|
||||
DesiredAccess: ACCESS_MASK,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,46 @@ impl<T: Write> Write for OutputLocation<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ConsoleTestDiscoveryState {
|
||||
pub log_out: Option<File>,
|
||||
pub tests: usize,
|
||||
pub benchmarks: usize,
|
||||
pub ignored: usize,
|
||||
pub options: Options,
|
||||
}
|
||||
|
||||
impl ConsoleTestDiscoveryState {
|
||||
pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestDiscoveryState> {
|
||||
let log_out = match opts.logfile {
|
||||
Some(ref path) => Some(File::create(path)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Ok(ConsoleTestDiscoveryState {
|
||||
log_out,
|
||||
tests: 0,
|
||||
benchmarks: 0,
|
||||
ignored: 0,
|
||||
options: opts.options,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_log<F, S>(&mut self, msg: F) -> io::Result<()>
|
||||
where
|
||||
S: AsRef<str>,
|
||||
F: FnOnce() -> S,
|
||||
{
|
||||
match self.log_out {
|
||||
None => Ok(()),
|
||||
Some(ref mut o) => {
|
||||
let msg = msg();
|
||||
let msg = msg.as_ref();
|
||||
o.write_all(msg.as_bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ConsoleTestState {
|
||||
pub log_out: Option<File>,
|
||||
pub total: usize,
|
||||
|
|
@ -138,53 +178,44 @@ impl ConsoleTestState {
|
|||
|
||||
// List the tests to console, and optionally to logfile. Filters are honored.
|
||||
pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> {
|
||||
let mut output = match term::stdout() {
|
||||
let output = match term::stdout() {
|
||||
None => OutputLocation::Raw(io::stdout().lock()),
|
||||
Some(t) => OutputLocation::Pretty(t),
|
||||
};
|
||||
|
||||
let quiet = opts.format == OutputFormat::Terse;
|
||||
let mut st = ConsoleTestState::new(opts)?;
|
||||
|
||||
let mut ntest = 0;
|
||||
let mut nbench = 0;
|
||||
let mut out: Box<dyn OutputFormatter> = match opts.format {
|
||||
OutputFormat::Pretty | OutputFormat::Junit => {
|
||||
Box::new(PrettyFormatter::new(output, false, 0, false, None))
|
||||
}
|
||||
OutputFormat::Terse => Box::new(TerseFormatter::new(output, false, 0, false)),
|
||||
OutputFormat::Json => Box::new(JsonFormatter::new(output)),
|
||||
};
|
||||
let mut st = ConsoleTestDiscoveryState::new(opts)?;
|
||||
|
||||
out.write_discovery_start()?;
|
||||
for test in filter_tests(opts, tests).into_iter() {
|
||||
use crate::TestFn::*;
|
||||
|
||||
let TestDescAndFn { desc: TestDesc { name, .. }, testfn } = test;
|
||||
let TestDescAndFn { desc, testfn } = test;
|
||||
|
||||
let fntype = match testfn {
|
||||
StaticTestFn(..) | DynTestFn(..) => {
|
||||
ntest += 1;
|
||||
st.tests += 1;
|
||||
"test"
|
||||
}
|
||||
StaticBenchFn(..) | DynBenchFn(..) => {
|
||||
nbench += 1;
|
||||
st.benchmarks += 1;
|
||||
"benchmark"
|
||||
}
|
||||
};
|
||||
|
||||
writeln!(output, "{name}: {fntype}")?;
|
||||
st.write_log(|| format!("{fntype} {name}\n"))?;
|
||||
st.ignored += if desc.ignore { 1 } else { 0 };
|
||||
|
||||
out.write_test_discovered(&desc, fntype)?;
|
||||
st.write_log(|| format!("{fntype} {}\n", desc.name))?;
|
||||
}
|
||||
|
||||
fn plural(count: u32, s: &str) -> String {
|
||||
match count {
|
||||
1 => format!("1 {s}"),
|
||||
n => format!("{n} {s}s"),
|
||||
}
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
if ntest != 0 || nbench != 0 {
|
||||
writeln!(output)?;
|
||||
}
|
||||
|
||||
writeln!(output, "{}, {}", plural(ntest, "test"), plural(nbench, "benchmark"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
out.write_discovery_finish(&st)
|
||||
}
|
||||
|
||||
// Updates `ConsoleTestState` depending on result of the test execution.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, io, io::prelude::Write};
|
|||
|
||||
use super::OutputFormatter;
|
||||
use crate::{
|
||||
console::{ConsoleTestState, OutputLocation},
|
||||
console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
|
||||
test_result::TestResult,
|
||||
time,
|
||||
types::TestDesc,
|
||||
|
|
@ -60,6 +60,56 @@ impl<T: Write> JsonFormatter<T> {
|
|||
}
|
||||
|
||||
impl<T: Write> OutputFormatter for JsonFormatter<T> {
|
||||
fn write_discovery_start(&mut self) -> io::Result<()> {
|
||||
self.writeln_message(&format!(r#"{{ "type": "suite", "event": "discovery" }}"#))
|
||||
}
|
||||
|
||||
fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
|
||||
let TestDesc {
|
||||
name,
|
||||
ignore,
|
||||
ignore_message,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col,
|
||||
..
|
||||
} = desc;
|
||||
|
||||
#[cfg(bootstrap)]
|
||||
let source_file = "";
|
||||
#[cfg(bootstrap)]
|
||||
let start_line = 0;
|
||||
#[cfg(bootstrap)]
|
||||
let start_col = 0;
|
||||
#[cfg(bootstrap)]
|
||||
let end_line = 0;
|
||||
#[cfg(bootstrap)]
|
||||
let end_col = 0;
|
||||
|
||||
self.writeln_message(&format!(
|
||||
r#"{{ "type": "{test_type}", "event": "discovered", "name": "{}", "ignore": {ignore}, "ignore_message": "{}", "source_path": "{}", "start_line": {start_line}, "start_col": {start_col}, "end_line": {end_line}, "end_col": {end_col} }}"#,
|
||||
EscapedString(name.as_slice()),
|
||||
ignore_message.unwrap_or(""),
|
||||
EscapedString(source_file),
|
||||
))
|
||||
}
|
||||
|
||||
fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> {
|
||||
let ConsoleTestDiscoveryState { tests, benchmarks, ignored, .. } = state;
|
||||
|
||||
let total = tests + benchmarks;
|
||||
self.writeln_message(&format!(
|
||||
r#"{{ "type": "suite", "event": "completed", "tests": {tests}, "benchmarks": {benchmarks}, "total": {total}, "ignored": {ignored} }}"#
|
||||
))
|
||||
}
|
||||
|
||||
fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
|
||||
let shuffle_seed_json = if let Some(shuffle_seed) = shuffle_seed {
|
||||
format!(r#", "shuffle_seed": {shuffle_seed}"#)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::time::Duration;
|
|||
|
||||
use super::OutputFormatter;
|
||||
use crate::{
|
||||
console::{ConsoleTestState, OutputLocation},
|
||||
console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
|
||||
test_result::TestResult,
|
||||
time,
|
||||
types::{TestDesc, TestType},
|
||||
|
|
@ -27,6 +27,18 @@ impl<T: Write> JunitFormatter<T> {
|
|||
}
|
||||
|
||||
impl<T: Write> OutputFormatter for JunitFormatter<T> {
|
||||
fn write_discovery_start(&mut self) -> io::Result<()> {
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
|
||||
}
|
||||
|
||||
fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> {
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
|
||||
}
|
||||
|
||||
fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> {
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "Not yet implemented!"))
|
||||
}
|
||||
|
||||
fn write_run_start(
|
||||
&mut self,
|
||||
_test_count: usize,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{io, io::prelude::Write};
|
||||
|
||||
use crate::{
|
||||
console::ConsoleTestState,
|
||||
console::{ConsoleTestDiscoveryState, ConsoleTestState},
|
||||
test_result::TestResult,
|
||||
time,
|
||||
types::{TestDesc, TestName},
|
||||
|
|
@ -18,6 +18,10 @@ pub(crate) use self::pretty::PrettyFormatter;
|
|||
pub(crate) use self::terse::TerseFormatter;
|
||||
|
||||
pub(crate) trait OutputFormatter {
|
||||
fn write_discovery_start(&mut self) -> io::Result<()>;
|
||||
fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()>;
|
||||
fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()>;
|
||||
|
||||
fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()>;
|
||||
fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>;
|
||||
fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{io, io::prelude::Write};
|
|||
use super::OutputFormatter;
|
||||
use crate::{
|
||||
bench::fmt_bench_samples,
|
||||
console::{ConsoleTestState, OutputLocation},
|
||||
console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
|
||||
term,
|
||||
test_result::TestResult,
|
||||
time,
|
||||
|
|
@ -181,6 +181,33 @@ impl<T: Write> PrettyFormatter<T> {
|
|||
}
|
||||
|
||||
impl<T: Write> OutputFormatter for PrettyFormatter<T> {
|
||||
fn write_discovery_start(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
|
||||
self.write_plain(format!("{}: {test_type}\n", desc.name))
|
||||
}
|
||||
|
||||
fn write_discovery_finish(&mut self, state: &ConsoleTestDiscoveryState) -> io::Result<()> {
|
||||
fn plural(count: usize, s: &str) -> String {
|
||||
match count {
|
||||
1 => format!("1 {s}"),
|
||||
n => format!("{n} {s}s"),
|
||||
}
|
||||
}
|
||||
|
||||
if state.tests != 0 || state.benchmarks != 0 {
|
||||
self.write_plain("\n")?;
|
||||
}
|
||||
|
||||
self.write_plain(format!(
|
||||
"{}, {}\n",
|
||||
plural(state.tests, "test"),
|
||||
plural(state.benchmarks, "benchmark")
|
||||
))
|
||||
}
|
||||
|
||||
fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
|
||||
let noun = if test_count != 1 { "tests" } else { "test" };
|
||||
let shuffle_seed_msg = if let Some(shuffle_seed) = shuffle_seed {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{io, io::prelude::Write};
|
|||
use super::OutputFormatter;
|
||||
use crate::{
|
||||
bench::fmt_bench_samples,
|
||||
console::{ConsoleTestState, OutputLocation},
|
||||
console::{ConsoleTestDiscoveryState, ConsoleTestState, OutputLocation},
|
||||
term,
|
||||
test_result::TestResult,
|
||||
time,
|
||||
|
|
@ -167,6 +167,18 @@ impl<T: Write> TerseFormatter<T> {
|
|||
}
|
||||
|
||||
impl<T: Write> OutputFormatter for TerseFormatter<T> {
|
||||
fn write_discovery_start(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_test_discovered(&mut self, desc: &TestDesc, test_type: &str) -> io::Result<()> {
|
||||
self.write_plain(format!("{}: {test_type}\n", desc.name))
|
||||
}
|
||||
|
||||
fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_run_start(&mut self, test_count: usize, shuffle_seed: Option<u64>) -> io::Result<()> {
|
||||
self.total_test_count = test_count;
|
||||
let noun = if test_count != 1 { "tests" } else { "test" };
|
||||
|
|
|
|||
|
|
@ -63,6 +63,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
|||
name: StaticTestName("1"),
|
||||
ignore: true,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -75,6 +85,16 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
|||
name: StaticTestName("2"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -95,6 +115,16 @@ pub fn do_not_run_ignored_tests() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: true,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -118,6 +148,16 @@ pub fn ignored_tests_result_in_ignored() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: true,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -143,6 +183,16 @@ fn test_should_panic() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::Yes,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -168,6 +218,16 @@ fn test_should_panic_good_message() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::YesWithMessage("error message"),
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -198,6 +258,16 @@ fn test_should_panic_bad_message() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::YesWithMessage(expected),
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -232,6 +302,16 @@ fn test_should_panic_non_string_message_type() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::YesWithMessage(expected),
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -260,6 +340,16 @@ fn test_should_panic_but_succeeds() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -288,6 +378,16 @@ fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -325,6 +425,16 @@ fn time_test_failure_template(test_type: TestType) -> TestResult {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -364,6 +474,16 @@ fn typed_test_desc(test_type: TestType) -> TestDesc {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -476,6 +596,16 @@ pub fn exclude_should_panic_option() {
|
|||
name: StaticTestName("3"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::Yes,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -500,6 +630,16 @@ pub fn exact_filter_match() {
|
|||
name: StaticTestName(name),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -591,6 +731,16 @@ fn sample_tests() -> Vec<TestDescAndFn> {
|
|||
name: DynTestName((*name).clone()),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -720,6 +870,16 @@ pub fn test_bench_no_iter() {
|
|||
name: StaticTestName("f"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -743,6 +903,16 @@ pub fn test_bench_iter() {
|
|||
name: StaticTestName("f"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -759,6 +929,16 @@ fn should_sort_failures_before_printing_them() {
|
|||
name: StaticTestName("a"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -769,6 +949,16 @@ fn should_sort_failures_before_printing_them() {
|
|||
name: StaticTestName("b"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
@ -816,6 +1006,16 @@ fn test_dyn_bench_returning_err_fails_when_run_as_test() {
|
|||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
|
|
|
|||
|
|
@ -119,6 +119,16 @@ pub struct TestDesc {
|
|||
pub name: TestName,
|
||||
pub ignore: bool,
|
||||
pub ignore_message: Option<&'static str>,
|
||||
#[cfg(not(bootstrap))]
|
||||
pub source_file: &'static str,
|
||||
#[cfg(not(bootstrap))]
|
||||
pub start_line: usize,
|
||||
#[cfg(not(bootstrap))]
|
||||
pub start_col: usize,
|
||||
#[cfg(not(bootstrap))]
|
||||
pub end_line: usize,
|
||||
#[cfg(not(bootstrap))]
|
||||
pub end_col: usize,
|
||||
pub should_panic: options::ShouldPanic,
|
||||
pub compile_fail: bool,
|
||||
pub no_run: bool,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ dependencies = [
|
|||
"tar",
|
||||
"toml",
|
||||
"walkdir",
|
||||
"winapi",
|
||||
"windows",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
|
|
@ -720,6 +720,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
|
@ -736,46 +745,61 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.0"
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
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.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.0"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
|
|
|
|||
|
|
@ -59,18 +59,20 @@ sysinfo = { version = "0.26.0", optional = true }
|
|||
[target.'cfg(not(target_os = "solaris"))'.dependencies]
|
||||
fd-lock = "3.0.8"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi]
|
||||
version = "0.3"
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
version = "0.46.0"
|
||||
features = [
|
||||
"fileapi",
|
||||
"ioapiset",
|
||||
"jobapi2",
|
||||
"handleapi",
|
||||
"winioctl",
|
||||
"psapi",
|
||||
"impl-default",
|
||||
"timezoneapi",
|
||||
"winbase",
|
||||
"Win32_Foundation",
|
||||
"Win32_Security",
|
||||
"Win32_Storage_FileSystem",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_IO",
|
||||
"Win32_System_Ioctl",
|
||||
"Win32_System_JobObjects",
|
||||
"Win32_System_ProcessStatus",
|
||||
"Win32_System_SystemServices",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_Time",
|
||||
]
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
|
|
@ -281,41 +281,49 @@ fn format_rusage_data(_child: Child) -> Option<String> {
|
|||
#[cfg(windows)]
|
||||
fn format_rusage_data(child: Child) -> Option<String> {
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
use winapi::um::{processthreadsapi, psapi, timezoneapi};
|
||||
let handle = child.as_raw_handle();
|
||||
macro_rules! try_bool {
|
||||
($e:expr) => {
|
||||
if $e != 1 {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
use windows::{
|
||||
Win32::Foundation::HANDLE,
|
||||
Win32::System::ProcessStatus::{
|
||||
K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX,
|
||||
},
|
||||
Win32::System::Threading::GetProcessTimes,
|
||||
Win32::System::Time::FileTimeToSystemTime,
|
||||
};
|
||||
|
||||
let handle = HANDLE(child.as_raw_handle() as isize);
|
||||
|
||||
let mut user_filetime = Default::default();
|
||||
let mut user_time = Default::default();
|
||||
let mut kernel_filetime = Default::default();
|
||||
let mut kernel_time = Default::default();
|
||||
let mut memory_counters = psapi::PROCESS_MEMORY_COUNTERS::default();
|
||||
let mut memory_counters = PROCESS_MEMORY_COUNTERS::default();
|
||||
|
||||
unsafe {
|
||||
try_bool!(processthreadsapi::GetProcessTimes(
|
||||
GetProcessTimes(
|
||||
handle,
|
||||
&mut Default::default(),
|
||||
&mut Default::default(),
|
||||
&mut kernel_filetime,
|
||||
&mut user_filetime,
|
||||
));
|
||||
try_bool!(timezoneapi::FileTimeToSystemTime(&user_filetime, &mut user_time));
|
||||
try_bool!(timezoneapi::FileTimeToSystemTime(&kernel_filetime, &mut kernel_time));
|
||||
|
||||
// Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
|
||||
// with the given handle and none of that process's children.
|
||||
try_bool!(psapi::GetProcessMemoryInfo(
|
||||
handle as _,
|
||||
&mut memory_counters as *mut _ as _,
|
||||
std::mem::size_of::<psapi::PROCESS_MEMORY_COUNTERS_EX>() as u32,
|
||||
));
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.ok()?;
|
||||
unsafe { FileTimeToSystemTime(&user_filetime, &mut user_time) }.ok().ok()?;
|
||||
unsafe { FileTimeToSystemTime(&kernel_filetime, &mut kernel_time) }.ok().ok()?;
|
||||
|
||||
// Unlike on Linux with RUSAGE_CHILDREN, this will only return memory information for the process
|
||||
// with the given handle and none of that process's children.
|
||||
unsafe {
|
||||
K32GetProcessMemoryInfo(
|
||||
handle,
|
||||
&mut memory_counters,
|
||||
std::mem::size_of::<PROCESS_MEMORY_COUNTERS_EX>() as u32,
|
||||
)
|
||||
}
|
||||
.ok()
|
||||
.ok()?;
|
||||
|
||||
// Guide on interpreting these numbers:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/psapi/process-memory-usage-information
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import sys
|
|||
from shutil import rmtree
|
||||
|
||||
import bootstrap
|
||||
import configure
|
||||
|
||||
|
||||
class VerifyTestCase(unittest.TestCase):
|
||||
|
|
@ -74,12 +75,50 @@ class ProgramOutOfDate(unittest.TestCase):
|
|||
self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
|
||||
|
||||
|
||||
class GenerateAndParseConfig(unittest.TestCase):
|
||||
"""Test that we can serialize and deserialize a config.toml file"""
|
||||
def serialize_and_parse(self, args):
|
||||
from io import StringIO
|
||||
|
||||
section_order, sections, targets = configure.parse_args(args)
|
||||
buffer = StringIO()
|
||||
configure.write_config_toml(buffer, section_order, targets, sections)
|
||||
build = bootstrap.RustBuild()
|
||||
build.config_toml = buffer.getvalue()
|
||||
|
||||
try:
|
||||
import tomllib
|
||||
# Verify this is actually valid TOML.
|
||||
tomllib.loads(build.config_toml)
|
||||
except ImportError:
|
||||
print("warning: skipping TOML validation, need at least python 3.11", file=sys.stderr)
|
||||
return build
|
||||
|
||||
def test_no_args(self):
|
||||
build = self.serialize_and_parse([])
|
||||
self.assertEqual(build.get_toml("changelog-seen"), '2')
|
||||
self.assertIsNone(build.get_toml("llvm.download-ci-llvm"))
|
||||
|
||||
def test_set_section(self):
|
||||
build = self.serialize_and_parse(["--set", "llvm.download-ci-llvm"])
|
||||
self.assertEqual(build.get_toml("download-ci-llvm", section="llvm"), 'true')
|
||||
|
||||
def test_set_target(self):
|
||||
build = self.serialize_and_parse(["--set", "target.x86_64-unknown-linux-gnu.cc=gcc"])
|
||||
self.assertEqual(build.get_toml("cc", section="target.x86_64-unknown-linux-gnu"), 'gcc')
|
||||
|
||||
# Uncomment when #108928 is fixed.
|
||||
# def test_set_top_level(self):
|
||||
# build = self.serialize_and_parse(["--set", "profile=compiler"])
|
||||
# self.assertEqual(build.get_toml("profile"), 'compiler')
|
||||
|
||||
if __name__ == '__main__':
|
||||
SUITE = unittest.TestSuite()
|
||||
TEST_LOADER = unittest.TestLoader()
|
||||
SUITE.addTest(doctest.DocTestSuite(bootstrap))
|
||||
SUITE.addTests([
|
||||
TEST_LOADER.loadTestsFromTestCase(VerifyTestCase),
|
||||
TEST_LOADER.loadTestsFromTestCase(GenerateAndParseConfig),
|
||||
TEST_LOADER.loadTestsFromTestCase(ProgramOutOfDate)])
|
||||
|
||||
RUNNER = unittest.TextTestRunner(stream=sys.stdout, verbosity=2)
|
||||
|
|
|
|||
|
|
@ -1303,6 +1303,14 @@ impl<'a> Builder<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
// By default, windows-rs depends on a native library that doesn't get copied into the
|
||||
// sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
|
||||
// library unnecessary. This can be removed when windows-rs enables raw-dylib
|
||||
// unconditionally.
|
||||
if let Mode::Rustc | Mode::ToolRustc = mode {
|
||||
rustflags.arg("--cfg=windows_raw_dylib");
|
||||
}
|
||||
|
||||
if use_new_symbol_mangling {
|
||||
rustflags.arg("-Csymbol-mangling-version=v0");
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -205,77 +205,78 @@ if '--help' in sys.argv or '-h' in sys.argv:
|
|||
|
||||
# Parse all command line arguments into one of these three lists, handling
|
||||
# boolean and value-based options separately
|
||||
unknown_args = []
|
||||
need_value_args = []
|
||||
known_args = {}
|
||||
def parse_args(args):
|
||||
unknown_args = []
|
||||
need_value_args = []
|
||||
known_args = {}
|
||||
|
||||
p("processing command line")
|
||||
i = 1
|
||||
while i < len(sys.argv):
|
||||
arg = sys.argv[i]
|
||||
i += 1
|
||||
if not arg.startswith('--'):
|
||||
unknown_args.append(arg)
|
||||
continue
|
||||
i = 0
|
||||
while i < len(args):
|
||||
arg = args[i]
|
||||
i += 1
|
||||
if not arg.startswith('--'):
|
||||
unknown_args.append(arg)
|
||||
continue
|
||||
|
||||
found = False
|
||||
for option in options:
|
||||
value = None
|
||||
if option.value:
|
||||
keyval = arg[2:].split('=', 1)
|
||||
key = keyval[0]
|
||||
if option.name != key:
|
||||
continue
|
||||
found = False
|
||||
for option in options:
|
||||
value = None
|
||||
if option.value:
|
||||
keyval = arg[2:].split('=', 1)
|
||||
key = keyval[0]
|
||||
if option.name != key:
|
||||
continue
|
||||
|
||||
if len(keyval) > 1:
|
||||
value = keyval[1]
|
||||
elif i < len(sys.argv):
|
||||
value = sys.argv[i]
|
||||
i += 1
|
||||
if len(keyval) > 1:
|
||||
value = keyval[1]
|
||||
elif i < len(args):
|
||||
value = args[i]
|
||||
i += 1
|
||||
else:
|
||||
need_value_args.append(arg)
|
||||
continue
|
||||
else:
|
||||
need_value_args.append(arg)
|
||||
continue
|
||||
else:
|
||||
if arg[2:] == 'enable-' + option.name:
|
||||
value = True
|
||||
elif arg[2:] == 'disable-' + option.name:
|
||||
value = False
|
||||
else:
|
||||
continue
|
||||
if arg[2:] == 'enable-' + option.name:
|
||||
value = True
|
||||
elif arg[2:] == 'disable-' + option.name:
|
||||
value = False
|
||||
else:
|
||||
continue
|
||||
|
||||
found = True
|
||||
if option.name not in known_args:
|
||||
known_args[option.name] = []
|
||||
known_args[option.name].append((option, value))
|
||||
break
|
||||
found = True
|
||||
if option.name not in known_args:
|
||||
known_args[option.name] = []
|
||||
known_args[option.name].append((option, value))
|
||||
break
|
||||
|
||||
if not found:
|
||||
unknown_args.append(arg)
|
||||
p("")
|
||||
if not found:
|
||||
unknown_args.append(arg)
|
||||
|
||||
# Note: here and a few other places, we use [-1] to apply the *last* value
|
||||
# passed. But if option-checking is enabled, then the known_args loop will
|
||||
# also assert that options are only passed once.
|
||||
option_checking = ('option-checking' not in known_args
|
||||
or known_args['option-checking'][-1][1])
|
||||
if option_checking:
|
||||
if len(unknown_args) > 0:
|
||||
err("Option '" + unknown_args[0] + "' is not recognized")
|
||||
if len(need_value_args) > 0:
|
||||
err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
|
||||
# Note: here and a few other places, we use [-1] to apply the *last* value
|
||||
# passed. But if option-checking is enabled, then the known_args loop will
|
||||
# also assert that options are only passed once.
|
||||
option_checking = ('option-checking' not in known_args
|
||||
or known_args['option-checking'][-1][1])
|
||||
if option_checking:
|
||||
if len(unknown_args) > 0:
|
||||
err("Option '" + unknown_args[0] + "' is not recognized")
|
||||
if len(need_value_args) > 0:
|
||||
err("Option '{0}' needs a value ({0}=val)".format(need_value_args[0]))
|
||||
|
||||
# Parse all known arguments into a configuration structure that reflects the
|
||||
# TOML we're going to write out
|
||||
config = {}
|
||||
config = {}
|
||||
|
||||
set('build.configure-args', sys.argv[1:], config)
|
||||
apply_args(known_args, option_checking, config)
|
||||
return parse_example_config(known_args, config)
|
||||
|
||||
|
||||
def build():
|
||||
def build(known_args):
|
||||
if 'build' in known_args:
|
||||
return known_args['build'][-1][1]
|
||||
return bootstrap.default_build_triple(verbose=False)
|
||||
|
||||
|
||||
def set(key, value):
|
||||
def set(key, value, config):
|
||||
if isinstance(value, list):
|
||||
# Remove empty values, which value.split(',') tends to generate.
|
||||
value = [v for v in value if v]
|
||||
|
|
@ -297,75 +298,76 @@ def set(key, value):
|
|||
arr = arr[part]
|
||||
|
||||
|
||||
for key in known_args:
|
||||
# The `set` option is special and can be passed a bunch of times
|
||||
if key == 'set':
|
||||
for option, value in known_args[key]:
|
||||
keyval = value.split('=', 1)
|
||||
if len(keyval) == 1 or keyval[1] == "true":
|
||||
value = True
|
||||
elif keyval[1] == "false":
|
||||
value = False
|
||||
else:
|
||||
value = keyval[1]
|
||||
set(keyval[0], value)
|
||||
continue
|
||||
def apply_args(known_args, option_checking, config):
|
||||
for key in known_args:
|
||||
# The `set` option is special and can be passed a bunch of times
|
||||
if key == 'set':
|
||||
for option, value in known_args[key]:
|
||||
keyval = value.split('=', 1)
|
||||
if len(keyval) == 1 or keyval[1] == "true":
|
||||
value = True
|
||||
elif keyval[1] == "false":
|
||||
value = False
|
||||
else:
|
||||
value = keyval[1]
|
||||
set(keyval[0], value, config)
|
||||
continue
|
||||
|
||||
# Ensure each option is only passed once
|
||||
arr = known_args[key]
|
||||
if option_checking and len(arr) > 1:
|
||||
err("Option '{}' provided more than once".format(key))
|
||||
option, value = arr[-1]
|
||||
# Ensure each option is only passed once
|
||||
arr = known_args[key]
|
||||
if option_checking and len(arr) > 1:
|
||||
err("Option '{}' provided more than once".format(key))
|
||||
option, value = arr[-1]
|
||||
|
||||
# If we have a clear avenue to set our value in rustbuild, do so
|
||||
if option.rustbuild is not None:
|
||||
set(option.rustbuild, value)
|
||||
continue
|
||||
# If we have a clear avenue to set our value in rustbuild, do so
|
||||
if option.rustbuild is not None:
|
||||
set(option.rustbuild, value, config)
|
||||
continue
|
||||
|
||||
# Otherwise we're a "special" option and need some extra handling, so do
|
||||
# that here.
|
||||
if option.name == 'sccache':
|
||||
set('llvm.ccache', 'sccache')
|
||||
elif option.name == 'local-rust':
|
||||
for path in os.environ['PATH'].split(os.pathsep):
|
||||
if os.path.exists(path + '/rustc'):
|
||||
set('build.rustc', path + '/rustc')
|
||||
break
|
||||
for path in os.environ['PATH'].split(os.pathsep):
|
||||
if os.path.exists(path + '/cargo'):
|
||||
set('build.cargo', path + '/cargo')
|
||||
break
|
||||
elif option.name == 'local-rust-root':
|
||||
set('build.rustc', value + '/bin/rustc')
|
||||
set('build.cargo', value + '/bin/cargo')
|
||||
elif option.name == 'llvm-root':
|
||||
set('target.{}.llvm-config'.format(build()), value + '/bin/llvm-config')
|
||||
elif option.name == 'llvm-config':
|
||||
set('target.{}.llvm-config'.format(build()), value)
|
||||
elif option.name == 'llvm-filecheck':
|
||||
set('target.{}.llvm-filecheck'.format(build()), value)
|
||||
elif option.name == 'tools':
|
||||
set('build.tools', value.split(','))
|
||||
elif option.name == 'codegen-backends':
|
||||
set('rust.codegen-backends', value.split(','))
|
||||
elif option.name == 'host':
|
||||
set('build.host', value.split(','))
|
||||
elif option.name == 'target':
|
||||
set('build.target', value.split(','))
|
||||
elif option.name == 'full-tools':
|
||||
set('rust.codegen-backends', ['llvm'])
|
||||
set('rust.lld', True)
|
||||
set('rust.llvm-tools', True)
|
||||
set('build.extended', True)
|
||||
elif option.name == 'option-checking':
|
||||
# this was handled above
|
||||
pass
|
||||
elif option.name == 'dist-compression-formats':
|
||||
set('dist.compression-formats', value.split(','))
|
||||
else:
|
||||
raise RuntimeError("unhandled option {}".format(option.name))
|
||||
# Otherwise we're a "special" option and need some extra handling, so do
|
||||
# that here.
|
||||
build_triple = build(known_args)
|
||||
|
||||
set('build.configure-args', sys.argv[1:])
|
||||
if option.name == 'sccache':
|
||||
set('llvm.ccache', 'sccache', config)
|
||||
elif option.name == 'local-rust':
|
||||
for path in os.environ['PATH'].split(os.pathsep):
|
||||
if os.path.exists(path + '/rustc'):
|
||||
set('build.rustc', path + '/rustc', config)
|
||||
break
|
||||
for path in os.environ['PATH'].split(os.pathsep):
|
||||
if os.path.exists(path + '/cargo'):
|
||||
set('build.cargo', path + '/cargo', config)
|
||||
break
|
||||
elif option.name == 'local-rust-root':
|
||||
set('build.rustc', value + '/bin/rustc', config)
|
||||
set('build.cargo', value + '/bin/cargo', config)
|
||||
elif option.name == 'llvm-root':
|
||||
set('target.{}.llvm-config'.format(build_triple), value + '/bin/llvm-config', config)
|
||||
elif option.name == 'llvm-config':
|
||||
set('target.{}.llvm-config'.format(build_triple), value, config)
|
||||
elif option.name == 'llvm-filecheck':
|
||||
set('target.{}.llvm-filecheck'.format(build_triple), value, config)
|
||||
elif option.name == 'tools':
|
||||
set('build.tools', value.split(','), config)
|
||||
elif option.name == 'codegen-backends':
|
||||
set('rust.codegen-backends', value.split(','), config)
|
||||
elif option.name == 'host':
|
||||
set('build.host', value.split(','), config)
|
||||
elif option.name == 'target':
|
||||
set('build.target', value.split(','), config)
|
||||
elif option.name == 'full-tools':
|
||||
set('rust.codegen-backends', ['llvm'], config)
|
||||
set('rust.lld', True, config)
|
||||
set('rust.llvm-tools', True, config)
|
||||
set('build.extended', True, config)
|
||||
elif option.name == 'option-checking':
|
||||
# this was handled above
|
||||
pass
|
||||
elif option.name == 'dist-compression-formats':
|
||||
set('dist.compression-formats', value.split(','), config)
|
||||
else:
|
||||
raise RuntimeError("unhandled option {}".format(option.name))
|
||||
|
||||
# "Parse" the `config.example.toml` file into the various sections, and we'll
|
||||
# use this as a template of a `config.toml` to write out which preserves
|
||||
|
|
@ -373,46 +375,50 @@ set('build.configure-args', sys.argv[1:])
|
|||
#
|
||||
# Note that the `target` section is handled separately as we'll duplicate it
|
||||
# per configured target, so there's a bit of special handling for that here.
|
||||
sections = {}
|
||||
cur_section = None
|
||||
sections[None] = []
|
||||
section_order = [None]
|
||||
targets = {}
|
||||
top_level_keys = []
|
||||
def parse_example_config(known_args, config):
|
||||
sections = {}
|
||||
cur_section = None
|
||||
sections[None] = []
|
||||
section_order = [None]
|
||||
targets = {}
|
||||
top_level_keys = []
|
||||
|
||||
for line in open(rust_dir + '/config.example.toml').read().split("\n"):
|
||||
if cur_section == None:
|
||||
if line.count('=') == 1:
|
||||
top_level_key = line.split('=')[0]
|
||||
top_level_key = top_level_key.strip(' #')
|
||||
top_level_keys.append(top_level_key)
|
||||
if line.startswith('['):
|
||||
cur_section = line[1:-1]
|
||||
if cur_section.startswith('target'):
|
||||
cur_section = 'target'
|
||||
elif '.' in cur_section:
|
||||
raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
|
||||
sections[cur_section] = [line]
|
||||
section_order.append(cur_section)
|
||||
else:
|
||||
sections[cur_section].append(line)
|
||||
for line in open(rust_dir + '/config.example.toml').read().split("\n"):
|
||||
if cur_section == None:
|
||||
if line.count('=') == 1:
|
||||
top_level_key = line.split('=')[0]
|
||||
top_level_key = top_level_key.strip(' #')
|
||||
top_level_keys.append(top_level_key)
|
||||
if line.startswith('['):
|
||||
cur_section = line[1:-1]
|
||||
if cur_section.startswith('target'):
|
||||
cur_section = 'target'
|
||||
elif '.' in cur_section:
|
||||
raise RuntimeError("don't know how to deal with section: {}".format(cur_section))
|
||||
sections[cur_section] = [line]
|
||||
section_order.append(cur_section)
|
||||
else:
|
||||
sections[cur_section].append(line)
|
||||
|
||||
# Fill out the `targets` array by giving all configured targets a copy of the
|
||||
# `target` section we just loaded from the example config
|
||||
configured_targets = [build()]
|
||||
if 'build' in config:
|
||||
if 'host' in config['build']:
|
||||
configured_targets += config['build']['host']
|
||||
if 'target' in config['build']:
|
||||
configured_targets += config['build']['target']
|
||||
if 'target' in config:
|
||||
for target in config['target']:
|
||||
configured_targets.append(target)
|
||||
for target in configured_targets:
|
||||
targets[target] = sections['target'][:]
|
||||
# For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
|
||||
# Avoid using quotes unless it's necessary.
|
||||
targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
|
||||
# Fill out the `targets` array by giving all configured targets a copy of the
|
||||
# `target` section we just loaded from the example config
|
||||
configured_targets = [build(known_args)]
|
||||
if 'build' in config:
|
||||
if 'host' in config['build']:
|
||||
configured_targets += config['build']['host']
|
||||
if 'target' in config['build']:
|
||||
configured_targets += config['build']['target']
|
||||
if 'target' in config:
|
||||
for target in config['target']:
|
||||
configured_targets.append(target)
|
||||
for target in configured_targets:
|
||||
targets[target] = sections['target'][:]
|
||||
# For `.` to be valid TOML, it needs to be quoted. But `bootstrap.py` doesn't use a proper TOML parser and fails to parse the target.
|
||||
# Avoid using quotes unless it's necessary.
|
||||
targets[target][0] = targets[target][0].replace("x86_64-unknown-linux-gnu", "'{}'".format(target) if "." in target else target)
|
||||
|
||||
configure_file(sections, top_level_keys, targets, config)
|
||||
return section_order, sections, targets
|
||||
|
||||
|
||||
def is_number(value):
|
||||
|
|
@ -475,17 +481,20 @@ def configure_top_level_key(lines, top_level_key, value):
|
|||
raise RuntimeError("failed to find config line for {}".format(top_level_key))
|
||||
|
||||
|
||||
for section_key, section_config in config.items():
|
||||
if section_key not in sections and section_key not in top_level_keys:
|
||||
raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
|
||||
if section_key in top_level_keys:
|
||||
configure_top_level_key(sections[None], section_key, section_config)
|
||||
# Modify `sections` to reflect the parsed arguments and example configs.
|
||||
def configure_file(sections, top_level_keys, targets, config):
|
||||
for section_key, section_config in config.items():
|
||||
if section_key not in sections and section_key not in top_level_keys:
|
||||
raise RuntimeError("config key {} not in sections or top_level_keys".format(section_key))
|
||||
if section_key in top_level_keys:
|
||||
configure_top_level_key(sections[None], section_key, section_config)
|
||||
|
||||
elif section_key == 'target':
|
||||
for target in section_config:
|
||||
configure_section(targets[target], section_config[target])
|
||||
else:
|
||||
configure_section(sections[section_key], section_config)
|
||||
|
||||
elif section_key == 'target':
|
||||
for target in section_config:
|
||||
configure_section(targets[target], section_config[target])
|
||||
else:
|
||||
configure_section(sections[section_key], section_config)
|
||||
|
||||
def write_uncommented(target, f):
|
||||
block = []
|
||||
|
|
@ -503,24 +512,36 @@ def write_uncommented(target, f):
|
|||
is_comment = is_comment and line.startswith('#')
|
||||
return f
|
||||
|
||||
# Now that we've built up our `config.toml`, write it all out in the same
|
||||
# order that we read it in.
|
||||
p("")
|
||||
p("writing `config.toml` in current directory")
|
||||
with bootstrap.output('config.toml') as f:
|
||||
|
||||
def write_config_toml(writer, section_order, targets, sections):
|
||||
for section in section_order:
|
||||
if section == 'target':
|
||||
for target in targets:
|
||||
f = write_uncommented(targets[target], f)
|
||||
writer = write_uncommented(targets[target], writer)
|
||||
else:
|
||||
f = write_uncommented(sections[section], f)
|
||||
writer = write_uncommented(sections[section], writer)
|
||||
|
||||
with bootstrap.output('Makefile') as f:
|
||||
contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
|
||||
contents = open(contents).read()
|
||||
contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
|
||||
contents = contents.replace("$(CFG_PYTHON)", sys.executable)
|
||||
f.write(contents)
|
||||
|
||||
p("")
|
||||
p("run `python {}/x.py --help`".format(rust_dir))
|
||||
if __name__ == "__main__":
|
||||
p("processing command line")
|
||||
# Parse all known arguments into a configuration structure that reflects the
|
||||
# TOML we're going to write out
|
||||
p("")
|
||||
section_order, sections, targets = parse_args(sys.argv[1:])
|
||||
|
||||
# Now that we've built up our `config.toml`, write it all out in the same
|
||||
# order that we read it in.
|
||||
p("")
|
||||
p("writing `config.toml` in current directory")
|
||||
with bootstrap.output('config.toml') as f:
|
||||
write_config_toml(f, section_order, targets, sections)
|
||||
|
||||
with bootstrap.output('Makefile') as f:
|
||||
contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in')
|
||||
contents = open(contents).read()
|
||||
contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/')
|
||||
contents = contents.replace("$(CFG_PYTHON)", sys.executable)
|
||||
f.write(contents)
|
||||
|
||||
p("")
|
||||
p("run `python {}/x.py --help`".format(rust_dir))
|
||||
|
|
|
|||
|
|
@ -210,6 +210,8 @@ fn make_win_dist(
|
|||
rustc_dlls.push("libgcc_s_seh-1.dll");
|
||||
}
|
||||
|
||||
// Libraries necessary to link the windows-gnu toolchains.
|
||||
// System libraries will be preferred if they are available (see #67429).
|
||||
let target_libs = [
|
||||
//MinGW libs
|
||||
"libgcc.a",
|
||||
|
|
@ -223,6 +225,7 @@ fn make_win_dist(
|
|||
"libmoldname.a",
|
||||
"libpthread.a",
|
||||
//Windows import libs
|
||||
//This should contain only the set of libraries necessary to link the standard library.
|
||||
"libadvapi32.a",
|
||||
"libbcrypt.a",
|
||||
"libcomctl32.a",
|
||||
|
|
@ -236,6 +239,7 @@ fn make_win_dist(
|
|||
"libkernel32.a",
|
||||
"libmsimg32.a",
|
||||
"libmsvcrt.a",
|
||||
"libntdll.a",
|
||||
"libodbc32.a",
|
||||
"libole32.a",
|
||||
"liboleaut32.a",
|
||||
|
|
|
|||
|
|
@ -27,52 +27,54 @@
|
|||
//! Note that this module has a #[cfg(windows)] above it as none of this logic
|
||||
//! is required on Unix.
|
||||
|
||||
#![allow(nonstandard_style, dead_code)]
|
||||
|
||||
use crate::Build;
|
||||
use std::env;
|
||||
use std::ffi::c_void;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::shared::minwindef::{DWORD, FALSE, LPVOID};
|
||||
use winapi::um::errhandlingapi::SetErrorMode;
|
||||
use winapi::um::handleapi::{CloseHandle, DuplicateHandle};
|
||||
use winapi::um::jobapi2::{AssignProcessToJobObject, CreateJobObjectW, SetInformationJobObject};
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, OpenProcess};
|
||||
use winapi::um::winbase::{BELOW_NORMAL_PRIORITY_CLASS, SEM_NOGPFAULTERRORBOX};
|
||||
use winapi::um::winnt::{
|
||||
JobObjectExtendedLimitInformation, DUPLICATE_SAME_ACCESS, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
|
||||
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
|
||||
use windows::{
|
||||
core::PCWSTR,
|
||||
Win32::Foundation::{CloseHandle, DuplicateHandle, DUPLICATE_SAME_ACCESS, HANDLE},
|
||||
Win32::System::Diagnostics::Debug::{SetErrorMode, SEM_NOGPFAULTERRORBOX, THREAD_ERROR_MODE},
|
||||
Win32::System::JobObjects::{
|
||||
AssignProcessToJobObject, CreateJobObjectW, JobObjectExtendedLimitInformation,
|
||||
SetInformationJobObject, JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
|
||||
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_PRIORITY_CLASS,
|
||||
},
|
||||
Win32::System::Threading::{
|
||||
GetCurrentProcess, OpenProcess, BELOW_NORMAL_PRIORITY_CLASS, PROCESS_DUP_HANDLE,
|
||||
},
|
||||
};
|
||||
|
||||
pub unsafe fn setup(build: &mut Build) {
|
||||
// Enable the Windows Error Reporting dialog which msys disables,
|
||||
// so we can JIT debug rustc
|
||||
let mode = SetErrorMode(0);
|
||||
let mode = SetErrorMode(THREAD_ERROR_MODE::default());
|
||||
let mode = THREAD_ERROR_MODE(mode);
|
||||
SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX);
|
||||
|
||||
// Create a new job object for us to use
|
||||
let job = CreateJobObjectW(ptr::null_mut(), ptr::null());
|
||||
assert!(!job.is_null(), "{}", io::Error::last_os_error());
|
||||
let job = CreateJobObjectW(None, PCWSTR::null()).unwrap();
|
||||
|
||||
// Indicate that when all handles to the job object are gone that all
|
||||
// process in the object should be killed. Note that this includes our
|
||||
// entire process tree by default because we've added ourselves and our
|
||||
// children will reside in the job by default.
|
||||
let mut info = mem::zeroed::<JOBOBJECT_EXTENDED_LIMIT_INFORMATION>();
|
||||
let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default();
|
||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
if build.config.low_priority {
|
||||
info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS;
|
||||
info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
|
||||
info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0;
|
||||
}
|
||||
let r = SetInformationJobObject(
|
||||
job,
|
||||
JobObjectExtendedLimitInformation,
|
||||
&mut info as *mut _ as LPVOID,
|
||||
mem::size_of_val(&info) as DWORD,
|
||||
);
|
||||
assert!(r != 0, "{}", io::Error::last_os_error());
|
||||
&info as *const _ as *const c_void,
|
||||
mem::size_of_val(&info) as u32,
|
||||
)
|
||||
.ok();
|
||||
assert!(r.is_ok(), "{}", io::Error::last_os_error());
|
||||
|
||||
// Assign our process to this job object. Note that if this fails, one very
|
||||
// likely reason is that we are ourselves already in a job object! This can
|
||||
|
|
@ -83,8 +85,8 @@ pub unsafe fn setup(build: &mut Build) {
|
|||
// Also note that nested jobs (why this might fail) are supported in recent
|
||||
// versions of Windows, but the version of Windows that our bots are running
|
||||
// at least don't support nested job objects.
|
||||
let r = AssignProcessToJobObject(job, GetCurrentProcess());
|
||||
if r == 0 {
|
||||
let r = AssignProcessToJobObject(job, GetCurrentProcess()).ok();
|
||||
if r.is_err() {
|
||||
CloseHandle(job);
|
||||
return;
|
||||
}
|
||||
|
|
@ -102,31 +104,32 @@ pub unsafe fn setup(build: &mut Build) {
|
|||
Err(..) => return,
|
||||
};
|
||||
|
||||
let parent = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid.parse().unwrap());
|
||||
let parent = match OpenProcess(PROCESS_DUP_HANDLE, false, pid.parse().unwrap()).ok() {
|
||||
Some(parent) => parent,
|
||||
_ => {
|
||||
// If we get a null parent pointer here, it is possible that either
|
||||
// we have an invalid pid or the parent process has been closed.
|
||||
// Since the first case rarely happens
|
||||
// (only when wrongly setting the environmental variable),
|
||||
// it might be better to improve the experience of the second case
|
||||
// when users have interrupted the parent process and we haven't finish
|
||||
// duplicating the handle yet. We just need close the job object if that occurs.
|
||||
CloseHandle(job);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// If we get a null parent pointer here, it is possible that either
|
||||
// we have got an invalid pid or the parent process has been closed.
|
||||
// Since the first case rarely happens
|
||||
// (only when wrongly setting the environmental variable),
|
||||
// so it might be better to improve the experience of the second case
|
||||
// when users have interrupted the parent process and we don't finish
|
||||
// duplicating the handle yet.
|
||||
// We just need close the job object if that occurs.
|
||||
if parent.is_null() {
|
||||
CloseHandle(job);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut parent_handle = ptr::null_mut();
|
||||
let mut parent_handle = HANDLE::default();
|
||||
let r = DuplicateHandle(
|
||||
GetCurrentProcess(),
|
||||
job,
|
||||
parent,
|
||||
&mut parent_handle,
|
||||
0,
|
||||
FALSE,
|
||||
false,
|
||||
DUPLICATE_SAME_ACCESS,
|
||||
);
|
||||
)
|
||||
.ok();
|
||||
|
||||
// If this failed, well at least we tried! An example of DuplicateHandle
|
||||
// failing in the past has been when the wrong python2 package spawned this
|
||||
|
|
@ -134,7 +137,7 @@ pub unsafe fn setup(build: &mut Build) {
|
|||
// `mingw-w64-x86_64-python2`. Not sure why it failed, but the "failure
|
||||
// mode" here is that we only clean everything up when the build system
|
||||
// dies, not when the python parent does, so not too bad.
|
||||
if r != 0 {
|
||||
if r.is_err() {
|
||||
CloseHandle(job);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,9 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
|
|||
// FIXME: Used by filetime, but we should not be triggering on external dependencies.
|
||||
(Some(Mode::Rustc), "emulate_second_only_system", None),
|
||||
(Some(Mode::ToolRustc), "emulate_second_only_system", None),
|
||||
// Needed to avoid the need to copy windows.lib into the sysroot.
|
||||
(Some(Mode::Rustc), "windows_raw_dylib", None),
|
||||
(Some(Mode::ToolRustc), "windows_raw_dylib", None),
|
||||
];
|
||||
|
||||
/// A structure representing a Rust compiler.
|
||||
|
|
|
|||
|
|
@ -567,6 +567,8 @@ fn configure_cmake(
|
|||
cfg.define("CMAKE_SYSTEM_NAME", "Haiku");
|
||||
} else if target.contains("solaris") || target.contains("illumos") {
|
||||
cfg.define("CMAKE_SYSTEM_NAME", "SunOS");
|
||||
} else if target.contains("linux") {
|
||||
cfg.define("CMAKE_SYSTEM_NAME", "Linux");
|
||||
}
|
||||
// When cross-compiling we should also set CMAKE_SYSTEM_VERSION, but in
|
||||
// that case like CMake we cannot easily determine system version either.
|
||||
|
|
|
|||
|
|
@ -155,29 +155,30 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
|
|||
fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::ptr;
|
||||
|
||||
use winapi::shared::minwindef::{DWORD, WORD};
|
||||
use winapi::um::fileapi::{CreateFileW, OPEN_EXISTING};
|
||||
use winapi::um::handleapi::CloseHandle;
|
||||
use winapi::um::ioapiset::DeviceIoControl;
|
||||
use winapi::um::winbase::{FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT};
|
||||
use winapi::um::winioctl::FSCTL_SET_REPARSE_POINT;
|
||||
use winapi::um::winnt::{
|
||||
FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_WRITE,
|
||||
IO_REPARSE_TAG_MOUNT_POINT, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, WCHAR,
|
||||
use windows::{
|
||||
core::PCWSTR,
|
||||
Win32::Foundation::{CloseHandle, HANDLE},
|
||||
Win32::Storage::FileSystem::{
|
||||
CreateFileW, FILE_ACCESS_FLAGS, FILE_FLAG_BACKUP_SEMANTICS,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE,
|
||||
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, OPEN_EXISTING,
|
||||
},
|
||||
Win32::System::Ioctl::FSCTL_SET_REPARSE_POINT,
|
||||
Win32::System::SystemServices::{GENERIC_WRITE, IO_REPARSE_TAG_MOUNT_POINT},
|
||||
Win32::System::IO::DeviceIoControl,
|
||||
};
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
struct REPARSE_MOUNTPOINT_DATA_BUFFER {
|
||||
ReparseTag: DWORD,
|
||||
ReparseDataLength: DWORD,
|
||||
Reserved: WORD,
|
||||
ReparseTargetLength: WORD,
|
||||
ReparseTargetMaximumLength: WORD,
|
||||
Reserved1: WORD,
|
||||
ReparseTarget: WCHAR,
|
||||
ReparseTag: u32,
|
||||
ReparseDataLength: u32,
|
||||
Reserved: u16,
|
||||
ReparseTargetLength: u16,
|
||||
ReparseTargetMaximumLength: u16,
|
||||
Reserved1: u16,
|
||||
ReparseTarget: u16,
|
||||
}
|
||||
|
||||
fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> {
|
||||
|
|
@ -193,17 +194,20 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
|
|||
|
||||
let path = to_u16s(junction)?;
|
||||
|
||||
unsafe {
|
||||
let h = CreateFileW(
|
||||
path.as_ptr(),
|
||||
GENERIC_WRITE,
|
||||
let h = unsafe {
|
||||
CreateFileW(
|
||||
PCWSTR(path.as_ptr()),
|
||||
FILE_ACCESS_FLAGS(GENERIC_WRITE),
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
HANDLE::default(),
|
||||
)
|
||||
}
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
|
||||
unsafe {
|
||||
#[repr(C, align(8))]
|
||||
struct Align8<T>(T);
|
||||
let mut data = Align8([0u8; MAXIMUM_REPARSE_DATA_BUFFER_SIZE as usize]);
|
||||
|
|
@ -219,27 +223,29 @@ pub fn symlink_dir(config: &Config, src: &Path, dest: &Path) -> io::Result<()> {
|
|||
}
|
||||
*buf.offset(i) = 0;
|
||||
i += 1;
|
||||
|
||||
(*db).ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
(*db).ReparseTargetMaximumLength = (i * 2) as WORD;
|
||||
(*db).ReparseTargetLength = ((i - 1) * 2) as WORD;
|
||||
(*db).ReparseDataLength = (*db).ReparseTargetLength as DWORD + 12;
|
||||
(*db).ReparseTargetMaximumLength = (i * 2) as u16;
|
||||
(*db).ReparseTargetLength = ((i - 1) * 2) as u16;
|
||||
(*db).ReparseDataLength = ((*db).ReparseTargetLength + 12) as u32;
|
||||
|
||||
let mut ret = 0;
|
||||
let res = DeviceIoControl(
|
||||
h as *mut _,
|
||||
let mut ret = 0u32;
|
||||
DeviceIoControl(
|
||||
h,
|
||||
FSCTL_SET_REPARSE_POINT,
|
||||
db.cast(),
|
||||
Some(db.cast()),
|
||||
(*db).ReparseDataLength + 8,
|
||||
ptr::null_mut(),
|
||||
None,
|
||||
0,
|
||||
&mut ret,
|
||||
ptr::null_mut(),
|
||||
);
|
||||
|
||||
let out = if res == 0 { Err(io::Error::last_os_error()) } else { Ok(()) };
|
||||
CloseHandle(h);
|
||||
out
|
||||
Some(&mut ret),
|
||||
None,
|
||||
)
|
||||
.ok()
|
||||
.map_err(|_| io::Error::last_os_error())?;
|
||||
}
|
||||
|
||||
unsafe { CloseHandle(h) };
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
# NOTE: intentionally uses python2 for x.py so we can test it still works.
|
||||
# validate-toolstate only runs in our CI, so it's ok for it to only support python3.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
make \
|
||||
|
|
@ -8,6 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-pkg-resources \
|
||||
|
|
@ -30,4 +33,4 @@ RUN pip3 install --no-deps --no-cache-dir --require-hashes -r /tmp/reuse-require
|
|||
COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/
|
||||
COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/
|
||||
|
||||
ENV SCRIPT python3 ../x.py test --stage 0 src/tools/tidy tidyselftest
|
||||
ENV SCRIPT python2.7 ../x.py test --stage 0 src/tools/tidy tidyselftest
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ FROM ubuntu:22.04
|
|||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# NOTE: intentionally installs both python2 and python3 so we can test support for both.
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
gcc-multilib \
|
||||
|
|
@ -11,8 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
python3 \
|
||||
python3.11 \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ x--expand-yaml-anchors--remove:
|
|||
env: {}
|
||||
|
||||
- &job-linux-xl
|
||||
os: ubuntu-20.04-xl
|
||||
os: ubuntu-20.04-16core-64gb
|
||||
<<: *base-job
|
||||
|
||||
- &job-macos-xl
|
||||
|
|
@ -82,7 +82,7 @@ x--expand-yaml-anchors--remove:
|
|||
<<: *base-job
|
||||
|
||||
- &job-windows-xl
|
||||
os: windows-latest-xl
|
||||
os: windows-2019-8core-32gb
|
||||
<<: *base-job
|
||||
|
||||
- &job-aarch64-linux
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use std::hash::Hash;
|
|||
use std::mem;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::clean::inline::merge_attrs;
|
||||
use crate::core::{self, DocContext, ImplTraitParam};
|
||||
use crate::formats::item_type::ItemType;
|
||||
use crate::visit_ast::Module as DocModule;
|
||||
|
|
@ -2373,21 +2374,22 @@ fn clean_maybe_renamed_item<'tcx>(
|
|||
_ => unreachable!("not yet converted"),
|
||||
};
|
||||
|
||||
let mut extra_attrs = Vec::new();
|
||||
let mut import_attrs = Vec::new();
|
||||
let mut target_attrs = Vec::new();
|
||||
if let Some(import_id) = import_id &&
|
||||
let Some(hir::Node::Item(use_node)) = cx.tcx.hir().find_by_def_id(import_id)
|
||||
{
|
||||
let is_inline = inline::load_attrs(cx, import_id.to_def_id()).lists(sym::doc).get_word_attr(sym::inline).is_some();
|
||||
// Then we get all the various imports' attributes.
|
||||
get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs, is_inline);
|
||||
add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id), is_inline);
|
||||
get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut import_attrs, is_inline);
|
||||
add_without_unwanted_attributes(&mut target_attrs, inline::load_attrs(cx, def_id), is_inline);
|
||||
} else {
|
||||
// We only keep the item's attributes.
|
||||
extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
|
||||
target_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
|
||||
}
|
||||
|
||||
let attrs = Attributes::from_ast(&extra_attrs);
|
||||
let cfg = extra_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg);
|
||||
let import_parent = import_id.map(|import_id| cx.tcx.local_parent(import_id).to_def_id());
|
||||
let (attrs, cfg) = merge_attrs(cx, import_parent, &target_attrs, Some(&import_attrs));
|
||||
|
||||
let mut item =
|
||||
Item::from_def_id_and_attrs_and_parts(def_id, Some(name), kind, Box::new(attrs), cfg);
|
||||
|
|
|
|||
|
|
@ -1057,6 +1057,16 @@ impl Tester for Collector {
|
|||
Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)),
|
||||
},
|
||||
ignore_message: None,
|
||||
#[cfg(not(bootstrap))]
|
||||
source_file: "",
|
||||
#[cfg(not(bootstrap))]
|
||||
start_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
start_col: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_line: 0,
|
||||
#[cfg(not(bootstrap))]
|
||||
end_col: 0,
|
||||
// compiler failures are test failures
|
||||
should_panic: test::ShouldPanic::No,
|
||||
compile_fail: config.compile_fail,
|
||||
|
|
|
|||
|
|
@ -1480,7 +1480,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
|
|||
debug!("path={:?}", path);
|
||||
// modified from `resolved_path()` to work with `DefPathData`
|
||||
let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
|
||||
let anchor = anchor(vis_did, last_name, cx).to_string();
|
||||
let anchor = anchor(vis_did, last_name, cx);
|
||||
|
||||
let mut s = "pub(in ".to_owned();
|
||||
for seg in &path.data[..path.data.len() - 1] {
|
||||
|
|
|
|||
|
|
@ -556,7 +556,15 @@ fn check_if_allowed_tag(t: &Tag<'_>) -> bool {
|
|||
}
|
||||
|
||||
fn is_forbidden_tag(t: &Tag<'_>) -> bool {
|
||||
matches!(t, Tag::CodeBlock(_) | Tag::Table(_) | Tag::TableHead | Tag::TableRow | Tag::TableCell)
|
||||
matches!(
|
||||
t,
|
||||
Tag::CodeBlock(_)
|
||||
| Tag::Table(_)
|
||||
| Tag::TableHead
|
||||
| Tag::TableRow
|
||||
| Tag::TableCell
|
||||
| Tag::FootnoteDefinition(_)
|
||||
)
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
|
||||
|
|
@ -589,6 +597,10 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
|
|||
is_start = false;
|
||||
check_if_allowed_tag(c)
|
||||
}
|
||||
Event::FootnoteReference(_) => {
|
||||
self.skipped_tags += 1;
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
};
|
||||
if !is_allowed_tag {
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ impl<'tcx> Context<'tcx> {
|
|||
},
|
||||
);
|
||||
|
||||
path = href.into_inner().to_string_lossy().to_string();
|
||||
path = href.into_inner().to_string_lossy().into_owned();
|
||||
|
||||
if let Some(c) = path.as_bytes().last() && *c != b'/' {
|
||||
path.push('/');
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use clean::AttributesExt;
|
||||
|
||||
use rustc_data_structures::captures::Captures;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::CtorKind;
|
||||
|
|
@ -28,8 +29,8 @@ use crate::formats::item_type::ItemType;
|
|||
use crate::formats::{AssocItemRender, Impl, RenderMode};
|
||||
use crate::html::escape::Escape;
|
||||
use crate::html::format::{
|
||||
join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
|
||||
visibility_print_with_space, Buffer, Ending, PrintWithSpace,
|
||||
display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
|
||||
print_where_clause, visibility_print_with_space, Buffer, Ending, PrintWithSpace,
|
||||
};
|
||||
use crate::html::layout::Page;
|
||||
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
|
||||
|
|
@ -367,7 +368,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
..myitem.clone()
|
||||
};
|
||||
|
||||
let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()));
|
||||
let stab_tags = Some(extra_info_tags(&import_item, item, cx.tcx()).to_string());
|
||||
stab_tags
|
||||
} else {
|
||||
None
|
||||
|
|
@ -461,42 +462,62 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
|
||||
/// Render the stability, deprecation and portability tags that are displayed in the item's summary
|
||||
/// at the module level.
|
||||
fn extra_info_tags(item: &clean::Item, parent: &clean::Item, tcx: TyCtxt<'_>) -> String {
|
||||
let mut tags = String::new();
|
||||
fn extra_info_tags<'a, 'tcx: 'a>(
|
||||
item: &'a clean::Item,
|
||||
parent: &'a clean::Item,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> impl fmt::Display + 'a + Captures<'tcx> {
|
||||
display_fn(move |f| {
|
||||
fn tag_html<'a>(
|
||||
class: &'a str,
|
||||
title: &'a str,
|
||||
contents: &'a str,
|
||||
) -> impl fmt::Display + 'a {
|
||||
display_fn(move |f| {
|
||||
write!(
|
||||
f,
|
||||
r#"<span class="stab {}" title="{}">{}</span>"#,
|
||||
class,
|
||||
Escape(title),
|
||||
contents
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn tag_html(class: &str, title: &str, contents: &str) -> String {
|
||||
format!(r#"<span class="stab {}" title="{}">{}</span>"#, class, Escape(title), contents)
|
||||
}
|
||||
// The trailing space after each tag is to space it properly against the rest of the docs.
|
||||
if let Some(depr) = &item.deprecation(tcx) {
|
||||
let message = if stability::deprecation_in_effect(depr) {
|
||||
"Deprecated"
|
||||
} else {
|
||||
"Deprecation planned"
|
||||
};
|
||||
write!(f, "{}", tag_html("deprecated", "", message))?;
|
||||
}
|
||||
|
||||
// The trailing space after each tag is to space it properly against the rest of the docs.
|
||||
if let Some(depr) = &item.deprecation(tcx) {
|
||||
let message = if stability::deprecation_in_effect(depr) {
|
||||
"Deprecated"
|
||||
} else {
|
||||
"Deprecation planned"
|
||||
// The "rustc_private" crates are permanently unstable so it makes no sense
|
||||
// to render "unstable" everywhere.
|
||||
if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
|
||||
== Some(true)
|
||||
{
|
||||
write!(f, "{}", tag_html("unstable", "", "Experimental"))?;
|
||||
}
|
||||
|
||||
let cfg = match (&item.cfg, parent.cfg.as_ref()) {
|
||||
(Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
|
||||
(cfg, _) => cfg.as_deref().cloned(),
|
||||
};
|
||||
tags += &tag_html("deprecated", "", message);
|
||||
}
|
||||
|
||||
// The "rustc_private" crates are permanently unstable so it makes no sense
|
||||
// to render "unstable" everywhere.
|
||||
if item.stability(tcx).as_ref().map(|s| s.is_unstable() && s.feature != sym::rustc_private)
|
||||
== Some(true)
|
||||
{
|
||||
tags += &tag_html("unstable", "", "Experimental");
|
||||
}
|
||||
|
||||
let cfg = match (&item.cfg, parent.cfg.as_ref()) {
|
||||
(Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
|
||||
(cfg, _) => cfg.as_deref().cloned(),
|
||||
};
|
||||
|
||||
debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
|
||||
if let Some(ref cfg) = cfg {
|
||||
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
|
||||
}
|
||||
|
||||
tags
|
||||
debug!("Portability name={:?} {:?} - {:?} = {:?}", item.name, item.cfg, parent.cfg, cfg);
|
||||
if let Some(ref cfg) = cfg {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html())
|
||||
)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl LocalSourcesCollector<'_, '_> {
|
|||
},
|
||||
);
|
||||
|
||||
let mut href = href.into_inner().to_string_lossy().to_string();
|
||||
let mut href = href.into_inner().to_string_lossy().into_owned();
|
||||
if let Some(c) = href.as_bytes().last() && *c != b'/' {
|
||||
href.push('/');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1202,28 +1202,42 @@ function initSearch(rawSearchIndex) {
|
|||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {integer} typeFilter
|
||||
* @param {Array<integer>} skipPositions - Do not return one of these positions.
|
||||
*
|
||||
* @return {integer} - Returns an edit distance to the best match. If there is no
|
||||
* match, returns `maxEditDistance + 1`.
|
||||
* @return {dist: integer, position: integer} - Returns an edit distance to the best match.
|
||||
* If there is no match, returns
|
||||
* `maxEditDistance + 1` and position: -1.
|
||||
*/
|
||||
function findArg(row, elem, typeFilter, maxEditDistance) {
|
||||
function findArg(row, elem, typeFilter, maxEditDistance, skipPositions) {
|
||||
let dist = maxEditDistance + 1;
|
||||
let position = -1;
|
||||
|
||||
if (row && row.type && row.type.inputs && row.type.inputs.length > 0) {
|
||||
let i = 0;
|
||||
for (const input of row.type.inputs) {
|
||||
if (!typePassesFilter(typeFilter, input.ty)) {
|
||||
if (!typePassesFilter(typeFilter, input.ty) ||
|
||||
skipPositions.indexOf(i) !== -1) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
dist = Math.min(
|
||||
dist,
|
||||
checkType(input, elem, parsedQuery.literalSearch, maxEditDistance)
|
||||
const typeDist = checkType(
|
||||
input,
|
||||
elem,
|
||||
parsedQuery.literalSearch,
|
||||
maxEditDistance
|
||||
);
|
||||
if (dist === 0) {
|
||||
return 0;
|
||||
if (typeDist === 0) {
|
||||
return {dist: 0, position: i};
|
||||
}
|
||||
if (typeDist < dist) {
|
||||
dist = typeDist;
|
||||
position = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
|
||||
dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
|
||||
return {dist, position};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1232,29 +1246,43 @@ function initSearch(rawSearchIndex) {
|
|||
* @param {Row} row
|
||||
* @param {QueryElement} elem - The element from the parsed query.
|
||||
* @param {integer} typeFilter
|
||||
* @param {Array<integer>} skipPositions - Do not return one of these positions.
|
||||
*
|
||||
* @return {integer} - Returns an edit distance to the best match. If there is no
|
||||
* match, returns `maxEditDistance + 1`.
|
||||
* @return {dist: integer, position: integer} - Returns an edit distance to the best match.
|
||||
* If there is no match, returns
|
||||
* `maxEditDistance + 1` and position: -1.
|
||||
*/
|
||||
function checkReturned(row, elem, typeFilter, maxEditDistance) {
|
||||
function checkReturned(row, elem, typeFilter, maxEditDistance, skipPositions) {
|
||||
let dist = maxEditDistance + 1;
|
||||
let position = -1;
|
||||
|
||||
if (row && row.type && row.type.output.length > 0) {
|
||||
const ret = row.type.output;
|
||||
let i = 0;
|
||||
for (const ret_ty of ret) {
|
||||
if (!typePassesFilter(typeFilter, ret_ty.ty)) {
|
||||
if (!typePassesFilter(typeFilter, ret_ty.ty) ||
|
||||
skipPositions.indexOf(i) !== -1) {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
dist = Math.min(
|
||||
dist,
|
||||
checkType(ret_ty, elem, parsedQuery.literalSearch, maxEditDistance)
|
||||
const typeDist = checkType(
|
||||
ret_ty,
|
||||
elem,
|
||||
parsedQuery.literalSearch,
|
||||
maxEditDistance
|
||||
);
|
||||
if (dist === 0) {
|
||||
return 0;
|
||||
if (typeDist === 0) {
|
||||
return {dist: 0, position: i};
|
||||
}
|
||||
if (typeDist < dist) {
|
||||
dist = typeDist;
|
||||
position = i;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
return parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
|
||||
dist = parsedQuery.literalSearch ? maxEditDistance + 1 : dist;
|
||||
return {dist, position};
|
||||
}
|
||||
|
||||
function checkPath(contains, ty, maxEditDistance) {
|
||||
|
|
@ -1455,13 +1483,13 @@ function initSearch(rawSearchIndex) {
|
|||
const fullId = row.id;
|
||||
const searchWord = searchWords[pos];
|
||||
|
||||
const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance);
|
||||
const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance);
|
||||
const in_args = findArg(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
|
||||
const returned = checkReturned(row, elem, parsedQuery.typeFilter, maxEditDistance, []);
|
||||
|
||||
// path_dist is 0 because no parent path information is currently stored
|
||||
// in the search index
|
||||
addIntoResults(results_in_args, fullId, pos, -1, in_args, 0, maxEditDistance);
|
||||
addIntoResults(results_returned, fullId, pos, -1, returned, 0, maxEditDistance);
|
||||
addIntoResults(results_in_args, fullId, pos, -1, in_args.dist, 0, maxEditDistance);
|
||||
addIntoResults(results_returned, fullId, pos, -1, returned.dist, 0, maxEditDistance);
|
||||
|
||||
if (!typePassesFilter(parsedQuery.typeFilter, row.ty)) {
|
||||
return;
|
||||
|
|
@ -1534,12 +1562,20 @@ function initSearch(rawSearchIndex) {
|
|||
|
||||
// If the result is too "bad", we return false and it ends this search.
|
||||
function checkArgs(elems, callback) {
|
||||
const skipPositions = [];
|
||||
for (const elem of elems) {
|
||||
// There is more than one parameter to the query so all checks should be "exact"
|
||||
const dist = callback(row, elem, NO_TYPE_FILTER, maxEditDistance);
|
||||
const { dist, position } = callback(
|
||||
row,
|
||||
elem,
|
||||
NO_TYPE_FILTER,
|
||||
maxEditDistance,
|
||||
skipPositions
|
||||
);
|
||||
if (dist <= 1) {
|
||||
nbDist += 1;
|
||||
totalDist += dist;
|
||||
skipPositions.push(position);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1597,9 +1633,17 @@ function initSearch(rawSearchIndex) {
|
|||
row,
|
||||
elem,
|
||||
parsedQuery.typeFilter,
|
||||
maxEditDistance,
|
||||
[]
|
||||
);
|
||||
addIntoResults(
|
||||
results_others,
|
||||
row.id,
|
||||
i,
|
||||
-1,
|
||||
in_returned.dist,
|
||||
maxEditDistance
|
||||
);
|
||||
addIntoResults(results_others, row.id, i, -1, in_returned, maxEditDistance);
|
||||
}
|
||||
}
|
||||
} else if (parsedQuery.foundElems > 0) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
{% when Self::Deprecation with { message } %}
|
||||
<div class="stab deprecated"> {# #}
|
||||
<span class="emoji">👎</span> {# #}
|
||||
<span>{{message}}</span> {# #}
|
||||
<span>{{message|safe}}</span> {# #}
|
||||
</div> {# #}
|
||||
{% when Self::Unstable with { feature, tracking } %}
|
||||
<div class="stab unstable"> {# #}
|
||||
|
|
|
|||
|
|
@ -286,7 +286,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
split.next().map(|f| Symbol::intern(f)).ok_or_else(no_res)?;
|
||||
let path = split
|
||||
.next()
|
||||
.map(|f| f.to_owned())
|
||||
// If there's no third component, we saw `[a::b]` before and it failed to resolve.
|
||||
// So there's no partial res.
|
||||
.ok_or_else(no_res)?;
|
||||
|
|
@ -429,7 +428,6 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
let item_name = Symbol::intern(item_str);
|
||||
let path_root = split
|
||||
.next()
|
||||
.map(|f| f.to_owned())
|
||||
// If there's no `::`, it's not an associated item.
|
||||
// So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
|
||||
.ok_or_else(|| {
|
||||
|
|
|
|||
|
|
@ -265,10 +265,6 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if !self.view_item_stack.insert(res_did) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !please_inline &&
|
||||
let mut visitor = OneLevelVisitor::new(self.cx.tcx.hir(), res_did) &&
|
||||
let Some(item) = visitor.find_target(self.cx.tcx, def_id.to_def_id(), path) &&
|
||||
|
|
@ -285,6 +281,10 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if !self.view_item_stack.insert(res_did) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let ret = match tcx.hir().get_by_def_id(res_did) {
|
||||
Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
|
||||
let prev = mem::replace(&mut self.inlining, true);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue