branches:
- auto
- try
+ - try-perf
- master
pull_request:
branches:
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
CACHE_DOMAIN: ci-caches.rust-lang.org
- if: "github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
strategy:
matrix:
include:
try-success:
needs:
- try
- if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
steps:
- name: mark the job as a success
run: exit 0
try-failure:
needs:
- try
- if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
steps:
- name: mark the job as a failure
run: exit 1
[submodule "src/tools/rust-analyzer"]
path = src/tools/rust-analyzer
url = https://github.com/rust-analyzer/rust-analyzer.git
-[submodule "src/backtrace"]
- path = src/backtrace
- url = https://github.com/rust-lang/backtrace-rs.git
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "addr2line"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
-dependencies = [
- "compiler_builtins",
- "gimli",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "adler"
-version = "0.2.2"
+name = "adler32"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
+checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
[[package]]
name = "aho-corasick"
[[package]]
name = "backtrace"
-version = "0.3.50"
+version = "0.3.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
dependencies = [
- "addr2line",
+ "backtrace-sys",
"cfg-if",
+ "compiler_builtins",
"libc",
- "miniz_oxide",
- "object",
"rustc-demangle",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399"
+dependencies = [
+ "cc",
+ "compiler_builtins",
+ "libc",
+ "rustc-std-workspace-core",
]
[[package]]
[[package]]
name = "cargo"
-version = "0.47.0"
+version = "0.48.0"
dependencies = [
"anyhow",
"atty",
[[package]]
name = "cc"
-version = "1.0.57"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe"
+checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
dependencies = [
"jobserver",
]
[[package]]
name = "crc32fast"
-version = "1.2.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
+checksum = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192"
dependencies = [
"cfg-if",
]
[[package]]
name = "flate2"
-version = "1.0.16"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
+checksum = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
dependencies = [
"cfg-if",
"crc32fast",
"wasi",
]
-[[package]]
-name = "gimli"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "git2"
version = "0.13.5"
[[package]]
name = "libc"
-version = "0.2.71"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
-version = "0.4.0"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
+checksum = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625"
dependencies = [
- "adler",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
+ "adler32",
]
[[package]]
"libc",
]
-[[package]]
-name = "object"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "once_cell"
version = "1.1.0"
name = "std"
version = "0.0.0"
dependencies = [
- "addr2line",
"alloc",
+ "backtrace",
"cfg-if",
"compiler_builtins",
"core",
"hashbrown",
"hermit-abi",
"libc",
- "miniz_oxide",
- "object",
"panic_abort",
"panic_unwind",
"profiler_builtins",
"rand 0.7.3",
- "rustc-demangle",
"unwind",
"wasi",
]
rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' }
rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' }
-# This crate's integration with libstd is a bit wonky, so we use a submodule
-# instead of a crates.io dependency. Make sure everything else in the repo is
-# also using the submodule, however, so we can avoid duplicate copies of the
-# source code for this crate.
-backtrace = { path = "src/backtrace" }
-
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
"src/tools/rust-analyzer",
"src/tools/rust-installer",
"src/tools/rustfmt",
- "src/backtrace",
# We do not format this file as it is externally sourced and auto-generated.
"src/libstd/sys/cloudabi/abi/cloudabi.rs",
+++ /dev/null
-Subproject commit 5965cf5fc17affc84c11dc9972ae8f4dc2c32db1
&& self.config.control_flow_guard
&& compiler.stage >= 1
{
- rustflags.arg("-Zcontrol-flow-guard");
+ rustflags.arg("-Ccontrol-flow-guard");
}
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
// (essentially libstd and all of its path dependencies)
let std_src_dirs = [
"src/build_helper",
- "src/backtrace/src",
"src/liballoc",
"src/libcore",
"src/libpanic_abort",
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
};
}
+/// Reads an environment variable and adds it to dependencies.
+/// Supposed to be used for all variables except those set for build scripts by cargo
+/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
+ println!("cargo:rerun-if-env-changed={}", key);
+ env::var_os(key)
+}
+
// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
// shared library, which means that when our freshly built llvm-config goes to load it's
// perfect -- we might actually want to see something from Cargo's added library paths -- but
// for now it works.
pub fn restore_library_path() {
- println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
- println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
- let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
- if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
+ let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
+ if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") {
env::set_var(&key, &env);
} else {
env::remove_var(&key);
#####################################
#
-# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+# Azure Pipelines "auto" branch build for Rust on macOS
#
pr: none
trigger:
- auto
-variables:
-- group: dummy-credentials
-
jobs:
-- job: Linux
- timeoutInMinutes: 600
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- x86_64-gnu-llvm-8:
- RUST_BACKTRACE: 1
- dist-x86_64-linux: {}
- dist-x86_64-linux-alt:
- IMAGE: dist-x86_64-linux
- arm-android: {}
- armhf-gnu: {}
- dist-various-1: {}
- dist-various-2: {}
- dist-aarch64-linux: {}
- dist-android: {}
- dist-arm-linux: {}
- dist-armhf-linux: {}
- dist-armv7-linux: {}
- dist-i586-gnu-i586-i686-musl: {}
- dist-i686-freebsd: {}
- dist-i686-linux: {}
- dist-mips-linux: {}
- dist-mips64-linux: {}
- dist-mips64el-linux: {}
- dist-mipsel-linux: {}
- dist-powerpc-linux: {}
- dist-powerpc64-linux: {}
- dist-powerpc64le-linux: {}
- dist-riscv64-linux: {}
- dist-s390x-linux: {}
- dist-x86_64-freebsd: {}
- dist-x86_64-illumos: {}
- dist-x86_64-musl: {}
- dist-x86_64-netbsd: {}
- i686-gnu: {}
- i686-gnu-nopt: {}
- test-various: {}
- wasm32: {}
- x86_64-gnu: {}
- x86_64-gnu-full-bootstrap: {}
- x86_64-gnu-aux: {}
- x86_64-gnu-tools:
- DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
- x86_64-gnu-debug: {}
- x86_64-gnu-nopt: {}
- x86_64-gnu-distcheck: {}
- mingw-check: {}
-
- job: macOS
timeoutInMinutes: 600
pool:
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
-
-
-- job: Windows
- timeoutInMinutes: 600
- pool:
- vmImage: 'vs2017-win2016'
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- # 32/64 bit MSVC tests
- x86_64-msvc-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
- SCRIPT: make ci-subset-1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-msvc-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
- SCRIPT: make ci-subset-2
- i686-msvc-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
- SCRIPT: make ci-subset-1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- i686-msvc-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
- SCRIPT: make ci-subset-2
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-msvc-cargo:
- SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
- VCVARS_BAT: vcvars64.bat
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- # MSVC tools tests
- x86_64-msvc-tools:
- SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
-
- # 32/64-bit MinGW builds.
- #
- # We are using MinGW with posix threads since LLVM does not compile with
- # the win32 threads version due to missing support for C++'s std::thread.
- #
- # Instead of relying on the MinGW version installed on appveryor we download
- # and install one ourselves so we won't be surprised by changes to appveyor's
- # build image.
- #
- # Finally, note that the downloads below are all in the `rust-lang-ci` S3
- # bucket, but they cleraly didn't originate there! The downloads originally
- # came from the mingw-w64 SourceForge download site. Unfortunately
- # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
- i686-mingw-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
- SCRIPT: make ci-mingw-subset-1
- CUSTOM_MINGW: 1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- i686-mingw-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
- SCRIPT: make ci-mingw-subset-2
- CUSTOM_MINGW: 1
- x86_64-mingw-1:
- SCRIPT: make ci-mingw-subset-1
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
- CUSTOM_MINGW: 1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-mingw-2:
- SCRIPT: make ci-mingw-subset-2
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
- CUSTOM_MINGW: 1
-
- # 32/64 bit MSVC and GNU deployment
- dist-x86_64-msvc:
- INITIAL_RUST_CONFIGURE_ARGS: >-
- --build=x86_64-pc-windows-msvc
- --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
- --enable-full-tools
- --enable-profiler
- SCRIPT: python x.py dist
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-i686-msvc:
- INITIAL_RUST_CONFIGURE_ARGS: >-
- --build=i686-pc-windows-msvc
- --target=i586-pc-windows-msvc
- --enable-full-tools
- --enable-profiler
- SCRIPT: python x.py dist
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-i686-mingw:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
- SCRIPT: python x.py dist
- CUSTOM_MINGW: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-x86_64-mingw:
- SCRIPT: python x.py dist
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
- CUSTOM_MINGW: 1
- DIST_REQUIRE_ALL_TOOLS: 1
-
- # "alternate" deployment, see .travis.yml for more info
- dist-x86_64-msvc-alt:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
- SCRIPT: python x.py dist
+++ /dev/null
-#####################################
-## READ BEFORE CHANGING THIS ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines job to publish toolstate. Only triggers on pushes to master.
-#
-
-pr: none
-trigger:
- - master
-
-variables:
-- group: dummy-credentials
-
-pool:
- vmImage: ubuntu-16.04
-
-steps:
-- checkout: self
- fetchDepth: 2
-
-- script: src/ci/publish_toolstate.sh
- displayName: Publish toolstate
- env:
- TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
+++ /dev/null
-#####################################
-## READ BEFORE CHANGING THIS ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines pull request build for Rust
-#
-
-trigger: none
-pr:
-- master
-
-variables:
-- group: public-credentials
-
-jobs:
-- job: Linux
- timeoutInMinutes: 600
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- x86_64-gnu-llvm-8: {}
- mingw-check: {}
- x86_64-gnu-tools:
- CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
trigger:
- try
-variables:
-- group: dummy-credentials
-
jobs:
-- job: Linux
+- job: Dummy
timeoutInMinutes: 600
pool:
vmImage: ubuntu-16.04
steps:
- - template: steps/run.yml
- strategy:
- matrix:
- dist-x86_64-linux: {}
-
-# The macOS and Windows builds here are currently disabled due to them not being
-# overly necessary on `try` builds. We also don't actually have anything that
-# consumes the artifacts currently. Perhaps one day we can re-enable, but for now
-# it helps free up capacity on Azure.
-# - job: macOS
-# timeoutInMinutes: 600
-# pool:
-# vmImage: macos-10.15
-# steps:
-# - template: steps/run.yml
-# strategy:
-# matrix:
-# dist-x86_64-apple:
-# SCRIPT: ./x.py dist
-# INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
-# DEPLOY: 1
-# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-# MACOSX_DEPLOYMENT_TARGET: 10.7
-# NO_LLVM_ASSERTIONS: 1
-# NO_DEBUG_ASSERTIONS: 1
-# DIST_REQUIRE_ALL_TOOLS: 1
-#
-# dist-x86_64-apple-alt:
-# SCRIPT: ./x.py dist
-# INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
-# DEPLOY_ALT: 1
-# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-# MACOSX_DEPLOYMENT_TARGET: 10.7
-# NO_LLVM_ASSERTIONS: 1
-# NO_DEBUG_ASSERTIONS: 1
-#
-# - job: Windows
-# timeoutInMinutes: 600
-# pool:
-# vmImage: 'vs2017-win2016'
-# steps:
-# - template: steps/run.yml
-# strategy:
-# matrix:
-# dist-x86_64-msvc:
-# INITIAL_RUST_CONFIGURE_ARGS: >
-# --build=x86_64-pc-windows-msvc
-# --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
-# --enable-full-tools
-# --enable-profiler
-# SCRIPT: python x.py dist
-# DIST_REQUIRE_ALL_TOOLS: 1
-# DEPLOY: 1
-#
-# dist-x86_64-msvc-alt:
-# INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
-# SCRIPT: python x.py dist
-# DEPLOY_ALT: 1
+ - bash: echo "We're running this job since bors is still gating on Azure"
branches:
- auto
- try
+ - try-perf
- master
pull_request:
branches:
name: try
env:
<<: [*shared-ci-variables, *prod-variables]
- if: github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'
strategy:
matrix:
include:
# successful listening to webhooks only.
try-success:
needs: [try]
- if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
<<: *base-success-job
try-failure:
needs: [try]
- if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
<<: *base-failure-job
auto-success:
needs: [auto]
-Subproject commit 84a31397b34f9d405df44f2899ff17a4828dba18
+Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e
-Subproject commit 82bec5877c77cfad530ca11095db4456d757f668
+Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1
-Subproject commit 0ea7bc494f1289234d8800bb9185021e0ad946f0
+Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb
The default value, if not specified, is 16 for non-incremental builds. For
incremental builds the default is 256 which allows caching to be more granular.
+## control-flow-guard
+
+This flag controls whether LLVM enables the Windows [Control Flow
+Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard)
+platform security feature. This flag is currently ignored for non-Windows targets.
+It takes one of the following values:
+
+* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard.
+* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this
+should only be used for testing purposes as it does not provide security enforcement).
+* `n`, `no`, `off`: do not enable Control Flow Guard (the default).
+
## debug-assertions
This flag lets you turn `cfg(debug_assertions)` [conditional
///
/// # Examples
///
-/// You can create a `String` from [a literal string][str] with [`String::from`]:
+/// You can create a `String` from [a literal string][`str`] with [`String::from`]:
///
/// [`String::from`]: From::from
///
///
/// Here, there's no need to allocate more memory inside the loop.
///
-/// [`&str`]: str
+/// [`str`]: type@str
+/// [`&str`]: type@str
/// [`Deref`]: core::ops::Deref
/// [`as_str()`]: String::as_str
#[derive(PartialOrd, Eq, Ord)]
///
///
/// However there is one case where `!` syntax can be used
-/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
+/// before `!` is stabilized as a full-fledged type: in the position of a function’s return type.
/// Specifically, it is possible implementations for two different function pointer types:
///
/// ```
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
-/// hashing. This lets you key your hashtables from a strong RNG, such as
+/// hashing. This lets you key your hash tables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
-//! without T-lang consulation, because it bakes a feature into the language that cannot be
+//! without T-lang consultation, because it bakes a feature into the language that cannot be
//! replicated in user code without compiler support.
//!
//! # Volatiles
/// [`std::mem::align_of`](../../std/mem/fn.align_of.html).
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
pub fn min_align_of<T>() -> usize;
- /// The prefered alignment of a type.
+ /// The preferred alignment of a type.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_pref_align_of", issue = "none")]
/// assert!(mid <= len);
/// unsafe {
/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
- /// // first: transmute is not typesafe; all it checks is that T and
+ /// // first: transmute is not type safe; all it checks is that T and
/// // U are of the same size. Second, right here, you have two
/// // mutable references pointing to the same memory.
/// (&mut slice[0..mid], &mut slice2[mid..len])
/// }
/// }
///
- /// // This gets rid of the typesafety problems; `&mut *` will *only* give
+ /// // This gets rid of the type safety problems; `&mut *` will *only* give
/// // you an `&mut T` from an `&mut T` or `*mut T`.
/// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
/// -> (&mut [T], &mut [T]) {
/// let vec = iter.collect::<Vec<_>>();
///
/// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
- /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
+ /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` encountered.
/// assert_eq!(vec, vec![0, 1, 2]);
/// ```
///
};
}
- /// Includes a utf8-encoded file as a string.
+ /// Includes a UTF-8 encoded file as a string.
///
/// The file is located relative to the current file (similarly to how
/// modules are found). The provided path is interpreted in a platform-specific
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
-/// - a [slice], then the length of the slice tail must be an intialized
+/// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - a [trait object], then the vtable part of the pointer must point
-/// to a valid vtable acquired by an unsizing coersion, and the size
+/// to a valid vtable acquired by an unsizing coercion, and the size
/// of the *entire value* (dynamic tail length + statically sized prefix)
/// must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
-/// - a [slice], then the length of the slice tail must be an intialized
+/// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - a [trait object], then the vtable part of the pointer must point
-/// to a valid vtable acquired by an unsizing coersion, and the size
+/// to a valid vtable acquired by an unsizing coercion, and the size
/// of the *entire value* (dynamic tail length + statically sized prefix)
/// must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
///
/// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
+ /// implementation favors preserving the exact bits. This means that
/// any payloads encoded in NaNs will be preserved even if the result of
/// this method is sent over the network from an x86 machine to a MIPS one.
///
///
/// If the input isn't NaN, then there is no portability concern.
///
- /// If you don't care about signalingness (very likely), then there is no
+ /// If you don't care about signaling-ness (very likely), then there is no
/// portability concern.
///
/// Note that this function is distinct from `as` casting, which attempts to
//!
//! Crucially, we have to be able to rely on [`drop`] being called. If an element
//! could be deallocated or otherwise invalidated without calling [`drop`], the pointers into it
-//! from its neighbouring elements would become invalid, which would break the data structure.
+//! from its neighboring elements would become invalid, which would break the data structure.
//!
//! Therefore, pinning also comes with a [`drop`]-related guarantee.
//!
intrinsics::ptr_guaranteed_eq(self, other)
}
- /// Returns whether two pointers are guaranteed to be inequal.
+ /// Returns whether two pointers are guaranteed to be unequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be inequal.
- /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ /// spuriously return `false` for pointers that later actually turn out to be unequal.
+ /// But when it returns `true`, the pointers are guaranteed to be unequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
/// operation because the returned value could be pointing to invalid
/// memory.
///
- /// When calling this method, you have to ensure that if the pointer is
- /// non-NULL, then it is properly aligned, dereferenceable (for the whole
- /// size of `T`) and points to an initialized instance of `T`. This applies
- /// even if the result of this method is unused!
+ /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// all of the following is true:
+ /// - it is properly aligned
+ /// - it must point to an initialized instance of T; in particular, the pointer must be
+ /// "dereferencable" in the sense defined [here].
+ ///
+ /// This applies even if the result of this method is unused!
/// (The part about being initialized is not yet fully decided, but until
/// it is, the only safe approach is to ensure that they are indeed initialized.)
///
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
- /// not necessarily reflect the actual lifetime of the data. It is up to the
- /// caller to ensure that for the duration of this lifetime, the memory this
- /// pointer points to does not get written to outside of `UnsafeCell<U>`.
+ /// not necessarily reflect the actual lifetime of the data. *You* must enforce
+ /// Rust's aliasing rules. In particular, for the duration of this lifetime,
+ /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
+ ///
+ /// [here]: crate::ptr#safety
///
/// # Examples
///
intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
}
- /// Returns whether two pointers are guaranteed to be inequal.
+ /// Returns whether two pointers are guaranteed to be unequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be inequal.
- /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ /// spuriously return `false` for pointers that later actually turn out to be unequal.
+ /// But when it returns `true`, the pointers are guaranteed to be unequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
/// assert_eq!(unsafe { slice.as_ref()[2] }, 7);
/// ```
///
- /// (Note that this example artifically demonstrates a use of this method,
+ /// (Note that this example artificially demonstrates a use of this method,
/// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
#[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
#[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
[package]
authors = ["The Rust Project Developers"]
-build = "build.rs"
name = "profiler_builtins"
version = "0.0.0"
edition = "2018"
let target = env::var("TARGET").expect("TARGET was not set");
let cfg = &mut cc::Build::new();
+ // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
+ // will not rerun on changes in these source files or headers included into them.
let mut profile_sources = vec![
"GCDAProfiling.c",
"InstrProfiling.c",
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
- println!("cargo:rerun-if-env-changed=CFG_DISABLE_UNSTABLE_FEATURES");
-}
fn visit_generics(&mut self, generics: &'a Generics) {
let mut prev_ty_default = None;
for param in &generics.params {
- if let GenericParamKind::Type { ref default, .. } = param.kind {
- if default.is_some() {
+ match param.kind {
+ GenericParamKind::Lifetime => (),
+ GenericParamKind::Type { default: Some(_), .. } => {
prev_ty_default = Some(param.ident.span);
- } else if let Some(span) = prev_ty_default {
- self.err_handler()
- .span_err(span, "type parameters with a default must be trailing");
- break;
+ }
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ if let Some(span) = prev_ty_default {
+ let mut err = self.err_handler().struct_span_err(
+ span,
+ "type parameters with a default must be trailing",
+ );
+ if matches!(param.kind, GenericParamKind::Const { .. }) {
+ err.note(
+ "using type defaults and const parameters \
+ in the same parameter list is currently not permitted",
+ );
+ }
+ err.emit();
+ break;
+ }
}
}
}
name = "rustc_attr"
version = "0.0.0"
edition = "2018"
-build = "build.rs"
[lib]
name = "rustc_attr"
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
///
/// - `#[stable]`
/// - `#[unstable]`
-/// - `#[rustc_deprecated]`
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
- pub rustc_depr: Option<RustcDeprecation>,
}
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
}
}
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
-pub struct RustcDeprecation {
- pub since: Symbol,
- pub reason: Symbol,
- /// A text snippet used to completely replace any use of the deprecated item in an expression.
- pub suggestion: Option<Symbol>,
-}
-
/// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
/// This will not perform any "sanity checks" on the form of the attributes.
pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
use StabilityLevel::*;
let mut stab: Option<Stability> = None;
- let mut rustc_depr: Option<RustcDeprecation> = None;
let mut const_stab: Option<ConstStability> = None;
let mut promotable = false;
let mut allow_const_fn_ptr = false;
'outer: for attr in attrs_iter {
if ![
- sym::rustc_deprecated,
sym::rustc_const_unstable,
sym::rustc_const_stable,
sym::unstable,
}
};
- macro_rules! get_meta {
- ($($name:ident),+) => {
- $(
- let mut $name = None;
- )+
- for meta in metas {
- if let Some(mi) = meta.meta_item() {
- match mi.name_or_empty() {
- $(
- sym::$name => if !get(mi, &mut $name) { continue 'outer },
- )+
- _ => {
- let expected = &[ $( stringify!($name) ),+ ];
- handle_errors(
- sess,
- mi.span,
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- expected,
- ),
- );
- continue 'outer
- }
- }
- } else {
- handle_errors(
- sess,
- meta.span(),
- AttrError::UnsupportedLiteral(
- "unsupported literal",
- false,
- ),
- );
- continue 'outer
- }
- }
- }
- }
-
let meta_name = meta.name_or_empty();
match meta_name {
- sym::rustc_deprecated => {
- if rustc_depr.is_some() {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0540,
- "multiple rustc_deprecated attributes"
- )
- .emit();
- continue 'outer;
- }
-
- get_meta!(since, reason, suggestion);
-
- match (since, reason) {
- (Some(since), Some(reason)) => {
- rustc_depr = Some(RustcDeprecation { since, reason, suggestion })
- }
- (None, _) => {
- handle_errors(sess, attr.span, AttrError::MissingSince);
- continue;
- }
- _ => {
- struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'")
- .emit();
- continue;
- }
- }
- }
sym::rustc_const_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
(Some(feature), reason, Some(_)) => {
let level = Unstable { reason, issue: issue_num, is_soft };
if sym::unstable == meta_name {
- stab = Some(Stability { level, feature, rustc_depr: None });
+ stab = Some(Stability { level, feature });
} else {
const_stab = Some(ConstStability {
level,
(Some(feature), Some(since)) => {
let level = Stable { since };
if sym::stable == meta_name {
- stab = Some(Stability { level, feature, rustc_depr: None });
+ stab = Some(Stability { level, feature });
} else {
const_stab = Some(ConstStability {
level,
}
}
- // Merge the deprecation info into the stability info
- if let Some(rustc_depr) = rustc_depr {
- if let Some(ref mut stab) = stab {
- stab.rustc_depr = Some(rustc_depr);
- } else {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0549,
- "rustc_deprecated attribute must be paired with \
- either stable or unstable attribute"
- )
- .emit();
- }
- }
-
// Merge the const-unstable info into the stability info
if promotable || allow_const_fn_ptr {
if let Some(ref mut stab) = const_stab {
#[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
pub struct Deprecation {
pub since: Option<Symbol>,
+ /// The note to issue a reason.
pub note: Option<Symbol>,
+ /// A text snippet used to completely replace any use of the deprecated item in an expression.
+ ///
+ /// This is currently unstable.
+ pub suggestion: Option<Symbol>,
+
+ /// Whether to treat the since attribute as being a Rust version identifier
+ /// (rather than an opaque string).
+ pub is_since_rustc_version: bool,
}
/// Finds the deprecation attribute. `None` if none exists.
let diagnostic = &sess.span_diagnostic;
'outer: for attr in attrs_iter {
- if !attr.check_name(sym::deprecated) {
+ if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
continue;
}
Some(meta) => meta,
None => continue,
};
- depr = match &meta.kind {
- MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
- MetaItemKind::NameValue(..) => {
- meta.value_str().map(|note| Deprecation { since: None, note: Some(note) })
- }
+ let mut since = None;
+ let mut note = None;
+ let mut suggestion = None;
+ match &meta.kind {
+ MetaItemKind::Word => {}
+ MetaItemKind::NameValue(..) => note = meta.value_str(),
MetaItemKind::List(list) => {
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
}
};
- let mut since = None;
- let mut note = None;
for meta in list {
match meta {
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
continue 'outer;
}
}
- sym::note => {
+ sym::note if attr.check_name(sym::deprecated) => {
+ if !get(mi, &mut note) {
+ continue 'outer;
+ }
+ }
+ sym::reason if attr.check_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
+ sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
+ if !get(mi, &mut suggestion) {
+ continue 'outer;
+ }
+ }
_ => {
handle_errors(
sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
- &["since", "note"],
+ if attr.check_name(sym::deprecated) {
+ &["since", "note"]
+ } else {
+ &["since", "reason", "suggestion"]
+ },
),
);
continue 'outer;
}
}
}
+ }
+ }
+
+ if suggestion.is_some() && attr.check_name(sym::deprecated) {
+ unreachable!("only allowed on rustc_deprecated")
+ }
- Some(Deprecation { since, note })
+ if attr.check_name(sym::rustc_deprecated) {
+ if since.is_none() {
+ handle_errors(sess, attr.span, AttrError::MissingSince);
+ continue;
}
- };
+
+ if note.is_none() {
+ struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+ continue;
+ }
+ }
+
+ mark_used(&attr);
+
+ let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
+ depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
}
depr
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_PREFIX");
- println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT");
-}
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
}
- fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
+ pub(crate) fn phi(
+ &mut self,
+ ty: &'ll Type,
+ vals: &[&'ll Value],
+ bbs: &[&'ll BasicBlock],
+ ) -> &'ll Value {
assert_eq!(vals.len(), bbs.len());
let phi = unsafe { llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) };
unsafe {
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.target.options.is_like_msvc {
- match sess.opts.debugging_opts.control_flow_guard {
+ match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
ifn!("llvm.wasm.trunc.saturate.signed.i32.f64", fn(t_f64) -> t_i32);
ifn!("llvm.wasm.trunc.saturate.signed.i64.f32", fn(t_f32) -> t_i64);
ifn!("llvm.wasm.trunc.saturate.signed.i64.f64", fn(t_f64) -> t_i64);
+ ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
+ ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
+ ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64);
+ ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64);
+ ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32);
+ ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32);
+ ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64);
+ ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64);
ifn!("llvm.trap", fn() -> void);
ifn!("llvm.debugtrap", fn() -> void);
}
sym::float_to_int_unchecked => {
- if float_type_width(arg_tys[0]).is_none() {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
+ let float_width = match float_type_width(arg_tys[0]) {
+ Some(width) => width,
+ None => {
+ span_invalid_monomorphization_error(
+ tcx.sess,
+ span,
+ &format!(
+ "invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic float type, \
found `{}`",
- arg_tys[0]
- ),
- );
- return;
- }
- match int_type_width_signed(ret_ty, self.cx) {
- Some((width, signed)) => {
- if signed {
- self.fptosi(args[0].immediate(), self.cx.type_ix(width))
- } else {
- self.fptoui(args[0].immediate(), self.cx.type_ix(width))
- }
+ arg_tys[0]
+ ),
+ );
+ return;
}
+ };
+ let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
+ Some(pair) => pair,
None => {
span_invalid_monomorphization_error(
tcx.sess,
);
return;
}
+ };
+
+ // The LLVM backend can reorder and speculate `fptosi` and
+ // `fptoui`, so on WebAssembly the codegen for this instruction
+ // is quite heavyweight. To avoid this heavyweight codegen we
+ // instead use the raw wasm intrinsics which will lower to one
+ // instruction in WebAssembly (`iNN.trunc_fMM_{s,u}`). This one
+ // instruction will trap if the operand is out of bounds, but
+ // that's ok since this intrinsic is UB if the operands are out
+ // of bounds, so the behavior can be different on WebAssembly
+ // than other targets.
+ //
+ // Note, however, that when the `nontrapping-fptoint` feature is
+ // enabled in LLVM then LLVM will lower `fptosi` to
+ // `iNN.trunc_sat_fMM_{s,u}`, so if that's the case we don't
+ // bother with intrinsics.
+ let mut result = None;
+ if self.sess().target.target.arch == "wasm32"
+ && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
+ {
+ let name = match (width, float_width, signed) {
+ (32, 32, true) => Some("llvm.wasm.trunc.signed.i32.f32"),
+ (32, 64, true) => Some("llvm.wasm.trunc.signed.i32.f64"),
+ (64, 32, true) => Some("llvm.wasm.trunc.signed.i64.f32"),
+ (64, 64, true) => Some("llvm.wasm.trunc.signed.i64.f64"),
+ (32, 32, false) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
+ (32, 64, false) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
+ (64, 32, false) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
+ (64, 64, false) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
+ _ => None,
+ };
+ if let Some(name) = name {
+ let intrinsic = self.get_intrinsic(name);
+ result = Some(self.call(intrinsic, &[args[0].immediate()], None));
+ }
}
+ result.unwrap_or_else(|| {
+ if signed {
+ self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+ } else {
+ self.fptoui(args[0].immediate(), self.cx.type_ix(width))
+ }
+ })
}
sym::discriminant_value => {
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_codegen_ssa::mir::operand::OperandRef;
-use rustc_codegen_ssa::traits::{
- BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods,
+use rustc_codegen_ssa::{
+ common::IntPredicate,
+ traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods},
};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Ty;
}
}
+fn emit_aapcs_va_arg(
+ bx: &mut Builder<'a, 'll, 'tcx>,
+ list: OperandRef<'tcx, &'ll Value>,
+ target_ty: Ty<'tcx>,
+) -> &'ll Value {
+ // Implementation of the AAPCS64 calling convention for va_args see
+ // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
+ let va_list_addr = list.immediate();
+ let layout = bx.cx.layout_of(target_ty);
+
+ let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
+ let mut in_reg = bx.build_sibling_block("va_arg.in_reg");
+ let mut on_stack = bx.build_sibling_block("va_arg.on_stack");
+ let mut end = bx.build_sibling_block("va_arg.end");
+ let zero = bx.const_i32(0);
+ let offset_align = Align::from_bytes(4).unwrap();
+ assert!(&*bx.tcx().sess.target.target.target_endian == "little");
+
+ let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
+ let (reg_off, reg_top_index, slot_size) = if gr_type {
+ let gr_offs = bx.struct_gep(va_list_addr, 7);
+ let nreg = (layout.size.bytes() + 7) / 8;
+ (gr_offs, 3, nreg * 8)
+ } else {
+ let vr_off = bx.struct_gep(va_list_addr, 9);
+ let nreg = (layout.size.bytes() + 15) / 16;
+ (vr_off, 5, nreg * 16)
+ };
+
+ // if the offset >= 0 then the value will be on the stack
+ let mut reg_off_v = bx.load(reg_off, offset_align);
+ let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
+ bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb());
+
+ // The value at this point might be in a register, but there is a chance that
+ // it could be on the stack so we have to update the offset and then check
+ // the offset again.
+
+ if gr_type && layout.align.abi.bytes() > 8 {
+ reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15));
+ reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16));
+ }
+ let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32));
+
+ maybe_reg.store(new_reg_off_v, reg_off, offset_align);
+
+ // Check to see if we have overflowed the registers as a result of this.
+ // If we have then we need to use the stack for this value
+ let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
+ maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
+
+ let top = in_reg.struct_gep(va_list_addr, reg_top_index);
+ let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi);
+
+ // reg_value = *(@top + reg_off_v);
+ let top = in_reg.gep(top, &[reg_off_v]);
+ let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx)));
+ let reg_value = in_reg.load(top, layout.align.abi);
+ in_reg.br(&end.llbb());
+
+ // On Stack block
+ let stack_value =
+ emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
+ on_stack.br(&end.llbb());
+
+ let val = end.phi(
+ layout.immediate_llvm_type(bx),
+ &[reg_value, stack_value],
+ &[&in_reg.llbb(), &on_stack.llbb()],
+ );
+
+ *bx = end;
+ val
+}
+
pub(super) fn emit_va_arg(
bx: &mut Builder<'a, 'll, 'tcx>,
addr: OperandRef<'tcx, &'ll Value>,
("aarch64", _) if target.target_os == "ios" => {
emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
}
+ ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty),
// Windows x86_64
("x86_64", true) => {
let target_ty_size = bx.cx.size_of(target_ty).bytes();
}
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- cmd.add_eh_frame_header();
+ if sess.target.target.options.eh_frame_header {
+ cmd.add_eh_frame_header();
+ }
// NO-OPT-OUT, OBJECT-FILES-NO
if crt_objects_fallback {
}
// OBJECT-FILES-NO, AUDIT-ORDER
- if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled {
+ if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
cmd.control_flow_guard();
}
// Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
// so we just always add it.
fn add_eh_frame_header(&mut self) {
- if !self.sess.target.target.options.is_like_osx
- && !self.sess.target.target.options.is_like_windows
- && !self.sess.target.target.options.is_like_solaris
- && self.sess.target.target.target_os != "uefi"
- {
- self.linker_arg("--eh-frame-hdr");
- }
+ self.linker_arg("--eh-frame-hdr");
}
}
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_VER_DATE");
- println!("cargo:rerun-if-env-changed=CFG_VER_HASH");
-}
E0521, // borrowed data escapes outside of closure
E0523,
// E0526, // shuffle indices are not constant
- E0540, // multiple rustc_deprecated attributes
+// E0540, // multiple rustc_deprecated attributes
E0542, // missing 'since'
E0543, // missing 'reason'
E0544, // multiple stability levels
E0755, // `#[ffi_pure]` is only allowed on foreign functions
E0756, // `#[ffi_const]` is only allowed on foreign functions
E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+ E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
}
-`#[ffi_returns_twice]` was used on non-foreign function.
+`#[ffi_returns_twice]` was used on something other than a foreign function
+declaration.
Erroneous code example:
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254), None),
/// Allows the use of `if` and `match` in constants.
- (accepted, const_if_match, "1.45.0", Some(49146), None),
+ (accepted, const_if_match, "1.46.0", Some(49146), None),
/// Allows the use of `loop` and `while` in constants.
- (accepted, const_loop, "1.45.0", Some(52000), None),
+ (accepted, const_loop, "1.46.0", Some(52000), None),
/// Allows `#[track_caller]` to be used which provides
/// accurate caller location reporting during panic (RFC 2091).
(accepted, track_caller, "1.46.0", Some(47809), None),
NotAsync,
}
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(
+ Copy,
+ Clone,
+ PartialEq,
+ RustcEncodable,
+ RustcDecodable,
+ Debug,
+ HashStable_Generic,
+ Eq,
+ Hash
+)]
pub enum Defaultness {
Default { has_value: bool },
Final,
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
-}
use rustc_ast::ast;
use rustc_hir::def_id::DefId;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{IntType, UintType};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
};
debug!("generalize: for_universe = {:?}", for_universe);
+ debug!("generalize: trace = {:?}", self.trace);
let mut generalize = Generalizer {
infcx: self.infcx,
- span: self.trace.cause.span,
+ cause: &self.trace.cause,
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
for_universe,
ambient_variance,
infcx: &'cx InferCtxt<'cx, 'tcx>,
/// The span, used when creating new type variables and things.
- span: Span,
+ cause: &'cx ObligationCause<'tcx>,
/// The vid of the type variable that is in the process of being
/// instantiated; if we find this within the type we are folding,
// FIXME: This is non-ideal because we don't give a
// very descriptive origin for this region variable.
- Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
+ Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
}
fn consts(
infer::MiscVariable(_) => String::new(),
infer::PatternRegion(_) => " for pattern".to_string(),
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
- infer::Autoref(_) => " for autoref".to_string(),
+ infer::Autoref(_, _) => " for autoref".to_string(),
infer::Coercion(_) => " for automatic coercion".to_string(),
infer::LateBoundRegion(_, br, infer::FnCall) => {
format!(" for lifetime parameter {}in function call", br_string(br))
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
-use rustc_middle::ty::RegionKind;
+use crate::infer::{SubregionOrigin, TypeTrace};
+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{
+ self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,
+ TyKind,
+};
+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};
+use rustc_span::symbol::Ident;
+use rustc_span::{MultiSpan, Span};
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- /// Print the error message for lifetime errors when the return type is a static impl Trait.
+ /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
+ /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
- if let Some(RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- ref sub_origin,
- sub_r,
- ref sup_origin,
- sup_r,
- )) = self.error
- {
- debug!(
- "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
- var_origin, sub_origin, sub_r, sup_origin, sup_r
- );
- let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
- debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
- let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
- if fn_returns.is_empty() {
+ let tcx = self.tcx();
+ let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
+ RegionResolutionError::SubSupConflict(
+ _,
+ var_origin,
+ sub_origin,
+ sub_r,
+ sup_origin,
+ sup_r,
+ ) if **sub_r == RegionKind::ReStatic => {
+ (var_origin, sub_origin, sub_r, sup_origin, sup_r)
+ }
+ RegionResolutionError::ConcreteFailure(
+ SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
+ sub_r,
+ sup_r,
+ ) if **sub_r == RegionKind::ReStatic => {
+ // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
+ if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+ let param = self.find_param_with_region(sup_r, sub_r)?;
+ let lifetime = if sup_r.has_name() {
+ format!("lifetime `{}`", sup_r)
+ } else {
+ "an anonymous lifetime `'_`".to_string()
+ };
+ let mut err = struct_span_err!(
+ tcx.sess,
+ cause.span,
+ E0772,
+ "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+ requirement",
+ param
+ .param
+ .pat
+ .simple_ident()
+ .map(|s| format!("`{}`", s))
+ .unwrap_or_else(|| "`fn` parameter".to_string()),
+ lifetime,
+ ctxt.assoc_item.ident,
+ );
+ err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+ err.span_label(
+ cause.span,
+ &format!(
+ "...is captured and required to live as long as `'static` here \
+ because of an implicit lifetime bound on the {}",
+ match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer(id) =>
+ format!("`impl` of `{}`", tcx.def_path_str(id)),
+ AssocItemContainer::ImplContainer(_) =>
+ "inherent `impl`".to_string(),
+ },
+ ),
+ );
+ if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+ err.emit();
+ return Some(ErrorReported);
+ } else {
+ err.cancel();
+ }
+ }
return None;
}
- debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
- if *sub_r == RegionKind::ReStatic {
- let sp = var_origin.span();
- let return_sp = sub_origin.span();
- let param_info = self.find_param_with_region(sup_r, sub_r)?;
- let (lifetime_name, lifetime) = if sup_r.has_name() {
- (sup_r.to_string(), format!("lifetime `{}`", sup_r))
- } else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let mut err = struct_span_err!(
- self.tcx().sess,
- sp,
- E0759,
- "cannot infer an appropriate lifetime"
- );
+ _ => return None,
+ };
+ debug!(
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
+ );
+ let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+ debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+ let sp = var_origin.span();
+ let return_sp = sub_origin.span();
+ let param = self.find_param_with_region(sup_r, sub_r)?;
+ let (lifetime_name, lifetime) = if sup_r.has_name() {
+ (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+ } else {
+ ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+ };
+ let param_name = param
+ .param
+ .pat
+ .simple_ident()
+ .map(|s| format!("`{}`", s))
+ .unwrap_or_else(|| "`fn` parameter".to_string());
+ let mut err = struct_span_err!(
+ tcx.sess,
+ sp,
+ E0759,
+ "{} has {} but it needs to satisfy a `'static` lifetime requirement",
+ param_name,
+ lifetime,
+ );
+ err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+ debug!("try_report_static_impl_trait: param_info={:?}", param);
+
+ // We try to make the output have fewer overlapping spans if possible.
+ if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+ && sup_origin.span() != return_sp
+ {
+ // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+
+ // Customize the spans and labels depending on their relative order so
+ // that split sentences flow correctly.
+ if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+ // Avoid the following:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ---------^-
+ //
+ // and instead show:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ^
err.span_label(
- param_info.param_ty_span,
- &format!("this data with {}...", lifetime),
+ sup_origin.span(),
+ "...is captured here, requiring it to live as long as `'static`",
);
- debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+ } else {
+ err.span_label(sup_origin.span(), "...is captured here...");
+ if return_sp < sup_origin.span() {
+ err.span_note(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ } else {
+ err.span_label(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ }
+ }
+ } else {
+ err.span_label(
+ return_sp,
+ "...is captured and required to live as long as `'static` here",
+ );
+ }
+
+ let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
- // We try to make the output have fewer overlapping spans if possible.
- if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
- && sup_origin.span() != return_sp
+ let mut override_error_code = None;
+ if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {
+ if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+ // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
+ // `'static` lifetime when called as a method on a binding: `bar.qux()`.
+ if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+ override_error_code = Some(ctxt.assoc_item.ident);
+ }
+ }
+ }
+ if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
+ if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code {
+ // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
+ // lifetime as above, but called using a fully-qualified path to the method:
+ // `Foo::qux(bar)`.
+ let mut v = TraitObjectVisitor(vec![]);
+ v.visit_ty(param.param_ty);
+ if let Some((ident, self_ty)) =
+ self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..])
{
- // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
-
- // Customize the spans and labels depending on their relative order so
- // that split sentences flow correctly.
- if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
- // Avoid the following:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ---------^-
- //
- // and instead show:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ^
- err.span_label(
- sup_origin.span(),
- "...is captured here, requiring it to live as long as `'static`",
+ if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty)
+ {
+ override_error_code = Some(ident);
+ }
+ }
+ }
+ }
+ if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
+ // Provide a more targetted error code and description.
+ err.code(rustc_errors::error_code!(E0772));
+ err.set_primary_message(&format!(
+ "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+ requirement",
+ param_name, lifetime, ident,
+ ));
+ }
+
+ debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+ // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+ let consider = "consider changing the";
+ let declare = "to declare that the";
+ let arg = match param.param.pat.simple_ident() {
+ Some(simple_ident) => format!("argument `{}`", simple_ident),
+ None => "the argument".to_string(),
+ };
+ let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+ let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);
+ let captures = format!("captures data from {}", arg);
+ let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
+ let plus_lt = format!(" + {}", lifetime_name);
+ for fn_return in fn_returns {
+ if fn_return.span.desugaring_kind().is_some() {
+ // Skip `async` desugaring `impl Future`.
+ continue;
+ }
+ match fn_return.kind {
+ TyKind::OpaqueDef(item_id, _) => {
+ let item = tcx.hir().item(item_id.id);
+ let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+ opaque
+ } else {
+ err.emit();
+ return Some(ErrorReported);
+ };
+
+ if let Some(span) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ name: LifetimeName::Static,
+ span,
+ ..
+ }) => Some(*span),
+ _ => None,
+ })
+ .next()
+ {
+ err.span_suggestion_verbose(
+ span,
+ &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param.param_ty_span,
+ add_static_bound,
+ param.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
);
+ } else if let Some(_) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime { name, span, .. })
+ if name.ident().to_string() == lifetime_name =>
+ {
+ Some(*span)
+ }
+ _ => None,
+ })
+ .next()
+ {
} else {
- err.span_label(sup_origin.span(), "...is captured here...");
- if return_sp < sup_origin.span() {
- err.span_note(
- return_sp,
- "...and is required to live as long as `'static` here",
- );
- } else {
- err.span_label(
- return_sp,
- "...and is required to live as long as `'static` here",
- );
- }
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} `impl Trait` {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
}
- } else {
- err.span_label(
- return_sp,
- "...is captured and required to live as long as `'static` here",
- );
}
+ TyKind::TraitObject(_, lt) => match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} trait object {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ name if name.ident().to_string() != lifetime_name => {
+ // With this check we avoid suggesting redundant bounds. This
+ // would happen if there are nested impl/dyn traits and only
+ // one of them has the bound we'd suggest already there, like
+ // in `impl Foo<X = dyn Bar> + '_`.
+ err.span_suggestion_verbose(
+ lt.span,
+ &format!("{} trait object's {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param.param_ty_span,
+ add_static_bound,
+ param.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ }
+ err.emit();
+ Some(ErrorReported)
+ }
- // FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
- let arg = match param_info.param.pat.simple_ident() {
- Some(simple_ident) => format!("argument `{}`", simple_ident),
- None => "the argument".to_string(),
- };
- let explicit =
- format!("you can add an explicit `{}` lifetime bound", lifetime_name);
- let explicit_static =
- format!("explicit `'static` bound to the lifetime of {}", arg);
- let captures = format!("captures data from {}", arg);
- let add_static_bound =
- "alternatively, add an explicit `'static` bound to this reference";
- let plus_lt = format!(" + {}", lifetime_name);
- for fn_return in fn_returns {
- if fn_return.span.desugaring_kind().is_some() {
- // Skip `async` desugaring `impl Future`.
- continue;
+ fn get_impl_ident_and_self_ty_from_trait(
+ &self,
+ def_id: DefId,
+ trait_objects: &[DefId],
+ ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
+ let tcx = self.tcx();
+ match tcx.hir().get_if_local(def_id) {
+ Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {
+ match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {
+ Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {
+ Some((*ident, self_ty))
}
- match fn_return.kind {
- TyKind::OpaqueDef(item_id, _) => {
- let item = self.tcx().hir().item(item_id.id);
- let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
- opaque
- } else {
- err.emit();
- return Some(ErrorReported);
- };
-
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- name: LifetimeName::Static,
- span,
+ _ => None,
+ }
+ }
+ Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {
+ let parent_id = tcx.hir().get_parent_item(*hir_id);
+ match tcx.hir().find(parent_id) {
+ Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();
+ match tcx
+ .hir()
+ .trait_impls(trait_did)
+ .iter()
+ .filter_map(|impl_node| {
+ let impl_did = tcx.hir().local_def_id(*impl_node);
+ match tcx.hir().get_if_local(impl_did.to_def_id()) {
+ Some(Node::Item(Item {
+ kind: ItemKind::Impl { self_ty, .. },
..
- }) => Some(*span),
- _ => None,
- })
- .next()
- {
- err.span_suggestion_verbose(
- span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(_) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { name, span, .. })
- if name.ident().to_string() == lifetime_name =>
+ })) if trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut hir_v = HirTraitObjectVisitor(vec![], *did);
+ hir_v.visit_ty(self_ty);
+ !hir_v.0.is_empty()
+ }) =>
{
- Some(*span)
+ Some(self_ty)
}
_ => None,
- })
- .next()
- {
- } else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
+ }
+ })
+ .next()
+ {
+ Some(self_ty) => Some((*ident, self_ty)),
+ _ => None,
}
- TyKind::TraitObject(_, lt) => match lt.name {
- LifetimeName::ImplicitObjectLifetimeDefault => {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} trait object {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
- name if name.ident().to_string() != lifetime_name => {
- // With this check we avoid suggesting redundant bounds. This
- // would happen if there are nested impl/dyn traits and only
- // one of them has the bound we'd suggest already there, like
- // in `impl Foo<X = dyn Bar> + '_`.
- err.span_suggestion_verbose(
- lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- _ => {}
- },
- _ => {}
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }
+ }
+
+ /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
+ /// `'static` obligation. Suggest relaxing that implicit bound.
+ fn find_impl_on_dyn_trait(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ ty: Ty<'_>,
+ ctxt: &UnifyReceiverContext<'tcx>,
+ ) -> bool {
+ let tcx = self.tcx();
+
+ // Find the method being called.
+ let instance = match ty::Instance::resolve(
+ tcx,
+ ctxt.param_env,
+ ctxt.assoc_item.def_id,
+ self.infcx.resolve_vars_if_possible(&ctxt.substs),
+ ) {
+ Ok(Some(instance)) => instance,
+ _ => return false,
+ };
+
+ let mut v = TraitObjectVisitor(vec![]);
+ v.visit_ty(ty);
+
+ // Get the `Ident` of the method being called and the corresponding `impl` (to point at
+ // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
+ let (ident, self_ty) =
+ match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) {
+ Some((ident, self_ty)) => (ident, self_ty),
+ None => return false,
+ };
+
+ // Find the trait object types in the argument, so we point at *only* the trait object.
+ self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty)
+ }
+
+ fn suggest_constrain_dyn_trait_in_impl(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ found_dids: &[DefId],
+ ident: Ident,
+ self_ty: &hir::Ty<'_>,
+ ) -> bool {
+ let mut suggested = false;
+ for found_did in found_dids {
+ let mut hir_v = HirTraitObjectVisitor(vec![], *found_did);
+ hir_v.visit_ty(&self_ty);
+ for span in &hir_v.0 {
+ let mut multi_span: MultiSpan = vec![*span].into();
+ multi_span.push_span_label(
+ *span,
+ "this has an implicit `'static` lifetime requirement".to_string(),
+ );
+ multi_span.push_span_label(
+ ident.span,
+ "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+ );
+ err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "consider relaxing the implicit `'static` requirement",
+ " + '_".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ suggested = true;
+ }
+ }
+ suggested
+ }
+}
+
+/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
+struct TraitObjectVisitor(Vec<DefId>);
+
+impl TypeVisitor<'_> for TraitObjectVisitor {
+ fn visit_ty(&mut self, t: Ty<'_>) -> bool {
+ match t.kind {
+ ty::Dynamic(preds, RegionKind::ReStatic) => {
+ if let Some(def_id) = preds.principal_def_id() {
+ self.0.push(def_id);
+ }
+ false
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+}
+
+/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
+struct HirTraitObjectVisitor(Vec<Span>, DefId);
+
+impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
+ type Map = ErasedMap<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
+ match t.kind {
+ TyKind::TraitObject(
+ poly_trait_refs,
+ Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
+ ) => {
+ for ptr in poly_trait_refs {
+ if Some(self.1) == ptr.trait_ref.trait_def_id() {
+ self.0.push(ptr.span);
}
}
- err.emit();
- return Some(ErrorReported);
}
+ _ => {}
}
- None
+ walk_ty(self, t);
}
}
use rustc_middle::ty::{self, DefIdTree, Region, Ty};
use rustc_span::Span;
-// The struct contains the information about the anonymous region
-// we are searching for.
+/// Information about the anonymous region we are searching for.
#[derive(Debug)]
pub(super) struct AnonymousParamInfo<'tcx> {
- // the parameter corresponding to the anonymous region
+ /// The parameter corresponding to the anonymous region.
pub param: &'tcx hir::Param<'tcx>,
- // the type corresponding to the anonymopus region parameter
+ /// The type corresponding to the anonymous region parameter.
pub param_ty: Ty<'tcx>,
- // the ty::BoundRegion corresponding to the anonymous region
+ /// The ty::BoundRegion corresponding to the anonymous region.
pub bound_region: ty::BoundRegion,
- // param_ty_span contains span of parameter type
+ /// The `Span` of the parameter type.
pub param_ty_span: Span,
- // corresponds to id the argument is the first parameter
- // in the declaration
+ /// Signals that the argument is the first parameter in the declaration.
pub is_first: bool,
}
AddrOfRegion(Span),
/// Regions created as part of an autoref of a method receiver
- Autoref(Span),
+ Autoref(Span, ty::AssocItem),
/// Regions created as part of an automatic coercion
Coercion(Span),
impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
- MiscVariable(a) => a,
- PatternRegion(a) => a,
- AddrOfRegion(a) => a,
- Autoref(a) => a,
- Coercion(a) => a,
- EarlyBoundRegion(a, ..) => a,
- LateBoundRegion(a, ..) => a,
+ MiscVariable(a)
+ | PatternRegion(a)
+ | AddrOfRegion(a)
+ | Autoref(a, _)
+ | Coercion(a)
+ | EarlyBoundRegion(a, ..)
+ | LateBoundRegion(a, ..)
+ | UpvarRegion(_, a) => a,
BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
- UpvarRegion(_, a) => a,
NLL(..) => bug!("NLL variable used with `span`"),
}
}
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=RUSTC_INSTALL_BINDIR");
-}
// Make sure that changing a [TRACKED] option changes the hash.
// This list is in alphabetical order.
tracked!(code_model, Some(CodeModel::Large));
+ tracked!(control_flow_guard, CFGuard::Checks);
tracked!(debug_assertions, Some(true));
tracked!(debuginfo, 0xdeadbeef);
tracked!(embed_bitcode, false);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
- tracked!(control_flow_guard, CFGuard::Checks);
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
authors = ["The Rust Project Developers"]
name = "rustc_llvm"
version = "0.0.0"
-build = "build.rs"
edition = "2018"
[lib]
emscripten = []
[dependencies]
-libc = "0.2"
+libc = "0.2.73"
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0.1"
+cc = "1.0.58"
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::output;
+use build_helper::{output, tracked_env_var_os};
fn detect_llvm_link() -> (&'static str, &'static str) {
// Force the link mode we want, preferring static by default, but
// possibly overridden by `configure --enable-llvm-link-shared`.
- if env::var_os("LLVM_LINK_SHARED").is_some() {
+ if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
("dylib", "--link-shared")
} else {
("static", "--link-static")
}
fn main() {
- println!("cargo:rerun-if-env-changed=RUST_CHECK");
- if env::var_os("RUST_CHECK").is_some() {
+ if tracked_env_var_os("RUST_CHECK").is_some() {
// If we're just running `check`, there's no need for LLVM to be built.
return;
}
let target = env::var("TARGET").expect("TARGET was not set");
let llvm_config =
- env::var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
- if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
+ tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
+ if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
let to_test = dir
.parent()
.unwrap()
}
let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));
- println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-
// Test whether we're cross-compiling LLVM. This is a pretty rare case
// currently where we're producing an LLVM for a different platform than
// what this build script is currently running on.
cfg.define(&flag, None);
}
- println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
- if env::var_os("LLVM_RUSTLLVM").is_some() {
+ if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
cfg.define("LLVM_RUSTLLVM", None);
}
- if env::var_os("LLVM_NDEBUG").is_some() {
+ if tracked_env_var_os("LLVM_NDEBUG").is_some() {
cfg.define("NDEBUG", None);
cfg.debug(false);
}
// librustc_llvm, for example when using static libc++, we may need to
// manually specify the library search path and -ldl -lpthread as link
// dependencies.
- let llvm_linker_flags = env::var_os("LLVM_LINKER_FLAGS");
+ let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
if lib.starts_with("-l") {
}
}
- let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");
- let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX");
+ let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
+ let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");
let stdcppname = if target.contains("openbsd") {
if target.contains("sparc64") { "estdc++" } else { "c++" }
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
-}
+++ /dev/null
-use std::env;
-
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
- println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
- println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR");
-
- if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
- println!("cargo:rustc-cfg=always_verify_llvm_ir");
- }
-}
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(cmp_min_max_by)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(const_fn_transmute)]
use crate::ty::{self, TyCtxt};
use rustc_ast::ast::CRATE_NODE_ID;
-use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_feature::GateIssue;
/// Checks whether an item marked with `deprecated(since="X")` is currently
/// deprecated (i.e., whether X is not greater than the current rustc version).
-pub fn deprecation_in_effect(since: &str) -> bool {
+pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
+ let since = if let Some(since) = since {
+ if is_since_rustc_version {
+ since
+ } else {
+ // We assume that the deprecation is in effect if it's not a
+ // rustc version.
+ return true;
+ }
+ } else {
+ // If since attribute is not set, then we're definitely in effect.
+ return true;
+ };
fn parse_version(ver: &str) -> Vec<u32> {
// We ignore non-integer components of the version (e.g., "nightly").
ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
}
if let Some(rustc) = option_env!("CFG_RELEASE") {
- let since: Vec<u32> = parse_version(since);
+ let since: Vec<u32> = parse_version(&since);
let rustc: Vec<u32> = parse_version(rustc);
// We simply treat invalid `since` attributes as relating to a previous
// Rust version, thus always displaying the warning.
}
}
-fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
- match reason {
- Some(reason) => format!("{}: {}", message, reason),
- None => message,
- }
-}
-
pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
- let message = format!("use of deprecated item '{}'", path);
- (deprecation_message_common(message, depr.note), DEPRECATED)
-}
-
-pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
- let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
+ let (message, lint) = if deprecation_in_effect(
+ depr.is_since_rustc_version,
+ depr.since.map(Symbol::as_str).as_deref(),
+ ) {
(format!("use of deprecated item '{}'", path), DEPRECATED)
} else {
(
format!(
"use of item '{}' that will be deprecated in future version {}",
- path, depr.since
+ path,
+ depr.since.unwrap()
),
DEPRECATED_IN_FUTURE,
)
};
- (deprecation_message_common(message, Some(depr.reason)), lint)
+ let message = match depr.note {
+ Some(reason) => format!("{}: {}", message, reason),
+ None => message,
+ };
+ (message, lint)
}
pub fn early_report_deprecation(
.lookup_deprecation_entry(parent_def_id.to_def_id())
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
- if !skip {
+ // #[deprecated] doesn't emit a notice if we're not on the
+ // topmost deprecation. For example, if a struct is deprecated,
+ // the use of a field won't be linted.
+ //
+ // #[rustc_deprecated] however wants to emit down the whole
+ // hierarchy.
+ if !skip || depr_entry.attr.is_since_rustc_version {
let (message, lint) =
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
- late_report_deprecation(self, &message, None, lint, span, id);
+ late_report_deprecation(
+ self,
+ &message,
+ depr_entry.attr.suggestion,
+ lint,
+ span,
+ id,
+ );
}
};
}
def_id, span, stability
);
- if let Some(id) = id {
- if let Some(stability) = stability {
- if let Some(depr) = &stability.rustc_depr {
- let (message, lint) =
- rustc_deprecation_message(depr, &self.def_path_str(def_id));
- late_report_deprecation(self, &message, depr.suggestion, lint, span, id);
- }
- }
- }
-
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct UnifyReceiverContext<'tcx> {
+ pub assoc_item: ty::AssocItem,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub substs: SubstsRef<'tcx>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
/// Method receiver
MethodReceiver,
+ UnifyReceiver(Box<UnifyReceiverContext<'tcx>>),
+
/// `return` with no expression
ReturnNoExpression,
super::StartFunctionType => Some(super::StartFunctionType),
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
+ super::UnifyReceiver(ref ctxt) => tcx.lift(ctxt).map(|ctxt| super::UnifyReceiver(ctxt)),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
}
}
}
+impl<'a, 'tcx> Lift<'tcx> for traits::UnifyReceiverContext<'a> {
+ type Lifted = traits::UnifyReceiverContext<'tcx>;
+ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.param_env).and_then(|param_env| {
+ tcx.lift(&self.substs).map(|substs| traits::UnifyReceiverContext {
+ assoc_item: self.assoc_item,
+ param_env,
+ substs,
+ })
+ })
+ }
+}
+
impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
type Lifted = traits::DerivedObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
.iter_enumerated()
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
- let mut niche_filling_layout = None;
-
// Niche-filling enum optimization.
if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
let mut dataful_variant = None;
let largest_niche =
Niche::from_scalar(dl, offset, niche_scalar.clone());
- niche_filling_layout = Some(Layout {
+ return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
largest_niche,
size,
align,
- });
+ }));
}
}
}
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
- let tagged_layout = Layout {
+ tcx.intern_layout(Layout {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
abi,
align,
size,
- };
-
- let best_layout = match (tagged_layout, niche_filling_layout) {
- (tagged_layout, Some(niche_filling_layout)) => {
- // Pick the smaller layout; otherwise,
- // pick the layout with the larger niche; otherwise,
- // pick tagged as it has simpler codegen.
- cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
- let niche_size =
- layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
- (layout.size, cmp::Reverse(niche_size))
- })
- }
- (tagged_layout, None) => tagged_layout,
- };
-
- tcx.intern_layout(best_layout)
+ })
}
// Types with no meaningful known layout.
pub extern_prelude: FxHashMap<Symbol, bool>,
}
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)]
pub enum AssocItemContainer {
TraitContainer(DefId),
ImplContainer(DefId),
Reservation,
}
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
#[stable_hasher(project(name))]
pub fn_has_self_parameter: bool,
}
-#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
pub enum AssocKind {
Const,
Fn,
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
Public,
impl<T> WithOptConstParam<T> {
/// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+ #[inline(always)]
pub fn unknown(did: T) -> WithOptConstParam<T> {
WithOptConstParam { did, const_param_did: None }
}
}
impl WithOptConstParam<LocalDefId> {
+ /// Returns `Some((did, param_did))` if `def_id` is a const argument,
+ /// `None` otherwise.
+ #[inline(always)]
+ pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
+ tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
+ }
+
+ /// In case `self` is unknown but `self.did` is a const argument, this returns
+ /// a `WithOptConstParam` with the correct `const_param_did`.
+ #[inline(always)]
+ pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
+ if self.const_param_did.is_none() {
+ if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
+ return Some(WithOptConstParam { did: self.did, const_param_did });
+ }
+ }
+
+ None
+ }
+
pub fn to_global(self) -> WithOptConstParam<DefId> {
WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
}
pub fn provide(providers: &mut Providers) {
*providers = Providers {
- mir_borrowck: |tcx, did| mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)),
+ mir_borrowck: |tcx, did| {
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.mir_borrowck_const_arg(def)
+ } else {
+ mir_borrowck(tcx, ty::WithOptConstParam::unknown(did))
+ }
+ },
mir_borrowck_const_arg: |tcx, (did, param_did)| {
mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
},
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx BorrowCheckResult<'tcx> {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_borrowck_const_arg((def.did, param_did));
- }
- }
-
let (input_body, promoted) = tcx.mir_validated(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
};
use rustc_middle::ty;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
let name = tcx.item_name(def_id);
Ok(match name {
sym::type_name => {
+ if tp_ty.needs_subst() {
+ throw_inval!(TooGeneric);
+ }
let alloc = type_name::alloc_type_name(tcx, tp_ty);
ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
}
};
ConstValue::from_machine_usize(n, &tcx)
}
- sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)),
+ sym::type_id => {
+ if tp_ty.needs_subst() {
+ throw_inval!(TooGeneric);
+ }
+ ConstValue::from_u64(tcx.type_id_hash(tp_ty))
+ }
sym::variant_count => {
if let ty::Adt(ref adt, _) = tp_ty.kind {
ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
Ok(val) => collect_const_value(self.tcx, val, self.output),
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
Err(ErrorHandled::TooGeneric) => span_bug!(
- self.tcx.def_span(def.did),
- "collection encountered polymorphic constant",
+ self.body.source_info(location).span,
+ "collection encountered polymorphic constant: {}",
+ substituted_constant
),
}
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
unsafety_check_result: |tcx, def_id| {
- unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.unsafety_check_result_for_const_arg(def)
+ } else {
+ unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
unsafety_check_result(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx UnsafetyCheckResult {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.unsafety_check_result_for_const_arg((def.did, param_did));
- }
- }
-
debug!("unsafety_violations({:?})", def);
// N.B., this borrow is valid because all the consumers of
*providers = Providers {
mir_keys,
mir_const,
- mir_const_qualif: |tcx, did| {
- mir_const_qualif(tcx, ty::WithOptConstParam::unknown(did.expect_local()))
+ mir_const_qualif: |tcx, def_id| {
+ let def_id = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.mir_const_qualif_const_arg(def)
+ } else {
+ mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
mir_const_qualif_const_arg: |tcx, (did, param_did)| {
mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
optimized_mir_of_const_arg,
is_mir_available,
promoted_mir: |tcx, def_id| {
- promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id.expect_local()))
+ let def_id = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.promoted_mir_of_const_arg(def)
+ } else {
+ promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
promoted_mir_of_const_arg: |tcx, (did, param_did)| {
promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
}
fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_const_qualif_const_arg((def.did, param_did));
- }
- }
-
let const_kind = tcx.hir().body_const_context(def.did);
// No need to const-check a non-const `fn`.
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_const(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_const(def);
}
// Unsafety check uses the raw mir, so make sure it is run.
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_validated(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_validated(def);
}
// Ensure that we compute the `mir_const_qualif` for constants at
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam {
- const_param_did,
- ..def
- });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_drops_elaborated_and_const_checked(def);
}
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
let did = did.expect_local();
- if let Some(param_did) = tcx.opt_const_param_of(did) {
- tcx.optimized_mir_of_const_arg((did, param_did))
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.optimized_mir_of_const_arg(def)
} else {
tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
}
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.promoted_mir_of_const_arg((def.did, param_did));
- }
- }
-
if tcx.is_constructor(def.did.to_def_id()) {
return tcx.arena.alloc(IndexVec::new());
}
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx ty::steal::Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_built(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_built(def);
}
tcx.alloc_steal_mir(mir_build(tcx, def))
) where
F: FnOnce(&mut Self),
{
+ debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+ let mut did_error = false;
if !self.tcx.features().staged_api {
- self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
- return;
+ did_error = self.forbid_staged_api_attrs(hir_id, attrs);
}
- // This crate explicitly wants staged API.
+ let depr = if did_error {
+ None
+ } else {
+ attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
+ };
+ let mut is_deprecated = false;
+ if let Some(depr) = &depr {
+ is_deprecated = true;
- debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
- if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
- self.tcx.sess.span_err(
- item_sp,
- "`#[deprecated]` cannot be used in staged API; \
- use `#[rustc_deprecated]` instead",
+ if kind == AnnotationKind::Prohibited {
+ self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
+ }
+
+ // `Deprecation` is just two pointers, no need to intern it
+ let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
+ self.index.depr_map.insert(hir_id, depr_entry);
+ } else if let Some(parent_depr) = self.parent_depr.clone() {
+ is_deprecated = true;
+ info!("tagging child {:?} as deprecated from parent", hir_id);
+ self.index.depr_map.insert(hir_id, parent_depr);
+ }
+
+ if self.tcx.features().staged_api {
+ if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+ self.tcx.sess.span_err(
+ item_sp,
+ "`#[deprecated]` cannot be used in staged API; \
+ use `#[rustc_deprecated]` instead",
+ );
+ }
+ } else {
+ self.recurse_with_stability_attrs(
+ depr.map(|d| DeprecationEntry::local(d, hir_id)),
+ None,
+ None,
+ visit_children,
);
+ return;
}
let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
}
}
- let stab = stab.map(|mut stab| {
+ if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) {
+ if stab.is_none() {
+ struct_span_err!(
+ self.tcx.sess,
+ item_sp,
+ E0549,
+ "rustc_deprecated attribute must be paired with \
+ either stable or unstable attribute"
+ )
+ .emit();
+ }
+ }
+
+ let stab = stab.map(|stab| {
// Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited
- || (kind == AnnotationKind::Container
- && stab.level.is_stable()
- && stab.rustc_depr.is_none())
+ || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
{
self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
}
debug!("annotate: found {:?}", stab);
- // If parent is deprecated and we're not, inherit this by merging
- // deprecated_since and its reason.
- if let Some(parent_stab) = self.parent_stab {
- if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
- stab.rustc_depr = parent_stab.rustc_depr
- }
- }
-
let stab = self.tcx.intern_stability(stab);
// Check if deprecated_since < stable_since. If it is,
// this is *almost surely* an accident.
- if let (
- &Some(attr::RustcDeprecation { since: dep_since, .. }),
- &attr::Stable { since: stab_since },
- ) = (&stab.rustc_depr, &stab.level)
+ if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
+ (&depr.as_ref().and_then(|d| d.since), &stab.level)
{
// Explicit version of iter::order::lt to handle parse errors properly
for (dep_v, stab_v) in
}
}
- self.recurse_with_stability_attrs(stab, const_stab, visit_children);
+ self.recurse_with_stability_attrs(
+ depr.map(|d| DeprecationEntry::local(d, hir_id)),
+ stab,
+ const_stab,
+ visit_children,
+ );
}
fn recurse_with_stability_attrs(
&mut self,
+ depr: Option<DeprecationEntry>,
stab: Option<&'tcx Stability>,
const_stab: Option<&'tcx ConstStability>,
f: impl FnOnce(&mut Self),
) {
// These will be `Some` if this item changes the corresponding stability attribute.
+ let mut replaced_parent_depr = None;
let mut replaced_parent_stab = None;
let mut replaced_parent_const_stab = None;
+ if let Some(depr) = depr {
+ replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
+ }
if let Some(stab) = stab {
replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
}
f(self);
+ if let Some(orig_parent_depr) = replaced_parent_depr {
+ self.parent_depr = orig_parent_depr;
+ }
if let Some(orig_parent_stab) = replaced_parent_stab {
self.parent_stab = orig_parent_stab;
}
}
}
- fn forbid_staged_api_attrs(
- &mut self,
- hir_id: HirId,
- attrs: &[Attribute],
- item_sp: Span,
- kind: AnnotationKind,
- visit_children: impl FnOnce(&mut Self),
- ) {
+ // returns true if an error occurred, used to suppress some spurious errors
+ fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
// Emit errors for non-staged-api crates.
let unstable_attrs = [
sym::unstable,
sym::rustc_const_unstable,
sym::rustc_const_stable,
];
+ let mut has_error = false;
for attr in attrs {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
"stability attributes may not be used outside of the standard library",
)
.emit();
+ has_error = true;
}
}
}
}
- if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
- if kind == AnnotationKind::Prohibited {
- self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
- }
-
- // `Deprecation` is just two pointers, no need to intern it
- let depr_entry = DeprecationEntry::local(depr, hir_id);
- self.index.depr_map.insert(hir_id, depr_entry.clone());
-
- let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry));
- visit_children(self);
- self.parent_depr = orig_parent_depr;
- } else if let Some(parent_depr) = self.parent_depr.clone() {
- self.index.depr_map.insert(hir_id, parent_depr);
- visit_children(self);
- } else {
- visit_children(self);
- }
+ has_error
}
}
is_soft: false,
},
feature: sym::rustc_private,
- rustc_depr: None,
});
annotator.parent_stab = Some(stability);
}
);
}
}
- if let Some(depr) = &stability.rustc_depr {
- let path = pprust::path_to_string(path);
- let (message, lint) = stability::rustc_deprecation_message(depr, &path);
- stability::early_report_deprecation(
- &mut self.lint_buffer,
- &message,
- depr.suggestion,
- lint,
- span,
- );
- }
}
if let Some(depr) = &ext.deprecation {
let path = pprust::path_to_string(&path);
let (message, lint) = stability::deprecation_message(depr, &path);
- stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span);
+ stability::early_report_deprecation(
+ &mut self.lint_buffer,
+ &message,
+ depr.suggestion,
+ lint,
+ span,
+ );
}
}
Symbols,
}
-/// The different settings that the `-Z control-flow-guard` flag can have.
+/// The different settings that the `-C control-flow-guard` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CFGuard {
/// Do not emit Control Flow Guard metadata or checks.
"choose the code model to use (`rustc --print code-models` for details)"),
codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
+ control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
+ "use Windows Control Flow Guard (default: no)"),
debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
"explicitly enable the `cfg(debug_assertions)` directive"),
debuginfo: usize = (0, parse_uint, [TRACKED],
"enable the experimental Chalk-based trait solving engine"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
- control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
- "use Windows Control Flow Guard (default: no)"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
debug_macros: bool = (false, parse_bool, [TRACKED],
(default: PLT is disabled if full relro is enabled)"),
polonius: bool = (false, parse_bool, [UNTRACKED],
"enable polonius-based borrow-checker (default: no)"),
- polymorphize: bool = (true, parse_bool, [TRACKED],
+ polymorphize: bool = (false, parse_bool, [TRACKED],
"perform polymorphization analysis"),
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to prepend the linker invocation (can be used several times)"),
self.opts.debugging_opts.asm_comments
}
pub fn verify_llvm_ir(&self) -> bool {
- self.opts.debugging_opts.verify_llvm_ir || cfg!(always_verify_llvm_ir)
+ self.opts.debugging_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some()
}
pub fn borrowck_stats(&self) -> bool {
self.opts.debugging_opts.borrowck_stats
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_DEFAULT_LINKER");
-}
--- /dev/null
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::apple_base::opts();
+ base.cpu = "apple-a12".to_string();
+ base.max_atomic_width = Some(128);
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
+
+ base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
+
+ // Clang automatically chooses a more specific target based on
+ // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
+ // correctly, we do too.
+ let arch = "aarch64";
+ let llvm_target = super::apple_base::macos_llvm_target(&arch);
+
+ Ok(Target {
+ llvm_target,
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: arch.to_string(),
+ target_os: "macos".to_string(),
+ target_env: String::new(),
+ target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+ })
+}
has_elf_tls: version >= (10, 7),
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ eh_frame_header: false,
// This environment variable is pretty magical but is intended for
// producing deterministic builds. This was first discovered to be used
has_rpath: false,
pre_link_args: args,
position_independent_executables: false,
+ eh_frame_header: false,
..Default::default()
}
}
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
eliminate_frame_pointer: false,
+ eh_frame_header: false,
late_link_args,
// While we support ELF TLS, rust requires a way to register
("i686-unknown-haiku", i686_unknown_haiku),
("x86_64-unknown-haiku", x86_64_unknown_haiku),
+ ("aarch64-apple-darwin", aarch64_apple_darwin),
("x86_64-apple-darwin", x86_64_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
/// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
/// to false (uses .init_array).
pub use_ctors_section: bool,
+
+ /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header
+ /// used to locate unwinding information is passed
+ /// (only has effect if the linker is `ld`-like).
+ pub eh_frame_header: bool,
}
impl Default for TargetOptions {
relax_elf_relocations: false,
llvm_args: vec![],
use_ctors_section: false,
+ eh_frame_header: true,
}
}
}
key!(relax_elf_relocations, bool);
key!(llvm_args, list);
key!(use_ctors_section, bool);
+ key!(eh_frame_header, bool);
// NB: The old name is deprecated, but support for it is retained for
// compatibility.
target_option_val!(relax_elf_relocations);
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);
+ target_option_val!(eh_frame_header);
if default.unsupported_abis != self.options.unsupported_abis {
d.insert(
// See the thumb_base.rs file for an explanation of this value
emit_debug_gdb_scripts: false,
+ eh_frame_header: false,
+
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
code_model: Some(CodeModel::Medium),
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
code_model: Some(CodeModel::Medium),
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
target_family: Some("unix".to_string()),
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
+ eh_frame_header: false,
..Default::default()
}
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
requires_uwtable: true,
+ eh_frame_header: false,
..Default::default()
}
base.cpu = "core2".to_string();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.eliminate_frame_pointer = false;
- base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
+ base.pre_link_args.insert(
+ LinkerFlavor::Gcc,
+ vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
+ );
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
base.stack_probes = true;
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::{
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+ Unimplemented,
};
use rustc_errors::ErrorReported;
use rustc_middle::ty::fold::TypeFoldable;
);
return Err(ErrorReported);
}
+ Err(Unimplemented) => {
+ // This can trigger when we probe for the source of a `'static` lifetime requirement
+ // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+ infcx.tcx.sess.delay_span_bug(
+ rustc_span::DUMMY_SP,
+ &format!(
+ "Encountered error `Unimplemented` selecting `{:?}` during codegen",
+ trait_ref
+ ),
+ );
+ return Err(ErrorReported);
+ }
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between
/// the local type and the type parameter.
-/// 3. Every type parameter before the local key parameter is fully known in C.
-/// - e.g., `impl<T> T: Trait<LocalType>` is bad, because `T` might be
-/// an unknown type.
-/// - but `impl<T> LocalType: Trait<T>` is OK, because `LocalType`
-/// occurs before `T`.
+/// 3. Before this local type, no generic type parameter of the impl must
+/// be reachable through fundamental types.
+/// - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
+/// - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is
+/// reachable through the fundamental type `Box`.
/// 4. Every type in the local key parameter not known in C, going
/// through the parameter's type tree, must appear only as a subtree of
/// a type local to C, with only fundamental types between the type
ty: Ty<'tcx>,
in_crate: InCrate,
) -> Vec<Ty<'tcx>> {
- // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
- // or maybe if this should be calling `ty_is_non_local_constructor`.
- if ty_is_non_local(tcx, ty, in_crate).is_some() {
+ // FIXME: this is currently somewhat overly complicated,
+ // but fixing this requires a more complicated refactor.
+ if !contained_non_local_types(tcx, ty, in_crate).is_empty() {
if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
return inner_tys
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
.enumerate()
{
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
- let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
- if non_local_tys.is_none() {
+ let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate);
+ if non_local_tys.is_empty() {
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
return Ok(());
} else if let ty::Param(_) = input_ty.kind {
.substs
.types()
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
- .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none());
+ .find(|ty| ty_is_local_constructor(ty, in_crate));
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
}
- if let Some(non_local_tys) = non_local_tys {
- for input_ty in non_local_tys {
- non_local_spans.push((input_ty, i == 0));
- }
+
+ for input_ty in non_local_tys {
+ non_local_spans.push((input_ty, i == 0));
}
}
// If we exit above loop, never found a local type.
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
}
-fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
- match ty_is_non_local_constructor(ty, in_crate) {
- Some(ty) => {
- if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
- let tys: Vec<_> = inner_tys
- .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate))
- .flatten()
- .collect();
- if tys.is_empty() { None } else { Some(tys) }
- } else {
- Some(vec![ty])
+/// Returns a list of relevant non-local types for `ty`.
+///
+/// This is just `ty` itself unless `ty` is `#[fundamental]`,
+/// in which case we recursively look into this type.
+///
+/// If `ty` is local itself, this method returns an empty `Vec`.
+///
+/// # Examples
+///
+/// - `u32` is not local, so this returns `[u32]`.
+/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
+/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
+/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
+fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
+ if ty_is_local_constructor(ty, in_crate) {
+ Vec::new()
+ } else {
+ match fundamental_ty_inner_tys(tcx, ty) {
+ Some(inner_tys) => {
+ inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect()
}
+ None => vec![ty],
}
- None => None,
}
}
}
}
-// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
-fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> {
- debug!("ty_is_non_local_constructor({:?})", ty);
+fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+ debug!("ty_is_local_constructor({:?})", ty);
match ty.kind {
ty::Bool
| ty::Never
| ty::Tuple(..)
| ty::Param(..)
- | ty::Projection(..) => Some(ty),
+ | ty::Projection(..) => false,
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
- InCrate::Local => Some(ty),
+ InCrate::Local => false,
// The inference variable might be unified with a local
// type in that remote crate.
- InCrate::Remote => None,
+ InCrate::Remote => true,
},
- ty::Adt(def, _) => {
- if def_id_is_local(def.did, in_crate) {
- None
- } else {
- Some(ty)
- }
- }
- ty::Foreign(did) => {
- if def_id_is_local(did, in_crate) {
- None
- } else {
- Some(ty)
- }
- }
+ ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
+ ty::Foreign(did) => def_id_is_local(did, in_crate),
ty::Opaque(..) => {
// This merits some explanation.
// Normally, opaque types are not involed when performing
// the underlying type *within the same crate*. When an
// opaque type is used from outside the module
// where it is declared, it should be impossible to observe
- // anyything about it other than the traits that it implements.
+ // anything about it other than the traits that it implements.
//
// The alternative would be to look at the underlying type
// to determine whether or not the opaque type itself should
// to a remote type. This would violate the rule that opaque
// types should be completely opaque apart from the traits
// that they implement, so we don't use this behavior.
- Some(ty)
+ false
}
ty::Dynamic(ref tt, ..) => {
if let Some(principal) = tt.principal() {
- if def_id_is_local(principal.def_id(), in_crate) { None } else { Some(ty) }
+ def_id_is_local(principal.def_id(), in_crate)
} else {
- Some(ty)
+ false
}
}
- ty::Error(_) => None,
+ ty::Error(_) => true,
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
| ObligationCauseCode::IntrinsicType
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
+ | ObligationCauseCode::UnifyReceiver(..)
| ObligationCauseCode::MiscObligation => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
use crate::hir::GenericArg;
use rustc_hir as hir;
use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
// signature (which is also done during probing).
let method_sig_rcvr =
self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]);
- self.unify_receivers(self_ty, method_sig_rcvr);
+ debug!(
+ "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
+ self_ty, method_sig_rcvr, method_sig, method_predicates
+ );
+ self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
let (method_sig, method_predicates) =
self.normalize_associated_types_in(self.span, &(method_sig, method_predicates));
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
if let Some(mutbl) = pick.autoref {
- let region = self.next_region_var(infer::Autoref(self.span));
+ let region = self.next_region_var(infer::Autoref(self.span, pick.item));
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
)
}
- fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
- match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
+ fn unify_receivers(
+ &mut self,
+ self_ty: Ty<'tcx>,
+ method_self_ty: Ty<'tcx>,
+ pick: &probe::Pick<'tcx>,
+ substs: SubstsRef<'tcx>,
+ ) {
+ debug!(
+ "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
+ self_ty, method_self_ty, self.span, pick
+ );
+ let cause = self.cause(
+ self.span,
+ ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
+ assoc_item: pick.item,
+ param_env: self.param_env,
+ substs,
+ })),
+ );
+ match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
/// opaque type.
opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
- /// Each type parameter has an implicit region bound that
- /// indicates it must outlive at least the function body (the user
- /// may specify stronger requirements). This field indicates the
- /// region of the callee. If it is `None`, then the parameter
- /// environment is for an item or something where the "callee" is
- /// not clear.
- implicit_region_bound: Option<ty::Region<'tcx>>,
-
body_id: Option<hir::BodyId>,
}
deferred_generator_interiors: RefCell::new(Vec::new()),
opaque_types: RefCell::new(Default::default()),
opaque_types_vars: RefCell::new(Default::default()),
- implicit_region_bound: None,
body_id,
}
}
fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
self.infcx.process_registered_region_obligations(
self.outlives_environment.region_bound_pairs_map(),
- self.implicit_region_bound,
+ Some(self.tcx.lifetimes.re_root_empty),
self.param_env,
);
placeholder_type_error(tcx, None, &[], visitor.0, false);
}
- hir::TraitItemKind::Type(_, None) => {}
+ hir::TraitItemKind::Type(_, None) => {
+ // #74612: Visit and try to find bad placeholders
+ // even if there is no concrete type.
+ let mut visitor = PlaceholderHirTyCollector::default();
+ visitor.visit_trait_item(trait_item);
+ placeholder_type_error(tcx, None, &[], visitor.0, false);
+ }
};
tcx.ensure().predicates_of(def_id);
attr::Stable { ref since } => since.to_string(),
_ => String::new(),
},
- deprecation: self.rustc_depr.as_ref().map(|d| Deprecation {
- note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
- since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
- }),
unstable_reason: match self.level {
attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
_ => None,
Deprecation {
since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
+ is_since_rustc_version: self.is_since_rustc_version,
}
}
}
classes.push("unstable");
}
- if s.deprecation.is_some() {
+ // FIXME: what about non-staged API items that are deprecated?
+ if self.deprecation.is_some() {
classes.push("deprecated");
}
ItemType::from(self)
}
- /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
- ///
- /// If the item is not deprecated, returns `None`.
- pub fn deprecation(&self) -> Option<&Deprecation> {
- self.deprecation
- .as_ref()
- .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
- }
pub fn is_default(&self) -> bool {
match self.inner {
ItemEnum::MethodItem(ref meth) => {
pub level: stability::StabilityLevel,
pub feature: Option<String>,
pub since: String,
- pub deprecation: Option<Deprecation>,
pub unstable_reason: Option<String>,
pub issue: Option<NonZeroU32>,
}
pub struct Deprecation {
pub since: Option<String>,
pub note: Option<String>,
+ pub is_since_rustc_version: bool,
}
/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
}
// The trailing space after each tag is to space it properly against the rest of the docs.
- if item.deprecation().is_some() {
+ if let Some(depr) = &item.deprecation {
let mut message = "Deprecated";
- if let Some(ref stab) = item.stability {
- if let Some(ref depr) = stab.deprecation {
- if let Some(ref since) = depr.since {
- if !stability::deprecation_in_effect(&since) {
- message = "Deprecation planned";
- }
- }
- }
+ if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
+ message = "Deprecation planned";
}
tags += &tag_html("deprecated", message);
}
let mut stability = vec![];
let error_codes = cx.shared.codes;
- if let Some(Deprecation { note, since }) = &item.deprecation() {
+ if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation {
// We display deprecation messages for #[deprecated] and #[rustc_deprecated]
// but only display the future-deprecation messages for #[rustc_deprecated].
let mut message = if let Some(since) = since {
- format!("Deprecated since {}", Escape(since))
+ if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
+ format!("Deprecating in {}", Escape(&since))
+ } else {
+ format!("Deprecated since {}", Escape(&since))
+ }
} else {
String::from("Deprecated")
};
- if let Some(ref stab) = item.stability {
- if let Some(ref depr) = stab.deprecation {
- if let Some(ref since) = depr.since {
- if !stability::deprecation_in_effect(&since) {
- message = format!("Deprecating in {}", Escape(&since));
- }
- }
- }
- }
if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
/* Media Queries */
+@media (min-width: 701px) {
+ /* In case there is no documentation before a code block, we need to add some margin at the top
+ to prevent an overlay between the "collapse toggle" and the information tooltip.
+ However, it's needed needed with smaller screen width because the doc/code block is always put
+ "one line" below. */
+ .information:first-child > .tooltip {
+ margin-top: 16px;
+ }
+}
+
@media (max-width: 700px) {
body {
padding-top: 0px;
background-color: #14191f;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #fff);
+}
+
/* Improve the scrollbar display on firefox */
* {
scrollbar-color: #5c6773 transparent;
:target > code, :target > .in-band {
background: rgba(255, 236, 164, 0.06);
- border-right: 3px solid #ffb44c;
+ border-right: 3px solid rgba(255, 180, 76, 0.85);
}
pre.compile_fail {
background-color: #505050;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #fff);
+}
+
/* Improve the scrollbar display on firefox */
* {
scrollbar-color: rgb(64, 65, 67) #717171;
:target > code, :target > .in-band {
background-color: #494a3d;
+ border-right: 3px solid #bb7410;
}
pre.compile_fail {
scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #aaa);
+}
+
/* Improve the scrollbar display on webkit-based browsers */
::-webkit-scrollbar-track {
background-color: #ecebeb;
:target > code, :target > .in-band {
background: #FDFFD3;
+ border-right: 3px solid #ffb44c;
}
pre.compile_fail {
use rustc_ast::ast;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_expand::base::SyntaxExtensionKind;
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
enum ErrorKind {
ResolutionFailure,
- AnchorFailure(&'static str),
+ AnchorFailure(AnchorFailure),
+}
+
+enum AnchorFailure {
+ MultipleAnchors,
+ Primitive,
+ Variant,
+ AssocConstant,
+ AssocType,
+ Field,
+ Method,
}
struct LinkCollector<'a, 'tcx> {
// Not a trait item; just return what we found.
Res::PrimTy(..) => {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((res, Some(path_str.to_owned())));
}
if disambiguator == Some("type") {
if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((prim, Some(path_str.to_owned())));
}
}
} else if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((prim, Some(path_str.to_owned())));
} else {
};
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn {
- "methods cannot be followed by anchors"
+ AnchorFailure::Method
} else {
- "associated constants cannot be followed by anchors"
+ AnchorFailure::AssocConstant
}))
} else {
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
} {
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if def.is_enum() {
- "enum variants cannot be followed by anchors"
+ AnchorFailure::Variant
} else {
- "struct fields cannot be followed by anchors"
+ AnchorFailure::Field
}))
} else {
Ok((
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const {
- "associated constants cannot be followed by anchors"
+ AnchorFailure::AssocConstant
} else if item.kind == ty::AssocKind::Type {
- "associated types cannot be followed by anchors"
+ AnchorFailure::AssocType
} else {
- "methods cannot be followed by anchors"
+ AnchorFailure::Method
}))
} else {
Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
let link = ori_link.replace("`", "");
let parts = link.split('#').collect::<Vec<_>>();
let (link, extra_fragment) = if parts.len() > 2 {
- build_diagnostic(
- cx,
- &item,
- &link,
- &dox,
- link_range,
- "has an issue with the link anchor.",
- "only one `#` is allowed in a link",
- None,
- );
+ anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors);
continue;
} else if parts.len() == 2 {
if parts[0].trim().is_empty() {
item.attrs.links.push((ori_link, None, fragment));
} else {
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
- if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
+
+ // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+ if let Some((src_id, dst_id)) = res
+ .opt_def_id()
+ .and_then(|def_id| def_id.as_local())
+ .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+ {
use rustc_hir::def_id::LOCAL_CRATE;
- let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
- if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
- && (item.visibility == Visibility::Public)
- && !self.cx.render_options.document_private
+ let hir_src = self.cx.tcx.hir().as_local_hir_id(src_id);
+ let hir_dst = self.cx.tcx.hir().as_local_hir_id(dst_id);
+
+ if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+ && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
{
- let item_name = item.name.as_deref().unwrap_or("<unknown>");
- let err_msg = format!(
- "public documentation for `{}` links to a private item",
- item_name
- );
- build_diagnostic(
- cx,
- &item,
- path_str,
- &dox,
- link_range,
- &err_msg,
- "this item is private",
- None,
- );
+ privacy_error(cx, &item, &path_str, &dox, link_range);
continue;
}
}
}
}
-fn build_diagnostic(
+/// Reports a diagnostic for an intra-doc link.
+///
+/// If no link range is provided, or the source span of the link cannot be determined, the span of
+/// the entire documentation block is used for the lint. If a range is provided but the span
+/// calculation fails, a note is added to the diagnostic pointing to the link in the markdown.
+///
+/// The `decorate` callback is invoked in all cases to allow further customization of the
+/// diagnostic before emission. If the span of the link was able to be determined, the second
+/// parameter of the callback will contain it, and the primary span of the diagnostic will be set
+/// to it.
+fn report_diagnostic(
cx: &DocContext<'_>,
+ msg: &str,
item: &Item,
- path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
- err_msg: &str,
- short_err_msg: &str,
- help_msg: Option<&str>,
+ decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>),
) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- info!("ignoring warning from parent crate: {}", err_msg);
+ info!("ignoring warning from parent crate: {}", msg);
return;
}
};
+
let attrs = &item.attrs;
let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
hir_id,
sp,
|lint| {
- let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg));
+ let mut diag = lint.build(msg);
+
+ let span = link_range
+ .as_ref()
+ .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs));
+
if let Some(link_range) = link_range {
- if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
- {
+ if let Some(sp) = span {
diag.set_span(sp);
- diag.span_label(sp, short_err_msg);
} else {
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah
// ^ ~~~~
found = link_range.len(),
));
}
- };
- if let Some(help_msg) = help_msg {
- diag.help(help_msg);
}
+
+ decorate(&mut diag, span);
+
diag.emit();
},
);
}
-/// Reports a resolution failure diagnostic.
-///
-/// If we cannot find the exact source span of the resolution failure, we use the span of the
-/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
-/// line containing the failure as a note as well.
fn resolution_failure(
cx: &DocContext<'_>,
item: &Item,
dox: &str,
link_range: Option<Range<usize>>,
) {
- build_diagnostic(
+ report_diagnostic(
cx,
+ &format!("unresolved link to `{}`", path_str),
item,
- path_str,
dox,
link_range,
- "cannot be resolved, ignoring it.",
- "cannot be resolved, ignoring",
- Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"),
+ |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "unresolved link");
+ }
+
+ diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
+ },
);
}
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
- msg: &str,
+ failure: AnchorFailure,
) {
- build_diagnostic(
- cx,
- item,
- path_str,
- dox,
- link_range,
- "has an issue with the link anchor.",
- msg,
- None,
- );
+ let msg = match failure {
+ AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str),
+ AnchorFailure::Primitive
+ | AnchorFailure::Variant
+ | AnchorFailure::AssocConstant
+ | AnchorFailure::AssocType
+ | AnchorFailure::Field
+ | AnchorFailure::Method => {
+ let kind = match failure {
+ AnchorFailure::Primitive => "primitive type",
+ AnchorFailure::Variant => "enum variant",
+ AnchorFailure::AssocConstant => "associated constant",
+ AnchorFailure::AssocType => "associated type",
+ AnchorFailure::Field => "struct field",
+ AnchorFailure::Method => "method",
+ AnchorFailure::MultipleAnchors => unreachable!("should be handled already"),
+ };
+
+ format!(
+ "`{}` contains an anchor, but links to {kind}s are already anchored",
+ path_str,
+ kind = kind
+ )
+ }
+ };
+
+ report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "contains invalid anchor");
+ }
+ });
}
fn ambiguity_error(
link_range: Option<Range<usize>>,
candidates: PerNS<Option<Res>>,
) {
- let hir_id = match cx.as_local_hir_id(item.def_id) {
- Some(hir_id) => hir_id,
- None => {
- // If non-local, no need to check anything.
- return;
+ let mut msg = format!("`{}` is ", path_str);
+
+ let candidates = [TypeNS, ValueNS, MacroNS]
+ .iter()
+ .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
+ .collect::<Vec<_>>();
+ match candidates.as_slice() {
+ [(first_def, _), (second_def, _)] => {
+ msg += &format!(
+ "both {} {} and {} {}",
+ first_def.article(),
+ first_def.descr(),
+ second_def.article(),
+ second_def.descr(),
+ );
}
- };
- let attrs = &item.attrs;
- let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
-
- cx.tcx.struct_span_lint_hir(
- lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- hir_id,
- sp,
- |lint| {
- let mut msg = format!("`{}` is ", path_str);
-
- let candidates = [TypeNS, ValueNS, MacroNS]
- .iter()
- .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
- .collect::<Vec<_>>();
- match candidates.as_slice() {
- [(first_def, _), (second_def, _)] => {
- msg += &format!(
- "both {} {} and {} {}",
- first_def.article(),
- first_def.descr(),
- second_def.article(),
- second_def.descr(),
- );
- }
- _ => {
- let mut candidates = candidates.iter().peekable();
- while let Some((res, _)) = candidates.next() {
- if candidates.peek().is_some() {
- msg += &format!("{} {}, ", res.article(), res.descr());
- } else {
- msg += &format!("and {} {}", res.article(), res.descr());
- }
- }
+ _ => {
+ let mut candidates = candidates.iter().peekable();
+ while let Some((res, _)) = candidates.next() {
+ if candidates.peek().is_some() {
+ msg += &format!("{} {}, ", res.article(), res.descr());
+ } else {
+ msg += &format!("and {} {}", res.article(), res.descr());
}
}
+ }
+ }
- let mut diag = lint.build(&msg);
-
- if let Some(link_range) = link_range {
- if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
- {
- diag.set_span(sp);
- diag.span_label(sp, "ambiguous link");
+ report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "ambiguous link");
- for (res, ns) in candidates {
- let (action, mut suggestion) = match res {
- Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
- ("add parentheses", format!("{}()", path_str))
- }
- Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
- ("add an exclamation mark", format!("{}!", path_str))
- }
- _ => {
- let type_ = match (res, ns) {
- (Res::Def(DefKind::Const, _), _) => "const",
- (Res::Def(DefKind::Static, _), _) => "static",
- (Res::Def(DefKind::Struct, _), _) => "struct",
- (Res::Def(DefKind::Enum, _), _) => "enum",
- (Res::Def(DefKind::Union, _), _) => "union",
- (Res::Def(DefKind::Trait, _), _) => "trait",
- (Res::Def(DefKind::Mod, _), _) => "module",
- (_, TypeNS) => "type",
- (_, ValueNS) => "value",
- (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => {
- "derive"
- }
- (_, MacroNS) => "macro",
- };
+ let link_range = link_range.expect("must have a link range if we have a span");
- // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
- ("prefix with the item type", format!("{}@{}", type_, path_str))
- }
+ for (res, ns) in candidates {
+ let (action, mut suggestion) = match res {
+ Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
+ ("add parentheses", format!("{}()", path_str))
+ }
+ Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
+ ("add an exclamation mark", format!("{}!", path_str))
+ }
+ _ => {
+ let type_ = match (res, ns) {
+ (Res::Def(DefKind::Const, _), _) => "const",
+ (Res::Def(DefKind::Static, _), _) => "static",
+ (Res::Def(DefKind::Struct, _), _) => "struct",
+ (Res::Def(DefKind::Enum, _), _) => "enum",
+ (Res::Def(DefKind::Union, _), _) => "union",
+ (Res::Def(DefKind::Trait, _), _) => "trait",
+ (Res::Def(DefKind::Mod, _), _) => "module",
+ (_, TypeNS) => "type",
+ (_, ValueNS) => "value",
+ (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive",
+ (_, MacroNS) => "macro",
};
- if dox.bytes().nth(link_range.start) == Some(b'`') {
- suggestion = format!("`{}`", suggestion);
- }
-
- diag.span_suggestion(
- sp,
- &format!("to link to the {}, {}", res.descr(), action),
- suggestion,
- Applicability::MaybeIncorrect,
- );
+ // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
+ ("prefix with the item type", format!("{}@{}", type_, path_str))
}
- } else {
- // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
- // ^ ~~~~
- // | link_range
- // last_new_line_offset
- let last_new_line_offset =
- dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
- let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+ };
- // Print the line containing the `link_range` and manually mark it with '^'s.
- diag.note(&format!(
- "the link appears in this line:\n\n{line}\n\
- {indicator: <before$}{indicator:^<found$}",
- line = line,
- indicator = "",
- before = link_range.start - last_new_line_offset,
- found = link_range.len(),
- ));
+ if dox.bytes().nth(link_range.start) == Some(b'`') {
+ suggestion = format!("`{}`", suggestion);
}
+
+ // FIXME: Create a version of this suggestion for when we don't have the span.
+ diag.span_suggestion(
+ sp,
+ &format!("to link to the {}, {}", res.descr(), action),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
}
- diag.emit();
- },
- );
+ }
+ });
+}
+
+fn privacy_error(
+ cx: &DocContext<'_>,
+ item: &Item,
+ path_str: &str,
+ dox: &str,
+ link_range: Option<Range<usize>>,
+) {
+ let item_name = item.name.as_deref().unwrap_or("<unknown>");
+ let msg =
+ format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
+
+ report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "this item is private");
+ }
+
+ let note_msg = if cx.render_options.document_private {
+ "this link resolves only because you passed `--document-private-items`, but will break without"
+ } else {
+ "this link will resolve properly if you pass `--document-private-items`"
+ };
+ diag.note(note_msg);
+ });
}
/// Given an enum variant's res, return the res of its enum and the associated fragment.
use rustc_middle::ty::DefIdTree;
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors"));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant));
}
let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
parent
authors = ["The Rust Project Developers"]
name = "std"
version = "0.0.0"
-build = "build.rs"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust Standard Library"
unwind = { path = "../libunwind" }
hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
-# Dependencies of the `backtrace` crate
-addr2line = { version = "0.13.0", optional = true, default-features = false }
-rustc-demangle = { version = "0.1.4", features = ['rustc-dep-of-std'] }
-miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
-[dependencies.object]
-version = "0.20"
-optional = true
-default-features = false
-features = ['read_core', 'elf', 'macho', 'pe']
+[dependencies.backtrace_rs]
+package = "backtrace"
+version = "0.3.46"
+default-features = false # without the libstd `backtrace` feature, stub out everything
+features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd
[dev-dependencies]
rand = "0.7"
[features]
backtrace = [
- "gimli-symbolize",
- 'addr2line/rustc-dep-of-std',
- 'object/rustc-dep-of-std',
- 'miniz_oxide/rustc-dep-of-std',
+ "backtrace_rs/dbghelp", # backtrace/symbolize on MSVC
+ "backtrace_rs/libbacktrace", # symbolize on most platforms
+ "backtrace_rs/libunwind", # backtrace on most platforms
+ "backtrace_rs/dladdr", # symbolize on platforms w/o libbacktrace
]
-gimli-symbolize = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.
-use crate::backtrace_rs::{self, BytesOrWideString};
use crate::env;
use crate::ffi::c_void;
use crate::fmt;
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
+use backtrace::BytesOrWideString;
+use backtrace_rs as backtrace;
/// A captured OS thread stack backtrace.
///
}
enum RawFrame {
- Actual(backtrace_rs::Frame),
+ Actual(backtrace::Frame),
#[cfg(test)]
Fake,
}
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{{ ")?;
- if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) {
+ if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
write!(fmt, "fn: \"{:#}\"", fn_name)?;
} else {
write!(fmt, "fn: <unknown>")?;
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
},
- backtrace_rs::PrintFmt::Short,
+ backtrace::PrintFmt::Short,
crate::env::current_dir().as_ref().ok(),
)
}
Backtrace::create(Backtrace::force_capture as usize)
}
+ /// Forcibly captures a disabled backtrace, regardless of environment
+ /// variable configuration.
+ pub const fn disabled() -> Backtrace {
+ Backtrace { inner: Inner::Disabled }
+ }
+
// Capture a backtrace which start just before the function addressed by
// `ip`
fn create(ip: usize) -> Backtrace {
let mut frames = Vec::new();
let mut actual_start = None;
unsafe {
- backtrace_rs::trace_unsynchronized(|frame| {
+ backtrace::trace_unsynchronized(|frame| {
frames.push(BacktraceFrame {
frame: RawFrame::Actual(frame.clone()),
symbols: Vec::new(),
let full = fmt.alternate();
let (frames, style) = if full {
- (&capture.frames[..], backtrace_rs::PrintFmt::Full)
+ (&capture.frames[..], backtrace::PrintFmt::Full)
} else {
- (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short)
+ (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
};
// When printing paths we try to strip the cwd if it exists, otherwise
output_filename(fmt, path, style, cwd.as_ref().ok())
};
- let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path);
+ let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
f.add_context()?;
for frame in frames {
let mut f = f.frame();
for symbol in frame.symbols.iter() {
f.print_raw(
frame.frame.ip(),
- symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)),
+ symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
symbol.filename.as_ref().map(|b| match b {
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
RawFrame::Fake => unimplemented!(),
};
unsafe {
- backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+ backtrace::resolve_frame_unsynchronized(frame, |symbol| {
symbols.push(BacktraceSymbol {
name: symbol.name().map(|m| m.as_bytes().to_vec()),
filename: symbol.filename_raw().map(|b| match b {
use std::env;
fn main() {
+ println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("linux") {
if target.contains("android") {
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
}
println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
- println!("cargo:rustc-cfg=backtrace_in_libstd");
}
assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
- // Check that NaNs roundtrip their bits regardless of signalingness
+ // Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
- // Check that NaNs roundtrip their bits regardless of signalingness
+ // Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
// compiler
pub mod rt;
-#[path = "../backtrace/src/lib.rs"]
-#[allow(dead_code, unused_attributes)]
-mod backtrace_rs;
-
// Pull in the `std_detect` crate directly into libstd. The contents of
// `std_detect` are in a different repository: rust-lang/stdarch.
//
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
- /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ /// Returns the "preferred" block size for efficient filesystem I/O.
///
/// # Examples
///
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
- /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ /// Returns the "preferred" block size for efficient filesystem I/O.
///
/// # Examples
///
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
let backtrace_env = if panic_count::get() >= 2 {
- RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
+ RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
} else {
backtrace::rust_backtrace_env()
};
///
/// let path = Path::new("foo.rs");
/// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
+ ///
+ /// let path = Path::new("foo.tar.gz");
+ /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
self.fd
}
- /// Extracts the actual filedescriptor without closing it.
+ /// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> Fd {
let fd = self.fd;
mem::forget(self);
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime_nsec(&self) -> i64;
- /// Returns the blocksize for filesystem I/O.
+ /// Returns the block size for filesystem I/O.
///
/// # Examples
///
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
- /// let blocksize = meta.blksize();
+ /// let block_size = meta.blksize();
/// Ok(())
/// }
/// ```
use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;
-use libc::{c_int, c_void, ssize_t};
+use libc::{c_int, c_void};
#[derive(Debug)]
pub struct FileDesc {
fd: c_int,
}
-fn max_len() -> usize {
- // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
- // with the man page quoting that if the count of bytes to read is
- // greater than `SSIZE_MAX` the result is "unspecified".
- //
- // On macOS, however, apparently the 64-bit libc is either buggy or
- // intentionally showing odd behavior by rejecting any read with a size
- // larger than or equal to INT_MAX. To handle both of these the read
- // size is capped on both platforms.
- if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize }
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+//
+// On macOS, however, apparently the 64-bit libc is either buggy or
+// intentionally showing odd behavior by rejecting any read with a size
+// larger than or equal to INT_MAX. To handle both of these the read
+// size is capped on both platforms.
+#[cfg(target_os = "macos")]
+const READ_LIMIT: usize = c_int::MAX as usize - 1;
+#[cfg(not(target_os = "macos"))]
+const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+ libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pread64(
self.fd,
buf.as_mut_ptr() as *mut c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+ libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pwrite64(
self.fd,
buf.as_ptr() as *const c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn duplicate(&self) -> io::Result<FileDesc> {
// We want to atomically duplicate this file descriptor and set the
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
- // flag, however, isn't supported on older Linux kernels (earlier than
- // 2.6.24).
- //
- // To detect this and ensure that CLOEXEC is still set, we
- // follow a strategy similar to musl [1] where if passing
- // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
- // supported (the third parameter, 0, is always valid), so we stop
- // trying that.
- //
- // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
- // resolve so we at least compile this.
- //
- // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
- #[cfg(any(target_os = "android", target_os = "haiku"))]
- use libc::F_DUPFD as F_DUPFD_CLOEXEC;
- #[cfg(not(any(target_os = "android", target_os = "haiku")))]
- use libc::F_DUPFD_CLOEXEC;
-
- let make_filedesc = |fd| {
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- Ok(fd)
- };
- static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android"));
- let fd = self.raw();
- if TRY_CLOEXEC.load(Ordering::Relaxed) {
- match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
- // We *still* call the `set_cloexec` method as apparently some
- // linux kernel at some point stopped setting CLOEXEC even
- // though it reported doing so on F_DUPFD_CLOEXEC.
- Ok(fd) => {
- return Ok(if cfg!(target_os = "linux") {
- make_filedesc(fd)?
- } else {
- FileDesc::new(fd)
- });
- }
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
- TRY_CLOEXEC.store(false, Ordering::Relaxed);
- }
- Err(e) => return Err(e),
- }
- }
- cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
+ // is a POSIX flag that was added to Linux in 2.6.24.
+ let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
+ Ok(FileDesc::new(fd))
}
}
// However, since this is a variadic function, C integer promotion rules mean that on
// the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
- let fd = FileDesc::new(fd);
-
- // Currently the standard library supports Linux 2.6.18 which did not
- // have the O_CLOEXEC flag (passed above). If we're running on an older
- // Linux kernel then the flag is just ignored by the OS. After we open
- // the first file, we check whether it has CLOEXEC set. If it doesn't,
- // we will explicitly ask for a CLOEXEC fd for every further file we
- // open, if it does, we will skip that step.
- //
- // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
- // that we support, so we only do this on Linux currently.
- #[cfg(target_os = "linux")]
- fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
- use crate::sync::atomic::{AtomicUsize, Ordering};
-
- const OPEN_CLOEXEC_UNKNOWN: usize = 0;
- const OPEN_CLOEXEC_SUPPORTED: usize = 1;
- const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
- static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
-
- let need_to_set;
- match OPEN_CLOEXEC.load(Ordering::Relaxed) {
- OPEN_CLOEXEC_UNKNOWN => {
- need_to_set = !fd.get_cloexec()?;
- OPEN_CLOEXEC.store(
- if need_to_set {
- OPEN_CLOEXEC_NOTSUPPORTED
- } else {
- OPEN_CLOEXEC_SUPPORTED
- },
- Ordering::Relaxed,
- );
- }
- OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
- OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
- _ => unreachable!(),
- }
- if need_to_set {
- fd.set_cloexec()?;
- }
- Ok(())
- }
-
- #[cfg(not(target_os = "linux"))]
- fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
- Ok(())
- }
-
- ensure_cloexec(&fd)?;
- Ok(File(fd))
+ Ok(File(FileDesc::new(fd)))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
unsafe {
- // On linux we first attempt to pass the SOCK_CLOEXEC flag to
- // atomically create the socket and set it as CLOEXEC. Support for
- // this option, however, was added in 2.6.27, and we still support
- // 2.6.18 as a kernel, so if the returned error is EINVAL we
- // fallthrough to the fallback.
- #[cfg(target_os = "linux")]
- {
- match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) {
- Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
- Err(e) => return Err(e),
- }
- }
-
- let fd = cvt(libc::socket(fam, ty, 0))?;
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- let socket = Socket(fd);
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ // On Linux we pass the SOCK_CLOEXEC flag to atomically create
+ // the socket and set it as CLOEXEC, added in 2.6.27.
+ let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
+ Ok(Socket(FileDesc::new(fd)))
+ } else {
+ let fd = cvt(libc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ let socket = Socket(fd);
- // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
- // flag to disable `SIGPIPE` emission on socket.
- #[cfg(target_vendor = "apple")]
- setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
+ // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
+ // flag to disable `SIGPIPE` emission on socket.
+ #[cfg(target_vendor = "apple")]
+ setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
- Ok(socket)
+ Ok(socket)
+ }
+ }
}
}
unsafe {
let mut fds = [0, 0];
- // Like above, see if we can set cloexec atomically
- #[cfg(target_os = "linux")]
- {
- match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
- Ok(_) => {
- return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
- }
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
- Err(e) => return Err(e),
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ // Like above, set cloexec atomically
+ cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
+ Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
+ } else {
+ cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+ let a = FileDesc::new(fds[0]);
+ let b = FileDesc::new(fds[1]);
+ a.set_cloexec()?;
+ b.set_cloexec()?;
+ Ok((Socket(a), Socket(b)))
}
}
-
- cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
- let a = FileDesc::new(fds[0]);
- let b = FileDesc::new(fds[1]);
- a.set_cloexec()?;
- b.set_cloexec()?;
- Ok((Socket(a), Socket(b)))
}
}
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
// Unfortunately the only known way right now to accept a socket and
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
- // Linux. This was added in 2.6.28, however, and because we support
- // 2.6.18 we must detect this support dynamically.
- #[cfg(target_os = "linux")]
- {
- syscall! {
- fn accept4(
- fd: c_int,
- addr: *mut sockaddr,
- addr_len: *mut socklen_t,
- flags: c_int
- ) -> c_int
- }
- let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) });
- match res {
- Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
- Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
- Err(e) => return Err(e),
+ // Linux. This was added in 2.6.28, glibc 2.10 and musl 0.9.5.
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ let fd = cvt_r(|| unsafe {
+ libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
+ })?;
+ Ok(Socket(FileDesc::new(fd)))
+ } else {
+ let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
}
}
-
- let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- Ok(Socket(fd))
}
pub fn duplicate(&self) -> io::Result<Socket> {
/// Sets the platform-specific value of errno
#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall!
+#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
}
use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::fd::FileDesc;
use crate::sys::{cvt, cvt_r};
-use libc::c_int;
-
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////
pub struct AnonPipe(FileDesc);
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
- syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
- static INVALID: AtomicBool = AtomicBool::new(false);
-
let mut fds = [0; 2];
- // Unfortunately the only known way right now to create atomically set the
- // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
- // 2.6.27, however, and because we support 2.6.18 we must detect this
- // support dynamically.
- if cfg!(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "redox"
- )) && !INVALID.load(Ordering::SeqCst)
- {
- // Note that despite calling a glibc function here we may still
- // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
- // emulate on older kernels, so if you happen to be running on
- // an older kernel you may see `pipe2` as a symbol but still not
- // see the syscall.
- match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
- Ok(_) => {
- return Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))));
- }
- Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
- INVALID.store(true, Ordering::SeqCst);
- }
- Err(e) => return Err(e),
+ // The only known way right now to create atomically set the CLOEXEC flag is
+ // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
+ // and musl 0.9.3, and some other targets also have it.
+ cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))] {
+ cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
+ Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+ } else {
+ cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+ let fd0 = FileDesc::new(fds[0]);
+ let fd1 = FileDesc::new(fds[1]);
+ fd0.set_cloexec()?;
+ fd1.set_cloexec()?;
+ Ok((AnonPipe(fd0), AnonPipe(fd1)))
}
}
- cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
-
- let fd0 = FileDesc::new(fds[0]);
- let fd1 = FileDesc::new(fds[1]);
- fd0.set_cloexec()?;
- fd1.set_cloexec()?;
- Ok((AnonPipe(fd0), AnonPipe(fd1)))
}
impl AnonPipe {
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).
+// There are a variety of `#[cfg]`s controlling which targets are involved in
+// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
+// that, we'll just allow that some unix targets don't use this module at all.
+#![allow(dead_code, unused_macros)]
+
use crate::ffi::CStr;
use crate::marker;
use crate::mem;
fd: c_int,
}
-fn max_len() -> usize {
- // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
- // with the man page quoting that if the count of bytes to read is
- // greater than `SSIZE_MAX` the result is "unspecified".
- <ssize_t>::MAX as usize
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+const READ_LIMIT: usize = ssize_t::MAX as usize;
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
self.fd
}
- /// Extracts the actual filedescriptor without closing it.
+ /// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> c_int {
let fd = self.fd;
mem::forget(self);
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+ libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pread(
self.fd,
buf.as_mut_ptr() as *mut c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+ libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pwrite(
self.fd,
buf.as_ptr() as *const c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
use crate::cmp::Ordering;
use crate::time::Duration;
-use ::core::hash::{Hash, Hasher};
+use core::hash::{Hash, Hasher};
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;
///
/// WASI has no fundamental capability to do this. All syscalls and operations
/// are relative to already-open file descriptors. The C library, however,
-/// manages a map of preopened file descriptors to their path, and then the C
+/// manages a map of pre-opened file descriptors to their path, and then the C
/// library provides an API to look at this. In other words, when you want to
/// open a path `p`, you have to find a previously opened file descriptor in a
/// global table and then see if `p` is relative to that file descriptor.
///
/// This function, if successful, will return two items:
///
-/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file
+/// * The first is a `ManuallyDrop<WasiFd>`. This represents a pre-opened file
/// descriptor which we don't have ownership of, but we can use. You shouldn't
/// actually drop the `fd`.
///
/// appropriate rights for performing `rights` actions.
///
/// Note that this can fail if `p` doesn't look like it can be opened relative
-/// to any preopened file descriptor.
+/// to any pre-opened file descriptor.
fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
let p = CString::new(p.as_os_str().as_bytes())?;
unsafe {
let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret);
if fd == -1 {
let msg = format!(
- "failed to find a preopened file descriptor \
+ "failed to find a pre-opened file descriptor \
through which {:?} could be opened",
p
);
-use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
use crate::borrow::Cow;
/// Common code for printing the backtrace in the same way across the different
/// supported platforms.
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;
+use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
+
/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;
authors = ["The Rust Project Developers"]
name = "unwind"
version = "0.0.0"
-build = "build.rs"
edition = "2018"
include = [
'/libunwind/*',
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
#![feature(start)]
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
#![deny(dead_code)]
#![feature(start)]
-// compile-flags:-Zprint-mono-items=lazy -Copt-level=1
+// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
// ignore-tidy-linelength
#![crate_type = "rlib"]
// revisions:x86_64 i686 arm
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
//[x86_64] compile-flags: --target x86_64-unknown-uefi
//[i686] compile-flags: --target i686-unknown-linux-musl
-// compile-flags: -Z control-flow-guard=checks
+// compile-flags: -C control-flow-guard=checks
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard=no
+// compile-flags: -C control-flow-guard=no
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard=nochecks
+// compile-flags: -C control-flow-guard=nochecks
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
// ignore-msvc
#![crate_type = "lib"]
-// min-llvm-version 8.0
+// min-llvm-version: 8.0
// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y
#![crate_type="lib"]
// unchecked intrinsics.
// compile-flags: -C opt-level=3
+// ignore-wasm32 the wasm target is tested in `wasm_casts_*`
#![crate_type = "lib"]
a as _
}
-
// CHECK-LABEL: @cast_f64_u64
#[no_mangle]
pub fn cast_f64_u64(a: f64) -> u64 {
a as _
}
-
-
// CHECK-LABEL: @cast_unchecked_f64_i64
#[no_mangle]
pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi double {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f64_i32
#[no_mangle]
pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi double {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_i64
#[no_mangle]
pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi float {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_i32
#[no_mangle]
pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi float {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
-
// CHECK-LABEL: @cast_unchecked_f64_u64
#[no_mangle]
pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui double {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f64_u32
#[no_mangle]
pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui double {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_u64
#[no_mangle]
pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui float {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_u32
#[no_mangle]
pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui float {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// This test does not passed with gdb < 8.0. See #53497.
-// min-gdb-version 8.0
+// min-gdb-version: 8.0
// compile-flags:-g
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
// The pretty printers being tested here require the patch from
// https://sourceware.org/bugzilla/show_bug.cgi?id=21763
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 7.7
+// min-gdb-version: 7.7
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize {
0
}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_int>() == 1);
+ continue_if!(ap.arg::<c_int>() == 2);
+ continue_if!(ap.arg::<c_int>() == 3);
+ continue_if!(ap.arg::<c_int>() == 4);
+ continue_if!(ap.arg::<c_int>() == 5);
+ continue_if!(ap.arg::<c_int>() == 6);
+ continue_if!(ap.arg::<c_int>() == 7);
+ continue_if!(ap.arg::<c_int>() == 8);
+ continue_if!(ap.arg::<c_int>() == 9);
+ continue_if!(ap.arg::<c_int>() == 10);
+ 0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_double>() == 1.0);
+ continue_if!(ap.arg::<c_double>() == 2.0);
+ continue_if!(ap.arg::<c_double>() == 3.0);
+ continue_if!(ap.arg::<c_double>() == 4.0);
+ continue_if!(ap.arg::<c_double>() == 5.0);
+ continue_if!(ap.arg::<c_double>() == 6.0);
+ continue_if!(ap.arg::<c_double>() == 7.0);
+ continue_if!(ap.arg::<c_double>() == 8.0);
+ continue_if!(ap.arg::<c_double>() == 9.0);
+ continue_if!(ap.arg::<c_double>() == 10.0);
+ 0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_double>() == 1.0);
+ continue_if!(ap.arg::<c_int>() == 1);
+ continue_if!(ap.arg::<c_double>() == 2.0);
+ continue_if!(ap.arg::<c_int>() == 2);
+ continue_if!(ap.arg::<c_double>() == 3.0);
+ continue_if!(ap.arg::<c_int>() == 3);
+ continue_if!(ap.arg::<c_double>() == 4.0);
+ continue_if!(ap.arg::<c_int>() == 4);
+ continue_if!(ap.arg::<c_int>() == 5);
+ continue_if!(ap.arg::<c_double>() == 5.0);
+ continue_if!(ap.arg::<c_int>() == 6);
+ continue_if!(ap.arg::<c_double>() == 6.0);
+ continue_if!(ap.arg::<c_int>() == 7);
+ continue_if!(ap.arg::<c_double>() == 7.0);
+ continue_if!(ap.arg::<c_int>() == 8);
+ continue_if!(ap.arg::<c_double>() == 8.0);
+ continue_if!(ap.arg::<c_int>() == 9);
+ continue_if!(ap.arg::<c_double>() == 9.0);
+ continue_if!(ap.arg::<c_int>() == 10);
+ continue_if!(ap.arg::<c_double>() == 10.0);
+ 0
+}
extern size_t check_varargs_0(int fixed, ...);
extern size_t check_varargs_1(int fixed, ...);
extern size_t check_varargs_2(int fixed, ...);
+extern size_t check_varargs_3(int fixed, ...);
+extern size_t check_varargs_4(double fixed, ...);
+extern size_t check_varargs_5(int fixed, ...);
int test_rust(size_t (*fn)(va_list), ...) {
size_t ret = 0;
assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0);
+ assert(check_varargs_3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 0);
+
+ assert(check_varargs_4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) == 0);
+
+ assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0,
+ 9, 9.0, 10, 10.0) == 0);
+
return 0;
}
-error: `[v2]` cannot be resolved, ignoring it.
+error: unresolved link to `v2`
--> $DIR/deny-intra-link-resolution-failure.rs:3:6
|
LL | /// [v2]
- | ^^ cannot be resolved, ignoring
+ | ^^ unresolved link
|
note: the lint level is defined here
--> $DIR/deny-intra-link-resolution-failure.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
-error: `[TypeAlias::hoge]` cannot be resolved, ignoring it.
+error: unresolved link to `TypeAlias::hoge`
--> $DIR/intra-doc-alias-ice.rs:5:30
|
LL | /// [broken cross-reference](TypeAlias::hoge)
- | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^^^^^^ unresolved link
|
note: the lint level is defined here
--> $DIR/intra-doc-alias-ice.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
/// ## For example:
///
/// (arr[i])
-//~^ ERROR `[i]` cannot be resolved, ignoring it.
+//~^ ERROR `i`
pub fn test_ice() {
unimplemented!();
}
-error: `[i]` cannot be resolved, ignoring it.
+error: unresolved link to `i`
--> $DIR/intra-link-span-ice-55723.rs:9:10
|
LL | /// (arr[i])
- | ^ cannot be resolved, ignoring
+ | ^ unresolved link
|
note: the lint level is defined here
--> $DIR/intra-link-span-ice-55723.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
/// Like [Foo#hola].
///
/// Or maybe [Foo::f#hola].
-//~^ ERROR `[Foo::f#hola]` has an issue with the link anchor.
+//~^ ERROR `Foo::f#hola` contains an anchor
pub fn foo() {}
/// Empty.
///
/// Another anchor error: [hello#people#!].
-//~^ ERROR `[hello#people#!]` has an issue with the link anchor.
+//~^ ERROR `hello#people#!` contains multiple anchors
pub fn bar() {}
/// Empty?
///
/// Damn enum's variants: [Enum::A#whatever].
-//~^ ERROR `[Enum::A#whatever]` has an issue with the link anchor.
+//~^ ERROR `Enum::A#whatever` contains an anchor
pub fn enum_link() {}
/// Primitives?
///
/// [u32#hello]
-//~^ ERROR `[u32#hello]` has an issue with the link anchor.
+//~^ ERROR `u32#hello` contains an anchor
pub fn x() {}
-error: `[Foo::f#hola]` has an issue with the link anchor.
+error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored
--> $DIR/intra-links-anchors.rs:25:15
|
LL | /// Or maybe [Foo::f#hola].
- | ^^^^^^^^^^^ struct fields cannot be followed by anchors
+ | ^^^^^^^^^^^ contains invalid anchor
|
note: the lint level is defined here
--> $DIR/intra-links-anchors.rs:1:9
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `[hello#people#!]` has an issue with the link anchor.
+error: `hello#people#!` contains multiple anchors
--> $DIR/intra-links-anchors.rs:31:28
|
LL | /// Another anchor error: [hello#people#!].
- | ^^^^^^^^^^^^^^ only one `#` is allowed in a link
+ | ^^^^^^^^^^^^^^ contains invalid anchor
-error: `[Enum::A#whatever]` has an issue with the link anchor.
+error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored
--> $DIR/intra-links-anchors.rs:37:28
|
LL | /// Damn enum's variants: [Enum::A#whatever].
- | ^^^^^^^^^^^^^^^^ variants cannot be followed by anchors
+ | ^^^^^^^^^^^^^^^^ contains invalid anchor
-error: `[u32#hello]` has an issue with the link anchor.
+error: `u32#hello` contains an anchor, but links to primitive types are already anchored
--> $DIR/intra-links-anchors.rs:43:6
|
LL | /// [u32#hello]
- | ^^^^^^^^^ primitive types cannot be followed by anchors
+ | ^^^^^^^^^ contains invalid anchor
error: aborting due to 4 previous errors
--- /dev/null
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/intra-links-private.rs:5:11
+ |
+LL | /// docs [DontDocMe]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
-warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
- --> $DIR/intra-links-private.rs:6:11
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/intra-links-private.rs:5:11
|
LL | /// docs [DontDocMe]
| ^^^^^^^^^ this item is private
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
warning: 1 warning emitted
// check-pass
// revisions: public private
// [private]compile-flags: --document-private-items
-#![cfg_attr(private, deny(intra_doc_link_resolution_failure))]
/// docs [DontDocMe]
-//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
+//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
// FIXME: for [private] we should also make sure the link was actually generated
pub struct DocMe;
struct DontDocMe;
/// [error]
pub struct A;
-//~^^ WARNING `[error]` cannot be resolved
+//~^^ WARNING `error`
///
/// docs [error1]
-//~^ WARNING `[error1]` cannot be resolved
+//~^ WARNING `error1`
/// docs [error2]
///
pub struct B;
-//~^^^ WARNING `[error2]` cannot be resolved
+//~^^^ WARNING `error2`
/**
* This is a multi-line comment.
* It also has an [error].
*/
pub struct C;
-//~^^^ WARNING `[error]` cannot be resolved
+//~^^^ WARNING `error`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:7:6
|
LL | /// [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
--> $DIR/intra-links-warning-crlf.rs:12:11
|
LL | /// docs [error1]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
--> $DIR/intra-links-warning-crlf.rs:15:11
|
LL | /// docs [error2]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:23:20
|
LL | * It also has an [error].
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: 4 warnings emitted
// check-pass
//! Test with [Foo::baz], [Bar::foo], ...
-//~^ WARNING `[Foo::baz]` cannot be resolved
-//~| WARNING `[Bar::foo]` cannot be resolved
+//~^ WARNING `Foo::baz`
+//~| WARNING `Bar::foo`
//! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
//!
//! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
/// [Qux:Y]
-//~^ WARNING `[Qux:Y]` cannot be resolved
+//~^ WARNING `Qux:Y`
pub struct Foo {
pub bar: usize,
}
/// Foo
-/// bar [BarA] bar //~ WARNING `[BarA]` cannot be resolved
+/// bar [BarA] bar //~ WARNING `BarA`
/// baz
pub fn a() {}
/**
* Foo
- * bar [BarB] bar //~ WARNING `[BarB]` cannot be resolved
+ * bar [BarB] bar //~ WARNING `BarB`
* baz
*/
pub fn b() {}
/** Foo
-bar [BarC] bar //~ WARNING `[BarC]` cannot be resolved
+bar [BarC] bar //~ WARNING `BarC`
baz
let bar_c_1 = 0;
*/
pub fn c() {}
-#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `[BarD]` cannot be resolved
+#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD`
pub fn d() {}
macro_rules! f {
($f:expr) => {
- #[doc = $f] //~ WARNING `[BarF]` cannot be resolved
+ #[doc = $f] //~ WARNING `BarF`
pub fn f() {}
}
}
/** # for example,
*
- * time to introduce a link [error]*/ //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error]*/ //~ WARNING `error`
pub struct A;
/**
* # for example,
*
- * time to introduce a link [error] //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error] //~ WARNING `error`
*/
pub struct B;
-#[doc = "single line [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line [error]"] //~ WARNING `error`
pub struct C;
-#[doc = "single line with \"escaping\" [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error`
pub struct D;
-/// Item docs. //~ WARNING `[error]` cannot be resolved
+/// Item docs. //~ WARNING `error`
#[doc="Hello there!"]
/// [error]
pub struct E;
///
-/// docs [error1] //~ WARNING `[error1]` cannot be resolved
+/// docs [error1] //~ WARNING `error1`
-/// docs [error2] //~ WARNING `[error2]` cannot be resolved
+/// docs [error2] //~ WARNING `error2`
///
pub struct F;
-warning: `[Foo::baz]` cannot be resolved, ignoring it.
+warning: unresolved link to `Foo::baz`
--> $DIR/intra-links-warning.rs:3:23
|
LL | //! Test with [Foo::baz], [Bar::foo], ...
- | ^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^ unresolved link
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Bar::foo]` cannot be resolved, ignoring it.
+warning: unresolved link to `Bar::foo`
--> $DIR/intra-links-warning.rs:3:35
|
LL | //! Test with [Foo::baz], [Bar::foo], ...
- | ^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:6:13
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:6:30
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:10:14
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:10:31
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux:Y]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux:Y`
--> $DIR/intra-links-warning.rs:14:13
|
LL | /// [Qux:Y]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:58:30
|
LL | * time to introduce a link [error]*/
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:64:30
|
LL | * time to introduce a link [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:68:1
|
LL | #[doc = "single line [error]"]
single line [error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:71:1
|
LL | #[doc = "single line with \"escaping\" [error]"]
single line with "escaping" [error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:74:1
|
LL | / /// Item docs.
[error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
--> $DIR/intra-links-warning.rs:80:11
|
LL | /// docs [error1]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
--> $DIR/intra-links-warning.rs:82:11
|
LL | /// docs [error2]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarA]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarA`
--> $DIR/intra-links-warning.rs:21:10
|
LL | /// bar [BarA] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarB]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarB`
--> $DIR/intra-links-warning.rs:27:9
|
LL | * bar [BarB] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarC]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarC`
--> $DIR/intra-links-warning.rs:34:6
|
LL | bar [BarC] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarD]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarD`
--> $DIR/intra-links-warning.rs:45:1
|
LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
bar [BarD] bar
^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarF]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarF`
--> $DIR/intra-links-warning.rs:50:9
|
LL | #[doc = $f]
bar [BarF] bar
^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 19 warnings emitted
--- /dev/null
+warning: public documentation for `public_item` links to private item `PrivateType`
+ --> $DIR/issue-74134.rs:19:10
+ |
+LL | /// [`PrivateType`]
+ | ^^^^^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
-warning: `[PrivateType]` public documentation for `public_item` links to a private item
+warning: public documentation for `public_item` links to private item `PrivateType`
--> $DIR/issue-74134.rs:19:10
|
LL | /// [`PrivateType`]
| ^^^^^^^^^^^^^ this item is private
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
warning: 1 warning emitted
// There are 4 cases here:
// 1. public item -> public type: no warning
-// 2. public item -> private type: warning, if --document-private-items is not passed
+// 2. public item -> private type: warning
// 3. private item -> public type: no warning
// 4. private item -> private type: no warning
// All 4 cases are tested with and without --document-private-items.
pub struct Public {
/// [`PublicType`]
/// [`PrivateType`]
- //[public]~^ WARNING public documentation for `public_item` links to a private
+ //~^ WARNING public documentation for `public_item` links to private item `PrivateType`
pub public_item: u32,
/// [`PublicType`]
/// ```
/// println!("sup");
/// ```
-pub fn link_error() {} //~^^^^^ ERROR cannot be resolved, ignoring it
+pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error`
/// wait, this doesn't have a doctest?
pub fn no_doctest() {} //~^ ERROR missing code example in this documentation
| ^^^^^^^
= note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]`
-error: `[error]` cannot be resolved, ignoring it.
+error: unresolved link to `error`
--> $DIR/lint-group.rs:9:29
|
LL | /// what up, let's make an [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
note: the lint level is defined here
--> $DIR/lint-group.rs:7:9
LL | #![deny(rustdoc)]
| ^^^^^^^
= note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]`
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: missing code example in this documentation
--> $DIR/lint-group.rs:16:1
#[cfg(transmute)] // one instantiations: BAD
fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
- bar(foo, x) //[transmute]~ ERROR E0495
+ bar(foo, x) //[transmute]~ ERROR E0759
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/project-fn-ret-contravariant.rs:38:8
|
-LL | bar(foo, x)
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8...
- --> $DIR/project-fn-ret-contravariant.rs:37:8
- |
LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/project-fn-ret-contravariant.rs:38:13
- |
-LL | bar(foo, x)
- | ^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/project-fn-ret-contravariant.rs:38:4
- |
+ | ------- this data with lifetime `'a`...
LL | bar(foo, x)
- | ^^^^^^^^^^^
+ | ----^^^---- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
// Cannot instantiate `foo` with any lifetime other than `'a`,
// since it is provided as input.
- bar(foo, x) //[transmute]~ ERROR E0495
+ bar(foo, x) //[transmute]~ ERROR E0759
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/project-fn-ret-invariant.rs:49:9
|
-LL | bar(foo, x)
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
- --> $DIR/project-fn-ret-invariant.rs:45:8
- |
LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:49:14
- |
-LL | bar(foo, x)
- | ^
- = note: expected `Type<'_>`
- found `Type<'a>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:49:5
- |
+ | -------- this data with lifetime `'a`...
+...
LL | bar(foo, x)
- | ^^^^^^^^^^^
- = note: expected `Type<'static>`
- found `Type<'_>`
+ | ----^^^---- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
struct Struct;
impl Struct {
- pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer
+ pub async fn run_dummy_fn(&self) { //~ ERROR E0759
foo(|| self.bar()).await;
}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
// run-pass
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
pub fn main() {
println!("hello, world");
--- /dev/null
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+struct A<T = u32, const N: usize> {
+ //~^ ERROR type parameters with a default must be trailing
+ arg: T,
+}
+
+fn main() {}
--- /dev/null
+error: type parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:3:10
+ |
+LL | struct A<T = u32, const N: usize> {
+ | ^
+ |
+ = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/wrong-order.rs:1:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+// check-pass
+//
+// This test is complement to the test in issue-73976-polymorphic.rs.
+// In that test we ensure that polymorphic use of type_id and type_name in patterns
+// will be properly rejected. This test will ensure that monomorphic use of these
+// would not be wrongly rejected in patterns.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+ pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+ matches!(GetTypeId::<T>::VALUE, GetTypeId::<usize>::VALUE)
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+ pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+ matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<usize>::VALUE)
+}
+
+fn main() {
+ assert!(check_type_id::<usize>());
+ assert!(check_type_name_len::<usize>());
+}
--- /dev/null
+// This test is from #73976. We previously did not check if a type is monomorphized
+// before calculating its type id, which leads to the bizzare behaviour below that
+// TypeId of a generic type does not match itself.
+//
+// This test case should either run-pass or be rejected at compile time.
+// Currently we just disallow this usage and require pattern is monomorphic.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+ pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+ matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ //~^ ERROR could not evaluate constant pattern
+ //~| ERROR could not evaluate constant pattern
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+ pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+ matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ //~^ ERROR could not evaluate constant pattern
+ //~| ERROR could not evaluate constant pattern
+}
+
+fn main() {
+ assert!(check_type_id::<usize>());
+ assert!(check_type_name_len::<usize>());
+}
--- /dev/null
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:20:37
+ |
+LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:32:42
+ |
+LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:20:37
+ |
+LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:32:42
+ |
+LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
}
fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
- static_val(x); //~ ERROR cannot infer
+ static_val(x); //~ ERROR E0759
}
fn not_static_val<T: NotStaticTrait>(_: T) {
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/dyn-trait.rs:20:16
|
-LL | static_val(x);
- | ^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26...
- --> $DIR/dyn-trait.rs:19:26
- |
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/dyn-trait.rs:20:16
- |
+ | ------------------- this data with lifetime `'a`...
LL | static_val(x);
- | ^
- = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
- found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the types are compatible
+ | ^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
--> $DIR/dyn-trait.rs:20:5
|
LL | static_val(x);
| ^^^^^^^^^^
- = note: expected `StaticTrait`
- found `StaticTrait`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| - ^ returning this value requires that `'1` must outlive `'static`
= help: consider replacing `'1` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^ lifetime `'a` required
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:24
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
| let's call the lifetime of this reference `'1`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:32:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
= help: consider adding the following bound: `'b: 'a`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
use std::fmt::Debug;
-fn elided(x: &i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759
-fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759
-fn elided2(x: &i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759
-fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } //~ ERROR E0759
fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
//~^ ERROR explicit lifetime required in the type of `x`
-fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
-fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
-fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
-fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
-fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-//~^ ERROR cannot infer an appropriate lifetime
-//~| ERROR cannot infer an appropriate lifetime
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
+//~^ ERROR E0759
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
-fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERROR E0759
// Tests that a closure type containing 'b cannot be returned from a type where
// only 'a was expected.
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:6:44
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ------- ^ ...is captured here...
| this data with lifetime `'a`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ^^^^^^^^^
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ---- ^ ...is captured here...
| this data with an anonymous lifetime `'_`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:9:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:24
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ------- ^ ...is captured here...
| this data with lifetime `'a`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:12:33
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:33
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:24
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^^^^^^^^^^^^^^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:65
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ---- this data with an anonymous lifetime `'_`... ^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:41
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ^^^^^^^^^^
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- this data with lifetime `'a`... ^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:37:34
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:34
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error[E0623]: lifetime mismatch
- --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:32:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| ------- ^^^^^^^^^^^^^^^^
| this parameter and the return type are declared with different lifetimes...
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'static +`
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:14:50
|
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:16:59
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| ------- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:24:60
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:60
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:20:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/static-return-lifetime-infered.rs:10:37
+ --> $DIR/static-return-lifetime-infered.rs:9:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
impl A {
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0)
+ self.x.iter().map(|a| a.0) //~ ERROR E0759
}
- //~^^ ERROR cannot infer an appropriate lifetime
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0)
+ self.x.iter().map(|a| a.0) //~ ERROR E0759
}
- //~^^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/static-return-lifetime-infered.rs:7:16
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/static-return-lifetime-infered.rs:11:16
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/static-return-lifetime-infered.rs:10:16
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| -------- this data with lifetime `'a`...
| ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/static-return-lifetime-infered.rs:10:37
+ --> $DIR/static-return-lifetime-infered.rs:9:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^
use std::any::Any;
fn foo<T: Any>(value: &T) -> Box<dyn Any> {
- Box::new(value) as Box<dyn Any>
- //~^ ERROR cannot infer an appropriate lifetime
+ Box::new(value) as Box<dyn Any> //~ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-16922.rs:4:14
|
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
--- /dev/null
+// build-pass
+
+fn test<T>() {
+ std::mem::size_of::<T>();
+}
+
+pub fn foo<T>(_: T) -> &'static fn() {
+ &(test::<T> as fn())
+}
+
+fn outer<T>() {
+ foo(|| ());
+}
+
+fn main() {
+ outer::<u8>();
+}
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/constant-in-expr-inherent-1.rs:8:5
|
-LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8...
- --> $DIR/constant-in-expr-inherent-1.rs:7:8
- |
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/constant-in-expr-inherent-1.rs:8:5
- |
-LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
- = note: expected `Foo<'_>`
- found `Foo<'a>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/constant-in-expr-inherent-1.rs:8:5
- |
+ | ------- this data with lifetime `'a`...
LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal.
- ss.r //~ ERROR cannot infer an appropriate lifetime
+ ss.r //~ ERROR E0759
}
fn store(ss: &mut SomeStruct, b: Box<dyn SomeTrait>) {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `ss` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/object-lifetime-default-from-box-error.rs:18:5
|
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(const_generics, rustc_attrs)]
//~^ WARN the feature `const_generics` is incomplete
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/closures.rs:2:12
+ --> $DIR/closures.rs:3:12
|
LL | #![feature(const_generics, rustc_attrs)]
| ^^^^^^^^^^^^^^
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: item has unused generic parameters
- --> $DIR/closures.rs:18:19
+ --> $DIR/closures.rs:19:19
|
LL | pub fn unused<const T: usize>() -> usize {
| - generic parameter `T` is unused
| ^^^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/closures.rs:16:8
+ --> $DIR/closures.rs:17:8
|
LL | pub fn unused<const T: usize>() -> usize {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
- --> $DIR/closures.rs:27:19
+ --> $DIR/closures.rs:28:19
|
LL | pub fn used_parent<const T: usize>() -> usize {
| - generic parameter `T` is unused
| ^^^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/closures.rs:47:13
+ --> $DIR/closures.rs:48:13
|
LL | pub fn unused_upvar<const T: usize>() -> usize {
| - generic parameter `T` is unused
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(const_generics, rustc_attrs)]
//~^ WARN the feature `const_generics` is incomplete
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/functions.rs:2:12
+ --> $DIR/functions.rs:3:12
|
LL | #![feature(const_generics, rustc_attrs)]
| ^^^^^^^^^^^^^^
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: item has unused generic parameters
- --> $DIR/functions.rs:14:8
+ --> $DIR/functions.rs:15:8
|
LL | pub fn unused<const T: usize>() {
| ^^^^^^ - generic parameter `T` is unused
// check-pass
+// compile-flags:-Zpolymorphize=on
pub struct OnDrop<F: Fn()>(pub F);
// check-pass
+// compile-flags:-Zpolymorphize=on
pub struct OnDrop<F: Fn()>(pub F);
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(const_generics, generators, generator_trait, rustc_attrs)]
//~^ WARN the feature `const_generics` is incomplete
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/generators.rs:2:12
+ --> $DIR/generators.rs:3:12
|
LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)]
| ^^^^^^^^^^^^^^
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
error: item has unused generic parameters
- --> $DIR/generators.rs:35:5
+ --> $DIR/generators.rs:36:5
|
LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| - generic parameter `T` is unused
| |_____^
error: item has unused generic parameters
- --> $DIR/generators.rs:33:8
+ --> $DIR/generators.rs:34:8
|
LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| ^^^^^^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
- --> $DIR/generators.rs:61:5
+ --> $DIR/generators.rs:62:5
|
LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| - generic parameter `T` is unused
| |_____^
error: item has unused generic parameters
- --> $DIR/generators.rs:59:8
+ --> $DIR/generators.rs:60:8
|
LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
| ^^^^^^^^^^^^ - generic parameter `T` is unused
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that the polymorphization analysis doesn't break when the
error: item has unused generic parameters
- --> $DIR/lifetimes.rs:9:8
+ --> $DIR/lifetimes.rs:10:8
|
LL | pub fn unused<'a, T>(_: &'a u32) {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
- --> $DIR/lifetimes.rs:16:19
+ --> $DIR/lifetimes.rs:17:19
|
LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
| - generic parameter `T` is unused
// build-pass
+// compile-flags:-Zpolymorphize=on
pub trait ParallelIterator: Sized {
fn drive<C: Consumer<()>>(_: C) {
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
error: item has unused generic parameters
- --> $DIR/predicates.rs:8:4
+ --> $DIR/predicates.rs:9:4
|
LL | fn bar<I>() {
| ^^^ - generic parameter `I` is unused
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(stmt_expr_attributes, rustc_attrs)]
// This test checks that the polymorphization analysis correctly detects unused type
error: item has unused generic parameters
- --> $DIR/closures.rs:18:19
+ --> $DIR/closures.rs:19:19
|
LL | pub fn unused<T>() -> u32 {
| - generic parameter `T` is unused
| ^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/closures.rs:15:8
+ --> $DIR/closures.rs:16:8
|
LL | pub fn unused<T>() -> u32 {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
- --> $DIR/closures.rs:27:19
+ --> $DIR/closures.rs:28:19
|
LL | pub fn used_parent<T: Default>() -> u32 {
| - generic parameter `T` is unused
| ^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/closures.rs:93:23
+ --> $DIR/closures.rs:94:23
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
| ^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/closures.rs:91:12
+ --> $DIR/closures.rs:92:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
| ^^^^^^^^^^ - generic parameter `G` is unused
error: item has unused generic parameters
- --> $DIR/closures.rs:127:23
+ --> $DIR/closures.rs:128:23
|
LL | pub fn used_impl<G: Default>() -> u32 {
| - generic parameter `G` is unused
| |_________^
error: item has unused generic parameters
- --> $DIR/closures.rs:125:12
+ --> $DIR/closures.rs:126:12
|
LL | pub fn used_impl<G: Default>() -> u32 {
| ^^^^^^^^^ - generic parameter `G` is unused
error: item has unused generic parameters
- --> $DIR/closures.rs:114:23
+ --> $DIR/closures.rs:115:23
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
| |_________^
error: item has unused generic parameters
- --> $DIR/closures.rs:112:12
+ --> $DIR/closures.rs:113:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(rustc_attrs)]
// This test checks that the polymorphization analysis correctly detects unused type
error: item has unused generic parameters
- --> $DIR/functions.rs:13:8
+ --> $DIR/functions.rs:14:8
|
LL | pub fn unused<T>() {
| ^^^^^^ - generic parameter `T` is unused
error: item has unused generic parameters
- --> $DIR/functions.rs:44:12
+ --> $DIR/functions.rs:45:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
| ^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/functions.rs:50:12
+ --> $DIR/functions.rs:51:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
| ^^^^^^^^^^^ - generic parameter `G` is unused
error: item has unused generic parameters
- --> $DIR/functions.rs:62:12
+ --> $DIR/functions.rs:63:12
|
LL | impl<F: Default> Foo<F> {
| - generic parameter `F` is unused
// build-fail
+// compile-flags:-Zpolymorphize=on
#![feature(fn_traits, rustc_attrs, unboxed_closures)]
// This test checks that the polymorphization analysis considers a closure
error: item has unused generic parameters
- --> $DIR/unsized_cast.rs:10:18
+ --> $DIR/unsized_cast.rs:11:18
|
LL | fn foo<T: Default>() {
| - generic parameter `T` is unused
| ^^^^^
error: item has unused generic parameters
- --> $DIR/unsized_cast.rs:10:5
+ --> $DIR/unsized_cast.rs:11:5
|
LL | fn foo<T: Default>() {
| - generic parameter `T` is unused
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/unsized_cast.rs:20:15
+ --> $DIR/unsized_cast.rs:21:15
|
LL | fn foo2<T: Default>() {
| - generic parameter `T` is unused
print-type-size field `.0`: 12 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
-print-type-size discriminant: 1 bytes
print-type-size variant `Record`: 7 bytes
-print-type-size field `.pre`: 1 bytes
-print-type-size field `.post`: 2 bytes
print-type-size field `.val`: 4 bytes
+print-type-size field `.post`: 2 bytes
+print-type-size field `.pre`: 1 bytes
print-type-size variant `None`: 0 bytes
+print-type-size end padding: 1 bytes
print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
+ let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759
x
}
fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) //~ ERROR E0759
}
fn c(v: &[u8]) -> Box<dyn Foo> {
// same as previous case due to RFC 599
- Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) //~ ERROR E0759
}
fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:8:46
|
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
| ^^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:13:14
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
| ^^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:19:14
|
LL | fn c(v: &[u8]) -> Box<dyn Foo> {
impl Dog {
pub fn chase_cat(&mut self) {
- let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer
+ let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759
*p += 1;
}
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-addr-of-self.rs:7:37
|
+LL | pub fn chase_cat(&mut self) {
+ | --------- this data with an anonymous lifetime `'_`...
LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
- --> $DIR/regions-addr-of-self.rs:6:5
- |
-LL | / pub fn chase_cat(&mut self) {
-LL | | let p: &'static mut usize = &mut self.cats_chased;
-LL | | *p += 1;
-LL | | }
- | |_____^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-addr-of-self.rs:7:37
- |
-LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-addr-of-self.rs:7:37
- |
-LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
impl<'a, T> X for B<'a, T> {}
fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+ box B(&*v) as Box<dyn X> //~ ERROR E0759
}
fn main() { }
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-close-object-into-object-2.rs:10:11
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
impl<'a, T> X for B<'a, T> {}
fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+ box B(&*v) as Box<dyn X> //~ ERROR E0759
}
fn main() {}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-close-object-into-object-4.rs:10:11
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static.
- Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(move || { *x }) //~ ERROR E0759
}
fn main() { }
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-proc-bound-capture.rs:9:14
|
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
--- /dev/null
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+use std::ptr::NonNull;
+
+pub unsafe trait RawData {
+ type Elem;
+}
+
+unsafe impl<A> RawData for OwnedRepr<A> {
+ type Elem = A;
+}
+
+unsafe impl<'a, A> RawData for ViewRepr<&'a A> {
+ type Elem = A;
+}
+
+pub struct OwnedRepr<A> {
+ ptr: PhantomData<A>,
+}
+
+// these Copy impls are not necessary for the repro, but allow the code to compile without error
+// on 1.44.1
+#[derive(Copy, Clone)]
+pub struct ViewRepr<A> {
+ life: PhantomData<A>,
+}
+
+#[derive(Copy, Clone)]
+pub struct ArrayBase<S>
+where
+ S: RawData,
+{
+ ptr: NonNull<S::Elem>,
+}
+
+pub type Array<A> = ArrayBase<OwnedRepr<A>>;
+
+pub type ArrayView<'a, A> = ArrayBase<ViewRepr<&'a A>>;
+
+impl<A, S> ArrayBase<S>
+where
+ S: RawData<Elem = A>,
+{
+ pub fn index_axis(&self) -> ArrayView<'_, A> {
+ unimplemented!()
+ }
+
+ pub fn axis_iter<'a>(&'a self) -> std::iter::Empty<&'a A> {
+ unimplemented!()
+ }
+}
+
+pub fn x<T: Copy>(a: Array<T>) {
+ // drop just avoids a must_use warning
+ drop((0..1).filter(|_| true));
+ let y = a.index_axis();
+ a.axis_iter().for_each(|_| {
+ drop(y);
+ });
+}
+
+fn main() {}
--- /dev/null
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+
+fn apply<T, F: FnOnce(T)>(_: T, _: F) {}
+
+#[derive(Clone, Copy)]
+struct Invariant<T> {
+ t: T,
+ p: PhantomData<fn(T) -> T>,
+}
+
+fn verify_reempty<T>(x: T) {
+ // r is inferred to have type `Invariant<&ReEmpty(U0) T>`
+ let r = Invariant { t: &x, p: PhantomData };
+ // Creates a new universe, all variables from now on are in `U1`, say.
+ let _: fn(&()) = |_| {};
+ // Closure parameter is of type `&ReEmpty(U1) T`, so the closure has an implied
+ // bound of `T: ReEmpty(U1)`
+ apply(&x, |_| {
+ // Requires `typeof(r)` is well-formed, i.e. `T: ReEmpty(U0)`. If we
+ // only have the implied bound from the closure parameter to use this
+ // requires `ReEmpty(U1): ReEmpty(U0)`, which isn't true so we reported
+ // an error.
+ //
+ // This doesn't happen any more because we ensure that `T: ReEmpty(U0)`
+ // is an implicit bound for all type parameters.
+ drop(r);
+ });
+}
+
+fn main() {}
// being run when compiling with new LLVM pass manager and ThinLTO.
// Note: The issue occurred only on non-zero opt-level.
//
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
// needs-sanitizer-support
// needs-sanitizer-address
//
impl Foo {
async fn f(self: Pin<&Self>) -> impl Clone { self }
- //~^ ERROR cannot infer an appropriate lifetime
+ //~^ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
struct Foo;
impl Foo {
- fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+ fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
#[rustc_deprecated(since = "b", reason = "text")]
#[rustc_const_unstable(feature = "c", issue = "none")]
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
-pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
+pub const fn multiple4() { } //~ ERROR multiple deprecated attributes
//~^ ERROR Invalid stability or deprecation version found
#[rustc_deprecated(since = "a", reason = "text")]
LL | #[stable(feature = "a", since = "b")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0540]: multiple rustc_deprecated attributes
+error[E0550]: multiple deprecated attributes
--> $DIR/stability-attribute-sanity.rs:65:1
|
LL | pub const fn multiple4() { }
error: aborting due to 18 previous errors
-Some errors have detailed explanations: E0539, E0541.
+Some errors have detailed explanations: E0539, E0541, E0550.
For more information about an error, try `rustc --explain E0539`.
--- /dev/null
+error[E0597]: `val` does not live long enough
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
+LL | val.use_self()
+ | ^^^ borrowed value does not live long enough
+LL | }
+ | - `val` dropped here while still borrowed
+ |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
--- /dev/null
+// FIXME: the following cases need to suggest more things to make users reach a working end state.
+
+mod bav {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ val.use_self() //~ ERROR E0597
+ }
+}
+
+mod bap {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0515
+ }
+}
+
+// This case in particular requires the user to write all of the bounds we have in `mod bax`.
+mod bay {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bax {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait<'a> {
+ fn use_self(&'a self) -> &'a () { panic!() }
+ }
+ trait Bar {}
+
+ impl<'a> MyTrait<'a> for Box<dyn ObjectTrait<Assoc = i32> + 'a> {
+ fn use_self(&'a self) -> &'a () { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ val.use_self()
+ }
+}
+
+mod baw {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl<'a> MyTrait for Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>>) -> impl OtherTrait<'a> + 'a{
+ val.use_self() //~ ERROR E0515
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `val` does not live long enough
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
+LL | val.use_self()
+ | ^^^ borrowed value does not live long enough
+LL | }
+ | - `val` dropped here while still borrowed
+ |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ | -------------------------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
+ | ^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait<T> {}
+ trait MyTrait<T> {
+ fn use_self<K>(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+ fn use_self<K>(&self) -> &() { panic!() }
+ }
+ impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+ fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ val.use_self::<T>() //~ ERROR E0759
+ }
+}
+
+mod bar {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for dyn ObjectTrait + '_ {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod baz {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for Box<dyn ObjectTrait + '_> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for Box<dyn ObjectTrait> {}
+
+ fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bat {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+
+ impl dyn ObjectTrait + '_ {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod ban {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait + '_ {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0759
+ }
+}
+
+mod bal {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait + '_ {}
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ MyTrait::use_self(val) //~ ERROR E0759
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9
+ |
+LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self::<T>()
+ | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self()
+ | ^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self()
+ | ^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | MyTrait::use_self(val)
+ | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait<T> {}
+ trait MyTrait<T> {
+ fn use_self<K>(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+ fn use_self<K>(&self) -> &() { panic!() }
+ }
+ impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+ fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ val.use_self::<T>() //~ ERROR E0759
+ }
+}
+
+mod bar {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for dyn ObjectTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod baz {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for Box<dyn ObjectTrait> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for Box<dyn ObjectTrait> {}
+
+ fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bat {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+
+ impl dyn ObjectTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod ban {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ val.use_self() //~ ERROR E0759
+ }
+}
+
+mod bal {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait {}
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ MyTrait::use_self(val) //~ ERROR E0759
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13
+ |
+LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ | ---------------------- this data with lifetime `'a`...
+LL | val.use_self::<T>()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32
+ |
+LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+ | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self<K>(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl`
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14
+ |
+LL | impl dyn ObjectTrait {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl dyn ObjectTrait + '_ {
+ | ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26
+ |
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL | impl MyTrait for dyn ObjectTrait {}
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {}
+ | ^^^^
+help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:27
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ------------------- this data with lifetime `'a`...
+LL | MyTrait::use_self(val)
+ | ^^^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+ |
+LL | MyTrait::use_self(val)
+ | ^^^^^^^^^^^^^^^^^
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:104:26
+ |
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL | impl MyTrait for dyn ObjectTrait {}
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {}
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26
+ |
+LL | impl MyTrait for dyn ObjectTrait {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13
+ |
+LL | fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ | ----------------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait> {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait + '_> {
+ | ^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
where
G: Get<T>
{
- move || { //~ ERROR cannot infer an appropriate lifetime
+ move || { //~ ERROR `dest`
*dest = g.get();
}
}
| |
| help: consider introducing lifetime `'a` here: `'a,`
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:30:31
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:41:31
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:52:31
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:63:31
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
#![feature(never_type)]
use std::mem::size_of;
-use std::num::NonZeroU8;
struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
None
}
-// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
-// Niche-filling:
-// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
-// Tagged:
-// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
-// Both are the same size (due to padding),
-// but the tagged layout is better as the tag creates a niche with 254 invalid values,
-// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
-pub enum CanBeNicheFilledButShouldnt {
- A(NonZeroU8, u32),
- B
-}
-pub enum AlwaysTaggedBecauseItHasNoNiche {
- A(u8, u32),
- B
-}
-
pub fn main() {
assert_eq!(size_of::<u8>(), 1 as usize);
assert_eq!(size_of::<u32>(), 4 as usize);
assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
-
- assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
- assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
- assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
- assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
- assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
- assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
}
const D: _ = 42;
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
// type E: _; // FIXME: make the parser propagate the existence of `B`
+ type F: std::ops::Fn(_);
+ //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
}
impl Qux for Struct {
type A = _;
| ^ expected identifier, found reserved identifier
error: associated constant in `impl` without body
- --> $DIR/typeck_type_placeholder_item.rs:203:5
+ --> $DIR/typeck_type_placeholder_item.rs:205:5
|
LL | const C: _;
| ^^^^^^^^^^-
| not allowed in type signatures
| help: replace `_` with the correct type: `i32`
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item.rs:197:26
+ |
+LL | type F: std::ops::Fn(_);
+ | ^ not allowed in type signatures
+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:40:24
|
| help: replace with the correct return type: `main::FnTest9`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:199:14
+ --> $DIR/typeck_type_placeholder_item.rs:201:14
|
LL | type A = _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:201:14
+ --> $DIR/typeck_type_placeholder_item.rs:203:14
|
LL | type B = _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:203:14
+ --> $DIR/typeck_type_placeholder_item.rs:205:14
|
LL | const C: _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:206:14
+ --> $DIR/typeck_type_placeholder_item.rs:208:14
|
LL | const D: _ = 42;
| ^
| not allowed in type signatures
| help: replace `_` with the correct type: `i32`
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
Some errors have detailed explanations: E0121, E0282, E0403.
For more information about an error, try `rustc --explain E0121`.
fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
// ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
- Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(items.iter()) //~ ERROR E0759
}
fn b<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `items` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/dyn-trait-underscore.rs:8:20
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
-Subproject commit 43cf77395cad5b79887b20b7cf19d418bbd703a9
+Subproject commit aa6872140ab0fa10f641ab0b981d5330d419e927
pub gdb_native_rust: bool,
/// Version of LLDB
- pub lldb_version: Option<String>,
+ pub lldb_version: Option<u32>,
/// Whether LLDB has native rust support
pub lldb_native_rust: bool,
/// Version of LLVM
- pub llvm_version: Option<String>,
+ pub llvm_version: Option<u32>,
/// Is LLVM a system LLVM
pub system_llvm: bool,
fn ignore_gdb(config: &Config, line: &str) -> bool {
if let Some(actual_version) = config.gdb_version {
- if line.starts_with("min-gdb-version") {
- let (start_ver, end_ver) = extract_gdb_version_range(line);
+ if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) {
+ let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version)
+ .unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
if start_ver != end_ver {
panic!("Expected single GDB version")
}
// Ignore if actual version is smaller the minimum required
// version
- actual_version < start_ver
- } else if line.starts_with("ignore-gdb-version") {
- let (min_version, max_version) = extract_gdb_version_range(line);
+ return actual_version < start_ver;
+ } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) {
+ let (min_version, max_version) =
+ extract_version_range(rest, extract_gdb_version).unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
if max_version < min_version {
panic!("Malformed GDB version range: max < min")
}
- actual_version >= min_version && actual_version <= max_version
- } else {
- false
- }
- } else {
- false
- }
- }
-
- // Takes a directive of the form "ignore-gdb-version <version1> [- <version2>]",
- // returns the numeric representation of <version1> and <version2> as
- // tuple: (<version1> as u32, <version2> as u32)
- // If the <version2> part is omitted, the second component of the tuple
- // is the same as <version1>.
- fn extract_gdb_version_range(line: &str) -> (u32, u32) {
- const ERROR_MESSAGE: &'static str = "Malformed GDB version directive";
-
- let range_components = line
- .split(&[' ', '-'][..])
- .filter(|word| !word.is_empty())
- .map(extract_gdb_version)
- .skip_while(Option::is_none)
- .take(3) // 3 or more = invalid, so take at most 3.
- .collect::<Vec<Option<u32>>>();
-
- match range_components.len() {
- 1 => {
- let v = range_components[0].unwrap();
- (v, v)
- }
- 2 => {
- let v_min = range_components[0].unwrap();
- let v_max = range_components[1].expect(ERROR_MESSAGE);
- (v_min, v_max)
+ return actual_version >= min_version && actual_version <= max_version;
}
- _ => panic!(ERROR_MESSAGE),
}
+ false
}
fn ignore_lldb(config: &Config, line: &str) -> bool {
- if let Some(ref actual_version) = config.lldb_version {
- if line.starts_with("min-lldb-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed lldb version directive");
+ if let Some(actual_version) = config.lldb_version {
+ if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) {
+ let min_version = min_version.parse().unwrap_or_else(|e| {
+ panic!(
+ "Unexpected format of LLDB version string: {}\n{:?}",
+ min_version, e
+ );
+ });
// Ignore if actual version is smaller the minimum required
// version
- lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+ actual_version < min_version
} else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
true
} else {
if config.system_llvm && line.starts_with("no-system-llvm") {
return true;
}
- if let Some(ref actual_version) = config.llvm_version {
- let actual_version = version_to_int(actual_version);
- if line.starts_with("min-llvm-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed llvm version directive");
+ if let Some(actual_version) = config.llvm_version {
+ if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) {
+ let min_version = extract_llvm_version(rest).unwrap();
// Ignore if actual version is smaller the minimum required
// version
- actual_version < version_to_int(min_version)
- } else if line.starts_with("min-system-llvm-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed llvm version directive");
+ actual_version < min_version
+ } else if let Some(rest) =
+ line.strip_prefix("min-system-llvm-version:").map(str::trim)
+ {
+ let min_version = extract_llvm_version(rest).unwrap();
// Ignore if using system LLVM and actual version
// is smaller the minimum required version
- config.system_llvm && actual_version < version_to_int(min_version)
- } else if line.starts_with("ignore-llvm-version") {
- // Syntax is: "ignore-llvm-version <version1> [- <version2>]"
- let range_components = line
- .split(' ')
- .skip(1) // Skip the directive.
- .map(|s| s.trim())
- .filter(|word| !word.is_empty() && word != &"-")
- .take(3) // 3 or more = invalid, so take at most 3.
- .collect::<Vec<&str>>();
- match range_components.len() {
- 1 => actual_version == version_to_int(range_components[0]),
- 2 => {
- let v_min = version_to_int(range_components[0]);
- let v_max = version_to_int(range_components[1]);
- if v_max < v_min {
- panic!("Malformed LLVM version range: max < min")
- }
- // Ignore if version lies inside of range.
- actual_version >= v_min && actual_version <= v_max
- }
- _ => panic!("Malformed LLVM version directive"),
+ config.system_llvm && actual_version < min_version
+ } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim)
+ {
+ // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
+ let (v_min, v_max) = extract_version_range(rest, extract_llvm_version)
+ .unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
+ if v_max < v_min {
+ panic!("Malformed LLVM version range: max < min")
}
+ // Ignore if version lies inside of range.
+ actual_version >= v_min && actual_version <= v_max
} else {
false
}
false
}
}
-
- fn version_to_int(version: &str) -> u32 {
- let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
- let components: Vec<u32> = version_without_suffix
- .split('.')
- .map(|s| s.parse().expect("Malformed version component"))
- .collect();
- match components.len() {
- 1 => components[0] * 10000,
- 2 => components[0] * 10000 + components[1] * 100,
- 3 => components[0] * 10000 + components[1] * 100 + components[2],
- _ => panic!("Malformed version"),
- }
- }
}
}
}
}
-pub fn lldb_version_to_int(version_string: &str) -> isize {
- let error_string =
- format!("Encountered LLDB version string with unexpected format: {}", version_string);
- version_string.parse().expect(&error_string)
-}
-
fn expand_variables(mut value: String, config: &Config) -> String {
const CWD: &'static str = "{{cwd}}";
const SRC_BASE: &'static str = "{{src-base}}";
*line = &line[end + 1..];
Some(result)
}
+
+pub fn extract_llvm_version(version: &str) -> Option<u32> {
+ let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
+ let components: Vec<u32> = version_without_suffix
+ .split('.')
+ .map(|s| s.parse().expect("Malformed version component"))
+ .collect();
+ let version = match *components {
+ [a] => a * 10_000,
+ [a, b] => a * 10_000 + b * 100,
+ [a, b, c] => a * 10_000 + b * 100 + c,
+ _ => panic!("Malformed version"),
+ };
+ Some(version)
+}
+
+// Takes a directive of the form "<version1> [- <version2>]",
+// returns the numeric representation of <version1> and <version2> as
+// tuple: (<version1> as u32, <version2> as u32)
+// If the <version2> part is omitted, the second component of the tuple
+// is the same as <version1>.
+fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
+where
+ F: Fn(&str) -> Option<u32>,
+{
+ let mut splits = line.splitn(2, "- ").map(str::trim);
+ let min = splits.next().unwrap();
+ if min.ends_with('-') {
+ return None;
+ }
+
+ let max = splits.next();
+
+ if min.is_empty() {
+ return None;
+ }
+
+ let min = parse(min)?;
+ let max = match max {
+ Some(max) if max.is_empty() => return None,
+ Some(max) => parse(max)?,
+ _ => min,
+ };
+
+ Some((min, max))
+}
fn llvm_version() {
let mut config = config();
- config.llvm_version = Some("8.1.2-rust".to_owned());
- assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore);
+ config.llvm_version = Some(80102);
+ assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore);
- config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned());
- assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore);
+ config.llvm_version = Some(90001);
+ assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore);
- config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned());
- assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore);
+ config.llvm_version = Some(90301);
+ assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore);
- config.llvm_version = Some("10.0.0-rust".to_owned());
- assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore);
+ config.llvm_version = Some(100000);
+ assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore);
}
#[test]
assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
}
+
+#[test]
+fn test_extract_version_range() {
+ use super::{extract_llvm_version, extract_version_range};
+
+ assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506)));
+ assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506)));
+ assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None);
+ assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None);
+ assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range("-", extract_llvm_version), None);
+ assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range("0 -", extract_llvm_version), None);
+}
let cdb = analyze_cdb(matches.opt_str("cdb"), &target);
let (gdb, gdb_version, gdb_native_rust) =
analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
- let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
-
- let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+ let (lldb_version, lldb_native_rust) = matches
+ .opt_str("lldb-version")
+ .as_deref()
+ .and_then(extract_lldb_version)
+ .map(|(v, b)| (Some(v), b))
+ .unwrap_or((None, false));
+ let color = match matches.opt_str("color").as_deref() {
Some("auto") | None => ColorConfig::AutoColor,
Some("always") => ColorConfig::AlwaysColor,
Some("never") => ColorConfig::NeverColor,
Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
};
+ let llvm_version =
+ matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version);
let src_base = opt_path(matches, "src-base");
let run_ignored = matches.opt_present("ignored");
gdb_native_rust,
lldb_version,
lldb_native_rust,
- llvm_version: matches.opt_str("llvm-version"),
+ llvm_version,
system_llvm: matches.opt_present("system-llvm"),
android_cross_path,
adb_path: opt_str2(matches.opt_str("adb-path")),
logv(c, format!("stage_id: {}", config.stage_id));
logv(c, format!("mode: {}", config.mode));
logv(c, format!("run_ignored: {}", config.run_ignored));
- logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned()))));
+ logv(c, format!("filter: {}", opt_str(&config.filter)));
logv(c, format!("filter_exact: {}", config.filter_exact));
logv(
c,
return None;
}
- if let Some(lldb_version) = config.lldb_version.as_ref() {
- if lldb_version == "350" {
- println!(
- "WARNING: The used version of LLDB ({}) has a \
- known issue that breaks debuginfo tests. See \
- issue #32520 for more information. Skipping all \
- LLDB-based tests!",
- lldb_version
- );
- return None;
- }
+ if let Some(350) = config.lldb_version {
+ println!(
+ "WARNING: The used version of LLDB (350) has a \
+ known issue that breaks debuginfo tests. See \
+ issue #32520 for more information. Skipping all \
+ LLDB-based tests!",
+ );
+ return None;
}
// Some older versions of LLDB seem to have problems with multiple
let config = config.clone();
let testpaths = testpaths.clone();
let revision = revision.cloned();
- test::DynTestFn(Box::new(move || {
- runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str()))
- }))
+ test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref())))
}
/// Returns `true` if the given target is an Android target for the
// This particular form is documented in the GNU coding standards:
// https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
- // don't start parsing in the middle of a number
- let mut prev_was_digit = false;
- let mut in_parens = false;
- for (pos, c) in full_version_line.char_indices() {
- if in_parens {
- if c == ')' {
- in_parens = false;
- }
- continue;
- } else if c == '(' {
- in_parens = true;
- continue;
- }
-
- if prev_was_digit || !c.is_digit(10) {
- prev_was_digit = c.is_digit(10);
- continue;
+ let mut splits = full_version_line.rsplit(' ');
+ let version_string = splits.next().unwrap();
+
+ let mut splits = version_string.split('.');
+ let major = splits.next().unwrap();
+ let minor = splits.next().unwrap();
+ let patch = splits.next();
+
+ let major: u32 = major.parse().unwrap();
+ let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
+ None => {
+ let minor = minor.parse().unwrap();
+ let patch: u32 = match patch {
+ Some(patch) => match patch.find(not_a_digit) {
+ None => patch.parse().unwrap(),
+ Some(idx) if idx > 3 => 0,
+ Some(idx) => patch[..idx].parse().unwrap(),
+ },
+ None => 0,
+ };
+ (minor, patch)
}
-
- prev_was_digit = true;
-
- let line = &full_version_line[pos..];
-
- let next_split = match line.find(|c: char| !c.is_digit(10)) {
- Some(idx) => idx,
- None => continue, // no minor version
- };
-
- if line.as_bytes()[next_split] != b'.' {
- continue; // no minor version
+ // There is no patch version after minor-date (e.g. "4-2012").
+ Some(idx) => {
+ let minor = minor[..idx].parse().unwrap();
+ (minor, 0)
}
+ };
- let major = &line[..next_split];
- let line = &line[next_split + 1..];
-
- let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
- Some(idx) => {
- if line.as_bytes()[idx] == b'.' {
- let patch = &line[idx + 1..];
-
- let patch_len =
- patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len());
- let patch = &patch[..patch_len];
- let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
-
- (&line[..idx], patch)
- } else {
- (&line[..idx], None)
- }
- }
- None => (line, None),
- };
-
- if minor.is_empty() {
- continue;
- }
-
- let major: u32 = major.parse().unwrap();
- let minor: u32 = minor.parse().unwrap();
- let patch: u32 = patch.unwrap_or("0").parse().unwrap();
-
- return Some(((major * 1000) + minor) * 1000 + patch);
- }
-
- None
+ Some(((major * 1000) + minor) * 1000 + patch)
}
/// Returns (LLDB version, LLDB is rust-enabled)
-fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
+fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
// Extract the major LLDB version from the given version string.
// LLDB version strings are different for Apple and non-Apple platforms.
// The Apple variant looks like this:
// lldb-300.2.51 (new versions)
//
// We are only interested in the major version number, so this function
- // will return `Some("179")` and `Some("300")` respectively.
+ // will return `Some(179)` and `Some(300)` respectively.
//
// Upstream versions look like:
// lldb version 6.0.1
// normally fine because the only non-Apple version we test is
// rust-enabled.
- if let Some(ref full_version_line) = full_version_line {
- if !full_version_line.trim().is_empty() {
- let full_version_line = full_version_line.trim();
-
- for (pos, l) in full_version_line.char_indices() {
- if l != 'l' && l != 'L' {
- continue;
- }
- if pos + 5 >= full_version_line.len() {
- continue;
- }
- let l = full_version_line[pos + 1..].chars().next().unwrap();
- if l != 'l' && l != 'L' {
- continue;
- }
- let d = full_version_line[pos + 2..].chars().next().unwrap();
- if d != 'd' && d != 'D' {
- continue;
- }
- let b = full_version_line[pos + 3..].chars().next().unwrap();
- if b != 'b' && b != 'B' {
- continue;
- }
- let dash = full_version_line[pos + 4..].chars().next().unwrap();
- if dash != '-' {
- continue;
- }
-
- let vers = full_version_line[pos + 5..]
- .chars()
- .take_while(|c| c.is_digit(10))
- .collect::<String>();
- if !vers.is_empty() {
- return (Some(vers), full_version_line.contains("rust-enabled"));
- }
- }
+ let full_version_line = full_version_line.trim();
- if full_version_line.starts_with("lldb version ") {
- let vers = full_version_line[13..]
- .chars()
- .take_while(|c| c.is_digit(10))
- .collect::<String>();
- if !vers.is_empty() {
- return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
- }
- }
+ if let Some(apple_ver) =
+ full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
+ {
+ if let Some(idx) = apple_ver.find(not_a_digit) {
+ let version: u32 = apple_ver[..idx].parse().unwrap();
+ return Some((version, full_version_line.contains("rust-enabled")));
+ }
+ } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
+ if let Some(idx) = lldb_ver.find(not_a_digit) {
+ let version: u32 = lldb_ver[..idx].parse().unwrap();
+ return Some((version * 100, full_version_line.contains("rust-enabled")));
}
}
- (None, false)
+ None
+}
+
+fn not_a_digit(c: char) -> bool {
+ !c.is_digit(10)
}
+use super::header::extract_llvm_version;
use super::*;
#[test]
fn test_extract_gdb_version() {
- macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
+ macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$(
assert_eq!(extract_gdb_version($input), Some($expectation));
)*}}}
}
}
+#[test]
+fn test_extract_lldb_version() {
+ // Apple variants
+ assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false)));
+ assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false)));
+
+ // Upstream versions
+ assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false)));
+ assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false)));
+}
+
#[test]
fn is_test_test() {
assert_eq!(true, is_test(&OsString::from("a_test.rs")));
assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
}
+
+#[test]
+fn test_extract_llvm_version() {
+ assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102));
+ assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001));
+ assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301));
+ assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000));
+}
name = "error_index_generator"
version = "0.0.0"
edition = "2018"
-build = "build.rs"
[dependencies]
rustdoc = { path = "../../librustdoc" }
"MIT",
"Unlicense/MIT",
"Unlicense OR MIT",
- "0BSD OR MIT OR Apache-2.0", // adler license
];
/// These are exceptions to Rust's permissive licensing policy, and
("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde)
("bytesize", "Apache-2.0"), // cargo
("im-rc", "MPL-2.0+"), // cargo
+ ("adler32", "BSD-3-Clause AND Zlib"), // cargo dep that isn't used
("constant_time_eq", "CC0-1.0"), // rustfmt
("sized-chunks", "MPL-2.0+"), // cargo via im-rc
("bitmaps", "MPL-2.0+"), // cargo via im-rc
/// This list is here to provide a speed-bump to adding a new dependency to
/// rustc. Please check with the compiler team before adding an entry.
const PERMITTED_DEPENDENCIES: &[&str] = &[
- "addr2line",
- "adler",
+ "adler32",
"aho-corasick",
"annotate-snippets",
"ansi_term",
"atty",
"autocfg",
"backtrace",
+ "backtrace-sys",
"bitflags",
"block-buffer",
"block-padding",
"generic-array",
"getopts",
"getrandom",
- "gimli",
"hashbrown",
"hermit-abi",
"humantime",
"miniz_oxide",
"nodrop",
"num_cpus",
- "object",
"once_cell",
"opaque-debug",
"parking_lot",
"src/tools/rust-installer",
"src/tools/rustfmt",
"src/doc/book",
- "src/backtrace",
// Filter RLS output directories
"target/rls",
];
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label)
- Priority?
- Regression?
- Notify people/groups?
message_on_add = """\
@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues)
- Already discussed?
- Worth the meeting time?
- Add agenda entry:
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
Prepare agenda entry:
- Why nominated?
- Author, assignee?
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
Prepare agenda entry:
- Why nominated?
- Author, assignee?
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team)
- Prepare agenda entry:
- What is it waiting for?
- Important details?
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
- Notify people/groups?
- Assign if possible?
- Add to agenda:
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
Is issue assigned? If not:
- Try to find an assignee?
- Otherwise add to agenda: