url = https://github.com/rust-lang/rust-installer.git
[submodule "src/doc/nomicon"]
path = src/doc/nomicon
- url = https://github.com/rust-lang-nursery/nomicon.git
+ url = https://github.com/rust-lang/nomicon.git
[submodule "src/tools/cargo"]
path = src/tools/cargo
url = https://github.com/rust-lang/cargo.git
[submodule "src/doc/reference"]
path = src/doc/reference
- url = https://github.com/rust-lang-nursery/reference.git
+ url = https://github.com/rust-lang/reference.git
[submodule "src/doc/book"]
path = src/doc/book
url = https://github.com/rust-lang/book.git
url = https://github.com/rust-lang/rustc-guide.git
[submodule "src/doc/edition-guide"]
path = src/doc/edition-guide
- url = https://github.com/rust-lang-nursery/edition-guide.git
+ url = https://github.com/rust-lang/edition-guide.git
[submodule "src/llvm-project"]
path = src/llvm-project
url = https://github.com/rust-lang/llvm-project.git
[[package]]
name = "ammonia"
-version = "2.1.2"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "384d704f242a0a9faf793fff775a0be6ab9aa27edabffa097331d73779142520"
+checksum = "9e266e1f4be5ffa05309f650e2586fe1d3ae6034eb24025a7ae1dfecc330823a"
dependencies = [
"html5ever",
"lazy_static 1.3.0",
"maplit",
"matches",
"tendril",
- "url 1.7.2",
+ "url 2.1.0",
]
[[package]]
"crypto-hash",
"curl",
"curl-sys",
- "env_logger 0.7.0",
+ "env_logger 0.7.1",
"failure",
"filetime",
"flate2",
version = "0.0.0"
dependencies = [
"diff",
- "env_logger 0.7.0",
+ "env_logger 0.7.1",
"getopts",
"lazy_static 1.3.0",
"libc",
[[package]]
name = "env_logger"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
[[package]]
name = "html5ever"
-version = "0.23.0"
+version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ce65ac8028cf5a287a7dbf6c4e0a6cf2dcf022ed5b167a81bae66ebf599a8b7"
+checksum = "025483b0a1e4577bb28578318c886ee5f817dda6eb62473269349044406644cb"
dependencies = [
"log",
"mac",
"markup5ever",
- "proc-macro2 0.4.30",
- "quote 0.6.12",
- "syn 0.15.35",
+ "proc-macro2 1.0.3",
+ "quote 1.0.2",
+ "syn 1.0.5",
]
[[package]]
[[package]]
name = "jsonrpc-core"
-version = "13.1.0"
+version = "13.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd42951eb35079520ee29b7efbac654d85821b397ef88c8151600ef7e2d00217"
+checksum = "91d767c183a7e58618a609499d359ce3820700b3ebb4823a18c343b4a2a41a0d"
dependencies = [
"futures",
"log",
[[package]]
name = "markup5ever"
-version = "0.8.1"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1af46a727284117e09780d05038b1ce6fc9c76cc6df183c3dae5a8955a25e21"
+checksum = "65381d9d47506b8592b97c4efd936afcf673b09b059f2bef39c7211ee78b9d03"
dependencies = [
"log",
"phf",
[[package]]
name = "mdbook"
-version = "0.3.1"
+version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "949bb2acb2cff9fa5c375cf9c43e70b3dba0a974d9fe01c31285d7a84d2a0fa2"
+checksum = "9a070268274c566082efb6b2ace7743e43ba91a70d5c6982981e96d3c05ac81c"
dependencies = [
"ammonia",
"chrono",
version = "0.1.0"
dependencies = [
"byteorder",
- "cargo_metadata 0.8.0",
+ "cargo_metadata 0.9.0",
"colored",
"compiletest_rs",
"directories",
- "env_logger 0.6.2",
+ "env_logger 0.7.1",
"getrandom",
- "hex 0.3.2",
+ "hex 0.4.0",
"log",
"num-traits",
"rand 0.7.0",
[[package]]
name = "rls"
-version = "1.39.0"
+version = "1.40.0"
dependencies = [
"cargo",
"cargo_metadata 0.8.0",
"clippy_lints",
"crossbeam-channel",
"difference",
- "env_logger 0.6.2",
+ "env_logger 0.7.1",
"failure",
"futures",
"heck",
"num_cpus",
"ordslice",
"racer",
- "rand 0.6.1",
+ "rand 0.7.0",
"rayon",
"regex",
"rls-analysis",
"rls-rustc",
"rls-span",
"rls-vfs",
- "rustc-serialize",
"rustc-workspace-hack",
"rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfmt-nightly",
version = "0.6.0"
dependencies = [
"clippy_lints",
- "env_logger 0.6.2",
+ "env_logger 0.7.1",
"failure",
"futures",
"log",
- "rand 0.6.1",
+ "rand 0.7.0",
"rls-data",
"rls-ipc",
"serde",
"failure",
"mdbook",
"mdbook-linkcheck",
+ "rustc-workspace-hack",
]
[[package]]
"num_cpus",
]
-[[package]]
-name = "rustc-serialize"
-version = "0.3.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
-
[[package]]
name = "rustc-std-workspace-alloc"
version = "1.99.0"
"serde",
"serde_json",
"smallvec",
+ "syn 0.15.35",
"url 2.1.0",
"winapi 0.3.6",
]
name = "rustc_driver"
version = "0.0.0"
dependencies = [
- "env_logger 0.7.0",
+ "env_logger 0.7.1",
"graphviz",
"lazy_static 1.3.0",
"log",
"mips-unknown-linux-musl install directory")
v("musl-root-mipsel", "target.mipsel-unknown-linux-musl.musl-root",
"mipsel-unknown-linux-musl install directory")
+v("musl-root-mips64", "target.mips64-unknown-linux-muslabi64.musl-root",
+ "mips64-unknown-linux-muslabi64 install directory")
+v("musl-root-mips64el", "target.mips64el-unknown-linux-muslabi64.musl-root",
+ "mips64el-unknown-linux-muslabi64 install directory")
v("qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs",
"rootfs in qemu testing, you probably don't want to use this")
v("qemu-aarch64-rootfs", "target.aarch64-unknown-linux-gnu.qemu-rootfs",
/// done. The file is updated immediately after this function completes.
pub fn save_toolstate(&self, tool: &str, state: ToolState) {
if let Some(ref path) = self.config.save_toolstates {
+ if let Some(parent) = path.parent() {
+ // Ensure the parent directory always exists
+ t!(std::fs::create_dir_all(parent));
+ }
let mut file = t!(fs::OpenOptions::new()
.create(true)
.read(true)
builder.info("Building test helpers");
t!(fs::create_dir_all(&dst));
let mut cfg = cc::Build::new();
+ // FIXME: Workaround for https://github.com/emscripten-core/emscripten/issues/9013
+ if target.contains("emscripten") {
+ cfg.pic(false);
+ }
// We may have found various cross-compilers a little differently due to our
// extra configuration, so inform gcc of these compilers. Note, though, that
path.ends_with("rls") ||
path.ends_with("clippy") ||
path.ends_with("miri") ||
+ path.ends_with("rustbook") ||
path.ends_with("rustfmt")
{
cargo.env("LIBZ_SYS_STATIC", "1");
IMAGE: x86_64-gnu-aux
x86_64-gnu-tools:
IMAGE: x86_64-gnu-tools
+ DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
x86_64-gnu-debug:
IMAGE: x86_64-gnu-debug
x86_64-gnu-nopt:
# MSVC tools tests
x86_64-msvc-tools:
MSYS_BITS: 64
- SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstates.json windows
- RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstates.json
+ SCRIPT: src/ci/docker/x86_64-gnu-tools/checktools.sh x.py /tmp/toolstate/toolstates.json windows
+ RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
+ DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
# 32/64-bit MinGW builds.
#
IMAGE: x86_64-gnu-llvm-6.0
mingw-check:
IMAGE: mingw-check
-
-- job: LinuxTools
- timeoutInMinutes: 600
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: steps/run.yml
- parameters:
- only_on_updated_submodules: 'yes'
- variables:
- IMAGE: x86_64-gnu-tools
+ x86_64-gnu-tools:
+ IMAGE: x86_64-gnu-tools
+ CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
#
# Check travis config for `gdb --batch` command to print all crash logs
-parameters:
- # When this parameter is set to anything other than an empty string the tests
- # will only be executed when the commit updates submodules
- only_on_updated_submodules: ''
-
steps:
# Disable automatic line ending conversion, which is enabled by default on
- checkout: self
fetchDepth: 2
-# Set the SKIP_JOB environment variable if this job is supposed to only run
-# when submodules are updated and they were not. The following time consuming
-# tasks will be skipped when the environment variable is present.
-- ${{ if parameters.only_on_updated_submodules }}:
- - bash: |
- set -e
- # Submodules pseudo-files inside git have the 160000 permissions, so when
- # those files are present in the diff a submodule was updated.
- if git diff HEAD^ | grep "^index .* 160000" >/dev/null 2>&1; then
- echo "Executing the job since submodules are updated"
- else
- echo "Not executing this job since no submodules were updated"
- echo "##vso[task.setvariable variable=SKIP_JOB;]1"
- fi
- displayName: Decide whether to run this job
+- bash: src/ci/scripts/should-skip-this.sh
+ displayName: Decide whether to run this job
# Spawn a background process to collect CPU usage statistics which we'll upload
# at the end of the build. See the comments in the script here for more
condition: and(succeeded(), not(variables.SKIP_JOB))
displayName: Run build
-# If we're a deploy builder, use the `aws` command to publish everything to our
-# bucket.
-- bash: |
- set -e
- source src/ci/shared.sh
- if [ "$AGENT_OS" = "Linux" ]; then
- rm -rf obj/build/dist/doc
- upload_dir=obj/build/dist
- else
- rm -rf build/dist/doc
- upload_dir=build/dist
- fi
- ls -la $upload_dir
- deploy_dir=rustc-builds
- if [ "$DEPLOY_ALT" == "1" ]; then
- deploy_dir=rustc-builds-alt
- fi
- retry aws s3 cp --no-progress --recursive --acl public-read ./$upload_dir s3://$DEPLOY_BUCKET/$deploy_dir/$BUILD_SOURCEVERSION
+- bash: src/ci/scripts/upload-artifacts.sh
env:
AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID)
AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY)
- condition: and(succeeded(), not(variables.SKIP_JOB), or(eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')))
displayName: Upload artifacts
-
-# Upload CPU usage statistics that we've been gathering this whole time. Always
-# execute this step in case we want to inspect failed builds, but don't let
-# errors here ever fail the build since this is just informational.
-- bash: aws s3 cp --acl public-read cpu-usage.csv s3://$DEPLOY_BUCKET/rustc-builds/$BUILD_SOURCEVERSION/cpu-$CI_JOB_NAME.csv
- env:
- AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID)
- AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY)
- condition: variables['UPLOAD_AWS_SECRET_ACCESS_KEY']
- continueOnError: true
- displayName: Upload CPU usage statistics
+ # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy
+ # builders *should* have the AWS credentials available. Still, explicitly
+ # adding the condition is helpful as this way CI will not silently skip
+ # deploying artifacts from a dist builder if the variables are misconfigured,
+ # erroring about invalid credentials instead.
+ condition: |
+ and(
+ succeeded(), not(variables.SKIP_JOB),
+ or(
+ variables.UPLOAD_AWS_SECRET_ACCESS_KEY,
+ eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1')
+ )
+ )
g++-arm-linux-gnueabi \
g++-arm-linux-gnueabihf \
g++-aarch64-linux-gnu \
+ g++-mips64-linux-gnuabi64 \
+ g++-mips64el-linux-gnuabi64 \
gcc-sparc64-linux-gnu \
libc6-dev-sparc64-cross \
bzip2 \
CC=mipsel-openwrt-linux-gcc \
CXX=mipsel-openwrt-linux-g++ \
bash musl.sh mipsel && \
+ env \
+ CC=mips64-linux-gnuabi64-gcc \
+ CXX=mips64-linux-gnuabi64-g++ \
+ bash musl.sh mips64 && \
+ env \
+ CC=mips64el-linux-gnuabi64-gcc \
+ CXX=mips64el-linux-gnuabi64-g++ \
+ bash musl.sh mips64el && \
rm -rf /build/*
# FIXME(mozilla/sccache#235) this shouldn't be necessary but is currently
ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd
ENV TARGETS=$TARGETS,mips-unknown-linux-musl
ENV TARGETS=$TARGETS,mipsel-unknown-linux-musl
+ENV TARGETS=$TARGETS,mips64-unknown-linux-muslabi64
+ENV TARGETS=$TARGETS,mips64el-unknown-linux-muslabi64
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabi
ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf
ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi
ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
+ CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \
+ CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \
CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \
CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \
CC_thumbv7neon_unknown_linux_gnueabihf=arm-linux-gnueabihf-gcc \
--musl-root-aarch64=/musl-aarch64 \
--musl-root-mips=/musl-mips \
--musl-root-mipsel=/musl-mipsel \
+ --musl-root-mips64=/musl-mips64 \
+ --musl-root-mips64el=/musl-mips64el \
--disable-docs
ENV SCRIPT \
mkdir -p $HOME/.cargo
mkdir -p $objdir/tmp
mkdir -p $objdir/cores
+mkdir -p /tmp/toolstate
args=
if [ "$SCCACHE_BUCKET" != "" ]; then
args="$args --volume $objdir:/checkout/obj"
args="$args --volume $HOME/.cargo:/cargo"
args="$args --volume $HOME/rustsrc:$HOME/rustsrc"
+ args="$args --volume /tmp/toolstate:/tmp/toolstate"
args="$args --env LOCAL_USER_ID=`id -u`"
fi
ENV RUST_CONFIGURE_ARGS \
--build=x86_64-unknown-linux-gnu \
- --save-toolstates=/tmp/toolstates.json
-ENV SCRIPT /tmp/checktools.sh ../x.py /tmp/toolstates.json linux
+ --save-toolstates=/tmp/toolstate/toolstates.json
+ENV SCRIPT /tmp/checktools.sh ../x.py /tmp/toolstate/toolstates.json linux
set -eu
X_PY="$1"
-TOOLSTATE_FILE="$(realpath $2)"
+TOOLSTATE_FILE="$(realpath -m $2)"
OS="$3"
COMMIT="$(git rev-parse HEAD)"
CHANGED_FILES="$(git diff --name-status HEAD HEAD^)"
# The Wednesday after this has value 0.
# We track this value to prevent regressing tools in the last week of the 6-week cycle.
+mkdir -p "$(dirname $TOOLSTATE_FILE)"
touch "$TOOLSTATE_FILE"
# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
if isWindows; then
pacman -S --noconfirm --needed base-devel ca-certificates make diffutils tar
- # FIXME(#65767): workaround msys bug, step 2
- arch=i686
- if [ "$MSYS_BITS" = "64" ]; then
- arch=x86_64
- fi
- pacman -U --noconfirm --noprogressbar mingw-w64-$arch-ca-certificates-20180409-1-any.pkg.tar.xz
- rm mingw-w64-$arch-ca-certificates-20180409-1-any.pkg.tar.xz
-
# Make sure we use the native python interpreter instead of some msys equivalent
# one way or another. The msys interpreters seem to have weird path conversions
# baked in which break LLVM's build system one way or another, so let's use the
#!/bin/bash
-# ignore-tidy-linelength
# Download and install MSYS2, needed primarily for the test suite (run-make) but
# also used by the MinGW toolchain for assembling things.
#
source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
if isWindows; then
- # FIXME(#65767): workaround msys bug, step 1
- arch=i686
- if [ "$MSYS_BITS" = "64" ]; then
- arch=x86_64
- fi
- curl -O "${MIRRORS_BASE}/msys2-repo/mingw/$arch/mingw-w64-$arch-ca-certificates-20180409-1-any.pkg.tar.xz"
-
choco install msys2 --params="/InstallDir:${SYSTEM_WORKFOLDER}/msys2 /NoPath" -y --no-progress
mkdir -p "${SYSTEM_WORKFOLDER}/msys2/home/${USERNAME}"
--- /dev/null
+#!/bin/bash
+# Set the SKIP_JOB environment variable if this job is supposed to only run
+# when submodules are updated and they were not. The following time consuming
+# tasks will be skipped when the environment variable is present.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+if [[ -z "${CI_ONLY_WHEN_SUBMODULES_CHANGED+x}" ]]; then
+ echo "Executing the job since there is no skip rule in effect"
+elif git diff HEAD^ | grep --quiet "^index .* 160000"; then
+ # Submodules pseudo-files inside git have the 160000 permissions, so when
+ # those files are present in the diff a submodule was updated.
+ echo "Executing the job since submodules are updated"
+else
+ echo "Not executing this job since no submodules were updated"
+ ciCommandSetEnv SKIP_JOB 1
+fi
--- /dev/null
+#!/bin/bash
+# Upload all the artifacts to our S3 bucket. All the files inside ${upload_dir}
+# will be uploaded to the deploy bucket and eventually signed and released in
+# static.rust-lang.org.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
+
+upload_dir="$(mktemp -d)"
+
+# Release tarballs produced by a dist builder.
+if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then
+ dist_dir=build/dist
+ if isLinux; then
+ dist_dir=obj/build/dist
+ fi
+ rm -rf "${dist_dir}/doc"
+ cp -r "${dist_dir}"/* "${upload_dir}"
+fi
+
+# CPU usage statistics.
+cp cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv"
+
+# Toolstate data.
+if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then
+ cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}"
+fi
+
+echo "Files that will be uploaded:"
+ls -lah "${upload_dir}"
+echo
+
+deploy_dir="rustc-builds"
+if [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then
+ deploy_dir="rustc-builds-alt"
+fi
+deploy_url="s3://${DEPLOY_BUCKET}/${deploy_dir}/$(ciCommit)"
+
+retry aws s3 cp --no-progress --recursive --acl public-read "${upload_dir}" "${deploy_url}"
echo "$BUILD_SOURCEBRANCHNAME"
}
+function ciCommit {
+ echo "${BUILD_SOURCEVERSION}"
+}
+
function ciCommandAddPath {
if [[ $# -ne 1 ]]; then
echo "usage: $0 <path>"
-Subproject commit 9bb8b161963fcebc9d9ccd732ba26f42108016d5
+Subproject commit 28fa3d15b0bc67ea5e79eeff2198e4277fc61baf
-Subproject commit 5b9d2fcefadfc32fceafacfc0dd9441d9b57dd94
+Subproject commit 4b21b646669e0af49fae7cae301898dc4bfaa1f0
-Subproject commit 0b111eaae36cc4b4997684be853882a59e2c7ca7
+Subproject commit f3197ddf2abab9abdbc029def8164f4a748b0d91
Not only are fenced code blocks considered more idiomatic for Rust code,
but there is no way to use directives such as `ignore` or `should_panic` with
indented code blocks.
+
+### Include items only when collecting doctests
+
+Rustdoc's documentation tests can do some things that regular unit tests can't, so it can
+sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
+documentation. To this end, Rustdoc allows you to have certain items only appear when it's
+collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
+docs, or to find an arbitrary private item to include it on.
+
+When compiling a crate for use in doctests (with `--test` option), rustdoc will set `cfg(doctest)`.
+Note that they will still link against only the public items of your crate; if you need to test
+private items, you need to write a unit test.
+
+In this example, we're adding doctests that we know won't compile, to verify that our struct can
+only take in valid data:
+
+```rust
+/// We have a struct here. Remember it doesn't accept negative numbers!
+pub struct MyStruct(pub usize);
+
+/// ```compile_fail
+/// let x = my_crate::MyStruct(-5);
+/// ```
+#[cfg(doctest)]
+pub struct MyStructOnlyTakesUsize;
+```
+
+Note that the struct `MyStructOnlyTakesUsize` here isn't actually part of your public crate
+API. The use of `#[cfg(doctest)]` makes sure that this struct only exists while rustdoc is
+collecting doctests. This means that its doctest is executed when `--test` is passed to rustdoc,
+but is hidden from the public documentation.
+
+Another possible use of `cfg(doctest)` is to test doctests that are included in your README file
+without including it in your main documentation. For example, you could write this into your
+`lib.rs` to test your README as part of your doctests:
+
+```rust,ignore
+#![feature(extern_doc)]
+
+#[doc(include="../README.md")]
+#[cfg(doctest)]
+pub struct ReadmeDoctests;
+```
+
+This will include your README as documentation on the hidden struct `ReadmeDoctests`, which will
+then be tested alongside the rest of your doctests.
Then, when looking for it through the `rustdoc` search, if you enter "x" or
"big", search will show the `BigX` struct first.
-### Include items only when collecting doctests
-
-Rustdoc's [documentation tests] can do some things that regular unit tests can't, so it can
-sometimes be useful to extend your doctests with samples that wouldn't otherwise need to be in
-documentation. To this end, Rustdoc allows you to have certain items only appear when it's
-collecting doctests, so you can utilize doctest functionality without forcing the test to appear in
-docs, or to find an arbitrary private item to include it on.
-
-If you add `#![feature(cfg_doctest)]` to your crate, Rustdoc will set `cfg(doctest)` when collecting
-doctests. Note that they will still link against only the public items of your crate; if you need to
-test private items, unit tests are still the way to go.
-
-In this example, we're adding doctests that we know won't compile, to verify that our struct can
-only take in valid data:
-
-```rust
-#![feature(cfg_doctest)]
-
-/// We have a struct here. Remember it doesn't accept negative numbers!
-pub struct MyStruct(usize);
-
-/// ```compile_fail
-/// let x = my_crate::MyStruct(-5);
-/// ```
-#[cfg(doctest)]
-pub struct MyStructOnlyTakesUsize;
-```
-
-[documentation tests]: documentation-tests.html
-
## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
- Runtime
- `start`: `libstd/rt.rs`
- `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
- - `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
+ - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
- - `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
- - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
+ - `eh_catch_typeinfo`: `libpanic_unwind/seh.rs` (SEH)
+ - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)
- `panic`: `libcore/panicking.rs`
- `panic_bounds_check`: `libcore/panicking.rs`
- `panic_impl`: `libcore/panicking.rs`
#![stable(feature = "rust1", since = "1.0.0")]
use core::ops::{Deref, DerefMut};
-use core::iter::{FromIterator, FusedIterator};
+use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::mem::{swap, size_of, ManuallyDrop};
use core::ptr;
use core::fmt;
self.extend(other.drain());
}
}
+
+ /// Returns an iterator which retrieves elements in heap order.
+ /// The retrieved elements are removed from the original heap.
+ /// The remaining elements will be removed on drop in heap order.
+ ///
+ /// Note:
+ /// * `.drain_sorted()` is O(n lg n); much slower than `.drain()`.
+ /// You should use the latter for most cases.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_drain_sorted)]
+ /// use std::collections::BinaryHeap;
+ ///
+ /// let mut heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+ /// assert_eq!(heap.len(), 5);
+ ///
+ /// drop(heap.drain_sorted()); // removes all elements in heap order
+ /// assert_eq!(heap.len(), 0);
+ /// ```
+ #[inline]
+ #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+ pub fn drain_sorted(&mut self) -> DrainSorted<'_, T> {
+ DrainSorted {
+ inner: self,
+ }
+ }
}
impl<T> BinaryHeap<T> {
Iter { iter: self.data.iter() }
}
+ /// Returns an iterator which retrieves elements in heap order.
+ /// This method consumes the original heap.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(binary_heap_into_iter_sorted)]
+ /// use std::collections::BinaryHeap;
+ /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+ ///
+ /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
+ /// ```
+ #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+ pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
+ IntoIterSorted {
+ inner: self,
+ }
+ }
+
/// Returns the greatest item in the binary heap, or `None` if it is empty.
///
/// # Examples
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for IntoIter<T> {}
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+#[derive(Clone, Debug)]
+pub struct IntoIterSorted<T> {
+ inner: BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> Iterator for IntoIterSorted<T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.inner.pop()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = self.inner.len();
+ (exact, Some(exact))
+ }
+}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for IntoIterSorted<T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for IntoIterSorted<T> {}
+
/// A draining iterator over the elements of a `BinaryHeap`.
///
/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its
#[stable(feature = "fused", since = "1.26.0")]
impl<T> FusedIterator for Drain<'_, T> {}
+/// A draining iterator over the elements of a `BinaryHeap`.
+///
+/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its
+/// documentation for more.
+///
+/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted
+/// [`BinaryHeap`]: struct.BinaryHeap.html
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+#[derive(Debug)]
+pub struct DrainSorted<'a, T: Ord> {
+ inner: &'a mut BinaryHeap<T>,
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<'a, T: Ord> Drop for DrainSorted<'a, T> {
+ /// Removes heap elements in heap order.
+ fn drop(&mut self) {
+ while let Some(_) = self.inner.pop() {}
+ }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> Iterator for DrainSorted<'_, T> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ self.inner.pop()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = self.inner.len();
+ (exact, Some(exact))
+ }
+}
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> ExactSizeIterator for DrainSorted<'_, T> { }
+
+#[unstable(feature = "binary_heap_drain_sorted", issue = "59278")]
+impl<T: Ord> FusedIterator for DrainSorted<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T: Ord> TrustedLen for DrainSorted<'_, T> {}
+
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
/// Converts a `Vec<T>` into a `BinaryHeap<T>`.
use std::collections::BinaryHeap;
use std::collections::binary_heap::{Drain, PeekMut};
+use std::iter::TrustedLen;
#[test]
fn test_iterator() {
}
#[test]
-fn test_iterator_reverse() {
+fn test_iter_rev_cloned_collect() {
let data = vec![5, 9, 3];
let iterout = vec![3, 5, 9];
let pq = BinaryHeap::from(data);
}
#[test]
-fn test_move_iter() {
+fn test_into_iter_collect() {
let data = vec![5, 9, 3];
let iterout = vec![9, 5, 3];
let pq = BinaryHeap::from(data);
}
#[test]
-fn test_move_iter_size_hint() {
+fn test_into_iter_size_hint() {
let data = vec![5, 9];
let pq = BinaryHeap::from(data);
}
#[test]
-fn test_move_iter_reverse() {
+fn test_into_iter_rev_collect() {
let data = vec![5, 9, 3];
let iterout = vec![3, 5, 9];
let pq = BinaryHeap::from(data);
assert_eq!(v, iterout);
}
+#[test]
+fn test_into_iter_sorted_collect() {
+ let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+ let it = heap.into_iter_sorted();
+ let sorted = it.collect::<Vec<_>>();
+ assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+#[test]
+fn test_drain_sorted_collect() {
+ let mut heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+ let it = heap.drain_sorted();
+ let sorted = it.collect::<Vec<_>>();
+ assert_eq!(sorted, vec![10, 9, 8, 7, 6, 5, 4, 3, 2, 2, 1, 1, 0]);
+}
+
+fn check_exact_size_iterator<I: ExactSizeIterator>(len: usize, it: I) {
+ let mut it = it;
+
+ for i in 0..it.len() {
+ let (lower, upper) = it.size_hint();
+ assert_eq!(Some(lower), upper);
+ assert_eq!(lower, len - i);
+ assert_eq!(it.len(), len - i);
+ it.next();
+ }
+ assert_eq!(it.len(), 0);
+ assert!(it.is_empty());
+}
+
+#[test]
+fn test_exact_size_iterator() {
+ let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+ check_exact_size_iterator(heap.len(), heap.iter());
+ check_exact_size_iterator(heap.len(), heap.clone().into_iter());
+ check_exact_size_iterator(heap.len(), heap.clone().into_iter_sorted());
+ check_exact_size_iterator(heap.len(), heap.clone().drain());
+ check_exact_size_iterator(heap.len(), heap.clone().drain_sorted());
+}
+
+fn check_trusted_len<I: TrustedLen>(len: usize, it: I) {
+ let mut it = it;
+ for i in 0..len {
+ let (lower, upper) = it.size_hint();
+ if upper.is_some() {
+ assert_eq!(Some(lower), upper);
+ assert_eq!(lower, len - i);
+ }
+ it.next();
+ }
+}
+
+#[test]
+fn test_trusted_len() {
+ let heap = BinaryHeap::from(vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
+ check_trusted_len(heap.len(), heap.clone().into_iter_sorted());
+ check_trusted_len(heap.len(), heap.clone().drain_sorted());
+}
+
#[test]
fn test_peek_and_pop() {
let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
assert!(q.is_empty());
}
+#[test]
+fn test_drain_sorted() {
+ let mut q: BinaryHeap<_> = [9, 8, 7, 6, 5, 4, 3, 2, 1].iter().cloned().collect();
+
+ assert_eq!(q.drain_sorted().take(5).collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
+
+ assert!(q.is_empty());
+}
+
#[test]
fn test_extend_ref() {
let mut a = BinaryHeap::new();
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(associated_type_bounds)]
+#![feature(binary_heap_into_iter_sorted)]
+#![feature(binary_heap_drain_sorted)]
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
/// stabilized, it is recommended to use a newtype wrapper around an empty
/// byte array. See the [Nomicon] for details.
///
+/// One could use `std::os::raw::c_void` if they want to support old Rust
+/// compiler down to 1.1.0. After Rust 1.30.0, it was re-exported by
+/// this definition. For more information, please read [RFC 2521].
+///
/// [pointer]: ../../std/primitive.pointer.html
/// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
+/// [RFC 2521]: https://github.com/rust-lang/rfcs/blob/master/text/2521-c_void-reunification.md
// N.B., for LLVM to recognize the void pointer type and by extension
// functions like malloc(), we need to have it represented as i8* in
// LLVM bitcode. The enum used here ensures this and prevents misuse
// would be uninhabited and at least dereferencing such pointers would
// be UB.
#[repr(u8)]
-#[stable(feature = "raw_os", since = "1.1.0")]
+#[stable(feature = "core_c_void", since = "1.30.0")]
pub enum c_void {
#[unstable(feature = "c_void_variant", reason = "temporary implementation detail",
issue = "0")]
/// Emits a `!nontemporal` store according to LLVM (see their docs).
/// Probably will never become stable.
pub fn nontemporal_store<T>(ptr: *mut T, val: T);
+
+ /// See documentation of `<*const T>::offset_from` for details.
+ #[cfg(not(bootstrap))]
+ pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
}
// Some functions are defined here because they accidentally got made
//!
//! let mut counter = Counter::new();
//!
-//! let x = counter.next().unwrap();
-//! println!("{}", x);
-//!
-//! let x = counter.next().unwrap();
-//! println!("{}", x);
-//!
-//! let x = counter.next().unwrap();
-//! println!("{}", x);
-//!
-//! let x = counter.next().unwrap();
-//! println!("{}", x);
-//!
-//! let x = counter.next().unwrap();
-//! println!("{}", x);
+//! assert_eq!(counter.next(), Some(1));
+//! assert_eq!(counter.next(), Some(2));
+//! assert_eq!(counter.next(), Some(3));
+//! assert_eq!(counter.next(), Some(4));
+//! assert_eq!(counter.next(), Some(5));
+//! assert_eq!(counter.next(), None);
//! ```
//!
-//! This will print `1` through `5`, each on their own line.
-//!
-//! Calling `next()` this way gets repetitive. Rust has a construct which can
-//! call `next()` on your iterator, until it reaches `None`. Let's go over that
+//! Calling [`next`] this way gets repetitive. Rust has a construct which can
+//! call [`next`] on your iterator, until it reaches `None`. Let's go over that
//! next.
//!
//! Also note that `Iterator` provides a default implementation of methods such as `nth` and `fold`
//! ```
//!
//! The idiomatic way to write a [`map`] for its side effects is to use a
-//! `for` loop instead:
+//! `for` loop or call the [`for_each`] method:
//!
//! ```
//! let v = vec![1, 2, 3, 4, 5];
//!
+//! v.iter().for_each(|x| println!("{}", x));
+//! // or
//! for x in &v {
//! println!("{}", x);
//! }
//! ```
//!
//! [`map`]: trait.Iterator.html#method.map
+//! [`for_each`]: trait.Iterator.html#method.for_each
//!
-//! The two most common ways to evaluate an iterator are to use a `for` loop
-//! like this, or using the [`collect`] method to produce a new collection.
+//! Another common way to evaluate an iterator is to use the [`collect`]
+//! method to produce a new collection.
//!
//! [`collect`]: trait.Iterator.html#method.collect
//!
#[allow(unused)]
use prelude::v1::*;
+#[cfg(not(test))] // See #65860
#[macro_use]
mod macros;
/* Core language traits */
+#[cfg(not(test))] // See #65860
pub mod marker;
pub mod ops;
+#[cfg(not(test))] // See #65860
pub mod cmp;
+#[cfg(not(test))] // See #65860
pub mod clone;
+#[cfg(not(test))] // See #65860
pub mod default;
pub mod convert;
pub mod borrow;
/* Core types and methods on primitives */
pub mod any;
+#[cfg(not(test))] // See #65860
pub mod array;
pub mod ascii;
pub mod sync;
pub mod char;
pub mod panic;
pub mod panicking;
+#[cfg(not(test))] // See #65860
pub mod pin;
+#[cfg(not(test))] // See #65860
pub mod iter;
pub mod option;
pub mod raw;
pub mod ffi;
pub mod slice;
+#[cfg(not(test))] // See #65860
pub mod str;
+#[cfg(not(test))] // See #65860
pub mod hash;
+#[cfg(not(test))] // See #65860
pub mod fmt;
pub mod time;
pub mod unicode;
/* Async */
+#[cfg(not(test))] // See #65860
pub mod future;
pub mod task;
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f32.to_be_bytes();
/// assert_eq!(bytes, [0x41, 0x48, 0x00, 0x00]);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_be_bytes(self) -> [u8; 4] {
self.to_bits().to_be_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f32.to_le_bytes();
/// assert_eq!(bytes, [0x00, 0x00, 0x48, 0x41]);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_le_bytes(self) -> [u8; 4] {
self.to_bits().to_le_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f32.to_ne_bytes();
/// assert_eq!(
/// bytes,
/// }
/// );
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_ne_bytes(self) -> [u8; 4] {
self.to_bits().to_ne_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f32::from_be_bytes([0x41, 0x48, 0x00, 0x00]);
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_be_bytes(bytes: [u8; 4]) -> Self {
Self::from_bits(u32::from_be_bytes(bytes))
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f32::from_le_bytes([0x00, 0x00, 0x48, 0x41]);
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_le_bytes(bytes: [u8; 4]) -> Self {
Self::from_bits(u32::from_le_bytes(bytes))
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f32::from_ne_bytes(if cfg!(target_endian = "big") {
/// [0x41, 0x48, 0x00, 0x00]
/// } else {
/// });
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_ne_bytes(bytes: [u8; 4]) -> Self {
Self::from_bits(u32::from_ne_bytes(bytes))
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f64.to_be_bytes();
/// assert_eq!(bytes, [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_be_bytes(self) -> [u8; 8] {
self.to_bits().to_be_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f64.to_le_bytes();
/// assert_eq!(bytes, [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_le_bytes(self) -> [u8; 8] {
self.to_bits().to_le_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let bytes = 12.5f64.to_ne_bytes();
/// assert_eq!(
/// bytes,
/// }
/// );
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn to_ne_bytes(self) -> [u8; 8] {
self.to_bits().to_ne_bytes()
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f64::from_be_bytes([0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_be_bytes(bytes: [u8; 8]) -> Self {
Self::from_bits(u64::from_be_bytes(bytes))
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f64::from_le_bytes([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40]);
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_le_bytes(bytes: [u8; 8]) -> Self {
Self::from_bits(u64::from_le_bytes(bytes))
/// # Examples
///
/// ```
- /// #![feature(float_to_from_bytes)]
/// let value = f64::from_ne_bytes(if cfg!(target_endian = "big") {
/// [0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
/// } else {
/// });
/// assert_eq!(value, 12.5);
/// ```
- #[unstable(feature = "float_to_from_bytes", issue = "60446")]
+ #[stable(feature = "float_to_from_bytes", since = "1.40.0")]
#[inline]
pub fn from_ne_bytes(bytes: [u8; 8]) -> Self {
Self::from_bits(u64::from_ne_bytes(bytes))
/// extracting those success or failure values from an existing instance and
/// creating a new instance from a success or failure value.
#[unstable(feature = "try_trait", issue = "42327")]
-#[rustc_on_unimplemented(
+#[cfg_attr(bootstrap, rustc_on_unimplemented(
on(all(
any(from_method="from_error", from_method="from_ok"),
from_desugaring="QuestionMark"),
message="the `?` operator can only be applied to values \
that implement `{Try}`",
label="the `?` operator cannot be applied to type `{Self}`")
-)]
+))]
+#[cfg_attr(not(bootstrap), rustc_on_unimplemented(
+on(all(
+any(from_method="from_error", from_method="from_ok"),
+from_desugaring="QuestionMark"),
+message="the `?` operator can only be used in {ItemContext} \
+ that returns `Result` or `Option` \
+ (or another type that implements `{Try}`)",
+label="cannot use the `?` operator in {ItemContext} that returns `{Self}`"),
+on(all(from_method="into_result", from_desugaring="QuestionMark"),
+message="the `?` operator can only be applied to values \
+ that implement `{Try}`",
+label="the `?` operator cannot be applied to type `{Self}`")
+))]
#[doc(alias = "?")]
pub trait Try {
/// The type of this value when viewed as successful.
/// }
/// ```
#[unstable(feature = "ptr_offset_from", issue = "41079")]
+ #[cfg(not(bootstrap))]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from")]
#[inline]
+ pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
+ let pointee_size = mem::size_of::<T>();
+ let ok = 0 < pointee_size && pointee_size <= isize::max_value() as usize;
+ // assert that the pointee size is valid in a const eval compatible way
+ // FIXME: do this with a real assert at some point
+ [()][(!ok) as usize];
+ intrinsics::ptr_offset_from(self, origin)
+ }
+
+ #[unstable(feature = "ptr_offset_from", issue = "41079")]
+ #[inline]
+ #[cfg(bootstrap)]
+ /// bootstrap
pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
let pointee_size = mem::size_of::<T>();
assert!(0 < pointee_size && pointee_size <= isize::max_value() as usize);
/// }
/// ```
#[unstable(feature = "ptr_offset_from", issue = "41079")]
+ #[rustc_const_unstable(feature = "const_ptr_offset_from")]
#[inline]
- pub unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
+ pub const unsafe fn offset_from(self, origin: *const T) -> isize where T: Sized {
(self as *const T).offset_from(origin)
}
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
-pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
+pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>, foreign_exception: bool)
-> Result<EHAction, ()>
{
if lsda.is_null() {
return Ok(EHAction::None)
} else {
let lpad = lpad_base + cs_lpad;
- return Ok(interpret_cs_action(cs_action, lpad))
+ return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
}
}
}
// Can never have null landing pad for sjlj -- that would have
// been indicated by a -1 call site index.
let lpad = (cs_lpad + 1) as usize;
- return Ok(interpret_cs_action(cs_action, lpad))
+ return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
}
}
}
}
-fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
+fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction {
if cs_action == 0 {
+ // If cs_action is 0 then this is a cleanup (Drop::drop). We run these
+ // for both Rust panics and foriegn exceptions.
EHAction::Cleanup(lpad)
+ } else if foreign_exception {
+ // catch_unwind should not catch foreign exceptions, only Rust panics.
+ // Instead just continue unwinding.
+ EHAction::None
} else {
+ // Stop unwinding Rust panics at catch_unwind.
EHAction::Catch(lpad)
}
}
use libc::{self, c_int};
use unwind as uw;
+// This matches the layout of std::type_info in C++
+#[repr(C)]
+struct TypeInfo {
+ vtable: *const usize,
+ name: *const u8,
+}
+unsafe impl Sync for TypeInfo {}
+
+extern "C" {
+ // The leading `\x01` byte here is actually a magical signal to LLVM to
+ // *not* apply any other mangling like prefixing with a `_` character.
+ //
+ // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
+ // `std::type_info`, type descriptors, have a pointer to this table. Type
+ // descriptors are referenced by the C++ EH structures defined above and
+ // that we construct below.
+ //
+ // Note that the real size is larger than 3 usize, but we only need our
+ // vtable to point to the third element.
+ #[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
+ static CLASS_TYPE_INFO_VTABLE: [usize; 3];
+}
+
+// std::type_info for a rust_panic class
+#[lang = "eh_catch_typeinfo"]
+static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
+ // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
+ vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
+ // This intentionally doesn't use the normal name mangling scheme because
+ // we don't want C++ to be able to produce or catch Rust panics.
+ name: b"rust_panic\0".as_ptr(),
+};
+
pub fn payload() -> *mut u8 {
ptr::null_mut()
}
pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
assert!(!ptr.is_null());
- let ex = ptr::read(ptr as *mut _);
- __cxa_free_exception(ptr as *mut _);
+ let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void);
+ let ex = ptr::read(adjusted_ptr as *mut _);
+ __cxa_end_catch();
ex
}
if exception == ptr::null_mut() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
- let exception = exception as *mut Box<dyn Any + Send>;
- ptr::write(exception, data);
- __cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());
-
- unreachable!()
+ ptr::write(exception as *mut _, data);
+ __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, ptr::null_mut());
}
#[lang = "eh_personality"]
extern "C" {
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
- fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
+ fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
+ fn __cxa_end_catch();
fn __cxa_throw(thrown_exception: *mut libc::c_void,
- tinfo: *mut libc::c_void,
- dest: *mut libc::c_void);
+ tinfo: *const TypeInfo,
+ dest: *mut libc::c_void) -> !;
fn __gxx_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
// https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c
-// The personality routine for most of our targets, except ARM, which has a slightly different ABI
-// (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation
-// lives in seh64_gnu.rs
-#[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))]
-#[lang = "eh_personality"]
-#[no_mangle]
-#[allow(unused)]
-unsafe extern "C" fn rust_eh_personality(version: c_int,
- actions: uw::_Unwind_Action,
- exception_class: uw::_Unwind_Exception_Class,
- exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- if version != 1 {
- return uw::_URC_FATAL_PHASE1_ERROR;
- }
- let eh_action = match find_eh_action(context) {
- Ok(action) => action,
- Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
- };
- if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
- match eh_action {
- EHAction::None |
- EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
- EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
- EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
- }
- } else {
- match eh_action {
- EHAction::None => uw::_URC_CONTINUE_UNWIND,
- EHAction::Cleanup(lpad) |
- EHAction::Catch(lpad) => {
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
- uw::_Unwind_SetIP(context, lpad);
- uw::_URC_INSTALL_CONTEXT
- }
- EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
- }
- }
-}
+cfg_if::cfg_if! {
+ if #[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] {
+ // ARM EHABI personality routine.
+ // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
+ //
+ // iOS uses the default routine instead since it uses SjLj unwinding.
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ let state = state as c_int;
+ let action = state & uw::_US_ACTION_MASK as c_int;
+ let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
+ // Backtraces on ARM will call the personality routine with
+ // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
+ // we want to continue unwinding the stack, otherwise all our backtraces
+ // would end at __rust_try
+ if state & uw::_US_FORCE_UNWIND as c_int != 0 {
+ return continue_unwind(exception_object, context);
+ }
+ true
+ } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
+ false
+ } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
+ return continue_unwind(exception_object, context);
+ } else {
+ return uw::_URC_FAILURE;
+ };
-// ARM EHABI personality routine.
-// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf
-#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))]
-#[lang = "eh_personality"]
-#[no_mangle]
-unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State,
- exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- let state = state as c_int;
- let action = state & uw::_US_ACTION_MASK as c_int;
- let search_phase = if action == uw::_US_VIRTUAL_UNWIND_FRAME as c_int {
- // Backtraces on ARM will call the personality routine with
- // state == _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND. In those cases
- // we want to continue unwinding the stack, otherwise all our backtraces
- // would end at __rust_try
- if state & uw::_US_FORCE_UNWIND as c_int != 0 {
- return continue_unwind(exception_object, context);
- }
- true
- } else if action == uw::_US_UNWIND_FRAME_STARTING as c_int {
- false
- } else if action == uw::_US_UNWIND_FRAME_RESUME as c_int {
- return continue_unwind(exception_object, context);
- } else {
- return uw::_URC_FAILURE;
- };
+ // The DWARF unwinder assumes that _Unwind_Context holds things like the function
+ // and LSDA pointers, however ARM EHABI places them into the exception object.
+ // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
+ // take only the context pointer, GCC personality routines stash a pointer to
+ // exception_object in the context, using location reserved for ARM's
+ // "scratch register" (r12).
+ uw::_Unwind_SetGR(context,
+ uw::UNWIND_POINTER_REG,
+ exception_object as uw::_Unwind_Ptr);
+ // ...A more principled approach would be to provide the full definition of ARM's
+ // _Unwind_Context in our libunwind bindings and fetch the required data from there
+ // directly, bypassing DWARF compatibility functions.
- // The DWARF unwinder assumes that _Unwind_Context holds things like the function
- // and LSDA pointers, however ARM EHABI places them into the exception object.
- // To preserve signatures of functions like _Unwind_GetLanguageSpecificData(), which
- // take only the context pointer, GCC personality routines stash a pointer to exception_object
- // in the context, using location reserved for ARM's "scratch register" (r12).
- uw::_Unwind_SetGR(context,
- uw::UNWIND_POINTER_REG,
- exception_object as uw::_Unwind_Ptr);
- // ...A more principled approach would be to provide the full definition of ARM's
- // _Unwind_Context in our libunwind bindings and fetch the required data from there directly,
- // bypassing DWARF compatibility functions.
+ let exception_class = (*exception_object).exception_class;
+ let foreign_exception = exception_class != rust_exception_class();
+ let eh_action = match find_eh_action(context, foreign_exception) {
+ Ok(action) => action,
+ Err(_) => return uw::_URC_FAILURE,
+ };
+ if search_phase {
+ match eh_action {
+ EHAction::None |
+ EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
+ EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
+ EHAction::Terminate => return uw::_URC_FAILURE,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => return continue_unwind(exception_object, context),
+ EHAction::Cleanup(lpad) |
+ EHAction::Catch(lpad) => {
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
+ exception_object as uintptr_t);
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+ uw::_Unwind_SetIP(context, lpad);
+ return uw::_URC_INSTALL_CONTEXT;
+ }
+ EHAction::Terminate => return uw::_URC_FAILURE,
+ }
+ }
- let eh_action = match find_eh_action(context) {
- Ok(action) => action,
- Err(_) => return uw::_URC_FAILURE,
- };
- if search_phase {
- match eh_action {
- EHAction::None |
- EHAction::Cleanup(_) => return continue_unwind(exception_object, context),
- EHAction::Catch(_) => return uw::_URC_HANDLER_FOUND,
- EHAction::Terminate => return uw::_URC_FAILURE,
+ // On ARM EHABI the personality routine is responsible for actually
+ // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
+ unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
+ uw::_URC_CONTINUE_UNWIND
+ } else {
+ uw::_URC_FAILURE
+ }
+ }
+ // defined in libgcc
+ extern "C" {
+ fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code;
+ }
}
} else {
- match eh_action {
- EHAction::None => return continue_unwind(exception_object, context),
- EHAction::Cleanup(lpad) |
- EHAction::Catch(lpad) => {
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
- uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
- uw::_Unwind_SetIP(context, lpad);
- return uw::_URC_INSTALL_CONTEXT;
+ // Default personality routine, which is used directly on most targets
+ // and indirectly on Windows x86_64 via SEH.
+ unsafe extern "C" fn rust_eh_personality_impl(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ if version != 1 {
+ return uw::_URC_FATAL_PHASE1_ERROR;
+ }
+ let foreign_exception = exception_class != rust_exception_class();
+ let eh_action = match find_eh_action(context, foreign_exception) {
+ Ok(action) => action,
+ Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
+ };
+ if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 {
+ match eh_action {
+ EHAction::None |
+ EHAction::Cleanup(_) => uw::_URC_CONTINUE_UNWIND,
+ EHAction::Catch(_) => uw::_URC_HANDLER_FOUND,
+ EHAction::Terminate => uw::_URC_FATAL_PHASE1_ERROR,
+ }
+ } else {
+ match eh_action {
+ EHAction::None => uw::_URC_CONTINUE_UNWIND,
+ EHAction::Cleanup(lpad) |
+ EHAction::Catch(lpad) => {
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
+ exception_object as uintptr_t);
+ uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, 0);
+ uw::_Unwind_SetIP(context, lpad);
+ uw::_URC_INSTALL_CONTEXT
+ }
+ EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR,
+ }
}
- EHAction::Terminate => return uw::_URC_FAILURE,
}
- }
- // On ARM EHABI the personality routine is responsible for actually
- // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
- unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code {
- if __gnu_unwind_frame(exception_object, context) == uw::_URC_NO_REASON {
- uw::_URC_CONTINUE_UNWIND
- } else {
- uw::_URC_FAILURE
+ cfg_if::cfg_if! {
+ if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
+ // On x86_64 MinGW targets, the unwinding mechanism is SEH however the unwind
+ // handler data (aka LSDA) uses GCC-compatible encoding.
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ #[allow(nonstandard_style)]
+ unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut uw::EXCEPTION_RECORD,
+ establisherFrame: uw::LPVOID,
+ contextRecord: *mut uw::CONTEXT,
+ dispatcherContext: *mut uw::DISPATCHER_CONTEXT)
+ -> uw::EXCEPTION_DISPOSITION {
+ uw::_GCC_specific_handler(exceptionRecord,
+ establisherFrame,
+ contextRecord,
+ dispatcherContext,
+ rust_eh_personality_impl)
+ }
+ } else {
+ // The personality routine for most of our targets.
+ #[lang = "eh_personality"]
+ #[no_mangle]
+ unsafe extern "C" fn rust_eh_personality(version: c_int,
+ actions: uw::_Unwind_Action,
+ exception_class: uw::_Unwind_Exception_Class,
+ exception_object: *mut uw::_Unwind_Exception,
+ context: *mut uw::_Unwind_Context)
+ -> uw::_Unwind_Reason_Code {
+ rust_eh_personality_impl(version,
+ actions,
+ exception_class,
+ exception_object,
+ context)
+ }
+ }
}
}
- // defined in libgcc
- extern "C" {
- fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
- context: *mut uw::_Unwind_Context)
- -> uw::_Unwind_Reason_Code;
- }
}
-unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
+unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: bool)
-> Result<EHAction, ()>
{
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
};
- eh::find_eh_action(lsda, &eh_context)
+ eh::find_eh_action(lsda, &eh_context, foreign_exception)
}
// See docs in the `unwind` module.
-#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
+#[cfg(all(target_os="windows", any(target_arch = "x86", target_arch = "x86_64"), target_env="gnu"))]
#[lang = "eh_unwind_resume"]
#[unwind(allowed)]
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
//! essentially gets categorized into three buckets currently:
//!
//! 1. MSVC targets use SEH in the `seh.rs` file.
-//! 2. The 64-bit MinGW target half-uses SEH and half-use gcc-like information
-//! in the `seh64_gnu.rs` module.
-//! 3. All other targets use libunwind/libgcc in the `gcc/mod.rs` module.
+//! 2. Emscripten uses C++ exceptions in the `emcc.rs` file.
+//! 3. All other targets use libunwind/libgcc in the `gcc.rs` file.
//!
//! More documentation about each implementation can be found in the respective
//! module.
} else if #[cfg(target_env = "msvc")] {
#[path = "seh.rs"]
mod imp;
- } else if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
- #[path = "seh64_gnu.rs"]
- mod imp;
} else {
// Rust runtime's startup objects depend on these symbols, so make them public.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
}
mod dwarf;
-mod windows;
// Entry point for catching an exception, implemented using the `try` intrinsic
// in the compiler.
use core::any::Any;
use core::mem;
use core::raw;
-
-use crate::windows as c;
-use libc::{c_int, c_uint};
+use libc::{c_int, c_uint, c_void};
// First up, a whole bunch of type definitions. There's a few platform-specific
// oddities here, and a lot that's just blatantly copied from LLVM. The purpose
// sort of operation. For example, if you compile this C++ code on MSVC and emit
// the LLVM IR:
//
-// #include <stdin.h>
+// #include <stdint.h>
+//
+// struct rust_panic {
+// uint64_t x[2];
+// }
//
// void foo() {
-// uint64_t a[2] = {0, 1};
+// rust_panic a = {0, 1};
// throw a;
// }
//
// That's essentially what we're trying to emulate. Most of the constant values
-// below were just copied from LLVM, I'm at least not 100% sure what's going on
-// everywhere. For example the `.PA_K\0` and `.PEA_K\0` strings below (stuck in
-// the names of a few of these) I'm not actually sure what they do, but it seems
-// to mirror what LLVM does!
+// below were just copied from LLVM,
//
// In any case, these structures are all constructed in a similar manner, and
// it's just somewhat verbose for us.
#[macro_use]
mod imp {
pub type ptr_t = *mut u8;
- pub const OFFSET: i32 = 4;
+ #[cfg(bootstrap)]
pub const NAME1: [u8; 7] = [b'.', b'P', b'A', b'_', b'K', 0, 0];
- pub const NAME2: [u8; 7] = [b'.', b'P', b'A', b'X', 0, 0, 0];
macro_rules! ptr {
(0) => (core::ptr::null_mut());
#[macro_use]
mod imp {
pub type ptr_t = u32;
- pub const OFFSET: i32 = 8;
+ #[cfg(bootstrap)]
pub const NAME1: [u8; 7] = [b'.', b'P', b'E', b'A', b'_', b'K', 0];
- pub const NAME2: [u8; 7] = [b'.', b'P', b'E', b'A', b'X', 0, 0];
extern "C" {
pub static __ImageBase: u8;
#[repr(C)]
pub struct _CatchableTypeArray {
pub nCatchableTypes: c_int,
- pub arrayOfCatchableTypes: [imp::ptr_t; 2],
+ pub arrayOfCatchableTypes: [imp::ptr_t; 1],
}
#[repr(C)]
pub struct _TypeDescriptor {
pub pVFTable: *const u8,
pub spare: *mut u8,
+ #[cfg(bootstrap)]
pub name: [u8; 7],
+ #[cfg(not(bootstrap))]
+ pub name: [u8; 11],
}
+// Note that we intentionally ignore name mangling rules here: we don't want C++
+// to be able to catch Rust panics by simply declaring a `struct rust_panic`.
+#[cfg(bootstrap)]
+use imp::NAME1 as TYPE_NAME;
+#[cfg(not(bootstrap))]
+const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
+
static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
attributes: 0,
pnfnUnwind: ptr!(0),
};
static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray {
- nCatchableTypes: 2,
- arrayOfCatchableTypes: [ptr!(0), ptr!(0)],
+ nCatchableTypes: 1,
+ arrayOfCatchableTypes: [ptr!(0)],
};
-static mut CATCHABLE_TYPE1: _CatchableType = _CatchableType {
- properties: 1,
+static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
+ properties: 0,
pType: ptr!(0),
thisDisplacement: _PMD {
mdisp: 0,
pdisp: -1,
vdisp: 0,
},
- sizeOrOffset: imp::OFFSET,
- copy_function: ptr!(0),
-};
-
-static mut CATCHABLE_TYPE2: _CatchableType = _CatchableType {
- properties: 1,
- pType: ptr!(0),
- thisDisplacement: _PMD {
- mdisp: 0,
- pdisp: -1,
- vdisp: 0,
- },
- sizeOrOffset: imp::OFFSET,
+ #[cfg(bootstrap)]
+ sizeOrOffset: mem::size_of::<*mut u64>() as c_int,
+ #[cfg(not(bootstrap))]
+ sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
copy_function: ptr!(0),
};
static TYPE_INFO_VTABLE: *const u8;
}
-// We use #[lang = "msvc_try_filter"] here as this is the type descriptor which
+// We use #[lang = "eh_catch_typeinfo"] here as this is the type descriptor which
// we'll use in LLVM's `catchpad` instruction which ends up also being passed as
// an argument to the C++ personality function.
//
// Again, I'm not entirely sure what this is describing, it just seems to work.
-#[cfg_attr(not(test), lang = "msvc_try_filter")]
-static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor {
+#[cfg_attr(bootstrap, lang = "msvc_try_filter")]
+#[cfg_attr(not(any(test, bootstrap)), lang = "eh_catch_typeinfo")]
+static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
spare: core::ptr::null_mut(),
- name: imp::NAME1,
-};
-
-static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor {
- pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
- spare: core::ptr::null_mut(),
- name: imp::NAME2,
+ name: TYPE_NAME,
};
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
let mut ptrs_ptr = ptrs.as_mut_ptr();
+ let throw_ptr = if cfg!(bootstrap) {
+ &mut ptrs_ptr as *mut _ as *mut _
+ } else {
+ ptrs_ptr as *mut _
+ };
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
// pointers between these structure are just that, pointers. On 64-bit MSVC,
atomic_store(&mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32,
ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32);
atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32,
- ptr!(&CATCHABLE_TYPE1 as *const _) as u32);
- atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[1] as *mut _ as *mut u32,
- ptr!(&CATCHABLE_TYPE2 as *const _) as u32);
- atomic_store(&mut CATCHABLE_TYPE1.pType as *mut _ as *mut u32,
- ptr!(&TYPE_DESCRIPTOR1 as *const _) as u32);
- atomic_store(&mut CATCHABLE_TYPE2.pType as *mut _ as *mut u32,
- ptr!(&TYPE_DESCRIPTOR2 as *const _) as u32);
+ ptr!(&CATCHABLE_TYPE as *const _) as u32);
+ atomic_store(&mut CATCHABLE_TYPE.pType as *mut _ as *mut u32,
+ ptr!(&TYPE_DESCRIPTOR as *const _) as u32);
+
+ extern "system" {
+ #[unwind(allowed)]
+ pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;
+ }
- c::_CxxThrowException(&mut ptrs_ptr as *mut _ as *mut _,
- &mut THROW_INFO as *mut _ as *mut _);
- u32::max_value()
+ _CxxThrowException(throw_ptr,
+ &mut THROW_INFO as *mut _ as *mut _);
}
pub fn payload() -> [u64; 2] {
+++ /dev/null
-//! Unwinding implementation of top of native Win64 SEH,
-//! however the unwind handler data (aka LSDA) uses GCC-compatible encoding.
-
-#![allow(nonstandard_style)]
-#![allow(private_no_mangle_fns)]
-
-use alloc::boxed::Box;
-
-use core::any::Any;
-use core::intrinsics;
-use core::ptr;
-use crate::dwarf::eh::{EHContext, EHAction, find_eh_action};
-use crate::windows as c;
-
-// Define our exception codes:
-// according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx,
-// [31:30] = 3 (error), 2 (warning), 1 (info), 0 (success)
-// [29] = 1 (user-defined)
-// [28] = 0 (reserved)
-// we define bits:
-// [24:27] = type
-// [0:23] = magic
-const ETYPE: c::DWORD = 0b1110_u32 << 28;
-const MAGIC: c::DWORD = 0x525354; // "RST"
-
-const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC;
-
-#[repr(C)]
-struct PanicData {
- data: Box<dyn Any + Send>,
-}
-
-pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
- let panic_ctx = Box::new(PanicData { data });
- let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR];
- c::RaiseException(RUST_PANIC,
- c::EXCEPTION_NONCONTINUABLE,
- params.len() as c::DWORD,
- ¶ms as *const c::ULONG_PTR);
- u32::max_value()
-}
-
-pub fn payload() -> *mut u8 {
- ptr::null_mut()
-}
-
-pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
- let panic_ctx = Box::from_raw(ptr as *mut PanicData);
- panic_ctx.data
-}
-
-// SEH doesn't support resuming unwinds after calling a landing pad like
-// libunwind does. For this reason, MSVC compiler outlines landing pads into
-// separate functions that can be called directly from the personality function
-// but are nevertheless able to find and modify stack frame of the "parent"
-// function.
-//
-// Since this cannot be done with libdwarf-style landing pads,
-// rust_eh_personality instead catches RUST_PANICs, runs the landing pad, then
-// reraises the exception.
-//
-// Note that it makes certain assumptions about the exception:
-//
-// 1. That RUST_PANIC is non-continuable, so no lower stack frame may choose to
-// resume execution.
-// 2. That the first parameter of the exception is a pointer to an extra data
-// area (PanicData).
-// Since these assumptions do not generally hold true for foreign exceptions
-// (system faults, C++ exceptions, etc), we make no attempt to invoke our
-// landing pads (and, thus, destructors!) for anything other than RUST_PANICs.
-// This is considered acceptable, because the behavior of throwing exceptions
-// through a C ABI boundary is undefined.
-
-#[lang = "eh_personality"]
-#[cfg(not(test))]
-unsafe extern "C" fn rust_eh_personality(exceptionRecord: *mut c::EXCEPTION_RECORD,
- establisherFrame: c::LPVOID,
- contextRecord: *mut c::CONTEXT,
- dispatcherContext: *mut c::DISPATCHER_CONTEXT)
- -> c::EXCEPTION_DISPOSITION {
- let er = &*exceptionRecord;
- let dc = &*dispatcherContext;
-
- if er.ExceptionFlags & c::EXCEPTION_UNWIND == 0 {
- // we are in the dispatch phase
- if er.ExceptionCode == RUST_PANIC {
- if let Some(lpad) = find_landing_pad(dc) {
- c::RtlUnwindEx(establisherFrame,
- lpad as c::LPVOID,
- exceptionRecord,
- er.ExceptionInformation[0] as c::LPVOID, // pointer to PanicData
- contextRecord,
- dc.HistoryTable);
- }
- }
- }
- c::ExceptionContinueSearch
-}
-
-#[lang = "eh_unwind_resume"]
-#[unwind(allowed)]
-unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
- let params = [panic_ctx as c::ULONG_PTR];
- c::RaiseException(RUST_PANIC,
- c::EXCEPTION_NONCONTINUABLE,
- params.len() as c::DWORD,
- ¶ms as *const c::ULONG_PTR);
- intrinsics::abort();
-}
-
-unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option<usize> {
- let eh_ctx = EHContext {
- // The return address points 1 byte past the call instruction,
- // which could be in the next IP range in LSDA range table.
- ip: dc.ControlPc as usize - 1,
- func_start: dc.ImageBase as usize + (*dc.FunctionEntry).BeginAddress as usize,
- get_text_start: &|| dc.ImageBase as usize,
- get_data_start: &|| unimplemented!(),
- };
- match find_eh_action(dc.HandlerData, &eh_ctx) {
- Err(_) |
- Ok(EHAction::None) => None,
- Ok(EHAction::Cleanup(lpad)) |
- Ok(EHAction::Catch(lpad)) => Some(lpad),
- Ok(EHAction::Terminate) => intrinsics::abort(),
- }
-}
+++ /dev/null
-#![allow(nonstandard_style)]
-#![allow(dead_code)]
-#![cfg(windows)]
-
-use libc::{c_long, c_ulong, c_void};
-
-pub type DWORD = c_ulong;
-pub type LONG = c_long;
-pub type ULONG_PTR = usize;
-pub type LPVOID = *mut c_void;
-
-pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
-pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception
-pub const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress
-pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress
-pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress
-pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call
-pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND |
- EXCEPTION_TARGET_UNWIND |
- EXCEPTION_COLLIDED_UNWIND;
-
-#[repr(C)]
-pub struct EXCEPTION_RECORD {
- pub ExceptionCode: DWORD,
- pub ExceptionFlags: DWORD,
- pub ExceptionRecord: *mut EXCEPTION_RECORD,
- pub ExceptionAddress: LPVOID,
- pub NumberParameters: DWORD,
- pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
-}
-
-#[repr(C)]
-pub struct EXCEPTION_POINTERS {
- pub ExceptionRecord: *mut EXCEPTION_RECORD,
- pub ContextRecord: *mut CONTEXT,
-}
-
-pub enum UNWIND_HISTORY_TABLE {}
-
-#[repr(C)]
-pub struct RUNTIME_FUNCTION {
- pub BeginAddress: DWORD,
- pub EndAddress: DWORD,
- pub UnwindData: DWORD,
-}
-
-pub enum CONTEXT {}
-
-#[repr(C)]
-pub struct DISPATCHER_CONTEXT {
- pub ControlPc: LPVOID,
- pub ImageBase: LPVOID,
- pub FunctionEntry: *const RUNTIME_FUNCTION,
- pub EstablisherFrame: LPVOID,
- pub TargetIp: LPVOID,
- pub ContextRecord: *const CONTEXT,
- pub LanguageHandler: LPVOID,
- pub HandlerData: *const u8,
- pub HistoryTable: *const UNWIND_HISTORY_TABLE,
-}
-
-#[repr(C)]
-pub enum EXCEPTION_DISPOSITION {
- ExceptionContinueExecution,
- ExceptionContinueSearch,
- ExceptionNestedException,
- ExceptionCollidedUnwind,
-}
-pub use self::EXCEPTION_DISPOSITION::*;
-
-extern "system" {
- #[unwind(allowed)]
- pub fn RaiseException(dwExceptionCode: DWORD,
- dwExceptionFlags: DWORD,
- nNumberOfArguments: DWORD,
- lpArguments: *const ULONG_PTR);
- #[unwind(allowed)]
- pub fn RtlUnwindEx(TargetFrame: LPVOID,
- TargetIp: LPVOID,
- ExceptionRecord: *const EXCEPTION_RECORD,
- ReturnValue: LPVOID,
- OriginalContext: *const CONTEXT,
- HistoryTable: *const UNWIND_HISTORY_TABLE);
- #[unwind(allowed)]
- pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8);
-}
}
impl HandleCounters {
- // FIXME(#53451) public to work around `Cannot create local mono-item` ICE.
- pub extern "C" fn get() -> &'static Self {
+ // FIXME(eddyb) use a reference to the `static COUNTERS`, intead of
+ // a wrapper `fn` pointer, once `const fn` can reference `static`s.
+ extern "C" fn get() -> &'static Self {
static COUNTERS: HandleCounters = HandleCounters {
$($oty: AtomicUsize::new(1),)*
$($ity: AtomicUsize::new(1),)*
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Client<F> {
+ // FIXME(eddyb) use a reference to the `static COUNTERS`, intead of
+ // a wrapper `fn` pointer, once `const fn` can reference `static`s.
pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters,
pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer<u8>,
pub(super) f: F,
}
-// FIXME(#53451) public to work around `Cannot create local mono-item` ICE,
-// affecting not only the function itself, but also the `BridgeState` `thread_local!`.
-pub extern "C" fn __run_expand1(
+/// Client-side helper for handling client panics, entering the bridge,
+/// deserializing input and serializing output.
+// FIXME(eddyb) maybe replace `Bridge::enter` with this?
+fn run_client<A: for<'a, 's> DecodeMut<'a, 's, ()>, R: Encode<()>>(
mut bridge: Bridge<'_>,
- f: fn(crate::TokenStream) -> crate::TokenStream,
+ f: impl FnOnce(A) -> R,
) -> Buffer<u8> {
// The initial `cached_buffer` contains the input.
let mut b = bridge.cached_buffer.take();
panic::catch_unwind(panic::AssertUnwindSafe(|| {
bridge.enter(|| {
let reader = &mut &b[..];
- let input = TokenStream::decode(reader, &mut ());
+ let input = A::decode(reader, &mut ());
// Put the `cached_buffer` back in the `Bridge`, for requests.
Bridge::with(|bridge| bridge.cached_buffer = b.take());
- let output = f(crate::TokenStream(input)).0;
+ let output = f(input);
// Take the `cached_buffer` back out, for the output value.
b = Bridge::with(|bridge| bridge.cached_buffer.take());
impl Client<fn(crate::TokenStream) -> crate::TokenStream> {
pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self {
+ extern "C" fn run(
+ bridge: Bridge<'_>,
+ f: impl FnOnce(crate::TokenStream) -> crate::TokenStream,
+ ) -> Buffer<u8> {
+ run_client(bridge, |input| f(crate::TokenStream(input)).0)
+ }
Client {
get_handle_counters: HandleCounters::get,
- run: __run_expand1,
+ run,
f,
}
}
}
-// FIXME(#53451) public to work around `Cannot create local mono-item` ICE,
-// affecting not only the function itself, but also the `BridgeState` `thread_local!`.
-pub extern "C" fn __run_expand2(
- mut bridge: Bridge<'_>,
- f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
-) -> Buffer<u8> {
- // The initial `cached_buffer` contains the input.
- let mut b = bridge.cached_buffer.take();
-
- panic::catch_unwind(panic::AssertUnwindSafe(|| {
- bridge.enter(|| {
- let reader = &mut &b[..];
- let input = TokenStream::decode(reader, &mut ());
- let input2 = TokenStream::decode(reader, &mut ());
-
- // Put the `cached_buffer` back in the `Bridge`, for requests.
- Bridge::with(|bridge| bridge.cached_buffer = b.take());
-
- let output = f(crate::TokenStream(input), crate::TokenStream(input2)).0;
-
- // Take the `cached_buffer` back out, for the output value.
- b = Bridge::with(|bridge| bridge.cached_buffer.take());
-
- // HACK(eddyb) Separate encoding a success value (`Ok(output)`)
- // from encoding a panic (`Err(e: PanicMessage)`) to avoid
- // having handles outside the `bridge.enter(|| ...)` scope, and
- // to catch panics that could happen while encoding the success.
- //
- // Note that panics should be impossible beyond this point, but
- // this is defensively trying to avoid any accidental panicking
- // reaching the `extern "C"` (which should `abort` but may not
- // at the moment, so this is also potentially preventing UB).
- b.clear();
- Ok::<_, ()>(output).encode(&mut b, &mut ());
- })
- }))
- .map_err(PanicMessage::from)
- .unwrap_or_else(|e| {
- b.clear();
- Err::<(), _>(e).encode(&mut b, &mut ());
- });
- b
-}
-
impl Client<fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream> {
pub const fn expand2(
f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream
) -> Self {
+ extern "C" fn run(
+ bridge: Bridge<'_>,
+ f: impl FnOnce(crate::TokenStream, crate::TokenStream) -> crate::TokenStream,
+ ) -> Buffer<u8> {
+ run_client(bridge, |(input, input2)| {
+ f(crate::TokenStream(input), crate::TokenStream(input2)).0
+ })
+ }
Client {
get_handle_counters: HandleCounters::get,
- run: __run_expand2,
+ run,
f,
}
}
/// Compares two given types, eliding parts that are the same between them and highlighting
/// relevant differences, and return two representation of those types for highlighted printing.
fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
+ debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind, t2, t2.kind);
+
+ // helper functions
fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match (&a.kind, &b.kind) {
(a, b) if *a == *b => true,
s.push_normal(ty.to_string());
}
+ // process starts here
match (&t1.kind, &t2.kind) {
(&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => {
let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1);
return values;
}
- // We couldn't find anything in common, highlight everything.
- // let x: Bar<Qux> = y::<Foo<Zar>>();
- (
- DiagnosticStyledString::highlighted(t1.to_string()),
- DiagnosticStyledString::highlighted(t2.to_string()),
- )
+ // We can't find anything in common, highlight relevant part of type path.
+ // let x: foo::bar::Baz<Qux> = y:<foo::bar::Bar<Zar>>();
+ // foo::bar::Baz<Qux>
+ // foo::bar::Bar<Zar>
+ // -------- this part of the path is different
+
+ let t1_str = t1.to_string();
+ let t2_str = t2.to_string();
+ let min_len = t1_str.len().min(t2_str.len());
+
+ const SEPARATOR: &str = "::";
+ let separator_len = SEPARATOR.len();
+ let split_idx: usize =
+ t1_str.split(SEPARATOR)
+ .zip(t2_str.split(SEPARATOR))
+ .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str)
+ .map(|(mod_str, _)| mod_str.len() + separator_len)
+ .sum();
+
+ debug!("cmp: separator_len={}, split_idx={}, min_len={}",
+ separator_len, split_idx, min_len
+ );
+
+ if split_idx >= min_len {
+ // paths are identical, highlight everything
+ (
+ DiagnosticStyledString::highlighted(t1_str),
+ DiagnosticStyledString::highlighted(t2_str)
+ )
+ } else {
+ let (common, uniq1) = t1_str.split_at(split_idx);
+ let (_, uniq2) = t2_str.split_at(split_idx);
+ debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2);
+
+ values.0.push_normal(common);
+ values.0.push_highlighted(uniq1);
+ values.1.push_normal(common);
+ values.1.push_highlighted(uniq2);
+
+ values
+ }
}
}
_ => {}
}
+ debug!("note_type_err(diag={:?})", diag);
let (expected_found, exp_found, is_simple_error) = match values {
None => (None, None, false),
Some(values) => {
diag.note_unsuccessfull_coercion(found, expected);
}
(_, false, _) => {
+ debug!(
+ "note_type_err: exp_found={:?}, expected={:?} found={:?}",
+ exp_found, expected, found
+ );
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
}
&self,
arg: &'tcx hir::Ty,
br: &ty::BoundRegion,
- ) -> Option<(&'tcx hir::Ty)> {
+ ) -> Option<&'tcx hir::Ty> {
let mut nested_visitor = FindNestedTypeVisitor {
tcx: self.tcx(),
bound_region: *br,
mod placeholder_error;
mod outlives_closure;
mod static_impl_trait;
+mod trait_impl_difference;
mod util;
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
.or_else(|| self.try_report_anon_anon_conflict())
.or_else(|| self.try_report_outlives_closure())
.or_else(|| self.try_report_static_impl_trait())
+ .or_else(|| self.try_report_impl_not_conforming_to_trait())
}
pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) {
--- /dev/null
+//! Error Reporting for `impl` items that do not match the obligations from their `trait`.
+
+use syntax_pos::Span;
+use crate::ty::Ty;
+use crate::infer::{ValuePairs, Subtype};
+use crate::infer::error_reporting::nice_region_error::NiceRegionError;
+use crate::infer::lexical_region_resolve::RegionResolutionError;
+use crate::util::common::ErrorReported;
+use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
+
+impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
+ /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
+ pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
+ if let Some(ref error) = self.error {
+ debug!("try_report_impl_not_conforming_to_trait {:?}", error);
+ if let RegionResolutionError::SubSupConflict(
+ _,
+ var_origin,
+ sub_origin,
+ _sub,
+ sup_origin,
+ _sup,
+ ) = error.clone() {
+ match (&sup_origin, &sub_origin) {
+ (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) => {
+ if let (
+ ValuePairs::Types(sub_expected_found),
+ ValuePairs::Types(sup_expected_found),
+ CompareImplMethodObligation { trait_item_def_id, .. },
+ ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) {
+ if sup_expected_found == sub_expected_found {
+ self.emit_err(
+ var_origin.span(),
+ sub_expected_found.expected,
+ sub_expected_found.found,
+ self.tcx().def_span(*trait_item_def_id),
+ );
+ return Some(ErrorReported);
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+ }
+ None
+ }
+
+ fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) {
+ let mut err = self.tcx().sess.struct_span_err(
+ sp,
+ "`impl` item signature doesn't match `trait` item signature",
+ );
+ err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found));
+ err.span_label(sp, &format!("found {:?}", found));
+ err.span_label(impl_sp, &format!("expected {:?}", expected));
+ err.emit();
+ }
+}
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
+ fn crate_host_hash_untracked(&self, cnum: CrateNum) -> Option<Svh>;
fn item_generics_cloned_untracked(&self, def: DefId, sess: &Session) -> ty::Generics;
fn postorder_cnums_untracked(&self) -> Vec<CrateNum>;
EhPersonalityLangItem, "eh_personality", eh_personality, Target::Fn;
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume, Target::Fn;
- MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter, Target::Static;
+ EhCatchTypeinfoLangItem, "eh_catch_typeinfo", eh_catch_typeinfo, Target::Static;
OwnedBoxLangItem, "owned_box", owned_box, Target::Struct;
eval_always
desc { "looking up the hash a crate" }
}
+ query crate_host_hash(_: CrateNum) -> Option<Svh> {
+ eval_always
+ desc { "looking up the hash of a host version of a crate" }
+ }
query original_crate_name(_: CrateNum) -> Symbol {
eval_always
desc { "looking up the original name a crate" }
pub fn has_errors(&self) -> bool {
self.diagnostic().has_errors()
}
+ pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
+ self.diagnostic().has_errors_or_delayed_span_bugs()
+ }
pub fn abort_if_errors(&self) {
self.diagnostic().abort_if_errors();
}
0,
&mut obligations
);
+
+ debug!("report_projection_error obligation.cause={:?} obligation.param_env={:?}",
+ obligation.cause, obligation.param_env);
+
+ debug!("report_projection_error normalized_ty={:?} data.ty={:?}",
+ normalized_ty, data.ty);
+
+ let is_normalized_ty_expected = match &obligation.cause.code {
+ ObligationCauseCode::ItemObligation(_) |
+ ObligationCauseCode::BindingObligation(_, _) |
+ ObligationCauseCode::ObjectCastObligation(_) => false,
+ _ => true,
+ };
+
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
- .eq(normalized_ty, data.ty)
+ .eq_exp(is_normalized_ty_expected, normalized_ty, data.ty)
{
- values = Some(infer::ValuePairs::Types(ExpectedFound {
- expected: normalized_ty,
- found: data.ty,
- }));
+ values = Some(infer::ValuePairs::Types(
+ ExpectedFound::new(is_normalized_ty_expected, normalized_ty, data.ty)));
+
err_buf = error;
err = &err_buf;
}
}
}
+ fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
+ self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| {
+ match gen_kind {
+ hir::GeneratorKind::Gen => "a generator",
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block",
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function",
+ hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure",
+ }
+ })
+ }
+
+ /// Used to set on_unimplemented's `ItemContext`
+ /// to be the enclosing (async) block/function/closure
+ fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
+ let hir = &self.tcx.hir();
+ let node = hir.find(hir_id)?;
+ if let hir::Node::Item(
+ hir::Item{kind: hir::ItemKind::Fn(_ ,fn_header ,_ , body_id), .. }) = &node {
+ self.describe_generator(*body_id).or_else(||
+ Some(if let hir::FnHeader{ asyncness: hir::IsAsync::Async, .. } = fn_header {
+ "an async function"
+ } else {
+ "a function"
+ })
+ )
+ } else if let hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), .. }) = &node {
+ self.describe_generator(*body_id).or_else(||
+ Some(if gen_movability.is_some() {
+ "an async closure"
+ } else {
+ "a closure"
+ })
+ )
+ } else if let hir::Node::Expr(hir::Expr { .. }) = &node {
+ let parent_hid = hir.get_parent_node(hir_id);
+ if parent_hid != hir_id {
+ return self.describe_enclosure(parent_hid);
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
fn on_unimplemented_note(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
let trait_ref = *trait_ref.skip_binder();
let mut flags = vec![];
+ flags.push((sym::item_context,
+ self.describe_enclosure(obligation.cause.body_id).map(|s|s.to_owned())));
+
match obligation.cause.code {
ObligationCauseCode::BuiltinDerivedObligation(..) |
ObligationCauseCode::ImplDerivedObligation(..) => {}
/// a pointer.
///
/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result
- /// in a new check that `Trait` is object safe, creating a cycle. So instead, we fudge a little
- /// by introducing a new type parameter `U` such that `Self: Unsize<U>` and `U: Trait + ?Sized`,
- /// and use `U` in place of `dyn Trait`. Written as a chalk-style query:
+ /// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch
+ /// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561).
+ /// Instead, we fudge a little by introducing a new type parameter `U` such that
+ /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+ /// Written as a chalk-style query:
///
/// forall (U: Trait + ?Sized) {
/// if (Self: Unsize<U>) {
// the type `U` in the query
// use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
- // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries
- // are implemented
+ // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can
+ // replace this with `dyn Trait`
let unsized_self_ty: Ty<'tcx> = self.mk_ty_param(
::std::u32::MAX,
Symbol::intern("RustaceansAreAwesome"),
Position::ArgumentNamed(s) if s == sym::from_method => (),
// `{from_desugaring}` is allowed
Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
+ // `{ItemContext}` is allowed
+ Position::ArgumentNamed(s) if s == sym::item_context => (),
// So is `{A}` if A is a type parameter
Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
param.name == s
let s = self.0.as_str();
let parser = Parser::new(&s, None, vec![], false);
+ let item_context = (options.get(&sym::item_context)).unwrap_or(&empty_string);
parser.map(|p|
match p {
Piece::String(s) => s,
} else if s == sym::from_desugaring || s == sym::from_method {
// don't break messages using these two arguments incorrectly
&empty_string
+ } else if s == sym::item_context {
+ &item_context
} else {
bug!("broken on_unimplemented {:?} for {:?}: \
no argument matching {:?}",
CrateType::Executable |
CrateType::Staticlib |
CrateType::ProcMacro |
- CrateType::Dylib |
CrateType::Cdylib => false,
+
+ // FIXME rust-lang/rust#64319, rust-lang/rust#64872:
+ // We want to block export of generics from dylibs,
+ // but we must fix rust-lang/rust#65890 before we can
+ // do that robustly.
+ CrateType::Dylib => true,
+
CrateType::Rlib => true,
}
})
assert_eq!(cnum, LOCAL_CRATE);
tcx.arena.alloc_slice(&tcx.cstore.crates_untracked())
};
+ providers.crate_host_hash = |tcx, cnum| {
+ assert_ne!(cnum, LOCAL_CRATE);
+ tcx.cstore.crate_host_hash_untracked(cnum)
+ };
providers.postorder_cnums = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
tcx.arena.alloc_slice(&tcx.cstore.postorder_cnums_untracked())
-use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextData, MirDebugScope};
+use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope};
use super::metadata::file_metadata;
use super::utils::{DIB, span_start};
use syntax_pos::Pos;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{Idx, IndexVec};
-
-use syntax_pos::BytePos;
+use rustc_index::vec::Idx;
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
-/// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(
+pub fn compute_mir_scopes(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
- debug_context: &FunctionDebugContext<&'ll DISubprogram>,
-) -> IndexVec<SourceScope, MirDebugScope<&'ll DIScope>> {
- let null_scope = MirDebugScope {
- scope_metadata: None,
- file_start_pos: BytePos(0),
- file_end_pos: BytePos(0)
- };
- let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes);
-
- let debug_context = match *debug_context {
- FunctionDebugContext::RegularContext(ref data) => data,
- FunctionDebugContext::DebugInfoDisabled |
- FunctionDebugContext::FunctionWithoutDebugInfo => {
- return scopes;
- }
- };
-
+ fn_metadata: &'ll DISubprogram,
+ debug_context: &mut FunctionDebugContext<&'ll DIScope>,
+) {
// Find all the scopes with variables defined in them.
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
+ // FIXME(eddyb) base this on `decl.name`, or even better, on debuginfo.
+ // FIXME(eddyb) take into account that arguments always have debuginfo,
+ // irrespective of their name (assuming full debuginfo is enabled).
for var in mir.vars_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.visibility_scope);
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
- make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
+ make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
}
-
- scopes
}
fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
+ fn_metadata: &'ll DISubprogram,
has_variables: &BitSet<SourceScope>,
- debug_context: &FunctionDebugContextData<&'ll DISubprogram>,
- scope: SourceScope,
- scopes: &mut IndexVec<SourceScope, MirDebugScope<&'ll DIScope>>) {
- if scopes[scope].is_valid() {
+ debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
+ scope: SourceScope) {
+ if debug_context.scopes[scope].is_valid() {
return;
}
let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
- make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
- scopes[parent]
+ make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
+ debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = span_start(cx, mir.span);
- scopes[scope] = MirDebugScope {
- scope_metadata: Some(debug_context.fn_metadata),
+ debug_context.scopes[scope] = DebugScope {
+ scope_metadata: Some(fn_metadata),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
- if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
- scopes[scope] = parent_scope;
+ if parent_scope.scope_metadata.unwrap() != fn_metadata {
+ debug_context.scopes[scope] = parent_scope;
return;
}
}
loc.line as c_uint,
loc.col.to_usize() as c_uint))
};
- scopes[scope] = MirDebugScope {
+ debug_context.scopes[scope] = DebugScope {
scope_metadata,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
// See doc.rs for documentation.
mod doc;
-use rustc_codegen_ssa::debuginfo::VariableAccess::*;
-use rustc_codegen_ssa::debuginfo::VariableKind::*;
+use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::mangled_name_of_instance;
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use crate::llvm;
-use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags,
+use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DIArray, DIFlags,
DISPFlags, DILexicalBlock};
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_index::vec::IndexVec;
-use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
- VariableKind, FunctionDebugContextData, type_names};
+use rustc_codegen_ssa::debuginfo::type_names;
+use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope,
+ VariableKind};
use libc::c_uint;
use std::cell::RefCell;
use std::ffi::{CStr, CString};
-use syntax_pos::{self, Span, Pos};
+use smallvec::SmallVec;
+use syntax_pos::{self, BytePos, Span, Pos};
use syntax::ast;
use syntax::symbol::Symbol;
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Size};
use rustc_codegen_ssa::traits::*;
pub mod gdb;
mod create_scope_map;
mod source_loc;
-pub use self::create_scope_map::{create_mir_scopes};
+pub use self::create_scope_map::compute_mir_scopes;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::extend_scope_to_file;
pub use self::source_loc::set_source_location;
impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn declare_local(
&mut self,
- dbg_context: &FunctionDebugContext<&'ll DISubprogram>,
+ dbg_context: &FunctionDebugContext<&'ll DIScope>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: &'ll DIScope,
- variable_access: VariableAccess<'_, &'ll Value>,
+ variable_alloca: Self::Value,
+ direct_offset: Size,
+ indirect_offsets: &[Size],
variable_kind: VariableKind,
span: Span,
) {
- assert!(!dbg_context.get_ref(span).source_locations_enabled);
+ assert!(!dbg_context.source_locations_enabled);
let cx = self.cx();
let file = span_start(cx, span).file;
let file_metadata = file_metadata(cx,
&file.name,
- dbg_context.get_ref(span).defining_crate);
+ dbg_context.defining_crate);
let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
};
let align = cx.align_of(variable_type);
- let name = SmallCStr::new(&variable_name.as_str());
- match (variable_access, &[][..]) {
- (DirectVariable { alloca }, address_operations) |
- (IndirectVariable {alloca, address_operations}, _) => {
- let metadata = unsafe {
- llvm::LLVMRustDIBuilderCreateVariable(
- DIB(cx),
- dwarf_tag,
- scope_metadata,
- name.as_ptr(),
- file_metadata,
- loc.line as c_uint,
- type_metadata,
- cx.sess().opts.optimize != config::OptLevel::No,
- DIFlags::FlagZero,
- argument_index,
- align.bytes() as u32,
- )
- };
- source_loc::set_debug_location(self,
- InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
- unsafe {
- let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
- let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
- DIB(cx),
- alloca,
- metadata,
- address_operations.as_ptr(),
- address_operations.len() as c_uint,
- debug_loc,
- self.llbb());
-
- llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
- }
- source_loc::set_debug_location(self, UnknownLocation);
+ // Convert the direct and indirect offsets to address ops.
+ let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
+ let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
+ let mut addr_ops = SmallVec::<[_; 8]>::new();
+
+ if direct_offset.bytes() > 0 {
+ addr_ops.push(op_plus_uconst());
+ addr_ops.push(direct_offset.bytes() as i64);
+ }
+ for &offset in indirect_offsets {
+ addr_ops.push(op_deref());
+ if offset.bytes() > 0 {
+ addr_ops.push(op_plus_uconst());
+ addr_ops.push(offset.bytes() as i64);
}
}
+
+ let name = SmallCStr::new(&variable_name.as_str());
+ let metadata = unsafe {
+ llvm::LLVMRustDIBuilderCreateVariable(
+ DIB(cx),
+ dwarf_tag,
+ scope_metadata,
+ name.as_ptr(),
+ file_metadata,
+ loc.line as c_uint,
+ type_metadata,
+ cx.sess().opts.optimize != config::OptLevel::No,
+ DIFlags::FlagZero,
+ argument_index,
+ align.bytes() as u32,
+ )
+ };
+ source_loc::set_debug_location(self,
+ InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
+ unsafe {
+ let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
+ let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
+ DIB(cx),
+ variable_alloca,
+ metadata,
+ addr_ops.as_ptr(),
+ addr_ops.len() as c_uint,
+ debug_loc,
+ self.llbb());
+
+ llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
+ }
+ source_loc::set_debug_location(self, UnknownLocation);
}
fn set_source_location(
&mut self,
- debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
- scope: Option<&'ll DIScope>,
+ debug_context: &mut FunctionDebugContext<&'ll DIScope>,
+ scope: &'ll DIScope,
span: Span,
) {
set_source_location(debug_context, &self, scope, span)
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
}
- fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) {
+ fn set_var_name(&mut self, value: &'ll Value, name: &str) {
// Avoid wasting time if LLVM value names aren't even enabled.
if self.sess().fewer_names() {
return;
Err(_) => return,
}
- let cname = CString::new(name.to_string()).unwrap();
+ let cname = SmallCStr::new(name);
unsafe {
llvm::LLVMSetValueName(value, cname.as_ptr());
}
sig: ty::FnSig<'tcx>,
llfn: &'ll Value,
mir: &mir::Body<'_>,
- ) -> FunctionDebugContext<&'ll DISubprogram> {
+ ) -> Option<FunctionDebugContext<&'ll DIScope>> {
if self.sess().opts.debuginfo == DebugInfo::None {
- return FunctionDebugContext::DebugInfoDisabled;
+ return None;
}
if let InstanceDef::Item(def_id) = instance.def {
if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
- return FunctionDebugContext::FunctionWithoutDebugInfo;
+ return None;
}
}
// This can be the case for functions inlined from another crate
if span.is_dummy() {
// FIXME(simulacrum): Probably can't happen; remove.
- return FunctionDebugContext::FunctionWithoutDebugInfo;
+ return None;
}
let def_id = instance.def_id();
None)
};
- // Initialize fn debug context (including scope map and namespace map)
- let fn_debug_context = FunctionDebugContextData {
- fn_metadata,
+ // Initialize fn debug context (including scopes).
+ // FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
+ let null_scope = DebugScope {
+ scope_metadata: None,
+ file_start_pos: BytePos(0),
+ file_end_pos: BytePos(0)
+ };
+ let mut fn_debug_context = FunctionDebugContext {
+ scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
source_locations_enabled: false,
defining_crate: def_id.krate,
};
- return FunctionDebugContext::RegularContext(fn_debug_context);
+ // Fill in all the scopes, with the information from the MIR body.
+ compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);
+
+ return Some(fn_debug_context);
fn get_function_signature<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
metadata::create_vtable_metadata(self, ty, vtable)
}
- fn create_mir_scopes(
- &self,
- mir: &mir::Body<'_>,
- debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
- ) -> IndexVec<mir::SourceScope, MirDebugScope<&'ll DIScope>> {
- create_scope_map::create_mir_scopes(self, mir, debug_context)
- }
-
fn extend_scope_to_file(
&self,
scope_metadata: &'ll DIScope,
fn debuginfo_finalize(&self) {
finalize(self)
}
-
- fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
- unsafe {
- [llvm::LLVMRustDIBuilderCreateOpDeref(),
- llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
- byte_offset_of_var_in_env as i64,
- llvm::LLVMRustDIBuilderCreateOpDeref()]
- }
- }
}
use super::utils::{debug_context, span_start};
use super::metadata::UNKNOWN_COLUMN_NUMBER;
-use rustc_codegen_ssa::debuginfo::FunctionDebugContext;
+use rustc_codegen_ssa::mir::debuginfo::FunctionDebugContext;
use crate::llvm;
use crate::llvm::debuginfo::DIScope;
pub fn set_source_location<D>(
debug_context: &FunctionDebugContext<D>,
bx: &Builder<'_, 'll, '_>,
- scope: Option<&'ll DIScope>,
+ scope: &'ll DIScope,
span: Span,
) {
- let function_debug_context = match *debug_context {
- FunctionDebugContext::DebugInfoDisabled => return,
- FunctionDebugContext::FunctionWithoutDebugInfo => {
- set_debug_location(bx, UnknownLocation);
- return;
- }
- FunctionDebugContext::RegularContext(ref data) => data
- };
-
- let dbg_loc = if function_debug_context.source_locations_enabled {
+ let dbg_loc = if debug_context.source_locations_enabled {
debug!("set_source_location: {}", bx.sess().source_map().span_to_string(span));
let loc = span_start(bx.cx(), span);
- InternalDebugLocation::new(scope.unwrap(), loc.line, loc.col.to_usize())
+ InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
} else {
UnknownLocation
};
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use syntax::ast::{self, FloatTy};
+use rustc_target::abi::HasDataLayout;
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
use rustc_codegen_ssa::traits::*;
return;
}
+ "ptr_offset_from" => {
+ let ty = substs.type_at(0);
+ let pointee_size = self.size_of(ty);
+
+ // This is the same sequence that Clang emits for pointer subtraction.
+ // It can be neither `nsw` nor `nuw` because the input is treated as
+ // unsigned but then the output is treated as signed, so neither works.
+ let a = args[0].immediate();
+ let b = args[1].immediate();
+ let a = self.ptrtoint(a, self.type_isize());
+ let b = self.ptrtoint(b, self.type_isize());
+ let d = self.sub(a, b);
+ let pointee_size = self.const_usize(pointee_size.bytes());
+ // this is where the signed magic happens (notice the `s` in `exactsdiv`)
+ self.exactsdiv(d, pointee_size)
+ }
+
_ => bug!("unknown intrinsic '{}'", name),
};
// We're generating an IR snippet that looks like:
//
// declare i32 @rust_try(%func, %data, %ptr) {
- // %slot = alloca i64*
+ // %slot = alloca [2 x i64]
// invoke %func(%data) to label %normal unwind label %catchswitch
//
// normal:
//
// #include <stdint.h>
//
+ // struct rust_panic {
+ // uint64_t x[2];
+ // }
+ //
// int bar(void (*foo)(void), uint64_t *ret) {
// try {
// foo();
// return 0;
- // } catch(uint64_t a[2]) {
- // ret[0] = a[0];
- // ret[1] = a[1];
+ // } catch(rust_panic a) {
+ // ret[0] = a.x[0];
+ // ret[1] = a.x[1];
// return 1;
// }
// }
//
// More information can be found in libstd's seh.rs implementation.
- let i64p = bx.type_ptr_to(bx.type_i64());
- let ptr_align = bx.tcx().data_layout.pointer_align.abi;
- let slot = bx.alloca(i64p, ptr_align);
+ let i64_2 = bx.type_array(bx.type_i64(), 2);
+ let i64_align = bx.tcx().data_layout.i64_align.abi;
+ let slot = bx.alloca(i64_2, i64_align);
bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
normal.ret(bx.const_i32(0));
let cs = catchswitch.catch_switch(None, None, 1);
catchswitch.add_handler(cs, catchpad.llbb());
- let tydesc = match bx.tcx().lang_items().msvc_try_filter() {
+ let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() {
Some(did) => bx.get_static(did),
- None => bug!("msvc_try_filter not defined"),
+ None => bug!("eh_catch_typeinfo not defined, but needed for SEH unwinding"),
};
let funclet = catchpad.catch_pad(cs, &[tydesc, bx.const_i32(0), slot]);
- let addr = catchpad.load(slot, ptr_align);
- let i64_align = bx.tcx().data_layout.i64_align.abi;
- let arg1 = catchpad.load(addr, i64_align);
- let val1 = bx.const_i32(1);
- let gep1 = catchpad.inbounds_gep(addr, &[val1]);
- let arg2 = catchpad.load(gep1, i64_align);
- let local_ptr = catchpad.bitcast(local_ptr, i64p);
- let gep2 = catchpad.inbounds_gep(local_ptr, &[val1]);
- catchpad.store(arg1, local_ptr, i64_align);
- catchpad.store(arg2, gep2, i64_align);
+ let payload = catchpad.load(slot, i64_align);
+ let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2));
+ catchpad.store(payload, local_ptr, i64_align);
catchpad.catch_ret(&funclet, caught.llbb());
caught.ret(bx.const_i32(1));
// rust_try ignores the selector.
let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1);
- catch.add_clause(vals, bx.const_null(bx.type_i8p()));
+ let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() {
+ Some(tydesc) => {
+ let tydesc = bx.get_static(tydesc);
+ bx.bitcast(tydesc, bx.type_i8p())
+ }
+ None => bx.const_null(bx.type_i8p()),
+ };
+ catch.add_clause(vals, tydesc);
let ptr = catch.extract_value(vals, 0);
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_i8p()));
// The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
// vector mask and returns an unsigned integer containing the most
// significant bit (MSB) of each lane.
- use rustc_target::abi::HasDataLayout;
// If the vector has less than 8 lanes, an u8 is returned with zeroed
// trailing bits.
extern crate rustc_driver as _;
#[macro_use] extern crate log;
+extern crate smallvec;
extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
use syntax_pos::symbol::Symbol;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
-use rustc_target::spec::MergeFunctions;
+use rustc_target::spec::{MergeFunctions, PanicStrategy};
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;
}
}
+ if sess.target.target.target_os == "emscripten" &&
+ sess.panic_strategy() == PanicStrategy::Unwind {
+ add("-enable-emscripten-cxx-exceptions");
+ }
+
// HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes
// during inlining. Unfortunately these may block other optimizations.
add("-preserve-alignment-assumptions-during-inlining=false");
use rustc::session::Session;
use rustc::session::config::{self, CrateType, OptLevel, DebugInfo,
LinkerPluginLto, Lto};
-use rustc::middle::exported_symbols::ExportedSymbol;
use rustc::ty::TyCtxt;
use rustc_target::spec::{LinkerFlavor, LldFlavor};
use rustc_serialize::{json, Encoder};
continue;
}
- // Do not export generic symbols from upstream crates in linked
- // artifact (notably the `dylib` crate type). The main reason
- // for this is that `symbol_name` is actually wrong for generic
- // symbols because it guesses the name we'd give them locally
- // rather than the name it has upstream (depending on
- // `share_generics` settings and such).
- //
- // To fix that issue we just say that linked artifacts, aka
- // `dylib`s, never export generic symbols and they aren't
- // available to downstream crates. (the not available part is
- // handled elsewhere).
- if let ExportedSymbol::Generic(..) = symbol {
- continue;
- }
+ // FIXME rust-lang/rust#64319, rust-lang/rust#64872:
+ // We want to block export of generics from dylibs,
+ // but we must fix rust-lang/rust#65890 before we can
+ // do that robustly.
symbols.push(symbol.symbol_name(tcx).to_string());
}
codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
if is_extern && !std_internal {
- // Emscripten cannot export statics, so reduce their export level here
- if tcx.sess.target.target.options.is_like_emscripten {
+ let target = &tcx.sess.target.target.llvm_target;
+ // WebAssembly cannot export data symbols, so reduce their export level
+ if target.contains("wasm32") || target.contains("emscripten") {
if let Some(Node::Item(&hir::Item {
kind: hir::ItemKind::Static(..),
..
-use syntax_pos::{BytePos, Span};
-use rustc::hir::def_id::CrateNum;
-
+// FIXME(eddyb) find a place for this (or a way to replace it).
pub mod type_names;
-
-pub enum FunctionDebugContext<D> {
- RegularContext(FunctionDebugContextData<D>),
- DebugInfoDisabled,
- FunctionWithoutDebugInfo,
-}
-
-impl<D> FunctionDebugContext<D> {
- pub fn get_ref(&self, span: Span) -> &FunctionDebugContextData<D> {
- match *self {
- FunctionDebugContext::RegularContext(ref data) => data,
- FunctionDebugContext::DebugInfoDisabled => {
- span_bug!(
- span,
- "debuginfo: Error trying to access FunctionDebugContext \
- although debug info is disabled!",
- );
- }
- FunctionDebugContext::FunctionWithoutDebugInfo => {
- span_bug!(
- span,
- "debuginfo: Error trying to access FunctionDebugContext \
- for function that should be ignored by debug info!",
- );
- }
- }
- }
-}
-
-/// Enables emitting source locations for the given functions.
-///
-/// Since we don't want source locations to be emitted for the function prelude,
-/// they are disabled when beginning to codegen a new function. This functions
-/// switches source location emitting on and must therefore be called before the
-/// first real statement/expression of the function is codegened.
-pub fn start_emitting_source_locations<D>(dbg_context: &mut FunctionDebugContext<D>) {
- match *dbg_context {
- FunctionDebugContext::RegularContext(ref mut data) => {
- data.source_locations_enabled = true;
- },
- _ => { /* safe to ignore */ }
- }
-}
-
-pub struct FunctionDebugContextData<D> {
- pub fn_metadata: D,
- pub source_locations_enabled: bool,
- pub defining_crate: CrateNum,
-}
-
-pub enum VariableAccess<'a, V> {
- // The llptr given is an alloca containing the variable's value
- DirectVariable { alloca: V },
- // The llptr given is an alloca containing the start of some pointer chain
- // leading to the variable's content.
- IndirectVariable { alloca: V, address_operations: &'a [i64] }
-}
-
-pub enum VariableKind {
- ArgumentVariable(usize /*index*/),
- LocalVariable,
-}
-
-
-#[derive(Clone, Copy, Debug)]
-pub struct MirDebugScope<D> {
- pub scope_metadata: Option<D>,
- // Start and end offsets of the file to which this DIScope belongs.
- // These are used to quickly determine whether some span refers to the same file.
- pub file_start_pos: BytePos,
- pub file_end_pos: BytePos,
-}
-
-impl<D> MirDebugScope<D> {
- pub fn is_valid(&self) -> bool {
- !self.scope_metadata.is_none()
- }
-}
use rustc::mir::{self, Location, TerminatorKind};
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::traversal;
+use rustc::session::config::DebugInfo;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
use syntax_pos::DUMMY_SP;
analyzer.visit_body(mir);
- for (index, (ty, span)) in mir.local_decls.iter()
- .map(|l| (l.ty, l.source_info.span))
- .enumerate()
+ for (local, decl) in mir.local_decls.iter_enumerated()
{
- let ty = fx.monomorphize(&ty);
- debug!("local {} has type {:?}", index, ty);
- let layout = fx.cx.spanned_layout_of(ty, span);
+ // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
+ // of putting everything in allocas just so we can use llvm.dbg.declare.
+ if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
+ if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() {
+ analyzer.not_ssa(local);
+ continue;
+ }
+ }
+
+ let ty = fx.monomorphize(&decl.ty);
+ debug!("local {:?} has type `{}`", local, ty);
+ let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
if fx.cx.is_backend_immediate(layout) {
// These sorts of types are immediates that we can store
// in an Value without an alloca.
// (e.g., structs) into an alloca unconditionally, just so
// that we don't have to deal with having two pathways
// (gep vs extractvalue etc).
- analyzer.not_ssa(mir::Local::new(index));
+ analyzer.not_ssa(local);
}
}
--- /dev/null
+use rustc_index::vec::{Idx, IndexVec};
+use rustc::hir::def_id::CrateNum;
+use rustc::mir;
+use rustc::session::config::DebugInfo;
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::layout::{LayoutOf, Size, VariantIdx};
+use crate::traits::*;
+
+use syntax_pos::{BytePos, Span, Symbol};
+use syntax::symbol::kw;
+
+use super::{FunctionCx, LocalRef};
+use super::OperandValue;
+
+pub struct FunctionDebugContext<D> {
+ pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
+ pub source_locations_enabled: bool,
+ pub defining_crate: CrateNum,
+}
+
+#[derive(Copy, Clone)]
+pub enum VariableKind {
+ ArgumentVariable(usize /*index*/),
+ LocalVariable,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct DebugScope<D> {
+ pub scope_metadata: Option<D>,
+ // Start and end offsets of the file to which this DIScope belongs.
+ // These are used to quickly determine whether some span refers to the same file.
+ pub file_start_pos: BytePos,
+ pub file_end_pos: BytePos,
+}
+
+impl<D> DebugScope<D> {
+ pub fn is_valid(&self) -> bool {
+ !self.scope_metadata.is_none()
+ }
+}
+
+impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
+ pub fn set_debug_loc(
+ &mut self,
+ bx: &mut Bx,
+ source_info: mir::SourceInfo
+ ) {
+ let (scope, span) = self.debug_loc(source_info);
+ if let Some(debug_context) = &mut self.debug_context {
+ // FIXME(eddyb) get rid of this unwrap somehow.
+ bx.set_source_location(debug_context, scope.unwrap(), span);
+ }
+ }
+
+ pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
+ // Bail out if debug info emission is not enabled.
+ match self.debug_context {
+ None => return (None, source_info.span),
+ Some(_) => {}
+ }
+
+ // In order to have a good line stepping behavior in debugger, we overwrite debug
+ // locations of macro expansions with that of the outermost expansion site
+ // (unless the crate is being compiled with `-Z debug-macros`).
+ if !source_info.span.from_expansion() ||
+ self.cx.sess().opts.debugging_opts.debug_macros {
+ let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
+ (scope, source_info.span)
+ } else {
+ // Walk up the macro expansion chain until we reach a non-expanded span.
+ // We also stop at the function body level because no line stepping can occur
+ // at the level above that.
+ let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
+ let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
+ // Use span of the outermost expansion site, while keeping the original lexical scope.
+ (scope, span)
+ }
+ }
+
+ // DILocations inherit source file name from the parent DIScope. Due to macro expansions
+ // it may so happen that the current span belongs to a different file than the DIScope
+ // corresponding to span's containing source scope. If so, we need to create a DIScope
+ // "extension" into that file.
+ fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
+ -> Option<Bx::DIScope> {
+ let debug_context = self.debug_context.as_ref()?;
+ let scope_metadata = debug_context.scopes[scope_id].scope_metadata;
+ if pos < debug_context.scopes[scope_id].file_start_pos ||
+ pos >= debug_context.scopes[scope_id].file_end_pos {
+ let sm = self.cx.sess().source_map();
+ let defining_crate = debug_context.defining_crate;
+ Some(self.cx.extend_scope_to_file(
+ scope_metadata.unwrap(),
+ &sm.lookup_char_pos(pos).file,
+ defining_crate
+ ))
+ } else {
+ scope_metadata
+ }
+ }
+
+ /// Apply debuginfo and/or name, after creating the `alloca` for a local,
+ /// or initializing the local with an operand (whichever applies).
+ // FIXME(eddyb) use `llvm.dbg.value` (which would work for operands),
+ // not just `llvm.dbg.declare` (which requires `alloca`).
+ pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
+ // FIXME(eddyb) maybe name the return place as `_0` or `return`?
+ if local == mir::RETURN_PLACE {
+ return;
+ }
+
+ let vars = match &self.per_local_var_debug_info {
+ Some(per_local) => &per_local[local],
+ None => return,
+ };
+ let whole_local_var = vars.iter().find(|var| {
+ var.place.projection.is_empty()
+ });
+ let has_proj = || vars.iter().any(|var| {
+ !var.place.projection.is_empty()
+ });
+
+ let (fallback_var, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
+ let arg_index = local.index() - 1;
+
+ // Add debuginfo even to unnamed arguments.
+ // FIXME(eddyb) is this really needed?
+ let var = if arg_index == 0 && has_proj() {
+ // Hide closure environments from debuginfo.
+ // FIXME(eddyb) shouldn't `ArgumentVariable` indices
+ // be offset to account for the hidden environment?
+ None
+ } else {
+ Some(VarDebugInfo {
+ name: kw::Invalid,
+ source_info: self.mir.local_decls[local].source_info,
+ place: local.into(),
+ })
+ };
+ (var, VariableKind::ArgumentVariable(arg_index + 1))
+ } else {
+ (None, VariableKind::LocalVariable)
+ };
+
+ let local_ref = &self.locals[local];
+
+ if !bx.sess().fewer_names() {
+ let name = match whole_local_var.or(fallback_var.as_ref()) {
+ Some(var) if var.name != kw::Invalid => var.name.to_string(),
+ _ => format!("{:?}", local),
+ };
+ match local_ref {
+ LocalRef::Place(place) |
+ LocalRef::UnsizedPlace(place) => {
+ bx.set_var_name(place.llval, &name);
+ }
+ LocalRef::Operand(Some(operand)) => match operand.val {
+ OperandValue::Ref(x, ..) |
+ OperandValue::Immediate(x) => {
+ bx.set_var_name(x, &name);
+ }
+ OperandValue::Pair(a, b) => {
+ // FIXME(eddyb) these are scalar components,
+ // maybe extract the high-level fields?
+ bx.set_var_name(a, &(name.clone() + ".0"));
+ bx.set_var_name(b, &(name + ".1"));
+ }
+ }
+ LocalRef::Operand(None) => {}
+ }
+ }
+
+ if bx.sess().opts.debuginfo != DebugInfo::Full {
+ return;
+ }
+
+ let debug_context = match &self.debug_context {
+ Some(debug_context) => debug_context,
+ None => return,
+ };
+
+ // FIXME(eddyb) add debuginfo for unsized places too.
+ let base = match local_ref {
+ LocalRef::Place(place) => place,
+ _ => return,
+ };
+
+ let vars = vars.iter().chain(if whole_local_var.is_none() {
+ fallback_var.as_ref()
+ } else {
+ None
+ });
+
+ for var in vars {
+ let mut layout = base.layout;
+ let mut direct_offset = Size::ZERO;
+ // FIXME(eddyb) use smallvec here.
+ let mut indirect_offsets = vec![];
+
+ let kind = if var.place.projection.is_empty() {
+ kind
+ } else {
+ VariableKind::LocalVariable
+ };
+
+ for elem in &var.place.projection[..] {
+ match *elem {
+ mir::ProjectionElem::Deref => {
+ indirect_offsets.push(Size::ZERO);
+ layout = bx.cx().layout_of(
+ layout.ty.builtin_deref(true)
+ .unwrap_or_else(|| {
+ span_bug!(
+ var.source_info.span,
+ "cannot deref `{}`",
+ layout.ty,
+ )
+ }).ty,
+ );
+ }
+ mir::ProjectionElem::Field(field, _) => {
+ let i = field.index();
+ let offset = indirect_offsets.last_mut()
+ .unwrap_or(&mut direct_offset);
+ *offset += layout.fields.offset(i);
+ layout = layout.field(bx.cx(), i);
+ }
+ mir::ProjectionElem::Downcast(_, variant) => {
+ layout = layout.for_variant(bx.cx(), variant);
+ }
+ _ => span_bug!(
+ var.source_info.span,
+ "unsupported var debuginfo place `{:?}`",
+ var.place,
+ ),
+ }
+ }
+
+ let (scope, span) = self.debug_loc(var.source_info);
+ if let Some(scope) = scope {
+ bx.declare_local(debug_context, var.name, layout.ty, scope,
+ base.llval, direct_offset, &indirect_offsets, kind, span);
+ }
+ }
+ }
+
+ pub fn debug_introduce_locals(&self, bx: &mut Bx) {
+ if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
+ for local in self.locals.indices() {
+ self.debug_introduce_local(bx, local);
+ }
+ }
+ }
+}
+
+pub fn per_local_var_debug_info(
+ tcx: TyCtxt<'tcx>,
+ body: &mir::Body<'tcx>,
+) -> Option<IndexVec<mir::Local, Vec<VarDebugInfo<'tcx>>>> {
+ if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
+ let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
+ for (local, decl) in body.local_decls.iter_enumerated() {
+ if let Some(name) = decl.name {
+ per_local[local].push(VarDebugInfo {
+ name,
+ source_info: mir::SourceInfo {
+ span: decl.source_info.span,
+ scope: decl.visibility_scope,
+ },
+ place: local.into(),
+ });
+ }
+ }
+
+ let upvar_debuginfo = &body.__upvar_debuginfo_codegen_only_do_not_use;
+ if !upvar_debuginfo.is_empty() {
+
+ let env_arg = mir::Local::new(1);
+ let mut env_projs = vec![];
+
+ let pin_did = tcx.lang_items().pin_type();
+ match body.local_decls[env_arg].ty.kind {
+ ty::RawPtr(_) |
+ ty::Ref(..) => {
+ env_projs.push(mir::ProjectionElem::Deref);
+ }
+ ty::Adt(def, substs) if Some(def.did) == pin_did => {
+ if let ty::Ref(..) = substs.type_at(0).kind {
+ env_projs.push(mir::ProjectionElem::Field(
+ mir::Field::new(0),
+ // HACK(eddyb) field types aren't used or needed here.
+ tcx.types.err,
+ ));
+ env_projs.push(mir::ProjectionElem::Deref);
+ }
+ }
+ _ => {}
+ }
+
+ let extra_locals = {
+ let upvars = upvar_debuginfo
+ .iter()
+ .enumerate()
+ .map(|(i, upvar)| {
+ let source_info = mir::SourceInfo {
+ span: body.span,
+ scope: mir::OUTERMOST_SOURCE_SCOPE,
+ };
+ (None, i, upvar.debug_name, upvar.by_ref, source_info)
+ });
+
+ let generator_fields = body.generator_layout.as_ref().map(|generator_layout| {
+ generator_layout.variant_fields.iter()
+ .enumerate()
+ .flat_map(move |(variant_idx, fields)| {
+ let variant_idx = Some(VariantIdx::from(variant_idx));
+ fields.iter()
+ .enumerate()
+ .filter_map(move |(i, field)| {
+ let decl = &generator_layout.
+ __local_debuginfo_codegen_only_do_not_use[*field];
+ if let Some(name) = decl.name {
+ let source_info = mir::SourceInfo {
+ span: decl.source_info.span,
+ scope: decl.visibility_scope,
+ };
+ Some((variant_idx, i, name, false, source_info))
+ } else {
+ None
+ }
+ })
+ })
+ }).into_iter().flatten();
+
+ upvars.chain(generator_fields)
+ };
+
+ for (variant_idx, field, name, by_ref, source_info) in extra_locals {
+ let mut projs = env_projs.clone();
+
+ if let Some(variant_idx) = variant_idx {
+ projs.push(mir::ProjectionElem::Downcast(None, variant_idx));
+ }
+
+ projs.push(mir::ProjectionElem::Field(
+ mir::Field::new(field),
+ // HACK(eddyb) field types aren't used or needed here.
+ tcx.types.err,
+ ));
+
+ if by_ref {
+ projs.push(mir::ProjectionElem::Deref);
+ }
+
+ per_local[env_arg].push(VarDebugInfo {
+ name,
+ source_info,
+ place: mir::Place {
+ base: mir::PlaceBase::Local(env_arg),
+ projection: tcx.intern_place_elems(&projs),
+ },
+ });
+ }
+ }
+
+ Some(per_local)
+ } else {
+ None
+ }
+}
+
+/// Debug information relatating to an user variable.
+// FIXME(eddyb) move this to the MIR bodies themselves.
+#[derive(Clone)]
+pub struct VarDebugInfo<'tcx> {
+ pub name: Symbol,
+
+ /// Source info of the user variable, including the scope
+ /// within which the variable is visible (to debuginfo)
+ /// (see `LocalDecl`'s `source_info` field for more details).
+ pub source_info: mir::SourceInfo,
+
+ /// Where the data for this user variable is to be found.
+ pub place: mir::Place<'tcx>,
+}
-use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts, Instance};
+use rustc::ty::{self, Ty, TypeFoldable, Instance};
use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Body};
-use rustc::session::config::DebugInfo;
use rustc_target::abi::call::{FnType, PassMode};
-use rustc_target::abi::{Variants, VariantIdx};
use crate::base;
-use crate::debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext};
use crate::traits::*;
-use syntax_pos::{DUMMY_SP, BytePos, Span};
-use syntax::symbol::kw;
-
use std::iter;
use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use self::analyze::CleanupKind;
+use self::debuginfo::FunctionDebugContext;
use self::place::PlaceRef;
use rustc::mir::traversal;
mir: &'a mir::Body<'tcx>,
- debug_context: FunctionDebugContext<Bx::DIScope>,
+ debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
llfn: Bx::Function,
/// notably `expect`.
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
- /// Debug information for MIR scopes.
- scopes: IndexVec<mir::SourceScope, debuginfo::MirDebugScope<Bx::DIScope>>,
+ per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<debuginfo::VarDebugInfo<'tcx>>>>,
}
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
value,
)
}
-
- pub fn set_debug_loc(
- &mut self,
- bx: &mut Bx,
- source_info: mir::SourceInfo
- ) {
- let (scope, span) = self.debug_loc(source_info);
- bx.set_source_location(&mut self.debug_context, scope, span);
- }
-
- pub fn debug_loc(&self, source_info: mir::SourceInfo) -> (Option<Bx::DIScope>, Span) {
- // Bail out if debug info emission is not enabled.
- match self.debug_context {
- FunctionDebugContext::DebugInfoDisabled |
- FunctionDebugContext::FunctionWithoutDebugInfo => {
- return (self.scopes[source_info.scope].scope_metadata, source_info.span);
- }
- FunctionDebugContext::RegularContext(_) =>{}
- }
-
- // In order to have a good line stepping behavior in debugger, we overwrite debug
- // locations of macro expansions with that of the outermost expansion site
- // (unless the crate is being compiled with `-Z debug-macros`).
- if !source_info.span.from_expansion() ||
- self.cx.sess().opts.debugging_opts.debug_macros {
- let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo());
- (scope, source_info.span)
- } else {
- // Walk up the macro expansion chain until we reach a non-expanded span.
- // We also stop at the function body level because no line stepping can occur
- // at the level above that.
- let span = syntax_pos::hygiene::walk_chain(source_info.span, self.mir.span.ctxt());
- let scope = self.scope_metadata_for_loc(source_info.scope, span.lo());
- // Use span of the outermost expansion site, while keeping the original lexical scope.
- (scope, span)
- }
- }
-
- // DILocations inherit source file name from the parent DIScope. Due to macro expansions
- // it may so happen that the current span belongs to a different file than the DIScope
- // corresponding to span's containing source scope. If so, we need to create a DIScope
- // "extension" into that file.
- fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos)
- -> Option<Bx::DIScope> {
- let scope_metadata = self.scopes[scope_id].scope_metadata;
- if pos < self.scopes[scope_id].file_start_pos ||
- pos >= self.scopes[scope_id].file_end_pos {
- let sm = self.cx.sess().source_map();
- let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate;
- Some(self.cx.extend_scope_to_file(
- scope_metadata.unwrap(),
- &sm.lookup_char_pos(pos).file,
- defining_crate
- ))
- } else {
- scope_metadata
- }
- }
}
enum LocalRef<'tcx, V> {
let fn_ty = FnType::new(cx, sig, &[]);
debug!("fn_ty: {:?}", fn_ty);
- let mut debug_context =
+
+ let debug_context =
cx.create_function_debug_context(instance, sig, llfn, mir);
+
let mut bx = Bx::new_block(cx, llfn, "start");
if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) {
}
}).collect();
- // Compute debuginfo scopes from MIR scopes.
- let scopes = cx.create_mir_scopes(mir, &mut debug_context);
let (landing_pads, funclets) = create_funclets(mir, &mut bx, &cleanup_kinds, &block_bxs);
let mut fx = FunctionCx {
cleanup_kinds,
landing_pads,
funclets,
- scopes,
locals: IndexVec::new(),
debug_context,
+ per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir),
};
let memory_locals = analyze::non_ssa_locals(&fx);
let layout = bx.layout_of(fx.monomorphize(&decl.ty));
assert!(!layout.ty.has_erasable_regions());
- if let Some(name) = decl.name {
- // User variable
- let debug_scope = fx.scopes[decl.visibility_scope];
- let dbg = debug_scope.is_valid() &&
- bx.sess().opts.debuginfo == DebugInfo::Full;
-
- if !memory_locals.contains(local) && !dbg {
- debug!("alloc: {:?} ({}) -> operand", local, name);
- return LocalRef::new_operand(&mut bx, layout);
- }
+ if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() {
+ debug!("alloc: {:?} (return place) -> place", local);
+ let llretptr = bx.get_param(0);
+ return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
+ }
- debug!("alloc: {:?} ({}) -> place", local, name);
+ if memory_locals.contains(local) {
+ debug!("alloc: {:?} -> place", local);
if layout.is_unsized() {
- let indirect_place =
- PlaceRef::alloca_unsized_indirect(&mut bx, layout);
- bx.set_var_name(indirect_place.llval, name);
- // FIXME: add an appropriate debuginfo
- LocalRef::UnsizedPlace(indirect_place)
+ LocalRef::UnsizedPlace(PlaceRef::alloca_unsized_indirect(&mut bx, layout))
} else {
- let place = PlaceRef::alloca(&mut bx, layout);
- bx.set_var_name(place.llval, name);
- if dbg {
- let (scope, span) = fx.debug_loc(mir::SourceInfo {
- span: decl.source_info.span,
- scope: decl.visibility_scope,
- });
- bx.declare_local(&fx.debug_context, name, layout.ty, scope.unwrap(),
- VariableAccess::DirectVariable { alloca: place.llval },
- VariableKind::LocalVariable, span);
- }
- LocalRef::Place(place)
+ LocalRef::Place(PlaceRef::alloca(&mut bx, layout))
}
} else {
- // Temporary or return place
- if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() {
- debug!("alloc: {:?} (return place) -> place", local);
- let llretptr = bx.get_param(0);
- LocalRef::Place(PlaceRef::new_sized(llretptr, layout))
- } else if memory_locals.contains(local) {
- debug!("alloc: {:?} -> place", local);
- if layout.is_unsized() {
- let indirect_place = PlaceRef::alloca_unsized_indirect(&mut bx, layout);
- bx.set_var_name(indirect_place.llval, format_args!("{:?}", local));
- LocalRef::UnsizedPlace(indirect_place)
- } else {
- let place = PlaceRef::alloca(&mut bx, layout);
- bx.set_var_name(place.llval, format_args!("{:?}", local));
- LocalRef::Place(place)
- }
- } else {
- // If this is an immediate local, we do not create an
- // alloca in advance. Instead we wait until we see the
- // definition and update the operand there.
- debug!("alloc: {:?} -> operand", local);
- LocalRef::new_operand(&mut bx, layout)
- }
+ debug!("alloc: {:?} -> operand", local);
+ LocalRef::new_operand(&mut bx, layout)
}
};
.collect()
};
+ // Apply debuginfo to the newly allocated locals.
+ fx.debug_introduce_locals(&mut bx);
+
// Branch to the START block, if it's not the entry block.
if reentrant_start_block {
bx.br(fx.blocks[mir::START_BLOCK]);
// Up until here, IR instructions for this function have explicitly not been annotated with
// source code location, so we don't step into call setup code. From here on, source location
// emitting should be enabled.
- debuginfo::start_emitting_source_locations(&mut fx.debug_context);
+ if let Some(debug_context) = &mut fx.debug_context {
+ debug_context.source_locations_enabled = true;
+ }
let rpo = traversal::reverse_postorder(&mir);
let mut visited = BitSet::new_empty(mir.basic_blocks().len());
memory_locals: &BitSet<mir::Local>,
) -> Vec<LocalRef<'tcx, Bx::Value>> {
let mir = fx.mir;
- let tcx = fx.cx.tcx();
let mut idx = 0;
let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize;
- // Get the argument scope, if it exists and if we need it.
- let arg_scope = fx.scopes[mir::OUTERMOST_SOURCE_SCOPE];
- let arg_scope = if bx.sess().opts.debuginfo == DebugInfo::Full {
- arg_scope.scope_metadata
- } else {
- None
- };
-
mir.args_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
- // FIXME(eddyb) don't allocate a `String` unless it gets used.
- let name = if let Some(name) = arg_decl.name {
- name.as_str().to_string()
- } else {
- format!("{:?}", local)
- };
-
if Some(local) == mir.spread_arg {
// This argument (e.g., the last argument in the "rust-call" ABI)
// is a tuple that was spread at the ABI level and now we have
};
let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
- bx.set_var_name(place.llval, name);
for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_ty.args[idx];
idx += 1;
bx.store_fn_arg(arg, &mut llarg_idx, pr_field);
}
- // Now that we have one alloca that contains the aggregate value,
- // we can create one debuginfo entry for the argument.
- arg_scope.map(|scope| {
- let variable_access = VariableAccess::DirectVariable {
- alloca: place.llval
- };
- bx.declare_local(
- &fx.debug_context,
- arg_decl.name.unwrap_or(kw::Invalid),
- arg_ty, scope,
- variable_access,
- VariableKind::ArgumentVariable(arg_index + 1),
- DUMMY_SP
- );
- });
-
return LocalRef::Place(place);
}
let arg_ty = fx.monomorphize(&arg_decl.ty);
let va_list = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
- bx.set_var_name(va_list.llval, name);
bx.va_start(va_list.llval);
- arg_scope.map(|scope| {
- let variable_access = VariableAccess::DirectVariable {
- alloca: va_list.llval
- };
- bx.declare_local(
- &fx.debug_context,
- arg_decl.name.unwrap_or(kw::Invalid),
- va_list.layout.ty,
- scope,
- variable_access,
- VariableKind::ArgumentVariable(arg_index + 1),
- DUMMY_SP
- );
- });
-
return LocalRef::Place(va_list);
}
llarg_idx += 1;
}
- if arg_scope.is_none() && !memory_locals.contains(local) {
+ if !memory_locals.contains(local) {
// We don't have to cast or keep the argument in the alloca.
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
// of putting everything in allocas just so we can use llvm.dbg.declare.
}
PassMode::Direct(_) => {
let llarg = bx.get_param(llarg_idx);
- bx.set_var_name(llarg, &name);
llarg_idx += 1;
return local(
OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout));
let (a, b) = (bx.get_param(llarg_idx), bx.get_param(llarg_idx + 1));
llarg_idx += 2;
- // FIXME(eddyb) these are scalar components,
- // maybe extract the high-level fields?
- bx.set_var_name(a, format_args!("{}.0", name));
- bx.set_var_name(b, format_args!("{}.1", name));
-
return local(OperandRef {
val: OperandValue::Pair(a, b),
layout: arg.layout
}
}
- let place = if arg.is_sized_indirect() {
+ if arg.is_sized_indirect() {
// Don't copy an indirect argument to an alloca, the caller
// already put it in a temporary alloca and gave it up.
// FIXME: lifetimes
let llarg = bx.get_param(llarg_idx);
- bx.set_var_name(llarg, &name);
llarg_idx += 1;
- PlaceRef::new_sized(llarg, arg.layout)
+ LocalRef::Place(PlaceRef::new_sized(llarg, arg.layout))
} else if arg.is_unsized_indirect() {
// As the storage for the indirect argument lives during
// the whole function call, we just copy the fat pointer.
let indirect_operand = OperandValue::Pair(llarg, llextra);
let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout);
- bx.set_var_name(tmp.llval, name);
indirect_operand.store(bx, tmp);
- tmp
+ LocalRef::UnsizedPlace(tmp)
} else {
let tmp = PlaceRef::alloca(bx, arg.layout);
- bx.set_var_name(tmp.llval, name);
bx.store_fn_arg(arg, &mut llarg_idx, tmp);
- tmp
- };
- let upvar_debuginfo = &mir.__upvar_debuginfo_codegen_only_do_not_use;
- arg_scope.map(|scope| {
- // Is this a regular argument?
- if arg_index > 0 || upvar_debuginfo.is_empty() {
- // The Rust ABI passes indirect variables using a pointer and a manual copy, so we
- // need to insert a deref here, but the C ABI uses a pointer and a copy using the
- // byval attribute, for which LLVM always does the deref itself,
- // so we must not add it.
- let variable_access = VariableAccess::DirectVariable {
- alloca: place.llval
- };
-
- bx.declare_local(
- &fx.debug_context,
- arg_decl.name.unwrap_or(kw::Invalid),
- arg.layout.ty,
- scope,
- variable_access,
- VariableKind::ArgumentVariable(arg_index + 1),
- DUMMY_SP
- );
- return;
- }
-
- let pin_did = tcx.lang_items().pin_type();
- // Or is it the closure environment?
- let (closure_layout, env_ref) = match arg.layout.ty.kind {
- ty::RawPtr(ty::TypeAndMut { ty, .. }) |
- ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
- ty::Adt(def, substs) if Some(def.did) == pin_did => {
- match substs.type_at(0).kind {
- ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
- _ => (arg.layout, false),
- }
- }
- _ => (arg.layout, false)
- };
-
- let (def_id, upvar_substs) = match closure_layout.ty.kind {
- ty::Closure(def_id, substs) => (def_id,
- UpvarSubsts::Closure(substs)),
- ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
- _ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty)
- };
- let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
-
- let extra_locals = {
- let upvars = upvar_debuginfo
- .iter()
- .zip(upvar_tys)
- .enumerate()
- .map(|(i, (upvar, ty))| {
- (None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP)
- });
-
- let generator_fields = mir.generator_layout.as_ref().map(|generator_layout| {
- let (def_id, gen_substs) = match closure_layout.ty.kind {
- ty::Generator(def_id, substs, _) => (def_id, substs),
- _ => bug!("generator layout without generator substs"),
- };
- let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);
-
- generator_layout.variant_fields.iter()
- .zip(state_tys)
- .enumerate()
- .flat_map(move |(variant_idx, (fields, tys))| {
- let variant_idx = Some(VariantIdx::from(variant_idx));
- fields.iter()
- .zip(tys)
- .enumerate()
- .filter_map(move |(i, (field, ty))| {
- let decl = &generator_layout.
- __local_debuginfo_codegen_only_do_not_use[*field];
- if let Some(name) = decl.name {
- let ty = fx.monomorphize(&ty);
- let (var_scope, var_span) = fx.debug_loc(mir::SourceInfo {
- span: decl.source_info.span,
- scope: decl.visibility_scope,
- });
- let var_scope = var_scope.unwrap_or(scope);
- Some((variant_idx, i, name, false, ty, var_scope, var_span))
- } else {
- None
- }
- })
- })
- }).into_iter().flatten();
-
- upvars.chain(generator_fields)
- };
-
- for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals {
- let fields = match variant_idx {
- Some(variant_idx) => {
- match &closure_layout.variants {
- Variants::Multiple { variants, .. } => {
- &variants[variant_idx].fields
- },
- _ => bug!("variant index on univariant layout"),
- }
- }
- None => &closure_layout.fields,
- };
- let byte_offset_of_var_in_env = fields.offset(field).bytes();
-
- let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);
-
- // The environment and the capture can each be indirect.
- let mut ops = if env_ref { &ops[..] } else { &ops[1..] };
-
- let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) {
- ty
- } else {
- ops = &ops[..ops.len() - 1];
- ty
- };
-
- let variable_access = VariableAccess::IndirectVariable {
- alloca: place.llval,
- address_operations: &ops
- };
- bx.declare_local(
- &fx.debug_context,
- name,
- ty,
- var_scope,
- variable_access,
- VariableKind::LocalVariable,
- var_span
- );
- }
- });
- if arg.is_unsized_indirect() {
- LocalRef::UnsizedPlace(place)
- } else {
- LocalRef::Place(place)
+ LocalRef::Place(tmp)
}
}).collect()
}
mod analyze;
mod block;
pub mod constant;
+pub mod debuginfo;
pub mod place;
pub mod operand;
mod rvalue;
}
}
+ // FIXME(eddyb) pass something else for the name so no work is done
+ // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyLayout<'tcx>,
}
/// Returns a place for an indirect reference to an unsized place.
+ // FIXME(eddyb) pass something else for the name so no work is done
+ // unless LLVM IR names are turned on (e.g. for `--emit=llvm-ir`).
pub fn alloca_unsized_indirect<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
bx: &mut Bx,
layout: TyLayout<'tcx>,
}
LocalRef::Operand(None) => {
let (mut bx, operand) = self.codegen_rvalue_operand(bx, rvalue);
- if let Some(name) = self.mir.local_decls[index].name {
- match operand.val {
- OperandValue::Ref(x, ..) |
- OperandValue::Immediate(x) => {
- bx.set_var_name(x, name);
- }
- OperandValue::Pair(a, b) => {
- // FIXME(eddyb) these are scalar components,
- // maybe extract the high-level fields?
- bx.set_var_name(a, format_args!("{}.0", name));
- bx.set_var_name(b, format_args!("{}.1", name));
- }
- }
- }
self.locals[index] = LocalRef::Operand(Some(operand));
+ self.debug_introduce_local(&mut bx, index);
bx
}
LocalRef::Operand(Some(op)) => {
use super::BackendTypes;
-use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind};
+use crate::mir::debuginfo::{FunctionDebugContext, VariableKind};
use rustc::hir::def_id::CrateNum;
use rustc::mir;
use rustc::ty::{self, Ty, Instance};
-use rustc_index::vec::IndexVec;
+use rustc::ty::layout::Size;
use syntax::ast::Name;
use syntax_pos::{SourceFile, Span};
/// Creates the function-specific debug context.
///
/// Returns the FunctionDebugContext for the function which holds state needed
- /// for debug info creation. The function may also return another variant of the
- /// FunctionDebugContext enum which indicates why no debuginfo should be created
- /// for the function.
+ /// for debug info creation, if it is enabled.
fn create_function_debug_context(
&self,
instance: Instance<'tcx>,
sig: ty::FnSig<'tcx>,
llfn: Self::Function,
mir: &mir::Body<'_>,
- ) -> FunctionDebugContext<Self::DIScope>;
+ ) -> Option<FunctionDebugContext<Self::DIScope>>;
- fn create_mir_scopes(
- &self,
- mir: &mir::Body<'_>,
- debug_context: &mut FunctionDebugContext<Self::DIScope>,
- ) -> IndexVec<mir::SourceScope, MirDebugScope<Self::DIScope>>;
fn extend_scope_to_file(
&self,
scope_metadata: Self::DIScope,
defining_crate: CrateNum,
) -> Self::DIScope;
fn debuginfo_finalize(&self);
- fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4];
}
pub trait DebugInfoBuilderMethods<'tcx>: BackendTypes {
variable_name: Name,
variable_type: Ty<'tcx>,
scope_metadata: Self::DIScope,
- variable_access: VariableAccess<'_, Self::Value>,
+ variable_alloca: Self::Value,
+ direct_offset: Size,
+ // NB: each offset implies a deref (i.e. they're steps in a pointer chain).
+ indirect_offsets: &[Size],
variable_kind: VariableKind,
span: Span,
);
fn set_source_location(
&mut self,
debug_context: &mut FunctionDebugContext<Self::DIScope>,
- scope: Option<Self::DIScope>,
+ scope: Self::DIScope,
span: Span,
);
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self);
- fn set_var_name(&mut self, value: Self::Value, name: impl ToString);
+ fn set_var_name(&mut self, value: Self::Value, name: &str);
}
where O: CloneStableAddress {}
unsafe impl<O, T: ?Sized> Send for OwningRef<O, T>
- where O: Send, for<'a> (&'a T): Send {}
+ where O: Send, for<'a> &'a T: Send {}
unsafe impl<O, T: ?Sized> Sync for OwningRef<O, T>
- where O: Sync, for<'a> (&'a T): Sync {}
+ where O: Sync, for<'a> &'a T: Sync {}
unsafe impl<O, T: ?Sized> Send for OwningRefMut<O, T>
- where O: Send, for<'a> (&'a mut T): Send {}
+ where O: Send, for<'a> &'a mut T: Send {}
unsafe impl<O, T: ?Sized> Sync for OwningRefMut<O, T>
- where O: Sync, for<'a> (&'a mut T): Sync {}
+ where O: Sync, for<'a> &'a mut T: Sync {}
impl Debug for dyn Erased {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
assert!(self.try_set(value).is_none());
}
- /// Tries to initialize the inner value by calling the closure while ensuring that no-one else
- /// can access the value in the mean time by holding a lock for the duration of the closure.
- /// If the value was already initialized the closure is not called and `false` is returned,
- /// otherwise if the value from the closure initializes the inner value, `true` is returned
+ /// Initializes the inner value if it wasn't already done by calling the provided closure. It
+ /// ensures that no-one else can access the value in the mean time by holding a lock for the
+ /// duration of the closure.
+ /// A reference to the inner value is returned.
#[inline]
- pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> bool {
- let mut lock = self.0.lock();
- if lock.is_some() {
- return false;
+ pub fn init_locking<F: FnOnce() -> T>(&self, f: F) -> &T {
+ {
+ let mut lock = self.0.lock();
+ if lock.is_none() {
+ *lock = Some(f());
+ }
}
- *lock = Some(f());
- true
+
+ self.borrow()
}
/// Tries to initialize the inner value by calling the closure without ensuring that no-one
pub render_span: Option<MultiSpan>,
}
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
pub struct DiagnosticStyledString(pub Vec<StringPart>);
impl DiagnosticStyledString {
}
}
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
pub enum StringPart {
Normal(String),
Highlighted(String),
// Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
}
- if middle < ann.line_end - 1 {
- for line in ann.line_end - 1..ann.line_end {
- add_annotation_to_file(&mut output, file.clone(), line, ann.as_line());
- }
+ let line_end = ann.line_end - 1;
+ if middle < line_end {
+ add_annotation_to_file(&mut output, file.clone(), line_end, ann.as_line());
}
} else {
end_ann.annotation_type = AnnotationType::Singleline;
pub fn has_errors(&self) -> bool {
self.inner.borrow().has_errors()
}
+ pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
+ self.inner.borrow().has_errors_or_delayed_span_bugs()
+ }
pub fn print_error_count(&self, registry: &Registry) {
self.inner.borrow_mut().print_error_count(registry)
fn has_errors(&self) -> bool {
self.err_count() > 0
}
+ fn has_errors_or_delayed_span_bugs(&self) -> bool {
+ self.has_errors() || !self.delayed_span_bugs.is_empty()
+ }
fn abort_if_errors_and_should_abort(&mut self) {
self.emit_stashed_diagnostics();
let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone();
- if sess.has_errors() {
+ if sess.has_errors_or_delayed_span_bugs() {
// If there have been any errors during compilation, we don't want to
// publish this session directory. Rather, we'll just delete it.
if sess.opts.incremental.is_none() {
return;
}
+ // This is going to be deleted in finalize_session_directory, so let's not create it
+ if sess.has_errors_or_delayed_span_bugs() {
+ return;
+ }
let query_cache_path = query_cache_path(sess);
let dep_graph_path = dep_graph_path(sess);
if sess.opts.incremental.is_none() {
return;
}
+ // This is going to be deleted in finalize_session_directory, so let's not create it
+ if sess.has_errors_or_delayed_span_bugs() {
+ return;
+ }
debug!("save_work_product_index()");
dep_graph.assert_ignored();
.map(|pred| pred.span()).collect();
let mut err = cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans,
"where clauses are not enforced in type aliases");
- err.help("the clause will not be checked when the type alias is used, \
- and should be removed");
+ err.span_suggestion(
+ type_alias_generics.where_clause.span_for_predicates_or_empty_place(),
+ "the clause will not be checked when the type alias is used, and should be removed",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
if !suggested_changing_assoc_types {
TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
suggested_changing_assoc_types = true;
// The parameters must not have bounds
for param in type_alias_generics.params.iter() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
+ let suggestion = spans.iter().map(|sp| {
+ let start = param.span.between(*sp); // Include the `:` in `T: Bound`.
+ (start.to(*sp), String::new())
+ }).collect();
if !spans.is_empty() {
let mut err = cx.struct_span_lint(
TYPE_ALIAS_BOUNDS,
spans,
"bounds on generic parameters are not enforced in type aliases",
);
- err.help("the bound will not be checked when the type alias is used, \
- and should be removed");
+ let msg = "the bound will not be checked when the type alias is used, \
+ and should be removed";
+ err.multipart_suggestion(&msg, suggestion, Applicability::MachineApplicable);
if !suggested_changing_assoc_types {
TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
suggested_changing_assoc_types = true;
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
self.check_unused_parens_pat(cx, &arm.pat, false, false);
}
+
+ fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
+ if let &ast::TyKind::Paren(ref r) = &ty.kind {
+ match &r.kind {
+ &ast::TyKind::TraitObject(..) => {}
+ &ast::TyKind::ImplTrait(_, ref bounds) if bounds.len() > 1 => {}
+ _ => {
+ let pattern_text = if let Ok(snippet) = cx.sess().source_map()
+ .span_to_snippet(ty.span) {
+ snippet
+ } else {
+ pprust::ty_to_string(ty)
+ };
+
+ Self::remove_outer_parens(cx, ty.span, &pattern_text, "type", (false, false));
+ }
+ }
+ }
+ }
}
declare_lint! {
use crate::cstore::{self, CStore, MetadataBlob};
use crate::locator::{self, CratePaths};
use crate::schema::{CrateRoot, CrateDep};
-use rustc_data_structures::sync::{RwLock, Lock, AtomicCell};
+use rustc_data_structures::sync::{Lock, Once, AtomicCell};
use rustc::hir::def_id::CrateNum;
use rustc_data_structures::svh::Svh;
let Library { source, metadata } = lib;
let crate_root = metadata.get_root();
+ let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash);
self.verify_no_symbol_conflicts(span, &crate_root);
let private_dep = self.sess.opts.externs.get(&name.as_str())
def_path_table,
trait_impls,
root: crate_root,
+ host_hash,
blob: metadata,
cnum_map,
cnum,
dependencies: Lock::new(dependencies),
- source_map_import_info: RwLock::new(vec![]),
+ source_map_import_info: Once::new(),
alloc_decoding_state: AllocDecodingState::new(interpret_alloc_index),
dep_kind: Lock::new(dep_kind),
source,
LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
LoadResult::Loaded(library) => Some(LoadResult::Loaded(library))
};
- // Don't look for a matching hash when looking for the host crate.
- // It won't be the same as the target crate hash
- locate_ctxt.hash = None;
+ locate_ctxt.hash = locate_ctxt.host_hash;
// Use the locate_ctxt when looking for the host proc macro crate, as that is required
// so we want it to affect the error message
(locate_ctxt, result)
dep: Option<(&'b CratePaths, &'b CrateDep)>,
) -> Result<CrateNum, LoadError<'b>> {
info!("resolving crate `{}`", name);
- let (root, hash, extra_filename, path_kind) = match dep {
- Some((root, dep)) =>
- (Some(root), Some(&dep.hash), Some(&dep.extra_filename[..]), PathKind::Dependency),
- None => (None, None, None, PathKind::Crate),
+ let (root, hash, host_hash, extra_filename, path_kind) = match dep {
+ Some((root, dep)) => (
+ Some(root),
+ Some(&dep.hash),
+ dep.host_hash.as_ref(),
+ Some(&dep.extra_filename[..]),
+ PathKind::Dependency
+ ),
+ None => (None, None, None, None, PathKind::Crate),
};
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
(LoadResult::Previous(cnum), None)
span,
crate_name: name,
hash,
+ host_hash,
extra_filename,
filesearch: self.sess.target_filesearch(path_kind),
target: &self.sess.target.target,
use rustc::mir::interpret::AllocDecodingState;
use rustc_index::vec::IndexVec;
use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::sync::{Lrc, RwLock, Lock, MetadataRef, AtomicCell};
+use rustc_data_structures::sync::{Lrc, Lock, MetadataRef, Once, AtomicCell};
+use rustc_data_structures::svh::Svh;
use syntax::ast;
use syntax::edition::Edition;
use syntax_expand::base::SyntaxExtension;
/// Proc macro descriptions for this crate, if it's a proc macro crate.
crate raw_proc_macros: Option<&'static [ProcMacro]>,
/// Source maps for code from the crate.
- crate source_map_import_info: RwLock<Vec<ImportedSourceFile>>,
+ crate source_map_import_info: Once<Vec<ImportedSourceFile>>,
/// Used for decoding interpret::AllocIds in a cached & thread-safe manner.
crate alloc_decoding_state: AllocDecodingState,
/// The `DepNodeIndex` of the `DepNode` representing this upstream crate.
/// Whether or not this crate should be consider a private dependency
/// for purposes of the 'exported_private_dependencies' lint
crate private_dep: bool,
+ /// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
+ crate host_hash: Option<Svh>,
// --- Data used only for improving diagnostics ---
use rustc::middle::cstore::{CrateSource, CrateStore, DepKind, EncodedMetadata, NativeLibraryKind};
use rustc::middle::exported_symbols::ExportedSymbol;
use rustc::middle::stability::DeprecationEntry;
-use rustc::middle::dependency_format::Linkage;
use rustc::hir::def;
use rustc::hir;
use rustc::session::{CrateDisambiguator, Session};
used_crate_source => { Lrc::new(cdata.source.clone()) }
exported_symbols => {
- let mut syms = cdata.exported_symbols(tcx);
-
- // When linked into a dylib crates don't export their generic symbols,
- // so if that's happening then we can't load upstream monomorphizations
- // from this crate.
- let formats = tcx.dependency_formats(LOCAL_CRATE);
- let remove_generics = formats.iter().any(|(_ty, list)| {
- match list.get(def_id.krate.as_usize() - 1) {
- Some(Linkage::IncludedFromDylib) | Some(Linkage::Dynamic) => true,
- _ => false,
- }
- });
- if remove_generics {
- syms.retain(|(sym, _threshold)| {
- match sym {
- ExportedSymbol::Generic(..) => false,
- _ => return true,
- }
- });
- }
+ let syms = cdata.exported_symbols(tcx);
+
+ // FIXME rust-lang/rust#64319, rust-lang/rust#64872: We want
+ // to block export of generics from dylibs, but we must fix
+ // rust-lang/rust#65890 before we can do that robustly.
Arc::new(syms)
}
self.get_crate_data(cnum).root.hash
}
+ fn crate_host_hash_untracked(&self, cnum: CrateNum) -> Option<Svh> {
+ self.get_crate_data(cnum).host_hash
+ }
+
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
use crate::table::{FixedSizeEncoding, PerDefTable};
use rustc_index::vec::IndexVec;
-use rustc_data_structures::sync::{Lrc, ReadGuard};
+use rustc_data_structures::sync::Lrc;
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc::hir;
use rustc::middle::cstore::{LinkagePreference, NativeLibrary, ForeignModule};
tcx: TyCtxt<'tcx>,
) -> ty::GenericPredicates<'tcx> {
self.root.per_def.predicates.get(self, item_id).unwrap().decode((self, tcx))
-}
+ }
crate fn get_predicates_defined_on(
&self,
fn imported_source_files(
&'a self,
local_source_map: &source_map::SourceMap,
- ) -> ReadGuard<'a, Vec<cstore::ImportedSourceFile>> {
- {
- let source_files = self.source_map_import_info.borrow();
- if !source_files.is_empty() {
- return source_files;
- }
- }
-
- // Lock the source_map_import_info to ensure this only happens once
- let mut source_map_import_info = self.source_map_import_info.borrow_mut();
-
- if !source_map_import_info.is_empty() {
- drop(source_map_import_info);
- return self.source_map_import_info.borrow();
- }
-
- let external_source_map = self.root.source_map.decode(self);
-
- let imported_source_files = external_source_map.map(|source_file_to_import| {
- // We can't reuse an existing SourceFile, so allocate a new one
- // containing the information we need.
- let syntax_pos::SourceFile { name,
- name_was_remapped,
- src_hash,
- start_pos,
- end_pos,
- mut lines,
- mut multibyte_chars,
- mut non_narrow_chars,
- mut normalized_pos,
- name_hash,
- .. } = source_file_to_import;
-
- let source_length = (end_pos - start_pos).to_usize();
-
- // Translate line-start positions and multibyte character
- // position into frame of reference local to file.
- // `SourceMap::new_imported_source_file()` will then translate those
- // coordinates to their new global frame of reference when the
- // offset of the SourceFile is known.
- for pos in &mut lines {
- *pos = *pos - start_pos;
- }
- for mbc in &mut multibyte_chars {
- mbc.pos = mbc.pos - start_pos;
- }
- for swc in &mut non_narrow_chars {
- *swc = *swc - start_pos;
- }
- for np in &mut normalized_pos {
- np.pos = np.pos - start_pos;
- }
-
- let local_version = local_source_map.new_imported_source_file(name,
- name_was_remapped,
- self.cnum.as_u32(),
- src_hash,
- name_hash,
- source_length,
- lines,
- multibyte_chars,
- non_narrow_chars,
- normalized_pos);
- debug!("CrateMetaData::imported_source_files alloc \
- source_file {:?} original (start_pos {:?} end_pos {:?}) \
- translated (start_pos {:?} end_pos {:?})",
- local_version.name, start_pos, end_pos,
- local_version.start_pos, local_version.end_pos);
-
- cstore::ImportedSourceFile {
- original_start_pos: start_pos,
- original_end_pos: end_pos,
- translated_source_file: local_version,
- }
- }).collect();
-
- *source_map_import_info = imported_source_files;
- drop(source_map_import_info);
+ ) -> &[cstore::ImportedSourceFile] {
+ self.source_map_import_info.init_locking(|| {
+ let external_source_map = self.root.source_map.decode(self);
+
+ external_source_map.map(|source_file_to_import| {
+ // We can't reuse an existing SourceFile, so allocate a new one
+ // containing the information we need.
+ let syntax_pos::SourceFile { name,
+ name_was_remapped,
+ src_hash,
+ start_pos,
+ end_pos,
+ mut lines,
+ mut multibyte_chars,
+ mut non_narrow_chars,
+ mut normalized_pos,
+ name_hash,
+ .. } = source_file_to_import;
+
+ let source_length = (end_pos - start_pos).to_usize();
+
+ // Translate line-start positions and multibyte character
+ // position into frame of reference local to file.
+ // `SourceMap::new_imported_source_file()` will then translate those
+ // coordinates to their new global frame of reference when the
+ // offset of the SourceFile is known.
+ for pos in &mut lines {
+ *pos = *pos - start_pos;
+ }
+ for mbc in &mut multibyte_chars {
+ mbc.pos = mbc.pos - start_pos;
+ }
+ for swc in &mut non_narrow_chars {
+ *swc = *swc - start_pos;
+ }
+ for np in &mut normalized_pos {
+ np.pos = np.pos - start_pos;
+ }
- // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref.
- self.source_map_import_info.borrow()
+ let local_version = local_source_map.new_imported_source_file(name,
+ name_was_remapped,
+ self.cnum.as_u32(),
+ src_hash,
+ name_hash,
+ source_length,
+ lines,
+ multibyte_chars,
+ non_narrow_chars,
+ normalized_pos);
+ debug!("CrateMetaData::imported_source_files alloc \
+ source_file {:?} original (start_pos {:?} end_pos {:?}) \
+ translated (start_pos {:?} end_pos {:?})",
+ local_version.name, start_pos, end_pos,
+ local_version.start_pos, local_version.end_pos);
+
+ cstore::ImportedSourceFile {
+ original_start_pos: start_pos,
+ original_end_pos: end_pos,
+ translated_source_file: local_version,
+ }
+ }).collect()
+ })
}
/// Get the `DepNodeIndex` corresponding this crate. The result of this
let dep = CrateDep {
name: self.tcx.original_crate_name(cnum),
hash: self.tcx.crate_hash(cnum),
+ host_hash: self.tcx.crate_host_hash(cnum),
kind: self.tcx.dep_kind(cnum),
extra_filename: self.tcx.extra_filename(cnum),
};
pub span: Span,
pub crate_name: Symbol,
pub hash: Option<&'a Svh>,
+ pub host_hash: Option<&'a Svh>,
pub extra_filename: Option<&'a str>,
// points to either self.sess.target.target or self.sess.host, must match triple
pub target: &'a Target,
span,
crate_name: name,
hash: None,
+ host_hash: None,
extra_filename: None,
filesearch: sess.host_filesearch(PathKind::Crate),
target: &sess.host,
crate struct CrateDep {
pub name: ast::Name,
pub hash: Svh,
+ pub host_hash: Option<Svh>,
pub kind: DepKind,
pub extra_filename: String,
}
body: &'cx Body<'tcx>,
tcx: TyCtxt<'tcx>,
kind: PrefixSet,
- next: Option<(PlaceRef<'cx, 'tcx>)>,
+ next: Option<PlaceRef<'cx, 'tcx>>,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
// E0471, // constant evaluation error (in pattern)
// E0385, // {} in an aliasable location
E0521, // borrowed data escapes outside of closure
- E0526, // shuffle indices are not constant
+// E0526, // shuffle indices are not constant
E0594, // cannot assign to {}
// E0598, // lifetime of {} is too short to guarantee its contents can be...
E0625, // thread-local statics cannot be accessed at compile-time
use rustc::mir::interpret::{InterpResult, Scalar, GlobalId, ConstValue};
use super::{
- Machine, PlaceTy, OpTy, InterpCx,
+ Machine, PlaceTy, OpTy, InterpCx, ImmTy,
};
mod caller_location;
let result = Scalar::from_uint(truncated_bits, layout.size);
self.write_scalar(result, dest)?;
}
+
+ "ptr_offset_from" => {
+ let a = self.read_immediate(args[0])?.to_scalar()?.to_ptr()?;
+ let b = self.read_immediate(args[1])?.to_scalar()?.to_ptr()?;
+ if a.alloc_id != b.alloc_id {
+ throw_ub_format!(
+ "ptr_offset_from cannot compute offset of pointers into different \
+ allocations.",
+ );
+ }
+ let usize_layout = self.layout_of(self.tcx.types.usize)?;
+ let a_offset = ImmTy::from_uint(a.offset.bytes(), usize_layout);
+ let b_offset = ImmTy::from_uint(b.offset.bytes(), usize_layout);
+ let (val, _overflowed, _ty) = self.overflowing_binary_op(
+ BinOp::Sub, a_offset, b_offset,
+ )?;
+ let pointee_layout = self.layout_of(substs.type_at(0))?;
+ let isize_layout = self.layout_of(self.tcx.types.isize)?;
+ let val = ImmTy::from_scalar(val, isize_layout);
+ let size = ImmTy::from_int(pointee_layout.size.bytes(), isize_layout);
+ self.exact_div(val, size, dest)?;
+ }
+
"transmute" => {
self.copy_op_transmute(args[0], dest)?;
}
return Ok(false);
}
}
+
+ pub fn exact_div(
+ &mut self,
+ a: ImmTy<'tcx, M::PointerTag>,
+ b: ImmTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
+ ) -> InterpResult<'tcx> {
+ // Performs an exact division, resulting in undefined behavior where
+ // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1`.
+ // First, check x % y != 0.
+ if self.binary_op(BinOp::Rem, a, b)?.to_bits()? != 0 {
+ // Then, check if `b` is -1, which is the "min_value / -1" case.
+ let minus1 = Scalar::from_int(-1, dest.layout.size);
+ let b = b.to_scalar().unwrap();
+ if b == minus1 {
+ throw_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented")
+ } else {
+ throw_ub_format!(
+ "exact_div: {} cannot be divided by {} without remainder",
+ a.to_scalar().unwrap(),
+ b,
+ )
+ }
+ }
+ self.binop_ignore_overflow(BinOp::Div, a, b, dest)
+ }
}
};
pub use rustc::mir::interpret::ScalarMaybeUndef;
-/// A `Value` represents a single immediate self-contained Rust value.
+/// An `Immediate` represents a single immediate self-contained Rust value.
///
/// For optimization of a few very common cases, there is also a representation for a pair of
/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary
Argument { bb: BasicBlock, index: usize },
}
+impl Candidate {
+ /// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
+ fn forces_explicit_promotion(&self) -> bool {
+ match self {
+ Candidate::Ref(_) |
+ Candidate::Repeat(_) => false,
+ Candidate::Argument { .. } => true,
+ }
+ }
+}
+
fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
let attrs = tcx.get_attrs(def_id);
let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
};
candidates.iter().copied().filter(|&candidate| {
- validator.explicit = match candidate {
- Candidate::Ref(_) |
- Candidate::Repeat(_) => false,
- Candidate::Argument { .. } => true,
- };
+ validator.explicit = candidate.forces_explicit_promotion();
// FIXME(eddyb) also emit the errors for shuffle indices
// and `#[rustc_args_required_const]` arguments here.
- validator.validate_candidate(candidate).is_ok()
+ let is_promotable = validator.validate_candidate(candidate).is_ok();
+ match candidate {
+ Candidate::Argument { bb, index } if !is_promotable => {
+ let span = body[bb].terminator().source_info.span;
+ let msg = format!("argument {} is required to be a constant", index + 1);
+ tcx.sess.span_err(span, &msg);
+ }
+ _ => ()
+ }
+
+ is_promotable
}).collect()
}
| "transmute"
| "simd_insert"
| "simd_extract"
+ | "ptr_offset_from"
=> return true,
_ => {}
// This is not a problem, because the argument explicitly
// requests constness, in contrast to regular promotion
// which happens even without the user requesting it.
- // We can error out with a hard error if the argument is not
- // constant here.
+ //
+ // `promote_consts` is responsible for emitting the error if
+ // the argument is not promotable.
if !IsNotPromotable::in_operand(self, arg) {
debug!("visit_terminator_kind: candidate={:?}", candidate);
self.promotion_candidates.push(candidate);
- } else {
- if is_shuffle {
- span_err!(self.tcx.sess, self.span, E0526,
- "shuffle indices are not constant");
- } else {
- self.tcx.sess.span_err(self.span,
- &format!("argument {} is required to be a constant",
- i + 1));
- }
}
}
}
where
W: Write,
{
- for def_id in dump_mir_def_ids(tcx, single) {
+ let def_ids = dump_mir_def_ids(tcx, single);
+
+ let use_subgraphs = def_ids.len() > 1;
+ if use_subgraphs {
+ writeln!(w, "digraph __crate__ {{")?;
+ }
+
+ for def_id in def_ids {
let body = &tcx.optimized_mir(def_id);
- write_mir_fn_graphviz(tcx, def_id, body, w)?;
+ write_mir_fn_graphviz(tcx, def_id, body, use_subgraphs, w)?;
}
+
+ if use_subgraphs {
+ writeln!(w, "}}")?;
+ }
+
Ok(())
}
tcx: TyCtxt<'tcx>,
def_id: DefId,
body: &Body<'_>,
+ subgraph: bool,
w: &mut W,
) -> io::Result<()>
where
W: Write,
{
- writeln!(w, "digraph Mir_{} {{", graphviz_safe_def_name(def_id))?;
+ let kind = if subgraph { "subgraph" } else { "digraph" };
+ let cluster = if subgraph { "cluster_" } else { "" }; // Prints a border around MIR
+ let def_name = graphviz_safe_def_name(def_id);
+ writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?;
// Global graph properties
writeln!(w, r#" graph [fontname="monospace"];"#)?;
// Nodes
for (block, _) in body.basic_blocks().iter_enumerated() {
- write_node(block, body, w)?;
+ write_node(def_id, block, body, w)?;
}
// Edges
for (source, _) in body.basic_blocks().iter_enumerated() {
- write_edges(source, body, w)?;
+ write_edges(def_id, source, body, w)?;
}
writeln!(w, "}}")
}
fini(w)?;
// Close the table
- writeln!(w, "</table>")
+ write!(w, "</table>")
}
/// Write a graphviz DOT node for the given basic block.
-fn write_node<W: Write>(block: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> {
+fn write_node<W: Write>(
+ def_id: DefId,
+ block: BasicBlock,
+ body: &Body<'_>,
+ w: &mut W,
+) -> io::Result<()> {
// Start a new node with the label to follow, in one of DOT's pseudo-HTML tables.
- write!(w, r#" {} [shape="none", label=<"#, node(block))?;
+ write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?;
write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?;
// Close the node label and the node itself.
writeln!(w, ">];")
}
/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
-fn write_edges<W: Write>(source: BasicBlock, body: &Body<'_>, w: &mut W) -> io::Result<()> {
+fn write_edges<W: Write>(
+ def_id: DefId,
+ source: BasicBlock,
+ body: &Body<'_>,
+ w: &mut W,
+) -> io::Result<()> {
let terminator = body[source].terminator();
let labels = terminator.kind.fmt_successor_labels();
for (&target, label) in terminator.successors().zip(labels) {
- writeln!(w, r#" {} -> {} [label="{}"];"#, node(source), node(target), label)?;
+ let src = node(def_id, source);
+ let trg = node(def_id, target);
+ writeln!(w, r#" {} -> {} [label="{}"];"#, src, trg, label)?;
}
Ok(())
writeln!(w, ">;")
}
-fn node(block: BasicBlock) -> String {
- format!("bb{}", block.index())
+fn node(def_id: DefId, block: BasicBlock) -> String {
+ format!("bb{}__{}", block.index(), graphviz_safe_def_name(def_id))
}
fn escape<T: Debug>(t: &T) -> String {
let _: io::Result<()> = try {
let mut file =
create_dump_file(tcx, "dot", pass_num, pass_name, disambiguator, source)?;
- write_mir_fn_graphviz(tcx, source.def_id(), body, &mut file)?;
+ write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?;
};
}
}
if self.r.is_accessible_from(vis, parent_scope.module) {
vis
} else {
- let msg =
- "visibilities can only be restricted to ancestor modules";
- self.r.session.span_err(path.span, msg);
+ struct_span_err!(self.r.session, path.span, E0742,
+ "visibilities can only be restricted to ancestor modules")
+ .emit();
ty::Visibility::Public
}
}
```
"##,
+E0577: r##"
+Something other than a module was found in visibility scope.
+
+Erroneous code example:
+
+```compile_fail,E0577,edition2018
+pub struct Sea;
+
+pub (in crate::Sea) struct Shark; // error!
+
+fn main() {}
+```
+
+`Sea` is not a module, therefore it is invalid to use it in a visibility path.
+To fix this error we need to ensure `Sea` is a module.
+
+Please note that the visibility scope can only be applied on ancestors!
+
+```edition2018
+pub mod Sea {
+ pub (in crate::Sea) struct Shark; // ok!
+}
+
+fn main() {}
+```
+"##,
+
+E0578: r##"
+A module cannot be found and therefore, the visibility cannot be determined.
+
+Erroneous code example:
+
+```compile_fail,E0578,edition2018
+foo!();
+
+pub (in ::Sea) struct Shark; // error!
+
+fn main() {}
+```
+
+Because of the call to the `foo` macro, the compiler guesses that the missing
+module could be inside it and fails because the macro definition cannot be
+found.
+
+To fix this error, please be sure that the module is in scope:
+
+```edition2018
+pub mod Sea {
+ pub (in crate::Sea) struct Shark;
+}
+
+fn main() {}
+```
+"##,
+
E0603: r##"
A private item was used outside its scope.
Const parameters cannot depend on type parameters.
The following is therefore invalid:
+
```compile_fail,E0741
#![feature(const_generics)]
```
"##,
+E0742: r##"
+Visibility is restricted to a module which isn't an ancestor of the current
+item.
+
+Erroneous code example:
+
+```compile_fail,E0742,edition2018
+pub mod Sea {}
+
+pub (in crate::Sea) struct Shark; // error!
+
+fn main() {}
+```
+
+To fix this error, we need to move the `Shark` struct inside the `Sea` module:
+
+```edition2018
+pub mod Sea {
+ pub (in crate::Sea) struct Shark; // ok!
+}
+
+fn main() {}
+```
+
+Of course, you can do it as long as the module you're referring to is an
+ancestor:
+
+```edition2018
+pub mod Earth {
+ pub mod Sea {
+ pub (in crate::Earth) struct Shark; // ok!
+ }
+}
+
+fn main() {}
+```
+"##,
+
;
// E0153, unused error code
// E0157, unused error code
// E0427, merged into 530
// E0467, removed
// E0470, removed
- E0577,
- E0578,
}
if !is_prelude &&
max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
!max_vis.get().is_at_least(directive.vis.get(), &*self) {
- let msg = "A non-empty glob must import something with the glob's visibility";
- self.r.session.span_err(directive.span, msg);
+ let msg =
+ "glob import doesn't reexport anything because no candidate is public enough";
+ self.r.session.buffer_lint(UNUSED_IMPORTS, directive.id, directive.span, msg);
}
return None;
}
}
if let ast::FunctionRetTy::Ty(ref ret_ty) = sig.decl.output {
- v.visit_ty(ret_ty);
+ // In async functions, return types are desugared and redefined
+ // as an `impl Trait` existential type. Because of this, to match
+ // the definition paths when resolving nested types we need to
+ // start walking from the newly-created definition.
+ match sig.header.asyncness.node {
+ ast::IsAsync::Async { return_impl_trait_id, .. } => {
+ v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
+ }
+ _ => v.visit_ty(ret_ty)
+ }
}
// walk the fn body
&mut self,
item: &'l ast::Item,
decl: &'l ast::FnDecl,
+ header: &'l ast::FnHeader,
ty_params: &'l ast::Generics,
body: &'l ast::Block,
) {
// FIXME: Opaque type desugaring prevents us from easily
// processing trait bounds. See `visit_ty` for more details.
} else {
- v.visit_ty(&ret_ty);
+ // In async functions, return types are desugared and redefined
+ // as an `impl Trait` existential type. Because of this, to match
+ // the definition paths when resolving nested types we need to
+ // start walking from the newly-created definition.
+ match header.asyncness.node {
+ ast::IsAsync::Async { return_impl_trait_id, .. } => {
+ v.nest_tables(return_impl_trait_id, |v| v.visit_ty(ret_ty))
+ }
+ _ => v.visit_ty(ret_ty)
+ }
}
}
);
}
}
- Fn(ref decl, .., ref ty_params, ref body) => {
- self.process_fn(item, &decl, ty_params, &body)
+ Fn(ref decl, ref header, ref ty_params, ref body) => {
+ self.process_fn(item, &decl, &header, ty_params, &body)
}
Static(ref typ, _, ref expr) => self.process_static_or_const_item(item, typ, expr),
Const(ref typ, ref expr) => self.process_static_or_const_item(item, &typ, &expr),
"-s".to_string(),
"ASSERTIONS=1".to_string(),
"-s".to_string(),
- "DISABLE_EXCEPTION_CATCHING=1".to_string(),
- "-s".to_string(),
"ABORTING_MALLOC=0".to_string(),
- // FIXME(tlively): Enable this linker option once libc type errors
- // are resolved. See https://github.com/rust-lang/libc/pull/1478.
- // "-Wl,--fatal-warnings".to_string(),
+ "-Wl,--fatal-warnings".to_string(),
]);
let opts = TargetOptions {
linker: None,
linker_is_gnu: true,
is_like_emscripten: true,
- // FIXME(tlively): Emscripten supports unwinding, but we would have to pass
- // -enable-emscripten-cxx-exceptions to LLVM at codegen time and merge
- // https://reviews.llvm.org/rG5c3cdef84b82464756bb571c13c31cf7773860c3to use it.
- panic_strategy: PanicStrategy::Abort,
+ panic_strategy: PanicStrategy::Unwind,
post_link_args,
target_family: Some("unix".to_string()),
.. wasm32_base::options()
(1, vec![param(0), param(0)],
tcx.intern_tup(&[param(0), tcx.types.bool])),
+ "ptr_offset_from" =>
+ (1, vec![ tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0)) ], tcx.types.isize),
"unchecked_div" | "unchecked_rem" | "exact_div" =>
(1, vec![param(0), param(0)], param(0)),
"unchecked_shl" | "unchecked_shr" |
<section id=\"main\" class=\"content\">{content}</section>\
<section id=\"search\" class=\"content hidden\"></section>\
<section class=\"footer\"></section>\
- <aside id=\"help\" class=\"hidden\">\
- <div>\
- <h1 class=\"hidden\">Help</h1>\
- <div class=\"shortcuts\">\
- <h2>Keyboard Shortcuts</h2>\
- <dl>\
- <dt><kbd>?</kbd></dt>\
- <dd>Show this help dialog</dd>\
- <dt><kbd>S</kbd></dt>\
- <dd>Focus the search field</dd>\
- <dt><kbd>↑</kbd></dt>\
- <dd>Move up in search results</dd>\
- <dt><kbd>↓</kbd></dt>\
- <dd>Move down in search results</dd>\
- <dt><kbd>↹</kbd></dt>\
- <dd>Switch tab</dd>\
- <dt><kbd>⏎</kbd></dt>\
- <dd>Go to active search result</dd>\
- <dt><kbd>+</kbd></dt>\
- <dd>Expand all sections</dd>\
- <dt><kbd>-</kbd></dt>\
- <dd>Collapse all sections</dd>\
- </dl>\
- </div>\
- <div class=\"infos\">\
- <h2>Search Tricks</h2>\
- <p>\
- Prefix searches with a type followed by a colon (e.g., \
- <code>fn:</code>) to restrict the search to a given type.\
- </p>\
- <p>\
- Accepted types are: <code>fn</code>, <code>mod</code>, \
- <code>struct</code>, <code>enum</code>, \
- <code>trait</code>, <code>type</code>, <code>macro</code>, \
- and <code>const</code>.\
- </p>\
- <p>\
- Search functions by type signature (e.g., \
- <code>vec -> usize</code> or <code>* -> vec</code>)\
- </p>\
- <p>\
- Search multiple things at once by splitting your query with comma (e.g., \
- <code>str,u8</code> or <code>String,struct:Vec,test</code>)\
- </p>\
- <p>\
- You can look for items with an exact name by putting double quotes around \
- your request: <code>\"string\"</code>\
- </p>\
- <p>\
- Look for items inside another one by searching for a path: \
- <code>vec::Vec</code>\
- </p>\
- </div>\
- </div>\
- </aside>\
{after_content}\
<script>\
window.rootPath = \"{root_path}\";\
set_fragment(cur_id);
}
- } else if (hasClass(document.getElementById("help"), "hidden") === false) {
- addClass(document.getElementById("help"), "hidden");
- removeClass(document.body, "blur");
+ } else if (hasClass(getHelpElement(), "hidden") === false) {
+ var help = getHelpElement();
+ var is_inside_help_popup = ev.target !== help && help.contains(ev.target);
+ if (is_inside_help_popup === false) {
+ addClass(help, "hidden");
+ removeClass(document.body, "blur");
+ }
} else {
// Making a collapsed element visible on onhashchange seems
// too late
}
dst = dst[0];
if (window.location.pathname === dst.pathname) {
- addClass(document.getElementById("search"), "hidden");
+ addClass(getSearchElement(), "hidden");
removeClass(main, "hidden");
document.location.href = dst.href;
}
function putBackSearch(search_input) {
if (search_input.value !== "") {
addClass(main, "hidden");
- removeClass(document.getElementById("search"), "hidden");
+ removeClass(getSearchElement(), "hidden");
if (browserSupportsHistoryApi()) {
history.replaceState(search_input.value,
"",
}
window.addSearchOptions = addSearchOptions;
+
+ function buildHelperPopup() {
+ var popup = document.createElement("aside");
+ addClass(popup, "hidden");
+ popup.id = "help";
+
+ var container = document.createElement("div");
+ var shortcuts = [
+ ["?", "Show this help dialog"],
+ ["S", "Focus the search field"],
+ ["↑", "Move up in search results"],
+ ["↓", "Move down in search results"],
+ ["↹", "Switch tab"],
+ ["⏎", "Go to active search result"],
+ ["+", "Expand all sections"],
+ ["-", "Collapse all sections"],
+ ].map(x => "<dt><kbd>" + x[0] + "</kbd></dt><dd>" + x[1] + "</dd>").join("");
+ var div_shortcuts = document.createElement("div");
+ addClass(div_shortcuts, "shortcuts");
+ div_shortcuts.innerHTML = "<h2>Keyboard Shortcuts</h2><dl>" + shortcuts + "</dl></div>";
+
+ var infos = [
+ "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
+ restrict the search to a given type.",
+ "Accepted types are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
+ <code>enum</code>, <code>trait</code>, <code>type</code>, <code>macro</code>, \
+ and <code>const</code>.",
+ "Search functions by type signature (e.g., <code>vec -> usize</code> or \
+ <code>* -> vec</code>)",
+ "Search multiple things at once by splitting your query with comma (e.g., \
+ <code>str,u8</code> or <code>String,struct:Vec,test</code>)",
+ "You can look for items with an exact name by putting double quotes around \
+ your request: <code>\"string\"</code>",
+ "Look for items inside another one by searching for a path: <code>vec::Vec</code>",
+ ].map(x => "<p>" + x + "</p>").join("");
+ var div_infos = document.createElement("div");
+ addClass(div_infos, "infos");
+ div_infos.innerHTML = "<h2>Search Tricks</h2>" + infos;
+
+ container.appendChild(div_shortcuts);
+ container.appendChild(div_infos);
+
+ popup.appendChild(container);
+ insertAfter(popup, getSearchElement());
+ }
+
+ buildHelperPopup();
}());
// Sets the focus on the search bar at the top of the page
continue;
}
+ // In order to correctly resolve intra-doc-links we need to
+ // pick a base AST node to work from. If the documentation for
+ // this module came from an inner comment (//!) then we anchor
+ // our name resolution *inside* the module. If, on the other
+ // hand it was an outer comment (///) then we anchor the name
+ // resolution in the parent module on the basis that the names
+ // used are more likely to be intended to be parent names. For
+ // this, we set base_node to None for inner comments since
+ // we've already pushed this node onto the resolution stack but
+ // for outer comments we explicitly try and resolve against the
+ // parent_node first.
+ let base_node = if item.is_mod() && item.attrs.inner_docs {
+ None
+ } else {
+ parent_node
+ };
+
match kind {
Some(ns @ ValueNS) => {
- if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) {
+ if let Ok(res) = self.resolve(path_str, ns, ¤t_item, base_node) {
res
} else {
resolution_failure(cx, &item, path_str, &dox, link_range);
}
}
Some(ns @ TypeNS) => {
- if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) {
+ if let Ok(res) = self.resolve(path_str, ns, ¤t_item, base_node) {
res
} else {
resolution_failure(cx, &item, path_str, &dox, link_range);
let candidates = PerNS {
macro_ns: macro_resolve(cx, path_str).map(|res| (res, None)),
type_ns: self
- .resolve(path_str, TypeNS, ¤t_item, parent_node)
+ .resolve(path_str, TypeNS, ¤t_item, base_node)
.ok(),
value_ns: self
- .resolve(path_str, ValueNS, ¤t_item, parent_node)
+ .resolve(path_str, ValueNS, ¤t_item, base_node)
.ok()
.and_then(|(res, fragment)| {
// Constructors are picked up in the type namespace.
type Item = &'a K;
#[inline]
- fn next(&mut self) -> Option<(&'a K)> {
+ fn next(&mut self) -> Option<&'a K> {
self.inner.next().map(|(k, _)| k)
}
#[inline]
type Item = &'a V;
#[inline]
- fn next(&mut self) -> Option<(&'a V)> {
+ fn next(&mut self) -> Option<&'a V> {
self.inner.next().map(|(_, v)| v)
}
#[inline]
type Item = &'a mut V;
#[inline]
- fn next(&mut self) -> Option<(&'a mut V)> {
+ fn next(&mut self) -> Option<&'a mut V> {
self.inner.next().map(|(_, v)| v)
}
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsString, OsStr};
-#[stable(feature = "raw_os", since = "1.1.0")]
+#[stable(feature = "core_c_void", since = "1.30.0")]
pub use core::ffi::c_void;
#[unstable(feature = "c_variadic",
///
/// # Examples
///
-/// Creates a new file and write bytes to it:
+/// Creates a new file and write bytes to it (you can also use [`write`]):
///
/// ```no_run
/// use std::fs::File;
/// }
/// ```
///
-/// Read the contents of a file into a [`String`]:
+/// Read the contents of a file into a [`String`] (you can also use [`read`]):
///
/// ```no_run
/// use std::fs::File;
/// [`Write`]: ../io/trait.Write.html
/// [`BufReader<R>`]: ../io/struct.BufReader.html
/// [`sync_all`]: struct.File.html#method.sync_all
+/// [`read`]: fn.read.html
+/// [`write`]: fn.write.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct File {
inner: fs_imp::File,
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
}
+ /// Returns a new OpenOptions object.
+ ///
+ /// This function returns a new OpenOptions object that you can use to
+ /// open or create a file with specific options if `open()` or `create()`
+ /// are not appropriate.
+ ///
+ /// It is equivalent to `OpenOptions::new()` but allows you to write more
+ /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
+ /// you can write `File::with_options().read(true).open("foo.txt"). This
+ /// also avoids the need to import `OpenOptions`.
+ ///
+ /// See the [`OpenOptions::new`] function for more details.
+ ///
+ /// [`OpenOptions::new`]: struct.OpenOptions.html#method.new
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(with_options)]
+ /// use std::fs::File;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let mut f = File::with_options().read(true).open("foo.txt")?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "with_options", issue = "65439")]
+ pub fn with_options() -> OpenOptions {
+ OpenOptions::new()
+ }
+
/// Attempts to sync all OS-internal metadata to disk.
///
/// This function will attempt to ensure that all in-memory data reaches the
use crate::os::raw;
use crate::sys;
use crate::io;
-use crate::sys_common::{AsInner, FromInner, IntoInner};
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+use crate::net;
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> AsRawFd for io::StderrLock<'a> {
fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+ fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
+ }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let socket = sys::net::Socket::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_socket().into_inner()
+ }
+}
-// Uhhh
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
pub mod fs;
pub mod raw;
pub mod process;
-pub mod net;
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
+++ /dev/null
-#![stable(feature = "unix_socket", since = "1.10.0")]
-
-//! Unix-specific networking functionality
-
-#[cfg(unix)]
-use libc;
-
-use crate::ascii;
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io::{self, Initializer, IoSlice, IoSliceMut};
-use crate::mem;
-use crate::net::{self, Shutdown};
-use crate::os::unix::ffi::OsStrExt;
-use crate::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
-use crate::path::Path;
-use crate::time::Duration;
-use crate::sys::{self, cvt};
-use crate::sys::net::Socket;
-use crate::sys_common::{self, AsInner, FromInner, IntoInner};
-
-const MSG_NOSIGNAL: libc::c_int = 0x0;
-
-fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
- // Work with an actual instance of the type since using a null pointer is UB
- let base = addr as *const _ as usize;
- let path = &addr.sun_path as *const _ as usize;
- path - base
-}
-
-unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
- let mut addr: libc::sockaddr_un = mem::zeroed();
- addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
-
- let bytes = path.as_os_str().as_bytes();
-
- if bytes.contains(&0) {
- return Err(io::Error::new(io::ErrorKind::InvalidInput,
- "paths may not contain interior null bytes"));
- }
-
- if bytes.len() >= addr.sun_path.len() {
- return Err(io::Error::new(io::ErrorKind::InvalidInput,
- "path must be shorter than SUN_LEN"));
- }
- for (dst, src) in addr.sun_path.iter_mut().zip(bytes.iter()) {
- *dst = *src as libc::c_char;
- }
- // null byte for pathname addresses is already there because we zeroed the
- // struct
-
- let mut len = sun_path_offset(&addr) + bytes.len();
- match bytes.get(0) {
- Some(&0) | None => {}
- Some(_) => len += 1,
- }
- Ok((addr, len as libc::socklen_t))
-}
-
-enum AddressKind<'a> {
- Unnamed,
- Pathname(&'a Path),
- Abstract(&'a [u8]),
-}
-
-/// An address associated with a Unix socket.
-///
-/// # Examples
-///
-/// ```
-/// use std::os::unix::net::UnixListener;
-///
-/// let socket = match UnixListener::bind("/tmp/sock") {
-/// Ok(sock) => sock,
-/// Err(e) => {
-/// println!("Couldn't bind: {:?}", e);
-/// return
-/// }
-/// };
-/// let addr = socket.local_addr().expect("Couldn't get local address");
-/// ```
-#[derive(Clone)]
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct SocketAddr {
- addr: libc::sockaddr_un,
- len: libc::socklen_t,
-}
-
-impl SocketAddr {
- fn new<F>(f: F) -> io::Result<SocketAddr>
- where F: FnOnce(*mut libc::sockaddr, *mut libc::socklen_t) -> libc::c_int
- {
- unsafe {
- let mut addr: libc::sockaddr_un = mem::zeroed();
- let mut len = mem::size_of::<libc::sockaddr_un>() as libc::socklen_t;
- cvt(f(&mut addr as *mut _ as *mut _, &mut len))?;
- SocketAddr::from_parts(addr, len)
- }
- }
-
- fn from_parts(addr: libc::sockaddr_un, mut len: libc::socklen_t) -> io::Result<SocketAddr> {
- if len == 0 {
- // When there is a datagram from unnamed unix socket
- // linux returns zero bytes of address
- len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
- } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
- return Err(io::Error::new(io::ErrorKind::InvalidInput,
- "file descriptor did not correspond to a Unix socket"));
- }
-
- Ok(SocketAddr {
- addr,
- len,
- })
- }
-
- /// Returns `true` if the address is unnamed.
- ///
- /// # Examples
- ///
- /// A named address:
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let socket = UnixListener::bind("/tmp/sock").unwrap();
- /// let addr = socket.local_addr().expect("Couldn't get local address");
- /// assert_eq!(addr.is_unnamed(), false);
- /// ```
- ///
- /// An unnamed address:
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let socket = UnixDatagram::unbound().unwrap();
- /// let addr = socket.local_addr().expect("Couldn't get local address");
- /// assert_eq!(addr.is_unnamed(), true);
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn is_unnamed(&self) -> bool {
- if let AddressKind::Unnamed = self.address() {
- true
- } else {
- false
- }
- }
-
- /// Returns the contents of this address if it is a `pathname` address.
- ///
- /// # Examples
- ///
- /// With a pathname:
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- /// use std::path::Path;
- ///
- /// let socket = UnixListener::bind("/tmp/sock").unwrap();
- /// let addr = socket.local_addr().expect("Couldn't get local address");
- /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
- /// ```
- ///
- /// Without a pathname:
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let socket = UnixDatagram::unbound().unwrap();
- /// let addr = socket.local_addr().expect("Couldn't get local address");
- /// assert_eq!(addr.as_pathname(), None);
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn as_pathname(&self) -> Option<&Path> {
- if let AddressKind::Pathname(path) = self.address() {
- Some(path)
- } else {
- None
- }
- }
-
- fn address<'a>(&'a self) -> AddressKind<'a> {
- let len = self.len as usize - sun_path_offset(&self.addr);
- let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) };
-
- if self.addr.sun_path[0] == 0 {
- AddressKind::Abstract(&path[1..len])
- } else {
- AddressKind::Pathname(OsStr::from_bytes(&path[..len - 1]).as_ref())
- }
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for SocketAddr {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.address() {
- AddressKind::Unnamed => write!(fmt, "(unnamed)"),
- AddressKind::Abstract(name) => write!(fmt, "{} (abstract)", AsciiEscaped(name)),
- AddressKind::Pathname(path) => write!(fmt, "{:?} (pathname)", path),
- }
- }
-}
-
-struct AsciiEscaped<'a>(&'a [u8]);
-
-impl<'a> fmt::Display for AsciiEscaped<'a> {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(fmt, "\"")?;
- for byte in self.0.iter().cloned().flat_map(ascii::escape_default) {
- write!(fmt, "{}", byte as char)?;
- }
- write!(fmt, "\"")
- }
-}
-
-/// A Unix stream socket.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::net::UnixStream;
-/// use std::io::prelude::*;
-///
-/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
-/// stream.write_all(b"hello world").unwrap();
-/// let mut response = String::new();
-/// stream.read_to_string(&mut response).unwrap();
-/// println!("{}", response);
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixStream(Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixStream {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("UnixStream");
- builder.field("fd", self.0.as_inner());
- if let Ok(addr) = self.local_addr() {
- builder.field("local", &addr);
- }
- if let Ok(addr) = self.peer_addr() {
- builder.field("peer", &addr);
- }
- builder.finish()
- }
-}
-
-impl UnixStream {
- /// Connects to the socket named by `path`.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = match UnixStream::connect("/tmp/sock") {
- /// Ok(sock) => sock,
- /// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
- fn inner(path: &Path) -> io::Result<UnixStream> {
- unsafe {
- let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
- let (addr, len) = sockaddr_un(path)?;
-
- cvt(libc::connect(*inner.as_inner(), &addr as *const _ as *const _, len))?;
- Ok(UnixStream(inner))
- }
- }
- inner(path.as_ref())
- }
-
- /// Creates an unnamed pair of connected sockets.
- ///
- /// Returns two `UnixStream`s which are connected to each other.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let (sock1, sock2) = match UnixStream::pair() {
- /// Ok((sock1, sock2)) => (sock1, sock2),
- /// Err(e) => {
- /// println!("Couldn't create a pair of sockets: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
- let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_STREAM)?;
- Ok((UnixStream(i1), UnixStream(i2)))
- }
-
- /// Creates a new independently owned handle to the underlying socket.
- ///
- /// The returned `UnixStream` is a reference to the same stream that this
- /// object references. Both handles will read and write the same stream of
- /// data, and options set on one stream will be propagated to the other
- /// stream.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn try_clone(&self) -> io::Result<UnixStream> {
- self.0.duplicate().map(UnixStream)
- }
-
- /// Returns the socket address of the local half of this connection.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// let addr = socket.local_addr().expect("Couldn't get local address");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn local_addr(&self) -> io::Result<SocketAddr> {
- SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
- }
-
- /// Returns the socket address of the remote half of this connection.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// let addr = socket.peer_addr().expect("Couldn't get peer address");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
- }
-
- /// Sets the read timeout for the socket.
- ///
- /// If the provided value is [`None`], then [`read`] calls will block
- /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method.
- ///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- /// use std::time::Duration;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
- /// ```
- ///
- /// An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method:
- ///
- /// ```no_run
- /// use std::io;
- /// use std::os::unix::net::UnixStream;
- /// use std::time::Duration;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
- /// let err = result.unwrap_err();
- /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
- self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
- }
-
- /// Sets the write timeout for the socket.
- ///
- /// If the provided value is [`None`], then [`write`] calls will block
- /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
- /// passed to this method.
- ///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- /// use std::time::Duration;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
- /// ```
- ///
- /// An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method:
- ///
- /// ```no_run
- /// use std::io;
- /// use std::net::UdpSocket;
- /// use std::time::Duration;
- ///
- /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
- /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
- /// let err = result.unwrap_err();
- /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
- self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
- }
-
- /// Returns the read timeout of this socket.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- /// use std::time::Duration;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
- /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- self.0.timeout(libc::SO_RCVTIMEO)
- }
-
- /// Returns the write timeout of this socket.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- /// use std::time::Duration;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
- /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- self.0.timeout(libc::SO_SNDTIMEO)
- }
-
- /// Moves the socket into or out of nonblocking mode.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
- self.0.set_nonblocking(nonblocking)
- }
-
- /// Returns the value of the `SO_ERROR` option.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// if let Ok(Some(err)) = socket.take_error() {
- /// println!("Got error: {:?}", err);
- /// }
- /// ```
- ///
- /// # Platform specific
- /// On Redox this always returns `None`.
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- self.0.take_error()
- }
-
- /// Shuts down the read, write, or both halves of this connection.
- ///
- /// This function will cause all pending and future I/O calls on the
- /// specified portions to immediately return with an appropriate value
- /// (see the documentation of [`Shutdown`]).
- ///
- /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixStream;
- /// use std::net::Shutdown;
- ///
- /// let socket = UnixStream::connect("/tmp/sock").unwrap();
- /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- self.0.shutdown(how)
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl io::Read for UnixStream {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- io::Read::read(&mut &*self, buf)
- }
-
- fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- io::Read::read_vectored(&mut &*self, bufs)
- }
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> io::Read for &'a UnixStream {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
- }
-
- fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- self.0.read_vectored(bufs)
- }
-
- #[inline]
- unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl io::Write for UnixStream {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- io::Write::write(&mut &*self, buf)
- }
-
- fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- io::Write::write_vectored(&mut &*self, bufs)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- io::Write::flush(&mut &*self)
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> io::Write for &'a UnixStream {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
- }
-
- fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- self.0.write_vectored(bufs)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixStream {
- fn as_raw_fd(&self) -> RawFd {
- *self.0.as_inner()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixStream {
- unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
- UnixStream(Socket::from_inner(fd))
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixStream {
- fn into_raw_fd(self) -> RawFd {
- self.0.into_inner()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::TcpStream {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::TcpListener {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for net::UdpSocket {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::TcpStream {
- unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
- let socket = sys::net::Socket::from_inner(fd);
- net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
- }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::TcpListener {
- unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
- let socket = sys::net::Socket::from_inner(fd);
- net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
- }
-}
-
-#[stable(feature = "from_raw_os", since = "1.1.0")]
-impl FromRawFd for net::UdpSocket {
- unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
- let socket = sys::net::Socket::from_inner(fd);
- net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
- }
-}
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::TcpStream {
- fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
- }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::TcpListener {
- fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
- }
-}
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for net::UdpSocket {
- fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
- }
-}
-
-/// A structure representing a Unix domain socket server.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread;
-/// use std::os::unix::net::{UnixStream, UnixListener};
-///
-/// fn handle_client(stream: UnixStream) {
-/// // ...
-/// }
-///
-/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
-///
-/// // accept connections and process them, spawning a new thread for each one
-/// for stream in listener.incoming() {
-/// match stream {
-/// Ok(stream) => {
-/// /* connection succeeded */
-/// thread::spawn(|| handle_client(stream));
-/// }
-/// Err(err) => {
-/// /* connection failed */
-/// break;
-/// }
-/// }
-/// }
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixListener(Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixListener {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("UnixListener");
- builder.field("fd", self.0.as_inner());
- if let Ok(addr) = self.local_addr() {
- builder.field("local", &addr);
- }
- builder.finish()
- }
-}
-
-impl UnixListener {
- /// Creates a new `UnixListener` bound to the specified socket.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = match UnixListener::bind("/path/to/the/socket") {
- /// Ok(sock) => sock,
- /// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
- fn inner(path: &Path) -> io::Result<UnixListener> {
- unsafe {
- let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?;
- let (addr, len) = sockaddr_un(path)?;
-
- cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?;
- cvt(libc::listen(*inner.as_inner(), 128))?;
-
- Ok(UnixListener(inner))
- }
- }
- inner(path.as_ref())
- }
-
- /// Accepts a new incoming connection to this listener.
- ///
- /// This function will block the calling thread until a new Unix connection
- /// is established. When established, the corresponding [`UnixStream`] and
- /// the remote peer's address will be returned.
- ///
- /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
- ///
- /// match listener.accept() {
- /// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
- /// Err(e) => println!("accept function failed: {:?}", e),
- /// }
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
- let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() };
- let mut len = mem::size_of_val(&storage) as libc::socklen_t;
- let sock = self.0.accept(&mut storage as *mut _ as *mut _, &mut len)?;
- let addr = SocketAddr::from_parts(storage, len)?;
- Ok((UnixStream(sock), addr))
- }
-
- /// Creates a new independently owned handle to the underlying socket.
- ///
- /// The returned `UnixListener` is a reference to the same socket that this
- /// object references. Both handles can be used to accept incoming
- /// connections and options set on one listener will affect the other.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
- ///
- /// let listener_copy = listener.try_clone().expect("try_clone failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn try_clone(&self) -> io::Result<UnixListener> {
- self.0.duplicate().map(UnixListener)
- }
-
- /// Returns the local socket address of this listener.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
- ///
- /// let addr = listener.local_addr().expect("Couldn't get local address");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn local_addr(&self) -> io::Result<SocketAddr> {
- SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
- }
-
- /// Moves the socket into or out of nonblocking mode.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
- ///
- /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
- self.0.set_nonblocking(nonblocking)
- }
-
- /// Returns the value of the `SO_ERROR` option.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixListener;
- ///
- /// let listener = UnixListener::bind("/tmp/sock").unwrap();
- ///
- /// if let Ok(Some(err)) = listener.take_error() {
- /// println!("Got error: {:?}", err);
- /// }
- /// ```
- ///
- /// # Platform specific
- /// On Redox this always returns `None`.
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- self.0.take_error()
- }
-
- /// Returns an iterator over incoming connections.
- ///
- /// The iterator will never return [`None`] and will also not yield the
- /// peer's [`SocketAddr`] structure.
- ///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`SocketAddr`]: struct.SocketAddr.html
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::thread;
- /// use std::os::unix::net::{UnixStream, UnixListener};
- ///
- /// fn handle_client(stream: UnixStream) {
- /// // ...
- /// }
- ///
- /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
- ///
- /// for stream in listener.incoming() {
- /// match stream {
- /// Ok(stream) => {
- /// thread::spawn(|| handle_client(stream));
- /// }
- /// Err(err) => {
- /// break;
- /// }
- /// }
- /// }
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn incoming<'a>(&'a self) -> Incoming<'a> {
- Incoming { listener: self }
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixListener {
- fn as_raw_fd(&self) -> RawFd {
- *self.0.as_inner()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixListener {
- unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
- UnixListener(Socket::from_inner(fd))
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixListener {
- fn into_raw_fd(self) -> RawFd {
- self.0.into_inner()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> IntoIterator for &'a UnixListener {
- type Item = io::Result<UnixStream>;
- type IntoIter = Incoming<'a>;
-
- fn into_iter(self) -> Incoming<'a> {
- self.incoming()
- }
-}
-
-/// An iterator over incoming connections to a [`UnixListener`].
-///
-/// It will never return [`None`].
-///
-/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
-/// [`UnixListener`]: struct.UnixListener.html
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::thread;
-/// use std::os::unix::net::{UnixStream, UnixListener};
-///
-/// fn handle_client(stream: UnixStream) {
-/// // ...
-/// }
-///
-/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
-///
-/// for stream in listener.incoming() {
-/// match stream {
-/// Ok(stream) => {
-/// thread::spawn(|| handle_client(stream));
-/// }
-/// Err(err) => {
-/// break;
-/// }
-/// }
-/// }
-/// ```
-#[derive(Debug)]
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct Incoming<'a> {
- listener: &'a UnixListener,
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl<'a> Iterator for Incoming<'a> {
- type Item = io::Result<UnixStream>;
-
- fn next(&mut self) -> Option<io::Result<UnixStream>> {
- Some(self.listener.accept().map(|s| s.0))
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- (usize::max_value(), None)
- }
-}
-
-/// A Unix datagram socket.
-///
-/// # Examples
-///
-/// ```no_run
-/// use std::os::unix::net::UnixDatagram;
-///
-/// let socket = UnixDatagram::bind("/path/to/my/socket").unwrap();
-/// socket.send_to(b"hello world", "/path/to/other/socket").unwrap();
-/// let mut buf = [0; 100];
-/// let (count, address) = socket.recv_from(&mut buf).unwrap();
-/// println!("socket {:?} sent {:?}", address, &buf[..count]);
-/// ```
-#[stable(feature = "unix_socket", since = "1.10.0")]
-pub struct UnixDatagram(Socket);
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl fmt::Debug for UnixDatagram {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut builder = fmt.debug_struct("UnixDatagram");
- builder.field("fd", self.0.as_inner());
- if let Ok(addr) = self.local_addr() {
- builder.field("local", &addr);
- }
- if let Ok(addr) = self.peer_addr() {
- builder.field("peer", &addr);
- }
- builder.finish()
- }
-}
-
-impl UnixDatagram {
- /// Creates a Unix datagram socket bound to the given path.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = match UnixDatagram::bind("/path/to/the/socket") {
- /// Ok(sock) => sock,
- /// Err(e) => {
- /// println!("Couldn't bind: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixDatagram> {
- fn inner(path: &Path) -> io::Result<UnixDatagram> {
- unsafe {
- let socket = UnixDatagram::unbound()?;
- let (addr, len) = sockaddr_un(path)?;
-
- cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?;
-
- Ok(socket)
- }
- }
- inner(path.as_ref())
- }
-
- /// Creates a Unix Datagram socket which is not bound to any address.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = match UnixDatagram::unbound() {
- /// Ok(sock) => sock,
- /// Err(e) => {
- /// println!("Couldn't unbound: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn unbound() -> io::Result<UnixDatagram> {
- let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_DGRAM)?;
- Ok(UnixDatagram(inner))
- }
-
- /// Creates an unnamed pair of connected sockets.
- ///
- /// Returns two `UnixDatagrams`s which are connected to each other.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let (sock1, sock2) = match UnixDatagram::pair() {
- /// Ok((sock1, sock2)) => (sock1, sock2),
- /// Err(e) => {
- /// println!("Couldn't unbound: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn pair() -> io::Result<(UnixDatagram, UnixDatagram)> {
- let (i1, i2) = Socket::new_pair(libc::AF_UNIX, libc::SOCK_DGRAM)?;
- Ok((UnixDatagram(i1), UnixDatagram(i2)))
- }
-
- /// Connects the socket to the specified address.
- ///
- /// The [`send`] method may be used to send data to the specified address.
- /// [`recv`] and [`recv_from`] will only receive data from that address.
- ///
- /// [`send`]: #method.send
- /// [`recv`]: #method.recv
- /// [`recv_from`]: #method.recv_from
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// match sock.connect("/path/to/the/socket") {
- /// Ok(sock) => sock,
- /// Err(e) => {
- /// println!("Couldn't connect: {:?}", e);
- /// return
- /// }
- /// };
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn connect<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
- fn inner(d: &UnixDatagram, path: &Path) -> io::Result<()> {
- unsafe {
- let (addr, len) = sockaddr_un(path)?;
-
- cvt(libc::connect(*d.0.as_inner(), &addr as *const _ as *const _, len))?;
-
- Ok(())
- }
- }
- inner(self, path.as_ref())
- }
-
- /// Creates a new independently owned handle to the underlying socket.
- ///
- /// The returned `UnixDatagram` is a reference to the same socket that this
- /// object references. Both handles can be used to accept incoming
- /// connections and options set on one side will affect the other.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
- ///
- /// let sock_copy = sock.try_clone().expect("try_clone failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn try_clone(&self) -> io::Result<UnixDatagram> {
- self.0.duplicate().map(UnixDatagram)
- }
-
- /// Returns the address of this socket.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
- ///
- /// let addr = sock.local_addr().expect("Couldn't get local address");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn local_addr(&self) -> io::Result<SocketAddr> {
- SocketAddr::new(|addr, len| unsafe { libc::getsockname(*self.0.as_inner(), addr, len) })
- }
-
- /// Returns the address of this socket's peer.
- ///
- /// The [`connect`] method will connect the socket to a peer.
- ///
- /// [`connect`]: #method.connect
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.connect("/path/to/the/socket").unwrap();
- ///
- /// let addr = sock.peer_addr().expect("Couldn't get peer address");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
- }
-
- /// Receives data from the socket.
- ///
- /// On success, returns the number of bytes read and the address from
- /// whence the data came.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// let mut buf = vec![0; 10];
- /// match sock.recv_from(buf.as_mut_slice()) {
- /// Ok((size, sender)) => println!("received {} bytes from {:?}", size, sender),
- /// Err(e) => println!("recv_from function failed: {:?}", e),
- /// }
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- let mut count = 0;
- let addr = SocketAddr::new(|addr, len| {
- unsafe {
- count = libc::recvfrom(*self.0.as_inner(),
- buf.as_mut_ptr() as *mut _,
- buf.len(),
- 0,
- addr,
- len);
- if count > 0 {
- 1
- } else if count == 0 {
- 0
- } else {
- -1
- }
- }
- })?;
-
- Ok((count as usize, addr))
- }
-
- /// Receives data from the socket.
- ///
- /// On success, returns the number of bytes read.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::bind("/path/to/the/socket").unwrap();
- /// let mut buf = vec![0; 10];
- /// sock.recv(buf.as_mut_slice()).expect("recv function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn recv(&self, buf: &mut [u8]) -> io::Result<usize> {
- self.0.read(buf)
- }
-
- /// Sends data on the socket to the specified address.
- ///
- /// On success, returns the number of bytes written.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.send_to(b"omelette au fromage", "/some/sock").expect("send_to function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn send_to<P: AsRef<Path>>(&self, buf: &[u8], path: P) -> io::Result<usize> {
- fn inner(d: &UnixDatagram, buf: &[u8], path: &Path) -> io::Result<usize> {
- unsafe {
- let (addr, len) = sockaddr_un(path)?;
-
- let count = cvt(libc::sendto(*d.0.as_inner(),
- buf.as_ptr() as *const _,
- buf.len(),
- MSG_NOSIGNAL,
- &addr as *const _ as *const _,
- len))?;
- Ok(count as usize)
- }
- }
- inner(self, buf, path.as_ref())
- }
-
- /// Sends data on the socket to the socket's peer.
- ///
- /// The peer address may be set by the `connect` method, and this method
- /// will return an error if the socket has not already been connected.
- ///
- /// On success, returns the number of bytes written.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.connect("/some/sock").expect("Couldn't connect");
- /// sock.send(b"omelette au fromage").expect("send_to function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
- self.0.write(buf)
- }
-
- /// Sets the read timeout for the socket.
- ///
- /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will
- /// block indefinitely. An [`Err`] is returned if the zero [`Duration`]
- /// is passed to this method.
- ///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
- /// [`recv`]: #method.recv
- /// [`recv_from`]: #method.recv_from
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
- /// ```
- ///
- /// An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method:
- ///
- /// ```no_run
- /// use std::io;
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let socket = UnixDatagram::unbound().unwrap();
- /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
- /// let err = result.unwrap_err();
- /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_read_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
- self.0.set_timeout(timeout, libc::SO_RCVTIMEO)
- }
-
- /// Sets the write timeout for the socket.
- ///
- /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will
- /// block indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method.
- ///
- /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
- /// [`send`]: #method.send
- /// [`send_to`]: #method.send_to
- /// [`Duration`]: ../../../../std/time/struct.Duration.html
- ///
- /// # Examples
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.set_write_timeout(Some(Duration::new(1, 0)))
- /// .expect("set_write_timeout function failed");
- /// ```
- ///
- /// An [`Err`] is returned if the zero [`Duration`] is passed to this
- /// method:
- ///
- /// ```no_run
- /// use std::io;
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let socket = UnixDatagram::unbound().unwrap();
- /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
- /// let err = result.unwrap_err();
- /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_write_timeout(&self, timeout: Option<Duration>) -> io::Result<()> {
- self.0.set_timeout(timeout, libc::SO_SNDTIMEO)
- }
-
- /// Returns the read timeout of this socket.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.set_read_timeout(Some(Duration::new(1, 0))).expect("set_read_timeout function failed");
- /// assert_eq!(sock.read_timeout().unwrap(), Some(Duration::new(1, 0)));
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- self.0.timeout(libc::SO_RCVTIMEO)
- }
-
- /// Returns the write timeout of this socket.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- /// use std::time::Duration;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.set_write_timeout(Some(Duration::new(1, 0)))
- /// .expect("set_write_timeout function failed");
- /// assert_eq!(sock.write_timeout().unwrap(), Some(Duration::new(1, 0)));
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- self.0.timeout(libc::SO_SNDTIMEO)
- }
-
- /// Moves the socket into or out of nonblocking mode.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.set_nonblocking(true).expect("set_nonblocking function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
- self.0.set_nonblocking(nonblocking)
- }
-
- /// Returns the value of the `SO_ERROR` option.
- ///
- /// # Examples
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// if let Ok(Some(err)) = sock.take_error() {
- /// println!("Got error: {:?}", err);
- /// }
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- self.0.take_error()
- }
-
- /// Shut down the read, write, or both halves of this connection.
- ///
- /// This function will cause all pending and future I/O calls on the
- /// specified portions to immediately return with an appropriate value
- /// (see the documentation of [`Shutdown`]).
- ///
- /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
- ///
- /// ```no_run
- /// use std::os::unix::net::UnixDatagram;
- /// use std::net::Shutdown;
- ///
- /// let sock = UnixDatagram::unbound().unwrap();
- /// sock.shutdown(Shutdown::Both).expect("shutdown function failed");
- /// ```
- #[stable(feature = "unix_socket", since = "1.10.0")]
- pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- self.0.shutdown(how)
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl AsRawFd for UnixDatagram {
- fn as_raw_fd(&self) -> RawFd {
- *self.0.as_inner()
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl FromRawFd for UnixDatagram {
- unsafe fn from_raw_fd(fd: RawFd) -> UnixDatagram {
- UnixDatagram(Socket::from_inner(fd))
- }
-}
-
-#[stable(feature = "unix_socket", since = "1.10.0")]
-impl IntoRawFd for UnixDatagram {
- fn into_raw_fd(self) -> RawFd {
- self.0.into_inner()
- }
-}
-
-#[cfg(all(test, not(target_os = "emscripten")))]
-mod test {
- use crate::thread;
- use crate::io::{self, ErrorKind};
- use crate::io::prelude::*;
- use crate::time::Duration;
- use crate::sys_common::io::test::tmpdir;
-
- use super::*;
-
- macro_rules! or_panic {
- ($e:expr) => {
- match $e {
- Ok(e) => e,
- Err(e) => panic!("{}", e),
- }
- }
- }
-
- #[test]
- fn basic() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
- let msg1 = b"hello";
- let msg2 = b"world!";
-
- let listener = or_panic!(UnixListener::bind(&socket_path));
- let thread = thread::spawn(move || {
- let mut stream = or_panic!(listener.accept()).0;
- let mut buf = [0; 5];
- or_panic!(stream.read(&mut buf));
- assert_eq!(&msg1[..], &buf[..]);
- or_panic!(stream.write_all(msg2));
- });
-
- let mut stream = or_panic!(UnixStream::connect(&socket_path));
- assert_eq!(Some(&*socket_path),
- stream.peer_addr().unwrap().as_pathname());
- or_panic!(stream.write_all(msg1));
- let mut buf = vec![];
- or_panic!(stream.read_to_end(&mut buf));
- assert_eq!(&msg2[..], &buf[..]);
- drop(stream);
-
- thread.join().unwrap();
- }
-
- #[test]
- fn vectored() {
- let (mut s1, mut s2) = or_panic!(UnixStream::pair());
-
- let len = or_panic!(s1.write_vectored(
- &[IoSlice::new(b"hello"), IoSlice::new(b" "), IoSlice::new(b"world!")],
- ));
- assert_eq!(len, 12);
-
- let mut buf1 = [0; 6];
- let mut buf2 = [0; 7];
- let len = or_panic!(s2.read_vectored(
- &mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],
- ));
- assert_eq!(len, 12);
- assert_eq!(&buf1, b"hello ");
- assert_eq!(&buf2, b"world!\0");
- }
-
- #[test]
- fn pair() {
- let msg1 = b"hello";
- let msg2 = b"world!";
-
- let (mut s1, mut s2) = or_panic!(UnixStream::pair());
- let thread = thread::spawn(move || {
- // s1 must be moved in or the test will hang!
- let mut buf = [0; 5];
- or_panic!(s1.read(&mut buf));
- assert_eq!(&msg1[..], &buf[..]);
- or_panic!(s1.write_all(msg2));
- });
-
- or_panic!(s2.write_all(msg1));
- let mut buf = vec![];
- or_panic!(s2.read_to_end(&mut buf));
- assert_eq!(&msg2[..], &buf[..]);
- drop(s2);
-
- thread.join().unwrap();
- }
-
- #[test]
- fn try_clone() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
- let msg1 = b"hello";
- let msg2 = b"world";
-
- let listener = or_panic!(UnixListener::bind(&socket_path));
- let thread = thread::spawn(move || {
- let mut stream = or_panic!(listener.accept()).0;
- or_panic!(stream.write_all(msg1));
- or_panic!(stream.write_all(msg2));
- });
-
- let mut stream = or_panic!(UnixStream::connect(&socket_path));
- let mut stream2 = or_panic!(stream.try_clone());
-
- let mut buf = [0; 5];
- or_panic!(stream.read(&mut buf));
- assert_eq!(&msg1[..], &buf[..]);
- or_panic!(stream2.read(&mut buf));
- assert_eq!(&msg2[..], &buf[..]);
-
- thread.join().unwrap();
- }
-
- #[test]
- fn iter() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
-
- let listener = or_panic!(UnixListener::bind(&socket_path));
- let thread = thread::spawn(move || {
- for stream in listener.incoming().take(2) {
- let mut stream = or_panic!(stream);
- let mut buf = [0];
- or_panic!(stream.read(&mut buf));
- }
- });
-
- for _ in 0..2 {
- let mut stream = or_panic!(UnixStream::connect(&socket_path));
- or_panic!(stream.write_all(&[0]));
- }
-
- thread.join().unwrap();
- }
-
- #[test]
- fn long_path() {
- let dir = tmpdir();
- let socket_path = dir.path()
- .join("asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\
- sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf");
- match UnixStream::connect(&socket_path) {
- Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
- Ok(_) => panic!("unexpected success"),
- }
-
- match UnixListener::bind(&socket_path) {
- Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
- Ok(_) => panic!("unexpected success"),
- }
-
- match UnixDatagram::bind(&socket_path) {
- Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {}
- Err(e) => panic!("unexpected error {}", e),
- Ok(_) => panic!("unexpected success"),
- }
- }
-
- #[test]
- fn timeouts() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
-
- let _listener = or_panic!(UnixListener::bind(&socket_path));
-
- let stream = or_panic!(UnixStream::connect(&socket_path));
- let dur = Duration::new(15410, 0);
-
- assert_eq!(None, or_panic!(stream.read_timeout()));
-
- or_panic!(stream.set_read_timeout(Some(dur)));
- assert_eq!(Some(dur), or_panic!(stream.read_timeout()));
-
- assert_eq!(None, or_panic!(stream.write_timeout()));
-
- or_panic!(stream.set_write_timeout(Some(dur)));
- assert_eq!(Some(dur), or_panic!(stream.write_timeout()));
-
- or_panic!(stream.set_read_timeout(None));
- assert_eq!(None, or_panic!(stream.read_timeout()));
-
- or_panic!(stream.set_write_timeout(None));
- assert_eq!(None, or_panic!(stream.write_timeout()));
- }
-
- #[test]
- fn test_read_timeout() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
-
- let _listener = or_panic!(UnixListener::bind(&socket_path));
-
- let mut stream = or_panic!(UnixStream::connect(&socket_path));
- or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
-
- let mut buf = [0; 10];
- let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
- assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
- "unexpected_error: {:?}", kind);
- }
-
- #[test]
- fn test_read_with_timeout() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
-
- let listener = or_panic!(UnixListener::bind(&socket_path));
-
- let mut stream = or_panic!(UnixStream::connect(&socket_path));
- or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000))));
-
- let mut other_end = or_panic!(listener.accept()).0;
- or_panic!(other_end.write_all(b"hello world"));
-
- let mut buf = [0; 11];
- or_panic!(stream.read(&mut buf));
- assert_eq!(b"hello world", &buf[..]);
-
- let kind = stream.read_exact(&mut buf).err().expect("expected error").kind();
- assert!(kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut,
- "unexpected_error: {:?}", kind);
- }
-
- // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
- // when passed zero Durations
- #[test]
- fn test_unix_stream_timeout_zero_duration() {
- let dir = tmpdir();
- let socket_path = dir.path().join("sock");
-
- let listener = or_panic!(UnixListener::bind(&socket_path));
- let stream = or_panic!(UnixStream::connect(&socket_path));
-
- let result = stream.set_write_timeout(Some(Duration::new(0, 0)));
- let err = result.unwrap_err();
- assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
- let result = stream.set_read_timeout(Some(Duration::new(0, 0)));
- let err = result.unwrap_err();
- assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
- drop(listener);
- }
-
- #[test]
- fn test_unix_datagram() {
- let dir = tmpdir();
- let path1 = dir.path().join("sock1");
- let path2 = dir.path().join("sock2");
-
- let sock1 = or_panic!(UnixDatagram::bind(&path1));
- let sock2 = or_panic!(UnixDatagram::bind(&path2));
-
- let msg = b"hello world";
- or_panic!(sock1.send_to(msg, &path2));
- let mut buf = [0; 11];
- or_panic!(sock2.recv_from(&mut buf));
- assert_eq!(msg, &buf[..]);
- }
-
- #[test]
- fn test_unnamed_unix_datagram() {
- let dir = tmpdir();
- let path1 = dir.path().join("sock1");
-
- let sock1 = or_panic!(UnixDatagram::bind(&path1));
- let sock2 = or_panic!(UnixDatagram::unbound());
-
- let msg = b"hello world";
- or_panic!(sock2.send_to(msg, &path1));
- let mut buf = [0; 11];
- let (usize, addr) = or_panic!(sock1.recv_from(&mut buf));
- assert_eq!(usize, 11);
- assert!(addr.is_unnamed());
- assert_eq!(msg, &buf[..]);
- }
-
- #[test]
- fn test_connect_unix_datagram() {
- let dir = tmpdir();
- let path1 = dir.path().join("sock1");
- let path2 = dir.path().join("sock2");
-
- let bsock1 = or_panic!(UnixDatagram::bind(&path1));
- let bsock2 = or_panic!(UnixDatagram::bind(&path2));
- let sock = or_panic!(UnixDatagram::unbound());
- or_panic!(sock.connect(&path1));
-
- // Check send()
- let msg = b"hello there";
- or_panic!(sock.send(msg));
- let mut buf = [0; 11];
- let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf));
- assert_eq!(usize, 11);
- assert!(addr.is_unnamed());
- assert_eq!(msg, &buf[..]);
-
- // Changing default socket works too
- or_panic!(sock.connect(&path2));
- or_panic!(sock.send(msg));
- or_panic!(bsock2.recv_from(&mut buf));
- }
-
- #[test]
- fn test_unix_datagram_recv() {
- let dir = tmpdir();
- let path1 = dir.path().join("sock1");
-
- let sock1 = or_panic!(UnixDatagram::bind(&path1));
- let sock2 = or_panic!(UnixDatagram::unbound());
- or_panic!(sock2.connect(&path1));
-
- let msg = b"hello world";
- or_panic!(sock2.send(msg));
- let mut buf = [0; 11];
- let size = or_panic!(sock1.recv(&mut buf));
- assert_eq!(size, 11);
- assert_eq!(msg, &buf[..]);
- }
-
- #[test]
- fn datagram_pair() {
- let msg1 = b"hello";
- let msg2 = b"world!";
-
- let (s1, s2) = or_panic!(UnixDatagram::pair());
- let thread = thread::spawn(move || {
- // s1 must be moved in or the test will hang!
- let mut buf = [0; 5];
- or_panic!(s1.recv(&mut buf));
- assert_eq!(&msg1[..], &buf[..]);
- or_panic!(s1.send(msg2));
- });
-
- or_panic!(s2.send(msg1));
- let mut buf = [0; 6];
- or_panic!(s2.recv(&mut buf));
- assert_eq!(&msg2[..], &buf[..]);
- drop(s2);
-
- thread.join().unwrap();
- }
-
- // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors
- // when passed zero Durations
- #[test]
- fn test_unix_datagram_timeout_zero_duration() {
- let dir = tmpdir();
- let path = dir.path().join("sock");
-
- let datagram = or_panic!(UnixDatagram::bind(&path));
-
- let result = datagram.set_write_timeout(Some(Duration::new(0, 0)));
- let err = result.unwrap_err();
- assert_eq!(err.kind(), ErrorKind::InvalidInput);
-
- let result = datagram.set_read_timeout(Some(Duration::new(0, 0)));
- let err = result.unwrap_err();
- assert_eq!(err.kind(), ErrorKind::InvalidInput);
- }
-
- #[test]
- fn abstract_namespace_not_allowed() {
- assert!(UnixStream::connect("\0asdf").is_err());
- }
-}
// `test_2018_feature` is
// included in the Rust 2018 edition
```
-
"##,
E0725: r##"
features in the `-Z allow_features` flag.
"##,
+E0743: r##"
+C-variadic has been used on a non-foreign function.
+
+Erroneous code example:
+
+```compile_fail,E0743
+fn foo2(x: u8, ...) {} // error!
+```
+
+Only foreign functions can use C-variadic (`...`). It is used to give an
+undefined number of parameters to a given function (like `printf` in C). The
+equivalent in Rust would be to use macros directly.
+"##,
+
;
E0539, // incorrect meta item
(accepted, non_exhaustive, "1.40.0", Some(44109), None),
/// Allows calling constructor functions in `const fn`.
(accepted, const_constructor, "1.40.0", Some(61456), None),
+ /// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
+ (accepted, cfg_doctest, "1.40.0", Some(62210), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
- /// Allows the use of `#[cfg(doctest)]`; set when rustdoc is collecting doctests.
- (active, cfg_doctest, "1.37.0", Some(62210), None),
-
/// Allows `[x; N]` where `x` is a constant (RFC 2203).
(active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None),
(sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
(sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
(sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)),
- (sym::doctest, sym::cfg_doctest, cfg_fn!(cfg_doctest)),
];
#[derive(Debug)]
use super::removed::{REMOVED_FEATURES, STABLE_REMOVED_FEATURES};
use super::builtin_attrs::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
-use crate::ast::{self, NodeId, PatKind, VariantData};
+use crate::ast::{
+ self, AssocTyConstraint, AssocTyConstraintKind, NodeId, GenericParam, GenericParamKind,
+ PatKind, RangeEnd, VariantData,
+};
use crate::attr::{self, check_builtin_attribute};
+use crate::source_map::Spanned;
use crate::edition::{ALL_EDITIONS, Edition};
use crate::visit::{self, FnKind, Visitor};
use crate::parse::token;
}
+const EXPLAIN_BOX_SYNTAX: &str =
+ "box expression syntax is experimental; you can call `Box::new` instead";
+
pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
"attributes on expressions are experimental";
"auto traits are experimental and possibly buggy");
}
+ ast::ItemKind::TraitAlias(..) => {
+ gate_feature_post!(
+ &self,
+ trait_alias,
+ i.span,
+ "trait aliases are experimental"
+ );
+ }
+
+ ast::ItemKind::MacroDef(ast::MacroDef { legacy: false, .. }) => {
+ let msg = "`macro` is experimental";
+ gate_feature_post!(&self, decl_macro, i.span, msg);
+ }
+
ast::ItemKind::OpaqueTy(..) => {
gate_feature_post!(
&self,
}
}
+ fn visit_expr(&mut self, e: &'a ast::Expr) {
+ match e.kind {
+ ast::ExprKind::Box(_) => {
+ gate_feature_post!(&self, box_syntax, e.span, EXPLAIN_BOX_SYNTAX);
+ }
+ ast::ExprKind::Type(..) => {
+ // To avoid noise about type ascription in common syntax errors, only emit if it
+ // is the *only* error.
+ if self.parse_sess.span_diagnostic.err_count() == 0 {
+ gate_feature_post!(&self, type_ascription, e.span,
+ "type ascription is experimental");
+ }
+ }
+ ast::ExprKind::TryBlock(_) => {
+ gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
+ }
+ ast::ExprKind::Block(_, opt_label) => {
+ if let Some(label) = opt_label {
+ gate_feature_post!(&self, label_break_value, label.ident.span,
+ "labels on blocks are unstable");
+ }
+ }
+ _ => {}
+ }
+ visit::walk_expr(self, e)
+ }
+
+ fn visit_arm(&mut self, arm: &'a ast::Arm) {
+ visit::walk_arm(self, arm)
+ }
+
fn visit_pat(&mut self, pattern: &'a ast::Pat) {
match &pattern.kind {
PatKind::Slice(pats) => {
}
}
}
+ PatKind::Box(..) => {
+ gate_feature_post!(&self, box_patterns,
+ pattern.span,
+ "box pattern syntax is experimental");
+ }
+ PatKind::Range(_, _, Spanned { node: RangeEnd::Excluded, .. }) => {
+ gate_feature_post!(&self, exclusive_range_pattern, pattern.span,
+ "exclusive range pattern syntax is experimental");
+ }
_ => {}
}
visit::walk_pat(self, pattern)
}
- fn visit_fn(&mut self, fn_kind: FnKind<'a>, fn_decl: &'a ast::FnDecl, span: Span, _: NodeId) {
+ fn visit_fn(&mut self,
+ fn_kind: FnKind<'a>,
+ fn_decl: &'a ast::FnDecl,
+ span: Span,
+ _node_id: NodeId) {
if let Some(header) = fn_kind.header() {
// Stability of const fn methods are covered in
// `visit_trait_item` and `visit_impl_item` below; this is
visit::walk_fn(self, fn_kind, fn_decl, span)
}
+ fn visit_generic_param(&mut self, param: &'a GenericParam) {
+ match param.kind {
+ GenericParamKind::Const { .. } =>
+ gate_feature_post!(&self, const_generics, param.ident.span,
+ "const generics are unstable"),
+ _ => {}
+ }
+ visit::walk_generic_param(self, param)
+ }
+
+ fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
+ match constraint.kind {
+ AssocTyConstraintKind::Bound { .. } =>
+ gate_feature_post!(&self, associated_type_bounds, constraint.span,
+ "associated type bounds are unstable"),
+ _ => {}
+ }
+ visit::walk_assoc_ty_constraint(self, constraint)
+ }
+
fn visit_trait_item(&mut self, ti: &'a ast::TraitItem) {
match ti.kind {
ast::TraitItemKind::Method(ref sig, ref block) => {
}
visit::walk_impl_item(self, ii)
}
+
+ fn visit_vis(&mut self, vis: &'a ast::Visibility) {
+ if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node {
+ gate_feature_post!(&self, crate_visibility_modifier, vis.span,
+ "`crate` visibility modifier is experimental");
+ }
+ visit::walk_vis(self, vis)
+ }
}
pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
gate_all!(yields, generators, "yield syntax is experimental");
gate_all!(or_patterns, "or-patterns syntax is experimental");
gate_all!(const_extern_fn, "`const extern fn` definitions are unstable");
+
+ // All uses of `gate_all!` below this point were added in #65742,
+ // and subsequently disabled (with the non-early gating readded).
+ macro_rules! gate_all {
+ ($gate:ident, $msg:literal) => {
+ // FIXME(eddyb) do something more useful than always
+ // disabling these uses of early feature-gatings.
+ if false {
+ for span in &*parse_sess.gated_spans.$gate.borrow() {
+ gate_feature!(&visitor, $gate, *span, $msg);
+ }
+ }
+ }
+ }
+
gate_all!(trait_alias, "trait aliases are experimental");
gate_all!(associated_type_bounds, "associated type bounds are unstable");
gate_all!(crate_visibility_modifier, "`crate` visibility modifier is experimental");
self.eat(&token::DotDotDot);
TyKind::CVarArgs
} else {
- return Err(self.fatal(
- "only foreign functions are allowed to be C-variadic"
+ return Err(struct_span_fatal!(
+ self.sess.span_diagnostic,
+ self.token.span,
+ E0743,
+ "only foreign functions are allowed to be C-variadic",
));
}
} else {
issue_5723_bootstrap,
issue_tracker_base_url,
item,
+ item_context: "ItemContext",
item_like_imports,
iter,
Iterator,
1
}
+ #[cfg(target_os = "hermit")]
+ fn num_cpus() -> usize {
+ // FIXME: Implement num_cpus on HermitCore
+ 1
+ }
+
#[cfg(any(
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")
//! if stdout is a tty.
#[cfg(any(
- target_os = "cloudabi",
+ target_os = "cloudabi", target_os = "hermit",
all(target_arch = "wasm32", not(target_os = "emscripten")),
all(target_vendor = "fortanix", target_env = "sgx")
))]
) {
let TestDescAndFn { desc, testfn } = test;
- // FIXME: Re-enable emscripten once it can catch panics again
+ // Emscripten can catch panics but other wasm targets cannot
let ignore_because_no_process_support = desc.should_panic != ShouldPanic::No
- && (cfg!(target_arch = "wasm32") || cfg!(target_os = "emscripten"));
+ && cfg!(target_arch = "wasm32") && !cfg!(target_os = "emscripten");
if force_ignore || desc.ignore || ignore_because_no_process_support {
let message = CompletedTest::new(desc, TrIgnored, None, Vec::new());
pub fn compile() {
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
+ let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big";
let cfg = &mut cc::Build::new();
cfg.cpp(true);
cfg.cpp_set_stdlib(None);
cfg.warnings(false);
+ // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765
+ if target_endian_little {
+ cfg.define("__LITTLE_ENDIAN__", Some("1"));
+ }
+
if target_env == "msvc" {
// Don't pull in extra libraries on MSVC
cfg.flag("/Zl");
}
}
} // cfg_if!
+
+cfg_if::cfg_if! {
+if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
+ // We declare these as opaque types. This is fine since you just need to
+ // pass them to _GCC_specific_handler and forget about them.
+ pub enum EXCEPTION_RECORD {}
+ pub type LPVOID = *mut c_void;
+ pub enum CONTEXT {}
+ pub enum DISPATCHER_CONTEXT {}
+ pub type EXCEPTION_DISPOSITION = c_int;
+ type PersonalityFn = unsafe extern "C" fn(version: c_int,
+ actions: _Unwind_Action,
+ exception_class: _Unwind_Exception_Class,
+ exception_object: *mut _Unwind_Exception,
+ context: *mut _Unwind_Context)
+ -> _Unwind_Reason_Code;
+
+ extern "C" {
+ pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
+ establisherFrame: LPVOID,
+ contextRecord: *mut CONTEXT,
+ dispatcherContext: *mut DISPATCHER_CONTEXT,
+ personality: PersonalityFn)
+ -> EXCEPTION_DISPOSITION;
+ }
+}
+} // cfg_if!
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C no-prepopulate-passes
// ignore-tidy-linelength
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
// CHECK-LABEL: define i32 @nothing
// CHECK-SAME: [[NOTHING_ATTRS:#[0-9]+]]
-// NO-OPT: ret i32 %1
+// NO-OPT: ret i32 %_1.0
// SIZE-OPT: ret i32 4
// SPEEC-OPT: ret i32 4
#[no_mangle]
// CHECK-LABEL: define i32 @size
// CHECK-SAME: [[SIZE_ATTRS:#[0-9]+]]
-// NO-OPT: ret i32 %1
+// NO-OPT: ret i32 %_1.0
// SIZE-OPT: ret i32 6
// SPEED-OPT: ret i32 6
#[optimize(size)]
// NO-OPT-SAME: [[NOTHING_ATTRS]]
// SPEED-OPT-SAME: [[NOTHING_ATTRS]]
// SIZE-OPT-SAME: [[SPEED_ATTRS:#[0-9]+]]
-// NO-OPT: ret i32 %1
+// NO-OPT: ret i32 %_1.0
// SIZE-OPT: ret i32 8
// SPEED-OPT: ret i32 8
#[optimize(speed)]
// ignore-msvc
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -O -C no-prepopulate-passes
fn simd_saturating_sub<T>(x: T, y: T) -> T;
}
+// NOTE(eddyb) `%{{x|_3}}` is used because on some targets (e.g. WASM)
+// SIMD vectors are passed directly, resulting in `%x` being a vector,
+// while on others they're passed indirectly, resulting in `%x` being
+// a pointer to a vector, and `%_3` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+// The same applies to `%{{y|_4}}` as well.
+
// CHECK-LABEL: @sadd_i8x2
#[no_mangle]
pub unsafe fn sadd_i8x2(x: i8x2, y: i8x2) -> i8x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.sadd.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i8x4
#[no_mangle]
pub unsafe fn sadd_i8x4(x: i8x4, y: i8x4) -> i8x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.sadd.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i8x8
#[no_mangle]
pub unsafe fn sadd_i8x8(x: i8x8, y: i8x8) -> i8x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.sadd.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i8x16
#[no_mangle]
pub unsafe fn sadd_i8x16(x: i8x16, y: i8x16) -> i8x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.sadd.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i8x32
#[no_mangle]
pub unsafe fn sadd_i8x32(x: i8x32, y: i8x32) -> i8x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.sadd.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i8x64
#[no_mangle]
pub unsafe fn sadd_i8x64(x: i8x64, y: i8x64) -> i8x64 {
- // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.sadd.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i16x2
#[no_mangle]
pub unsafe fn sadd_i16x2(x: i16x2, y: i16x2) -> i16x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.sadd.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i16x4
#[no_mangle]
pub unsafe fn sadd_i16x4(x: i16x4, y: i16x4) -> i16x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.sadd.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i16x8
#[no_mangle]
pub unsafe fn sadd_i16x8(x: i16x8, y: i16x8) -> i16x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.sadd.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i16x16
#[no_mangle]
pub unsafe fn sadd_i16x16(x: i16x16, y: i16x16) -> i16x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.sadd.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i16x32
#[no_mangle]
pub unsafe fn sadd_i16x32(x: i16x32, y: i16x32) -> i16x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.sadd.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i32x2
#[no_mangle]
pub unsafe fn sadd_i32x2(x: i32x2, y: i32x2) -> i32x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.sadd.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i32x4
#[no_mangle]
pub unsafe fn sadd_i32x4(x: i32x4, y: i32x4) -> i32x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i32x8
#[no_mangle]
pub unsafe fn sadd_i32x8(x: i32x8, y: i32x8) -> i32x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.sadd.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i32x16
#[no_mangle]
pub unsafe fn sadd_i32x16(x: i32x16, y: i32x16) -> i32x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.sadd.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i64x2
#[no_mangle]
pub unsafe fn sadd_i64x2(x: i64x2, y: i64x2) -> i64x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.sadd.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i64x4
#[no_mangle]
pub unsafe fn sadd_i64x4(x: i64x4, y: i64x4) -> i64x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.sadd.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i64x8
#[no_mangle]
pub unsafe fn sadd_i64x8(x: i64x8, y: i64x8) -> i64x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.sadd.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i128x2
#[no_mangle]
pub unsafe fn sadd_i128x2(x: i128x2, y: i128x2) -> i128x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.sadd.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @sadd_i128x4
#[no_mangle]
pub unsafe fn sadd_i128x4(x: i128x4, y: i128x4) -> i128x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.sadd.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x2
#[no_mangle]
pub unsafe fn uadd_u8x2(x: u8x2, y: u8x2) -> u8x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x4
#[no_mangle]
pub unsafe fn uadd_u8x4(x: u8x4, y: u8x4) -> u8x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.uadd.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x8
#[no_mangle]
pub unsafe fn uadd_u8x8(x: u8x8, y: u8x8) -> u8x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.uadd.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x16
#[no_mangle]
pub unsafe fn uadd_u8x16(x: u8x16, y: u8x16) -> u8x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.uadd.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x32
#[no_mangle]
pub unsafe fn uadd_u8x32(x: u8x32, y: u8x32) -> u8x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.uadd.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u8x64
#[no_mangle]
pub unsafe fn uadd_u8x64(x: u8x64, y: u8x64) -> u8x64 {
- // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.uadd.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u16x2
#[no_mangle]
pub unsafe fn uadd_u16x2(x: u16x2, y: u16x2) -> u16x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.uadd.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u16x4
#[no_mangle]
pub unsafe fn uadd_u16x4(x: u16x4, y: u16x4) -> u16x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.uadd.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u16x8
#[no_mangle]
pub unsafe fn uadd_u16x8(x: u16x8, y: u16x8) -> u16x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.uadd.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u16x16
#[no_mangle]
pub unsafe fn uadd_u16x16(x: u16x16, y: u16x16) -> u16x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.uadd.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u16x32
#[no_mangle]
pub unsafe fn uadd_u16x32(x: u16x32, y: u16x32) -> u16x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.uadd.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u32x2
#[no_mangle]
pub unsafe fn uadd_u32x2(x: u32x2, y: u32x2) -> u32x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.uadd.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u32x4
#[no_mangle]
pub unsafe fn uadd_u32x4(x: u32x4, y: u32x4) -> u32x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.uadd.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u32x8
#[no_mangle]
pub unsafe fn uadd_u32x8(x: u32x8, y: u32x8) -> u32x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.uadd.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u32x16
#[no_mangle]
pub unsafe fn uadd_u32x16(x: u32x16, y: u32x16) -> u32x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.uadd.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u64x2
#[no_mangle]
pub unsafe fn uadd_u64x2(x: u64x2, y: u64x2) -> u64x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.uadd.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u64x4
#[no_mangle]
pub unsafe fn uadd_u64x4(x: u64x4, y: u64x4) -> u64x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.uadd.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u64x8
#[no_mangle]
pub unsafe fn uadd_u64x8(x: u64x8, y: u64x8) -> u64x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.uadd.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u128x2
#[no_mangle]
pub unsafe fn uadd_u128x2(x: u128x2, y: u128x2) -> u128x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.uadd.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @uadd_u128x4
#[no_mangle]
pub unsafe fn uadd_u128x4(x: u128x4, y: u128x4) -> u128x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.uadd.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}})
simd_saturating_add(x, y)
}
// CHECK-LABEL: @ssub_i8x2
#[no_mangle]
pub unsafe fn ssub_i8x2(x: i8x2, y: i8x2) -> i8x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.ssub.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i8x4
#[no_mangle]
pub unsafe fn ssub_i8x4(x: i8x4, y: i8x4) -> i8x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.ssub.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i8x8
#[no_mangle]
pub unsafe fn ssub_i8x8(x: i8x8, y: i8x8) -> i8x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.ssub.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i8x16
#[no_mangle]
pub unsafe fn ssub_i8x16(x: i8x16, y: i8x16) -> i8x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.ssub.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i8x32
#[no_mangle]
pub unsafe fn ssub_i8x32(x: i8x32, y: i8x32) -> i8x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.ssub.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i8x64
#[no_mangle]
pub unsafe fn ssub_i8x64(x: i8x64, y: i8x64) -> i8x64 {
- // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.ssub.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i16x2
#[no_mangle]
pub unsafe fn ssub_i16x2(x: i16x2, y: i16x2) -> i16x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.ssub.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i16x4
#[no_mangle]
pub unsafe fn ssub_i16x4(x: i16x4, y: i16x4) -> i16x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.ssub.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i16x8
#[no_mangle]
pub unsafe fn ssub_i16x8(x: i16x8, y: i16x8) -> i16x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.ssub.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i16x16
#[no_mangle]
pub unsafe fn ssub_i16x16(x: i16x16, y: i16x16) -> i16x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.ssub.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i16x32
#[no_mangle]
pub unsafe fn ssub_i16x32(x: i16x32, y: i16x32) -> i16x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.ssub.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i32x2
#[no_mangle]
pub unsafe fn ssub_i32x2(x: i32x2, y: i32x2) -> i32x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.ssub.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i32x4
#[no_mangle]
pub unsafe fn ssub_i32x4(x: i32x4, y: i32x4) -> i32x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.ssub.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i32x8
#[no_mangle]
pub unsafe fn ssub_i32x8(x: i32x8, y: i32x8) -> i32x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.ssub.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i32x16
#[no_mangle]
pub unsafe fn ssub_i32x16(x: i32x16, y: i32x16) -> i32x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.ssub.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i64x2
#[no_mangle]
pub unsafe fn ssub_i64x2(x: i64x2, y: i64x2) -> i64x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.ssub.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i64x4
#[no_mangle]
pub unsafe fn ssub_i64x4(x: i64x4, y: i64x4) -> i64x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.ssub.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i64x8
#[no_mangle]
pub unsafe fn ssub_i64x8(x: i64x8, y: i64x8) -> i64x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.ssub.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i128x2
#[no_mangle]
pub unsafe fn ssub_i128x2(x: i128x2, y: i128x2) -> i128x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.ssub.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @ssub_i128x4
#[no_mangle]
pub unsafe fn ssub_i128x4(x: i128x4, y: i128x4) -> i128x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.ssub.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x2
#[no_mangle]
pub unsafe fn usub_u8x2(x: u8x2, y: u8x2) -> u8x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{[0-9a-z]+}}, <2 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %{{x|_3}}, <2 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x4
#[no_mangle]
pub unsafe fn usub_u8x4(x: u8x4, y: u8x4) -> u8x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{[0-9a-z]+}}, <4 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i8> @llvm.usub.sat.v4i8(<4 x i8> %{{x|_3}}, <4 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x8
#[no_mangle]
pub unsafe fn usub_u8x8(x: u8x8, y: u8x8) -> u8x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{[0-9a-z]+}}, <8 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i8> @llvm.usub.sat.v8i8(<8 x i8> %{{x|_3}}, <8 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x16
#[no_mangle]
pub unsafe fn usub_u8x16(x: u8x16, y: u8x16) -> u8x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{[0-9a-z]+}}, <16 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i8> @llvm.usub.sat.v16i8(<16 x i8> %{{x|_3}}, <16 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x32
#[no_mangle]
pub unsafe fn usub_u8x32(x: u8x32, y: u8x32) -> u8x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{[0-9a-z]+}}, <32 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i8> @llvm.usub.sat.v32i8(<32 x i8> %{{x|_3}}, <32 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u8x64
#[no_mangle]
pub unsafe fn usub_u8x64(x: u8x64, y: u8x64) -> u8x64 {
- // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{[0-9a-z]+}}, <64 x i8> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <64 x i8> @llvm.usub.sat.v64i8(<64 x i8> %{{x|_3}}, <64 x i8> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u16x2
#[no_mangle]
pub unsafe fn usub_u16x2(x: u16x2, y: u16x2) -> u16x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{[0-9a-z]+}}, <2 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %{{x|_3}}, <2 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u16x4
#[no_mangle]
pub unsafe fn usub_u16x4(x: u16x4, y: u16x4) -> u16x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{[0-9a-z]+}}, <4 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i16> @llvm.usub.sat.v4i16(<4 x i16> %{{x|_3}}, <4 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u16x8
#[no_mangle]
pub unsafe fn usub_u16x8(x: u16x8, y: u16x8) -> u16x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{[0-9a-z]+}}, <8 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i16> @llvm.usub.sat.v8i16(<8 x i16> %{{x|_3}}, <8 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u16x16
#[no_mangle]
pub unsafe fn usub_u16x16(x: u16x16, y: u16x16) -> u16x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{[0-9a-z]+}}, <16 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i16> @llvm.usub.sat.v16i16(<16 x i16> %{{x|_3}}, <16 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u16x32
#[no_mangle]
pub unsafe fn usub_u16x32(x: u16x32, y: u16x32) -> u16x32 {
- // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{[0-9a-z]+}}, <32 x i16> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <32 x i16> @llvm.usub.sat.v32i16(<32 x i16> %{{x|_3}}, <32 x i16> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u32x2
#[no_mangle]
pub unsafe fn usub_u32x2(x: u32x2, y: u32x2) -> u32x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{[0-9a-z]+}}, <2 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i32> @llvm.usub.sat.v2i32(<2 x i32> %{{x|_3}}, <2 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u32x4
#[no_mangle]
pub unsafe fn usub_u32x4(x: u32x4, y: u32x4) -> u32x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{[0-9a-z]+}}, <4 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> %{{x|_3}}, <4 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u32x8
#[no_mangle]
pub unsafe fn usub_u32x8(x: u32x8, y: u32x8) -> u32x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{[0-9a-z]+}}, <8 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i32> @llvm.usub.sat.v8i32(<8 x i32> %{{x|_3}}, <8 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u32x16
#[no_mangle]
pub unsafe fn usub_u32x16(x: u32x16, y: u32x16) -> u32x16 {
- // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{[0-9a-z]+}}, <16 x i32> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <16 x i32> @llvm.usub.sat.v16i32(<16 x i32> %{{x|_3}}, <16 x i32> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u64x2
#[no_mangle]
pub unsafe fn usub_u64x2(x: u64x2, y: u64x2) -> u64x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{[0-9a-z]+}}, <2 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i64> @llvm.usub.sat.v2i64(<2 x i64> %{{x|_3}}, <2 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u64x4
#[no_mangle]
pub unsafe fn usub_u64x4(x: u64x4, y: u64x4) -> u64x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{[0-9a-z]+}}, <4 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i64> @llvm.usub.sat.v4i64(<4 x i64> %{{x|_3}}, <4 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u64x8
#[no_mangle]
pub unsafe fn usub_u64x8(x: u64x8, y: u64x8) -> u64x8 {
- // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{[0-9a-z]+}}, <8 x i64> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <8 x i64> @llvm.usub.sat.v8i64(<8 x i64> %{{x|_3}}, <8 x i64> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u128x2
#[no_mangle]
pub unsafe fn usub_u128x2(x: u128x2, y: u128x2) -> u128x2 {
- // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{[0-9a-z]+}}, <2 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <2 x i128> @llvm.usub.sat.v2i128(<2 x i128> %{{x|_3}}, <2 x i128> %{{y|_4}})
simd_saturating_sub(x, y)
}
// CHECK-LABEL: @usub_u128x4
#[no_mangle]
pub unsafe fn usub_u128x4(x: u128x4, y: u128x4) -> u128x4 {
- // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{[0-9a-z]+}}, <4 x i128> %{{[0-9a-z]+}})
+ // CHECK: %{{[0-9]+}} = call <4 x i128> @llvm.usub.sat.v4i128(<4 x i128> %{{x|_3}}, <4 x i128> %{{y|_4}})
simd_saturating_sub(x, y)
}
fn simd_bitmask<T, U>(x: T) -> U;
}
+// NOTE(eddyb) `%{{x|_2}}` is used because on some targets (e.g. WASM)
+// SIMD vectors are passed directly, resulting in `%x` being a vector,
+// while on others they're passed indirectly, resulting in `%x` being
+// a pointer to a vector, and `%_2` a vector loaded from that pointer.
+// This is controlled by the target spec option `simd_types_indirect`.
+
// CHECK-LABEL: @bitmask_int
#[no_mangle]
pub unsafe fn bitmask_int(x: i32x2) -> u8 {
- // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
// CHECK-LABEL: @bitmask_uint
#[no_mangle]
pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
- // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9a-z]+}}, <i32 31, i32 31>
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|_2}}, <i32 31, i32 31>
// CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
// CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
// CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
// CHECK-LABEL: @bitmask_int16
#[no_mangle]
pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
- // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9a-z]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|_2}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
// CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
// CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
// CHECK-NOT: zext
// compile-flags: -C opt-level=0
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![crate_type = "lib"]
#![feature(unwind_attributes)]
// compile-flags: -C no-prepopulate-passes
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![crate_type = "lib"]
#![feature(unwind_attributes)]
// Test that we detect changes to the `dep_kind` query. If the change is not
// detected then -Zincremental-verify-ich will trigger an assertion.
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// revisions:cfail1 cfail2
// compile-flags: -Z query-dep-graph -Cpanic=unwind
// build-pass (FIXME(62277): could be check-pass?)
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(box_syntax)]
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// Test that we generate StorageDead on unwind paths for generators.
//
// node [fontname="monospace"];
// edge [fontname="monospace"];
// label=<fn main() -> ()<br align="left"/>>;
-// bb0 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = ()<br/></td></tr><tr><td align="left">goto</td></tr></table>
-// >];
-// bb1 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>
-// >];
-// bb2 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>
-// >];
-// bb0 -> bb2 [label=""];
+// bb0__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = ()<br/></td></tr><tr><td align="left">goto</td></tr></table>>];
+// bb1__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">1</td></tr><tr><td align="left">resume</td></tr></table>>];
+// bb2__0_12 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">2</td></tr><tr><td align="left">return</td></tr></table>>];
+// bb0__0_12 -> bb2__0_12 [label=""];
// }
// END rustc.main.mir_map.0.dot
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// check that we don't emit multiple drop flags when they are not needed.
// check that we don't forget to drop the Box if we early return before
// initializing it
// ignore-tidy-linelength
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(box_syntax)]
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// Test that after the call to `std::mem::drop` we do not generate a
// MIR drop of the argument. (We used to have a `DROP(_2)` in the code
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
fn main() {
let mut x = Packed(Aligned(Droppy(0)));
// Test that the fake borrows for matches are removed after borrow checking.
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
fn match_guard(x: Option<&&i32>, c: bool) -> i32 {
match x {
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// ignore-tidy-linelength
// compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
--- /dev/null
+-include ../tools.mk
+
+all: foo
+ $(call RUN,foo)
+
+foo: foo.rs $(call NATIVE_STATICLIB,foo)
+ $(RUSTC) $< -lfoo $(EXTRARSCXXFLAGS)
+
+$(TMPDIR)/libfoo.o: foo.cpp
+ $(call COMPILE_OBJ_CXX,$@,$<)
--- /dev/null
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+
+void println(const char* s) {
+ puts(s);
+ fflush(stdout);
+}
+
+struct exception {};
+struct rust_panic {};
+
+struct drop_check {
+ bool* ok;
+ ~drop_check() {
+ println("~drop_check");
+
+ if (ok)
+ *ok = true;
+ }
+};
+
+extern "C" {
+ void rust_catch_callback(void (*cb)(), bool* rust_ok);
+
+ static void callback() {
+ println("throwing C++ exception");
+ throw exception();
+ }
+
+ void throw_cxx_exception() {
+ bool rust_ok = false;
+ try {
+ rust_catch_callback(callback, &rust_ok);
+ assert(false && "unreachable");
+ } catch (exception e) {
+ println("caught C++ exception");
+ assert(rust_ok);
+ return;
+ }
+ assert(false && "did not catch thrown C++ exception");
+ }
+
+ void cxx_catch_callback(void (*cb)(), bool* cxx_ok) {
+ drop_check x;
+ x.ok = NULL;
+ try {
+ cb();
+ } catch (rust_panic e) {
+ assert(false && "shouldn't be able to catch a rust panic");
+ } catch (...) {
+ println("caught foreign exception in catch (...)");
+ // Foreign exceptions are caught by catch (...). We only set the ok
+ // flag if we successfully caught the panic. The destructor of
+ // drop_check will then set the flag to true if it is executed.
+ x.ok = cxx_ok;
+ throw;
+ }
+ }
+}
--- /dev/null
+// Tests that C++ exceptions can unwind through Rust code, run destructors and
+// are ignored by catch_unwind. Also tests that Rust panics can unwind through
+// C++ code.
+
+// For linking libstdc++ on MinGW
+#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
+
+#![feature(unwind_attributes)]
+
+use std::panic::{catch_unwind, AssertUnwindSafe};
+
+struct DropCheck<'a>(&'a mut bool);
+impl<'a> Drop for DropCheck<'a> {
+ fn drop(&mut self) {
+ println!("DropCheck::drop");
+ *self.0 = true;
+ }
+}
+
+extern "C" {
+ fn throw_cxx_exception();
+
+ #[unwind(allowed)]
+ fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool);
+}
+
+#[no_mangle]
+#[unwind(allowed)]
+extern "C" fn rust_catch_callback(cb: extern "C" fn(), rust_ok: &mut bool) {
+ let _caught_unwind = catch_unwind(AssertUnwindSafe(|| {
+ let _drop = DropCheck(rust_ok);
+ cb();
+ unreachable!("should have unwound instead of returned");
+ }));
+ unreachable!("catch_unwind should not have caught foreign exception");
+}
+
+fn throw_rust_panic() {
+ #[unwind(allowed)]
+ extern "C" fn callback() {
+ println!("throwing rust panic");
+ panic!(1234i32);
+ }
+
+ let mut dropped = false;
+ let mut cxx_ok = false;
+ let caught_unwind = catch_unwind(AssertUnwindSafe(|| {
+ let _drop = DropCheck(&mut dropped);
+ unsafe {
+ cxx_catch_callback(callback, &mut cxx_ok);
+ }
+ unreachable!("should have unwound instead of returned");
+ }));
+ println!("caught rust panic");
+ assert!(dropped);
+ assert!(caught_unwind.is_err());
+ let panic_obj = caught_unwind.unwrap_err();
+ let panic_int = *panic_obj.downcast_ref::<i32>().unwrap();
+ assert_eq!(panic_int, 1234);
+ assert!(cxx_ok);
+}
+
+fn main() {
+ unsafe { throw_cxx_exception() };
+ throw_rust_panic();
+}
$(call RUN,foo)
foo: foo.rs $(call NATIVE_STATICLIB,foo)
- $(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
+ $(RUSTC) $< -lfoo $(EXTRARSCXXFLAGS)
$(TMPDIR)/libfoo.o: foo.cpp
$(call COMPILE_OBJ_CXX,$@,$<)
// Tests that linking to C++ code with global destructors works.
+// For linking libstdc++ on MinGW
+#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
+
extern { fn get() -> u32; }
fn main() {
+++ /dev/null
--include ../tools.mk
-
-# Different optimization levels imply different values for `-Zshare-generics`,
-# so try out a whole bunch of combinations to make sure everything is compatible
-all:
- # First up, try some defaults
- $(RUSTC) --crate-type rlib foo.rs
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=3
-
- # Next try mixing up some things explicitly
- $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
- $(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
- $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
- $(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-
- # Now combine a whole bunch of options together
- $(RUSTC) --crate-type rlib foo.rs
- $(RUSTC) --crate-type dylib bar.rs
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=1
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=2
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=3
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=s
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=z
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no
- $(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes
+++ /dev/null
-extern crate foo;
-
-pub fn bar() {
- foo::foo();
-}
+++ /dev/null
-pub fn foo() {
- bar::<usize>();
-}
-
-pub fn bar<T>() {
- baz();
-}
-
-fn baz() {}
# Check that a Rust dylib exports its monomorphic functions, including generics this time
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rust_dylib)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rust_dylib)" -eq "1" ]
# Check that a Rust dylib exports the monomorphic functions from its dependencies
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ]
[ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ]
- [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "0" ]
+ [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_generic_function_from_rlib)" -eq "1" ]
# Check that an executable does not export any dynamic symbols
[ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ]
ifdef IS_MSVC
COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
-COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
+COMPILE_OBJ_CXX = $(CXX) -EHs -c -Fo:`cygpath -w $(1)` $(2)
NATIVE_STATICLIB_FILE = $(1).lib
NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib
else
EXTRACFLAGS := -lws2_32 -luserenv
+ EXTRACXXFLAGS := -lstdc++
+ # So this is a bit hacky: we can't use the DLL version of libstdc++ because
+ # it pulls in the DLL version of libgcc, which means that we end up with 2
+ # instances of the DW2 unwinding implementation. This is a problem on
+ # i686-pc-windows-gnu because each module (DLL/EXE) needs to register its
+ # unwind information with the unwinding implementation, and libstdc++'s
+ # __cxa_throw won't see the unwinding info we registered with our statically
+ # linked libgcc.
+ #
+ # Now, simply statically linking libstdc++ would fix this problem, except
+ # that it is compiled with the expectation that pthreads is dynamically
+ # linked as a DLL and will fail to link with a statically linked libpthread.
+ #
+ # So we end up with the following hack: we link use static-nobundle to only
+ # link the parts of libstdc++ that we actually use, which doesn't include
+ # the dependency on the pthreads DLL.
+ EXTRARSCXXFLAGS := -l static-nobundle=stdc++
endif
else
ifeq ($(UNAME),Darwin)
EXTRACFLAGS := -lresolv
+ EXTRACXXFLAGS := -lc++
+ EXTRARSCXXFLAGS := -lc++
else
ifeq ($(UNAME),FreeBSD)
EXTRACFLAGS := -lm -lpthread -lgcc_s
else
EXTRACFLAGS := -lm -lrt -ldl -lpthread
EXTRACXXFLAGS := -lstdc++
+ EXTRARSCXXFLAGS := -lstdc++
endif
endif
endif
// Crates like core have doctests gated on `cfg(not(test))` so we need to make
// sure `cfg(test)` is not active when running `rustdoc --test`.
-#![feature(cfg_doctest)]
-
/// this doctest will be ignored:
///
/// ```
running 2 tests
-test $DIR/cfg-test.rs - Bar (line 28) ... ok
-test $DIR/cfg-test.rs - Foo (line 20) ... ok
+test $DIR/cfg-test.rs - Bar (line 26) ... ok
+test $DIR/cfg-test.rs - Foo (line 18) ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-#![feature(cfg_doctest)]
-
// @!has cfg_doctest/struct.SomeStruct.html
// @!has cfg_doctest/index.html '//a/@href' 'struct.SomeStruct.html'
--- /dev/null
+// ignore-tidy-linelength
+
+// First a module with inner documentation
+
+// @has issue_55364/subone/index.html
+// These foo/bar links in the module's documentation should refer inside `subone`
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo'
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar'
+pub mod subone {
+ //! See either [foo] or [bar].
+
+ // This should refer to subone's `bar`
+ // @has issue_55364/subone/fn.foo.html
+ // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.bar.html"]' 'bar'
+ /// See [bar]
+ pub fn foo() {}
+ // This should refer to subone's `foo`
+ // @has issue_55364/subone/fn.bar.html
+ // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subone/fn.foo.html"]' 'foo'
+ /// See [foo]
+ pub fn bar() {}
+}
+
+// A module with outer documentation
+
+// @has issue_55364/subtwo/index.html
+// These foo/bar links in the module's documentation should not reference inside `subtwo`
+// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo'
+// @!has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar'
+// Instead it should be referencing the top level functions
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo'
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar'
+// Though there should be such links later
+// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+/// See either [foo] or [bar].
+pub mod subtwo {
+
+ // Despite the module's docs referring to the top level foo/bar,
+ // this should refer to subtwo's `bar`
+ // @has issue_55364/subtwo/fn.foo.html
+ // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.bar.html"]' 'bar'
+ /// See [bar]
+ pub fn foo() {}
+ // Despite the module's docs referring to the top level foo/bar,
+ // this should refer to subtwo's `foo`
+ // @has issue_55364/subtwo/fn.bar.html
+ // @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/subtwo/fn.foo.html"]' 'foo'
+ /// See [foo]
+ pub fn bar() {}
+}
+
+// These are the function referred to by the module above with outer docs
+
+/// See [bar]
+pub fn foo() {}
+/// See [foo]
+pub fn bar() {}
+
+// This module refers to the outer foo/bar by means of `super::`
+
+// @has issue_55364/subthree/index.html
+// This module should also refer to the top level foo/bar
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.foo.html"]' 'foo'
+// @has - '//section[@id="main"]/div[@class="docblock"]//a[@href="../../issue_55364/fn.bar.html"]' 'bar'
+pub mod subthree {
+ //! See either [foo][super::foo] or [bar][super::bar]
+}
+
+// Next we go *deeper* - In order to ensure it's not just "this or parent"
+// we test `crate::` and a `super::super::...` chain
+// @has issue_55364/subfour/subfive/subsix/subseven/subeight/index.html
+// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subone/fn.foo.html"]' 'other foo'
+// @has - '//section[@id="main"]/table//tr[@class="module-item"]/td[@class="docblock-short"]//a[@href="../../../../../../issue_55364/subtwo/fn.bar.html"]' 'other bar'
+pub mod subfour {
+ pub mod subfive {
+ pub mod subsix {
+ pub mod subseven {
+ pub mod subeight {
+ /// See [other foo][crate::subone::foo]
+ pub fn foo() {}
+ /// See [other bar][super::super::super::super::super::subtwo::bar]
+ pub fn bar() {}
+ }
+ }
+ }
+ }
+}
// ignore-stage1
#![feature(plugin)]
-#![plugin(lint_group_plugin_test)]
+#![plugin(lint_group_plugin_test)] //~ WARNING use of deprecated attribute
#![allow(dead_code)]
fn lintme() { } //~ WARNING item is named 'lintme'
// aux-build:lint-plugin-test.rs
// ignore-stage1
#![feature(plugin)]
-#![plugin(lint_plugin_test)]
+#![plugin(lint_plugin_test)] //~ WARNING use of deprecated attribute
#![allow(dead_code)]
fn lintme() { } //~ WARNING item is named 'lintme'
// ignore-wasm32-bare no libc to test ffi with
-// FIXME: This will work on emscripten once libc is updated to include
-// rust-lang/libc/#1478
-// ignore-emscripten libc type mismatch
-
#![feature(rustc_private)]
extern crate libc;
box Invoker {
a: a,
b: b,
- } as (Box<dyn Invokable<A>+'static>)
+ } as Box<dyn Invokable<A>+'static>
}
pub fn main() {
// run-pass
+#[allow(unused_parens)]
fn main() {
assert_eq!(3 as usize * 3, 9);
assert_eq!(3 as (usize) * 3, 9);
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere1<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias.rs:6:25
LL | type _TaWhere2<T> where T: Iterator<Item: 'static> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere2<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias.rs:7:25
LL | type _TaWhere3<T> where T: Iterator<Item: 'static> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere3<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias.rs:8:25
LL | type _TaWhere4<T> where T: Iterator<Item: 'static + Copy + Send> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere4<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias.rs:9:25
LL | type _TaWhere5<T> where T: Iterator<Item: for<'a> Into<&'a u8>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere5<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias.rs:10:25
LL | type _TaWhere6<T> where T: Iterator<Item: Iterator<Item: Copy>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaWhere6<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:12:20
LL | type _TaInline1<T: Iterator<Item: Copy>> = T;
| ^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline1<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:13:20
LL | type _TaInline2<T: Iterator<Item: 'static>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline2<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:14:20
LL | type _TaInline3<T: Iterator<Item: 'static>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline3<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:15:20
LL | type _TaInline4<T: Iterator<Item: 'static + Copy + Send>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline4<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:16:20
LL | type _TaInline5<T: Iterator<Item: for<'a> Into<&'a u8>>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline5<T> = T;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias.rs:17:20
LL | type _TaInline6<T: Iterator<Item: Iterator<Item: Copy>>> = T;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type _TaInline6<T> = T;
+ | --
| -------- ---------- required by this bound in `blue_car`
...
LL | fn b() { blue_car(ModelT); }
- | ^^^^^^^^ expected struct `Black`, found struct `Blue`
+ | ^^^^^^^^ expected struct `Blue`, found struct `Black`
|
- = note: expected type `Black`
- found type `Blue`
+ = note: expected type `Blue`
+ found type `Black`
error[E0271]: type mismatch resolving `<ModelU as Vehicle>::Color == Black`
--> $DIR/associated-types-binding-to-type-defined-in-supertrait.rs:32:10
| --------- ----------- required by this bound in `black_car`
...
LL | fn c() { black_car(ModelU); }
- | ^^^^^^^^^ expected struct `Blue`, found struct `Black`
+ | ^^^^^^^^^ expected struct `Black`, found struct `Blue`
|
- = note: expected type `Blue`
- found type `Black`
+ = note: expected type `Black`
+ found type `Blue`
error: aborting due to 2 previous errors
let a = 42;
foo1(a);
//~^ ERROR type mismatch resolving
- //~| expected usize, found struct `Bar`
+ //~| expected struct `Bar`, found usize
baz(&a);
//~^ ERROR type mismatch resolving
- //~| expected usize, found struct `Bar`
+ //~| expected struct `Bar`, found usize
}
| ---- ----- required by this bound in `foo1`
...
LL | foo1(a);
- | ^^^^ expected usize, found struct `Bar`
+ | ^^^^ expected struct `Bar`, found usize
|
- = note: expected type `usize`
- found type `Bar`
+ = note: expected type `Bar`
+ found type `usize`
error[E0271]: type mismatch resolving `<isize as Foo>::A == Bar`
--> $DIR/associated-types-eq-3.rs:41:9
|
LL | baz(&a);
- | ^^ expected usize, found struct `Bar`
+ | ^^ expected struct `Bar`, found usize
|
- = note: expected type `usize`
- found type `Bar`
+ = note: expected type `Bar`
+ found type `usize`
= note: required for the cast to the object type `dyn Foo<A = Bar>`
error: aborting due to 3 previous errors
| ------------- required by this bound in `foo`
...
LL | foo::<UintStruct>();
- | ^^^^^^^^^^^^^^^^^ expected usize, found isize
+ | ^^^^^^^^^^^^^^^^^ expected isize, found usize
|
- = note: expected type `&usize`
- found type `&isize`
+ = note: expected type `&isize`
+ found type `&usize`
error[E0271]: type mismatch resolving `for<'x> <IntStruct as TheTrait<&'x isize>>::A == &'x usize`
--> $DIR/associated-types-eq-hr.rs:86:5
| ------------- required by this bound in `bar`
...
LL | bar::<IntStruct>();
- | ^^^^^^^^^^^^^^^^ expected isize, found usize
+ | ^^^^^^^^^^^^^^^^ expected usize, found isize
|
- = note: expected type `&isize`
- found type `&usize`
+ = note: expected type `&usize`
+ found type `&isize`
error[E0277]: the trait bound `for<'x, 'y> Tuple: TheTrait<(&'x isize, &'y isize)>` is not satisfied
--> $DIR/associated-types-eq-hr.rs:91:17
| -------------- ------ required by this bound in `is_iterator_of`
...
LL | is_iterator_of::<Option<T>, _>(&adapter);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found enum `std::option::Option`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found type parameter
|
- = note: expected type `T`
- found type `std::option::Option<T>`
+ = note: expected type `std::option::Option<T>`
+ found type `T`
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
--> $DIR/associated-types-multiple-types-one-trait.rs:13:5
|
LL | want_y(t);
- | ^^^^^^ expected associated type, found i32
+ | ^^^^^^ expected i32, found associated type
...
LL | fn want_y<T:Foo<Y=i32>>(t: &T) { }
| ------ ----- required by this bound in `want_y`
|
- = note: expected type `<T as Foo>::Y`
- found type `i32`
- = note: consider constraining the associated type `<T as Foo>::Y` to `i32` or calling a method that returns `<T as Foo>::Y`
+ = note: expected type `i32`
+ found type `<T as Foo>::Y`
+ = note: consider constraining the associated type `<T as Foo>::Y` to `i32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `<T as Foo>::X == u32`
--> $DIR/associated-types-multiple-types-one-trait.rs:18:5
|
LL | want_x(t);
- | ^^^^^^ expected associated type, found u32
+ | ^^^^^^ expected u32, found associated type
...
LL | fn want_x<T:Foo<X=u32>>(t: &T) { }
| ------ ----- required by this bound in `want_x`
|
- = note: expected type `<T as Foo>::X`
- found type `u32`
- = note: consider constraining the associated type `<T as Foo>::X` to `u32` or calling a method that returns `<T as Foo>::X`
+ = note: expected type `u32`
+ found type `<T as Foo>::X`
+ = note: consider constraining the associated type `<T as Foo>::X` to `u32`
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error: aborting due to 2 previous errors
--> $DIR/associated-types-overridden-binding-2.rs:6:43
|
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
- | ^^^^^^^^^^^^^^^^^^^^^ expected u32, found i32
+ | ^^^^^^^^^^^^^^^^^^^^^ expected i32, found u32
|
- = note: expected type `u32`
- found type `i32`
+ = note: expected type `i32`
+ found type `u32`
= note: required for the cast to the object type `dyn std::iter::Iterator<Item = u32, Item = i32>`
error: aborting due to previous error
--> $DIR/async-block-control-flow-static-semantics.rs:18:39
|
LL | let _: &dyn Future<Output = ()> = █
- | ^^^^^^ expected u8, found ()
+ | ^^^^^^ expected (), found u8
|
- = note: expected type `u8`
- found type `()`
+ = note: expected type `()`
+ found type `u8`
= note: required for the cast to the object type `dyn std::future::Future<Output = ()>`
error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:27:39
|
LL | let _: &dyn Future<Output = ()> = █
- | ^^^^^^ expected u8, found ()
+ | ^^^^^^ expected (), found u8
|
- = note: expected type `u8`
- found type `()`
+ = note: expected type `()`
+ found type `u8`
= note: required for the cast to the object type `dyn std::future::Future<Output = ()>`
error[E0308]: mismatched types
--- /dev/null
+#![feature(try_trait, async_closure)]
+// edition:2018
+fn main() {}
+
+async fn an_async_block() -> u32 {
+ async {
+ let x: Option<u32> = None;
+ x?; //~ ERROR the `?` operator
+ 22
+ }.await
+}
+
+async fn async_closure_containing_fn() -> u32 {
+ let async_closure = async || {
+ let x: Option<u32> = None;
+ x?; //~ ERROR the `?` operator
+ 22_u32
+ };
+
+ async_closure().await
+}
+
+async fn an_async_function() -> u32 {
+ let x: Option<u32> = None;
+ x?; //~ ERROR the `?` operator
+ 22
+}
--- /dev/null
+error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/try-on-option-in-async.rs:8:9
+ |
+LL | x?;
+ | ^^ cannot use the `?` operator in an async block that returns `{integer}`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `{integer}`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/try-on-option-in-async.rs:16:9
+ |
+LL | x?;
+ | ^^ cannot use the `?` operator in an async closure that returns `u32`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `u32`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/try-on-option-in-async.rs:25:5
+ |
+LL | x?;
+ | ^^ cannot use the `?` operator in an async function that returns `u32`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `u32`
+ = note: required by `std::ops::Try::from_error`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
// Check that partially moved from function parameters are dropped after the
// named bindings that move from them.
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
use std::{panic, cell::RefCell};
#![allow(unused_variables)]
#![allow(unused_imports)]
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// Test that builtin implementations of `Clone` cleanup everything
// in case of unwinding.
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
fn worker() -> ! {
panic!()
box Invoker {
a: a,
b: b,
- } as (Box<dyn Invokable<A>+'static>)
+ } as Box<dyn Invokable<A>+'static>
}
pub fn main() {
fn main() {
MustUseDeprecated::new(); //~ warning: use of deprecated item
- //| warning: unused `MustUseDeprecated` that must be used
+ //~| warning: unused `MustUseDeprecated` that must be used
}
struct Foo<const NUM_BYTES: usize>(pub [u8; NUM_BYTES]);
fn main() {
- let _ = Foo::<3>([1, 2, 3]); //~ ERROR type annotations needed
- //~^ ERROR mismatched types
+ let _ = Foo::<3>([1, 2, 3]);
}
error[E0658]: const generics are unstable
- --> $DIR/const-param-in-trait-ungated.rs:1:13
+ --> $DIR/const-param-in-trait-ungated.rs:1:19
|
LL | trait Trait<const T: ()> {}
- | ^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
- --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:13
+ --> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
|
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
- | ^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
- --> $DIR/issue-60263.rs:1:10
+ --> $DIR/issue-60263.rs:1:16
|
LL | struct B<const I: u8>;
- | ^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
}
fn main() {
- let foo = <[u8; 2]>::BIT_LEN;
+ let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable
}
--- /dev/null
+// run-pass
+
+#![feature(const_raw_ptr_deref)]
+#![feature(const_ptr_offset_from)]
+#![feature(ptr_offset_from)]
+
+struct Struct {
+ field: (),
+}
+
+#[repr(C)]
+struct Struct2 {
+ data: u8,
+ field: u8,
+}
+
+pub const OFFSET: usize = {
+ let uninit = std::mem::MaybeUninit::<Struct>::uninit();
+ let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
+ // The following statement is UB (taking the address of an uninitialized field).
+ // Const eval doesn't detect this right now, but it may stop compiling at some point
+ // in the future.
+ let field_ptr = unsafe { &(*base_ptr).field as *const () as *const u8 };
+ let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) };
+ offset as usize
+};
+
+pub const OFFSET_2: usize = {
+ let uninit = std::mem::MaybeUninit::<Struct2>::uninit();
+ let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2;
+ let field_ptr = unsafe { &(*base_ptr).field as *const u8 };
+ let offset = unsafe { field_ptr.offset_from(base_ptr as *const u8) };
+ offset as usize
+};
+
+pub const OVERFLOW: isize = {
+ let uninit = std::mem::MaybeUninit::<Struct2>::uninit();
+ let base_ptr: *const Struct2 = &uninit as *const _ as *const Struct2;
+ let field_ptr = unsafe { &(*base_ptr).field as *const u8 };
+ unsafe { (base_ptr as *const u8).offset_from(field_ptr) }
+};
+
+fn main() {
+ assert_eq!(OFFSET, 0);
+ assert_eq!(OFFSET_2, 1);
+ assert_eq!(OVERFLOW, -1);
+}
--- /dev/null
+// ignore-x86 FIXME: missing sysroot spans (#53081)
+
+#![feature(const_raw_ptr_deref)]
+#![feature(const_ptr_offset_from)]
+#![feature(ptr_offset_from)]
+
+#[repr(C)]
+struct Struct {
+ data: u8,
+ field: u8,
+}
+
+pub const DIFFERENT_ALLOC: usize = {
+ //~^ NOTE
+ let uninit = std::mem::MaybeUninit::<Struct>::uninit();
+ let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
+ let uninit2 = std::mem::MaybeUninit::<Struct>::uninit();
+ let field_ptr: *const Struct = &uninit2 as *const _ as *const Struct;
+ let offset = unsafe { field_ptr.offset_from(base_ptr) };
+ offset as usize
+};
+
+pub const NOT_PTR: usize = {
+ //~^ NOTE
+ unsafe { (42 as *const u8).offset_from(&5u8) as usize }
+};
+
+pub const NOT_MULTIPLE_OF_SIZE: usize = {
+ //~^ NOTE
+ let data = [5u8, 6, 7];
+ let base_ptr = data.as_ptr();
+ let field_ptr = &data[1] as *const u8 as *const u16;
+ let offset = unsafe { field_ptr.offset_from(base_ptr as *const u16) };
+ offset as usize
+};
+
+fn main() {}
--- /dev/null
+error: any use of this value will cause an error
+ --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ |
+LL | intrinsics::ptr_offset_from(self, origin)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | ptr_offset_from cannot compute offset of pointers into different allocations.
+ | inside call to `std::ptr::<impl *const Struct>::offset_from` at $DIR/offset_from_ub.rs:19:27
+ |
+ ::: $DIR/offset_from_ub.rs:13:1
+ |
+LL | / pub const DIFFERENT_ALLOC: usize = {
+LL | |
+LL | | let uninit = std::mem::MaybeUninit::<Struct>::uninit();
+LL | | let base_ptr: *const Struct = &uninit as *const _ as *const Struct;
+... |
+LL | | offset as usize
+LL | | };
+ | |__-
+ |
+ = note: `#[deny(const_err)]` on by default
+
+error: any use of this value will cause an error
+ --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ |
+LL | intrinsics::ptr_offset_from(self, origin)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | a memory access tried to interpret some bytes as a pointer
+ | inside call to `std::ptr::<impl *const u8>::offset_from` at $DIR/offset_from_ub.rs:25:14
+ |
+ ::: $DIR/offset_from_ub.rs:23:1
+ |
+LL | / pub const NOT_PTR: usize = {
+LL | |
+LL | | unsafe { (42 as *const u8).offset_from(&5u8) as usize }
+LL | | };
+ | |__-
+
+error: any use of this value will cause an error
+ --> $SRC_DIR/libcore/ptr/mod.rs:LL:COL
+ |
+LL | intrinsics::ptr_offset_from(self, origin)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | exact_div: 1 cannot be divided by 2 without remainder
+ | inside call to `std::ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:33:27
+ |
+ ::: $DIR/offset_from_ub.rs:28:1
+ |
+LL | / pub const NOT_MULTIPLE_OF_SIZE: usize = {
+LL | |
+LL | | let data = [5u8, 6, 7];
+LL | | let base_ptr = data.as_ptr();
+... |
+LL | | offset as usize
+LL | | };
+ | |__-
+
+error: aborting due to 3 previous errors
+
|
LL | / #![allow(dead_code)]
LL | |
-LL | | // error-pattern:`main` function not found in crate
-LL | |
+LL | | struct Tableau<'a, MP> {
+LL | | provider: &'a MP,
... |
LL | |
LL | | }
-#![allow(dead_code)]
-
-// error-pattern:`main` function not found in crate
+#![allow(dead_code)] //~ ERROR `main` function not found in crate
struct Tableau<'a, MP> {
provider: &'a MP,
|
LL | / #![allow(dead_code)]
LL | |
-LL | | // error-pattern:`main` function not found in crate
-LL | |
+LL | | struct Tableau<'a, MP> {
+LL | | provider: &'a MP,
... |
LL | |
LL | | }
| |_^ consider adding a `main` function to `$DIR/continue-after-missing-main.rs`
error[E0623]: lifetime mismatch
- --> $DIR/continue-after-missing-main.rs:30:56
+ --> $DIR/continue-after-missing-main.rs:28:56
|
LL | tableau: Tableau<'data_provider, AdaptedMatrixProvider<'original_data, MP>>,
| ------------------------------------------------------------------ these two types are declared with different lifetimes...
--- /dev/null
+// compile-flags: -C debuginfo=2
+
+// no-prefer-dynamic
+#![crate_type = "rlib"]
+
+pub trait Object { fn method(&self) { } }
+
+impl Object for u32 { }
+impl Object for () { }
+impl<T> Object for &T { }
+
+pub fn unused() {
+ let ref u = 0_u32;
+ let _d = &u as &dyn crate::Object;
+ _d.method()
+}
--- /dev/null
+// compile-flags: -C debuginfo=2 -C prefer-dynamic
+
+#![crate_type="dylib"]
+
+extern crate a_def_obj;
+
+pub use a_def_obj::Object;
--- /dev/null
+// no-prefer-dynamic
+// compile-flags: -C debuginfo=2
+#![crate_type="rlib"]
+
+extern crate b_reexport_obj;
+use b_reexport_obj::Object;
+
+pub fn another_dyn_debug() {
+ let ref u = 1_u32;
+ let _d = &u as &dyn crate::Object;
+ _d.method()
+}
--- /dev/null
+// compile-flags: -C debuginfo=2 -C prefer-dynamic
+
+#![crate_type="rlib"]
+
+extern crate c_another_vtable_for_obj;
+
+pub fn chain() {
+ c_another_vtable_for_obj::another_dyn_debug();
+}
--- /dev/null
+// run-pass
+
+// note that these aux-build directives must be in this order: the
+// later crates depend on the earlier ones. (The particular bug that
+// is being exercised here used to exhibit itself during the build of
+// `chain_of_rlibs_and_dylibs.dylib`)
+
+// aux-build:a_def_obj.rs
+// aux-build:b_reexport_obj.rs
+// aux-build:c_another_vtable_for_obj.rs
+// aux-build:d_chain_of_rlibs_and_dylibs.rs
+
+extern crate d_chain_of_rlibs_and_dylibs;
+
+pub fn main() {
+ d_chain_of_rlibs_and_dylibs::chain();
+}
#[derive(Debug)]
enum Foo {
Bar(u8),
- Void(Void), //~ WARN never used
+ Void(Void), //~ WARN never constructed
}
fn main() {
// run-pass
// edition:2018
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(slice_patterns)]
#![allow(unused)]
#![allow(unused_assignments)]
#![allow(unused_variables)]
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait, untagged_unions)]
#![feature(slice_patterns)]
| --- ------------------ required by this bound in `foo`
...
LL | foo(3_i8);
- | ^^^ expected reference, found u32
+ | ^^^ expected u32, found reference
|
- = note: expected type `&'static str`
- found type `u32`
+ = note: expected type `u32`
+ found type `&'static str`
error: aborting due to previous error
+++ /dev/null
-#[cfg(doctest)] //~ ERROR
-pub struct SomeStruct;
-
-fn main() {}
+++ /dev/null
-error[E0658]: `cfg(doctest)` is experimental and subject to change
- --> $DIR/feature-gate-cfg_doctest.rs:1:7
- |
-LL | #[cfg(doctest)]
- | ^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/62210
- = help: add `#![feature(cfg_doctest)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
// Exception, a gated and deprecated attribute.
#![plugin_registrar] //~ WARN unused attribute
+//~| WARN use of deprecated attribute
// UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES
#![crate_id = "10"] //~ WARN use of deprecated attribute
// FIXME(#44232) we should warn that this isn't used.
-#![feature(rust1)]
+#![feature(rust1)] //~ WARN no longer requires an attribute to enable
#![no_start] //~ WARN use of deprecated attribute
#[plugin_registrar]
//~^ WARN unused attribute
+//~| WARN use of deprecated attribute
mod plugin_registrar {
mod inner { #![plugin_registrar] }
//~^ WARN unused attribute
+ //~| WARN use of deprecated attribute
// for `fn f()` case, see gated-plugin_registrar.rs
#[plugin_registrar] struct S;
//~^ WARN unused attribute
+ //~| WARN use of deprecated attribute
#[plugin_registrar] type T = S;
//~^ WARN unused attribute
+ //~| WARN use of deprecated attribute
#[plugin_registrar] impl S { }
//~^ WARN unused attribute
+ //~| WARN use of deprecated attribute
}
#[main]
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:44:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
|
LL | #![warn(x5400)]
| ^^^^^
| ^^^^^^^^^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:10
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10
|
LL | #![allow(x5300)]
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:11
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11
|
LL | #![forbid(x5200)]
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9
|
LL | #![deny(x5100)]
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:8
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8
|
LL | #[warn(x5400)]
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:25
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25
|
LL | mod inner { #![warn(x5400)] }
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12
|
LL | #[warn(x5400)] fn f() { }
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12
|
LL | #[warn(x5400)] struct S;
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12
|
LL | #[warn(x5400)] type T = S;
| ^^^^^
warning: unknown lint: `x5400`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12
|
LL | #[warn(x5400)] impl S { }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:9
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9
|
LL | #[allow(x5300)]
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:26
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26
|
LL | mod inner { #![allow(x5300)] }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13
|
LL | #[allow(x5300)] fn f() { }
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13
|
LL | #[allow(x5300)] struct S;
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13
|
LL | #[allow(x5300)] type T = S;
| ^^^^^
warning: unknown lint: `x5300`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13
|
LL | #[allow(x5300)] impl S { }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:10
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10
|
LL | #[forbid(x5200)]
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:27
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27
|
LL | mod inner { #![forbid(x5200)] }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14
|
LL | #[forbid(x5200)] fn f() { }
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14
|
LL | #[forbid(x5200)] struct S;
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14
|
LL | #[forbid(x5200)] type T = S;
| ^^^^^
warning: unknown lint: `x5200`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14
|
LL | #[forbid(x5200)] impl S { }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:8
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8
|
LL | #[deny(x5100)]
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:25
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25
|
LL | mod inner { #![deny(x5100)] }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12
|
LL | #[deny(x5100)] fn f() { }
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12
|
LL | #[deny(x5100)] struct S;
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12
|
LL | #[deny(x5100)] type T = S;
| ^^^^^
warning: unknown lint: `x5100`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12
|
LL | #[deny(x5100)] impl S { }
| ^^^^^
warning: macro_escape is a deprecated synonym for macro_use
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:460:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1
|
LL | #[macro_escape]
| ^^^^^^^^^^^^^^^
warning: macro_escape is a deprecated synonym for macro_use
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:17
|
LL | mod inner { #![macro_escape] }
| ^^^^^^^^^^^^^^^^
= help: consider an outer attribute, `#[macro_use]` mod ...
warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17
|
LL | mod inner { #![plugin_registrar] }
| ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
= note: `#[warn(deprecated)]` on by default
warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5
|
LL | #[plugin_registrar] struct S;
| ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5
|
LL | #[plugin_registrar] type T = S;
| ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5
|
LL | #[plugin_registrar] impl S { }
| ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1
|
LL | #[plugin_registrar]
| ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
| ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version
warning: use of deprecated attribute `crate_id`: no longer used.
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:91:1
|
LL | #![crate_id = "10"]
| ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
warning: use of deprecated attribute `no_start`: no longer used.
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:95:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1
|
LL | #![no_start]
| ^^^^^^^^^^^^ help: remove this attribute
warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:93:12
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:12
|
LL | #![feature(rust1)]
| ^^^^^
= note: `#[warn(stable_features)]` on by default
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5
|
LL | #[macro_use] fn f() { }
| ^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5
|
LL | #[macro_use] struct S;
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
|
LL | #[macro_use] type T = S;
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5
|
LL | #[macro_use] impl S { }
| ^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17
|
LL | mod inner { #![macro_export] }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5
|
LL | #[macro_export] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5
|
LL | #[macro_export] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5
|
LL | #[macro_export] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5
|
LL | #[macro_export] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1
|
LL | #[macro_export]
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:219:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17
|
LL | mod inner { #![plugin_registrar] }
| ^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5
|
LL | #[plugin_registrar] struct S;
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5
|
LL | #[plugin_registrar] type T = S;
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:230:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5
|
LL | #[plugin_registrar] impl S { }
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:216:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1
|
LL | #[plugin_registrar]
| ^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:237:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:243:17
|
LL | mod inner { #![main] }
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:242:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5
|
LL | #[main] struct S;
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5
|
LL | #[main] type T = S;
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5
|
LL | #[main] impl S { }
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:234:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:1
|
LL | #[main]
| ^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17
|
LL | mod inner { #![start] }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5
|
LL | #[start] struct S;
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5
|
LL | #[start] type T = S;
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
|
LL | #[start] impl S { }
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1
|
LL | #[start]
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:319:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5
|
LL | #[path = "3800"] fn f() { }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5
|
LL | #[path = "3800"] struct S;
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5
|
LL | #[path = "3800"] type T = S;
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5
|
LL | #[path = "3800"] impl S { }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:17
|
LL | mod inner { #![automatically_derived] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5
|
LL | #[automatically_derived] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5
|
LL | #[automatically_derived] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
|
LL | #[automatically_derived] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5
|
LL | #[automatically_derived] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:1
|
LL | #[automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:17
|
LL | mod inner { #![no_link] }
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5
|
LL | #[no_link] fn f() { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5
|
LL | #[no_link] struct S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5
|
LL | #[no_link]type T = S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5
|
LL | #[no_link] impl S { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1
|
LL | #[no_link]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17
|
LL | mod inner { #![should_panic] }
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5
|
LL | #[should_panic] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5
|
LL | #[should_panic] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5
|
LL | #[should_panic] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
|
LL | #[should_panic] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1
|
LL | #[should_panic]
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17
|
LL | mod inner { #![ignore] }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
|
LL | #[ignore] fn f() { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5
|
LL | #[ignore] struct S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5
|
LL | #[ignore] type T = S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
|
LL | #[ignore] impl S { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1
|
LL | #[ignore]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17
|
LL | mod inner { #![no_implicit_prelude] }
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5
|
LL | #[no_implicit_prelude] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5
|
LL | #[no_implicit_prelude] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5
|
LL | #[no_implicit_prelude] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5
|
LL | #[no_implicit_prelude] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1
|
LL | #[no_implicit_prelude]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:17
|
LL | mod inner { #![reexport_test_harness_main="2900"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5
|
LL | #[reexport_test_harness_main = "2900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5
|
LL | #[reexport_test_harness_main = "2900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5
|
LL | #[reexport_test_harness_main = "2900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5
|
LL | #[reexport_test_harness_main = "2900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:1
|
LL | #[reexport_test_harness_main = "2900"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5
|
LL | #[macro_escape] fn f() { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5
|
LL | #[macro_escape] struct S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5
|
LL | #[macro_escape] type T = S;
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5
|
LL | #[macro_escape] impl S { }
| ^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:483:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17
|
LL | mod inner { #![no_std] }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5
|
LL | #[no_std] fn f() { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:491:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5
|
LL | #[no_std] struct S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5
|
LL | #[no_std] type T = S;
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5
|
LL | #[no_std] impl S { }
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1
|
LL | #[no_std]
| ^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1
|
LL | #[no_std]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17
|
LL | mod inner { #![crate_name="0900"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17
|
LL | mod inner { #![crate_name="0900"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5
|
LL | #[crate_name = "0900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5
|
LL | #[crate_name = "0900"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5
|
LL | #[crate_name = "0900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5
|
LL | #[crate_name = "0900"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5
|
LL | #[crate_name = "0900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5
|
LL | #[crate_name = "0900"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
|
LL | #[crate_name = "0900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
|
LL | #[crate_name = "0900"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1
|
LL | #[crate_name = "0900"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1
|
LL | #[crate_name = "0900"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17
|
LL | mod inner { #![crate_type="0800"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17
|
LL | mod inner { #![crate_type="0800"] }
| ^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5
|
LL | #[crate_type = "0800"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:667:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5
|
LL | #[crate_type = "0800"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5
|
LL | #[crate_type = "0800"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5
|
LL | #[crate_type = "0800"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
|
LL | #[crate_type = "0800"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
|
LL | #[crate_type = "0800"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
|
LL | #[crate_type = "0800"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
|
LL | #[crate_type = "0800"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1
|
LL | #[crate_type = "0800"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1
|
LL | #[crate_type = "0800"]
| ^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17
|
LL | mod inner { #![feature(x0600)] }
| ^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17
|
LL | mod inner { #![feature(x0600)] }
| ^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5
|
LL | #[feature(x0600)] fn f() { }
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5
|
LL | #[feature(x0600)] fn f() { }
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
|
LL | #[feature(x0600)] struct S;
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
|
LL | #[feature(x0600)] struct S;
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
|
LL | #[feature(x0600)] type T = S;
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5
|
LL | #[feature(x0600)] type T = S;
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5
|
LL | #[feature(x0600)] impl S { }
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5
|
LL | #[feature(x0600)] impl S { }
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1
|
LL | #[feature(x0600)]
| ^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1
|
LL | #[feature(x0600)]
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17
|
LL | mod inner { #![no_main] }
| ^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17
|
LL | mod inner { #![no_main] }
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
|
LL | #[no_main] fn f() { }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
|
LL | #[no_main] fn f() { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5
|
LL | #[no_main] struct S;
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:722:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5
|
LL | #[no_main] struct S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
|
LL | #[no_main] type T = S;
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
|
LL | #[no_main] type T = S;
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5
|
LL | #[no_main] impl S { }
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5
|
LL | #[no_main] impl S { }
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1
|
LL | #[no_main]
| ^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1
|
LL | #[no_main]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17
|
LL | mod inner { #![recursion_limit="0200"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17
|
LL | mod inner { #![recursion_limit="0200"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
|
LL | #[recursion_limit="0200"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
|
LL | #[recursion_limit="0200"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5
|
LL | #[recursion_limit="0200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:760:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5
|
LL | #[recursion_limit="0200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
|
LL | #[recursion_limit="0200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
|
LL | #[recursion_limit="0200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5
|
LL | #[recursion_limit="0200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:768:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5
|
LL | #[recursion_limit="0200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1
|
LL | #[recursion_limit="0200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1
|
LL | #[recursion_limit="0200"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17
|
LL | mod inner { #![type_length_limit="0100"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be in the root module
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:777:17
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17
|
LL | mod inner { #![type_length_limit="0100"] }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5
|
LL | #[type_length_limit="0100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:781:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5
|
LL | #[type_length_limit="0100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5
|
LL | #[type_length_limit="0100"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:785:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5
|
LL | #[type_length_limit="0100"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5
|
LL | #[type_length_limit="0100"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:789:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5
|
LL | #[type_length_limit="0100"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5
|
LL | #[type_length_limit="0100"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:793:5
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5
|
LL | #[type_length_limit="0100"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1
|
LL | #[type_length_limit="0100"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:773:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1
|
LL | #[type_length_limit="0100"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1
|
LL | #![macro_export]
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
|
LL | #![main]
| ^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
|
LL | #![start]
| ^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:56:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1
|
LL | #![repr()]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
|
LL | #![path = "3800"]
| ^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
|
LL | #![automatically_derived]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
|
LL | #![no_link]
| ^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:63:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
|
LL | #![should_panic]
| ^^^^^^^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
|
LL | #![ignore]
| ^^^^^^^^^^
warning: unused attribute
- --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1
+ --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1
|
LL | #![proc_macro_derive()]
| ^^^^^^^^^^^^^^^^^^^^^^^
// FIXME: uncomment when `impl_trait_in_bindings` feature is fixed.
// let _: &dyn Tr1<As1: Copy> = &S1;
}
-
-macro_rules! accept_path { ($p:path) => {} }
-accept_path!(Iterator<Item: Ord>);
-//~^ ERROR associated type bounds are unstable
= note: for more information, see https://github.com/rust-lang/rust/issues/52662
= help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
-error[E0658]: associated type bounds are unstable
- --> $DIR/feature-gate-associated_type_bounds.rs:75:23
- |
-LL | accept_path!(Iterator<Item: Ord>);
- | ^^^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/52662
- = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
-
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> $DIR/feature-gate-associated_type_bounds.rs:54:14
|
|
= help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
Some errors have detailed explanations: E0562, E0658.
For more information about an error, try `rustc --explain E0562`.
let box x = Box::new('c'); //~ ERROR box pattern syntax is experimental
println!("x: {}", x);
}
-
-macro_rules! accept_pat { ($p:pat) => {} }
-accept_pat!(box 0); //~ ERROR box pattern syntax is experimental
= note: for more information, see https://github.com/rust-lang/rust/issues/29641
= help: add `#![feature(box_patterns)]` to the crate attributes to enable
-error[E0658]: box pattern syntax is experimental
- --> $DIR/feature-gate-box_patterns.rs:7:13
- |
-LL | accept_pat!(box 0);
- | ^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/29641
- = help: add `#![feature(box_patterns)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
// Test that the use of the box syntax is gated by `box_syntax` feature gate.
-#[cfg(FALSE)]
-fn foo() {
+fn main() {
let x = box 3;
//~^ ERROR box expression syntax is experimental; you can call `Box::new` instead
}
-
-fn main() {}
error[E0658]: box expression syntax is experimental; you can call `Box::new` instead
- --> $DIR/feature-gate-box_syntax.rs:5:13
+ --> $DIR/feature-gate-box_syntax.rs:4:13
|
LL | let x = box 3;
| ^^^^^
error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics-ptr.rs:1:16
+ --> $DIR/feature-gate-const_generics-ptr.rs:1:22
|
LL | struct ConstFn<const F: fn()>;
- | ^^^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics-ptr.rs:5:17
+ --> $DIR/feature-gate-const_generics-ptr.rs:5:23
|
LL | struct ConstPtr<const P: *const u32>;
- | ^^^^^^^^^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
struct Foo<const X: usize>([(); X]); //~ ERROR const generics are unstable
-macro_rules! accept_item { ($i:item) => {} }
-accept_item! {
- impl<const X: ()> A {} //~ ERROR const generics are unstable
-}
-
fn main() {}
error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics.rs:1:8
+ --> $DIR/feature-gate-const_generics.rs:1:14
|
LL | fn foo<const X: ()>() {}
- | ^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics.rs:3:12
+ --> $DIR/feature-gate-const_generics.rs:3:18
|
LL | struct Foo<const X: usize>([(); X]);
- | ^^^^^^^^^^^^^^
+ | ^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/44580
= help: add `#![feature(const_generics)]` to the crate attributes to enable
-error[E0658]: const generics are unstable
- --> $DIR/feature-gate-const_generics.rs:7:10
- |
-LL | impl<const X: ()> A {}
- | ^^^^^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/44580
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.
water: bool,
}
-macro_rules! accept_vis { ($v:vis) => {} }
-accept_vis!(crate); //~ ERROR `crate` visibility modifier is experimental
-
fn main() {}
= note: for more information, see https://github.com/rust-lang/rust/issues/53120
= help: add `#![feature(crate_visibility_modifier)]` to the crate attributes to enable
-error[E0658]: `crate` visibility modifier is experimental
- --> $DIR/feature-gate-crate_visibility_modifier.rs:9:13
- |
-LL | accept_vis!(crate);
- | ^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/53120
- = help: add `#![feature(crate_visibility_modifier)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
macro m() {} //~ ERROR `macro` is experimental
-macro_rules! accept_item { ($i:item) => {} }
-accept_item! {
- macro m() {} //~ ERROR `macro` is experimental
-}
fn main() {}
= note: for more information, see https://github.com/rust-lang/rust/issues/39412
= help: add `#![feature(decl_macro)]` to the crate attributes to enable
-error[E0658]: `macro` is experimental
- --> $DIR/feature-gate-decl_macro.rs:7:5
- |
-LL | macro m() {}
- | ^^^^^^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/39412
- = help: add `#![feature(decl_macro)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
-#[cfg(FALSE)]
-fn foo() {
+pub fn main() {
match 22 {
0 .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental
- PATH .. 3 => {} //~ ERROR exclusive range pattern syntax is experimental
_ => {}
}
}
-
-fn main() {}
error[E0658]: exclusive range pattern syntax is experimental
- --> $DIR/feature-gate-exclusive-range-pattern.rs:4:11
+ --> $DIR/feature-gate-exclusive-range-pattern.rs:3:9
|
LL | 0 .. 3 => {}
- | ^^
+ | ^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/37854
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
-error[E0658]: exclusive range pattern syntax is experimental
- --> $DIR/feature-gate-exclusive-range-pattern.rs:5:14
- |
-LL | PATH .. 3 => {}
- | ^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/37854
- = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
-#[cfg(FALSE)]
-pub fn foo() {
+pub fn main() {
'a: { //~ ERROR labels on blocks are unstable
break 'a;
}
}
-
-fn main() {}
error[E0658]: labels on blocks are unstable
- --> $DIR/feature-gate-label_break_value.rs:3:5
+ --> $DIR/feature-gate-label_break_value.rs:2:5
|
LL | 'a: {
| ^^
trait Foo = Default;
//~^ ERROR trait aliases are experimental
-macro_rules! accept_item {
- ($i:item) => {}
-}
-
-accept_item! {
- trait Foo = Ord + Eq;
- //~^ ERROR trait aliases are experimental
-}
-
fn main() {}
= note: for more information, see https://github.com/rust-lang/rust/issues/41517
= help: add `#![feature(trait_alias)]` to the crate attributes to enable
-error[E0658]: trait aliases are experimental
- --> $DIR/feature-gate-trait-alias.rs:9:5
- |
-LL | trait Foo = Ord + Eq;
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: for more information, see https://github.com/rust-lang/rust/issues/41517
- = help: add `#![feature(trait_alias)]` to the crate attributes to enable
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.
// compile-flags: --edition 2018
-#[cfg(FALSE)]
-fn foo() {
- let try_result: Option<_> = try { //~ ERROR `try` blocks are unstable
+pub fn main() {
+ let try_result: Option<_> = try { //~ ERROR `try` expression is experimental
let x = 5;
x
};
assert_eq!(try_result, Some(5));
}
-
-fn main() {}
-error[E0658]: `try` blocks are unstable
- --> $DIR/feature-gate-try_blocks.rs:5:33
+error[E0658]: `try` expression is experimental
+ --> $DIR/feature-gate-try_blocks.rs:4:33
|
LL | let try_result: Option<_> = try {
| _________________________________^
// Type ascription is unstable
-#[cfg(FALSE)]
-fn foo() {
+fn main() {
let a = 10: u8; //~ ERROR type ascription is experimental
}
-
-fn main() {}
error[E0658]: type ascription is experimental
- --> $DIR/feature-gate-type_ascription.rs:5:13
+ --> $DIR/feature-gate-type_ascription.rs:4:13
|
LL | let a = 10: u8;
| ^^^^^^
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C no-prepopulate-passes -Cpasses=name-anon-globals
#![crate_type = "lib"]
|v: &mut u32| *v += 3,
|v: &mut u32| *v += 4,
];
-fn func_specific() -> (fn() -> u32) {
+fn func_specific() -> fn() -> u32 {
|| return 42
}
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(generators, generator_trait)]
fn main() {
let fat: Option<S1M<S1M<S1M<u32>>>> = None;
- //~^ ERROR the type `S32<S1M<S1M<u32>>>` is too big for the current architecture
+ //~^ ERROR is too big for the current architecture
}
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
if let $p = $e $b
+ //~^ WARN irrefutable if-let
+ //~| WARN irrefutable if-let
}}
}
macro_rules! bar{
}}
}
- foo!(a, 1, { //~ WARN irrefutable if-let
+ foo!(a, 1, {
println!("irrefutable pattern");
});
- bar!(a, 1, { //~ WARN irrefutable if-let
+ bar!(a, 1, {
println!("irrefutable pattern");
});
}
| |_______- in this macro invocation
warning: irrefutable if-let pattern
- --> $DIR/if-let.rs:24:5
+ --> $DIR/if-let.rs:26:5
|
LL | / if let a = 1 {
LL | | println!("irrefutable pattern");
| |_____^
warning: irrefutable if-let pattern
- --> $DIR/if-let.rs:28:5
+ --> $DIR/if-let.rs:30:5
|
LL | / if let a = 1 {
LL | | println!("irrefutable pattern");
| |_____^
warning: irrefutable if-let pattern
- --> $DIR/if-let.rs:38:12
+ --> $DIR/if-let.rs:40:12
|
LL | } else if let a = 1 {
| ____________^
| |_____^
warning: irrefutable if-let pattern
- --> $DIR/if-let.rs:44:12
+ --> $DIR/if-let.rs:46:12
|
LL | } else if let a = 1 {
| ____________^
+#![warn(unused_imports)]
+
mod a {
fn foo() {}
mod foo {}
mod a {
pub use super::foo; //~ ERROR cannot be re-exported
- pub use super::*; //~ ERROR must import something with the glob's visibility
+ pub use super::*;
+ //~^ WARNING glob import doesn't reexport anything because no candidate is public enough
}
}
mod b {
pub fn foo() {}
- mod foo { pub struct S; }
+ mod foo {
+ pub struct S;
+ }
pub mod a {
pub use super::foo; // This is OK since the value `foo` is visible enough.
error[E0364]: `foo` is private, and cannot be re-exported
- --> $DIR/reexports.rs:6:17
+ --> $DIR/reexports.rs:8:17
|
LL | pub use super::foo;
| ^^^^^^^^^^
|
note: consider marking `foo` as `pub` in the imported module
- --> $DIR/reexports.rs:6:17
+ --> $DIR/reexports.rs:8:17
|
LL | pub use super::foo;
| ^^^^^^^^^^
-error: A non-empty glob must import something with the glob's visibility
- --> $DIR/reexports.rs:7:17
- |
-LL | pub use super::*;
- | ^^^^^^^^
-
error[E0603]: module `foo` is private
- --> $DIR/reexports.rs:28:15
+ --> $DIR/reexports.rs:33:15
|
LL | use b::a::foo::S;
| ^^^
error[E0603]: module `foo` is private
- --> $DIR/reexports.rs:29:15
+ --> $DIR/reexports.rs:34:15
|
LL | use b::b::foo::S as T;
| ^^^
-error: aborting due to 4 previous errors
+warning: glob import doesn't reexport anything because no candidate is public enough
+ --> $DIR/reexports.rs:9:17
+ |
+LL | pub use super::*;
+ | ^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/reexports.rs:1:9
+ |
+LL | #![warn(unused_imports)]
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
Some errors have detailed explanations: E0364, E0603.
For more information about an error, try `rustc --explain E0364`.
+// ignore-x86
+// ^ due to stderr output differences
use std::ops::Deref;
trait Trait {}
impl Deref for Struct {
type Target = dyn Trait;
fn deref(&self) -> &dyn Trait {
+ //~^ ERROR `impl` item signature doesn't match `trait` item signature
unimplemented!();
}
}
-//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter
fn main() {}
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
- --> $DIR/mismatched_trait_impl-2.rs:8:5
+error: `impl` item signature doesn't match `trait` item signature
+ --> $DIR/mismatched_trait_impl-2.rs:10:5
|
LL | fn deref(&self) -> &dyn Trait {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&Struct) -> &dyn Trait
+ |
+ ::: $SRC_DIR/libcore/ops/deref.rs:LL:COL
|
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 8:5...
- --> $DIR/mismatched_trait_impl-2.rs:8:5
+LL | fn deref(&self) -> &Self::Target;
+ | --------------------------------- expected fn(&Struct) -> &(dyn Trait + 'static)
|
-LL | / fn deref(&self) -> &dyn Trait {
-LL | | unimplemented!();
-LL | | }
- | |_____^
- = note: ...but the lifetime must also be valid for the static lifetime...
- = note: ...so that the method type is compatible with trait:
- expected fn(&Struct) -> &(dyn Trait + 'static)
- found fn(&Struct) -> &dyn Trait
+ = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
+ found `fn(&Struct) -> &dyn Trait`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
+error: `impl` item signature doesn't match `trait` item signature
--> $DIR/mismatched_trait_impl.rs:9:5
|
+LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
+ | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5...
- --> $DIR/mismatched_trait_impl.rs:9:5
- |
-LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-LL | | x
-LL | | }
- | |_____^
-note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32...
- --> $DIR/mismatched_trait_impl.rs:9:32
- |
-LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^
- = note: ...so that the method type is compatible with trait:
- expected fn(&i32, &'a u32, &u32) -> &'a u32
- found fn(&i32, &u32, &u32) -> &u32
+ = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ found `fn(&i32, &u32, &u32) -> &u32`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
}
impl Get for i32 {
- fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+ fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR `impl` item signature doesn't match
x //~ ERROR lifetime mismatch
}
}
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
+error: `impl` item signature doesn't match `trait` item signature
--> $DIR/mismatched_trait_impl.rs:9:5
|
+LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
+ | ---------------------------------------------- expected fn(&i32, &'a u32, &u32) -> &'a u32
+...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &u32, &u32) -> &u32
|
-note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 9:5...
- --> $DIR/mismatched_trait_impl.rs:9:5
- |
-LL | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
-LL | | x
-LL | | }
- | |_____^
-note: ...but the lifetime must also be valid for the lifetime `'a` as defined on the method body at 9:32...
- --> $DIR/mismatched_trait_impl.rs:9:32
- |
-LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^
- = note: ...so that the method type is compatible with trait:
- expected fn(&i32, &'a u32, &u32) -> &'a u32
- found fn(&i32, &u32, &u32) -> &u32
+ = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ found `fn(&i32, &u32, &u32) -> &u32`
error[E0623]: lifetime mismatch
--> $DIR/mismatched_trait_impl.rs:10:9
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0495`.
-error: only foreign functions are allowed to be C-variadic
+error[E0743]: only foreign functions are allowed to be C-variadic
--> $DIR/invalid-variadic-function.rs:1:26
|
LL | extern "C" fn foo(x: u8, ...);
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0743`.
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// Check that values are not leaked when a dtor panics (#14875)
| ------------------ required by `Trait`
...
LL | fn test<T: Trait<B=i32>>(b: i32) -> T where T::A: MultiDispatch<i32> { T::new(b) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected associated type, found type parameter
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found associated type
|
- = note: expected type `<<T as Trait>::A as MultiDispatch<i32>>::O`
- found type `T`
+ = note: expected type `T`
+ found type `<<T as Trait>::A as MultiDispatch<i32>>::O`
= note: you might be missing a type parameter or trait bound
error: aborting due to previous error
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
use std::panic;
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
use std::panic;
// run-pass
// compile-flags:--test -O
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#[test]
#[should_panic(expected = "creating inhabited type")]
return;
let _x = foo::<Vec<_>>(Vec::<&'a u32>::new());
- //~^ ERROR the type `&'a u32` does not fulfill the required lifetime [E0477]
}
fn main() {}
// run-pass
// only-32bit too impatient for 2⁶⁴ items
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes -C opt-level=3
use std::panic;
// run-pass
// only-32bit too impatient for 2⁶⁴ items
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes -C opt-level=3
use std::panic;
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes
use std::panic;
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C debug_assertions=yes
use std::panic;
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -C overflow-checks
use std::panic;
--- /dev/null
+trait Foo {
+ fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
+}
+
+impl Foo for () {
+ fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+ //~^ ERROR `impl` item signature doesn't match `trait` item signature
+ if x > y { x } else { y }
+ }
+}
+
+fn main() {}
--- /dev/null
+error: `impl` item signature doesn't match `trait` item signature
+ --> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
+ |
+LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
+ | ------------------------------------------- expected fn(&i32, &'a i32) -> &'a i32
+...
+LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found fn(&i32, &i32) -> &i32
+ |
+ = note: expected `fn(&i32, &'a i32) -> &'a i32`
+ found `fn(&i32, &i32) -> &i32`
+
+error: aborting due to previous error
+
return (X { y }); //~ ERROR unnecessary parentheses around `return` value
}
+fn unused_parens_around_return_type() -> (u32) { //~ ERROR unnecessary parentheses around type
+ panic!()
+}
+
+trait Trait {
+ fn test(&self);
+}
+
+fn passes_unused_parens_lint() -> &'static (dyn Trait) {
+ panic!()
+}
+
fn main() {
foo();
bar((true)); //~ ERROR unnecessary parentheses around function argument
LL | return (X { y });
| ^^^^^^^^^ help: remove these parentheses
+error: unnecessary parentheses around type
+ --> $DIR/lint-unnecessary-parens.rs:16:42
+ |
+LL | fn unused_parens_around_return_type() -> (u32) {
+ | ^^^^^ help: remove these parentheses
+
error: unnecessary parentheses around function argument
- --> $DIR/lint-unnecessary-parens.rs:18:9
+ --> $DIR/lint-unnecessary-parens.rs:30:9
|
LL | bar((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `if` condition
- --> $DIR/lint-unnecessary-parens.rs:20:8
+ --> $DIR/lint-unnecessary-parens.rs:32:8
|
LL | if (true) {}
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `while` condition
- --> $DIR/lint-unnecessary-parens.rs:21:11
+ --> $DIR/lint-unnecessary-parens.rs:33:11
|
LL | while (true) {}
| ^^^^^^ help: remove these parentheses
warning: denote infinite loops with `loop { ... }`
- --> $DIR/lint-unnecessary-parens.rs:21:5
+ --> $DIR/lint-unnecessary-parens.rs:33:5
|
LL | while (true) {}
| ^^^^^^^^^^^^ help: use `loop`
= note: `#[warn(while_true)]` on by default
error: unnecessary parentheses around `match` head expression
- --> $DIR/lint-unnecessary-parens.rs:23:11
+ --> $DIR/lint-unnecessary-parens.rs:35:11
|
LL | match (true) {
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:26:16
+ --> $DIR/lint-unnecessary-parens.rs:38:16
|
LL | if let 1 = (1) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around `let` head expression
- --> $DIR/lint-unnecessary-parens.rs:27:19
+ --> $DIR/lint-unnecessary-parens.rs:39:19
|
LL | while let 1 = (2) {}
| ^^^ help: remove these parentheses
error: unnecessary parentheses around method argument
- --> $DIR/lint-unnecessary-parens.rs:41:24
+ --> $DIR/lint-unnecessary-parens.rs:53:24
|
LL | X { y: false }.foo((true));
| ^^^^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:43:18
+ --> $DIR/lint-unnecessary-parens.rs:55:18
|
LL | let mut _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:44:10
+ --> $DIR/lint-unnecessary-parens.rs:56:10
|
LL | _a = (0);
| ^^^ help: remove these parentheses
error: unnecessary parentheses around assigned value
- --> $DIR/lint-unnecessary-parens.rs:45:11
+ --> $DIR/lint-unnecessary-parens.rs:57:11
|
LL | _a += (1);
| ^^^ help: remove these parentheses
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
fn main() {
let Social_exchange_psychology = CheaterDetectionMechanism {};
- //~^ WARN should have a snake case name such as
+ //~^ WARN should have a snake case name
+ //~| NOTE #[warn(non_snake_case)]` implied by `#[warn(nonstandard_style)]
//~| NOTE people shouldn't have to change their usual style habits
+ //~| HELP convert the identifier to snake case
}
#![warn(overflowing_literals)]
fn main() {
- let error = 255i8; //~WARNING literal out of range for i8
+ let error = 255i8; //~WARNING literal out of range for `i8`
let ok = 0b1000_0001; // should be ok -> i32
let ok = 0b0111_1111i8; // should be ok -> 127i8
// build-pass (FIXME(62277): could be check-pass?)
#![warn(unused_imports)]
-use crate::foo::Bar; //~ WARNING first import
+use crate::foo::Bar;
mod foo {
pub type Bar = i32;
mod m1 { pub struct S {} }
mod m2 { pub struct S {} }
-use m1::*;
-use m2::*;
+use m1::*; //~ WARNING unused import
+use m2::*; //~ WARNING unused import
fn main() {
- use crate::foo::Bar; //~ WARNING redundant import
+ use crate::foo::Bar; //~ WARNING imported redundantly
let _a: Bar = 3;
baz();
- use m1::S; //~ WARNING redundant import
+ use m1::S;
let _s = S {};
}
// compile-flags: --test -C debug_assertions=yes
// revisions: std core
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![cfg_attr(core, no_std)]
// build-pass (FIXME(62277): could be check-pass?)
-#[doc] //~ WARN attribute must be of the form
-#[ignore()] //~ WARN attribute must be of the form
-#[inline = ""] //~ WARN attribute must be of the form
-#[link] //~ WARN attribute must be of the form
-#[link = ""] //~ WARN attribute must be of the form
+#[doc]
+//~^ WARN attribute must be of the form
+//~| WARN this was previously accepted
+#[ignore()]
+//~^ WARN attribute must be of the form
+//~| WARN this was previously accepted
+#[inline = ""]
+//~^ WARN attribute must be of the form
+//~| WARN this was previously accepted
+#[link]
+//~^WARN attribute must be of the form
+//~| WARN this was previously accepted
+#[link = ""]
+//~^ WARN attribute must be of the form
+//~| WARN this was previously accepted
fn main() {}
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: attribute must be of the form `#[ignore]` or `#[ignore = "reason"]`
- --> $DIR/malformed-regressions.rs:4:1
+ --> $DIR/malformed-regressions.rs:6:1
|
LL | #[ignore()]
| ^^^^^^^^^^^
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
- --> $DIR/malformed-regressions.rs:5:1
+ --> $DIR/malformed-regressions.rs:9:1
|
LL | #[inline = ""]
| ^^^^^^^^^^^^^^
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...")]`
- --> $DIR/malformed-regressions.rs:6:1
+ --> $DIR/malformed-regressions.rs:12:1
|
LL | #[link]
| ^^^^^^^
= note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
warning: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...")]`
- --> $DIR/malformed-regressions.rs:7:1
+ --> $DIR/malformed-regressions.rs:15:1
|
LL | #[link = ""]
| ^^^^^^^^^^^^
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(fn_traits)]
#![feature(never_type)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
use std::cell::RefCell;
use std::panic;
// Test that a variable of type ! can coerce to another type.
-// run-fail
-// error-pattern:explicit
+// check-pass
#![feature(never_type)]
// Test that we can use a ! for an argument of type !
-// run-fail
-// error-pattern:wowzers!
+// check-pass
#![feature(never_type)]
#![allow(unreachable_code)]
// Test that we can explicitly cast ! to another type
-// run-fail
-// error-pattern:explicit
+// check-pass
#![feature(never_type)]
// Test that we can use ! as an associated type.
-// run-fail
-// error-pattern:kapow!
+// check-pass
#![feature(never_type)]
// Test that we can use ! as an argument to a trait impl.
-// run-fail
-// error-pattern:oh no!
+// check-pass
#![feature(never_type)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// This test checks that instantiating an uninhabited type via `mem::{uninitialized,zeroed}` results
// in a runtime panic.
// run-pass
// compile-flags: -C debug_assertions=yes
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// ignore-emscripten dies with an LLVM error
use std::panic;
--- /dev/null
+// run-pass
+
+#![feature(ptr_offset_from)]
+
+fn main() {
+ let mut a = [0; 5];
+ let ptr1: *mut i32 = &mut a[1];
+ let ptr2: *mut i32 = &mut a[3];
+ unsafe {
+ assert_eq!(ptr2.offset_from(ptr1), 2);
+ assert_eq!(ptr1.offset_from(ptr2), -2);
+ assert_eq!(ptr1.offset(2), ptr2);
+ assert_eq!(ptr2.offset(-2), ptr1);
+ }
+}
// check-pass
#![feature(or_patterns)]
-#![feature(box_patterns)]
fn main() {}
// aux-build:wants-panic-runtime-abort.rs
// aux-build:panic-runtime-lang-items.rs
// error-pattern: is not compiled with this crate's panic strategy `unwind`
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![no_std]
#![no_main]
// error-pattern:is incompatible with this crate's strategy of `unwind`
// aux-build:panic-runtime-abort.rs
// aux-build:panic-runtime-lang-items.rs
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![no_std]
#![no_main]
// aux-build:panic-runtime-abort.rs
// aux-build:wants-panic-runtime-abort.rs
// aux-build:panic-runtime-lang-items.rs
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![no_std]
#![no_main]
match 0 {
(.. PAT) => {}
//~^ ERROR `..X` range patterns are not supported
+ //~| ERROR exclusive range pattern syntax is experimental
}
}
LL | (.. PAT) => {}
| ^^^^^^ help: try using the minimum value for the type: `MIN..PAT`
+error[E0658]: exclusive range pattern syntax is experimental
+ --> $DIR/pat-tuple-4.rs:5:10
+ |
+LL | (.. PAT) => {}
+ | ^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/37854
+ = help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
+
error[E0308]: mismatched types
- --> $DIR/pat-tuple-4.rs:10:30
+ --> $DIR/pat-tuple-4.rs:11:30
|
LL | const RECOVERY_WITNESS: () = 0;
| ^ expected (), found integer
= note: expected type `()`
found type `{integer}`
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
| ^^^^^^ help: try using the maximum value for the type: `PAT..MAX`
error[E0658]: exclusive range pattern syntax is experimental
- --> $DIR/pat-tuple-5.rs:5:14
+ --> $DIR/pat-tuple-5.rs:5:10
|
LL | (PAT ..) => {}
- | ^^
+ | ^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/37854
= help: add `#![feature(exclusive_range_pattern)]` to the crate attributes to enable
-error: only foreign functions are allowed to be C-variadic
+error[E0743]: only foreign functions are allowed to be C-variadic
--> $DIR/variadic-ffi-3.rs:1:18
|
LL | fn foo(x: isize, ...) {
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0743`.
-error: only foreign functions are allowed to be C-variadic
+error[E0743]: only foreign functions are allowed to be C-variadic
--> $DIR/variadic-ffi-4.rs:1:29
|
LL | extern "C" fn foo(x: isize, ...) {
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0743`.
// check-pass
-#![feature(box_patterns)]
-
fn main() {}
macro_rules! accept_pat {
match 10 {
1..10 => {},
- 8..=9 => {}, //~ WARNING multiple patterns covering the same range
+ 8..=9 => {}, //~ WARNING unreachable pattern
_ => {},
}
match 10 {
5..7 => {},
6 => {}, //~ WARNING unreachable pattern
- 1..10 => {}, //~ WARNING multiple patterns covering the same range
+ 1..10 => {},
9..=9 => {}, //~ WARNING unreachable pattern
6 => {}, //~ WARNING unreachable pattern
_ => {},
| ^^^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | pub type Alias<T> = T;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/private-in-public-warn.rs:75:29
LL | pub type Alias<T> where T: PrivTr = T;
| ^^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | pub type Alias<T> = T;
+ | --
error: aborting due to 36 previous errors
-error: visibilities can only be restricted to ancestor modules
+error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/relative-2018.rs:7:12
|
LL | pub(in ::core) struct S4;
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0742`.
LL | pub(in bad::path) mod m1 {}
| ^^^ maybe a missing crate `bad`?
-error: visibilities can only be restricted to ancestor modules
+error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/test.rs:51:12
|
LL | pub(in foo) mod m2 {}
error: aborting due to 12 previous errors
-Some errors have detailed explanations: E0364, E0433, E0603, E0616, E0624.
+Some errors have detailed explanations: E0364, E0433, E0603, E0616, E0624, E0742.
For more information about an error, try `rustc --explain E0364`.
// run-pass
// aux-build:expand-with-a-macro.rs
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![deny(warnings)]
-error: visibilities can only be restricted to ancestor modules
+error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/issue-50493.rs:8:12
|
LL | pub(in restricted) field: usize,
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0616`.
+Some errors have detailed explanations: E0616, E0742.
+For more information about an error, try `rustc --explain E0616`.
`pub(super)`: visible only in the current module's parent
`pub(in path::to::module)`: visible only on the specified path
-error: visibilities can only be restricted to ancestor modules
+error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/pub-restricted.rs:25:17
|
LL | pub (in x) non_parent_invalid: usize,
error: aborting due to 6 previous errors
-For more information about this error, try `rustc --explain E0704`.
+Some errors have detailed explanations: E0704, E0742.
+For more information about an error, try `rustc --explain E0704`.
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// aux-build:reachable-unnameable-items.rs
extern crate reachable_unnameable_items;
x: &'a i32,
}
struct Bar<'a,'b> {
- f: &'a Foo<'b> //~ ERROR reference has a longer lifetime
+ f: &'a Foo<'b>
}
}
x: fn(T)
}
struct Bar<'a,'b> {
- f: &'a Foo<&'b i32> //~ ERROR reference has a longer lifetime
+ f: &'a Foo<&'b i32>
}
}
x: T
}
struct Bar<'a,'b> {
- f: &'a Foo<&'b i32> //~ ERROR reference has a longer lifetime
+ f: &'a Foo<&'b i32>
}
}
//~^ ERROR Implementations of Drop cannot be specialized
impl<'lw> Drop for W<'lw,'lw> { fn drop(&mut self) { } } // REJECT
-//~^ ERROR cannot infer an appropriate lifetime
+//~^ ERROR cannot infer an appropriate lifetime for lifetime parameter `'lw`
pub fn main() { }
LL | pub(in Tr) struct Z;
| ^^ not a module
-error: visibilities can only be restricted to ancestor modules
+error[E0742]: visibilities can only be restricted to ancestor modules
--> $DIR/resolve-bad-visibility.rs:6:8
|
LL | pub(in std::vec) struct F;
error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0433`.
+Some errors have detailed explanations: E0433, E0577, E0742.
+For more information about an error, try `rustc --explain E0433`.
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0578`.
// compile-flags: --test
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![feature(test)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
#![allow(dead_code, unreachable_code)]
--- /dev/null
+// check-pass
+// compile-flags: -Zsave-analysis
+// edition:2018
+
+// Async desugaring for return types in (associated) functions introduces a
+// separate definition internally, which we need to take into account
+// (or else we ICE).
+trait Trait { type Assoc; }
+struct Struct;
+
+async fn foobar<T: Trait>() -> T::Assoc {
+ unimplemented!()
+}
+
+impl Struct {
+ async fn foo<T: Trait>(&self) -> T::Assoc {
+ unimplemented!()
+ }
+}
+
+fn main() {}
// run-pass
// ignore-emscripten
// min-llvm-version 7.0
-// error-pattern: panicked
// Test that the simd_f{min,max} intrinsics produce the correct results.
s
}
-fn november<'a>(s: &'a str) -> (&'a str) {
+fn november<'a>(s: &'a str) -> &'a str {
//~^ ERROR lifetime parameter `'b` never used
//~| HELP elide the unused lifetime
s
s
}
-fn november<'a, 'b>(s: &'a str) -> (&'a str) {
+fn november<'a, 'b>(s: &'a str) -> &'a str {
//~^ ERROR lifetime parameter `'b` never used
//~| HELP elide the unused lifetime
s
error: lifetime parameter `'b` never used
--> $DIR/zero-uses-in-fn.rs:18:17
|
-LL | fn november<'a, 'b>(s: &'a str) -> (&'a str) {
+LL | fn november<'a, 'b>(s: &'a str) -> &'a str {
| --^^
| |
| help: elide the unused lifetime
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0577`.
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: --test
#![feature(allow_fail)]
// run-pass
-// ignore-emscripten compiled with panic=abort by default
+// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: --test
#[test]
#[should_panic(expected = "foo")]
| ^^^^^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type Y = ();
+ | --
warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
--> $DIR/trivial-bounds-inconsistent.rs:22:19
--- /dev/null
+#![feature(try_trait)]
+// edition:2018
+fn main() {}
+
+fn a_function() -> u32 {
+ let x: Option<u32> = None;
+ x?; //~ ERROR the `?` operator
+ 22
+}
+
+fn a_closure() -> u32 {
+ let a_closure = || {
+ let x: Option<u32> = None;
+ x?; //~ ERROR the `?` operator
+ 22
+ };
+ a_closure()
+}
--- /dev/null
+error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/try-on-option-diagnostics.rs:7:5
+ |
+LL | x?;
+ | ^^ cannot use the `?` operator in a function that returns `u32`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `u32`
+ = note: required by `std::ops::Try::from_error`
+
+error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`)
+ --> $DIR/try-on-option-diagnostics.rs:14:9
+ |
+LL | x?;
+ | ^^ cannot use the `?` operator in a closure that returns `{integer}`
+ |
+ = help: the trait `std::ops::Try` is not implemented for `{integer}`
+ = note: required by `std::ops::Try::from_error`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
| ^^^^ ^^^^
|
= note: `#[warn(type_alias_bounds)]` on by default
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type SVec<T> = Vec<T>;
+ | -- --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:10:21
LL | type S2Vec<T> where T: Send = Vec<T>;
| ^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type S2Vec<T> = Vec<T>;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:12:19
LL | type VVec<'b, 'a: 'b + 'b> = (&'b u32, Vec<&'a i32>);
| ^^ ^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type VVec<'b, 'a> = (&'b u32, Vec<&'a i32>);
+ | -- --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:14:18
LL | type WVec<'b, T: 'b + 'b> = (&'b u32, Vec<T>);
| ^^ ^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type WVec<'b, T> = (&'b u32, Vec<T>);
+ | -- --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:16:25
LL | type W2Vec<'b, T> where T: 'b, T: 'b = (&'b u32, Vec<T>);
| ^^^^^ ^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type W2Vec<'b, T> = (&'b u32, Vec<T>);
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:47:12
LL | type T1<U: Bound> = U::Assoc;
| ^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
--> $DIR/type-alias-bounds.rs:47:21
|
LL | type T1<U: Bound> = U::Assoc;
| ^^^^^^^^
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type T1<U> = U::Assoc;
+ | --
warning: where clauses are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:48:18
LL | type T2<U> where U: Bound = U::Assoc;
| ^^^^^^^^
|
- = help: the clause will not be checked when the type alias is used, and should be removed
help: use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
--> $DIR/type-alias-bounds.rs:48:29
|
LL | type T2<U> where U: Bound = U::Assoc;
| ^^^^^^^^
+help: the clause will not be checked when the type alias is used, and should be removed
+ |
+LL | type T2<U> = U::Assoc;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:56:12
LL | type T5<U: Bound> = <U as Bound>::Assoc;
| ^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type T5<U> = <U as Bound>::Assoc;
+ | --
warning: bounds on generic parameters are not enforced in type aliases
--> $DIR/type-alias-bounds.rs:57:12
LL | type T6<U: Bound> = ::std::vec::Vec<U>;
| ^^^^^
|
- = help: the bound will not be checked when the type alias is used, and should be removed
+help: the bound will not be checked when the type alias is used, and should be removed
+ |
+LL | type T6<U> = ::std::vec::Vec<U>;
+ | --
macro_rules! foo{
($p:pat, $e:expr, $b:block) => {{
while let $p = $e $b
+ //~^ WARN irrefutable while-let
+ //~| WARN irrefutable while-let
}}
}
macro_rules! bar{
}}
}
- foo!(_a, 1, { //~ WARN irrefutable while-let
+ foo!(_a, 1, {
println!("irrefutable pattern");
});
- bar!(_a, 1, { //~ WARN irrefutable while-let
+ bar!(_a, 1, {
println!("irrefutable pattern");
});
}
| |_______- in this macro invocation
warning: irrefutable while-let pattern
- --> $DIR/while-let.rs:25:5
+ --> $DIR/while-let.rs:27:5
|
LL | / while let _a = 1 {
LL | | println!("irrefutable pattern");
"mips-unknown-linux-gnu",
"mips-unknown-linux-musl",
"mips64-unknown-linux-gnuabi64",
+ "mips64-unknown-linux-muslabi64",
"mips64el-unknown-linux-gnuabi64",
+ "mips64el-unknown-linux-muslabi64",
"mipsisa32r6-unknown-linux-gnu",
"mipsisa32r6el-unknown-linux-gnu",
"mipsisa64r6-unknown-linux-gnuabi64",
-Subproject commit 3ba5f27170db10af7a92f2b682e049397197b8fa
+Subproject commit 5da4b4d47963868d9878480197581ccbbdaece74
-Subproject commit 66df92aeba64547f3e9600635a30df34b12a11d8
+Subproject commit c8e3cfbdd997839c771ca32c7ac860fe95149a04
if config.target == "wasm32-unknown-unknown" && config.parse_check_run_results(ln) {
props.ignore = Ignore::Ignore;
}
- // FIXME: Re-enable run-fail once panics are handled correctly
- if config.target.contains("emscripten") && config.mode == common::RunFail {
- props.ignore = Ignore::Ignore;
- }
}
if (config.mode == common::DebugInfoGdb || config.mode == common::DebugInfoGdbLldb) &&
self.fatal_proc_rec("test run succeeded!", &proc_res);
}
}
+ if !self.props.error_patterns.is_empty() {
+ // "// error-pattern" comments
+ self.check_error_patterns(&proc_res.stderr, &proc_res);
+ }
}
debug!("run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \
explicit, self.config.compare_mode, expected_errors, proc_res.status,
self.props.error_patterns);
if !explicit && self.config.compare_mode.is_none() {
- if !proc_res.status.success() {
- if !self.props.error_patterns.is_empty() {
- // "// error-pattern" comments
- self.check_error_patterns(&proc_res.stderr, &proc_res);
- } else {
- // "//~ERROR comments"
- self.check_expected_errors(expected_errors, &proc_res);
- }
+ if !self.should_run() && !self.props.error_patterns.is_empty() {
+ // "// error-pattern" comments
+ self.check_error_patterns(&proc_res.stderr, &proc_res);
+ }
+ if !expected_errors.is_empty() {
+ // "//~ERROR comments"
+ self.check_expected_errors(expected_errors, &proc_res);
}
}
-Subproject commit d9ae0285169e52050416fb3618f05b5fdf582b6b
+Subproject commit d4e4fe71e6a9568f5d081d99f1c621c5a4ddd7db
-Subproject commit a18df16181947edd5eb593ea0f2321e0035448ee
+Subproject commit 5db91c7b94ca81eead6b25bcf6196b869a44ece0
failure = "0.1"
mdbook-linkcheck = { version = "0.3.0", optional = true }
+# A noop dependency that changes in the Rust repository, it's a bit of a hack.
+# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
+# for more information.
+rustc-workspace-hack = "1.0.0"
+
[dependencies.mdbook]
version = "0.3.0"
default-features = false
serde_json = { version = "1.0.31", features = ["raw_value"] }
smallvec = { version = "0.6", features = ['union', 'may_dangle'] }
url = { version = "2.0", features = ['serde'] }
-
+syn = { version = "0.15", features = ['full'] }
[target.'cfg(not(windows))'.dependencies]
openssl = { version = "0.10.12", optional = true }
"E0514",
"E0519",
"E0523",
- "E0526",
"E0554",
"E0570",
"E0629",