# Ensure the `aws` CLI is installed so we can deploy later on, cache docker
# images, etc.
-- bash: |
- set -e
- # Temporary code to debug #62967.
- debug_failed_connections() {
- echo "trying to ping pypi.org"
- ping pypi.org -c10 || true
- echo "trying to ping google.com"
- ping google.com -c10 || true
- echo "trying to ping 8.8.8.8"
- ping 8.8.8.8 -c10 || true
- echo "trying to download pypi.org"
- curl https://pypi.org || true
- echo "trying to download from our S3 bucket"
- curl https://rust-lang-ci2.s3.amazonaws.com || true
- echo "trying to dig pypi.org"
- dig pypi.org || true
- echo "trying to dig files.pythonhosted.org"
- dig files.pythonhosted.org || true
- echo "trying to connect to pypi.org with openssl"
- echo | openssl s_client -connect pypi.org:443 || true
- echo "trying to connect to files.pythonhosted.org with openssl"
- echo | openssl s_client -connect files.pythonhosted.org:443 || true
- }
- debug_failed_connections_and_fail() {
- debug_failed_connections
- return 1
- }
- source src/ci/shared.sh
- sudo apt-get install -y python3-setuptools
- debug_failed_connections
- retry pip3 install -r src/ci/awscli-requirements.txt --upgrade --user || debug_failed_connections_and_fail
- echo "##vso[task.prependpath]$HOME/.local/bin"
- displayName: Install awscli (Linux)
- condition: and(succeeded(), not(variables.SKIP_JOB), eq(variables['Agent.OS'], 'Linux'))
-- script: pip install -r src/ci/awscli-requirements.txt
- displayName: Install awscli (non-Linux)
- condition: and(succeeded(), not(variables.SKIP_JOB), ne(variables['Agent.OS'], 'Linux'))
+- bash: src/ci/install-awscli.sh
+ env:
+ AGENT_OS: $(Agent.OS)
+ condition: and(succeeded(), not(variables.SKIP_JOB))
+ displayName: Install awscli
# Configure our CI_JOB_NAME variable which log analyzers can use for the main
# step to see what's going on.
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-epoch"
-version = "0.7.0"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "memoffset"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "mime"
version = "0.3.13"
[[package]]
name = "minifier"
-version = "0.0.30"
+version = "0.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rustc_driver"
version = "0.0.0"
dependencies = [
- "arena 0.0.0",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
- "rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_ast_borrowck 0.0.0",
"rustc_codegen_utils 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
- "rustc_incremental 0.0.0",
"rustc_interface 0.0.0",
- "rustc_lint 0.0.0",
"rustc_metadata 0.0.0",
"rustc_mir 0.0.0",
- "rustc_passes 0.0.0",
- "rustc_plugin 0.0.0",
- "rustc_privacy 0.0.0",
- "rustc_resolve 0.0.0",
"rustc_save_analysis 0.0.0",
"rustc_target 0.0.0",
- "rustc_traits 0.0.0",
- "rustc_typeck 0.0.0",
"serialize 0.0.0",
- "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntax 0.0.0",
- "syntax_ext 0.0.0",
"syntax_pos 0.0.0",
]
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
- "rustc_mir 0.0.0",
"syntax 0.0.0",
- "syntax_ext 0.0.0",
"syntax_pos 0.0.0",
]
name = "rustdoc"
version = "0.0.0"
dependencies = [
- "minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "minifier 0.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "scopeguard"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "security-framework"
version = "0.3.1"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
-"checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c"
+"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
"checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425"
"checksum mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30de2e4613efcba1ec63d8133f344076952090c122992a903359be5a4f99c3ed"
-"checksum minifier 0.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "4c909e78edf61f3aa0dd2086da168cdf304329044bbf248768ca3d20253ec8c0"
+"checksum minifier 0.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "70bf0db2475f5e627787da77ca52fe33c294063f49f4134b8bc662eedb5e7332"
"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e"
"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
//! parent directory, and otherwise documentation can be found throughout the `build`
//! directory in each respective module.
-#![deny(warnings)]
+// NO-RUSTC-WRAPPER
+#![deny(warnings, rust_2018_idioms, unused_lifetimes)]
use std::env;
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.
-#![deny(warnings)]
+// NO-RUSTC-WRAPPER
+#![deny(warnings, rust_2018_idioms, unused_lifetimes)]
use std::env;
use std::ffi::OsString;
if env::var_os("RUSTC_DENY_WARNINGS").is_some() &&
env::var_os("RUSTC_EXTERNAL_TOOL").is_none() {
+ // When extending this list, search for `NO-RUSTC-WRAPPER` and add the new lints
+ // there as well, some code doesn't go through this `rustc` wrapper.
cmd.arg("-Dwarnings");
cmd.arg("-Drust_2018_idioms");
+ cmd.arg("-Dunused_lifetimes");
// cfg(not(bootstrap)): Remove this during the next stage 0 compiler update.
// `-Drustc::internal` is a new feature and `rustc_version` mis-reports the `stage`.
let cfg_not_bootstrap = stage != "0" && crate_name != Some("rustc_version");
//!
//! See comments in `src/bootstrap/rustc.rs` for more information.
-#![deny(warnings)]
+// NO-RUSTC-WRAPPER
+#![deny(warnings, rust_2018_idioms, unused_lifetimes)]
use std::env;
use std::process::Command;
//! More documentation can be found in each respective module below, and you can
//! also check out the `src/bootstrap/README.md` file for more information.
-#![deny(rust_2018_idioms)]
-#![deny(warnings)]
+// NO-RUSTC-WRAPPER
+#![deny(warnings, rust_2018_idioms, unused_lifetimes)]
+
#![feature(core_intrinsics)]
#![feature(drain_filter)]
fn chmod(_path: &Path, _perms: u32) {}
-impl<'a> Compiler {
+impl Compiler {
pub fn with_stage(mut self, stage: u32) -> Compiler {
self.stage = stage;
self
-#![deny(rust_2018_idioms)]
+// NO-RUSTC-WRAPPER
+#![deny(warnings, rust_2018_idioms, unused_lifetimes)]
use std::fs::File;
use std::path::{Path, PathBuf};
+++ /dev/null
-awscli==1.16.201
-botocore==1.12.191
-colorama==0.3.9
-docutils==0.14
-jmespath==0.9.4
-pyasn1==0.4.5
-python-dateutil==2.8.0
-PyYAML==5.1
-rsa==3.4.2
-s3transfer==0.2.1
-six==1.12.0
-urllib3==1.25.3
-futures==3.3.0; python_version < '3.0'
ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
-
-# FIXME(#36150) this will fail the bootstrap. Probably means something bad is
-# happening!
-ENV NO_LLVM_ASSERTIONS 1
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+## This script has two purposes: detect any tool that *regressed*, which is used
+## during the week before the beta branches to reject PRs; and detect any tool
+## that *changed* to see if we need to update the toolstate repo.
+
import sys
import json
+# Regressions for these tools during the beta cutoff week do not cause failure.
+# See `status_check` in `checktools.sh` for tools that have to pass on the
+# beta/stable branches.
+REGRESSION_OK = ["rustc-guide", "miri", "embedded-book"]
+
if __name__ == '__main__':
os_name = sys.argv[1]
toolstate_file = sys.argv[2]
'The state of "{}" has {} from "{}" to "{}"'
.format(tool, verb, state, new_state)
)
- regressed = True
+ if not (verb == 'regressed' and tool in REGRESSION_OK):
+ regressed = True
if regressed:
sys.exit(1)
src/doc/rust-by-example \
src/doc/embedded-book \
src/doc/edition-guide \
+ src/doc/rustc-guide \
src/tools/clippy \
src/tools/rls \
src/tools/rustfmt \
}
# This function checks that if a tool's submodule changed, the tool's state must improve
-verify_status() {
+verify_submodule_changed() {
echo "Verifying status of $1..."
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
echo "This PR updated '$2', verifying if status is 'test-pass'..."
check_dispatch() {
if [ "$1" = submodule_changed ]; then
# ignore $2 (branch id)
- verify_status $3 $4
+ verify_submodule_changed $3 $4
elif [ "$2" = beta ]; then
echo "Requiring test passing for $3..."
if check_tool_failed "$3"; then
fi
}
-# list all tools here
+# List all tools here.
+# This function gets called with "submodule_changed" for each PR that changed a submodule,
+# and with "beta_required" for each PR that lands on beta/stable.
+# The purpose of this function is to *reject* PRs if a tool is not "test-pass" and
+# (a) the tool's submodule has been updated, or (b) we landed on beta/stable and the
+# tool has to "test-pass" on that branch.
status_check() {
check_dispatch $1 beta book src/doc/book
check_dispatch $1 beta nomicon src/doc/nomicon
check_dispatch $1 beta rls src/tools/rls
check_dispatch $1 beta rustfmt src/tools/rustfmt
check_dispatch $1 beta clippy-driver src/tools/clippy
- # these tools are not required for beta to successfully branch
+ # These tools are not required on the beta/stable branches, but they *do* cause
+ # PRs to fail if a submodule update does not fix them.
+ # They will still cause failure during the beta cutoff week, unless `checkregression.py`
+ # exempts them from that.
check_dispatch $1 nightly miri src/tools/miri
check_dispatch $1 nightly embedded-book src/doc/embedded-book
check_dispatch $1 nightly rustc-guide src/doc/rustc-guide
status_check "submodule_changed"
CHECK_NOT="$(readlink -f "$(dirname $0)/checkregression.py")"
+# This callback is called by `commit_toolstate_change`, see `repo.sh`.
change_toolstate() {
# only update the history
if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then
echo 'Toolstate is not changed. Not updating.'
else
if [ $SIX_WEEK_CYCLE -ge 35 ]; then
+ # Reject any regressions during the week before beta cutoff.
python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed
fi
sed -i "1 a\\
MESSAGE_FILE="$1"
shift
for RETRY_COUNT in 1 2 3 4 5; do
+ # Call the callback.
+ # - If we are in the `auto` branch (pre-landing), this is called from `checktools.sh` and
+ # the callback is `change_toolstate` in that file. The purpose of this is to publish the
+ # test results (the new commit-to-toolstate mapping) in the toolstate repo.
+ # - If we are in the `master` branch (post-landing), this is called by the CI pipeline
+ # and the callback is `src/tools/publish_toolstate.py`. The purpose is to publish
+ # the new "current" toolstate in the toolstate repo.
"$@"
# `git commit` failing means nothing to commit.
FAILURE=0
--- /dev/null
+#!/bin/bash
+# This script downloads and installs awscli from the packages mirrored in our
+# own S3 bucket. This follows the recommendations at:
+#
+# https://packaging.python.org/guides/index-mirrors-and-caches/#caching-with-pip
+#
+# To create a new mirrored copy you can run the command:
+#
+# pip wheel awscli
+#
+# Before compressing please make sure all the wheels end with `-none-any.whl`.
+# If that's not the case you'll need to remove the non-cross-platform ones and
+# replace them with the .tar.gz downloaded from https://pypi.org. Also make
+# sure it's possible to call this script with both Python 2 and Python 3.
+
+set -euo pipefail
+IFS=$'\n\t'
+
+MIRROR="https://rust-lang-ci2.s3.amazonaws.com/rust-ci-mirror/2019-07-27-awscli.tar"
+DEPS_DIR="/tmp/awscli-deps"
+
+pip="pip"
+pipflags=""
+if [[ "${AGENT_OS}" == "Linux" ]]; then
+ pip="pip3"
+ pipflags="--user"
+
+ sudo apt-get install -y python3-setuptools
+ echo "##vso[task.prependpath]$HOME/.local/bin"
+fi
+
+mkdir -p "${DEPS_DIR}"
+curl "${MIRROR}" | tar xf - -C "${DEPS_DIR}"
+"${pip}" install ${pipflags} --no-index "--find-links=${DEPS_DIR}" awscli
+rm -rf "${DEPS_DIR}"
fn is_symmetric(list: &[u32]) -> bool {
match list {
&[] | &[_] => true,
- &[x, ref inside.., y] if x == y => is_symmetric(inside),
+ &[x, ref inside @ .., y] if x == y => is_symmetric(inside),
&[..] => false,
}
}
}
}
- if self.len() == 0 {
+ if self.is_empty() {
// Ideally we'd call `BTreeMap::new` here, but that has the `K:
// Ord` constraint, which this method lacks.
BTreeMap {
#[stable(feature = "btree_append", since = "1.11.0")]
pub fn append(&mut self, other: &mut Self) {
// Do we have to append anything at all?
- if other.len() == 0 {
+ if other.is_empty() {
return;
}
// We can just swap `self` and `other` if `self` is empty.
- if self.len() == 0 {
+ if self.is_empty() {
mem::swap(self, other);
return;
}
// Not creating new mutable (unique!) references overlapping `element`.
match node.prev {
- Some(prev) => (*prev.as_ptr()).next = node.next.clone(),
+ Some(prev) => (*prev.as_ptr()).next = node.next,
// this node is the head node
- None => self.head = node.next.clone(),
+ None => self.head = node.next,
};
match node.next {
- Some(next) => (*next.as_ptr()).prev = node.prev.clone(),
+ Some(next) => (*next.as_ptr()).prev = node.prev,
// this node is the tail node
- None => self.tail = node.prev.clone(),
+ None => self.tail = node.prev,
};
self.len -= 1;
#![stable(feature = "rust1", since = "1.0.0")]
+use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
use core::iter::{repeat_with, FromIterator, FusedIterator};
impl<A: Eq> Eq for VecDeque<A> {}
macro_rules! __impl_slice_eq1 {
- ($Lhs: ty, $Rhs: ty) => {
- __impl_slice_eq1! { $Lhs, $Rhs, Sized }
- };
- ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
+ ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => {
#[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")]
- impl<A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
- fn eq(&self, other: &$Rhs) -> bool {
+ impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
+ where
+ A: PartialEq<B>,
+ $($constraints)*
+ {
+ fn eq(&self, other: &$rhs) -> bool {
if self.len() != other.len() {
return false;
}
}
}
-__impl_slice_eq1! { VecDeque<A>, Vec<B> }
-__impl_slice_eq1! { VecDeque<A>, &[B] }
-__impl_slice_eq1! { VecDeque<A>, &mut [B] }
-
-macro_rules! array_impls {
- ($($N: expr)+) => {
- $(
- __impl_slice_eq1! { VecDeque<A>, [B; $N] }
- __impl_slice_eq1! { VecDeque<A>, &[B; $N] }
- __impl_slice_eq1! { VecDeque<A>, &mut [B; $N] }
- )+
- }
-}
-
-array_impls! {
- 0 1 2 3 4 5 6 7 8 9
- 10 11 12 13 14 15 16 17 18 19
- 20 21 22 23 24 25 26 27 28 29
- 30 31 32
-}
+__impl_slice_eq1! { [] VecDeque<A>, Vec<B>, }
+__impl_slice_eq1! { [] VecDeque<A>, &[B], }
+__impl_slice_eq1! { [] VecDeque<A>, &mut [B], }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, [B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, &[B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, &mut [B; N], [B; N]: LengthAtMost32 }
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PartialOrd> PartialOrd for VecDeque<A> {
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
-
-#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]
#![cfg_attr(not(test), feature(generator_trait))]
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![cfg_attr(not(bootstrap), feature(const_in_array_repeat_expressions))]
+#![feature(const_generic_impls_guard)]
+#![feature(const_generics)]
#![feature(dispatch_from_dyn)]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
let slice = from_raw_parts_mut(self.elems, self.n_elems);
ptr::drop_in_place(slice);
- Global.dealloc(self.mem, self.layout.clone());
+ Global.dealloc(self.mem, self.layout);
}
}
}
macro_rules! impl_eq {
($lhs:ty, $rhs: ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(unused_lifetimes)]
impl<'a, 'b> PartialEq<$rhs> for $lhs {
#[inline]
fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&self[..], &other[..]) }
}
#[stable(feature = "rust1", since = "1.0.0")]
+ #[allow(unused_lifetimes)]
impl<'a, 'b> PartialEq<$lhs> for $rhs {
#[inline]
fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&self[..], &other[..]) }
let slice = from_raw_parts_mut(self.elems, self.n_elems);
ptr::drop_in_place(slice);
- Global.dealloc(self.mem.cast(), self.layout.clone());
+ Global.dealloc(self.mem.cast(), self.layout);
}
}
}
#![feature(trusted_len)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
-#![deny(rust_2018_idioms)]
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
#![stable(feature = "rust1", since = "1.0.0")]
+use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
use core::hash::{self, Hash};
}
macro_rules! __impl_slice_eq1 {
- ($Lhs: ty, $Rhs: ty) => {
- __impl_slice_eq1! { $Lhs, $Rhs, Sized }
- };
- ($Lhs: ty, $Rhs: ty, $Bound: ident) => {
+ ([$($vars:tt)*] $lhs:ty, $rhs:ty, $($constraints:tt)*) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
+ impl<A, B, $($vars)*> PartialEq<$rhs> for $lhs
+ where
+ A: PartialEq<B>,
+ $($constraints)*
+ {
#[inline]
- fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] }
+ fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
#[inline]
- fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] }
+ fn ne(&self, other: &$rhs) -> bool { self[..] != other[..] }
}
}
}
-__impl_slice_eq1! { Vec<A>, Vec<B> }
-__impl_slice_eq1! { Vec<A>, &'b [B] }
-__impl_slice_eq1! { Vec<A>, &'b mut [B] }
-__impl_slice_eq1! { Cow<'a, [A]>, &'b [B], Clone }
-__impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B], Clone }
-__impl_slice_eq1! { Cow<'a, [A]>, Vec<B>, Clone }
+__impl_slice_eq1! { [] Vec<A>, Vec<B>, }
+__impl_slice_eq1! { [] Vec<A>, &[B], }
+__impl_slice_eq1! { [] Vec<A>, &mut [B], }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &[B], A: Clone }
+__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B], A: Clone }
+__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B>, A: Clone }
+__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], [B; N]: LengthAtMost32 }
-macro_rules! array_impls {
- ($($N: expr)+) => {
- $(
- // NOTE: some less important impls are omitted to reduce code bloat
- __impl_slice_eq1! { Vec<A>, [B; $N] }
- __impl_slice_eq1! { Vec<A>, &'b [B; $N] }
- // __impl_slice_eq1! { Vec<A>, &'b mut [B; $N] }
- // __impl_slice_eq1! { Cow<'a, [A]>, [B; $N], Clone }
- // __impl_slice_eq1! { Cow<'a, [A]>, &'b [B; $N], Clone }
- // __impl_slice_eq1! { Cow<'a, [A]>, &'b mut [B; $N], Clone }
- )+
- }
-}
-
-array_impls! {
- 0 1 2 3 4 5 6 7 8 9
- 10 11 12 13 14 15 16 17 18 19
- 20 21 22 23 24 25 26 27 28 29
- 30 31 32
-}
+// NOTE: some less important impls are omitted to reduce code bloat
+// FIXME(Centril): Reconsider this?
+//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], [B; N]: LengthAtMost32 }
/// Implements comparison of vectors, lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(no_crate_inject, attr(deny(warnings))))]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(raw_vec_internals)]
let old_size = layout.size();
if new_size >= old_size {
- if let Ok(()) = self.grow_in_place(ptr, layout.clone(), new_size) {
+ if let Ok(()) = self.grow_in_place(ptr, layout, new_size) {
return Ok(ptr);
}
} else if new_size < old_size {
- if let Ok(()) = self.shrink_in_place(ptr, layout.clone(), new_size) {
+ if let Ok(()) = self.shrink_in_place(ptr, layout, new_size) {
return Ok(ptr);
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<[B; N]> for [A; N]
+impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<[B]> for [A; N]
+impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for [B]
+impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
where
B: PartialEq<A>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N]
+impl<'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B]
+impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B]
where
B: PartialEq<A>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N]
+impl<'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N]
where
A: PartialEq<B>,
[A; N]: LengthAtMost32,
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, 'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B]
+impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B]
where
B: PartialEq<A>,
[A; N]: LengthAtMost32,
#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
where F: FnMut(&I::Item) {}
+
+/// An iterator adapter that produces output as long as the underlying
+/// iterator produces `Option::Some` values.
+pub(crate) struct OptionShunt<I> {
+ iter: I,
+ exited_early: bool,
+}
+
+impl<I, T> OptionShunt<I>
+where
+ I: Iterator<Item = Option<T>>,
+{
+ /// Process the given iterator as if it yielded a `T` instead of a
+ /// `Option<T>`. Any `None` value will stop the inner iterator and
+ /// the overall result will be a `None`.
+ pub fn process<F, U>(iter: I, mut f: F) -> Option<U>
+ where
+ F: FnMut(&mut Self) -> U,
+ {
+ let mut shunt = OptionShunt::new(iter);
+ let value = f(shunt.by_ref());
+ shunt.reconstruct(value)
+ }
+
+ fn new(iter: I) -> Self {
+ OptionShunt {
+ iter,
+ exited_early: false,
+ }
+ }
+
+ /// Consume the adapter and rebuild a `Option` value.
+ fn reconstruct<U>(self, val: U) -> Option<U> {
+ if self.exited_early {
+ None
+ } else {
+ Some(val)
+ }
+ }
+}
+
+impl<I, T> Iterator for OptionShunt<I>
+where
+ I: Iterator<Item = Option<T>>,
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.iter.next() {
+ Some(Some(v)) => Some(v),
+ Some(None) => {
+ self.exited_early = true;
+ None
+ }
+ None => None,
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.exited_early {
+ (0, Some(0))
+ } else {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+ }
+}
+
+/// An iterator adapter that produces output as long as the underlying
+/// iterator produces `Result::Ok` values.
+///
+/// If an error is encountered, the iterator stops and the error is
+/// stored. The error may be recovered later via `reconstruct`.
+pub(crate) struct ResultShunt<I, E> {
+ iter: I,
+ error: Option<E>,
+}
+
+impl<I, T, E> ResultShunt<I, E>
+ where I: Iterator<Item = Result<T, E>>
+{
+ /// Process the given iterator as if it yielded a `T` instead of a
+ /// `Result<T, _>`. Any errors will stop the inner iterator and
+ /// the overall result will be an error.
+ pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
+ where F: FnMut(&mut Self) -> U
+ {
+ let mut shunt = ResultShunt::new(iter);
+ let value = f(shunt.by_ref());
+ shunt.reconstruct(value)
+ }
+
+ fn new(iter: I) -> Self {
+ ResultShunt {
+ iter,
+ error: None,
+ }
+ }
+
+ /// Consume the adapter and rebuild a `Result` value. This should
+ /// *always* be called, otherwise any potential error would be
+ /// lost.
+ fn reconstruct<U>(self, val: U) -> Result<U, E> {
+ match self.error {
+ None => Ok(val),
+ Some(e) => Err(e),
+ }
+ }
+}
+
+impl<I, T, E> Iterator for ResultShunt<I, E>
+ where I: Iterator<Item = Result<T, E>>
+{
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.iter.next() {
+ Some(Ok(v)) => Some(v),
+ Some(Err(e)) => {
+ self.error = Some(e);
+ None
+ }
+ None => None,
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.error.is_some() {
+ (0, Some(0))
+ } else {
+ let (_, upper) = self.iter.size_hint();
+ (0, upper)
+ }
+ }
+}
#[stable(feature = "iter_copied", since = "1.36.0")]
pub use self::adapters::Copied;
-pub(crate) use self::adapters::TrustedRandomAccess;
+pub(crate) use self::adapters::{TrustedRandomAccess, OptionShunt, ResultShunt};
mod range;
mod sources;
use crate::ops::{Mul, Add};
use crate::num::Wrapping;
+use crate::iter::adapters::{OptionShunt, ResultShunt};
/// Trait to represent types that can be created by summing up an iterator.
///
integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
float_sum_product! { f32 f64 }
-/// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Result::Ok` values.
-///
-/// If an error is encountered, the iterator stops and the error is
-/// stored. The error may be recovered later via `reconstruct`.
-struct ResultShunt<I, E> {
- iter: I,
- error: Option<E>,
-}
-
-impl<I, T, E> ResultShunt<I, E>
- where I: Iterator<Item = Result<T, E>>
-{
- /// Process the given iterator as if it yielded a `T` instead of a
- /// `Result<T, _>`. Any errors will stop the inner iterator and
- /// the overall result will be an error.
- pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
- where F: FnMut(&mut Self) -> U
- {
- let mut shunt = ResultShunt::new(iter);
- let value = f(shunt.by_ref());
- shunt.reconstruct(value)
- }
-
- fn new(iter: I) -> Self {
- ResultShunt {
- iter,
- error: None,
- }
- }
-
- /// Consume the adapter and rebuild a `Result` value. This should
- /// *always* be called, otherwise any potential error would be
- /// lost.
- fn reconstruct<U>(self, val: U) -> Result<U, E> {
- match self.error {
- None => Ok(val),
- Some(e) => Err(e),
- }
- }
-}
-
-impl<I, T, E> Iterator for ResultShunt<I, E>
- where I: Iterator<Item = Result<T, E>>
-{
- type Item = T;
-
- fn next(&mut self) -> Option<Self::Item> {
- match self.iter.next() {
- Some(Ok(v)) => Some(v),
- Some(Err(e)) => {
- self.error = Some(e);
- None
- }
- None => None,
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.error.is_some() {
- (0, Some(0))
- } else {
- let (_, upper) = self.iter.size_hint();
- (0, upper)
- }
- }
-}
-
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
where T: Sum<U>,
}
}
-/// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Option::Some` values.
-struct OptionShunt<I> {
- iter: I,
- exited_early: bool,
-}
-
-impl<I, T> OptionShunt<I>
-where
- I: Iterator<Item = Option<T>>,
-{
- /// Process the given iterator as if it yielded a `T` instead of a
- /// `Option<T>`. Any `None` value will stop the inner iterator and
- /// the overall result will be a `None`.
- pub fn process<F, U>(iter: I, mut f: F) -> Option<U>
- where
- F: FnMut(&mut Self) -> U,
- {
- let mut shunt = OptionShunt::new(iter);
- let value = f(shunt.by_ref());
- shunt.reconstruct(value)
- }
-
- fn new(iter: I) -> Self {
- OptionShunt {
- iter,
- exited_early: false,
- }
- }
-
- /// Consume the adapter and rebuild a `Option` value.
- fn reconstruct<U>(self, val: U) -> Option<U> {
- if self.exited_early {
- None
- } else {
- Some(val)
- }
- }
-}
-
-impl<I, T> Iterator for OptionShunt<I>
-where
- I: Iterator<Item = Option<T>>,
-{
- type Item = T;
-
- fn next(&mut self) -> Option<Self::Item> {
- match self.iter.next() {
- Some(Some(v)) => Some(v),
- Some(None) => {
- self.exited_early = true;
- None
- }
- None => None,
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.exited_early {
- (0, Some(0))
- } else {
- let (_, upper) = self.iter.size_hint();
- (0, upper)
- }
- }
-}
-
#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
impl<T, U> Sum<Option<U>> for Option<T>
where
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
-
-#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]
#![feature(allow_internal_unstable)]
/// This function runs the destructor of the contained value and thus the wrapped value
/// now represents uninitialized data. It is up to the user of this method to ensure the
/// uninitialized data is not actually used.
+ /// In particular, this function can only be called called at most once
+ /// for a given instance of `ManuallyDrop<T>`.
///
/// [`ManuallyDrop::into_inner`]: #method.into_inner
#[stable(feature = "manually_drop", since = "1.20.0")]
#![stable(feature = "rust1", since = "1.0.0")]
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{FromIterator, FusedIterator, TrustedLen, OptionShunt};
use crate::{convert, fmt, hint, mem, ops::{self, Deref, DerefMut}};
use crate::pin::Pin;
// FIXME(#11084): This could be replaced with Iterator::scan when this
// performance bug is closed.
- struct Adapter<Iter> {
- iter: Iter,
- found_none: bool,
- }
-
- impl<T, Iter: Iterator<Item=Option<T>>> Iterator for Adapter<Iter> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- match self.iter.next() {
- Some(Some(value)) => Some(value),
- Some(None) => {
- self.found_none = true;
- None
- }
- None => None,
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.found_none {
- (0, Some(0))
- } else {
- let (_, upper) = self.iter.size_hint();
- (0, upper)
- }
- }
- }
-
- let mut adapter = Adapter { iter: iter.into_iter(), found_none: false };
- let v: V = FromIterator::from_iter(adapter.by_ref());
-
- if adapter.found_none {
- None
- } else {
- Some(v)
- }
+ OptionShunt::process(iter.into_iter(), |i| i.collect())
}
}
{}
#[stable(feature = "pin", since = "1.33.0")]
-impl<'a, P, U> DispatchFromDyn<Pin<U>> for Pin<P>
+impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P>
where
P: DispatchFromDyn<U>,
{}
}
#[unstable(feature = "ptr_internals", issue = "0")]
-impl<'a, T: ?Sized> From<NonNull<T>> for Unique<T> {
+impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
#[inline]
fn from(p: NonNull<T>) -> Self {
unsafe { Unique::new_unchecked(p.as_ptr()) }
#![stable(feature = "rust1", since = "1.0.0")]
use crate::fmt;
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{FromIterator, FusedIterator, TrustedLen, ResultShunt};
use crate::ops::{self, Deref, DerefMut};
/// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]).
// FIXME(#11084): This could be replaced with Iterator::scan when this
// performance bug is closed.
- struct Adapter<Iter, E> {
- iter: Iter,
- err: Option<E>,
- }
-
- impl<T, E, Iter: Iterator<Item=Result<T, E>>> Iterator for Adapter<Iter, E> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- match self.iter.next() {
- Some(Ok(value)) => Some(value),
- Some(Err(err)) => {
- self.err = Some(err);
- None
- }
- None => None,
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (_min, max) = self.iter.size_hint();
- (0, max)
- }
- }
-
- let mut adapter = Adapter { iter: iter.into_iter(), err: None };
- let v: V = FromIterator::from_iter(adapter.by_ref());
-
- match adapter.err {
- Some(err) => Err(err),
- None => Ok(v),
- }
+ ResultShunt::process(iter.into_iter(), |i| i.collect())
}
}
Some(tail)
}
}
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = match start.checked_add(self.chunk_size) {
+ Some(res) => cmp::min(res, self.v.len()),
+ None => self.v.len(),
+ };
+ let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (head, nth_back) = temp.split_at_mut(start);
+ self.v = head;
+ Some(nth_back)
+ }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
type Item = Utf8LossyChunk<'a>;
fn next(&mut self) -> Option<Utf8LossyChunk<'a>> {
- if self.source.len() == 0 {
+ if self.source.is_empty() {
return None;
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// If we're the empty string then our iterator won't actually yield
// anything, so perform the formatting manually
- if self.bytes.len() == 0 {
+ if self.bytes.is_empty() {
return "".fmt(f)
}
#![feature(const_fn)]
#![feature(iter_partition_in_place)]
#![feature(iter_is_partitioned)]
-#![warn(rust_2018_idioms)]
extern crate test;
assert_eq!(c2.next(), None);
}
+#[test]
+fn test_chunks_mut_nth_back() {
+ let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
+ let mut c = v.chunks_mut(2);
+ assert_eq!(c.nth_back(1).unwrap(), &[2, 3]);
+ assert_eq!(c.next().unwrap(), &[0, 1]);
+
+ let v1: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c1 = v1.chunks_mut(3);
+ assert_eq!(c1.nth_back(1).unwrap(), &[0, 1, 2]);
+ assert_eq!(c1.next(), None);
+
+ let v3: &mut [i32] = &mut [0, 1, 2, 3, 4];
+ let mut c3 = v3.chunks_mut(10);
+ assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]);
+ assert_eq!(c3.next(), None);
+
+ let v4: &mut [i32] = &mut [0, 1, 2];
+ let mut c4 = v4.chunks_mut(10);
+ assert_eq!(c4.nth_back(1_000_000_000usize), None);
+}
+
#[test]
fn test_chunks_mut_last() {
let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
html_playground_url = "https://play.rust-lang.org/",
test(attr(deny(warnings))))]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(nll)]
#![feature(rustc_private)]
#![feature(unicode_internals)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(allow(unused_variables), deny(warnings))))]
-#![deny(rust_2018_idioms)]
-
#![feature(nll)]
use LabelText::*;
#![panic_runtime]
#![allow(unused_features)]
-#![deny(rust_2018_idioms)]
#![feature(core_intrinsics)]
#![feature(libc)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
-#![deny(rust_2018_idioms)]
-
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(libc)]
use std::ops::{Deref, DerefMut};
/// Type lambda application, with a lifetime.
+#[allow(unused_lifetimes)]
pub trait ApplyL<'a> {
type Out;
}
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
-#![deny(rust_2018_idioms)]
-
#![feature(nll)]
#![feature(staged_api)]
#![feature(const_fn)]
#![allow(unused_features)]
#![feature(nll)]
#![feature(staged_api)]
-#![deny(rust_2018_idioms)]
-#![allow(non_snake_case)]
-
// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
}
}
+ fn visit_arg(&mut self, arg: &'v Arg) {
+ walk_arg(self, arg)
+ }
+
/// Visits the top-level item and (optionally) nested items / impl items. See
/// `visit_nested_item` for details.
fn visit_item(&mut self, i: &'v Item) {
}
pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
- for argument in &body.arguments {
- visitor.visit_id(argument.hir_id);
- visitor.visit_pat(&argument.pat);
- }
+ walk_list!(visitor, visit_arg, &body.arguments);
visitor.visit_expr(&body.value);
}
visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
}
+pub fn walk_arg<'v, V: Visitor<'v>>(visitor: &mut V, arg: &'v Arg) {
+ visitor.visit_id(arg.hir_id);
+ visitor.visit_pat(&arg.pat);
+ walk_list!(visitor, visit_attribute, &arg.attrs);
+}
+
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_vis(&item.vis);
visitor.visit_ident(item.ident);
use smallvec::SmallVec;
use syntax::attr;
use syntax::ast;
+use syntax::ptr::P as AstP;
use syntax::ast::*;
use syntax::errors;
use syntax::ext::hygiene::ExpnId;
use syntax::print::pprust;
use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned};
-use syntax::std_inject;
use syntax::symbol::{kw, sym, Symbol};
use syntax::tokenstream::{TokenStream, TokenTree};
use syntax::parse::token::{self, Token};
dep_graph.assert_ignored();
LoweringContext {
- crate_root: std_inject::injected_crate_name().map(Symbol::intern),
+ crate_root: sess.parse_sess.injected_crate_name.try_get().copied(),
sess,
cstore,
resolver,
fn visit_pat(&mut self, p: &'tcx Pat) {
match p.node {
// Doesn't generate a HIR node
- PatKind::Paren(..) => {},
+ PatKind::Paren(..) | PatKind::Rest => {},
_ => {
if let Some(owner) = self.hir_id_owner {
self.lctx.lower_node_id_with_owner(p.id, owner);
&mut self,
capture_clause: CaptureBy,
closure_node_id: NodeId,
- ret_ty: Option<syntax::ptr::P<Ty>>,
+ ret_ty: Option<AstP<Ty>>,
span: Span,
body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr,
) -> hir::ExprKind {
fn lower_arg(&mut self, arg: &Arg) -> hir::Arg {
hir::Arg {
+ attrs: self.lower_attrs(&arg.attrs),
hir_id: self.lower_node_id(arg.id),
pat: self.lower_pat(&arg.pat),
+ span: arg.span,
}
}
//
// If this is the simple case, this argument will end up being the same as the
// original argument, but with a different pattern id.
+ let mut stmt_attrs = ThinVec::new();
+ stmt_attrs.extend(argument.attrs.iter().cloned());
let (new_argument_pat, new_argument_id) = this.pat_ident(desugared_span, ident);
let new_argument = hir::Arg {
+ attrs: argument.attrs,
hir_id: argument.hir_id,
pat: new_argument_pat,
+ span: argument.span,
};
+
if is_simple_argument {
// If this is the simple case, then we only insert one statement that is
// `let <pat> = <pat>;`. We re-use the original argument's pattern so that
// `HirId`s are densely assigned.
let expr = this.expr_ident(desugared_span, ident, new_argument_id);
let stmt = this.stmt_let_pat(
- desugared_span, Some(P(expr)), argument.pat, hir::LocalSource::AsyncFn);
+ stmt_attrs,
+ desugared_span,
+ Some(P(expr)),
+ argument.pat,
+ hir::LocalSource::AsyncFn
+ );
statements.push(stmt);
} else {
// If this is not the simple case, then we construct two statements:
desugared_span, ident, hir::BindingAnnotation::Mutable);
let move_expr = this.expr_ident(desugared_span, ident, new_argument_id);
let move_stmt = this.stmt_let_pat(
- desugared_span, Some(P(move_expr)), move_pat, hir::LocalSource::AsyncFn);
+ ThinVec::new(),
+ desugared_span,
+ Some(P(move_expr)),
+ move_pat,
+ hir::LocalSource::AsyncFn
+ );
// Construct the `let <pat> = __argN;` statement. We re-use the original
// argument's pattern so that `HirId`s are densely assigned.
let pattern_expr = this.expr_ident(desugared_span, ident, move_id);
let pattern_stmt = this.stmt_let_pat(
- desugared_span, Some(P(pattern_expr)), argument.pat,
- hir::LocalSource::AsyncFn);
+ stmt_attrs,
+ desugared_span,
+ Some(P(pattern_expr)),
+ argument.pat,
+ hir::LocalSource::AsyncFn
+ );
statements.push(move_stmt);
statements.push(pattern_stmt);
let node = match p.node {
PatKind::Wild => hir::PatKind::Wild,
PatKind::Ident(ref binding_mode, ident, ref sub) => {
- match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
- // `None` can occur in body-less function signatures
- res @ None | res @ Some(Res::Local(_)) => {
- let canonical_id = match res {
- Some(Res::Local(id)) => id,
- _ => p.id,
- };
-
- hir::PatKind::Binding(
- self.lower_binding_mode(binding_mode),
- self.lower_node_id(canonical_id),
- ident,
- sub.as_ref().map(|x| self.lower_pat(x)),
- )
- }
- Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
- None,
- P(hir::Path {
- span: ident.span,
- res: self.lower_res(res),
- segments: hir_vec![hir::PathSegment::from_ident(ident)],
- }),
- )),
- }
+ let lower_sub = |this: &mut Self| sub.as_ref().map(|x| this.lower_pat(x));
+ self.lower_pat_ident(p, binding_mode, ident, lower_sub)
}
PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
- PatKind::TupleStruct(ref path, ref pats, ddpos) => {
+ PatKind::TupleStruct(ref path, ref pats) => {
let qpath = self.lower_qpath(
p.id,
&None,
ParamMode::Optional,
ImplTraitContext::disallowed(),
);
- hir::PatKind::TupleStruct(
- qpath,
- pats.iter().map(|x| self.lower_pat(x)).collect(),
- ddpos,
- )
+ let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
+ hir::PatKind::TupleStruct(qpath, pats, ddpos)
}
PatKind::Path(ref qself, ref path) => {
let qpath = self.lower_qpath(
.collect();
hir::PatKind::Struct(qpath, fs, etc)
}
- PatKind::Tuple(ref elts, ddpos) => {
- hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
+ PatKind::Tuple(ref pats) => {
+ let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
+ hir::PatKind::Tuple(pats, ddpos)
}
PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
PatKind::Ref(ref inner, mutbl) => {
P(self.lower_expr(e2)),
self.lower_range_end(end),
),
- PatKind::Slice(ref before, ref slice, ref after) => hir::PatKind::Slice(
- before.iter().map(|x| self.lower_pat(x)).collect(),
- slice.as_ref().map(|x| self.lower_pat(x)),
- after.iter().map(|x| self.lower_pat(x)).collect(),
- ),
+ PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
+ PatKind::Rest => {
+ // If we reach here the `..` pattern is not semantically allowed.
+ self.ban_illegal_rest_pat(p.span)
+ }
PatKind::Paren(ref inner) => return self.lower_pat(inner),
PatKind::Mac(_) => panic!("Shouldn't exist here"),
};
+ self.pat_with_node_id_of(p, node)
+ }
+
+ fn lower_pat_tuple(
+ &mut self,
+ pats: &[AstP<Pat>],
+ ctx: &str,
+ ) -> (HirVec<P<hir::Pat>>, Option<usize>) {
+ let mut elems = Vec::with_capacity(pats.len());
+ let mut rest = None;
+
+ let mut iter = pats.iter().enumerate();
+ while let Some((idx, pat)) = iter.next() {
+ // Interpret the first `..` pattern as a subtuple pattern.
+ if pat.is_rest() {
+ rest = Some((idx, pat.span));
+ break;
+ }
+ // It was not a subslice pattern so lower it normally.
+ elems.push(self.lower_pat(pat));
+ }
+
+ while let Some((_, pat)) = iter.next() {
+ // There was a previous subtuple pattern; make sure we don't allow more.
+ if pat.is_rest() {
+ self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
+ } else {
+ elems.push(self.lower_pat(pat));
+ }
+ }
+
+ (elems.into(), rest.map(|(ddpos, _)| ddpos))
+ }
+
+ fn lower_pat_slice(&mut self, pats: &[AstP<Pat>]) -> hir::PatKind {
+ let mut before = Vec::new();
+ let mut after = Vec::new();
+ let mut slice = None;
+ let mut prev_rest_span = None;
+
+ let mut iter = pats.iter();
+ while let Some(pat) = iter.next() {
+ // Interpret the first `((ref mut?)? x @)? ..` pattern as a subslice pattern.
+ match pat.node {
+ PatKind::Rest => {
+ prev_rest_span = Some(pat.span);
+ slice = Some(self.pat_wild_with_node_id_of(pat));
+ break;
+ },
+ PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
+ prev_rest_span = Some(sub.span);
+ let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
+ let node = self.lower_pat_ident(pat, bm, ident, lower_sub);
+ slice = Some(self.pat_with_node_id_of(pat, node));
+ break;
+ },
+ _ => {}
+ }
+
+ // It was not a subslice pattern so lower it normally.
+ before.push(self.lower_pat(pat));
+ }
+
+ while let Some(pat) = iter.next() {
+ // There was a previous subslice pattern; make sure we don't allow more.
+ let rest_span = match pat.node {
+ PatKind::Rest => Some(pat.span),
+ PatKind::Ident(.., Some(ref sub)) if sub.is_rest() => {
+ // The `HirValidator` is merciless; add a `_` pattern to avoid ICEs.
+ after.push(self.pat_wild_with_node_id_of(pat));
+ Some(sub.span)
+ },
+ _ => None,
+ };
+ if let Some(rest_span) = rest_span {
+ self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
+ } else {
+ after.push(self.lower_pat(pat));
+ }
+ }
+
+ hir::PatKind::Slice(before.into(), slice, after.into())
+ }
+
+ fn lower_pat_ident(
+ &mut self,
+ p: &Pat,
+ binding_mode: &BindingMode,
+ ident: Ident,
+ lower_sub: impl FnOnce(&mut Self) -> Option<P<hir::Pat>>,
+ ) -> hir::PatKind {
+ match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
+ // `None` can occur in body-less function signatures
+ res @ None | res @ Some(Res::Local(_)) => {
+ let canonical_id = match res {
+ Some(Res::Local(id)) => id,
+ _ => p.id,
+ };
+
+ hir::PatKind::Binding(
+ self.lower_binding_mode(binding_mode),
+ self.lower_node_id(canonical_id),
+ ident,
+ lower_sub(self),
+ )
+ }
+ Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
+ None,
+ P(hir::Path {
+ span: ident.span,
+ res: self.lower_res(res),
+ segments: hir_vec![hir::PathSegment::from_ident(ident)],
+ }),
+ )),
+ }
+ }
+
+ fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> P<hir::Pat> {
+ self.pat_with_node_id_of(p, hir::PatKind::Wild)
+ }
+
+ /// Construct a `Pat` with the `HirId` of `p.id` lowered.
+ fn pat_with_node_id_of(&mut self, p: &Pat, node: hir::PatKind) -> P<hir::Pat> {
P(hir::Pat {
hir_id: self.lower_node_id(p.id),
node,
})
}
+ /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
+ fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
+ self.diagnostic()
+ .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
+ .span_label(sp, &format!("can only be used once per {} pattern", ctx))
+ .span_label(prev_sp, "previously used here")
+ .emit();
+ }
+
+ /// Used to ban the `..` pattern in places it shouldn't be semantically.
+ fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind {
+ self.diagnostic()
+ .struct_span_err(sp, "`..` patterns are not allowed here")
+ .note("only allowed in tuple, tuple struct, and slice patterns")
+ .emit();
+
+ // We're not in a list context so `..` can be reasonably treated
+ // as `_` because it should always be valid and roughly matches the
+ // intent of `..` (notice that the rest of a single slot is that slot).
+ hir::PatKind::Wild
+ }
+
fn lower_range_end(&mut self, e: &RangeEnd) -> hir::RangeEnd {
match *e {
RangeEnd::Included(_) => hir::RangeEnd::Included,
// `let mut __next`
let next_let = self.stmt_let_pat(
+ ThinVec::new(),
desugared_span,
None,
next_pat,
// `let <pat> = __next`
let pat = self.lower_pat(pat);
let pat_let = self.stmt_let_pat(
+ ThinVec::new(),
head_sp,
Some(next_expr),
pat,
fn stmt_let_pat(
&mut self,
+ attrs: ThinVec<Attribute>,
span: Span,
init: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
source: hir::LocalSource,
) -> hir::Stmt {
let local = hir::Local {
- pat,
- ty: None,
- init,
+ attrs,
hir_id: self.next_id(),
- span,
+ init,
+ pat,
source,
- attrs: ThinVec::new()
+ span,
+ ty: None,
};
self.stmt(span, hir::StmtKind::Local(P(local)))
}
hir::BindingAnnotation::Mutable,
);
let pinned_let = self.stmt_let_pat(
+ ThinVec::new(),
span,
Some(expr),
pinned_pat,
self.currently_in_body = prev_in_body;
}
+ fn visit_arg(&mut self, arg: &'hir Arg) {
+ let node = Node::Arg(arg);
+ self.insert(arg.pat.span, arg.hir_id, node);
+ self.with_parent(arg.hir_id, |this| {
+ intravisit::walk_arg(this, arg);
+ });
+ }
+
fn visit_item(&mut self, i: &'hir Item) {
debug!("visit_item: {:?}", i);
debug_assert_eq!(i.hir_id.owner,
Node::Pat(_) |
Node::Binding(_) |
Node::Local(_) |
+ Node::Arg(_) |
Node::Arm(_) |
Node::Lifetime(_) |
Node::Visibility(_) |
pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
self.read(id); // reveals attributes on the node
let attrs = match self.find_entry(id).map(|entry| entry.node) {
+ Some(Node::Arg(a)) => Some(&a.attrs[..]),
Some(Node::Local(l)) => Some(&l.attrs[..]),
Some(Node::Item(i)) => Some(&i.attrs[..]),
Some(Node::ForeignItem(fi)) => Some(&fi.attrs[..]),
pub fn span(&self, hir_id: HirId) -> Span {
self.read(hir_id); // reveals span from node
match self.find_entry(hir_id).map(|entry| entry.node) {
+ Some(Node::Arg(arg)) => arg.span,
Some(Node::Item(item)) => item.span,
Some(Node::ForeignItem(foreign_item)) => foreign_item.span,
Some(Node::TraitItem(trait_method)) => trait_method.span,
impl<'a> print::State<'a> {
pub fn print_node(&mut self, node: Node<'_>) {
match node {
+ Node::Arg(a) => self.print_arg(&a),
Node::Item(a) => self.print_item(&a),
Node::ForeignItem(a) => self.print_foreign_item(&a),
Node::TraitItem(a) => self.print_trait_item(a),
Some(Node::Pat(_)) => {
format!("pat {}{}", map.hir_to_pretty_string(id), id_str)
}
+ Some(Node::Arg(_)) => {
+ format!("arg {}{}", map.hir_to_pretty_string(id), id_str)
+ }
Some(Node::Arm(_)) => {
format!("arm {}{}", map.hir_to_pretty_string(id), id_str)
}
/// Represents an argument in a function header.
#[derive(RustcEncodable, RustcDecodable, Debug, HashStable)]
pub struct Arg {
- pub pat: P<Pat>,
+ pub attrs: HirVec<Attribute>,
pub hir_id: HirId,
+ pub pat: P<Pat>,
+ pub span: Span,
}
/// Represents the header (not the body) of a function declaration.
#[derive(Copy, Clone, Debug)]
pub enum Node<'hir> {
+ Arg(&'hir Arg),
Item(&'hir Item),
ForeignItem(&'hir ForeignItem),
TraitItem(&'hir TraitItem),
self.ann.post(self, AnnNode::Pat(pat))
}
+ pub fn print_arg(&mut self, arg: &hir::Arg) {
+ self.print_outer_attributes(&arg.attrs);
+ self.print_pat(&arg.pat);
+ }
+
pub fn print_arm(&mut self, arm: &hir::Arm) {
// I have no idea why this check is necessary, but here it
// is :(
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(box_syntax)]
// Use the test crate here so we depend on getopts through it. This allow tools to link to both
// librustc_driver and libtest.
-#[allow(unused_extern_crates)]
-extern crate test;
+extern crate test as _;
#[macro_use]
mod macros;
self.context.tables = old_tables;
}
+ fn visit_arg(&mut self, arg: &'tcx hir::Arg) {
+ self.with_lint_attrs(arg.hir_id, &arg.attrs, |cx| {
+ lint_callback!(cx, check_arg, arg);
+ hir_visit::walk_arg(cx, arg);
+ });
+ }
+
fn visit_body(&mut self, body: &'tcx hir::Body) {
lint_callback!(self, check_body, body);
hir_visit::walk_body(self, body);
}
impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> {
+ fn visit_arg(&mut self, arg: &'a ast::Arg) {
+ self.with_lint_attrs(arg.id, &arg.attrs, |cx| {
+ run_early_pass!(cx, check_arg, arg);
+ ast_visit::walk_arg(cx, arg);
+ });
+ }
+
fn visit_item(&mut self, it: &'a ast::Item) {
self.with_lint_attrs(it.id, &it.attrs, |cx| {
run_early_pass!(cx, check_item, it);
macro_rules! late_lint_methods {
($macro:path, $args:tt, [$hir:tt]) => (
$macro!($args, [$hir], [
+ fn check_arg(a: &$hir hir::Arg);
fn check_body(a: &$hir hir::Body);
fn check_body_post(a: &$hir hir::Body);
fn check_name(a: Span, b: ast::Name);
macro_rules! early_lint_methods {
($macro:path, $args:tt) => (
$macro!($args, [
+ fn check_arg(a: &ast::Arg);
fn check_ident(a: ast::Ident);
fn check_crate(a: &ast::Crate);
fn check_crate_post(a: &ast::Crate);
pub type LateLintPassObject = Box<dyn for<'a, 'tcx> LateLintPass<'a, 'tcx> + sync::Send
+ sync::Sync + 'static>;
-
-
/// Identifies a lint known to the compiler.
#[derive(Clone, Copy, Debug)]
pub struct LintId {
intravisit::NestedVisitorMap::All(&self.tcx.hir())
}
+ fn visit_arg(&mut self, arg: &'tcx hir::Arg) {
+ self.with_lint_attrs(arg.hir_id, &arg.attrs, |builder| {
+ intravisit::walk_arg(builder, arg);
+ });
+ }
+
fn visit_item(&mut self, it: &'tcx hir::Item) {
self.with_lint_attrs(it.hir_id, &it.attrs, |builder| {
intravisit::walk_item(builder, it);
// First (determined here), if `self` is by-reference, then the
// implied output region is the region of the self parameter.
if has_self {
- // Look for `self: &'a Self` - also desugared from `&'a self`,
- // and if that matches, use it for elision and return early.
- let is_self_ty = |res: Res| {
- if let Res::SelfTy(..) = res {
- return true;
- }
-
- // Can't always rely on literal (or implied) `Self` due
- // to the way elision rules were originally specified.
- let impl_self = impl_self.map(|ty| &ty.node);
- if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = impl_self {
- match path.res {
- // Whitelist the types that unambiguously always
- // result in the same type constructor being used
- // (it can't differ between `Self` and `self`).
- Res::Def(DefKind::Struct, _)
- | Res::Def(DefKind::Union, _)
- | Res::Def(DefKind::Enum, _)
- | Res::PrimTy(_) => {
- return res == path.res
+ struct SelfVisitor<'a> {
+ map: &'a NamedRegionMap,
+ impl_self: Option<&'a hir::TyKind>,
+ lifetime: Set1<Region>,
+ }
+
+ impl SelfVisitor<'_> {
+ // Look for `self: &'a Self` - also desugared from `&'a self`,
+ // and if that matches, use it for elision and return early.
+ fn is_self_ty(&self, res: Res) -> bool {
+ if let Res::SelfTy(..) = res {
+ return true;
+ }
+
+ // Can't always rely on literal (or implied) `Self` due
+ // to the way elision rules were originally specified.
+ if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) =
+ self.impl_self
+ {
+ match path.res {
+ // Whitelist the types that unambiguously always
+ // result in the same type constructor being used
+ // (it can't differ between `Self` and `self`).
+ Res::Def(DefKind::Struct, _)
+ | Res::Def(DefKind::Union, _)
+ | Res::Def(DefKind::Enum, _)
+ | Res::PrimTy(_) => {
+ return res == path.res
+ }
+ _ => {}
}
- _ => {}
}
+
+ false
}
+ }
- false
- };
+ impl<'a> Visitor<'a> for SelfVisitor<'a> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
+ NestedVisitorMap::None
+ }
- if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node {
- if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node {
- if is_self_ty(path.res) {
- if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
- let scope = Scope::Elision {
- elide: Elide::Exact(lifetime),
- s: self.scope,
- };
- self.with(scope, |_, this| this.visit_ty(output));
- return;
+ fn visit_ty(&mut self, ty: &'a hir::Ty) {
+ if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.node {
+ if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node
+ {
+ if self.is_self_ty(path.res) {
+ if let Some(lifetime) = self.map.defs.get(&lifetime_ref.hir_id) {
+ self.lifetime.insert(*lifetime);
+ }
+ }
}
}
+ intravisit::walk_ty(self, ty)
}
}
+
+ let mut visitor = SelfVisitor {
+ map: self.map,
+ impl_self: impl_self.map(|ty| &ty.node),
+ lifetime: Set1::Empty,
+ };
+ visitor.visit_ty(&inputs[0]);
+ if let Set1::One(lifetime) = visitor.lifetime {
+ let scope = Scope::Elision {
+ elide: Elide::Exact(lifetime),
+ s: self.scope,
+ };
+ self.with(scope, |_, this| this.visit_ty(output));
+ return;
+ }
}
// Second, if there was exactly one lifetime (either a substitution or a
// *unstable* options, i.e., options that are only enabled when the
// user also passes the `-Z unstable-options` debugging flag.
mod opt {
- // The `fn opt_u` etc below are written so that we can use them
+ // The `fn flag*` etc below are written so that we can use them
// in the future; do not warn about them not being used right now.
#![allow(dead_code)]
-#![allow(warnings)]
-
-use std::mem;
-use std::process;
-use std::{fmt, ptr};
+use crate::ty::context::TyCtxt;
+use crate::ty::query::plumbing::CycleError;
+use crate::ty::query::Query;
+use crate::ty::tls;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak};
-use rustc_data_structures::OnDrop;
-use rustc_data_structures::jobserver;
+use rustc_data_structures::sync::Lrc;
use syntax_pos::Span;
-use crate::ty::tls;
-use crate::ty::query::Query;
-use crate::ty::query::plumbing::CycleError;
#[cfg(not(parallel_compiler))]
-use crate::ty::query::{
- plumbing::TryGetJob,
- config::QueryDescription,
-};
-use crate::ty::context::TyCtxt;
+use std::ptr;
#[cfg(parallel_compiler)]
use {
- rustc_rayon_core as rayon_core,
parking_lot::{Mutex, Condvar},
- std::sync::atomic::Ordering,
- std::thread,
- std::iter,
- std::iter::FromIterator,
+ rustc_data_structures::{jobserver, OnDrop},
+ rustc_data_structures::fx::FxHashSet,
+ rustc_data_structures::stable_hasher::{StableHasher, HashStable},
+ rustc_data_structures::sync::Lock,
+ rustc_rayon_core as rayon_core,
syntax_pos::DUMMY_SP,
- rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable},
+ std::{mem, process, thread},
+ std::iter::FromIterator,
};
/// Indicates the state of a query for a given key in a query map.
span: Span,
) -> Result<(), CycleError<'tcx>> {
tls::with_related_context(tcx, move |icx| {
- let mut waiter = Lrc::new(QueryWaiter {
+ let waiter = Lrc::new(QueryWaiter {
query: icx.query.clone(),
span,
cycle: Lock::new(None),
self.latch.set();
}
+ #[cfg(parallel_compiler)]
fn as_ptr(&self) -> *const QueryJob<'tcx> {
self as *const _
}
let usage = usage.as_ref().map(|(span, query)| (*span, query.info.query.clone()));
// Create the cycle error
- let mut error = CycleError {
+ let error = CycleError {
usage,
cycle: stack.iter().map(|&(s, ref q)| QueryInfo {
span: s,
/// Must only be called when a deadlock is about to happen.
#[cfg(parallel_compiler)]
pub unsafe fn handle_deadlock() {
- use syntax;
- use syntax_pos;
-
let registry = rayon_core::Registry::current();
let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| {
});
let gcx_ptr = &*gcx_ptr;
- let syntax_globals = syntax::GLOBALS.with(|syntax_globals| {
- syntax_globals as *const _
- });
- let syntax_globals = &*syntax_globals;
-
let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| {
syntax_pos_globals as *const _
});
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![forbid(unsafe_code)]
-#![deny(rust_2018_idioms)]
#![feature(nll)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-#![deny(rust_2018_idioms)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![allow(non_camel_case_types)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
}
debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
+ let rustc_producer = format!(
+ "rustc version {}",
+ option_env!("CFG_VERSION").expect("CFG_VERSION"),
+ );
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
- let producer = format!("clang LLVM (rustc version {})",
- (option_env!("CFG_VERSION")).expect("CFG_VERSION"));
+ let producer = format!("clang LLVM ({})", rustc_producer);
let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let name_in_debuginfo = SmallCStr::new(&name_in_debuginfo);
gcov_metadata);
}
+ // Insert `llvm.ident` metadata on the wasm32 targets since that will
+ // get hooked up to the "producer" sections `processed-by` information.
+ if tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+ let name_metadata = llvm::LLVMMDStringInContext(
+ debug_context.llcontext,
+ rustc_producer.as_ptr() as *const _,
+ rustc_producer.as_bytes().len() as c_uint,
+ );
+ llvm::LLVMAddNamedMetadataOperand(
+ debug_context.llmod,
+ const_cstr!("llvm.ident").as_ptr(),
+ llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1),
+ );
+ }
+
return unit_metadata;
};
-#![allow(non_snake_case)]
-
register_long_diagnostics! {
E0511: r##"
-#![allow(non_upper_case_globals)]
-
use crate::attributes;
use crate::llvm;
use crate::llvm_util;
#![feature(crate_visibility_modifier)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
-#![allow(unused_attributes)]
#![feature(libc)]
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
#![feature(static_nobundle)]
#![feature(trusted_len)]
#![feature(mem_take)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
use back::write::{create_target_machine, create_informational_target_machine};
use syntax_pos::symbol::Symbol;
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+
use super::debuginfo::{
DIBuilder, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType,
DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable,
-#![allow(non_upper_case_globals)]
-#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
-#![deny(bare_trait_objects)]
pub use self::IntPredicate::*;
pub use self::RealPredicate::*;
-#![allow(non_upper_case_globals)]
-
pub use crate::llvm::Type;
use crate::llvm;
sess.fatal(&format!("failed to run dsymutil: {}", e))
}
}
-
- if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" {
- super::wasm::add_producer_section(
- &out_filename,
- &sess.edition().to_string(),
- option_env!("CFG_VERSION").unwrap_or("unknown"),
- );
- }
}
/// Returns a boolean indicating whether the specified crate should be ignored
}
impl<'a> WasmLd<'a> {
- fn new(cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
+ fn new(mut cmd: Command, sess: &'a Session, info: &'a LinkerInfo) -> WasmLd<'a> {
+ // If the atomics feature is enabled for wasm then we need a whole bunch
+ // of flags:
+ //
+ // * `--shared-memory` - the link won't even succeed without this, flags
+ // the one linear memory as `shared`
+ //
+ // * `--max-memory=1G` - when specifying a shared memory this must also
+ // be specified. We conservatively choose 1GB but users should be able
+ // to override this with `-C link-arg`.
+ //
+ // * `--import-memory` - it doesn't make much sense for memory to be
+ // exported in a threaded module because typically you're
+ // sharing memory and instantiating the module multiple times. As a
+ // result if it were exported then we'd just have no sharing.
+ //
+ // * `--passive-segments` - all memory segments should be passive to
+ // prevent each module instantiation from reinitializing memory.
+ //
+ // * `--export=__wasm_init_memory` - when using `--passive-segments` the
+ // linker will synthesize this function, and so we need to make sure
+ // that our usage of `--export` below won't accidentally cause this
+ // function to get deleted.
+ //
+ // * `--export=*tls*` - when `#[thread_local]` symbols are used these
+ // symbols are how the TLS segments are initialized and configured.
+ let atomics = sess.opts.cg.target_feature.contains("+atomics") ||
+ sess.target.target.options.features.contains("+atomics");
+ if atomics {
+ cmd.arg("--shared-memory");
+ cmd.arg("--max-memory=1073741824");
+ cmd.arg("--import-memory");
+ cmd.arg("--passive-segments");
+ cmd.arg("--export=__wasm_init_memory");
+ cmd.arg("--export=__wasm_init_tls");
+ cmd.arg("--export=__tls_size");
+ cmd.arg("--export=__tls_align");
+ cmd.arg("--export=__tls_base");
+ }
WasmLd { cmd, sess, info }
}
}
for sym in self.info.exports[&crate_type].iter() {
self.cmd.arg("--export").arg(&sym);
}
+
+ // LLD will hide these otherwise-internal symbols since our `--export`
+ // list above is a whitelist of what to export. Various bits and pieces
+ // of tooling use this, so be sure these symbols make their way out of
+ // the linker as well.
+ self.cmd.arg("--export=__heap_base");
+ self.cmd.arg("--export=__data_end");
}
fn subsystem(&mut self, _subsystem: &str) {
pub mod symbol_export;
pub mod archive;
pub mod rpath;
-pub mod wasm;
+++ /dev/null
-use std::fs;
-use std::path::Path;
-use std::str;
-
-use rustc_serialize::leb128;
-
-// https://webassembly.github.io/spec/core/binary/modules.html#binary-importsec
-const WASM_CUSTOM_SECTION_ID: u8 = 0;
-
-/// Adds or augment the existing `producers` section to encode information about
-/// the Rust compiler used to produce the wasm file.
-pub fn add_producer_section(
- path: &Path,
- rust_version: &str,
- rustc_version: &str,
-) {
- struct Field<'a> {
- name: &'a str,
- values: Vec<FieldValue<'a>>,
- }
-
- #[derive(Copy, Clone)]
- struct FieldValue<'a> {
- name: &'a str,
- version: &'a str,
- }
-
- let wasm = fs::read(path).expect("failed to read wasm output");
- let mut ret = WasmEncoder::new();
- ret.data.extend(&wasm[..8]);
-
- // skip the 8 byte wasm/version header
- let rustc_value = FieldValue {
- name: "rustc",
- version: rustc_version,
- };
- let rust_value = FieldValue {
- name: "Rust",
- version: rust_version,
- };
- let mut fields = Vec::new();
- let mut wrote_rustc = false;
- let mut wrote_rust = false;
-
- // Move all sections from the original wasm file to our output, skipping
- // everything except the producers section
- for (id, raw) in WasmSections(WasmDecoder::new(&wasm[8..])) {
- if id != WASM_CUSTOM_SECTION_ID {
- ret.byte(id);
- ret.bytes(raw);
- continue
- }
- let mut decoder = WasmDecoder::new(raw);
- if decoder.str() != "producers" {
- ret.byte(id);
- ret.bytes(raw);
- continue
- }
-
- // Read off the producers section into our fields outside the loop,
- // we'll re-encode the producers section when we're done (to handle an
- // entirely missing producers section as well).
- info!("rewriting existing producers section");
-
- for _ in 0..decoder.u32() {
- let name = decoder.str();
- let mut values = Vec::new();
- for _ in 0..decoder.u32() {
- let name = decoder.str();
- let version = decoder.str();
- values.push(FieldValue { name, version });
- }
-
- if name == "language" {
- values.push(rust_value);
- wrote_rust = true;
- } else if name == "processed-by" {
- values.push(rustc_value);
- wrote_rustc = true;
- }
- fields.push(Field { name, values });
- }
- }
-
- if !wrote_rust {
- fields.push(Field {
- name: "language",
- values: vec![rust_value],
- });
- }
- if !wrote_rustc {
- fields.push(Field {
- name: "processed-by",
- values: vec![rustc_value],
- });
- }
-
- // Append the producers section to the end of the wasm file.
- let mut section = WasmEncoder::new();
- section.str("producers");
- section.u32(fields.len() as u32);
- for field in fields {
- section.str(field.name);
- section.u32(field.values.len() as u32);
- for value in field.values {
- section.str(value.name);
- section.str(value.version);
- }
- }
- ret.byte(WASM_CUSTOM_SECTION_ID);
- ret.bytes(§ion.data);
-
- fs::write(path, &ret.data).expect("failed to write wasm output");
-}
-
-struct WasmSections<'a>(WasmDecoder<'a>);
-
-impl<'a> Iterator for WasmSections<'a> {
- type Item = (u8, &'a [u8]);
-
- fn next(&mut self) -> Option<(u8, &'a [u8])> {
- if self.0.data.is_empty() {
- return None
- }
-
- // see https://webassembly.github.io/spec/core/binary/modules.html#sections
- let id = self.0.byte();
- let section_len = self.0.u32();
- info!("new section {} / {} bytes", id, section_len);
- let section = self.0.skip(section_len as usize);
- Some((id, section))
- }
-}
-
-struct WasmDecoder<'a> {
- data: &'a [u8],
-}
-
-impl<'a> WasmDecoder<'a> {
- fn new(data: &'a [u8]) -> WasmDecoder<'a> {
- WasmDecoder { data }
- }
-
- fn byte(&mut self) -> u8 {
- self.skip(1)[0]
- }
-
- fn u32(&mut self) -> u32 {
- let (n, l1) = leb128::read_u32_leb128(self.data);
- self.data = &self.data[l1..];
- return n
- }
-
- fn skip(&mut self, amt: usize) -> &'a [u8] {
- let (data, rest) = self.data.split_at(amt);
- self.data = rest;
- data
- }
-
- fn str(&mut self) -> &'a str {
- let len = self.u32();
- str::from_utf8(self.skip(len as usize)).unwrap()
- }
-}
-
-struct WasmEncoder {
- data: Vec<u8>,
-}
-
-impl WasmEncoder {
- fn new() -> WasmEncoder {
- WasmEncoder { data: Vec::new() }
- }
-
- fn u32(&mut self, val: u32) {
- leb128::write_u32_leb128(&mut self.data, val);
- }
-
- fn byte(&mut self, val: u8) {
- self.data.push(val);
- }
-
- fn bytes(&mut self, val: &[u8]) {
- self.u32(val.len() as u32);
- self.data.extend_from_slice(val);
- }
-
- fn str(&mut self, val: &str) {
- self.bytes(val.as_bytes())
- }
-}
}
}
-fn is_codegened_item(tcx: TyCtxt<'_>, id: DefId) -> bool {
- let (all_mono_items, _) =
- tcx.collect_and_partition_mono_items(LOCAL_CRATE);
- all_mono_items.contains(&id)
-}
-
pub fn provide_both(providers: &mut Providers<'_>) {
providers.backend_optimization_level = |tcx, cratenum| {
let for_speed = match tcx.sess.opts.optimize {
-#![allow(non_snake_case)]
-
register_long_diagnostics! {
E0668: r##"
#![feature(nll)]
#![feature(trusted_len)]
#![feature(mem_take)]
-#![allow(unused_attributes)]
-#![allow(dead_code)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
#![recursion_limit="256"]
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(warnings)]
-#![feature(box_syntax)]
use std::any::Any;
use std::sync::mpsc;
#![feature(core_intrinsics)]
#![feature(never_type)]
#![feature(nll)]
-#![allow(unused_attributes)]
#![feature(rustc_diagnostic_macros)]
#![feature(in_band_lifetimes)]
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use]
extern crate rustc;
}
}
+#[allow(unused_lifetimes)]
pub trait GraphSuccessors<'graph> {
type Item;
type Iter: Iterator<Item = Self::Item>;
) -> <Self as GraphPredecessors<'_>>::Iter;
}
+#[allow(unused_lifetimes)]
pub trait GraphPredecessors<'graph> {
type Item;
type Iter: Iterator<Item = Self::Item>;
#![cfg_attr(unix, feature(libc))]
#![cfg_attr(test, feature(test))]
-#![deny(rust_2018_idioms)]
#![cfg_attr(not(bootstrap), allow(rustc::default_hash_types))]
#[macro_use]
This can sometimes be useful because Rust borrowing rules normally prevent
moving a type that has been moved from. For example, this kind of code gets rejected:
-```rust,ignore
+```compile_fail,E0515
fn return_owned_and_referenced<'a>() -> (Vec<u8>, &'a [u8]) {
let v = vec![1, 2, 3, 4];
let s = &v[1..3];
as provided by `Box<T>`, `Rc<T>`, etc.
Also provided are typedefs for common owner type combinations,
-which allow for less verbose type signatures. For example, `BoxRef<T>` instead of `OwningRef<Box<T>, T>`.
+which allow for less verbose type signatures.
+For example, `BoxRef<T>` instead of `OwningRef<Box<T>, T>`.
The crate also provides the more advanced `OwningHandle` type,
which allows more freedom in bundling a dependent handle object
/// Helper trait for erasing the concrete type of what an owner dereferences to,
/// for example `Box<T> -> Box<Erased>`. This would be unneeded with
/// higher kinded types support in the language.
+#[allow(unused_lifetimes)]
pub unsafe trait IntoErased<'a> {
/// Owner with the dereference type substituted to `Erased`.
type Erased;
/// Helper trait for erasing the concrete type of what an owner dereferences to,
/// for example `Box<T> -> Box<Erased + Send>`. This would be unneeded with
/// higher kinded types support in the language.
+#[allow(unused_lifetimes)]
pub unsafe trait IntoErasedSend<'a> {
/// Owner with the dereference type substituted to `Erased + Send`.
type Erased: Send;
/// Helper trait for erasing the concrete type of what an owner dereferences to,
/// for example `Box<T> -> Box<Erased + Send + Sync>`. This would be unneeded with
/// higher kinded types support in the language.
+#[allow(unused_lifetimes)]
pub unsafe trait IntoErasedSendSync<'a> {
/// Owner with the dereference type substituted to `Erased + Send + Sync`.
type Erased: Send + Sync;
}
}
- /// Erases the concrete base type of the owner with a trait object which implements `Send` and `Sync`.
+ /// Erases the concrete base type of the owner with a trait object
+ /// which implements `Send` and `Sync`.
///
/// This allows mixing of owned references with different owner base types.
pub fn erase_send_sync_owner<'a>(self) -> OwningRef<O::Erased, T>
}
}
- // TODO: wrap_owner
+ // UNIMPLEMENTED: wrap_owner
// FIXME: Naming convention?
/// A getter for the underlying owner.
}
}
- // TODO: wrap_owner
+ // UNIMPLEMENTED: wrap_owner
// FIXME: Naming convention?
/// A getter for the underlying owner.
use std::cell::RefCell;
let cell = Rc::new(RefCell::new(2));
let cell_ref = RcRef::new(cell);
- let mut handle = OwningHandle::new_with_fn(cell_ref, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
+ let mut handle = OwningHandle::new_with_fn(cell_ref, |x| {
+ unsafe { x.as_ref() }.unwrap().borrow_mut()
+ });
assert_eq!(*handle, 2);
*handle = 3;
assert_eq!(*handle, 3);
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
- let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
- let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
+ let curr = OwningHandle::new_with_fn(curr, |x| {
+ unsafe { x.as_ref() }.unwrap().borrow_mut()
+ });
+ let mut curr = OwningHandle::new_with_fn(curr, |x| {
+ unsafe { x.as_ref() }.unwrap().try_write().unwrap()
+ });
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
let result = {
let complex = Rc::new(RefCell::new(Arc::new(RwLock::new("someString"))));
let curr = RcRef::new(complex);
- let curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().borrow_mut());
- let mut curr = OwningHandle::new_with_fn(curr, |x| unsafe { x.as_ref() }.unwrap().try_write().unwrap());
+ let curr = OwningHandle::new_with_fn(curr, |x| {
+ unsafe { x.as_ref() }.unwrap().borrow_mut()
+ });
+ let mut curr = OwningHandle::new_with_fn(curr, |x| {
+ unsafe { x.as_ref() }.unwrap().try_write().unwrap()
+ });
assert_eq!(*curr, "someString");
*curr = "someOtherString";
curr
crate-type = ["dylib"]
[dependencies]
-arena = { path = "../libarena" }
graphviz = { path = "../libgraphviz" }
log = "0.4"
env_logger = { version = "0.5", default-features = false }
-rayon = { version = "0.2.0", package = "rustc-rayon" }
rustc = { path = "../librustc" }
rustc_target = { path = "../librustc_target" }
rustc_ast_borrowck = { path = "../librustc_ast_borrowck" }
rustc_data_structures = { path = "../librustc_data_structures" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
-rustc_incremental = { path = "../librustc_incremental" }
-rustc_lint = { path = "../librustc_lint" }
rustc_metadata = { path = "../librustc_metadata" }
rustc_mir = { path = "../librustc_mir" }
-rustc_passes = { path = "../librustc_passes" }
-rustc_plugin = { path = "../librustc_plugin" }
-rustc_privacy = { path = "../librustc_privacy" }
-rustc_resolve = { path = "../librustc_resolve" }
rustc_save_analysis = { path = "../librustc_save_analysis" }
-rustc_traits = { path = "../librustc_traits" }
rustc_codegen_utils = { path = "../librustc_codegen_utils" }
-rustc_typeck = { path = "../librustc_typeck" }
rustc_interface = { path = "../librustc_interface" }
rustc_serialize = { path = "../libserialize", package = "serialize" }
syntax = { path = "../libsyntax" }
-smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
syntax_pos = { path = "../libsyntax_pos" }
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
pub extern crate getopts;
#[cfg(unix)]
extern crate libc;
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(crate_visibility_modifier)]
-#![allow(unused_attributes)]
#![cfg_attr(unix, feature(libc))]
#![feature(nll)]
#![feature(optin_builtin_traits)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
pub use emitter::ColorConfig;
}
}
if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
- buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
+ let end = std::cmp::min(cur_line.len(), cur_lo.col.to_usize());
+ buf.push_str(&cur_line[..end]);
}
}
buf.push_str(&part.snippet);
-#![deny(rust_2018_idioms)]
-
use std::path::{Path, PathBuf};
use std::ffi::CString;
use std::fs;
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use] extern crate rustc;
#[macro_use] extern crate log;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc_metadata::cstore::CStore;
-use std::io::Write;
use std::path::PathBuf;
use std::result;
use std::sync::{Arc, Mutex};
#![feature(generators)]
#![cfg_attr(unix, feature(libc))]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
-#![allow(unused_imports)]
-
#![recursion_limit="256"]
#[cfg(unix)]
use crate::util;
use crate::proc_macro_decls;
-use log::{debug, info, warn, log_enabled};
+use log::{info, warn, log_enabled};
use rustc::dep_graph::DepGraph;
use rustc::hir;
use rustc::hir::lowering::lower_crate;
use rustc::lint;
use rustc::middle::{self, reachable, resolve_lifetime, stability};
use rustc::middle::cstore::CrateStore;
-use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt, GlobalCtxt};
use rustc::ty::steal::Steal;
use rustc::traits;
use rustc::util::common::{time, ErrorReported};
-use rustc::util::profiling::ProfileCategory;
-use rustc::session::{CompileResult, CrateDisambiguator, Session};
+use rustc::session::Session;
use rustc::session::config::{self, CrateType, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
-use rustc_allocator as allocator;
use rustc_ast_borrowck as borrowck;
use rustc_codegen_ssa::back::link::emit_metadata;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_codegen_utils::link::filename_for_metadata;
use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{Lrc, ParallelIterator, par_iter};
use rustc_incremental;
-use rustc_incremental::DepGraphFuture;
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::{self, CStore};
use rustc_mir as mir;
-use rustc_passes::{self, ast_validation, hir_stats, loops, rvalue_promotion, layout_test};
+use rustc_passes::{self, ast_validation, hir_stats, layout_test};
use rustc_plugin as plugin;
use rustc_plugin::registry::Registry;
use rustc_privacy;
use rustc_resolve::{Resolver, ResolverArenas};
use rustc_traits;
use rustc_typeck as typeck;
-use syntax::{self, ast, attr, diagnostics, visit};
+use syntax::{self, ast, diagnostics, visit};
use syntax::early_buffered_lints::BufferedEarlyLint;
use syntax::ext::base::{NamedSyntaxExtension, ExtCtxt};
use syntax::mut_visit::MutVisitor;
use syntax::parse::{self, PResult};
use syntax::util::node_count::NodeCounter;
-use syntax::util::lev_distance::find_best_match_for_name;
use syntax::symbol::Symbol;
use syntax::feature_gate::AttributeType;
-use syntax_pos::{FileName, edition::Edition, hygiene};
+use syntax_pos::FileName;
use syntax_ext;
use rustc_serialize::json;
use std::fs;
use std::io::{self, Write};
use std::iter;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
use std::sync::mpsc;
use std::cell::RefCell;
use std::rc::Rc;
use std::mem;
-use std::ops::Generator;
pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
sess.diagnostic()
krate = time(sess, "crate injection", || {
let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| &**s);
- syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name, sess.edition())
+ let (krate, name) =
+ syntax_ext::standard_library_imports::inject(krate, alt_std_name, sess.edition());
+ if let Some(name) = name {
+ sess.parse_sess.injected_crate_name.set(name);
+ }
+ krate
});
let registrars = time(sess, "plugin loading", || {
sess.profiler(|p| p.end_activity("macro expansion"));
time(sess, "maybe building test harness", || {
- syntax::test::modify_for_testing(
+ syntax_ext::test_harness::inject(
&sess.parse_sess,
&mut resolver,
sess.opts.test,
let num_crate_types = crate_types.len();
let is_proc_macro_crate = crate_types.contains(&config::CrateType::ProcMacro);
let is_test_crate = sess.opts.test;
- syntax_ext::proc_macro_decls::modify(
+ syntax_ext::proc_macro_harness::inject(
&sess.parse_sess,
&mut resolver,
krate,
use crate::passes::{self, BoxedResolver, ExpansionResult, BoxedGlobalCtxt, PluginInfo};
use rustc_incremental::DepGraphFuture;
-use rustc_data_structures::sync::Lrc;
-use rustc::session::config::{Input, OutputFilenames, OutputType};
-use rustc::session::Session;
+use rustc::session::config::{OutputFilenames, OutputType};
use rustc::util::common::{time, ErrorReported};
-use rustc::util::profiling::ProfileCategory;
-use rustc::lint;
use rustc::hir;
use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::ty;
use rustc::ty::steal::Steal;
use rustc::dep_graph::DepGraph;
-use rustc_passes::hir_stats;
-use rustc_plugin::registry::Registry;
-use rustc_serialize::json;
use std::cell::{Ref, RefMut, RefCell};
-use std::ops::Deref;
use std::rc::Rc;
use std::sync::mpsc;
use std::any::Any;
use std::mem;
-use syntax::parse::{self, PResult};
-use syntax::util::node_count::NodeCounter;
-use syntax::{self, ast, attr, diagnostics, visit};
-use syntax_pos::hygiene;
+use syntax::{self, ast};
/// Represent the result of a query.
/// This result can be stolen with the `take` method and returned with the `give` method.
f: F,
) -> R {
use rayon::{ThreadPool, ThreadPoolBuilder};
- use syntax;
- use syntax_pos;
let gcx_ptr = &Lock::new(0);
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use]
extern crate rustc;
-#![deny(rust_2018_idioms)]
#![feature(nll)]
#![feature(static_nobundle)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-#![deny(rust_2018_idioms)]
#![feature(proc_macro_hygiene)]
-#![deny(rust_2018_idioms)]
#![cfg_attr(not(bootstrap), allow(rustc::default_hash_types))]
#![recursion_limit="128"]
rustc_serialize = { path = "../libserialize", package = "serialize" }
stable_deref_trait = "1.0.0"
syntax = { path = "../libsyntax" }
-syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
use std::{env, mem};
use crate::dynamic_lib::DynamicLibrary;
use proc_macro::bridge::client::ProcMacro;
- use syntax_ext::deriving::custom::ProcMacroDerive;
- use syntax_ext::proc_macro_impl::{AttrProcMacro, BangProcMacro};
+ use syntax::ext::proc_macro::{BangProcMacro, AttrProcMacro, ProcMacroDerive};
let path = match dylib {
Some(dylib) => dylib,
use syntax::source_map;
use syntax::edition::Edition;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
+use syntax::ext::proc_macro::BangProcMacro;
use syntax::parse::source_file_to_stream;
use syntax::parse::parser::emit_unclosed_delims;
use syntax::symbol::{Symbol, sym};
-use syntax_ext::proc_macro_impl::BangProcMacro;
use syntax_pos::{Span, NO_EXPANSION, FileName};
use rustc_data_structures::bit_set::BitSet;
-#![allow(non_snake_case)]
-
use syntax::{register_diagnostics, register_long_diagnostics};
register_long_diagnostics! {
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
extern crate libc;
extern crate proc_macro;
bug!("try_report_cannot_return_reference_to_local: not a local")
};
match self.body.local_kind(*local) {
- LocalKind::ReturnPointer | LocalKind::Temp => {
- (
- "temporary value".to_string(),
- "temporary value created here".to_string(),
- )
- }
- LocalKind::Arg => {
- (
- "function parameter".to_string(),
- "function parameter borrowed here".to_string(),
- )
- },
- LocalKind::Var => bug!("local variable without a name"),
+ LocalKind::ReturnPointer | LocalKind::Temp => (
+ "temporary value".to_string(),
+ "temporary value created here".to_string(),
+ ),
+ LocalKind::Arg => (
+ "function parameter".to_string(),
+ "function parameter borrowed here".to_string(),
+ ),
+ LocalKind::Var => (
+ "local binding".to_string(),
+ "local binding introduced here".to_string(),
+ ),
}
};
//! This pass type-checks the MIR to ensure it is not broken.
-#![allow(unreachable_code)]
-
use crate::borrow_check::borrow_set::BorrowSet;
use crate::borrow_check::location::LocationTable;
use crate::borrow_check::nll::constraints::{OutlivesConstraintSet, OutlivesConstraint};
self_arg = None;
}
- ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&*arg.pat), self_arg)
+ ArgInfo(fn_sig.inputs()[index], opt_ty_info, Some(&arg), self_arg)
});
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
///////////////////////////////////////////////////////////////////////////
/// the main entry point for building MIR for a function
-struct ArgInfo<'tcx>(Ty<'tcx>, Option<Span>, Option<&'tcx hir::Pat>, Option<ImplicitSelfKind>);
+struct ArgInfo<'tcx>(Ty<'tcx>, Option<Span>, Option<&'tcx hir::Arg>, Option<ImplicitSelfKind>);
fn construct_fn<'a, 'tcx, A>(
hir: Cx<'a, 'tcx>,
-> BlockAnd<()>
{
// Allocate locals for the function arguments
- for &ArgInfo(ty, _, pattern, _) in arguments.iter() {
+ for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() {
// If this is a simple binding pattern, give the local a name for
// debuginfo and so that error reporting knows that this is a user
// variable. For any other pattern the pattern introduces new
// variables which will be named instead.
- let (name, span) = if let Some(pat) = pattern {
- (pat.simple_ident().map(|ident| ident.name), pat.span)
+ let (name, span) = if let Some(arg) = arg_opt {
+ (arg.pat.simple_ident().map(|ident| ident.name), arg.pat.span)
} else {
(None, self.fn_span)
};
// Function arguments always get the first Local indices after the return place
let local = Local::new(index + 1);
let place = Place::from(local);
- let &ArgInfo(ty, opt_ty_info, pattern, ref self_binding) = arg_info;
+ let &ArgInfo(ty, opt_ty_info, arg_opt, ref self_binding) = arg_info;
// Make sure we drop (parts of) the argument even when not matched on.
self.schedule_drop(
- pattern.as_ref().map_or(ast_body.span, |pat| pat.span),
+ arg_opt.as_ref().map_or(ast_body.span, |arg| arg.pat.span),
argument_scope, local, ty, DropKind::Value,
);
- if let Some(pattern) = pattern {
- let pattern = self.hir.pattern_from_hir(pattern);
+ if let Some(arg) = arg_opt {
+ let pattern = self.hir.pattern_from_hir(&arg.pat);
+ let original_source_scope = self.source_scope;
let span = pattern.span;
-
+ self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span);
match *pattern.kind {
// Don't introduce extra copies for simple bindings
PatternKind::Binding {
..
} => {
self.local_decls[local].mutability = mutability;
+ self.local_decls[local].source_info.scope = self.source_scope;
self.local_decls[local].is_user_variable =
if let Some(kind) = self_binding {
Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf(*kind)))
unpack!(block = self.place_into_pattern(block, pattern, &place, false));
}
}
+ self.source_scope = original_source_scope;
}
}
self.into(&Place::RETURN_PLACE, block, body)
}
+ fn set_correct_source_scope_for_arg(
+ &mut self,
+ arg_hir_id: hir::HirId,
+ original_source_scope: SourceScope,
+ pattern_span: Span
+ ) {
+ let tcx = self.hir.tcx();
+ let current_root = tcx.maybe_lint_level_root_bounded(
+ arg_hir_id,
+ self.hir.root_lint_level
+ );
+ let parent_root = tcx.maybe_lint_level_root_bounded(
+ self.source_scope_local_data[original_source_scope].lint_root,
+ self.hir.root_lint_level,
+ );
+ if current_root != parent_root {
+ self.source_scope = self.new_source_scope(
+ pattern_span,
+ LintLevel::Explicit(current_root),
+ None
+ );
+ }
+ }
+
fn get_unit_temp(&mut self) -> Place<'tcx> {
match self.unit_temp {
Some(ref tmp) => tmp.clone(),
-#![allow(non_snake_case)]
-
register_long_diagnostics! {
/// Matches against a slice, checking the length and extracting elements.
/// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
- /// e.g., `&[ref xs..]`.
+ /// e.g., `&[ref xs @ ..]`.
Slice {
prefix: Vec<Pattern<'tcx>>,
slice: Option<Pattern<'tcx>>,
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use] extern crate log;
#[macro_use] extern crate rustc;
#[macro_use] extern crate rustc_data_structures;
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-#![deny(rust_2018_idioms)]
[dependencies]
log = "0.4"
rustc = { path = "../librustc" }
-rustc_mir = { path = "../librustc_mir"}
rustc_data_structures = { path = "../librustc_data_structures" }
syntax = { path = "../libsyntax" }
-syntax_ext = { path = "../libsyntax_ext" }
syntax_pos = { path = "../libsyntax_pos" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::*;
use syntax::attr;
+use syntax::ext::proc_macro::is_proc_macro_attr;
use syntax::feature_gate::is_builtin_attr;
use syntax::source_map::Spanned;
use syntax::symbol::{kw, sym};
use syntax::visit::{self, Visitor};
use syntax::{span_err, struct_span_err, walk_list};
-use syntax_ext::proc_macro_decls::is_proc_macro_attr;
use syntax_pos::{Span, MultiSpan};
use errors::{Applicability, FatalError};
// ```
fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
match expr.node {
- ExprKind::Lit(..) => {}
+ ExprKind::Lit(..) | ExprKind::Err => {}
ExprKind::Path(..) if allow_paths => {}
ExprKind::Unary(UnOp::Neg, ref inner)
if match inner.node { ExprKind::Lit(_) => true, _ => false } => {}
-#![allow(non_snake_case)]
-
use syntax::{register_diagnostics, register_long_diagnostics};
register_long_diagnostics! {
}
impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
+ fn visit_arg(&mut self, arg: &'v hir::Arg) {
+ self.record("Arg", Id::Node(arg.hir_id), arg);
+ hir_visit::walk_arg(self, arg)
+ }
+
fn nested_visit_map<'this>(&'this mut self) -> hir_visit::NestedVisitorMap<'this, 'v> {
panic!("visit_nested_xxx must be manually implemented in this visitor")
}
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use]
extern crate rustc;
-#![allow(non_snake_case)]
-
use syntax::{register_diagnostics, register_long_diagnostics};
register_long_diagnostics! {
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-
pub use registry::Registry;
mod error_codes;
-#![allow(non_snake_case)]
-
register_long_diagnostics! {
E0445: r##"
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![feature(rustc_diagnostic_macros)]
use syntax::feature_gate::is_builtin_attr;
use syntax::parse::token::{self, Token};
use syntax::span_err;
-use syntax::std_inject::injected_crate_name;
use syntax::symbol::{kw, sym};
use syntax::visit::{self, Visitor};
};
self.populate_module_if_necessary(module);
- if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) {
- self.injected_crate = Some(module);
+ if let Some(name) = self.session.parse_sess.injected_crate_name.try_get() {
+ if name.as_str() == ident.name.as_str() {
+ self.injected_crate = Some(module);
+ }
}
let used = self.process_legacy_macro_imports(item, module, &parent_scope);
-#![allow(non_snake_case)]
-
use syntax::{register_diagnostics, register_long_diagnostics};
// Error messages for EXXXX errors. Each message should start and end with a
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
pub use rustc::hir::def::{Namespace, PerNS};
use Determinacy::*;
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(nll)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-#![allow(unused_attributes)]
#![recursion_limit="256"]
-
mod dumper;
mod dump_visitor;
#[macro_use]
-#![allow(non_upper_case_globals)]
-
use crate::abi::call::{FnType, ArgType};
fn classify_ret_ty<Ty>(ret: &mut ArgType<'_, Ty>) {
let mut dl = TargetDataLayout::default();
let mut i128_align_src = 64;
for spec in target.data_layout.split('-') {
- match spec.split(':').collect::<Vec<_>>()[..] {
+ let spec_parts = spec.split(':').collect::<Vec<_>>();
+
+ match &*spec_parts {
["e"] => dl.endian = Endian::Little,
["E"] => dl.endian = Endian::Big,
[p] if p.starts_with("P") => {
dl.instruction_address_space = parse_address_space(&p[1..], "P")?
}
- ["a", ref a..] => dl.aggregate_align = align(a, "a")?,
- ["f32", ref a..] => dl.f32_align = align(a, "f32")?,
- ["f64", ref a..] => dl.f64_align = align(a, "f64")?,
- [p @ "p", s, ref a..] | [p @ "p0", s, ref a..] => {
+ // FIXME: Ping cfg(bootstrap) -- Use `ref a @ ..` with new bootstrap compiler.
+ ["a", ..] => {
+ let a = &spec_parts[1..]; // FIXME inline into pattern.
+ dl.aggregate_align = align(a, "a")?
+ }
+ ["f32", ..] => {
+ let a = &spec_parts[1..]; // FIXME inline into pattern.
+ dl.f32_align = align(a, "f32")?
+ }
+ ["f64", ..] => {
+ let a = &spec_parts[1..]; // FIXME inline into pattern.
+ dl.f64_align = align(a, "f64")?
+ }
+ [p @ "p", s, ..] | [p @ "p0", s, ..] => {
+ let a = &spec_parts[2..]; // FIXME inline into pattern.
dl.pointer_size = size(s, p)?;
dl.pointer_align = align(a, p)?;
}
- [s, ref a..] if s.starts_with("i") => {
+ [s, ..] if s.starts_with("i") => {
+ let a = &spec_parts[1..]; // FIXME inline into pattern.
let bits = match s[1..].parse::<u64>() {
Ok(bits) => bits,
Err(_) => {
dl.i128_align = a;
}
}
- [s, ref a..] if s.starts_with("v") => {
+ [s, ..] if s.starts_with("v") => {
+ let a = &spec_parts[1..]; // FIXME inline into pattern.
let v_size = size(&s[1..], "v")?;
let a = align(a, s)?;
if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
#![feature(nll)]
#![feature(slice_patterns)]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use] extern crate log;
pub mod abi;
// non-relative calls and such later on).
relocation_model: "static".to_string(),
+ // When the atomics feature is activated then these two keys matter,
+ // otherwise they're basically ignored by the standard library. In this
+ // mode, however, the `#[thread_local]` attribute works (i.e.
+ // `has_elf_tls`) and we need to get it to work by specifying
+ // `local-exec` as that's all that's implemented in LLVM today for wasm.
+ has_elf_tls: true,
+ tls_model: "local-exec".to_string(),
+
.. Default::default()
}
}
//! New recursive solver modeled on Chalk's recursive solver. Most of
//! the guts are broken up into modules; see the comments in those modules.
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)]
#![feature(nll)]
#![unstable(feature = "sanitizer_runtime_lib",
reason = "internal implementation detail of sanitizers",
issue = "0")]
-
-#![deny(rust_2018_idioms)]
let rhs_ty = self.check_expr(end);
// Check that both end-points are of numeric or char type.
- let numeric_or_char = |ty: Ty<'_>| ty.is_numeric() || ty.is_char();
+ let numeric_or_char = |ty: Ty<'_>| {
+ ty.is_numeric()
+ || ty.is_char()
+ || ty.references_error()
+ };
let lhs_compat = numeric_or_char(lhs_ty);
let rhs_compat = numeric_or_char(rhs_ty);
) {
let tcx = self.tcx;
if let PatKind::Binding(..) = inner.node {
- let parent_id = tcx.hir().get_parent_node(pat.hir_id);
- let parent = tcx.hir().get(parent_id);
- debug!("inner {:?} pat {:?} parent {:?}", inner, pat, parent);
- match parent {
- hir::Node::Item(hir::Item { node: hir::ItemKind::Fn(..), .. }) |
- hir::Node::ForeignItem(hir::ForeignItem {
- node: hir::ForeignItemKind::Fn(..), ..
- }) |
- hir::Node::TraitItem(hir::TraitItem { node: hir::TraitItemKind::Method(..), .. }) |
- hir::Node::ImplItem(hir::ImplItem { node: hir::ImplItemKind::Method(..), .. }) => {
- // this pat is likely an argument
+ let binding_parent_id = tcx.hir().get_parent_node(pat.hir_id);
+ let binding_parent = tcx.hir().get(binding_parent_id);
+ debug!("inner {:?} pat {:?} parent {:?}", inner, pat, binding_parent);
+ match binding_parent {
+ hir::Node::Arg(hir::Arg { span, .. }) => {
if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(inner.span) {
- // FIXME: turn into structured suggestion, will need a span that also
- // includes the the arg's type.
- err.help(&format!("did you mean `{}: &{}`?", snippet, expected));
+ err.span_suggestion(
+ *span,
+ &format!("did you mean `{}`", snippet),
+ format!(" &{}", expected),
+ Applicability::MachineApplicable,
+ );
}
}
hir::Node::Arm(_) |
&self,
expr: &hir::Expr,
) -> Option<(Span, &'static str, String)> {
- if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.node {
- if let hir::def::Res::Local(id) = path.res {
- let parent = self.tcx.hir().get_parent_node(id);
- if let Some(Node::Expr(hir::Expr {
- hir_id,
- node: hir::ExprKind::Closure(_, decl, ..),
- ..
- })) = self.tcx.hir().find(parent) {
- let parent = self.tcx.hir().get_parent_node(*hir_id);
- if let (Some(Node::Expr(hir::Expr {
- node: hir::ExprKind::MethodCall(path, span, expr),
- ..
- })), 1) = (self.tcx.hir().find(parent), decl.inputs.len()) {
- let self_ty = self.tables.borrow().node_type(expr[0].hir_id);
- let self_ty = format!("{:?}", self_ty);
- let name = path.ident.as_str();
- let is_as_ref_able = (
- self_ty.starts_with("&std::option::Option") ||
- self_ty.starts_with("&std::result::Result") ||
- self_ty.starts_with("std::option::Option") ||
- self_ty.starts_with("std::result::Result")
- ) && (name == "map" || name == "and_then");
- match (is_as_ref_able, self.sess().source_map().span_to_snippet(*span)) {
- (true, Ok(src)) => {
- return Some((*span, "consider using `as_ref` instead",
- format!("as_ref().{}", src)));
- },
- _ => ()
- }
- }
- }
- }
+ let path = match expr.node {
+ hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => path,
+ _ => return None
+ };
+
+ let local_id = match path.res {
+ hir::def::Res::Local(id) => id,
+ _ => return None
+ };
+
+ let local_parent = self.tcx.hir().get_parent_node(local_id);
+ let arg_hir_id = match self.tcx.hir().find(local_parent) {
+ Some(Node::Arg(hir::Arg { hir_id, .. })) => hir_id,
+ _ => return None
+ };
+
+ let arg_parent = self.tcx.hir().get_parent_node(*arg_hir_id);
+ let (expr_hir_id, closure_fn_decl) = match self.tcx.hir().find(arg_parent) {
+ Some(Node::Expr(
+ hir::Expr { hir_id, node: hir::ExprKind::Closure(_, decl, ..), .. }
+ )) => (hir_id, decl),
+ _ => return None
+ };
+
+ let expr_parent = self.tcx.hir().get_parent_node(*expr_hir_id);
+ let hir = self.tcx.hir().find(expr_parent);
+ let closure_params_len = closure_fn_decl.inputs.len();
+ let (method_path, method_span, method_expr) = match (hir, closure_params_len) {
+ (Some(Node::Expr(
+ hir::Expr { node: hir::ExprKind::MethodCall(path, span, expr), .. }
+ )), 1) => (path, span, expr),
+ _ => return None
+ };
+
+ let self_ty = self.tables.borrow().node_type(method_expr[0].hir_id);
+ let self_ty = format!("{:?}", self_ty);
+ let name = method_path.ident.as_str();
+ let is_as_ref_able = (
+ self_ty.starts_with("&std::option::Option") ||
+ self_ty.starts_with("&std::result::Result") ||
+ self_ty.starts_with("std::option::Option") ||
+ self_ty.starts_with("std::result::Result")
+ ) && (name == "map" || name == "and_then");
+ match (is_as_ref_able, self.sess().source_map().span_to_snippet(*method_span)) {
+ (true, Ok(src)) => {
+ let suggestion = format!("as_ref().{}", src);
+ Some((*method_span, "consider using `as_ref` instead", suggestion))
+ },
+ _ => None
}
- None
}
crate fn is_hir_id_from_struct_pattern_shorthand_field(
check_packed(tcx, span, def_id);
}
-fn check_opaque<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, span: Span) {
+fn check_opaque<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+ span: Span,
+ origin: &hir::ExistTyOrigin
+) {
if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) {
- let mut err = struct_span_err!(
- tcx.sess, span, E0720,
- "opaque type expands to a recursive type",
- );
- err.span_label(span, "expands to a recursive type");
- if let ty::Opaque(..) = partially_expanded_type.sty {
- err.note("type resolves to itself");
+ if let hir::ExistTyOrigin::AsyncFn = origin {
+ struct_span_err!(
+ tcx.sess, span, E0733,
+ "recursion in an `async fn` requires boxing",
+ )
+ .span_label(span, "an `async fn` cannot invoke itself directly")
+ .note("a recursive `async fn` must be rewritten to return a boxed future.")
+ .emit();
} else {
- err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ let mut err = struct_span_err!(
+ tcx.sess, span, E0720,
+ "opaque type expands to a recursive type",
+ );
+ err.span_label(span, "expands to a recursive type");
+ if let ty::Opaque(..) = partially_expanded_type.sty {
+ err.note("type resolves to itself");
+ } else {
+ err.note(&format!("expanded type is `{}`", partially_expanded_type));
+ }
+ err.emit();
}
- err.emit();
}
}
hir::ItemKind::Union(..) => {
check_union(tcx, it.hir_id, it.span);
}
- hir::ItemKind::Existential(..) => {
+ hir::ItemKind::Existential(hir::ExistTy{origin, ..}) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
let substs = InternalSubsts::identity_for_item(tcx, def_id);
- check_opaque(tcx, def_id, substs, it.span);
+ check_opaque(tcx, def_id, substs, it.span, &origin);
}
hir::ItemKind::Ty(..) => {
let def_id = tcx.hir().local_def_id(it.hir_id);
);
let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg);
err.span_label(sp, &msg);
- if let &[ref start.., ref end] = &variant_spans[..] {
+ if let &[.., ref end] = &variant_spans[..] {
+ // FIXME: Ping cfg(bootstrap) -- Use `ref start @ ..` with new bootstrap compiler.
+ let start = &variant_spans[..variant_spans.len() - 1];
for variant_span in start {
err.span_label(*variant_span, "");
}
// ignore-tidy-filelength
-#![allow(non_snake_case)]
-
register_long_diagnostics! {
E0023: r##"
let r = &[1, 2];
match r {
- &[a, b, c, rest..] => { // error: pattern requires at least 3
- // elements but array has 2
+ &[a, b, c, rest @ ..] => { // error: pattern requires at least 3
+ // elements but array has 2
println!("a={}, b={}, c={} rest={:?}", a, b, c, rest);
}
}
let r = &[1, 2, 3, 4, 5];
match r {
- &[a, b, c, rest..] => { // ok!
+ &[a, b, c, rest @ ..] => { // ok!
// prints `a=1, b=2, c=3 rest=[4, 5]`
println!("a={}, b={}, c={} rest={:?}", a, b, c, rest);
}
```
"##,
+E0733: r##"
+Recursion in an `async fn` requires boxing. For example, this will not compile:
+
+```edition2018,compile_fail,E0733
+#![feature(async_await)]
+async fn foo(n: usize) {
+ if n > 0 {
+ foo(n - 1).await;
+ }
+}
+```
+
+To achieve async recursion, the `async fn` needs to be desugared
+such that the `Future` is explicit in the return type:
+
+```edition2018,compile_fail,E0720
+# #![feature(async_await)]
+use std::future::Future;
+fn foo_desugered(n: usize) -> impl Future<Output = ()> {
+ async move {
+ if n > 0 {
+ foo_desugered(n - 1).await;
+ }
+ }
+}
+```
+
+Finally, the future is wrapped in a pinned box:
+
+```edition2018
+# #![feature(async_await)]
+use std::future::Future;
+use std::pin::Pin;
+fn foo_recursive(n: usize) -> Pin<Box<dyn Future<Output = ()>>> {
+ Box::pin(async move {
+ if n > 0 {
+ foo_recursive(n - 1).await;
+ }
+ })
}
+```
+
+The `Box<...>` ensures that the result is of known size,
+and the pin is required to keep it in the same place in memory.
+"##,
+
+} // (end of detailed error messages)
register_diagnostics! {
// E0035, merged into E0087/E0089
#![recursion_limit="256"]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
[dependencies]
pulldown-cmark = { version = "0.5.3", default-features = false }
-minifier = "0.0.30"
+minifier = "0.0.33"
rayon = { version = "0.2.0", package = "rustc-rayon" }
tempfile = "3"
parking_lot = "0.7"
{
let tokens: Tokens<'_> = simple_minify(contents)
.into_iter()
- .filter(|f| {
+ .filter(|(f, next)| {
// We keep backlines.
- minifier::js::clean_token_except(f, &|c: &Token<'_>| {
+ minifier::js::clean_token_except(f, next, &|c: &Token<'_>| {
c.get_char() != Some(ReservedChar::Backline)
})
})
- .map(|f| {
+ .map(|(f, _)| {
minifier::js::replace_token_with(f, &|t: &Token<'_>| {
match *t {
Token::Keyword(Keyword::Null) => Some(Token::Other("N")),
// shouldn't be aggregated.
|tokens, pos| {
pos < 2 ||
- !tokens[pos - 1].is_char(ReservedChar::OpenBracket) ||
+ !tokens[pos - 1].eq_char(ReservedChar::OpenBracket) ||
tokens[pos - 2].get_other() != Some("searchIndex")
}
)
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/")]
html_playground_url = "https://play.rust-lang.org/",
test(attr(allow(unused_variables), deny(warnings))))]
-#![deny(rust_2018_idioms)]
-
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(specialization)]
# requires rebuilding the standard library to use it.
wasm_syscall = []
-# An off-by-default features to enable libstd to assume that wasm-bindgen is in
-# the environment for hooking up some thread-related information like the
-# current thread id and accessing/getting the current thread's TCB
-wasm-bindgen-threads = []
-
# Enable std_detect default features for stdarch/crates/std_detect:
# https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
std_detect_file_io = []
-#![deny(warnings)]
-
use std::env;
fn main() {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.done_first {
match self.first.read(buf)? {
- 0 if buf.len() != 0 => self.done_first = true,
+ 0 if !buf.is_empty() => self.done_first = true,
n => return Ok(n),
}
}
fn fill_buf(&mut self) -> Result<&[u8]> {
if !self.done_first {
match self.first.fill_buf()? {
- buf if buf.len() == 0 => { self.done_first = true; }
+ buf if buf.is_empty() => { self.done_first = true; }
buf => return Ok(buf),
}
}
#![warn(missing_docs)]
#![warn(missing_debug_implementations)]
#![deny(intra_doc_link_resolution_failure)] // rustdoc is run without -D warnings
-
-#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]
+#![allow(unused_lifetimes)]
// Tell the compiler to link to either panic_abort or panic_unwind
#![needs_panic_runtime]
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
libc::calloc(layout.size(), 1) as *mut u8
} else {
- let ptr = self.alloc(layout.clone());
+ let ptr = self.alloc(layout);
if !ptr.is_null() {
ptr::write_bytes(ptr, 0, layout.size());
}
if self.get_gid().is_some() ||
self.get_uid().is_some() ||
self.env_saw_path() ||
- self.get_closures().len() != 0 {
+ !self.get_closures().is_empty() {
return Ok(None)
}
pub mod thread;
#[path = "../wasm/thread_local.rs"]
pub mod thread_local;
+#[path = "../wasm/fast_thread_local.rs"]
+pub mod fast_thread_local;
pub mod time;
pub mod ext;
--- /dev/null
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+pub unsafe fn register_dtor(_t: *mut u8, _dtor: unsafe extern fn(*mut u8)) {
+ // FIXME: right now there is no concept of "thread exit", but this is likely
+ // going to show up at some point in the form of an exported symbol that the
+ // wasm runtime is oging to be expected to call. For now we basically just
+ // ignore the arguments, but if such a function starts to exist it will
+ // likely look like the OSX implementation in `unix/fast_thread_local.rs`
+}
pub mod thread;
pub mod time;
pub mod stdio;
+pub mod thread_local;
+pub mod fast_thread_local;
pub use crate::sys_common::os_str_bytes as os_str;
pub mod mutex;
#[path = "rwlock_atomics.rs"]
pub mod rwlock;
- #[path = "thread_local_atomics.rs"]
- pub mod thread_local;
} else {
pub mod condvar;
pub mod mutex;
pub mod rwlock;
- pub mod thread_local;
}
}
pub unsafe fn init() -> Option<Guard> { None }
}
-cfg_if::cfg_if! {
- if #[cfg(all(target_feature = "atomics", feature = "wasm-bindgen-threads"))] {
- #[link(wasm_import_module = "__wbindgen_thread_xform__")]
- extern {
- fn __wbindgen_current_id() -> u32;
- fn __wbindgen_tcb_get() -> u32;
- fn __wbindgen_tcb_set(ptr: u32);
+// This is only used by atomics primitives when the `atomics` feature is
+// enabled. In that mode we currently just use our own thread-local to store our
+// current thread's ID, and then we lazily initialize it to something allocated
+// from a global counter.
+#[cfg(target_feature = "atomics")]
+pub fn my_id() -> u32 {
+ use crate::sync::atomic::{AtomicU32, Ordering::SeqCst};
+
+ static NEXT_ID: AtomicU32 = AtomicU32::new(0);
+
+ #[thread_local]
+ static mut MY_ID: u32 = 0;
+
+ unsafe {
+ // If our thread ID isn't set yet then we need to allocate one. Do so
+ // with with a simple "atomically add to a global counter" strategy.
+ // This strategy doesn't handled what happens when the counter
+ // overflows, however, so just abort everything once the counter
+ // overflows and eventually we could have some sort of recycling scheme
+ // (or maybe this is all totally irrelevant by that point!). In any case
+ // though we're using a CAS loop instead of a `fetch_add` to ensure that
+ // the global counter never overflows.
+ if MY_ID == 0 {
+ let mut cur = NEXT_ID.load(SeqCst);
+ MY_ID = loop {
+ let next = cur.checked_add(1).unwrap_or_else(|| {
+ crate::arch::wasm32::unreachable()
+ });
+ match NEXT_ID.compare_exchange(cur, next, SeqCst, SeqCst) {
+ Ok(_) => break next,
+ Err(i) => cur = i,
+ }
+ };
}
- pub fn my_id() -> u32 {
- unsafe { __wbindgen_current_id() }
- }
-
- // These are currently only ever used in `thread_local_atomics.rs`, if
- // you'd like to use them be sure to update that and make sure everyone
- // agrees what's what.
- pub fn tcb_get() -> *mut u8 {
- use crate::mem;
- assert_eq!(mem::size_of::<*mut u8>(), mem::size_of::<u32>());
- unsafe { __wbindgen_tcb_get() as *mut u8 }
- }
-
- pub fn tcb_set(ptr: *mut u8) {
- unsafe { __wbindgen_tcb_set(ptr as u32); }
- }
-
- // FIXME: still need something for hooking exiting a thread to free
- // data...
-
- } else if #[cfg(target_feature = "atomics")] {
- pub fn my_id() -> u32 {
- panic!("thread ids not implemented on wasm with atomics yet")
- }
-
- pub fn tcb_get() -> *mut u8 {
- panic!("thread local data not implemented on wasm with atomics yet")
- }
-
- pub fn tcb_set(_ptr: *mut u8) {
- panic!("thread local data not implemented on wasm with atomics yet")
- }
- } else {
- // stubbed out because no functions actually access these intrinsics
- // unless atomics are enabled
+ MY_ID
}
}
-use crate::boxed::Box;
-use crate::ptr;
-
pub type Key = usize;
-struct Allocated {
- value: *mut u8,
- dtor: Option<unsafe extern fn(*mut u8)>,
-}
-
#[inline]
-pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
- Box::into_raw(Box::new(Allocated {
- value: ptr::null_mut(),
- dtor,
- })) as usize
+pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ panic!("should not be used on the wasm target");
}
#[inline]
-pub unsafe fn set(key: Key, value: *mut u8) {
- (*(key as *mut Allocated)).value = value;
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+ panic!("should not be used on the wasm target");
}
#[inline]
-pub unsafe fn get(key: Key) -> *mut u8 {
- (*(key as *mut Allocated)).value
+pub unsafe fn get(_key: Key) -> *mut u8 {
+ panic!("should not be used on the wasm target");
}
#[inline]
-pub unsafe fn destroy(key: Key) {
- let key = Box::from_raw(key as *mut Allocated);
- if let Some(f) = key.dtor {
- f(key.value);
- }
+pub unsafe fn destroy(_key: Key) {
+ panic!("should not be used on the wasm target");
}
#[inline]
pub fn requires_synchronized_create() -> bool {
- false
+ panic!("should not be used on the wasm target");
}
+++ /dev/null
-use crate::sys::thread;
-use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
-
-const MAX_KEYS: usize = 128;
-static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
-
-struct ThreadControlBlock {
- keys: [*mut u8; MAX_KEYS],
-}
-
-impl ThreadControlBlock {
- fn new() -> ThreadControlBlock {
- ThreadControlBlock {
- keys: [core::ptr::null_mut(); MAX_KEYS],
- }
- }
-
- fn get() -> *mut ThreadControlBlock {
- let ptr = thread::tcb_get();
- if !ptr.is_null() {
- return ptr as *mut ThreadControlBlock
- }
- let tcb = Box::into_raw(Box::new(ThreadControlBlock::new()));
- thread::tcb_set(tcb as *mut u8);
- tcb
- }
-}
-
-pub type Key = usize;
-
-pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
- drop(dtor); // FIXME: need to figure out how to hook thread exit to run this
- let key = NEXT_KEY.fetch_add(1, SeqCst);
- if key >= MAX_KEYS {
- NEXT_KEY.store(MAX_KEYS, SeqCst);
- panic!("cannot allocate space for more TLS keys");
- }
- // offset by 1 so we never hand out 0. This is currently required by
- // `sys_common/thread_local.rs` where it can't cope with keys of value 0
- // because it messes up the atomic management.
- return key + 1
-}
-
-pub unsafe fn set(key: Key, value: *mut u8) {
- (*ThreadControlBlock::get()).keys[key - 1] = value;
-}
-
-pub unsafe fn get(key: Key) -> *mut u8 {
- (*ThreadControlBlock::get()).keys[key - 1]
-}
-
-pub unsafe fn destroy(_key: Key) {
- // FIXME: should implement this somehow, this isn't typically called but it
- // can be called if two threads race to initialize a TLS slot and one ends
- // up not being needed.
-}
-
-#[inline]
-pub fn requires_synchronized_create() -> bool {
- false
-}
/// This function may fail because measurements taken earlier are not
/// guaranteed to always be before later measurements (due to anomalies such
/// as the system clock being adjusted either forwards or backwards).
+ /// [`Instant`] can be used to measure elapsed time without this risk of failure.
///
/// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
/// the amount of time elapsed from the specified measurement to this one.
/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
/// [`Duration`]: ../../std/time/struct.Duration.html
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Instant`]: ../../std/time/struct.Instant.html
///
/// # Examples
///
///
/// let sys_time = SystemTime::now();
/// let difference = sys_time.duration_since(sys_time)
- /// .expect("SystemTime::duration_since failed");
+ /// .expect("Clock may have gone backwards");
/// println!("{:?}", difference);
/// ```
#[stable(feature = "time2", since = "1.8.0")]
self.0.sub_time(&earlier.0).map_err(SystemTimeError)
}
- /// Returns the amount of time elapsed since this system time was created.
+ /// Returns the difference between the clock time when this
+ /// system time was created, and the current clock time.
///
/// This function may fail as the underlying system clock is susceptible to
/// drift and updates (e.g., the system clock could go backwards), so this
/// returned where the duration represents the amount of time elapsed from
/// this time measurement to the current time.
///
+ /// To measure elapsed time reliably, use [`Instant`] instead.
+ ///
/// Returns an [`Err`] if `self` is later than the current system time, and
/// the error contains how far from the current system time `self` is.
///
/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
/// [`Duration`]: ../../std/time/struct.Duration.html
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Instant`]: ../../std/time/struct.Instant.html
///
/// # Examples
///
}
impl Pat {
+ /// Attempt reparsing the pattern as a type.
+ /// This is intended for use by diagnostics.
pub(super) fn to_ty(&self) -> Option<P<Ty>> {
let node = match &self.node {
+ // In a type expression `_` is an inference variable.
PatKind::Wild => TyKind::Infer,
+ // An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
PatKind::Ident(BindingMode::ByValue(Mutability::Immutable), ident, None) => {
TyKind::Path(None, Path::from_ident(*ident))
}
PatKind::Path(qself, path) => TyKind::Path(qself.clone(), path.clone()),
PatKind::Mac(mac) => TyKind::Mac(mac.clone()),
+ // `&mut? P` can be reinterpreted as `&mut? T` where `T` is `P` reparsed as a type.
PatKind::Ref(pat, mutbl) => pat
.to_ty()
.map(|ty| TyKind::Rptr(None, MutTy { ty, mutbl: *mutbl }))?,
- PatKind::Slice(pats, None, _) if pats.len() == 1 => {
- pats[0].to_ty().map(TyKind::Slice)?
- }
- PatKind::Tuple(pats, None) => {
+ // A slice/array pattern `[P]` can be reparsed as `[T]`, an unsized array,
+ // when `P` can be reparsed as a type `T`.
+ PatKind::Slice(pats) if pats.len() == 1 => pats[0].to_ty().map(TyKind::Slice)?,
+ // A tuple pattern `(P0, .., Pn)` can be reparsed as `(T0, .., Tn)`
+ // assuming `T0` to `Tn` are all syntactically valid as types.
+ PatKind::Tuple(pats) => {
let mut tys = Vec::with_capacity(pats.len());
// FIXME(#48994) - could just be collected into an Option<Vec>
for pat in pats {
return false;
}
- match self.node {
- PatKind::Ident(_, _, Some(ref p)) => p.walk(it),
- PatKind::Struct(_, ref fields, _) => fields.iter().all(|field| field.node.pat.walk(it)),
- PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
+ match &self.node {
+ PatKind::Ident(_, _, Some(p)) => p.walk(it),
+ PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.node.pat.walk(it)),
+ PatKind::TupleStruct(_, s) | PatKind::Tuple(s) | PatKind::Slice(s) => {
s.iter().all(|p| p.walk(it))
}
- PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => s.walk(it),
- PatKind::Slice(ref before, ref slice, ref after) => {
- before.iter().all(|p| p.walk(it))
- && slice.iter().all(|p| p.walk(it))
- && after.iter().all(|p| p.walk(it))
- }
+ PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
PatKind::Wild
+ | PatKind::Rest
| PatKind::Lit(_)
| PatKind::Range(..)
| PatKind::Ident(..)
| PatKind::Mac(_) => true,
}
}
+
+ /// Is this a `..` pattern?
+ pub fn is_rest(&self) -> bool {
+ match self.node {
+ PatKind::Rest => true,
+ _ => false,
+ }
+ }
}
/// A single field in a struct pattern
Struct(Path, Vec<Spanned<FieldPat>>, /* recovered */ bool),
/// A tuple struct/variant pattern (`Variant(x, y, .., z)`).
- /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
- /// `0 <= position <= subpats.len()`.
- TupleStruct(Path, Vec<P<Pat>>, Option<usize>),
+ TupleStruct(Path, Vec<P<Pat>>),
/// A possibly qualified path pattern.
/// Unqualified path patterns `A::B::C` can legally refer to variants, structs, constants
Path(Option<QSelf>, Path),
/// A tuple pattern (`(a, b)`).
- /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
- /// `0 <= position <= subpats.len()`.
- Tuple(Vec<P<Pat>>, Option<usize>),
+ Tuple(Vec<P<Pat>>),
/// A `box` pattern.
Box(P<Pat>),
/// A range pattern (e.g., `1...2`, `1..=2` or `1..2`).
Range(P<Expr>, P<Expr>, Spanned<RangeEnd>),
- /// `[a, b, ..i, y, z]` is represented as:
- /// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
- Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+ /// A slice pattern `[a, b, c]`.
+ Slice(Vec<P<Pat>>),
+
+ /// A rest pattern `..`.
+ ///
+ /// Syntactically it is valid anywhere.
+ ///
+ /// Semantically however, it only has meaning immediately inside:
+ /// - a slice pattern: `[a, .., b]`,
+ /// - a binding pattern immediately inside a slice pattern: `[a, r @ ..]`,
+ /// - a tuple pattern: `(a, .., b)`,
+ /// - a tuple struct/variant pattern: `$path(a, .., b)`.
+ ///
+ /// In all of these cases, an additional restriction applies,
+ /// only one rest pattern may occur in the pattern sequences.
+ Rest,
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
Paren(P<Pat>),
pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
+ pub span: Span,
}
/// Alternative representation for `Arg`s describing `self` parameter of methods.
node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
span,
}),
+ span,
ty,
id: DUMMY_NODE_ID,
};
MacEager::items(smallvec![])
}
-#[allow(deprecated)]
pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt<'_>,
span: Span,
token_tree: &[TokenTree])
ecx.span_bug(span, &format!(
"error writing metadata for triple `{}` and crate `{}`, error: {}, \
cause: {:?}",
- target_triple, crate_name, e.description(), e.cause()
+ target_triple, crate_name, e.description(), e.source()
));
}
});
-#![allow(non_snake_case)]
-
// Error messages for EXXXX errors.
// Each message should start and end with a new line, and be wrapped to 80 characters.
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
use crate::ast::{self, Attribute, Name, PatKind};
use crate::attr::{HasAttrs, Stability, Deprecation};
-use crate::source_map::{SourceMap, Spanned, FileName, respan};
+use crate::source_map::{SourceMap, Spanned, respan};
use crate::edition::Edition;
use crate::ext::expand::{self, AstFragment, Invocation};
use crate::ext::hygiene::{ExpnId, SyntaxContext, Transparency};
use errors::{DiagnosticBuilder, DiagnosticId};
use smallvec::{smallvec, SmallVec};
-use syntax_pos::{Span, MultiSpan, DUMMY_SP};
+use syntax_pos::{FileName, Span, MultiSpan, DUMMY_SP};
use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
use rustc_data_structures::fx::FxHashMap;
}
fn pat_tuple_struct(&self, span: Span, path: ast::Path,
subpats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
- self.pat(span, PatKind::TupleStruct(path, subpats, None))
+ self.pat(span, PatKind::TupleStruct(path, subpats))
}
fn pat_struct(&self, span: Span, path: ast::Path,
field_pats: Vec<Spanned<ast::FieldPat>>) -> P<ast::Pat> {
self.pat(span, PatKind::Struct(path, field_pats, false))
}
fn pat_tuple(&self, span: Span, pats: Vec<P<ast::Pat>>) -> P<ast::Pat> {
- self.pat(span, PatKind::Tuple(pats, None))
+ self.pat(span, PatKind::Tuple(pats))
}
fn pat_some(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> {
attrs: ThinVec::default(),
id: ast::DUMMY_NODE_ID,
pat: arg_pat,
+ span,
ty,
}
}
+++ /dev/null
-use crate::attr::HasAttrs;
-use crate::ast;
-use crate::source_map::{ExpnInfo, ExpnKind};
-use crate::ext::base::{ExtCtxt, MacroKind};
-use crate::ext::build::AstBuilder;
-use crate::parse::parser::PathStyle;
-use crate::symbol::{Symbol, sym};
-use crate::errors::Applicability;
-
-use syntax_pos::Span;
-use rustc_data_structures::fx::FxHashSet;
-
-pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
- let mut result = Vec::new();
- attrs.retain(|attr| {
- if attr.path != sym::derive {
- return true;
- }
- if !attr.is_meta_item_list() {
- cx.struct_span_err(attr.span, "malformed `derive` attribute input")
- .span_suggestion(
- attr.span,
- "missing traits to be derived",
- "#[derive(Trait1, Trait2, ...)]".to_owned(),
- Applicability::HasPlaceholders,
- ).emit();
- return false;
- }
-
- match attr.parse_list(cx.parse_sess,
- |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
- Ok(traits) => {
- result.extend(traits);
- true
- }
- Err(mut e) => {
- e.emit();
- false
- }
- }
- });
- result
-}
-
-pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T)
- where T: HasAttrs,
-{
- let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
- for (i, path) in traits.iter().enumerate() {
- if i > 0 {
- pretty_name.push_str(", ");
- }
- pretty_name.push_str(&path.to_string());
- names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
- }
-
- let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
- ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
- cx.parse_sess.edition, cx.allow_derive_markers.clone(),
- ));
-
- item.visit_attrs(|attrs| {
- if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
- let meta = cx.meta_word(span, sym::structural_match);
- attrs.push(cx.attribute(span, meta));
- }
- if names.contains(&sym::Copy) {
- let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
- attrs.push(cx.attribute(span, meta));
- }
- });
-}
use crate::source_map::{dummy_spanned, respan};
use crate::config::StripUnconfigured;
use crate::ext::base::*;
-use crate::ext::derive::{add_derived_markers, collect_derives};
+use crate::ext::proc_macro::{add_derived_markers, collect_derives};
use crate::ext::hygiene::{ExpnId, SyntaxContext, ExpnInfo, ExpnKind};
use crate::ext::placeholders::{placeholder, PlaceholderExpander};
use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
--- /dev/null
+use crate::ast::{self, ItemKind, Attribute, Mac};
+use crate::attr::{mark_used, mark_known, HasAttrs};
+use crate::errors::{Applicability, FatalError};
+use crate::ext::base::{self, *};
+use crate::ext::build::AstBuilder;
+use crate::ext::proc_macro_server;
+use crate::parse::{self, token};
+use crate::parse::parser::PathStyle;
+use crate::symbol::{sym, Symbol};
+use crate::tokenstream::{self, TokenStream};
+use crate::visit::Visitor;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sync::Lrc;
+use syntax_pos::hygiene::{ExpnInfo, ExpnKind};
+use syntax_pos::{Span, DUMMY_SP};
+
+const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
+ proc_macro::bridge::server::SameThread;
+
+pub struct BangProcMacro {
+ pub client: proc_macro::bridge::client::Client<
+ fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
+ >,
+}
+
+impl base::ProcMacro for BangProcMacro {
+ fn expand<'cx>(&self,
+ ecx: &'cx mut ExtCtxt<'_>,
+ span: Span,
+ input: TokenStream)
+ -> TokenStream {
+ let server = proc_macro_server::Rustc::new(ecx);
+ match self.client.run(&EXEC_STRATEGY, server, input) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let msg = "proc macro panicked";
+ let mut err = ecx.struct_span_fatal(span, msg);
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
+ }
+
+ err.emit();
+ FatalError.raise();
+ }
+ }
+ }
+}
+
+pub struct AttrProcMacro {
+ pub client: proc_macro::bridge::client::Client<
+ fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
+ >,
+}
+
+impl base::AttrProcMacro for AttrProcMacro {
+ fn expand<'cx>(&self,
+ ecx: &'cx mut ExtCtxt<'_>,
+ span: Span,
+ annotation: TokenStream,
+ annotated: TokenStream)
+ -> TokenStream {
+ let server = proc_macro_server::Rustc::new(ecx);
+ match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let msg = "custom attribute panicked";
+ let mut err = ecx.struct_span_fatal(span, msg);
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
+ }
+
+ err.emit();
+ FatalError.raise();
+ }
+ }
+ }
+}
+
+pub struct ProcMacroDerive {
+ pub client: proc_macro::bridge::client::Client<
+ fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
+ >,
+ pub attrs: Vec<ast::Name>,
+}
+
+impl MultiItemModifier for ProcMacroDerive {
+ fn expand(&self,
+ ecx: &mut ExtCtxt<'_>,
+ span: Span,
+ _meta_item: &ast::MetaItem,
+ item: Annotatable)
+ -> Vec<Annotatable> {
+ let item = match item {
+ Annotatable::Item(item) => item,
+ Annotatable::ImplItem(_) |
+ Annotatable::TraitItem(_) |
+ Annotatable::ForeignItem(_) |
+ Annotatable::Stmt(_) |
+ Annotatable::Expr(_) => {
+ ecx.span_err(span, "proc-macro derives may only be \
+ applied to a struct, enum, or union");
+ return Vec::new()
+ }
+ };
+ match item.node {
+ ItemKind::Struct(..) |
+ ItemKind::Enum(..) |
+ ItemKind::Union(..) => {},
+ _ => {
+ ecx.span_err(span, "proc-macro derives may only be \
+ applied to a struct, enum, or union");
+ return Vec::new()
+ }
+ }
+
+ // Mark attributes as known, and used.
+ MarkAttrs(&self.attrs).visit_item(&item);
+
+ let token = token::Interpolated(Lrc::new(token::NtItem(item)));
+ let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
+
+ let server = proc_macro_server::Rustc::new(ecx);
+ let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
+ Ok(stream) => stream,
+ Err(e) => {
+ let msg = "proc-macro derive panicked";
+ let mut err = ecx.struct_span_fatal(span, msg);
+ if let Some(s) = e.as_str() {
+ err.help(&format!("message: {}", s));
+ }
+
+ err.emit();
+ FatalError.raise();
+ }
+ };
+
+ let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
+ let msg = "proc-macro derive produced unparseable tokens";
+
+ let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
+ let mut items = vec![];
+
+ loop {
+ match parser.parse_item() {
+ Ok(None) => break,
+ Ok(Some(item)) => {
+ items.push(Annotatable::Item(item))
+ }
+ Err(mut err) => {
+ // FIXME: handle this better
+ err.cancel();
+ ecx.struct_span_fatal(span, msg).emit();
+ FatalError.raise();
+ }
+ }
+ }
+
+
+ // fail if there have been errors emitted
+ if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
+ ecx.struct_span_fatal(span, msg).emit();
+ FatalError.raise();
+ }
+
+ items
+ }
+}
+
+struct MarkAttrs<'a>(&'a [ast::Name]);
+
+impl<'a> Visitor<'a> for MarkAttrs<'a> {
+ fn visit_attribute(&mut self, attr: &Attribute) {
+ if let Some(ident) = attr.ident() {
+ if self.0.contains(&ident.name) {
+ mark_used(attr);
+ mark_known(attr);
+ }
+ }
+ }
+
+ fn visit_mac(&mut self, _mac: &Mac) {}
+}
+
+pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
+ [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
+ .iter().any(|kind| attr.check_name(*kind))
+}
+
+crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
+ let mut result = Vec::new();
+ attrs.retain(|attr| {
+ if attr.path != sym::derive {
+ return true;
+ }
+ if !attr.is_meta_item_list() {
+ cx.struct_span_err(attr.span, "malformed `derive` attribute input")
+ .span_suggestion(
+ attr.span,
+ "missing traits to be derived",
+ "#[derive(Trait1, Trait2, ...)]".to_owned(),
+ Applicability::HasPlaceholders,
+ ).emit();
+ return false;
+ }
+
+ match attr.parse_list(cx.parse_sess,
+ |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
+ Ok(traits) => {
+ result.extend(traits);
+ true
+ }
+ Err(mut e) => {
+ e.emit();
+ false
+ }
+ }
+ });
+ result
+}
+
+crate fn add_derived_markers<T: HasAttrs>(
+ cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T
+) {
+ let (mut names, mut pretty_name) = (FxHashSet::default(), String::new());
+ for (i, path) in traits.iter().enumerate() {
+ if i > 0 {
+ pretty_name.push_str(", ");
+ }
+ pretty_name.push_str(&path.to_string());
+ names.insert(unwrap_or!(path.segments.get(0), continue).ident.name);
+ }
+
+ let span = span.fresh_expansion(cx.current_expansion.id, ExpnInfo::allow_unstable(
+ ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span,
+ cx.parse_sess.edition, cx.allow_derive_markers.clone(),
+ ));
+
+ item.visit_attrs(|attrs| {
+ if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
+ let meta = cx.meta_word(span, sym::structural_match);
+ attrs.push(cx.attribute(span, meta));
+ }
+ if names.contains(&sym::Copy) {
+ let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
+ attrs.push(cx.attribute(span, meta));
+ }
+ });
+}
--- /dev/null
+use crate::ast;
+use crate::ext::base::ExtCtxt;
+use crate::parse::{self, token, ParseSess};
+use crate::parse::lexer::comments;
+use crate::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
+
+use errors::{Diagnostic, DiagnosticBuilder};
+use rustc_data_structures::sync::Lrc;
+use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
+use syntax_pos::hygiene::{SyntaxContext, Transparency};
+use syntax_pos::symbol::{kw, sym, Symbol};
+
+use proc_macro::{Delimiter, Level, LineColumn, Spacing};
+use proc_macro::bridge::{server, TokenTree};
+use std::{ascii, panic};
+use std::ops::Bound;
+
+trait FromInternal<T> {
+ fn from_internal(x: T) -> Self;
+}
+
+trait ToInternal<T> {
+ fn to_internal(self) -> T;
+}
+
+impl FromInternal<token::DelimToken> for Delimiter {
+ fn from_internal(delim: token::DelimToken) -> Delimiter {
+ match delim {
+ token::Paren => Delimiter::Parenthesis,
+ token::Brace => Delimiter::Brace,
+ token::Bracket => Delimiter::Bracket,
+ token::NoDelim => Delimiter::None,
+ }
+ }
+}
+
+impl ToInternal<token::DelimToken> for Delimiter {
+ fn to_internal(self) -> token::DelimToken {
+ match self {
+ Delimiter::Parenthesis => token::Paren,
+ Delimiter::Brace => token::Brace,
+ Delimiter::Bracket => token::Bracket,
+ Delimiter::None => token::NoDelim,
+ }
+ }
+}
+
+impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
+ for TokenTree<Group, Punct, Ident, Literal>
+{
+ fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
+ -> Self {
+ use crate::parse::token::*;
+
+ let joint = is_joint == Joint;
+ let Token { kind, span } = match tree {
+ tokenstream::TokenTree::Delimited(span, delim, tts) => {
+ let delimiter = Delimiter::from_internal(delim);
+ return TokenTree::Group(Group {
+ delimiter,
+ stream: tts.into(),
+ span,
+ });
+ }
+ tokenstream::TokenTree::Token(token) => token,
+ };
+
+ macro_rules! tt {
+ ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
+ TokenTree::$ty(self::$ty {
+ $($field $(: $value)*,)+
+ span,
+ })
+ );
+ ($ty:ident::$method:ident($($value:expr),*)) => (
+ TokenTree::$ty(self::$ty::$method($($value,)* span))
+ );
+ }
+ macro_rules! op {
+ ($a:expr) => {
+ tt!(Punct::new($a, joint))
+ };
+ ($a:expr, $b:expr) => {{
+ stack.push(tt!(Punct::new($b, joint)));
+ tt!(Punct::new($a, true))
+ }};
+ ($a:expr, $b:expr, $c:expr) => {{
+ stack.push(tt!(Punct::new($c, joint)));
+ stack.push(tt!(Punct::new($b, true)));
+ tt!(Punct::new($a, true))
+ }};
+ }
+
+ match kind {
+ Eq => op!('='),
+ Lt => op!('<'),
+ Le => op!('<', '='),
+ EqEq => op!('=', '='),
+ Ne => op!('!', '='),
+ Ge => op!('>', '='),
+ Gt => op!('>'),
+ AndAnd => op!('&', '&'),
+ OrOr => op!('|', '|'),
+ Not => op!('!'),
+ Tilde => op!('~'),
+ BinOp(Plus) => op!('+'),
+ BinOp(Minus) => op!('-'),
+ BinOp(Star) => op!('*'),
+ BinOp(Slash) => op!('/'),
+ BinOp(Percent) => op!('%'),
+ BinOp(Caret) => op!('^'),
+ BinOp(And) => op!('&'),
+ BinOp(Or) => op!('|'),
+ BinOp(Shl) => op!('<', '<'),
+ BinOp(Shr) => op!('>', '>'),
+ BinOpEq(Plus) => op!('+', '='),
+ BinOpEq(Minus) => op!('-', '='),
+ BinOpEq(Star) => op!('*', '='),
+ BinOpEq(Slash) => op!('/', '='),
+ BinOpEq(Percent) => op!('%', '='),
+ BinOpEq(Caret) => op!('^', '='),
+ BinOpEq(And) => op!('&', '='),
+ BinOpEq(Or) => op!('|', '='),
+ BinOpEq(Shl) => op!('<', '<', '='),
+ BinOpEq(Shr) => op!('>', '>', '='),
+ At => op!('@'),
+ Dot => op!('.'),
+ DotDot => op!('.', '.'),
+ DotDotDot => op!('.', '.', '.'),
+ DotDotEq => op!('.', '.', '='),
+ Comma => op!(','),
+ Semi => op!(';'),
+ Colon => op!(':'),
+ ModSep => op!(':', ':'),
+ RArrow => op!('-', '>'),
+ LArrow => op!('<', '-'),
+ FatArrow => op!('=', '>'),
+ Pound => op!('#'),
+ Dollar => op!('$'),
+ Question => op!('?'),
+ SingleQuote => op!('\''),
+
+ Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
+ Ident(name, is_raw) => tt!(Ident::new(name, is_raw)),
+ Lifetime(name) => {
+ let ident = ast::Ident::new(name, span).without_first_quote();
+ stack.push(tt!(Ident::new(ident.name, false)));
+ tt!(Punct::new('\'', true))
+ }
+ Literal(lit) => tt!(Literal { lit }),
+ DocComment(c) => {
+ let style = comments::doc_comment_style(&c.as_str());
+ let stripped = comments::strip_doc_comment_decoration(&c.as_str());
+ let mut escaped = String::new();
+ for ch in stripped.chars() {
+ escaped.extend(ch.escape_debug());
+ }
+ let stream = vec![
+ Ident(sym::doc, false),
+ Eq,
+ TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
+ ]
+ .into_iter()
+ .map(|kind| tokenstream::TokenTree::token(kind, span))
+ .collect();
+ stack.push(TokenTree::Group(Group {
+ delimiter: Delimiter::Bracket,
+ stream,
+ span: DelimSpan::from_single(span),
+ }));
+ if style == ast::AttrStyle::Inner {
+ stack.push(tt!(Punct::new('!', false)));
+ }
+ tt!(Punct::new('#', false))
+ }
+
+ Interpolated(nt) => {
+ let stream = nt.to_tokenstream(sess, span);
+ TokenTree::Group(Group {
+ delimiter: Delimiter::None,
+ stream,
+ span: DelimSpan::from_single(span),
+ })
+ }
+
+ OpenDelim(..) | CloseDelim(..) => unreachable!(),
+ Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
+ }
+ }
+}
+
+impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
+ fn to_internal(self) -> TokenStream {
+ use crate::parse::token::*;
+
+ let (ch, joint, span) = match self {
+ TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
+ TokenTree::Group(Group {
+ delimiter,
+ stream,
+ span,
+ }) => {
+ return tokenstream::TokenTree::Delimited(
+ span,
+ delimiter.to_internal(),
+ stream.into(),
+ )
+ .into();
+ }
+ TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
+ return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
+ }
+ TokenTree::Literal(self::Literal {
+ lit: token::Lit { kind: token::Integer, symbol, suffix },
+ span,
+ }) if symbol.as_str().starts_with("-") => {
+ let minus = BinOp(BinOpToken::Minus);
+ let symbol = Symbol::intern(&symbol.as_str()[1..]);
+ let integer = TokenKind::lit(token::Integer, symbol, suffix);
+ let a = tokenstream::TokenTree::token(minus, span);
+ let b = tokenstream::TokenTree::token(integer, span);
+ return vec![a, b].into_iter().collect();
+ }
+ TokenTree::Literal(self::Literal {
+ lit: token::Lit { kind: token::Float, symbol, suffix },
+ span,
+ }) if symbol.as_str().starts_with("-") => {
+ let minus = BinOp(BinOpToken::Minus);
+ let symbol = Symbol::intern(&symbol.as_str()[1..]);
+ let float = TokenKind::lit(token::Float, symbol, suffix);
+ let a = tokenstream::TokenTree::token(minus, span);
+ let b = tokenstream::TokenTree::token(float, span);
+ return vec![a, b].into_iter().collect();
+ }
+ TokenTree::Literal(self::Literal { lit, span }) => {
+ return tokenstream::TokenTree::token(Literal(lit), span).into()
+ }
+ };
+
+ let kind = match ch {
+ '=' => Eq,
+ '<' => Lt,
+ '>' => Gt,
+ '!' => Not,
+ '~' => Tilde,
+ '+' => BinOp(Plus),
+ '-' => BinOp(Minus),
+ '*' => BinOp(Star),
+ '/' => BinOp(Slash),
+ '%' => BinOp(Percent),
+ '^' => BinOp(Caret),
+ '&' => BinOp(And),
+ '|' => BinOp(Or),
+ '@' => At,
+ '.' => Dot,
+ ',' => Comma,
+ ';' => Semi,
+ ':' => Colon,
+ '#' => Pound,
+ '$' => Dollar,
+ '?' => Question,
+ '\'' => SingleQuote,
+ _ => unreachable!(),
+ };
+
+ let tree = tokenstream::TokenTree::token(kind, span);
+ TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })])
+ }
+}
+
+impl ToInternal<errors::Level> for Level {
+ fn to_internal(self) -> errors::Level {
+ match self {
+ Level::Error => errors::Level::Error,
+ Level::Warning => errors::Level::Warning,
+ Level::Note => errors::Level::Note,
+ Level::Help => errors::Level::Help,
+ _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct TokenStreamIter {
+ cursor: tokenstream::Cursor,
+ stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
+}
+
+#[derive(Clone)]
+pub struct Group {
+ delimiter: Delimiter,
+ stream: TokenStream,
+ span: DelimSpan,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Punct {
+ ch: char,
+ // NB. not using `Spacing` here because it doesn't implement `Hash`.
+ joint: bool,
+ span: Span,
+}
+
+impl Punct {
+ fn new(ch: char, joint: bool, span: Span) -> Punct {
+ const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
+ '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
+ if !LEGAL_CHARS.contains(&ch) {
+ panic!("unsupported character `{:?}`", ch)
+ }
+ Punct { ch, joint, span }
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Ident {
+ sym: Symbol,
+ is_raw: bool,
+ span: Span,
+}
+
+impl Ident {
+ fn is_valid(string: &str) -> bool {
+ let mut chars = string.chars();
+ if let Some(start) = chars.next() {
+ (start == '_' || start.is_xid_start())
+ && chars.all(|cont| cont == '_' || cont.is_xid_continue())
+ } else {
+ false
+ }
+ }
+ fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident {
+ let string = sym.as_str();
+ if !Self::is_valid(&string) {
+ panic!("`{:?}` is not a valid identifier", string)
+ }
+ // Get rid of gensyms to conservatively check rawness on the string contents only.
+ if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
+ panic!("`{}` cannot be a raw identifier", string);
+ }
+ Ident { sym, is_raw, span }
+ }
+ fn dollar_crate(span: Span) -> Ident {
+ // `$crate` is accepted as an ident only if it comes from the compiler.
+ Ident { sym: kw::DollarCrate, is_raw: false, span }
+ }
+}
+
+// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
+#[derive(Clone, Debug)]
+pub struct Literal {
+ lit: token::Lit,
+ span: Span,
+}
+
+pub(crate) struct Rustc<'a> {
+ sess: &'a ParseSess,
+ def_site: Span,
+ call_site: Span,
+}
+
+impl<'a> Rustc<'a> {
+ pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
+ // No way to determine def location for a proc macro right now, so use call location.
+ let location = cx.current_expansion.id.expn_info().unwrap().call_site;
+ let to_span = |transparency| {
+ location.with_ctxt(
+ SyntaxContext::empty()
+ .apply_mark_with_transparency(cx.current_expansion.id, transparency),
+ )
+ };
+ Rustc {
+ sess: cx.parse_sess,
+ def_site: to_span(Transparency::Opaque),
+ call_site: to_span(Transparency::Transparent),
+ }
+ }
+
+ fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
+ Literal {
+ lit: token::Lit::new(kind, symbol, suffix),
+ span: server::Span::call_site(self),
+ }
+ }
+}
+
+impl server::Types for Rustc<'_> {
+ type TokenStream = TokenStream;
+ type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
+ type TokenStreamIter = TokenStreamIter;
+ type Group = Group;
+ type Punct = Punct;
+ type Ident = Ident;
+ type Literal = Literal;
+ type SourceFile = Lrc<SourceFile>;
+ type MultiSpan = Vec<Span>;
+ type Diagnostic = Diagnostic;
+ type Span = Span;
+}
+
+impl server::TokenStream for Rustc<'_> {
+ fn new(&mut self) -> Self::TokenStream {
+ TokenStream::empty()
+ }
+ fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
+ stream.is_empty()
+ }
+ fn from_str(&mut self, src: &str) -> Self::TokenStream {
+ parse::parse_stream_from_source_str(
+ FileName::proc_macro_source_code(src),
+ src.to_string(),
+ self.sess,
+ Some(self.call_site),
+ )
+ }
+ fn to_string(&mut self, stream: &Self::TokenStream) -> String {
+ stream.to_string()
+ }
+ fn from_token_tree(
+ &mut self,
+ tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
+ ) -> Self::TokenStream {
+ tree.to_internal()
+ }
+ fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
+ TokenStreamIter {
+ cursor: stream.trees(),
+ stack: vec![],
+ }
+ }
+}
+
+impl server::TokenStreamBuilder for Rustc<'_> {
+ fn new(&mut self) -> Self::TokenStreamBuilder {
+ tokenstream::TokenStreamBuilder::new()
+ }
+ fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
+ builder.push(stream);
+ }
+ fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
+ builder.build()
+ }
+}
+
+impl server::TokenStreamIter for Rustc<'_> {
+ fn next(
+ &mut self,
+ iter: &mut Self::TokenStreamIter,
+ ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
+ loop {
+ let tree = iter.stack.pop().or_else(|| {
+ let next = iter.cursor.next_with_joint()?;
+ Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
+ })?;
+ // HACK: The condition "dummy span + group with empty delimiter" represents an AST
+ // fragment approximately converted into a token stream. This may happen, for
+ // example, with inputs to proc macro attributes, including derives. Such "groups"
+ // need to flattened during iteration over stream's token trees.
+ // Eventually this needs to be removed in favor of keeping original token trees
+ // and not doing the roundtrip through AST.
+ if let TokenTree::Group(ref group) = tree {
+ if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
+ iter.cursor.append(group.stream.clone());
+ continue;
+ }
+ }
+ return Some(tree);
+ }
+ }
+}
+
+impl server::Group for Rustc<'_> {
+ fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
+ Group {
+ delimiter,
+ stream,
+ span: DelimSpan::from_single(server::Span::call_site(self)),
+ }
+ }
+ fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
+ group.delimiter
+ }
+ fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
+ group.stream.clone()
+ }
+ fn span(&mut self, group: &Self::Group) -> Self::Span {
+ group.span.entire()
+ }
+ fn span_open(&mut self, group: &Self::Group) -> Self::Span {
+ group.span.open
+ }
+ fn span_close(&mut self, group: &Self::Group) -> Self::Span {
+ group.span.close
+ }
+ fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
+ group.span = DelimSpan::from_single(span);
+ }
+}
+
+impl server::Punct for Rustc<'_> {
+ fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
+ Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
+ }
+ fn as_char(&mut self, punct: Self::Punct) -> char {
+ punct.ch
+ }
+ fn spacing(&mut self, punct: Self::Punct) -> Spacing {
+ if punct.joint {
+ Spacing::Joint
+ } else {
+ Spacing::Alone
+ }
+ }
+ fn span(&mut self, punct: Self::Punct) -> Self::Span {
+ punct.span
+ }
+ fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
+ Punct { span, ..punct }
+ }
+}
+
+impl server::Ident for Rustc<'_> {
+ fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
+ Ident::new(Symbol::intern(string), is_raw, span)
+ }
+ fn span(&mut self, ident: Self::Ident) -> Self::Span {
+ ident.span
+ }
+ fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
+ Ident { span, ..ident }
+ }
+}
+
+impl server::Literal for Rustc<'_> {
+ // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
+ fn debug(&mut self, literal: &Self::Literal) -> String {
+ format!("{:?}", literal)
+ }
+ fn integer(&mut self, n: &str) -> Self::Literal {
+ self.lit(token::Integer, Symbol::intern(n), None)
+ }
+ fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
+ self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
+ }
+ fn float(&mut self, n: &str) -> Self::Literal {
+ self.lit(token::Float, Symbol::intern(n), None)
+ }
+ fn f32(&mut self, n: &str) -> Self::Literal {
+ self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
+ }
+ fn f64(&mut self, n: &str) -> Self::Literal {
+ self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
+ }
+ fn string(&mut self, string: &str) -> Self::Literal {
+ let mut escaped = String::new();
+ for ch in string.chars() {
+ escaped.extend(ch.escape_debug());
+ }
+ self.lit(token::Str, Symbol::intern(&escaped), None)
+ }
+ fn character(&mut self, ch: char) -> Self::Literal {
+ let mut escaped = String::new();
+ escaped.extend(ch.escape_unicode());
+ self.lit(token::Char, Symbol::intern(&escaped), None)
+ }
+ fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
+ let string = bytes
+ .iter()
+ .cloned()
+ .flat_map(ascii::escape_default)
+ .map(Into::<char>::into)
+ .collect::<String>();
+ self.lit(token::ByteStr, Symbol::intern(&string), None)
+ }
+ fn span(&mut self, literal: &Self::Literal) -> Self::Span {
+ literal.span
+ }
+ fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
+ literal.span = span;
+ }
+ fn subspan(
+ &mut self,
+ literal: &Self::Literal,
+ start: Bound<usize>,
+ end: Bound<usize>,
+ ) -> Option<Self::Span> {
+ let span = literal.span;
+ let length = span.hi().to_usize() - span.lo().to_usize();
+
+ let start = match start {
+ Bound::Included(lo) => lo,
+ Bound::Excluded(lo) => lo + 1,
+ Bound::Unbounded => 0,
+ };
+
+ let end = match end {
+ Bound::Included(hi) => hi + 1,
+ Bound::Excluded(hi) => hi,
+ Bound::Unbounded => length,
+ };
+
+ // Bounds check the values, preventing addition overflow and OOB spans.
+ if start > u32::max_value() as usize
+ || end > u32::max_value() as usize
+ || (u32::max_value() - start as u32) < span.lo().to_u32()
+ || (u32::max_value() - end as u32) < span.lo().to_u32()
+ || start >= end
+ || end > length
+ {
+ return None;
+ }
+
+ let new_lo = span.lo() + BytePos::from_usize(start);
+ let new_hi = span.lo() + BytePos::from_usize(end);
+ Some(span.with_lo(new_lo).with_hi(new_hi))
+ }
+}
+
+impl server::SourceFile for Rustc<'_> {
+ fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
+ Lrc::ptr_eq(file1, file2)
+ }
+ fn path(&mut self, file: &Self::SourceFile) -> String {
+ match file.name {
+ FileName::Real(ref path) => path
+ .to_str()
+ .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
+ .to_string(),
+ _ => file.name.to_string(),
+ }
+ }
+ fn is_real(&mut self, file: &Self::SourceFile) -> bool {
+ file.is_real_file()
+ }
+}
+
+impl server::MultiSpan for Rustc<'_> {
+ fn new(&mut self) -> Self::MultiSpan {
+ vec![]
+ }
+ fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
+ spans.push(span)
+ }
+}
+
+impl server::Diagnostic for Rustc<'_> {
+ fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
+ let mut diag = Diagnostic::new(level.to_internal(), msg);
+ diag.set_span(MultiSpan::from_spans(spans));
+ diag
+ }
+ fn sub(
+ &mut self,
+ diag: &mut Self::Diagnostic,
+ level: Level,
+ msg: &str,
+ spans: Self::MultiSpan,
+ ) {
+ diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
+ }
+ fn emit(&mut self, diag: Self::Diagnostic) {
+ DiagnosticBuilder::new_diagnostic(&self.sess.span_diagnostic, diag).emit()
+ }
+}
+
+impl server::Span for Rustc<'_> {
+ fn debug(&mut self, span: Self::Span) -> String {
+ format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
+ }
+ fn def_site(&mut self) -> Self::Span {
+ self.def_site
+ }
+ fn call_site(&mut self) -> Self::Span {
+ self.call_site
+ }
+ fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
+ self.sess.source_map().lookup_char_pos(span.lo()).file
+ }
+ fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
+ span.ctxt().outer_expn_info().map(|i| i.call_site)
+ }
+ fn source(&mut self, span: Self::Span) -> Self::Span {
+ span.source_callsite()
+ }
+ fn start(&mut self, span: Self::Span) -> LineColumn {
+ let loc = self.sess.source_map().lookup_char_pos(span.lo());
+ LineColumn {
+ line: loc.line,
+ column: loc.col.to_usize(),
+ }
+ }
+ fn end(&mut self, span: Self::Span) -> LineColumn {
+ let loc = self.sess.source_map().lookup_char_pos(span.hi());
+ LineColumn {
+ line: loc.line,
+ column: loc.col.to_usize(),
+ }
+ }
+ fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
+ let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
+ let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
+
+ if self_loc.file.name != other_loc.file.name {
+ return None;
+ }
+
+ Some(first.to(second))
+ }
+ fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
+ span.with_ctxt(at.ctxt())
+ }
+ fn source_text(&mut self, span: Self::Span) -> Option<String> {
+ self.sess.source_map().span_to_snippet(span).ok()
+ }
+}
+++ /dev/null
-use crate::ast;
-use crate::ext::base::{self, *};
-use crate::ext::build::AstBuilder;
-use crate::parse::{self, token, DirectoryOwnership};
-use crate::print::pprust;
-use crate::ptr::P;
-use crate::symbol::Symbol;
-use crate::tokenstream;
-
-use smallvec::SmallVec;
-use syntax_pos::{self, Pos, Span};
-
-use std::fs;
-use std::io::ErrorKind;
-use rustc_data_structures::sync::Lrc;
-
-// These macros all relate to the file system; they either return
-// the column/row/filename of the expression, or they include
-// a given file into the current one.
-
-/// line!(): expands to the current line number
-pub fn expand_line(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- base::check_zero_tts(cx, sp, tts, "line!");
-
- let topmost = cx.expansion_cause().unwrap_or(sp);
- let loc = cx.source_map().lookup_char_pos(topmost.lo());
-
- base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
-}
-
-/* column!(): expands to the current column number */
-pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- base::check_zero_tts(cx, sp, tts, "column!");
-
- let topmost = cx.expansion_cause().unwrap_or(sp);
- let loc = cx.source_map().lookup_char_pos(topmost.lo());
-
- base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
-}
-
-/// file!(): expands to the current filename */
-/// The source_file (`loc.file`) contains a bunch more information we could spit
-/// out if we wanted.
-pub fn expand_file(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- base::check_zero_tts(cx, sp, tts, "file!");
-
- let topmost = cx.expansion_cause().unwrap_or(sp);
- let loc = cx.source_map().lookup_char_pos(topmost.lo());
- base::MacEager::expr(cx.expr_str(topmost, Symbol::intern(&loc.file.name.to_string())))
-}
-
-pub fn expand_stringify(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let s = pprust::tts_to_string(tts);
- base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
-}
-
-pub fn expand_mod(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- base::check_zero_tts(cx, sp, tts, "module_path!");
- let mod_path = &cx.current_expansion.module.mod_path;
- let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
-
- base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))
-}
-
-/// include! : parse the given file as an expr
-/// This is generally a bad idea because it's going to behave
-/// unhygienically.
-pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'cx> {
- let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
- Some(f) => f,
- None => return DummyResult::any(sp),
- };
- // The file will be added to the code map by the parser
- let file = cx.resolve_path(file, sp);
- let directory_ownership = DirectoryOwnership::Owned { relative: None };
- let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
-
- struct ExpandResult<'a> {
- p: parse::parser::Parser<'a>,
- }
- impl<'a> base::MacResult for ExpandResult<'a> {
- fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
- Some(panictry!(self.p.parse_expr()))
- }
-
- fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
- let mut ret = SmallVec::new();
- while self.p.token != token::Eof {
- match panictry!(self.p.parse_item()) {
- Some(item) => ret.push(item),
- None => self.p.diagnostic().span_fatal(self.p.token.span,
- &format!("expected item, found `{}`",
- self.p.this_token_to_string()))
- .raise()
- }
- }
- Some(ret)
- }
- }
-
- Box::new(ExpandResult { p })
-}
-
-// include_str! : read the given file, insert it as a literal string expr
-pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
- Some(f) => f,
- None => return DummyResult::expr(sp)
- };
- let file = cx.resolve_path(file, sp);
- match fs::read_to_string(&file) {
- Ok(src) => {
- let interned_src = Symbol::intern(&src);
-
- // Add this input file to the code map to make it available as
- // dependency information
- cx.source_map().new_source_file(file.into(), src);
-
- base::MacEager::expr(cx.expr_str(sp, interned_src))
- },
- Err(ref e) if e.kind() == ErrorKind::InvalidData => {
- cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display()));
- DummyResult::expr(sp)
- }
- Err(e) => {
- cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
- DummyResult::expr(sp)
- }
- }
-}
-
-pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
- Some(f) => f,
- None => return DummyResult::expr(sp)
- };
- let file = cx.resolve_path(file, sp);
- match fs::read(&file) {
- Ok(bytes) => {
- // Add the contents to the source map if it contains UTF-8.
- let (contents, bytes) = match String::from_utf8(bytes) {
- Ok(s) => {
- let bytes = s.as_bytes().to_owned();
- (s, bytes)
- },
- Err(e) => (String::new(), e.into_bytes()),
- };
- cx.source_map().new_source_file(file.into(), contents);
-
- base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes))))
- },
- Err(e) => {
- cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
- DummyResult::expr(sp)
- }
- }
-}
}
fn visit_pat(&mut self, pattern: &'a ast::Pat) {
- match pattern.node {
- PatKind::Slice(_, Some(ref subslice), _) => {
- gate_feature_post!(&self, slice_patterns,
- subslice.span,
- "syntax for subslices in slice patterns is not yet stabilized");
+ match &pattern.node {
+ PatKind::Slice(pats) => {
+ for pat in &*pats {
+ let span = pat.span;
+ let inner_pat = match &pat.node {
+ PatKind::Ident(.., Some(pat)) => pat,
+ _ => pat,
+ };
+ if inner_pat.is_rest() {
+ gate_feature_post!(
+ &self,
+ slice_patterns,
+ span,
+ "subslice patterns are unstable"
+ );
+ }
+ }
}
PatKind::Box(..) => {
gate_feature_post!(&self, box_patterns,
}
#[derive(RustcEncodable)]
-#[allow(unused_attributes)]
struct DiagnosticSpan {
file_name: String,
byte_start: u32,
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/",
test(attr(deny(warnings))))]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(bind_by_move_pattern_guards)]
#![feature(box_syntax)]
#![feature(const_fn)]
#![feature(label_break_value)]
#![feature(mem_take)]
#![feature(nll)]
+#![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_internals)]
+#![feature(proc_macro_span)]
#![feature(rustc_diagnostic_macros)]
#![feature(try_trait)]
#![feature(unicode_internals)]
#![recursion_limit="256"]
+extern crate proc_macro;
+
pub use errors;
use rustc_data_structures::sync::Lock;
use rustc_data_structures::bit_set::GrowableBitSet;
// way towards a non-panic!-prone parser. It should be used for fatal parsing
// errors; eventually we plan to convert all code using panictry to just use
// normal try.
+#[macro_export]
macro_rules! panictry {
($e:expr) => ({
use std::result::Result::{Ok, Err};
pub mod parse;
pub mod ptr;
pub mod show_span;
-pub mod std_inject;
pub use syntax_pos::edition;
pub use syntax_pos::symbol;
-pub mod test;
pub mod tokenstream;
pub mod visit;
}
pub mod ext {
+ mod placeholders;
+ mod proc_macro_server;
+
pub use syntax_pos::hygiene;
pub mod allocator;
pub mod base;
pub mod build;
- pub mod derive;
pub mod expand;
- pub mod placeholders;
- pub mod source_util;
+ pub mod proc_macro;
pub mod tt {
pub mod transcribe;
vis.visit_span(span);
}
-pub fn noop_visit_arg<T: MutVisitor>(Arg { attrs, id, pat, ty }: &mut Arg, vis: &mut T) {
+pub fn noop_visit_arg<T: MutVisitor>(Arg { attrs, id, pat, span, ty }: &mut Arg, vis: &mut T) {
vis.visit_id(id);
visit_thin_attrs(attrs, vis);
vis.visit_pat(pat);
+ vis.visit_span(span);
vis.visit_ty(ty);
}
let Pat { id, node, span } = pat.deref_mut();
vis.visit_id(id);
match node {
- PatKind::Wild => {}
+ PatKind::Wild | PatKind::Rest => {}
PatKind::Ident(_binding_mode, ident, sub) => {
vis.visit_ident(ident);
visit_opt(sub, |sub| vis.visit_pat(sub));
}
PatKind::Lit(e) => vis.visit_expr(e),
- PatKind::TupleStruct(path, pats, _ddpos) => {
+ PatKind::TupleStruct(path, elems) => {
vis.visit_path(path);
- visit_vec(pats, |pat| vis.visit_pat(pat));
+ visit_vec(elems, |elem| vis.visit_pat(elem));
}
PatKind::Path(qself, path) => {
vis.visit_qself(qself);
vis.visit_span(span);
};
}
- PatKind::Tuple(elts, _ddpos) => visit_vec(elts, |elt| vis.visit_pat(elt)),
+ PatKind::Tuple(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Box(inner) => vis.visit_pat(inner),
PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
vis.visit_expr(e2);
vis.visit_span(span);
}
- PatKind::Slice(before, slice, after) => {
- visit_vec(before, |pat| vis.visit_pat(pat));
- visit_opt(slice, |slice| vis.visit_pat(slice));
- visit_vec(after, |pat| vis.visit_pat(pat));
- }
+ PatKind::Slice(elems) => visit_vec(elems, |elem| vis.visit_pat(elem)),
PatKind::Paren(inner) => vis.visit_pat(inner),
PatKind::Mac(mac) => vis.visit_mac(mac),
}
use crate::parse::token::{self, Nonterminal, DelimToken};
use crate::parse::parser::{Parser, TokenType, PathStyle};
use crate::tokenstream::{TokenStream, TokenTree};
+use crate::source_map::Span;
use log::debug;
use smallvec::smallvec;
#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
Permitted,
- NotPermitted { reason: &'a str },
+ NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
}
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
};
let inner_parse_policy =
- InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
+ InnerAttributeParsePolicy::NotPermitted {
+ reason: inner_error_reason,
+ saw_doc_comment: just_parsed_doc_comment,
+ prev_attr_sp: attrs.last().and_then(|a| Some(a.span))
+ };
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
attrs.push(attr);
just_parsed_doc_comment = false;
let inner_parse_policy = if permit_inner {
InnerAttributeParsePolicy::Permitted
} else {
- InnerAttributeParsePolicy::NotPermitted
- { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
+ InnerAttributeParsePolicy::NotPermitted {
+ reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
+ saw_doc_comment: false,
+ prev_attr_sp: None
+ }
};
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
}
if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
self.expected_tokens.push(TokenType::Token(token::Not));
}
+
let style = if self.token == token::Not {
self.bump();
- if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
- {
- let span = self.token.span;
- self.diagnostic()
- .struct_span_err(span, reason)
- .note("inner attributes, like `#![no_std]`, annotate the item \
- enclosing them, and are usually found at the beginning of \
- source files. Outer attributes, like `#[test]`, annotate the \
- item following them.")
- .emit()
- }
ast::AttrStyle::Inner
} else {
ast::AttrStyle::Outer
self.expect(&token::CloseDelim(token::Bracket))?;
let hi = self.prev_span;
- (lo.to(hi), path, tokens, style)
+ let attr_sp = lo.to(hi);
+
+ // Emit error if inner attribute is encountered and not permitted
+ if style == ast::AttrStyle::Inner {
+ if let InnerAttributeParsePolicy::NotPermitted { reason,
+ saw_doc_comment, prev_attr_sp } = inner_parse_policy {
+ let prev_attr_note = if saw_doc_comment {
+ "previous doc comment"
+ } else {
+ "previous outer attribute"
+ };
+
+ let mut diagnostic = self
+ .diagnostic()
+ .struct_span_err(attr_sp, reason);
+
+ if let Some(prev_attr_sp) = prev_attr_sp {
+ diagnostic
+ .span_label(attr_sp, "not permitted following an outer attibute")
+ .span_label(prev_attr_sp, prev_attr_note);
+ }
+
+ diagnostic
+ .note("inner attributes, like `#![no_std]`, annotate the item \
+ enclosing them, and are usually found at the beginning of \
+ source files. Outer attributes, like `#[test]`, annotate the \
+ item following them.")
+ .emit()
+ }
+ }
+
+ (attr_sp, path, tokens, style)
}
_ => {
let token_str = self.this_token_to_string();
span: ident.span,
id: ast::DUMMY_NODE_ID
};
- Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, ty: P(ty) }
+ Arg { attrs: ThinVec::default(), id: ast::DUMMY_NODE_ID, pat, span: ident.span, ty: P(ty) }
}
pub enum Error {
use std::path::PathBuf;
use syntax_pos::{BytePos, Span, NO_EXPANSION, edition::Edition};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
- use rustc_data_structures::sync::Lock;
+ use rustc_data_structures::sync::{Lock, Once};
fn mk_sess(sm: Lrc<SourceMap>) -> ParseSess {
let emitter = errors::emitter::EmitterWriter::new(Box::new(io::sink()),
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
+ injected_crate_name: Once::new(),
}
}
use crate::tokenstream::{TokenStream, TokenTree};
use crate::diagnostics::plugin::ErrorMap;
use crate::print::pprust;
+use crate::symbol::Symbol;
use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
-use rustc_data_structures::sync::{Lrc, Lock};
+use rustc_data_structures::sync::{Lrc, Lock, Once};
use syntax_pos::{Span, SourceFile, FileName, MultiSpan};
use syntax_pos::edition::Edition;
pub let_chains_spans: Lock<Vec<Span>>,
// Places where `async || ..` exprs were used and should be feature gated.
pub async_closure_spans: Lock<Vec<Span>>,
+ pub injected_crate_name: Once<Symbol>,
}
impl ParseSess {
param_attr_spans: Lock::new(Vec::new()),
let_chains_spans: Lock::new(Vec::new()),
async_closure_spans: Lock::new(Vec::new()),
+ injected_crate_name: Once::new(),
}
}
/// Parses a sequence, including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
- pub fn parse_seq_to_end<T, F>(&mut self,
- ket: &TokenKind,
- sep: SeqSep,
- f: F)
- -> PResult<'a, Vec<T>> where
- F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
- {
- let (val, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
+ pub fn parse_seq_to_end<T>(
+ &mut self,
+ ket: &TokenKind,
+ sep: SeqSep,
+ f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, Vec<T>> {
+ let (val, _, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
if !recovered {
self.bump();
}
/// Parses a sequence, not including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
- pub fn parse_seq_to_before_end<T, F>(
+ pub fn parse_seq_to_before_end<T>(
&mut self,
ket: &TokenKind,
sep: SeqSep,
- f: F,
- ) -> PResult<'a, (Vec<T>, bool)>
- where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
- {
+ f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, (Vec<T>, bool, bool)> {
self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f)
}
- crate fn parse_seq_to_before_tokens<T, F>(
+ fn expect_any_with_type(&mut self, kets: &[&TokenKind], expect: TokenExpectType) -> bool {
+ kets.iter().any(|k| {
+ match expect {
+ TokenExpectType::Expect => self.check(k),
+ TokenExpectType::NoExpect => self.token == **k,
+ }
+ })
+ }
+
+ crate fn parse_seq_to_before_tokens<T>(
&mut self,
kets: &[&TokenKind],
sep: SeqSep,
expect: TokenExpectType,
- mut f: F,
- ) -> PResult<'a, (Vec<T>, bool /* recovered */)>
- where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>
- {
+ mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, (Vec<T>, bool /* trailing */, bool /* recovered */)> {
let mut first = true;
let mut recovered = false;
+ let mut trailing = false;
let mut v = vec![];
- while !kets.iter().any(|k| {
- match expect {
- TokenExpectType::Expect => self.check(k),
- TokenExpectType::NoExpect => self.token == **k,
- }
- }) {
- match self.token.kind {
- token::CloseDelim(..) | token::Eof => break,
- _ => {}
- };
+ while !self.expect_any_with_type(kets, expect) {
+ if let token::CloseDelim(..) | token::Eof = self.token.kind {
+ break
+ }
if let Some(ref t) = sep.sep {
if first {
first = false;
}
}
}
- if sep.trailing_sep_allowed && kets.iter().any(|k| {
- match expect {
- TokenExpectType::Expect => self.check(k),
- TokenExpectType::NoExpect => self.token == **k,
- }
- }) {
+ if sep.trailing_sep_allowed && self.expect_any_with_type(kets, expect) {
+ trailing = true;
break;
}
v.push(t);
}
- Ok((v, recovered))
+ Ok((v, trailing, recovered))
}
/// Parses a sequence, including the closing delimiter. The function
/// `f` must consume tokens until reaching the next separator or
/// closing bracket.
- fn parse_unspanned_seq<T, F>(
+ fn parse_unspanned_seq<T>(
&mut self,
bra: &TokenKind,
ket: &TokenKind,
sep: SeqSep,
- f: F,
- ) -> PResult<'a, Vec<T>> where
- F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
- {
+ f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, (Vec<T>, bool)> {
self.expect(bra)?;
- let (result, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
+ let (result, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
if !recovered {
self.eat(ket);
}
- Ok(result)
+ Ok((result, trailing))
+ }
+
+ fn parse_delim_comma_seq<T>(
+ &mut self,
+ delim: DelimToken,
+ f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, (Vec<T>, bool)> {
+ self.parse_unspanned_seq(
+ &token::OpenDelim(delim),
+ &token::CloseDelim(delim),
+ SeqSep::trailing_allowed(token::Comma),
+ f,
+ )
+ }
+
+ fn parse_paren_comma_seq<T>(
+ &mut self,
+ f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
+ ) -> PResult<'a, (Vec<T>, bool)> {
+ self.parse_delim_comma_seq(token::Paren, f)
}
/// Advance the parser by one token
where
F: Fn(&token::Token) -> bool
{
+ let lo = self.token.span;
let attrs = self.parse_arg_attributes()?;
if let Some(mut arg) = self.parse_self_arg()? {
arg.attrs = attrs.into();
}
};
- Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, ty })
+ let span = lo.to(self.token.span);
+
+ Ok(Arg { attrs: attrs.into(), id: ast::DUMMY_NODE_ID, pat, span, ty })
}
/// Parses an argument in a lambda header (e.g., `|arg, arg|`).
fn parse_fn_block_arg(&mut self) -> PResult<'a, Arg> {
+ let lo = self.token.span;
let attrs = self.parse_arg_attributes()?;
let pat = self.parse_pat(Some("argument name"))?;
let t = if self.eat(&token::Colon) {
span: self.prev_span,
})
};
+ let span = lo.to(self.token.span);
Ok(Arg {
attrs: attrs.into(),
ty: t,
pat,
+ span,
id: ast::DUMMY_NODE_ID
})
}
AngleBracketedArgs { args, constraints, span }.into()
} else {
// `(T, U) -> R`
- self.bump(); // `(`
- let (inputs, recovered) = self.parse_seq_to_before_tokens(
- &[&token::CloseDelim(token::Paren)],
- SeqSep::trailing_allowed(token::Comma),
- TokenExpectType::Expect,
- |p| p.parse_ty())?;
- if !recovered {
- self.bump(); // `)`
- }
+ let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?;
let span = lo.to(self.prev_span);
let output = if self.eat(&token::RArrow) {
Some(self.parse_ty_common(false, false, false)?)
Ok(match self.token.kind {
token::OpenDelim(token::Paren) => {
// Method call `expr.f()`
- let mut args = self.parse_unspanned_seq(
- &token::OpenDelim(token::Paren),
- &token::CloseDelim(token::Paren),
- SeqSep::trailing_allowed(token::Comma),
- |p| Ok(p.parse_expr()?)
- )?;
+ let mut args = self.parse_paren_expr_seq()?;
args.insert(0, self_arg);
let span = lo.to(self.prev_span);
match self.token.kind {
// expr(...)
token::OpenDelim(token::Paren) => {
- let seq = self.parse_unspanned_seq(
- &token::OpenDelim(token::Paren),
- &token::CloseDelim(token::Paren),
- SeqSep::trailing_allowed(token::Comma),
- |p| Ok(p.parse_expr()?)
- ).map(|es| {
+ let seq = self.parse_paren_expr_seq().map(|es| {
let nd = self.mk_call(e, es);
let hi = self.prev_span;
self.mk_expr(lo.to(hi), nd, ThinVec::new())
return Ok(e);
}
+ fn parse_paren_expr_seq(&mut self) -> PResult<'a, Vec<P<Expr>>> {
+ self.parse_paren_comma_seq(|p| p.parse_expr()).map(|(r, _)| r)
+ }
+
crate fn process_potential_macro_variable(&mut self) {
self.token = match self.token.kind {
token::Dollar if self.token.span.ctxt() != SyntaxContext::empty() &&
};
}
- // Parses a parenthesized list of patterns like
- // `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
- // - a vector of the patterns that were parsed
- // - an option indicating the index of the `..` element
- // - a boolean indicating whether a trailing comma was present.
- // Trailing commas are significant because (p) and (p,) are different patterns.
- fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
- self.expect(&token::OpenDelim(token::Paren))?;
- let result = match self.parse_pat_list() {
- Ok(result) => result,
- Err(mut err) => { // recover from parse error in tuple pattern list
- err.emit();
- self.consume_block(token::Paren);
- return Ok((vec![], Some(0), false));
- }
- };
- self.expect(&token::CloseDelim(token::Paren))?;
- Ok(result)
- }
-
- fn parse_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
- let mut fields = Vec::new();
- let mut ddpos = None;
- let mut prev_dd_sp = None;
- let mut trailing_comma = false;
- loop {
- if self.eat(&token::DotDot) {
- if ddpos.is_none() {
- ddpos = Some(fields.len());
- prev_dd_sp = Some(self.prev_span);
- } else {
- // Emit a friendly error, ignore `..` and continue parsing
- let mut err = self.struct_span_err(
- self.prev_span,
- "`..` can only be used once per tuple or tuple struct pattern",
- );
- err.span_label(self.prev_span, "can only be used once per pattern");
- if let Some(sp) = prev_dd_sp {
- err.span_label(sp, "previously present here");
- }
- err.emit();
- }
- } else if !self.check(&token::CloseDelim(token::Paren)) {
- fields.push(self.parse_pat(None)?);
- } else {
- break
- }
-
- trailing_comma = self.eat(&token::Comma);
- if !trailing_comma {
- break
- }
- }
-
- if ddpos == Some(fields.len()) && trailing_comma {
- // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
- let msg = "trailing comma is not permitted after `..`";
- self.struct_span_err(self.prev_span, msg)
- .span_label(self.prev_span, msg)
- .emit();
- }
-
- Ok((fields, ddpos, trailing_comma))
- }
-
- fn parse_pat_vec_elements(
- &mut self,
- ) -> PResult<'a, (Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>)> {
- let mut before = Vec::new();
- let mut slice = None;
- let mut after = Vec::new();
- let mut first = true;
- let mut before_slice = true;
-
- while self.token != token::CloseDelim(token::Bracket) {
- if first {
- first = false;
- } else {
- self.expect(&token::Comma)?;
-
- if self.token == token::CloseDelim(token::Bracket)
- && (before_slice || !after.is_empty()) {
- break
- }
- }
-
- if before_slice {
- if self.eat(&token::DotDot) {
-
- if self.check(&token::Comma) ||
- self.check(&token::CloseDelim(token::Bracket)) {
- slice = Some(P(Pat {
- id: ast::DUMMY_NODE_ID,
- node: PatKind::Wild,
- span: self.prev_span,
- }));
- before_slice = false;
- }
- continue
- }
- }
-
- let subpat = self.parse_pat(None)?;
- if before_slice && self.eat(&token::DotDot) {
- slice = Some(subpat);
- before_slice = false;
- } else if before_slice {
- before.push(subpat);
- } else {
- after.push(subpat);
- }
- }
-
- Ok((before, slice, after))
- }
-
fn parse_pat_field(
&mut self,
lo: Span,
}
}
- // helper function to decide whether to parse as ident binding or to try to do
- // something more complex like range patterns
+ /// Is the current token suitable as the start of a range patterns end?
+ fn is_pat_range_end_start(&self) -> bool {
+ self.token.is_path_start() // e.g. `MY_CONST`;
+ || self.token == token::Dot // e.g. `.5` for recovery;
+ || self.token.can_begin_literal_or_bool() // e.g. `42`.
+ }
+
+ // Helper function to decide whether to parse as ident binding
+ // or to try to do something more complex like range patterns.
fn parse_as_ident(&mut self) -> bool {
self.look_ahead(1, |t| match t.kind {
token::OpenDelim(token::Paren) | token::OpenDelim(token::Brace) |
- token::DotDotDot | token::DotDotEq | token::ModSep | token::Not => Some(false),
- // ensure slice patterns [a, b.., c] and [a, b, c..] don't go into the
- // range pattern branch
- token::DotDot => None,
- _ => Some(true),
- }).unwrap_or_else(|| self.look_ahead(2, |t| match t.kind {
- token::Comma | token::CloseDelim(token::Bracket) => true,
- _ => false,
- }))
+ token::DotDotDot | token::DotDotEq | token::DotDot |
+ token::ModSep | token::Not => false,
+ _ => true,
+ })
+ }
+
+ /// Parse and throw away a parentesized comma separated
+ /// sequence of patterns until `)` is reached.
+ fn skip_pat_list(&mut self) -> PResult<'a, ()> {
+ while !self.check(&token::CloseDelim(token::Paren)) {
+ self.parse_pat(None)?;
+ if !self.eat(&token::Comma) {
+ return Ok(())
+ }
+ }
+ Ok(())
}
/// A wrapper around `parse_pat` with some special error handling for the
// later.
let comma_span = self.token.span;
self.bump();
- if let Err(mut err) = self.parse_pat_list() {
+ if let Err(mut err) = self.skip_pat_list() {
// We didn't expect this to work anyway; we just wanted
// to advance to the end of the comma-sequence so we know
// the span to suggest parenthesizing
self.parse_pat_with_range_pat(true, expected)
}
+ /// Parse a range-to pattern, e.g. `..X` and `..=X` for recovery.
+ fn parse_pat_range_to(&mut self, re: RangeEnd, form: &str) -> PResult<'a, PatKind> {
+ let lo = self.prev_span;
+ let end = self.parse_pat_range_end()?;
+ let range_span = lo.to(end.span);
+ let begin = self.mk_expr(range_span, ExprKind::Err, ThinVec::new());
+
+ self.diagnostic()
+ .struct_span_err(range_span, &format!("`{}X` range patterns are not supported", form))
+ .span_suggestion(
+ range_span,
+ "try using the minimum value for the type",
+ format!("MIN{}{}", form, pprust::expr_to_string(&end)),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+
+ Ok(PatKind::Range(begin, end, respan(lo, re)))
+ }
+
+ /// Parse the end of a `X..Y`, `X..=Y`, or `X...Y` range pattern or recover
+ /// if that end is missing treating it as `X..`, `X..=`, or `X...` respectively.
+ fn parse_pat_range_end_opt(&mut self, begin: &Expr, form: &str) -> PResult<'a, P<Expr>> {
+ if self.is_pat_range_end_start() {
+ // Parsing e.g. `X..=Y`.
+ self.parse_pat_range_end()
+ } else {
+ // Parsing e.g. `X..`.
+ let range_span = begin.span.to(self.prev_span);
+
+ self.diagnostic()
+ .struct_span_err(
+ range_span,
+ &format!("`X{}` range patterns are not supported", form),
+ )
+ .span_suggestion(
+ range_span,
+ "try using the maximum value for the type",
+ format!("{}{}MAX", pprust::expr_to_string(&begin), form),
+ Applicability::HasPlaceholders,
+ )
+ .emit();
+
+ Ok(self.mk_expr(range_span, ExprKind::Err, ThinVec::new()))
+ }
+ }
+
/// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are
/// allowed).
fn parse_pat_with_range_pat(
pat = PatKind::Ref(subpat, mutbl);
}
token::OpenDelim(token::Paren) => {
- // Parse (pat,pat,pat,...) as tuple pattern
- let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
- pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
+ // Parse a tuple or parenthesis pattern.
+ let (fields, trailing_comma) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+
+ // Here, `(pat,)` is a tuple pattern.
+ // For backward compatibility, `(..)` is a tuple pattern as well.
+ pat = if fields.len() == 1 && !(trailing_comma || fields[0].is_rest()) {
PatKind::Paren(fields.into_iter().nth(0).unwrap())
} else {
- PatKind::Tuple(fields, ddpos)
+ PatKind::Tuple(fields)
};
}
token::OpenDelim(token::Bracket) => {
- // Parse [pat,pat,...] as slice pattern
+ // Parse `[pat, pat,...]` as a slice pattern.
+ let (slice, _) = self.parse_delim_comma_seq(token::Bracket, |p| p.parse_pat(None))?;
+ pat = PatKind::Slice(slice);
+ }
+ token::DotDot => {
self.bump();
- let (before, slice, after) = self.parse_pat_vec_elements()?;
- self.expect(&token::CloseDelim(token::Bracket))?;
- pat = PatKind::Slice(before, slice, after);
+ pat = if self.is_pat_range_end_start() {
+ // Parse `..42` for recovery.
+ self.parse_pat_range_to(RangeEnd::Excluded, "..")?
+ } else {
+ // A rest pattern `..`.
+ PatKind::Rest
+ };
+ }
+ token::DotDotEq => {
+ // Parse `..=42` for recovery.
+ self.bump();
+ pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotEq), "..=")?;
+ }
+ token::DotDotDot => {
+ // Parse `...42` for recovery.
+ self.bump();
+ pat = self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")?;
}
// At this point, token != &, &&, (, [
_ => if self.eat_keyword(kw::Underscore) {
pat = PatKind::Mac(mac);
}
token::DotDotDot | token::DotDotEq | token::DotDot => {
- let end_kind = match self.token.kind {
- token::DotDot => RangeEnd::Excluded,
- token::DotDotDot => RangeEnd::Included(RangeSyntax::DotDotDot),
- token::DotDotEq => RangeEnd::Included(RangeSyntax::DotDotEq),
+ let (end_kind, form) = match self.token.kind {
+ token::DotDot => (RangeEnd::Excluded, ".."),
+ token::DotDotDot => (RangeEnd::Included(RangeSyntax::DotDotDot), "..."),
+ token::DotDotEq => (RangeEnd::Included(RangeSyntax::DotDotEq), "..="),
_ => panic!("can only parse `..`/`...`/`..=` for ranges \
(checked above)"),
};
let span = lo.to(self.prev_span);
let begin = self.mk_expr(span, ExprKind::Path(qself, path), ThinVec::new());
self.bump();
- let end = self.parse_pat_range_end()?;
- let op = Spanned { span: op_span, node: end_kind };
- pat = PatKind::Range(begin, end, op);
+ let end = self.parse_pat_range_end_opt(&begin, form)?;
+ pat = PatKind::Range(begin, end, respan(op_span, end_kind));
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
return Err(err);
}
// Parse tuple struct or enum pattern
- let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
- pat = PatKind::TupleStruct(path, fields, ddpos)
+ let (fields, _) = self.parse_paren_comma_seq(|p| p.parse_pat(None))?;
+ pat = PatKind::TupleStruct(path, fields)
}
_ => pat = PatKind::Path(qself, path),
}
let op_span = self.token.span;
if self.check(&token::DotDot) || self.check(&token::DotDotEq) ||
self.check(&token::DotDotDot) {
- let end_kind = if self.eat(&token::DotDotDot) {
- RangeEnd::Included(RangeSyntax::DotDotDot)
+ let (end_kind, form) = if self.eat(&token::DotDotDot) {
+ (RangeEnd::Included(RangeSyntax::DotDotDot), "...")
} else if self.eat(&token::DotDotEq) {
- RangeEnd::Included(RangeSyntax::DotDotEq)
+ (RangeEnd::Included(RangeSyntax::DotDotEq), "..=")
} else if self.eat(&token::DotDot) {
- RangeEnd::Excluded
+ (RangeEnd::Excluded, "..")
} else {
panic!("impossible case: we already matched \
on a range-operator token")
};
- let end = self.parse_pat_range_end()?;
- let op = Spanned { span: op_span, node: end_kind };
- pat = PatKind::Range(begin, end, op);
+ let end = self.parse_pat_range_end_opt(&begin, form)?;
+ pat = PatKind::Range(begin, end, respan(op_span, end_kind))
} else {
pat = PatKind::Lit(begin);
}
fn parse_fn_args(&mut self, named_args: bool, allow_c_variadic: bool)
-> PResult<'a, (Vec<Arg> , bool)> {
- self.expect(&token::OpenDelim(token::Paren))?;
-
let sp = self.token.span;
let mut c_variadic = false;
- let (args, recovered): (Vec<Option<Arg>>, bool) =
- self.parse_seq_to_before_end(
- &token::CloseDelim(token::Paren),
- SeqSep::trailing_allowed(token::Comma),
- |p| {
- let do_not_enforce_named_arguments_for_c_variadic =
- |token: &token::Token| -> bool {
- if token == &token::DotDotDot {
- false
- } else {
- named_args
- }
- };
- match p.parse_arg_general(
- false,
- allow_c_variadic,
- do_not_enforce_named_arguments_for_c_variadic
- ) {
- Ok(arg) => {
- if let TyKind::CVarArgs = arg.ty.node {
- c_variadic = true;
- if p.token != token::CloseDelim(token::Paren) {
- let span = p.token.span;
- p.span_err(span,
- "`...` must be the last argument of a C-variadic function");
- Ok(None)
- } else {
- Ok(Some(arg))
- }
- } else {
- Ok(Some(arg))
- }
- },
- Err(mut e) => {
- e.emit();
- let lo = p.prev_span;
- // Skip every token until next possible arg or end.
- p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
- // Create a placeholder argument for proper arg count (issue #34264).
- let span = lo.to(p.prev_span);
- Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
+ let (args, _): (Vec<Option<Arg>>, _) = self.parse_paren_comma_seq(|p| {
+ let do_not_enforce_named_arguments_for_c_variadic =
+ |token: &token::Token| -> bool {
+ if token == &token::DotDotDot {
+ false
+ } else {
+ named_args
+ }
+ };
+ match p.parse_arg_general(
+ false,
+ allow_c_variadic,
+ do_not_enforce_named_arguments_for_c_variadic
+ ) {
+ Ok(arg) => {
+ if let TyKind::CVarArgs = arg.ty.node {
+ c_variadic = true;
+ if p.token != token::CloseDelim(token::Paren) {
+ let span = p.token.span;
+ p.span_err(span,
+ "`...` must be the last argument of a C-variadic function");
+ Ok(None)
+ } else {
+ Ok(Some(arg))
}
+ } else {
+ Ok(Some(arg))
}
+ },
+ Err(mut e) => {
+ e.emit();
+ let lo = p.prev_span;
+ // Skip every token until next possible arg or end.
+ p.eat_to_tokens(&[&token::Comma, &token::CloseDelim(token::Paren)]);
+ // Create a placeholder argument for proper arg count (issue #34264).
+ let span = lo.to(p.prev_span);
+ Ok(Some(dummy_arg(Ident::new(kw::Invalid, span))))
}
- )?;
-
- if !recovered {
- self.eat(&token::CloseDelim(token::Paren));
- }
+ }
+ })?;
let args: Vec<_> = args.into_iter().filter_map(|x| x).collect();
(vec![self_arg], false)
} else if self.eat(&token::Comma) {
let mut fn_inputs = vec![self_arg];
- let (mut input, recovered) = self.parse_seq_to_before_end(
+ let (mut input, _, recovered) = self.parse_seq_to_before_end(
&token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
fn_inputs.append(&mut input);
(fn_inputs, recovered)
}
}
} else {
- self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?
+ let (input, _, recovered) =
+ self.parse_seq_to_before_end(&token::CloseDelim(token::Paren), sep, parse_arg_fn)?;
+ (input, recovered)
};
if !recovered {
fn parse_tuple_struct_body(&mut self) -> PResult<'a, Vec<StructField>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
// Unit like structs are handled in parse_item_struct function
- let fields = self.parse_unspanned_seq(
- &token::OpenDelim(token::Paren),
- &token::CloseDelim(token::Paren),
- SeqSep::trailing_allowed(token::Comma),
- |p| {
- let attrs = p.parse_outer_attributes()?;
- let lo = p.token.span;
- let vis = p.parse_visibility(true)?;
- let ty = p.parse_ty()?;
- Ok(StructField {
- span: lo.to(ty.span),
- vis,
- ident: None,
- id: ast::DUMMY_NODE_ID,
- ty,
- attrs,
- })
- })?;
-
- Ok(fields)
+ self.parse_paren_comma_seq(|p| {
+ let attrs = p.parse_outer_attributes()?;
+ let lo = p.token.span;
+ let vis = p.parse_visibility(true)?;
+ let ty = p.parse_ty()?;
+ Ok(StructField {
+ span: lo.to(ty.span),
+ vis,
+ ident: None,
+ id: ast::DUMMY_NODE_ID,
+ ty,
+ attrs,
+ })
+ }).map(|(r, _)| r)
}
/// Parses a structure field declaration.
/// USE_TREE_LIST = Ø | (USE_TREE `,`)* USE_TREE [`,`]
/// ```
fn parse_use_tree_list(&mut self) -> PResult<'a, Vec<(UseTree, ast::NodeId)>> {
- self.parse_unspanned_seq(&token::OpenDelim(token::Brace),
- &token::CloseDelim(token::Brace),
- SeqSep::trailing_allowed(token::Comma), |this| {
- Ok((this.parse_use_tree()?, ast::DUMMY_NODE_ID))
- })
+ self.parse_delim_comma_seq(token::Brace, |p| Ok((p.parse_use_tree()?, ast::DUMMY_NODE_ID)))
+ .map(|(r, _)| r)
}
fn parse_rename(&mut self) -> PResult<'a, Option<Ident>> {
use crate::print::pp::{self, Breaks};
use crate::print::pp::Breaks::{Consistent, Inconsistent};
use crate::ptr::P;
-use crate::std_inject;
use crate::symbol::{kw, sym};
use crate::tokenstream::{self, TokenStream, TokenTree};
is_expanded,
};
- if is_expanded && std_inject::injected_crate_name().is_some() {
+ if is_expanded && sess.injected_crate_name.try_get().is_some() {
// We need to print `#![no_std]` (and its feature gate) so that
// compiling pretty-printed source won't inject libstd again.
// However we don't want these attributes in the AST because
self.print_pat(p);
}
}
- PatKind::TupleStruct(ref path, ref elts, ddpos) => {
+ PatKind::TupleStruct(ref path, ref elts) => {
self.print_path(path, true, 0);
self.popen();
- if let Some(ddpos) = ddpos {
- self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
- if ddpos != 0 {
- self.word_space(",");
- }
- self.s.word("..");
- if ddpos != elts.len() {
- self.s.word(",");
- self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
- }
- } else {
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- }
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.pclose();
}
PatKind::Path(None, ref path) => {
self.s.space();
self.s.word("}");
}
- PatKind::Tuple(ref elts, ddpos) => {
+ PatKind::Tuple(ref elts) => {
self.popen();
- if let Some(ddpos) = ddpos {
- self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(p));
- if ddpos != 0 {
- self.word_space(",");
- }
- self.s.word("..");
- if ddpos != elts.len() {
- self.s.word(",");
- self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(p));
- }
- } else {
- self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
- if elts.len() == 1 {
- self.s.word(",");
- }
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
+ if elts.len() == 1 {
+ self.s.word(",");
}
self.pclose();
}
}
self.print_expr(end);
}
- PatKind::Slice(ref before, ref slice, ref after) => {
+ PatKind::Slice(ref elts) => {
self.s.word("[");
- self.commasep(Inconsistent,
- &before[..],
- |s, p| s.print_pat(p));
- if let Some(ref p) = *slice {
- if !before.is_empty() { self.word_space(","); }
- if let PatKind::Wild = p.node {
- // Print nothing
- } else {
- self.print_pat(p);
- }
- self.s.word("..");
- if !after.is_empty() { self.word_space(","); }
- }
- self.commasep(Inconsistent,
- &after[..],
- |s, p| s.print_pat(p));
+ self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(p));
self.s.word("]");
}
+ PatKind::Rest => self.s.word(".."),
PatKind::Paren(ref inner) => {
self.popen();
self.print_pat(inner);
+++ /dev/null
-use crate::ast;
-use crate::attr;
-use crate::edition::Edition;
-use crate::ext::hygiene::{ExpnId, MacroKind};
-use crate::symbol::{Ident, Symbol, kw, sym};
-use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan};
-use crate::ptr::P;
-use crate::tokenstream::TokenStream;
-
-use std::cell::Cell;
-use std::iter;
-use syntax_pos::DUMMY_SP;
-
-pub fn injected_crate_name() -> Option<&'static str> {
- INJECTED_CRATE_NAME.with(|name| name.get())
-}
-
-thread_local! {
- // A `Symbol` might make more sense here, but it doesn't work, probably for
- // reasons relating to the use of thread-local storage for the Symbol
- // interner.
- static INJECTED_CRATE_NAME: Cell<Option<&'static str>> = Cell::new(None);
-}
-
-pub fn maybe_inject_crates_ref(
- mut krate: ast::Crate,
- alt_std_name: Option<&str>,
- edition: Edition,
-) -> ast::Crate {
- let rust_2018 = edition >= Edition::Edition2018;
-
- // the first name in this list is the crate name of the crate with the prelude
- let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) {
- return krate;
- } else if attr::contains_name(&krate.attrs, sym::no_std) {
- if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
- &["core"]
- } else {
- &["core", "compiler_builtins"]
- }
- } else {
- &["std"]
- };
-
- // .rev() to preserve ordering above in combination with insert(0, ...)
- let alt_std_name = alt_std_name.map(Symbol::intern);
- for orig_name_str in names.iter().rev() {
- // HACK(eddyb) gensym the injected crates on the Rust 2018 edition,
- // so they don't accidentally interfere with the new import paths.
- let orig_name_sym = Symbol::intern(orig_name_str);
- let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym);
- let (rename, orig_name) = if rust_2018 {
- (orig_name_ident.gensym(), Some(orig_name_sym))
- } else {
- (orig_name_ident, None)
- };
- krate.module.items.insert(0, P(ast::Item {
- attrs: vec![attr::mk_attr_outer(
- DUMMY_SP,
- attr::mk_attr_id(),
- attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use))
- )],
- vis: dummy_spanned(ast::VisibilityKind::Inherited),
- node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)),
- ident: rename,
- id: ast::DUMMY_NODE_ID,
- span: DUMMY_SP,
- tokens: None,
- }));
- }
-
- // the crates have been injected, the assumption is that the first one is the one with
- // the prelude.
- let name = names[0];
-
- INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name)));
-
- let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
- ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition,
- [sym::prelude_import][..].into(),
- ));
-
- krate.module.items.insert(0, P(ast::Item {
- attrs: vec![ast::Attribute {
- style: ast::AttrStyle::Outer,
- path: ast::Path::from_ident(ast::Ident::new(sym::prelude_import, span)),
- tokens: TokenStream::empty(),
- id: attr::mk_attr_id(),
- is_sugared_doc: false,
- span,
- }],
- vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited),
- node: ast::ItemKind::Use(P(ast::UseTree {
- prefix: ast::Path {
- segments: iter::once(ast::Ident::with_empty_ctxt(kw::PathRoot))
- .chain(
- [name, "prelude", "v1"].iter().cloned()
- .map(ast::Ident::from_str)
- ).map(ast::PathSegment::from_ident).collect(),
- span,
- },
- kind: ast::UseTreeKind::Glob,
- span,
- })),
- id: ast::DUMMY_NODE_ID,
- ident: ast::Ident::invalid(),
- span,
- tokens: None,
- }));
-
- krate
-}
+++ /dev/null
-// Code that generates a test runner to run all the tests in a crate
-
-#![allow(dead_code)]
-#![allow(unused_imports)]
-
-use HasTestSignature::*;
-
-use std::iter;
-use std::slice;
-use std::mem;
-use std::vec;
-
-use log::debug;
-use smallvec::{smallvec, SmallVec};
-use syntax_pos::{DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos};
-
-use crate::attr::{self, HasAttrs};
-use crate::source_map::{self, SourceMap, ExpnInfo, ExpnKind, dummy_spanned, respan};
-use crate::config;
-use crate::entry::{self, EntryPointType};
-use crate::ext::base::{ExtCtxt, Resolver};
-use crate::ext::build::AstBuilder;
-use crate::ext::expand::ExpansionConfig;
-use crate::ext::hygiene::{self, ExpnId, SyntaxContext, MacroKind};
-use crate::mut_visit::{*, ExpectOne};
-use crate::feature_gate::Features;
-use crate::util::map_in_place::MapInPlace;
-use crate::parse::{token, ParseSess};
-use crate::ast::{self, Ident};
-use crate::ptr::P;
-use crate::symbol::{self, Symbol, kw, sym};
-use crate::ThinVec;
-
-struct Test {
- span: Span,
- path: Vec<Ident>,
-}
-
-struct TestCtxt<'a> {
- span_diagnostic: &'a errors::Handler,
- path: Vec<Ident>,
- ext_cx: ExtCtxt<'a>,
- test_cases: Vec<Test>,
- reexport_test_harness_main: Option<Symbol>,
- is_libtest: bool,
- features: &'a Features,
- test_runner: Option<ast::Path>,
-
- // top-level re-export submodule, filled out after folding is finished
- toplevel_reexport: Option<Ident>,
-}
-
-// Traverse the crate, collecting all the test functions, eliding any
-// existing main functions, and synthesizing a main test harness
-pub fn modify_for_testing(sess: &ParseSess,
- resolver: &mut dyn Resolver,
- should_test: bool,
- krate: &mut ast::Crate,
- span_diagnostic: &errors::Handler,
- features: &Features) {
- // Check for #[reexport_test_harness_main = "some_name"] which
- // creates a `use __test::main as some_name;`. This needs to be
- // unconditional, so that the attribute is still marked as used in
- // non-test builds.
- let reexport_test_harness_main =
- attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
-
- // Do this here so that the test_runner crate attribute gets marked as used
- // even in non-test builds
- let test_runner = get_test_runner(span_diagnostic, &krate);
-
- if should_test {
- generate_test_harness(sess, resolver, reexport_test_harness_main,
- krate, span_diagnostic, features, test_runner)
- }
-}
-
-struct TestHarnessGenerator<'a> {
- cx: TestCtxt<'a>,
- tests: Vec<Ident>,
-
- // submodule name, gensym'd identifier for re-exports
- tested_submods: Vec<(Ident, Ident)>,
-}
-
-impl<'a> MutVisitor for TestHarnessGenerator<'a> {
- fn visit_crate(&mut self, c: &mut ast::Crate) {
- noop_visit_crate(c, self);
-
- // Create a main function to run our tests
- let test_main = {
- let unresolved = mk_main(&mut self.cx);
- self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap()
- };
-
- c.module.items.push(test_main);
- }
-
- fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
- let ident = i.ident;
- if ident.name != kw::Invalid {
- self.cx.path.push(ident);
- }
- debug!("current path: {}", path_name_i(&self.cx.path));
-
- let mut item = i.into_inner();
- if is_test_case(&item) {
- debug!("this is a test item");
-
- let test = Test {
- span: item.span,
- path: self.cx.path.clone(),
- };
- self.cx.test_cases.push(test);
- self.tests.push(item.ident);
- }
-
- // We don't want to recurse into anything other than mods, since
- // mods or tests inside of functions will break things
- if let ast::ItemKind::Mod(mut module) = item.node {
- let tests = mem::take(&mut self.tests);
- let tested_submods = mem::take(&mut self.tested_submods);
- noop_visit_mod(&mut module, self);
- let tests = mem::replace(&mut self.tests, tests);
- let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
-
- if !tests.is_empty() || !tested_submods.is_empty() {
- let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
- module.items.push(it);
-
- if !self.cx.path.is_empty() {
- self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
- } else {
- debug!("pushing nothing, sym: {:?}", sym);
- self.cx.toplevel_reexport = Some(sym);
- }
- }
- item.node = ast::ItemKind::Mod(module);
- }
- if ident.name != kw::Invalid {
- self.cx.path.pop();
- }
- smallvec![P(item)]
- }
-
- fn visit_mac(&mut self, _mac: &mut ast::Mac) {
- // Do nothing.
- }
-}
-
-/// A folder used to remove any entry points (like fn main) because the harness
-/// generator will provide its own
-struct EntryPointCleaner {
- // Current depth in the ast
- depth: usize,
-}
-
-impl MutVisitor for EntryPointCleaner {
- fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
- self.depth += 1;
- let item = noop_flat_map_item(i, self).expect_one("noop did something");
- self.depth -= 1;
-
- // Remove any #[main] or #[start] from the AST so it doesn't
- // clash with the one we're going to add, but mark it as
- // #[allow(dead_code)] to avoid printing warnings.
- let item = match entry::entry_point_type(&item, self.depth) {
- EntryPointType::MainNamed |
- EntryPointType::MainAttr |
- EntryPointType::Start =>
- item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| {
- let allow_ident = Ident::with_empty_ctxt(sym::allow);
- let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code"));
- let allow_dead_code_item = attr::mk_list_item(DUMMY_SP, allow_ident,
- vec![dc_nested]);
- let allow_dead_code = attr::mk_attr_outer(DUMMY_SP,
- attr::mk_attr_id(),
- allow_dead_code_item);
-
- ast::Item {
- id,
- ident,
- attrs: attrs.into_iter()
- .filter(|attr| {
- !attr.check_name(sym::main) && !attr.check_name(sym::start)
- })
- .chain(iter::once(allow_dead_code))
- .collect(),
- node,
- vis,
- span,
- tokens,
- }
- }),
- EntryPointType::None |
- EntryPointType::OtherMain => item,
- };
-
- smallvec![item]
- }
-
- fn visit_mac(&mut self, _mac: &mut ast::Mac) {
- // Do nothing.
- }
-}
-
-/// Creates an item (specifically a module) that "pub use"s the tests passed in.
-/// Each tested submodule will contain a similar reexport module that we will export
-/// under the name of the original module. That is, `submod::__test_reexports` is
-/// reexported like so `pub use submod::__test_reexports as submod`.
-fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
- parent: ast::NodeId,
- tests: Vec<Ident>,
- tested_submods: Vec<(Ident, Ident)>)
- -> (P<ast::Item>, Ident) {
- let super_ = Ident::with_empty_ctxt(kw::Super);
-
- let items = tests.into_iter().map(|r| {
- cx.ext_cx.item_use_simple(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public),
- cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
- }).chain(tested_submods.into_iter().map(|(r, sym)| {
- let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
- cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public),
- Some(r), path)
- })).collect();
-
- let reexport_mod = ast::Mod {
- inline: true,
- inner: DUMMY_SP,
- items,
- };
-
- let name = Ident::from_str("__test_reexports").gensym();
- let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
- cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent);
- let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item {
- ident: name,
- attrs: Vec::new(),
- id: ast::DUMMY_NODE_ID,
- node: ast::ItemKind::Mod(reexport_mod),
- vis: dummy_spanned(ast::VisibilityKind::Public),
- span: DUMMY_SP,
- tokens: None,
- })).pop().unwrap();
-
- (it, name)
-}
-
-/// Crawl over the crate, inserting test reexports and the test main function
-fn generate_test_harness(sess: &ParseSess,
- resolver: &mut dyn Resolver,
- reexport_test_harness_main: Option<Symbol>,
- krate: &mut ast::Crate,
- sd: &errors::Handler,
- features: &Features,
- test_runner: Option<ast::Path>) {
- // Remove the entry points
- let mut cleaner = EntryPointCleaner { depth: 0 };
- cleaner.visit_crate(krate);
-
- let mut econfig = ExpansionConfig::default("test".to_string());
- econfig.features = Some(features);
-
- let cx = TestCtxt {
- span_diagnostic: sd,
- ext_cx: ExtCtxt::new(sess, econfig, resolver),
- path: Vec::new(),
- test_cases: Vec::new(),
- reexport_test_harness_main,
- // N.B., doesn't consider the value of `--crate-name` passed on the command line.
- is_libtest: attr::find_crate_name(&krate.attrs)
- .map(|s| s == sym::test).unwrap_or(false),
- toplevel_reexport: None,
- features,
- test_runner
- };
-
- TestHarnessGenerator {
- cx,
- tests: Vec::new(),
- tested_submods: Vec::new(),
- }.visit_crate(krate);
-}
-
-enum HasTestSignature {
- Yes,
- No(BadTestSignature),
-}
-
-#[derive(PartialEq)]
-enum BadTestSignature {
- NotEvenAFunction,
- WrongTypeSignature,
- NoArgumentsAllowed,
- ShouldPanicOnlyWithNoArgs,
-}
-
-/// Creates a function item for use as the main function of a test build.
-/// This function will call the `test_runner` as specified by the crate attribute
-fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
- // Writing this out by hand:
- // pub fn main() {
- // #![main]
- // test::test_main_static(&[..tests]);
- // }
- let sp = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
- ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition,
- [sym::main, sym::test, sym::rustc_attrs][..].into(),
- ));
- let ecx = &cx.ext_cx;
- let test_id = Ident::with_empty_ctxt(sym::test);
-
- // test::test_main_static(...)
- let mut test_runner = cx.test_runner.clone().unwrap_or(
- ecx.path(sp, vec![
- test_id, ecx.ident_of("test_main_static")
- ]));
-
- test_runner.span = sp;
-
- let test_main_path_expr = ecx.expr_path(test_runner);
- let call_test_main = ecx.expr_call(sp, test_main_path_expr,
- vec![mk_tests_slice(cx)]);
- let call_test_main = ecx.stmt_expr(call_test_main);
-
- // #![main]
- let main_meta = ecx.meta_word(sp, sym::main);
- let main_attr = ecx.attribute(sp, main_meta);
-
- // extern crate test as test_gensym
- let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp,
- test_id,
- vec![],
- ast::ItemKind::ExternCrate(None)
- ));
-
- // pub fn main() { ... }
- let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
-
- // If no test runner is provided we need to import the test crate
- let main_body = if cx.test_runner.is_none() {
- ecx.block(sp, vec![test_extern_stmt, call_test_main])
- } else {
- ecx.block(sp, vec![call_test_main])
- };
-
- let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
- ast::FnHeader::default(),
- ast::Generics::default(),
- main_body);
-
- // Honor the reexport_test_harness_main attribute
- let main_id = match cx.reexport_test_harness_main {
- Some(sym) => Ident::new(sym, sp),
- None => Ident::from_str_and_span("main", sp).gensym(),
- };
-
- P(ast::Item {
- ident: main_id,
- attrs: vec![main_attr],
- id: ast::DUMMY_NODE_ID,
- node: main,
- vis: dummy_spanned(ast::VisibilityKind::Public),
- span: sp,
- tokens: None,
- })
-
-}
-
-fn path_name_i(idents: &[Ident]) -> String {
- let mut path_name = "".to_string();
- let mut idents_iter = idents.iter().peekable();
- while let Some(ident) = idents_iter.next() {
- path_name.push_str(&ident.as_str());
- if idents_iter.peek().is_some() {
- path_name.push_str("::")
- }
- }
- path_name
-}
-
-/// Creates a slice containing every test like so:
-/// &[path::to::test1, path::to::test2]
-fn mk_tests_slice(cx: &TestCtxt<'_>) -> P<ast::Expr> {
- debug!("building test vector from {} tests", cx.test_cases.len());
- let ref ecx = cx.ext_cx;
-
- ecx.expr_vec_slice(DUMMY_SP,
- cx.test_cases.iter().map(|test| {
- ecx.expr_addr_of(test.span,
- ecx.expr_path(ecx.path(test.span, visible_path(cx, &test.path))))
- }).collect())
-}
-
-/// Creates a path from the top-level __test module to the test via __test_reexports
-fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec<Ident>{
- let mut visible_path = vec![];
- match cx.toplevel_reexport {
- Some(id) => visible_path.push(id),
- None => {
- cx.span_diagnostic.bug("expected to find top-level re-export name, but found None");
- }
- }
- visible_path.extend_from_slice(path);
- visible_path
-}
-
-fn is_test_case(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, sym::rustc_test_marker)
-}
-
-fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
- let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
- test_attr.meta_item_list().map(|meta_list| {
- if meta_list.len() != 1 {
- sd.span_fatal(test_attr.span,
- "`#![test_runner(..)]` accepts exactly 1 argument").raise()
- }
- match meta_list[0].meta_item() {
- Some(meta_item) if meta_item.is_word() => meta_item.path.clone(),
- _ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise()
- }
- })
-}
fn visit_local(&mut self, l: &'ast Local) { walk_local(self, l) }
fn visit_block(&mut self, b: &'ast Block) { walk_block(self, b) }
fn visit_stmt(&mut self, s: &'ast Stmt) { walk_stmt(self, s) }
+ fn visit_arg(&mut self, arg: &'ast Arg) { walk_arg(self, arg) }
fn visit_arm(&mut self, a: &'ast Arm) { walk_arm(self, a) }
fn visit_pat(&mut self, p: &'ast Pat) { walk_pat(self, p) }
fn visit_anon_const(&mut self, c: &'ast AnonConst) { walk_anon_const(self, c) }
pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) {
match pattern.node {
- PatKind::TupleStruct(ref path, ref children, _) => {
+ PatKind::TupleStruct(ref path, ref elems) => {
visitor.visit_path(path, pattern.id);
- walk_list!(visitor, visit_pat, children);
+ walk_list!(visitor, visit_pat, elems);
}
PatKind::Path(ref opt_qself, ref path) => {
if let Some(ref qself) = *opt_qself {
visitor.visit_pat(&field.node.pat)
}
}
- PatKind::Tuple(ref tuple_elements, _) => {
- walk_list!(visitor, visit_pat, tuple_elements);
+ PatKind::Tuple(ref elems) => {
+ walk_list!(visitor, visit_pat, elems);
}
PatKind::Box(ref subpattern) |
PatKind::Ref(ref subpattern, _) |
visitor.visit_expr(lower_bound);
visitor.visit_expr(upper_bound);
}
- PatKind::Wild => (),
- PatKind::Slice(ref prepatterns, ref slice_pattern, ref postpatterns) => {
- walk_list!(visitor, visit_pat, prepatterns);
- walk_list!(visitor, visit_pat, slice_pattern);
- walk_list!(visitor, visit_pat, postpatterns);
+ PatKind::Wild | PatKind::Rest => {},
+ PatKind::Slice(ref elems) => {
+ walk_list!(visitor, visit_pat, elems);
}
PatKind::Mac(ref mac) => visitor.visit_mac(mac),
}
}
pub fn walk_fn_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_declaration: &'a FnDecl) {
- for argument in &function_declaration.inputs {
- walk_list!(visitor, visit_attribute, argument.attrs.iter());
- visitor.visit_pat(&argument.pat);
- visitor.visit_ty(&argument.ty);
+ for arg in &function_declaration.inputs {
+ visitor.visit_arg(arg);
}
- visitor.visit_fn_ret_ty(&function_declaration.output)
+ visitor.visit_fn_ret_ty(&function_declaration.output);
}
pub fn walk_fn<'a, V>(visitor: &mut V, kind: FnKind<'a>, declaration: &'a FnDecl, _span: Span)
visitor.visit_expr_post(expression)
}
+pub fn walk_arg<'a, V: Visitor<'a>>(visitor: &mut V, arg: &'a Arg) {
+ walk_list!(visitor, visit_attribute, arg.attrs.iter());
+ visitor.visit_pat(&arg.pat);
+ visitor.visit_ty(&arg.ty);
+}
+
pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
walk_list!(visitor, visit_pat, &arm.pats);
if let Some(ref e) = &arm.guard {
doctest = false
[dependencies]
-fmt_macros = { path = "../libfmt_macros" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
-syntax = { path = "../libsyntax" }
-syntax_pos = { path = "../libsyntax_pos" }
+fmt_macros = { path = "../libfmt_macros" }
+log = "0.4"
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_target = { path = "../librustc_target" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-log = "0.4"
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
+++ /dev/null
-use crate::proc_macro_impl::EXEC_STRATEGY;
-use crate::proc_macro_server;
-
-use errors::FatalError;
-use rustc_data_structures::sync::Lrc;
-use syntax::ast::{self, ItemKind, Attribute, Mac};
-use syntax::attr::{mark_used, mark_known};
-use syntax::source_map::Span;
-use syntax::ext::base::*;
-use syntax::parse;
-use syntax::parse::token;
-use syntax::tokenstream;
-use syntax::visit::Visitor;
-use syntax_pos::DUMMY_SP;
-
-struct MarkAttrs<'a>(&'a [ast::Name]);
-
-impl<'a> Visitor<'a> for MarkAttrs<'a> {
- fn visit_attribute(&mut self, attr: &Attribute) {
- if let Some(ident) = attr.ident() {
- if self.0.contains(&ident.name) {
- mark_used(attr);
- mark_known(attr);
- }
- }
- }
-
- fn visit_mac(&mut self, _mac: &Mac) {}
-}
-
-pub struct ProcMacroDerive {
- pub client: proc_macro::bridge::client::Client<
- fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
- >,
- pub attrs: Vec<ast::Name>,
-}
-
-impl MultiItemModifier for ProcMacroDerive {
- fn expand(&self,
- ecx: &mut ExtCtxt<'_>,
- span: Span,
- _meta_item: &ast::MetaItem,
- item: Annotatable)
- -> Vec<Annotatable> {
- let item = match item {
- Annotatable::Item(item) => item,
- Annotatable::ImplItem(_) |
- Annotatable::TraitItem(_) |
- Annotatable::ForeignItem(_) |
- Annotatable::Stmt(_) |
- Annotatable::Expr(_) => {
- ecx.span_err(span, "proc-macro derives may only be \
- applied to a struct, enum, or union");
- return Vec::new()
- }
- };
- match item.node {
- ItemKind::Struct(..) |
- ItemKind::Enum(..) |
- ItemKind::Union(..) => {},
- _ => {
- ecx.span_err(span, "proc-macro derives may only be \
- applied to a struct, enum, or union");
- return Vec::new()
- }
- }
-
- // Mark attributes as known, and used.
- MarkAttrs(&self.attrs).visit_item(&item);
-
- let token = token::Interpolated(Lrc::new(token::NtItem(item)));
- let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
-
- let server = proc_macro_server::Rustc::new(ecx);
- let stream = match self.client.run(&EXEC_STRATEGY, server, input) {
- Ok(stream) => stream,
- Err(e) => {
- let msg = "proc-macro derive panicked";
- let mut err = ecx.struct_span_fatal(span, msg);
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
-
- err.emit();
- FatalError.raise();
- }
- };
-
- let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
- let msg = "proc-macro derive produced unparseable tokens";
-
- let mut parser = parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
- let mut items = vec![];
-
- loop {
- match parser.parse_item() {
- Ok(None) => break,
- Ok(Some(item)) => {
- items.push(Annotatable::Item(item))
- }
- Err(mut err) => {
- // FIXME: handle this better
- err.cancel();
- ecx.struct_span_fatal(span, msg).emit();
- FatalError.raise();
- }
- }
- }
-
-
- // fail if there have been errors emitted
- if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
- ecx.struct_span_fatal(span, msg).emit();
- FatalError.raise();
- }
-
- items
- }
-}
}
}
-/// Call the method that is being derived on all the fields, and then
-/// process the collected results. i.e.
-///
-/// ```ignore (only-for-syntax-highlight)
-/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
-/// self_2.method(__arg_1_2, __arg_2_2)])
-/// ```
-#[inline]
-pub fn cs_same_method<F>(f: F,
- mut enum_nonmatch_f: EnumNonMatchCollapsedFunc<'_>,
- cx: &mut ExtCtxt<'_>,
- trait_span: Span,
- substructure: &Substructure<'_>)
- -> P<Expr>
- where F: FnOnce(&mut ExtCtxt<'_>, Span, Vec<P<Expr>>) -> P<Expr>
-{
- match *substructure.fields {
- EnumMatching(.., ref all_fields) |
- Struct(_, ref all_fields) => {
- // call self_n.method(other_1_n, other_2_n, ...)
- let called = all_fields.iter()
- .map(|field| {
- cx.expr_method_call(field.span,
- field.self_.clone(),
- substructure.method_ident,
- field.other
- .iter()
- .map(|e| cx.expr_addr_of(field.span, e.clone()))
- .collect())
- })
- .collect();
-
- f(cx, trait_span, called)
- }
- EnumNonMatchingCollapsed(ref all_self_args, _, tuple) => {
- enum_nonmatch_f(cx,
- trait_span,
- (&all_self_args[..], tuple),
- substructure.nonself_args)
- }
- StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
- }
-}
-
/// Returns `true` if the type has no value fields
/// (for an enum, no variant has any fields)
pub fn is_type_without_fields(item: &Annotatable) -> bool {
/// &'lifetime mut
Borrowed(Option<&'a str>, ast::Mutability),
/// *mut
+ #[allow(dead_code)]
Raw(ast::Mutability),
}
Tuple(Vec<Ty<'a>>),
}
-/// A const expression. Supports literals and blocks.
-#[derive(Clone, Eq, PartialEq)]
-pub enum Const {
- Literal,
- Block,
-}
-
pub fn borrowed_ptrty<'r>() -> PtrTy<'r> {
Borrowed(None, ast::Mutability::Immutable)
}
pub mod hash;
pub mod debug;
pub mod default;
-pub mod custom;
#[path="cmp/partial_eq.rs"]
pub mod partial_eq;
-#![allow(non_snake_case)]
-
use syntax::register_long_diagnostics;
// Error messages for EXXXX errors.
-//! Syntax extensions in the Rust compiler.
+//! This crate contains implementations of built-in macros and other code generating facilities
+//! injecting code into the crate before it is lowered to HIR.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(crate_visibility_modifier)]
#![feature(decl_macro)]
+#![feature(mem_take)]
#![feature(nll)]
-#![feature(proc_macro_diagnostic)]
-#![feature(proc_macro_internals)]
-#![feature(proc_macro_span)]
#![feature(rustc_diagnostic_macros)]
-#![feature(unicode_internals)]
-
-extern crate proc_macro;
use crate::deriving::*;
use syntax::ast::Ident;
use syntax::edition::Edition;
use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind, MacroExpanderFn};
-use syntax::ext::source_util;
use syntax::symbol::sym;
mod error_codes;
mod compile_error;
mod concat;
mod concat_idents;
+mod deriving;
mod env;
mod format;
mod format_foreign;
mod global_allocator;
mod global_asm;
mod log_syntax;
-mod proc_macro_server;
+mod source_util;
mod test;
-mod test_case;
mod trace_macros;
-pub mod deriving;
pub mod plugin_macro_defs;
-pub mod proc_macro_decls;
-pub mod proc_macro_impl;
+pub mod proc_macro_harness;
+pub mod standard_library_imports;
+pub mod test_harness;
pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, edition: Edition) {
let mut register = |name, kind| resolver.register_builtin_macro(
bench: test::expand_bench,
global_allocator: global_allocator::expand,
test: test::expand_test,
- test_case: test_case::expand,
+ test_case: test::expand_test_case,
}
register_derive! {
+++ /dev/null
-use std::mem;
-
-use syntax::ast::{self, Ident};
-use syntax::attr;
-use syntax::source_map::{ExpnInfo, ExpnKind, respan};
-use syntax::ext::base::{ExtCtxt, MacroKind};
-use syntax::ext::build::AstBuilder;
-use syntax::ext::expand::ExpansionConfig;
-use syntax::ext::hygiene::ExpnId;
-use syntax::mut_visit::MutVisitor;
-use syntax::parse::ParseSess;
-use syntax::ptr::P;
-use syntax::symbol::Symbol;
-use syntax::symbol::{kw, sym};
-use syntax::visit::{self, Visitor};
-
-use syntax_pos::{Span, DUMMY_SP};
-
-const PROC_MACRO_KINDS: [Symbol; 3] = [
- sym::proc_macro_derive,
- sym::proc_macro_attribute,
- sym::proc_macro
-];
-
-struct ProcMacroDerive {
- trait_name: ast::Name,
- function_name: Ident,
- span: Span,
- attrs: Vec<ast::Name>,
-}
-
-struct ProcMacroDef {
- function_name: Ident,
- span: Span,
-}
-
-struct CollectProcMacros<'a> {
- derives: Vec<ProcMacroDerive>,
- attr_macros: Vec<ProcMacroDef>,
- bang_macros: Vec<ProcMacroDef>,
- in_root: bool,
- handler: &'a errors::Handler,
- is_proc_macro_crate: bool,
- is_test_crate: bool,
-}
-
-pub fn modify(sess: &ParseSess,
- resolver: &mut dyn (::syntax::ext::base::Resolver),
- mut krate: ast::Crate,
- is_proc_macro_crate: bool,
- has_proc_macro_decls: bool,
- is_test_crate: bool,
- num_crate_types: usize,
- handler: &errors::Handler) -> ast::Crate {
- let ecfg = ExpansionConfig::default("proc_macro".to_string());
- let mut cx = ExtCtxt::new(sess, ecfg, resolver);
-
- let (derives, attr_macros, bang_macros) = {
- let mut collect = CollectProcMacros {
- derives: Vec::new(),
- attr_macros: Vec::new(),
- bang_macros: Vec::new(),
- in_root: true,
- handler,
- is_proc_macro_crate,
- is_test_crate,
- };
- if has_proc_macro_decls || is_proc_macro_crate {
- visit::walk_crate(&mut collect, &krate);
- }
- (collect.derives, collect.attr_macros, collect.bang_macros)
- };
-
- if !is_proc_macro_crate {
- return krate
- }
-
- if num_crate_types > 1 {
- handler.err("cannot mix `proc-macro` crate type with others");
- }
-
- if is_test_crate {
- return krate;
- }
-
- krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros));
-
- krate
-}
-
-pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
- PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(*kind))
-}
-
-impl<'a> CollectProcMacros<'a> {
- fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
- if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() {
- self.handler.span_err(sp,
- "`proc-macro` crate types cannot \
- export any items other than functions \
- tagged with `#[proc_macro_derive]` currently");
- }
- }
-
- fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
- // Once we've located the `#[proc_macro_derive]` attribute, verify
- // that it's of the form `#[proc_macro_derive(Foo)]` or
- // `#[proc_macro_derive(Foo, attributes(A, ..))]`
- let list = match attr.meta_item_list() {
- Some(list) => list,
- None => return,
- };
- if list.len() != 1 && list.len() != 2 {
- self.handler.span_err(attr.span,
- "attribute must have either one or two arguments");
- return
- }
- let trait_attr = match list[0].meta_item() {
- Some(meta_item) => meta_item,
- _ => {
- self.handler.span_err(list[0].span(), "not a meta item");
- return
- }
- };
- let trait_ident = match trait_attr.ident() {
- Some(trait_ident) if trait_attr.is_word() => trait_ident,
- _ => {
- self.handler.span_err(trait_attr.span, "must only be one word");
- return
- }
- };
-
- if !trait_ident.name.can_be_raw() {
- self.handler.span_err(trait_attr.span,
- &format!("`{}` cannot be a name of derive macro", trait_ident));
- }
-
- let attributes_attr = list.get(1);
- let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
- if !attr.check_name(sym::attributes) {
- self.handler.span_err(attr.span(), "second argument must be `attributes`")
- }
- attr.meta_item_list().unwrap_or_else(|| {
- self.handler.span_err(attr.span(),
- "attribute must be of form: `attributes(foo, bar)`");
- &[]
- }).into_iter().filter_map(|attr| {
- let attr = match attr.meta_item() {
- Some(meta_item) => meta_item,
- _ => {
- self.handler.span_err(attr.span(), "not a meta item");
- return None;
- }
- };
-
- let ident = match attr.ident() {
- Some(ident) if attr.is_word() => ident,
- _ => {
- self.handler.span_err(attr.span, "must only be one word");
- return None;
- }
- };
- if !ident.name.can_be_raw() {
- self.handler.span_err(
- attr.span,
- &format!("`{}` cannot be a name of derive helper attribute", ident),
- );
- }
-
- Some(ident.name)
- }).collect()
- } else {
- Vec::new()
- };
-
- if self.in_root && item.vis.node.is_pub() {
- self.derives.push(ProcMacroDerive {
- span: item.span,
- trait_name: trait_ident.name,
- function_name: item.ident,
- attrs: proc_attrs,
- });
- } else {
- let msg = if !self.in_root {
- "functions tagged with `#[proc_macro_derive]` must \
- currently reside in the root of the crate"
- } else {
- "functions tagged with `#[proc_macro_derive]` must be `pub`"
- };
- self.handler.span_err(item.span, msg);
- }
- }
-
- fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) {
- if self.in_root && item.vis.node.is_pub() {
- self.attr_macros.push(ProcMacroDef {
- span: item.span,
- function_name: item.ident,
- });
- } else {
- let msg = if !self.in_root {
- "functions tagged with `#[proc_macro_attribute]` must \
- currently reside in the root of the crate"
- } else {
- "functions tagged with `#[proc_macro_attribute]` must be `pub`"
- };
- self.handler.span_err(item.span, msg);
- }
- }
-
- fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
- if self.in_root && item.vis.node.is_pub() {
- self.bang_macros.push(ProcMacroDef {
- span: item.span,
- function_name: item.ident,
- });
- } else {
- let msg = if !self.in_root {
- "functions tagged with `#[proc_macro]` must \
- currently reside in the root of the crate"
- } else {
- "functions tagged with `#[proc_macro]` must be `pub`"
- };
- self.handler.span_err(item.span, msg);
- }
- }
-}
-
-impl<'a> Visitor<'a> for CollectProcMacros<'a> {
- fn visit_item(&mut self, item: &'a ast::Item) {
- if let ast::ItemKind::MacroDef(..) = item.node {
- if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
- let msg =
- "cannot export macro_rules! macros from a `proc-macro` crate type currently";
- self.handler.span_err(item.span, msg);
- }
- }
-
- // First up, make sure we're checking a bare function. If we're not then
- // we're just not interested in this item.
- //
- // If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
- let is_fn = match item.node {
- ast::ItemKind::Fn(..) => true,
- _ => false,
- };
-
- let mut found_attr: Option<&'a ast::Attribute> = None;
-
- for attr in &item.attrs {
- if is_proc_macro_attr(&attr) {
- if let Some(prev_attr) = found_attr {
- let msg = if attr.path.segments[0].ident.name ==
- prev_attr.path.segments[0].ident.name {
- format!("only one `#[{}]` attribute is allowed on any given function",
- attr.path)
- } else {
- format!("`#[{}]` and `#[{}]` attributes cannot both be applied \
- to the same function", attr.path, prev_attr.path)
- };
-
- self.handler.struct_span_err(attr.span, &msg)
- .span_note(prev_attr.span, "previous attribute here")
- .emit();
-
- return;
- }
-
- found_attr = Some(attr);
- }
- }
-
- let attr = match found_attr {
- None => {
- self.check_not_pub_in_root(&item.vis, item.span);
- let prev_in_root = mem::replace(&mut self.in_root, false);
- visit::walk_item(self, item);
- self.in_root = prev_in_root;
- return;
- },
- Some(attr) => attr,
- };
-
- if !is_fn {
- let msg = format!("the `#[{}]` attribute may only be used on bare functions",
- attr.path);
-
- self.handler.span_err(attr.span, &msg);
- return;
- }
-
- if self.is_test_crate {
- return;
- }
-
- if !self.is_proc_macro_crate {
- let msg = format!("the `#[{}]` attribute is only usable with crates of the \
- `proc-macro` crate type", attr.path);
-
- self.handler.span_err(attr.span, &msg);
- return;
- }
-
- if attr.check_name(sym::proc_macro_derive) {
- self.collect_custom_derive(item, attr);
- } else if attr.check_name(sym::proc_macro_attribute) {
- self.collect_attr_proc_macro(item);
- } else if attr.check_name(sym::proc_macro) {
- self.collect_bang_proc_macro(item);
- };
-
- let prev_in_root = mem::replace(&mut self.in_root, false);
- visit::walk_item(self, item);
- self.in_root = prev_in_root;
- }
-
- fn visit_mac(&mut self, mac: &'a ast::Mac) {
- visit::walk_mac(self, mac)
- }
-}
-
-// Creates a new module which looks like:
-//
-// #[doc(hidden)]
-// mod $gensym {
-// extern crate proc_macro;
-//
-// use proc_macro::bridge::client::ProcMacro;
-//
-// #[rustc_proc_macro_decls]
-// static DECLS: &[ProcMacro] = &[
-// ProcMacro::custom_derive($name_trait1, &[], ::$name1);
-// ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2);
-// // ...
-// ];
-// }
-fn mk_decls(
- cx: &mut ExtCtxt<'_>,
- custom_derives: &[ProcMacroDerive],
- custom_attrs: &[ProcMacroDef],
- custom_macros: &[ProcMacroDef],
-) -> P<ast::Item> {
- let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
- ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition,
- [sym::rustc_attrs, sym::proc_macro_internals][..].into(),
- ));
-
- let hidden = cx.meta_list_item_word(span, sym::hidden);
- let doc = cx.meta_list(span, sym::doc, vec![hidden]);
- let doc_hidden = cx.attribute(span, doc);
-
- let proc_macro = Ident::with_empty_ctxt(sym::proc_macro);
- let krate = cx.item(span,
- proc_macro,
- Vec::new(),
- ast::ItemKind::ExternCrate(None));
-
- let bridge = Ident::from_str("bridge");
- let client = Ident::from_str("client");
- let proc_macro_ty = Ident::from_str("ProcMacro");
- let custom_derive = Ident::from_str("custom_derive");
- let attr = Ident::from_str("attr");
- let bang = Ident::from_str("bang");
- let crate_kw = Ident::with_empty_ctxt(kw::Crate);
-
- let decls = {
- let local_path = |sp: Span, name| {
- cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name]))
- };
- let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![
- proc_macro, bridge, client, proc_macro_ty, method,
- ]));
- custom_derives.iter().map(|cd| {
- cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
- cx.expr_str(cd.span, cd.trait_name),
- cx.expr_vec_slice(
- span,
- cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
- ),
- local_path(cd.span, cd.function_name),
- ])
- }).chain(custom_attrs.iter().map(|ca| {
- cx.expr_call(span, proc_macro_ty_method_path(attr), vec![
- cx.expr_str(ca.span, ca.function_name.name),
- local_path(ca.span, ca.function_name),
- ])
- })).chain(custom_macros.iter().map(|cm| {
- cx.expr_call(span, proc_macro_ty_method_path(bang), vec![
- cx.expr_str(cm.span, cm.function_name.name),
- local_path(cm.span, cm.function_name),
- ])
- })).collect()
- };
-
- let decls_static = cx.item_static(
- span,
- Ident::from_str("_DECLS"),
- cx.ty_rptr(span,
- cx.ty(span, ast::TyKind::Slice(
- cx.ty_path(cx.path(span,
- vec![proc_macro, bridge, client, proc_macro_ty])))),
- None, ast::Mutability::Immutable),
- ast::Mutability::Immutable,
- cx.expr_vec_slice(span, decls),
- ).map(|mut i| {
- let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);
- i.attrs.push(cx.attribute(span, attr));
- i.vis = respan(span, ast::VisibilityKind::Public);
- i
- });
-
- let module = cx.item_mod(
- span,
- span,
- ast::Ident::from_str("decls").gensym(),
- vec![doc_hidden],
- vec![krate, decls_static],
- ).map(|mut i| {
- i.vis = respan(span, ast::VisibilityKind::Public);
- i
- });
-
- cx.monotonic_expander().flat_map_item(module).pop().unwrap()
-}
--- /dev/null
+use std::mem;
+
+use syntax::ast::{self, Ident};
+use syntax::attr;
+use syntax::source_map::{ExpnInfo, ExpnKind, respan};
+use syntax::ext::base::{ExtCtxt, MacroKind};
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::ExpnId;
+use syntax::ext::proc_macro::is_proc_macro_attr;
+use syntax::mut_visit::MutVisitor;
+use syntax::parse::ParseSess;
+use syntax::ptr::P;
+use syntax::symbol::{kw, sym};
+use syntax::visit::{self, Visitor};
+
+use syntax_pos::{Span, DUMMY_SP};
+
+struct ProcMacroDerive {
+ trait_name: ast::Name,
+ function_name: Ident,
+ span: Span,
+ attrs: Vec<ast::Name>,
+}
+
+struct ProcMacroDef {
+ function_name: Ident,
+ span: Span,
+}
+
+struct CollectProcMacros<'a> {
+ derives: Vec<ProcMacroDerive>,
+ attr_macros: Vec<ProcMacroDef>,
+ bang_macros: Vec<ProcMacroDef>,
+ in_root: bool,
+ handler: &'a errors::Handler,
+ is_proc_macro_crate: bool,
+ is_test_crate: bool,
+}
+
+pub fn inject(sess: &ParseSess,
+ resolver: &mut dyn (::syntax::ext::base::Resolver),
+ mut krate: ast::Crate,
+ is_proc_macro_crate: bool,
+ has_proc_macro_decls: bool,
+ is_test_crate: bool,
+ num_crate_types: usize,
+ handler: &errors::Handler) -> ast::Crate {
+ let ecfg = ExpansionConfig::default("proc_macro".to_string());
+ let mut cx = ExtCtxt::new(sess, ecfg, resolver);
+
+ let (derives, attr_macros, bang_macros) = {
+ let mut collect = CollectProcMacros {
+ derives: Vec::new(),
+ attr_macros: Vec::new(),
+ bang_macros: Vec::new(),
+ in_root: true,
+ handler,
+ is_proc_macro_crate,
+ is_test_crate,
+ };
+ if has_proc_macro_decls || is_proc_macro_crate {
+ visit::walk_crate(&mut collect, &krate);
+ }
+ (collect.derives, collect.attr_macros, collect.bang_macros)
+ };
+
+ if !is_proc_macro_crate {
+ return krate
+ }
+
+ if num_crate_types > 1 {
+ handler.err("cannot mix `proc-macro` crate type with others");
+ }
+
+ if is_test_crate {
+ return krate;
+ }
+
+ krate.module.items.push(mk_decls(&mut cx, &derives, &attr_macros, &bang_macros));
+
+ krate
+}
+
+impl<'a> CollectProcMacros<'a> {
+ fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
+ if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() {
+ self.handler.span_err(sp,
+ "`proc-macro` crate types cannot \
+ export any items other than functions \
+ tagged with `#[proc_macro_derive]` currently");
+ }
+ }
+
+ fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
+ // Once we've located the `#[proc_macro_derive]` attribute, verify
+ // that it's of the form `#[proc_macro_derive(Foo)]` or
+ // `#[proc_macro_derive(Foo, attributes(A, ..))]`
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
+ None => return,
+ };
+ if list.len() != 1 && list.len() != 2 {
+ self.handler.span_err(attr.span,
+ "attribute must have either one or two arguments");
+ return
+ }
+ let trait_attr = match list[0].meta_item() {
+ Some(meta_item) => meta_item,
+ _ => {
+ self.handler.span_err(list[0].span(), "not a meta item");
+ return
+ }
+ };
+ let trait_ident = match trait_attr.ident() {
+ Some(trait_ident) if trait_attr.is_word() => trait_ident,
+ _ => {
+ self.handler.span_err(trait_attr.span, "must only be one word");
+ return
+ }
+ };
+
+ if !trait_ident.name.can_be_raw() {
+ self.handler.span_err(trait_attr.span,
+ &format!("`{}` cannot be a name of derive macro", trait_ident));
+ }
+
+ let attributes_attr = list.get(1);
+ let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
+ if !attr.check_name(sym::attributes) {
+ self.handler.span_err(attr.span(), "second argument must be `attributes`")
+ }
+ attr.meta_item_list().unwrap_or_else(|| {
+ self.handler.span_err(attr.span(),
+ "attribute must be of form: `attributes(foo, bar)`");
+ &[]
+ }).into_iter().filter_map(|attr| {
+ let attr = match attr.meta_item() {
+ Some(meta_item) => meta_item,
+ _ => {
+ self.handler.span_err(attr.span(), "not a meta item");
+ return None;
+ }
+ };
+
+ let ident = match attr.ident() {
+ Some(ident) if attr.is_word() => ident,
+ _ => {
+ self.handler.span_err(attr.span, "must only be one word");
+ return None;
+ }
+ };
+ if !ident.name.can_be_raw() {
+ self.handler.span_err(
+ attr.span,
+ &format!("`{}` cannot be a name of derive helper attribute", ident),
+ );
+ }
+
+ Some(ident.name)
+ }).collect()
+ } else {
+ Vec::new()
+ };
+
+ if self.in_root && item.vis.node.is_pub() {
+ self.derives.push(ProcMacroDerive {
+ span: item.span,
+ trait_name: trait_ident.name,
+ function_name: item.ident,
+ attrs: proc_attrs,
+ });
+ } else {
+ let msg = if !self.in_root {
+ "functions tagged with `#[proc_macro_derive]` must \
+ currently reside in the root of the crate"
+ } else {
+ "functions tagged with `#[proc_macro_derive]` must be `pub`"
+ };
+ self.handler.span_err(item.span, msg);
+ }
+ }
+
+ fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) {
+ if self.in_root && item.vis.node.is_pub() {
+ self.attr_macros.push(ProcMacroDef {
+ span: item.span,
+ function_name: item.ident,
+ });
+ } else {
+ let msg = if !self.in_root {
+ "functions tagged with `#[proc_macro_attribute]` must \
+ currently reside in the root of the crate"
+ } else {
+ "functions tagged with `#[proc_macro_attribute]` must be `pub`"
+ };
+ self.handler.span_err(item.span, msg);
+ }
+ }
+
+ fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) {
+ if self.in_root && item.vis.node.is_pub() {
+ self.bang_macros.push(ProcMacroDef {
+ span: item.span,
+ function_name: item.ident,
+ });
+ } else {
+ let msg = if !self.in_root {
+ "functions tagged with `#[proc_macro]` must \
+ currently reside in the root of the crate"
+ } else {
+ "functions tagged with `#[proc_macro]` must be `pub`"
+ };
+ self.handler.span_err(item.span, msg);
+ }
+ }
+}
+
+impl<'a> Visitor<'a> for CollectProcMacros<'a> {
+ fn visit_item(&mut self, item: &'a ast::Item) {
+ if let ast::ItemKind::MacroDef(..) = item.node {
+ if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
+ let msg =
+ "cannot export macro_rules! macros from a `proc-macro` crate type currently";
+ self.handler.span_err(item.span, msg);
+ }
+ }
+
+ // First up, make sure we're checking a bare function. If we're not then
+ // we're just not interested in this item.
+ //
+ // If we find one, try to locate a `#[proc_macro_derive]` attribute on it.
+ let is_fn = match item.node {
+ ast::ItemKind::Fn(..) => true,
+ _ => false,
+ };
+
+ let mut found_attr: Option<&'a ast::Attribute> = None;
+
+ for attr in &item.attrs {
+ if is_proc_macro_attr(&attr) {
+ if let Some(prev_attr) = found_attr {
+ let msg = if attr.path.segments[0].ident.name ==
+ prev_attr.path.segments[0].ident.name {
+ format!("only one `#[{}]` attribute is allowed on any given function",
+ attr.path)
+ } else {
+ format!("`#[{}]` and `#[{}]` attributes cannot both be applied \
+ to the same function", attr.path, prev_attr.path)
+ };
+
+ self.handler.struct_span_err(attr.span, &msg)
+ .span_note(prev_attr.span, "previous attribute here")
+ .emit();
+
+ return;
+ }
+
+ found_attr = Some(attr);
+ }
+ }
+
+ let attr = match found_attr {
+ None => {
+ self.check_not_pub_in_root(&item.vis, item.span);
+ let prev_in_root = mem::replace(&mut self.in_root, false);
+ visit::walk_item(self, item);
+ self.in_root = prev_in_root;
+ return;
+ },
+ Some(attr) => attr,
+ };
+
+ if !is_fn {
+ let msg = format!("the `#[{}]` attribute may only be used on bare functions",
+ attr.path);
+
+ self.handler.span_err(attr.span, &msg);
+ return;
+ }
+
+ if self.is_test_crate {
+ return;
+ }
+
+ if !self.is_proc_macro_crate {
+ let msg = format!("the `#[{}]` attribute is only usable with crates of the \
+ `proc-macro` crate type", attr.path);
+
+ self.handler.span_err(attr.span, &msg);
+ return;
+ }
+
+ if attr.check_name(sym::proc_macro_derive) {
+ self.collect_custom_derive(item, attr);
+ } else if attr.check_name(sym::proc_macro_attribute) {
+ self.collect_attr_proc_macro(item);
+ } else if attr.check_name(sym::proc_macro) {
+ self.collect_bang_proc_macro(item);
+ };
+
+ let prev_in_root = mem::replace(&mut self.in_root, false);
+ visit::walk_item(self, item);
+ self.in_root = prev_in_root;
+ }
+
+ fn visit_mac(&mut self, mac: &'a ast::Mac) {
+ visit::walk_mac(self, mac)
+ }
+}
+
+// Creates a new module which looks like:
+//
+// #[doc(hidden)]
+// mod $gensym {
+// extern crate proc_macro;
+//
+// use proc_macro::bridge::client::ProcMacro;
+//
+// #[rustc_proc_macro_decls]
+// static DECLS: &[ProcMacro] = &[
+// ProcMacro::custom_derive($name_trait1, &[], ::$name1);
+// ProcMacro::custom_derive($name_trait2, &["attribute_name"], ::$name2);
+// // ...
+// ];
+// }
+fn mk_decls(
+ cx: &mut ExtCtxt<'_>,
+ custom_derives: &[ProcMacroDerive],
+ custom_attrs: &[ProcMacroDef],
+ custom_macros: &[ProcMacroDef],
+) -> P<ast::Item> {
+ let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
+ ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition,
+ [sym::rustc_attrs, sym::proc_macro_internals][..].into(),
+ ));
+
+ let hidden = cx.meta_list_item_word(span, sym::hidden);
+ let doc = cx.meta_list(span, sym::doc, vec![hidden]);
+ let doc_hidden = cx.attribute(span, doc);
+
+ let proc_macro = Ident::with_empty_ctxt(sym::proc_macro);
+ let krate = cx.item(span,
+ proc_macro,
+ Vec::new(),
+ ast::ItemKind::ExternCrate(None));
+
+ let bridge = Ident::from_str("bridge");
+ let client = Ident::from_str("client");
+ let proc_macro_ty = Ident::from_str("ProcMacro");
+ let custom_derive = Ident::from_str("custom_derive");
+ let attr = Ident::from_str("attr");
+ let bang = Ident::from_str("bang");
+ let crate_kw = Ident::with_empty_ctxt(kw::Crate);
+
+ let decls = {
+ let local_path = |sp: Span, name| {
+ cx.expr_path(cx.path(sp.with_ctxt(span.ctxt()), vec![crate_kw, name]))
+ };
+ let proc_macro_ty_method_path = |method| cx.expr_path(cx.path(span, vec![
+ proc_macro, bridge, client, proc_macro_ty, method,
+ ]));
+ custom_derives.iter().map(|cd| {
+ cx.expr_call(span, proc_macro_ty_method_path(custom_derive), vec![
+ cx.expr_str(cd.span, cd.trait_name),
+ cx.expr_vec_slice(
+ span,
+ cd.attrs.iter().map(|&s| cx.expr_str(cd.span, s)).collect::<Vec<_>>()
+ ),
+ local_path(cd.span, cd.function_name),
+ ])
+ }).chain(custom_attrs.iter().map(|ca| {
+ cx.expr_call(span, proc_macro_ty_method_path(attr), vec![
+ cx.expr_str(ca.span, ca.function_name.name),
+ local_path(ca.span, ca.function_name),
+ ])
+ })).chain(custom_macros.iter().map(|cm| {
+ cx.expr_call(span, proc_macro_ty_method_path(bang), vec![
+ cx.expr_str(cm.span, cm.function_name.name),
+ local_path(cm.span, cm.function_name),
+ ])
+ })).collect()
+ };
+
+ let decls_static = cx.item_static(
+ span,
+ Ident::from_str("_DECLS"),
+ cx.ty_rptr(span,
+ cx.ty(span, ast::TyKind::Slice(
+ cx.ty_path(cx.path(span,
+ vec![proc_macro, bridge, client, proc_macro_ty])))),
+ None, ast::Mutability::Immutable),
+ ast::Mutability::Immutable,
+ cx.expr_vec_slice(span, decls),
+ ).map(|mut i| {
+ let attr = cx.meta_word(span, sym::rustc_proc_macro_decls);
+ i.attrs.push(cx.attribute(span, attr));
+ i.vis = respan(span, ast::VisibilityKind::Public);
+ i
+ });
+
+ let module = cx.item_mod(
+ span,
+ span,
+ ast::Ident::from_str("decls").gensym(),
+ vec![doc_hidden],
+ vec![krate, decls_static],
+ ).map(|mut i| {
+ i.vis = respan(span, ast::VisibilityKind::Public);
+ i
+ });
+
+ cx.monotonic_expander().flat_map_item(module).pop().unwrap()
+}
+++ /dev/null
-use crate::proc_macro_server;
-
-use errors::FatalError;
-use syntax::source_map::Span;
-use syntax::ext::base::{self, *};
-use syntax::tokenstream::TokenStream;
-
-pub const EXEC_STRATEGY: proc_macro::bridge::server::SameThread =
- proc_macro::bridge::server::SameThread;
-
-pub struct AttrProcMacro {
- pub client: proc_macro::bridge::client::Client<
- fn(proc_macro::TokenStream, proc_macro::TokenStream) -> proc_macro::TokenStream,
- >,
-}
-
-impl base::AttrProcMacro for AttrProcMacro {
- fn expand<'cx>(&self,
- ecx: &'cx mut ExtCtxt<'_>,
- span: Span,
- annotation: TokenStream,
- annotated: TokenStream)
- -> TokenStream {
- let server = proc_macro_server::Rustc::new(ecx);
- match self.client.run(&EXEC_STRATEGY, server, annotation, annotated) {
- Ok(stream) => stream,
- Err(e) => {
- let msg = "custom attribute panicked";
- let mut err = ecx.struct_span_fatal(span, msg);
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
-
- err.emit();
- FatalError.raise();
- }
- }
- }
-}
-
-pub struct BangProcMacro {
- pub client: proc_macro::bridge::client::Client<
- fn(proc_macro::TokenStream) -> proc_macro::TokenStream,
- >,
-}
-
-impl base::ProcMacro for BangProcMacro {
- fn expand<'cx>(&self,
- ecx: &'cx mut ExtCtxt<'_>,
- span: Span,
- input: TokenStream)
- -> TokenStream {
- let server = proc_macro_server::Rustc::new(ecx);
- match self.client.run(&EXEC_STRATEGY, server, input) {
- Ok(stream) => stream,
- Err(e) => {
- let msg = "proc macro panicked";
- let mut err = ecx.struct_span_fatal(span, msg);
- if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
- }
-
- err.emit();
- FatalError.raise();
- }
- }
- }
-}
+++ /dev/null
-use errors::{Diagnostic, DiagnosticBuilder};
-
-use std::panic;
-
-use proc_macro::bridge::{server, TokenTree};
-use proc_macro::{Delimiter, Level, LineColumn, Spacing};
-
-use rustc_data_structures::sync::Lrc;
-use std::ascii;
-use std::ops::Bound;
-use syntax::ast;
-use syntax::ext::base::ExtCtxt;
-use syntax::parse::lexer::comments;
-use syntax::parse::{self, token, ParseSess};
-use syntax::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
-use syntax_pos::hygiene::{SyntaxContext, Transparency};
-use syntax_pos::symbol::{kw, sym, Symbol};
-use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
-
-trait FromInternal<T> {
- fn from_internal(x: T) -> Self;
-}
-
-trait ToInternal<T> {
- fn to_internal(self) -> T;
-}
-
-impl FromInternal<token::DelimToken> for Delimiter {
- fn from_internal(delim: token::DelimToken) -> Delimiter {
- match delim {
- token::Paren => Delimiter::Parenthesis,
- token::Brace => Delimiter::Brace,
- token::Bracket => Delimiter::Bracket,
- token::NoDelim => Delimiter::None,
- }
- }
-}
-
-impl ToInternal<token::DelimToken> for Delimiter {
- fn to_internal(self) -> token::DelimToken {
- match self {
- Delimiter::Parenthesis => token::Paren,
- Delimiter::Brace => token::Brace,
- Delimiter::Bracket => token::Bracket,
- Delimiter::None => token::NoDelim,
- }
- }
-}
-
-impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
- for TokenTree<Group, Punct, Ident, Literal>
-{
- fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
- -> Self {
- use syntax::parse::token::*;
-
- let joint = is_joint == Joint;
- let Token { kind, span } = match tree {
- tokenstream::TokenTree::Delimited(span, delim, tts) => {
- let delimiter = Delimiter::from_internal(delim);
- return TokenTree::Group(Group {
- delimiter,
- stream: tts.into(),
- span,
- });
- }
- tokenstream::TokenTree::Token(token) => token,
- };
-
- macro_rules! tt {
- ($ty:ident { $($field:ident $(: $value:expr)*),+ $(,)? }) => (
- TokenTree::$ty(self::$ty {
- $($field $(: $value)*,)+
- span,
- })
- );
- ($ty:ident::$method:ident($($value:expr),*)) => (
- TokenTree::$ty(self::$ty::$method($($value,)* span))
- );
- }
- macro_rules! op {
- ($a:expr) => {
- tt!(Punct::new($a, joint))
- };
- ($a:expr, $b:expr) => {{
- stack.push(tt!(Punct::new($b, joint)));
- tt!(Punct::new($a, true))
- }};
- ($a:expr, $b:expr, $c:expr) => {{
- stack.push(tt!(Punct::new($c, joint)));
- stack.push(tt!(Punct::new($b, true)));
- tt!(Punct::new($a, true))
- }};
- }
-
- match kind {
- Eq => op!('='),
- Lt => op!('<'),
- Le => op!('<', '='),
- EqEq => op!('=', '='),
- Ne => op!('!', '='),
- Ge => op!('>', '='),
- Gt => op!('>'),
- AndAnd => op!('&', '&'),
- OrOr => op!('|', '|'),
- Not => op!('!'),
- Tilde => op!('~'),
- BinOp(Plus) => op!('+'),
- BinOp(Minus) => op!('-'),
- BinOp(Star) => op!('*'),
- BinOp(Slash) => op!('/'),
- BinOp(Percent) => op!('%'),
- BinOp(Caret) => op!('^'),
- BinOp(And) => op!('&'),
- BinOp(Or) => op!('|'),
- BinOp(Shl) => op!('<', '<'),
- BinOp(Shr) => op!('>', '>'),
- BinOpEq(Plus) => op!('+', '='),
- BinOpEq(Minus) => op!('-', '='),
- BinOpEq(Star) => op!('*', '='),
- BinOpEq(Slash) => op!('/', '='),
- BinOpEq(Percent) => op!('%', '='),
- BinOpEq(Caret) => op!('^', '='),
- BinOpEq(And) => op!('&', '='),
- BinOpEq(Or) => op!('|', '='),
- BinOpEq(Shl) => op!('<', '<', '='),
- BinOpEq(Shr) => op!('>', '>', '='),
- At => op!('@'),
- Dot => op!('.'),
- DotDot => op!('.', '.'),
- DotDotDot => op!('.', '.', '.'),
- DotDotEq => op!('.', '.', '='),
- Comma => op!(','),
- Semi => op!(';'),
- Colon => op!(':'),
- ModSep => op!(':', ':'),
- RArrow => op!('-', '>'),
- LArrow => op!('<', '-'),
- FatArrow => op!('=', '>'),
- Pound => op!('#'),
- Dollar => op!('$'),
- Question => op!('?'),
- SingleQuote => op!('\''),
-
- Ident(name, false) if name == kw::DollarCrate => tt!(Ident::dollar_crate()),
- Ident(name, is_raw) => tt!(Ident::new(name, is_raw)),
- Lifetime(name) => {
- let ident = ast::Ident::new(name, span).without_first_quote();
- stack.push(tt!(Ident::new(ident.name, false)));
- tt!(Punct::new('\'', true))
- }
- Literal(lit) => tt!(Literal { lit }),
- DocComment(c) => {
- let style = comments::doc_comment_style(&c.as_str());
- let stripped = comments::strip_doc_comment_decoration(&c.as_str());
- let mut escaped = String::new();
- for ch in stripped.chars() {
- escaped.extend(ch.escape_debug());
- }
- let stream = vec![
- Ident(sym::doc, false),
- Eq,
- TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
- ]
- .into_iter()
- .map(|kind| tokenstream::TokenTree::token(kind, span))
- .collect();
- stack.push(TokenTree::Group(Group {
- delimiter: Delimiter::Bracket,
- stream,
- span: DelimSpan::from_single(span),
- }));
- if style == ast::AttrStyle::Inner {
- stack.push(tt!(Punct::new('!', false)));
- }
- tt!(Punct::new('#', false))
- }
-
- Interpolated(nt) => {
- let stream = nt.to_tokenstream(sess, span);
- TokenTree::Group(Group {
- delimiter: Delimiter::None,
- stream,
- span: DelimSpan::from_single(span),
- })
- }
-
- OpenDelim(..) | CloseDelim(..) => unreachable!(),
- Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
- }
- }
-}
-
-impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
- fn to_internal(self) -> TokenStream {
- use syntax::parse::token::*;
-
- let (ch, joint, span) = match self {
- TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
- TokenTree::Group(Group {
- delimiter,
- stream,
- span,
- }) => {
- return tokenstream::TokenTree::Delimited(
- span,
- delimiter.to_internal(),
- stream.into(),
- )
- .into();
- }
- TokenTree::Ident(self::Ident { sym, is_raw, span }) => {
- return tokenstream::TokenTree::token(Ident(sym, is_raw), span).into();
- }
- TokenTree::Literal(self::Literal {
- lit: token::Lit { kind: token::Integer, symbol, suffix },
- span,
- }) if symbol.as_str().starts_with("-") => {
- let minus = BinOp(BinOpToken::Minus);
- let symbol = Symbol::intern(&symbol.as_str()[1..]);
- let integer = TokenKind::lit(token::Integer, symbol, suffix);
- let a = tokenstream::TokenTree::token(minus, span);
- let b = tokenstream::TokenTree::token(integer, span);
- return vec![a, b].into_iter().collect();
- }
- TokenTree::Literal(self::Literal {
- lit: token::Lit { kind: token::Float, symbol, suffix },
- span,
- }) if symbol.as_str().starts_with("-") => {
- let minus = BinOp(BinOpToken::Minus);
- let symbol = Symbol::intern(&symbol.as_str()[1..]);
- let float = TokenKind::lit(token::Float, symbol, suffix);
- let a = tokenstream::TokenTree::token(minus, span);
- let b = tokenstream::TokenTree::token(float, span);
- return vec![a, b].into_iter().collect();
- }
- TokenTree::Literal(self::Literal { lit, span }) => {
- return tokenstream::TokenTree::token(Literal(lit), span).into()
- }
- };
-
- let kind = match ch {
- '=' => Eq,
- '<' => Lt,
- '>' => Gt,
- '!' => Not,
- '~' => Tilde,
- '+' => BinOp(Plus),
- '-' => BinOp(Minus),
- '*' => BinOp(Star),
- '/' => BinOp(Slash),
- '%' => BinOp(Percent),
- '^' => BinOp(Caret),
- '&' => BinOp(And),
- '|' => BinOp(Or),
- '@' => At,
- '.' => Dot,
- ',' => Comma,
- ';' => Semi,
- ':' => Colon,
- '#' => Pound,
- '$' => Dollar,
- '?' => Question,
- '\'' => SingleQuote,
- _ => unreachable!(),
- };
-
- let tree = tokenstream::TokenTree::token(kind, span);
- TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })])
- }
-}
-
-impl ToInternal<errors::Level> for Level {
- fn to_internal(self) -> errors::Level {
- match self {
- Level::Error => errors::Level::Error,
- Level::Warning => errors::Level::Warning,
- Level::Note => errors::Level::Note,
- Level::Help => errors::Level::Help,
- _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
- }
- }
-}
-
-#[derive(Clone)]
-pub struct TokenStreamIter {
- cursor: tokenstream::Cursor,
- stack: Vec<TokenTree<Group, Punct, Ident, Literal>>,
-}
-
-#[derive(Clone)]
-pub struct Group {
- delimiter: Delimiter,
- stream: TokenStream,
- span: DelimSpan,
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct Punct {
- ch: char,
- // NB. not using `Spacing` here because it doesn't implement `Hash`.
- joint: bool,
- span: Span,
-}
-
-impl Punct {
- fn new(ch: char, joint: bool, span: Span) -> Punct {
- const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
- '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
- if !LEGAL_CHARS.contains(&ch) {
- panic!("unsupported character `{:?}`", ch)
- }
- Punct { ch, joint, span }
- }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct Ident {
- sym: Symbol,
- is_raw: bool,
- span: Span,
-}
-
-impl Ident {
- fn is_valid(string: &str) -> bool {
- let mut chars = string.chars();
- if let Some(start) = chars.next() {
- (start == '_' || start.is_xid_start())
- && chars.all(|cont| cont == '_' || cont.is_xid_continue())
- } else {
- false
- }
- }
- fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident {
- let string = sym.as_str();
- if !Self::is_valid(&string) {
- panic!("`{:?}` is not a valid identifier", string)
- }
- // Get rid of gensyms to conservatively check rawness on the string contents only.
- if is_raw && !sym.as_interned_str().as_symbol().can_be_raw() {
- panic!("`{}` cannot be a raw identifier", string);
- }
- Ident { sym, is_raw, span }
- }
- fn dollar_crate(span: Span) -> Ident {
- // `$crate` is accepted as an ident only if it comes from the compiler.
- Ident { sym: kw::DollarCrate, is_raw: false, span }
- }
-}
-
-// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
-#[derive(Clone, Debug)]
-pub struct Literal {
- lit: token::Lit,
- span: Span,
-}
-
-pub(crate) struct Rustc<'a> {
- sess: &'a ParseSess,
- def_site: Span,
- call_site: Span,
-}
-
-impl<'a> Rustc<'a> {
- pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
- // No way to determine def location for a proc macro right now, so use call location.
- let location = cx.current_expansion.id.expn_info().unwrap().call_site;
- let to_span = |transparency| {
- location.with_ctxt(
- SyntaxContext::empty()
- .apply_mark_with_transparency(cx.current_expansion.id, transparency),
- )
- };
- Rustc {
- sess: cx.parse_sess,
- def_site: to_span(Transparency::Opaque),
- call_site: to_span(Transparency::Transparent),
- }
- }
-
- fn lit(&mut self, kind: token::LitKind, symbol: Symbol, suffix: Option<Symbol>) -> Literal {
- Literal {
- lit: token::Lit::new(kind, symbol, suffix),
- span: server::Span::call_site(self),
- }
- }
-}
-
-impl server::Types for Rustc<'_> {
- type TokenStream = TokenStream;
- type TokenStreamBuilder = tokenstream::TokenStreamBuilder;
- type TokenStreamIter = TokenStreamIter;
- type Group = Group;
- type Punct = Punct;
- type Ident = Ident;
- type Literal = Literal;
- type SourceFile = Lrc<SourceFile>;
- type MultiSpan = Vec<Span>;
- type Diagnostic = Diagnostic;
- type Span = Span;
-}
-
-impl server::TokenStream for Rustc<'_> {
- fn new(&mut self) -> Self::TokenStream {
- TokenStream::empty()
- }
- fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
- stream.is_empty()
- }
- fn from_str(&mut self, src: &str) -> Self::TokenStream {
- parse::parse_stream_from_source_str(
- FileName::proc_macro_source_code(src),
- src.to_string(),
- self.sess,
- Some(self.call_site),
- )
- }
- fn to_string(&mut self, stream: &Self::TokenStream) -> String {
- stream.to_string()
- }
- fn from_token_tree(
- &mut self,
- tree: TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>,
- ) -> Self::TokenStream {
- tree.to_internal()
- }
- fn into_iter(&mut self, stream: Self::TokenStream) -> Self::TokenStreamIter {
- TokenStreamIter {
- cursor: stream.trees(),
- stack: vec![],
- }
- }
-}
-
-impl server::TokenStreamBuilder for Rustc<'_> {
- fn new(&mut self) -> Self::TokenStreamBuilder {
- tokenstream::TokenStreamBuilder::new()
- }
- fn push(&mut self, builder: &mut Self::TokenStreamBuilder, stream: Self::TokenStream) {
- builder.push(stream);
- }
- fn build(&mut self, builder: Self::TokenStreamBuilder) -> Self::TokenStream {
- builder.build()
- }
-}
-
-impl server::TokenStreamIter for Rustc<'_> {
- fn next(
- &mut self,
- iter: &mut Self::TokenStreamIter,
- ) -> Option<TokenTree<Self::Group, Self::Punct, Self::Ident, Self::Literal>> {
- loop {
- let tree = iter.stack.pop().or_else(|| {
- let next = iter.cursor.next_with_joint()?;
- Some(TokenTree::from_internal((next, self.sess, &mut iter.stack)))
- })?;
- // HACK: The condition "dummy span + group with empty delimiter" represents an AST
- // fragment approximately converted into a token stream. This may happen, for
- // example, with inputs to proc macro attributes, including derives. Such "groups"
- // need to flattened during iteration over stream's token trees.
- // Eventually this needs to be removed in favor of keeping original token trees
- // and not doing the roundtrip through AST.
- if let TokenTree::Group(ref group) = tree {
- if group.delimiter == Delimiter::None && group.span.entire().is_dummy() {
- iter.cursor.append(group.stream.clone());
- continue;
- }
- }
- return Some(tree);
- }
- }
-}
-
-impl server::Group for Rustc<'_> {
- fn new(&mut self, delimiter: Delimiter, stream: Self::TokenStream) -> Self::Group {
- Group {
- delimiter,
- stream,
- span: DelimSpan::from_single(server::Span::call_site(self)),
- }
- }
- fn delimiter(&mut self, group: &Self::Group) -> Delimiter {
- group.delimiter
- }
- fn stream(&mut self, group: &Self::Group) -> Self::TokenStream {
- group.stream.clone()
- }
- fn span(&mut self, group: &Self::Group) -> Self::Span {
- group.span.entire()
- }
- fn span_open(&mut self, group: &Self::Group) -> Self::Span {
- group.span.open
- }
- fn span_close(&mut self, group: &Self::Group) -> Self::Span {
- group.span.close
- }
- fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
- group.span = DelimSpan::from_single(span);
- }
-}
-
-impl server::Punct for Rustc<'_> {
- fn new(&mut self, ch: char, spacing: Spacing) -> Self::Punct {
- Punct::new(ch, spacing == Spacing::Joint, server::Span::call_site(self))
- }
- fn as_char(&mut self, punct: Self::Punct) -> char {
- punct.ch
- }
- fn spacing(&mut self, punct: Self::Punct) -> Spacing {
- if punct.joint {
- Spacing::Joint
- } else {
- Spacing::Alone
- }
- }
- fn span(&mut self, punct: Self::Punct) -> Self::Span {
- punct.span
- }
- fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
- Punct { span, ..punct }
- }
-}
-
-impl server::Ident for Rustc<'_> {
- fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
- Ident::new(Symbol::intern(string), is_raw, span)
- }
- fn span(&mut self, ident: Self::Ident) -> Self::Span {
- ident.span
- }
- fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
- Ident { span, ..ident }
- }
-}
-
-impl server::Literal for Rustc<'_> {
- // FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
- fn debug(&mut self, literal: &Self::Literal) -> String {
- format!("{:?}", literal)
- }
- fn integer(&mut self, n: &str) -> Self::Literal {
- self.lit(token::Integer, Symbol::intern(n), None)
- }
- fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
- self.lit(token::Integer, Symbol::intern(n), Some(Symbol::intern(kind)))
- }
- fn float(&mut self, n: &str) -> Self::Literal {
- self.lit(token::Float, Symbol::intern(n), None)
- }
- fn f32(&mut self, n: &str) -> Self::Literal {
- self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
- }
- fn f64(&mut self, n: &str) -> Self::Literal {
- self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
- }
- fn string(&mut self, string: &str) -> Self::Literal {
- let mut escaped = String::new();
- for ch in string.chars() {
- escaped.extend(ch.escape_debug());
- }
- self.lit(token::Str, Symbol::intern(&escaped), None)
- }
- fn character(&mut self, ch: char) -> Self::Literal {
- let mut escaped = String::new();
- escaped.extend(ch.escape_unicode());
- self.lit(token::Char, Symbol::intern(&escaped), None)
- }
- fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
- let string = bytes
- .iter()
- .cloned()
- .flat_map(ascii::escape_default)
- .map(Into::<char>::into)
- .collect::<String>();
- self.lit(token::ByteStr, Symbol::intern(&string), None)
- }
- fn span(&mut self, literal: &Self::Literal) -> Self::Span {
- literal.span
- }
- fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
- literal.span = span;
- }
- fn subspan(
- &mut self,
- literal: &Self::Literal,
- start: Bound<usize>,
- end: Bound<usize>,
- ) -> Option<Self::Span> {
- let span = literal.span;
- let length = span.hi().to_usize() - span.lo().to_usize();
-
- let start = match start {
- Bound::Included(lo) => lo,
- Bound::Excluded(lo) => lo + 1,
- Bound::Unbounded => 0,
- };
-
- let end = match end {
- Bound::Included(hi) => hi + 1,
- Bound::Excluded(hi) => hi,
- Bound::Unbounded => length,
- };
-
- // Bounds check the values, preventing addition overflow and OOB spans.
- if start > u32::max_value() as usize
- || end > u32::max_value() as usize
- || (u32::max_value() - start as u32) < span.lo().to_u32()
- || (u32::max_value() - end as u32) < span.lo().to_u32()
- || start >= end
- || end > length
- {
- return None;
- }
-
- let new_lo = span.lo() + BytePos::from_usize(start);
- let new_hi = span.lo() + BytePos::from_usize(end);
- Some(span.with_lo(new_lo).with_hi(new_hi))
- }
-}
-
-impl server::SourceFile for Rustc<'_> {
- fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
- Lrc::ptr_eq(file1, file2)
- }
- fn path(&mut self, file: &Self::SourceFile) -> String {
- match file.name {
- FileName::Real(ref path) => path
- .to_str()
- .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
- .to_string(),
- _ => file.name.to_string(),
- }
- }
- fn is_real(&mut self, file: &Self::SourceFile) -> bool {
- file.is_real_file()
- }
-}
-
-impl server::MultiSpan for Rustc<'_> {
- fn new(&mut self) -> Self::MultiSpan {
- vec![]
- }
- fn push(&mut self, spans: &mut Self::MultiSpan, span: Self::Span) {
- spans.push(span)
- }
-}
-
-impl server::Diagnostic for Rustc<'_> {
- fn new(&mut self, level: Level, msg: &str, spans: Self::MultiSpan) -> Self::Diagnostic {
- let mut diag = Diagnostic::new(level.to_internal(), msg);
- diag.set_span(MultiSpan::from_spans(spans));
- diag
- }
- fn sub(
- &mut self,
- diag: &mut Self::Diagnostic,
- level: Level,
- msg: &str,
- spans: Self::MultiSpan,
- ) {
- diag.sub(level.to_internal(), msg, MultiSpan::from_spans(spans), None);
- }
- fn emit(&mut self, diag: Self::Diagnostic) {
- DiagnosticBuilder::new_diagnostic(&self.sess.span_diagnostic, diag).emit()
- }
-}
-
-impl server::Span for Rustc<'_> {
- fn debug(&mut self, span: Self::Span) -> String {
- format!("{:?} bytes({}..{})", span.ctxt(), span.lo().0, span.hi().0)
- }
- fn def_site(&mut self) -> Self::Span {
- self.def_site
- }
- fn call_site(&mut self) -> Self::Span {
- self.call_site
- }
- fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
- self.sess.source_map().lookup_char_pos(span.lo()).file
- }
- fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
- span.ctxt().outer_expn_info().map(|i| i.call_site)
- }
- fn source(&mut self, span: Self::Span) -> Self::Span {
- span.source_callsite()
- }
- fn start(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.lo());
- LineColumn {
- line: loc.line,
- column: loc.col.to_usize(),
- }
- }
- fn end(&mut self, span: Self::Span) -> LineColumn {
- let loc = self.sess.source_map().lookup_char_pos(span.hi());
- LineColumn {
- line: loc.line,
- column: loc.col.to_usize(),
- }
- }
- fn join(&mut self, first: Self::Span, second: Self::Span) -> Option<Self::Span> {
- let self_loc = self.sess.source_map().lookup_char_pos(first.lo());
- let other_loc = self.sess.source_map().lookup_char_pos(second.lo());
-
- if self_loc.file.name != other_loc.file.name {
- return None;
- }
-
- Some(first.to(second))
- }
- fn resolved_at(&mut self, span: Self::Span, at: Self::Span) -> Self::Span {
- span.with_ctxt(at.ctxt())
- }
- fn source_text(&mut self, span: Self::Span) -> Option<String> {
- self.sess.source_map().span_to_snippet(span).ok()
- }
-}
--- /dev/null
+use syntax::{ast, panictry};
+use syntax::ext::base::{self, *};
+use syntax::ext::build::AstBuilder;
+use syntax::parse::{self, token, DirectoryOwnership};
+use syntax::print::pprust;
+use syntax::ptr::P;
+use syntax::symbol::Symbol;
+use syntax::tokenstream;
+
+use smallvec::SmallVec;
+use syntax_pos::{self, Pos, Span};
+
+use std::fs;
+use std::io::ErrorKind;
+use rustc_data_structures::sync::Lrc;
+
+// These macros all relate to the file system; they either return
+// the column/row/filename of the expression, or they include
+// a given file into the current one.
+
+/// line!(): expands to the current line number
+pub fn expand_line(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ base::check_zero_tts(cx, sp, tts, "line!");
+
+ let topmost = cx.expansion_cause().unwrap_or(sp);
+ let loc = cx.source_map().lookup_char_pos(topmost.lo());
+
+ base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
+}
+
+/* column!(): expands to the current column number */
+pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ base::check_zero_tts(cx, sp, tts, "column!");
+
+ let topmost = cx.expansion_cause().unwrap_or(sp);
+ let loc = cx.source_map().lookup_char_pos(topmost.lo());
+
+ base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
+}
+
+/// file!(): expands to the current filename */
+/// The source_file (`loc.file`) contains a bunch more information we could spit
+/// out if we wanted.
+pub fn expand_file(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ base::check_zero_tts(cx, sp, tts, "file!");
+
+ let topmost = cx.expansion_cause().unwrap_or(sp);
+ let loc = cx.source_map().lookup_char_pos(topmost.lo());
+ base::MacEager::expr(cx.expr_str(topmost, Symbol::intern(&loc.file.name.to_string())))
+}
+
+pub fn expand_stringify(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ let s = pprust::tts_to_string(tts);
+ base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
+}
+
+pub fn expand_mod(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ base::check_zero_tts(cx, sp, tts, "module_path!");
+ let mod_path = &cx.current_expansion.module.mod_path;
+ let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
+
+ base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))
+}
+
+/// include! : parse the given file as an expr
+/// This is generally a bad idea because it's going to behave
+/// unhygienically.
+pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'cx> {
+ let file = match get_single_str_from_tts(cx, sp, tts, "include!") {
+ Some(f) => f,
+ None => return DummyResult::any(sp),
+ };
+ // The file will be added to the code map by the parser
+ let file = cx.resolve_path(file, sp);
+ let directory_ownership = DirectoryOwnership::Owned { relative: None };
+ let p = parse::new_sub_parser_from_file(cx.parse_sess(), &file, directory_ownership, None, sp);
+
+ struct ExpandResult<'a> {
+ p: parse::parser::Parser<'a>,
+ }
+ impl<'a> base::MacResult for ExpandResult<'a> {
+ fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
+ Some(panictry!(self.p.parse_expr()))
+ }
+
+ fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
+ let mut ret = SmallVec::new();
+ while self.p.token != token::Eof {
+ match panictry!(self.p.parse_item()) {
+ Some(item) => ret.push(item),
+ None => self.p.sess.span_diagnostic.span_fatal(self.p.token.span,
+ &format!("expected item, found `{}`",
+ self.p.this_token_to_string()))
+ .raise()
+ }
+ }
+ Some(ret)
+ }
+ }
+
+ Box::new(ExpandResult { p })
+}
+
+// include_str! : read the given file, insert it as a literal string expr
+pub fn expand_include_str(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") {
+ Some(f) => f,
+ None => return DummyResult::expr(sp)
+ };
+ let file = cx.resolve_path(file, sp);
+ match fs::read_to_string(&file) {
+ Ok(src) => {
+ let interned_src = Symbol::intern(&src);
+
+ // Add this input file to the code map to make it available as
+ // dependency information
+ cx.source_map().new_source_file(file.into(), src);
+
+ base::MacEager::expr(cx.expr_str(sp, interned_src))
+ },
+ Err(ref e) if e.kind() == ErrorKind::InvalidData => {
+ cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display()));
+ DummyResult::expr(sp)
+ }
+ Err(e) => {
+ cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
+ DummyResult::expr(sp)
+ }
+ }
+}
+
+pub fn expand_include_bytes(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
+ -> Box<dyn base::MacResult+'static> {
+ let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") {
+ Some(f) => f,
+ None => return DummyResult::expr(sp)
+ };
+ let file = cx.resolve_path(file, sp);
+ match fs::read(&file) {
+ Ok(bytes) => {
+ // Add the contents to the source map if it contains UTF-8.
+ let (contents, bytes) = match String::from_utf8(bytes) {
+ Ok(s) => {
+ let bytes = s.as_bytes().to_owned();
+ (s, bytes)
+ },
+ Err(e) => (String::new(), e.into_bytes()),
+ };
+ cx.source_map().new_source_file(file.into(), contents);
+
+ base::MacEager::expr(cx.expr_lit(sp, ast::LitKind::ByteStr(Lrc::new(bytes))))
+ },
+ Err(e) => {
+ cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
+ DummyResult::expr(sp)
+ }
+ }
+}
--- /dev/null
+use syntax::{ast, attr};
+use syntax::edition::Edition;
+use syntax::ext::hygiene::{ExpnId, MacroKind};
+use syntax::ptr::P;
+use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan};
+use syntax::symbol::{Ident, Symbol, kw, sym};
+use syntax::tokenstream::TokenStream;
+use syntax_pos::DUMMY_SP;
+
+use std::iter;
+
+pub fn inject(
+ mut krate: ast::Crate, alt_std_name: Option<&str>, edition: Edition
+) -> (ast::Crate, Option<Symbol>) {
+ let rust_2018 = edition >= Edition::Edition2018;
+
+ // the first name in this list is the crate name of the crate with the prelude
+ let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) {
+ return (krate, None);
+ } else if attr::contains_name(&krate.attrs, sym::no_std) {
+ if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
+ &["core"]
+ } else {
+ &["core", "compiler_builtins"]
+ }
+ } else {
+ &["std"]
+ };
+
+ // .rev() to preserve ordering above in combination with insert(0, ...)
+ let alt_std_name = alt_std_name.map(Symbol::intern);
+ for orig_name_str in names.iter().rev() {
+ // HACK(eddyb) gensym the injected crates on the Rust 2018 edition,
+ // so they don't accidentally interfere with the new import paths.
+ let orig_name_sym = Symbol::intern(orig_name_str);
+ let orig_name_ident = Ident::with_empty_ctxt(orig_name_sym);
+ let (rename, orig_name) = if rust_2018 {
+ (orig_name_ident.gensym(), Some(orig_name_sym))
+ } else {
+ (orig_name_ident, None)
+ };
+ krate.module.items.insert(0, P(ast::Item {
+ attrs: vec![attr::mk_attr_outer(
+ DUMMY_SP,
+ attr::mk_attr_id(),
+ attr::mk_word_item(ast::Ident::with_empty_ctxt(sym::macro_use))
+ )],
+ vis: dummy_spanned(ast::VisibilityKind::Inherited),
+ node: ast::ItemKind::ExternCrate(alt_std_name.or(orig_name)),
+ ident: rename,
+ id: ast::DUMMY_NODE_ID,
+ span: DUMMY_SP,
+ tokens: None,
+ }));
+ }
+
+ // the crates have been injected, the assumption is that the first one is the one with
+ // the prelude.
+ let name = names[0];
+
+ let span = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
+ ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition,
+ [sym::prelude_import][..].into(),
+ ));
+
+ krate.module.items.insert(0, P(ast::Item {
+ attrs: vec![ast::Attribute {
+ style: ast::AttrStyle::Outer,
+ path: ast::Path::from_ident(ast::Ident::new(sym::prelude_import, span)),
+ tokens: TokenStream::empty(),
+ id: attr::mk_attr_id(),
+ is_sugared_doc: false,
+ span,
+ }],
+ vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited),
+ node: ast::ItemKind::Use(P(ast::UseTree {
+ prefix: ast::Path {
+ segments: iter::once(ast::Ident::with_empty_ctxt(kw::PathRoot))
+ .chain(
+ [name, "prelude", "v1"].iter().cloned()
+ .map(ast::Ident::from_str)
+ ).map(ast::PathSegment::from_ident).collect(),
+ span,
+ },
+ kind: ast::UseTreeKind::Glob,
+ span,
+ })),
+ id: ast::DUMMY_NODE_ID,
+ ident: ast::Ident::invalid(),
+ span,
+ tokens: None,
+ }));
+
+ (krate, Some(Symbol::intern(name)))
+}
use syntax::ext::build::AstBuilder;
use syntax::ext::hygiene::SyntaxContext;
use syntax::print::pprust;
+use syntax::source_map::respan;
use syntax::symbol::{Symbol, sym};
use syntax_pos::Span;
use std::iter;
+// #[test_case] is used by custom test authors to mark tests
+// When building for test, it needs to make the item public and gensym the name
+// Otherwise, we'll omit the item. This behavior means that any item annotated
+// with #[test_case] is never addressable.
+//
+// We mark item with an inert attribute "rustc_test_marker" which the test generation
+// logic will pick up on.
+pub fn expand_test_case(
+ ecx: &mut ExtCtxt<'_>,
+ attr_sp: Span,
+ meta_item: &ast::MetaItem,
+ anno_item: Annotatable
+) -> Vec<Annotatable> {
+ check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
+
+ if !ecx.ecfg.should_test { return vec![]; }
+
+ let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
+ let mut item = anno_item.expect_item();
+ item = item.map(|mut item| {
+ item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+ item.ident = item.ident.gensym();
+ item.attrs.push(
+ ecx.attribute(sp,
+ ecx.meta_word(sp, sym::rustc_test_marker))
+ );
+ item
+ });
+
+ return vec![Annotatable::Item(item)]
+}
+
pub fn expand_test(
cx: &mut ExtCtxt<'_>,
attr_sp: Span,
+++ /dev/null
-// http://rust-lang.org/COPYRIGHT.
-//
-
-// #[test_case] is used by custom test authors to mark tests
-// When building for test, it needs to make the item public and gensym the name
-// Otherwise, we'll omit the item. This behavior means that any item annotated
-// with #[test_case] is never addressable.
-//
-// We mark item with an inert attribute "rustc_test_marker" which the test generation
-// logic will pick up on.
-
-use syntax::ast;
-use syntax::attr::check_builtin_macro_attribute;
-use syntax::ext::base::*;
-use syntax::ext::build::AstBuilder;
-use syntax::ext::hygiene::SyntaxContext;
-use syntax::source_map::respan;
-use syntax::symbol::sym;
-use syntax_pos::Span;
-
-pub fn expand(
- ecx: &mut ExtCtxt<'_>,
- attr_sp: Span,
- meta_item: &ast::MetaItem,
- anno_item: Annotatable
-) -> Vec<Annotatable> {
- check_builtin_macro_attribute(ecx, meta_item, sym::test_case);
-
- if !ecx.ecfg.should_test { return vec![]; }
-
- let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.id));
- let mut item = anno_item.expect_item();
- item = item.map(|mut item| {
- item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
- item.ident = item.ident.gensym();
- item.attrs.push(
- ecx.attribute(sp,
- ecx.meta_word(sp, sym::rustc_test_marker))
- );
- item
- });
-
- return vec![Annotatable::Item(item)]
-}
--- /dev/null
+// Code that generates a test runner to run all the tests in a crate
+
+use log::debug;
+use smallvec::{smallvec, SmallVec};
+use syntax::ast::{self, Ident};
+use syntax::attr;
+use syntax::entry::{self, EntryPointType};
+use syntax::ext::base::{ExtCtxt, Resolver};
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::{ExpnId, MacroKind};
+use syntax::feature_gate::Features;
+use syntax::mut_visit::{*, ExpectOne};
+use syntax::parse::ParseSess;
+use syntax::ptr::P;
+use syntax::source_map::{ExpnInfo, ExpnKind, dummy_spanned};
+use syntax::symbol::{kw, sym, Symbol};
+use syntax_pos::{Span, DUMMY_SP};
+
+use std::{iter, mem};
+
+struct Test {
+ span: Span,
+ path: Vec<Ident>,
+}
+
+struct TestCtxt<'a> {
+ span_diagnostic: &'a errors::Handler,
+ path: Vec<Ident>,
+ ext_cx: ExtCtxt<'a>,
+ test_cases: Vec<Test>,
+ reexport_test_harness_main: Option<Symbol>,
+ test_runner: Option<ast::Path>,
+ // top-level re-export submodule, filled out after folding is finished
+ toplevel_reexport: Option<Ident>,
+}
+
+// Traverse the crate, collecting all the test functions, eliding any
+// existing main functions, and synthesizing a main test harness
+pub fn inject(
+ sess: &ParseSess,
+ resolver: &mut dyn Resolver,
+ should_test: bool,
+ krate: &mut ast::Crate,
+ span_diagnostic: &errors::Handler,
+ features: &Features,
+) {
+ // Check for #[reexport_test_harness_main = "some_name"] which
+ // creates a `use __test::main as some_name;`. This needs to be
+ // unconditional, so that the attribute is still marked as used in
+ // non-test builds.
+ let reexport_test_harness_main =
+ attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
+
+ // Do this here so that the test_runner crate attribute gets marked as used
+ // even in non-test builds
+ let test_runner = get_test_runner(span_diagnostic, &krate);
+
+ if should_test {
+ generate_test_harness(sess, resolver, reexport_test_harness_main,
+ krate, span_diagnostic, features, test_runner)
+ }
+}
+
+struct TestHarnessGenerator<'a> {
+ cx: TestCtxt<'a>,
+ tests: Vec<Ident>,
+
+ // submodule name, gensym'd identifier for re-exports
+ tested_submods: Vec<(Ident, Ident)>,
+}
+
+impl<'a> MutVisitor for TestHarnessGenerator<'a> {
+ fn visit_crate(&mut self, c: &mut ast::Crate) {
+ noop_visit_crate(c, self);
+
+ // Create a main function to run our tests
+ let test_main = {
+ let unresolved = mk_main(&mut self.cx);
+ self.cx.ext_cx.monotonic_expander().flat_map_item(unresolved).pop().unwrap()
+ };
+
+ c.module.items.push(test_main);
+ }
+
+ fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+ let ident = i.ident;
+ if ident.name != kw::Invalid {
+ self.cx.path.push(ident);
+ }
+ debug!("current path: {}", path_name_i(&self.cx.path));
+
+ let mut item = i.into_inner();
+ if is_test_case(&item) {
+ debug!("this is a test item");
+
+ let test = Test {
+ span: item.span,
+ path: self.cx.path.clone(),
+ };
+ self.cx.test_cases.push(test);
+ self.tests.push(item.ident);
+ }
+
+ // We don't want to recurse into anything other than mods, since
+ // mods or tests inside of functions will break things
+ if let ast::ItemKind::Mod(mut module) = item.node {
+ let tests = mem::take(&mut self.tests);
+ let tested_submods = mem::take(&mut self.tested_submods);
+ noop_visit_mod(&mut module, self);
+ let tests = mem::replace(&mut self.tests, tests);
+ let tested_submods = mem::replace(&mut self.tested_submods, tested_submods);
+
+ if !tests.is_empty() || !tested_submods.is_empty() {
+ let (it, sym) = mk_reexport_mod(&mut self.cx, item.id, tests, tested_submods);
+ module.items.push(it);
+
+ if !self.cx.path.is_empty() {
+ self.tested_submods.push((self.cx.path[self.cx.path.len()-1], sym));
+ } else {
+ debug!("pushing nothing, sym: {:?}", sym);
+ self.cx.toplevel_reexport = Some(sym);
+ }
+ }
+ item.node = ast::ItemKind::Mod(module);
+ }
+ if ident.name != kw::Invalid {
+ self.cx.path.pop();
+ }
+ smallvec![P(item)]
+ }
+
+ fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+ // Do nothing.
+ }
+}
+
+/// A folder used to remove any entry points (like fn main) because the harness
+/// generator will provide its own
+struct EntryPointCleaner {
+ // Current depth in the ast
+ depth: usize,
+}
+
+impl MutVisitor for EntryPointCleaner {
+ fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+ self.depth += 1;
+ let item = noop_flat_map_item(i, self).expect_one("noop did something");
+ self.depth -= 1;
+
+ // Remove any #[main] or #[start] from the AST so it doesn't
+ // clash with the one we're going to add, but mark it as
+ // #[allow(dead_code)] to avoid printing warnings.
+ let item = match entry::entry_point_type(&item, self.depth) {
+ EntryPointType::MainNamed |
+ EntryPointType::MainAttr |
+ EntryPointType::Start =>
+ item.map(|ast::Item {id, ident, attrs, node, vis, span, tokens}| {
+ let allow_ident = Ident::with_empty_ctxt(sym::allow);
+ let dc_nested = attr::mk_nested_word_item(Ident::from_str("dead_code"));
+ let allow_dead_code_item = attr::mk_list_item(DUMMY_SP, allow_ident,
+ vec![dc_nested]);
+ let allow_dead_code = attr::mk_attr_outer(DUMMY_SP,
+ attr::mk_attr_id(),
+ allow_dead_code_item);
+
+ ast::Item {
+ id,
+ ident,
+ attrs: attrs.into_iter()
+ .filter(|attr| {
+ !attr.check_name(sym::main) && !attr.check_name(sym::start)
+ })
+ .chain(iter::once(allow_dead_code))
+ .collect(),
+ node,
+ vis,
+ span,
+ tokens,
+ }
+ }),
+ EntryPointType::None |
+ EntryPointType::OtherMain => item,
+ };
+
+ smallvec![item]
+ }
+
+ fn visit_mac(&mut self, _mac: &mut ast::Mac) {
+ // Do nothing.
+ }
+}
+
+/// Creates an item (specifically a module) that "pub use"s the tests passed in.
+/// Each tested submodule will contain a similar reexport module that we will export
+/// under the name of the original module. That is, `submod::__test_reexports` is
+/// reexported like so `pub use submod::__test_reexports as submod`.
+fn mk_reexport_mod(cx: &mut TestCtxt<'_>,
+ parent: ast::NodeId,
+ tests: Vec<Ident>,
+ tested_submods: Vec<(Ident, Ident)>)
+ -> (P<ast::Item>, Ident) {
+ let super_ = Ident::with_empty_ctxt(kw::Super);
+
+ let items = tests.into_iter().map(|r| {
+ cx.ext_cx.item_use_simple(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public),
+ cx.ext_cx.path(DUMMY_SP, vec![super_, r]))
+ }).chain(tested_submods.into_iter().map(|(r, sym)| {
+ let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]);
+ cx.ext_cx.item_use_simple_(DUMMY_SP, dummy_spanned(ast::VisibilityKind::Public),
+ Some(r), path)
+ })).collect();
+
+ let reexport_mod = ast::Mod {
+ inline: true,
+ inner: DUMMY_SP,
+ items,
+ };
+
+ let name = Ident::from_str("__test_reexports").gensym();
+ let parent = if parent == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { parent };
+ cx.ext_cx.current_expansion.id = cx.ext_cx.resolver.get_module_scope(parent);
+ let it = cx.ext_cx.monotonic_expander().flat_map_item(P(ast::Item {
+ ident: name,
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ node: ast::ItemKind::Mod(reexport_mod),
+ vis: dummy_spanned(ast::VisibilityKind::Public),
+ span: DUMMY_SP,
+ tokens: None,
+ })).pop().unwrap();
+
+ (it, name)
+}
+
+/// Crawl over the crate, inserting test reexports and the test main function
+fn generate_test_harness(sess: &ParseSess,
+ resolver: &mut dyn Resolver,
+ reexport_test_harness_main: Option<Symbol>,
+ krate: &mut ast::Crate,
+ sd: &errors::Handler,
+ features: &Features,
+ test_runner: Option<ast::Path>) {
+ // Remove the entry points
+ let mut cleaner = EntryPointCleaner { depth: 0 };
+ cleaner.visit_crate(krate);
+
+ let mut econfig = ExpansionConfig::default("test".to_string());
+ econfig.features = Some(features);
+
+ let cx = TestCtxt {
+ span_diagnostic: sd,
+ ext_cx: ExtCtxt::new(sess, econfig, resolver),
+ path: Vec::new(),
+ test_cases: Vec::new(),
+ reexport_test_harness_main,
+ toplevel_reexport: None,
+ test_runner
+ };
+
+ TestHarnessGenerator {
+ cx,
+ tests: Vec::new(),
+ tested_submods: Vec::new(),
+ }.visit_crate(krate);
+}
+
+/// Creates a function item for use as the main function of a test build.
+/// This function will call the `test_runner` as specified by the crate attribute
+fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
+ // Writing this out by hand:
+ // pub fn main() {
+ // #![main]
+ // test::test_main_static(&[..tests]);
+ // }
+ let sp = DUMMY_SP.fresh_expansion(ExpnId::root(), ExpnInfo::allow_unstable(
+ ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition,
+ [sym::main, sym::test, sym::rustc_attrs][..].into(),
+ ));
+ let ecx = &cx.ext_cx;
+ let test_id = Ident::with_empty_ctxt(sym::test);
+
+ // test::test_main_static(...)
+ let mut test_runner = cx.test_runner.clone().unwrap_or(
+ ecx.path(sp, vec![
+ test_id, ecx.ident_of("test_main_static")
+ ]));
+
+ test_runner.span = sp;
+
+ let test_main_path_expr = ecx.expr_path(test_runner);
+ let call_test_main = ecx.expr_call(sp, test_main_path_expr,
+ vec![mk_tests_slice(cx)]);
+ let call_test_main = ecx.stmt_expr(call_test_main);
+
+ // #![main]
+ let main_meta = ecx.meta_word(sp, sym::main);
+ let main_attr = ecx.attribute(sp, main_meta);
+
+ // extern crate test as test_gensym
+ let test_extern_stmt = ecx.stmt_item(sp, ecx.item(sp,
+ test_id,
+ vec![],
+ ast::ItemKind::ExternCrate(None)
+ ));
+
+ // pub fn main() { ... }
+ let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(vec![]));
+
+ // If no test runner is provided we need to import the test crate
+ let main_body = if cx.test_runner.is_none() {
+ ecx.block(sp, vec![test_extern_stmt, call_test_main])
+ } else {
+ ecx.block(sp, vec![call_test_main])
+ };
+
+ let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)),
+ ast::FnHeader::default(),
+ ast::Generics::default(),
+ main_body);
+
+ // Honor the reexport_test_harness_main attribute
+ let main_id = match cx.reexport_test_harness_main {
+ Some(sym) => Ident::new(sym, sp),
+ None => Ident::from_str_and_span("main", sp).gensym(),
+ };
+
+ P(ast::Item {
+ ident: main_id,
+ attrs: vec![main_attr],
+ id: ast::DUMMY_NODE_ID,
+ node: main,
+ vis: dummy_spanned(ast::VisibilityKind::Public),
+ span: sp,
+ tokens: None,
+ })
+
+}
+
+fn path_name_i(idents: &[Ident]) -> String {
+ let mut path_name = "".to_string();
+ let mut idents_iter = idents.iter().peekable();
+ while let Some(ident) = idents_iter.next() {
+ path_name.push_str(&ident.as_str());
+ if idents_iter.peek().is_some() {
+ path_name.push_str("::")
+ }
+ }
+ path_name
+}
+
+/// Creates a slice containing every test like so:
+/// &[path::to::test1, path::to::test2]
+fn mk_tests_slice(cx: &TestCtxt<'_>) -> P<ast::Expr> {
+ debug!("building test vector from {} tests", cx.test_cases.len());
+ let ref ecx = cx.ext_cx;
+
+ ecx.expr_vec_slice(DUMMY_SP,
+ cx.test_cases.iter().map(|test| {
+ ecx.expr_addr_of(test.span,
+ ecx.expr_path(ecx.path(test.span, visible_path(cx, &test.path))))
+ }).collect())
+}
+
+/// Creates a path from the top-level __test module to the test via __test_reexports
+fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec<Ident>{
+ let mut visible_path = vec![];
+ match cx.toplevel_reexport {
+ Some(id) => visible_path.push(id),
+ None => {
+ cx.span_diagnostic.bug("expected to find top-level re-export name, but found None");
+ }
+ }
+ visible_path.extend_from_slice(path);
+ visible_path
+}
+
+fn is_test_case(i: &ast::Item) -> bool {
+ attr::contains_name(&i.attrs, sym::rustc_test_marker)
+}
+
+fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
+ let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
+ test_attr.meta_item_list().map(|meta_list| {
+ if meta_list.len() != 1 {
+ sd.span_fatal(test_attr.span,
+ "`#![test_runner(..)]` accepts exactly 1 argument").raise()
+ }
+ match meta_list[0].meta_item() {
+ Some(meta_item) if meta_item.is_word() => meta_item.path.clone(),
+ _ => sd.span_fatal(test_attr.span, "`test_runner` argument must be a path").raise()
+ }
+ })
+}
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
-#![deny(rust_2018_idioms)]
-#![deny(unused_lifetimes)]
-
#![feature(const_fn)]
#![feature(crate_visibility_modifier)]
#![feature(nll)]
test(attr(deny(warnings))))]
#![deny(missing_docs)]
-#![deny(rust_2018_idioms)]
-
#![cfg_attr(windows, feature(libc))]
use std::io::prelude::*;
// this crate, which relies on this attribute (rather than the value of `--crate-name` passed by
// cargo) to detect this crate.
-#![deny(rust_2018_idioms)]
#![crate_name = "test"]
#![unstable(feature = "test", issue = "27812")]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))]
#![no_std]
#![unstable(feature = "panic_unwind", issue = "32837")]
-#![deny(rust_2018_idioms)]
-
#![feature(link_cfg)]
#![feature(nll)]
#![feature(staged_api)]
-Subproject commit f6446fa8e9629ffb1861303f17930c3aa83ef660
+Subproject commit 9b64ca5b7e1e3583978f9ac8af6d93b220a13d90
fn move_out_by_subslice() {
let a = [box 1, box 2];
- let [_y..] = a;
+ let [_y @ ..] = a;
}
fn main() {
extern crate rustc;
extern crate rustc_interface;
-#[allow(unused_extern_crates)]
-extern crate rustc_driver;
+extern crate rustc_driver as _;
extern crate syntax;
use rustc::session::DiagnosticOutput;
// libsyntax is not compiled for it.
#![deny(plugin_as_library)]
-#![allow(unused_extern_crates)]
extern crate attr_plugin_test; //~ ERROR compiler plugin used as an ordinary library
error: compiler plugin used as an ordinary library
- --> $DIR/plugin-as-extern-crate.rs:10:1
+ --> $DIR/plugin-as-extern-crate.rs:9:1
|
LL | extern crate attr_plugin_test;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
U: Clone+Debug, T:Debug,
F: FnMut(U, &T) -> U,
{ match values {
- &[ref head, ref tail..] =>
+ &[ref head, ref tail @ ..] =>
foldl(tail, function(initial, head), function),
&[] => {
// FIXME: call guards
F: FnMut(&T, U) -> U,
{
match values {
- &[ref head.., ref tail] =>
+ &[ref head @ .., ref tail] =>
foldr(head, function(tail, initial), function),
&[] => {
// FIXME: call guards
let x: &[isize] = &[1, 2, 3, 4, 5];
if !x.is_empty() {
let el = match x {
- &[1, ref tail..] => &tail[0],
+ &[1, ref tail @ ..] => &tail[0],
_ => unreachable!()
};
println!("{}", *el);
fn b() {
let x = [1, 2, 3];
match x {
- [a, b, c..] => {
+ [a, b, c @ ..] => {
assert_eq!(a, 1);
assert_eq!(b, 2);
let expected: &[_] = &[3];
}
}
match x {
- [a.., b, c] => {
+ [a @ .., b, c] => {
let expected: &[_] = &[1];
assert_eq!(a, expected);
assert_eq!(b, 2);
}
}
match x {
- [a, b.., c] => {
+ [a, b @ .., c] => {
assert_eq!(a, 1);
let expected: &[_] = &[2];
assert_eq!(b, expected);
fn b_slice() {
let x : &[_] = &[1, 2, 3];
match x {
- &[a, b, ref c..] => {
+ &[a, b, ref c @ ..] => {
assert_eq!(a, 1);
assert_eq!(b, 2);
let expected: &[_] = &[3];
_ => unreachable!()
}
match x {
- &[ref a.., b, c] => {
+ &[ref a @ .., b, c] => {
let expected: &[_] = &[1];
assert_eq!(a, expected);
assert_eq!(b, 2);
_ => unreachable!()
}
match x {
- &[a, ref b.., c] => {
+ &[a, ref b @ .., c] => {
assert_eq!(a, 1);
let expected: &[_] = &[2];
assert_eq!(b, expected);
assert_eq!(c, 1);
}
-fn f() {
- let x = &[1, 2, 3, 4, 5];
- let [a, [b, [c, ..].., d].., e] = *x;
- assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5));
-
- let x: &[isize] = x;
- let (a, b, c, d, e) = match *x {
- [a, [b, [c, ..].., d].., e] => (a, b, c, d, e),
- _ => unimplemented!()
- };
-
- assert_eq!((a, b, c, d, e), (1, 2, 3, 4, 5));
-}
-
pub fn main() {
a();
b();
c();
d();
e();
- f();
}
Foo { string: "baz" }
];
match x {
- [ref first, ref tail..] => {
+ [ref first, ref tail @ ..] => {
assert_eq!(first.string, "foo");
assert_eq!(tail.len(), 2);
assert_eq!(tail[0].string, "bar");
assert_eq!(tail[1].string, "baz");
match *(tail as &[_]) {
- [Foo { .. }, _, Foo { .. }, ref _tail..] => {
+ [Foo { .. }, _, Foo { .. }, ref _tail @ ..] => {
unreachable!();
}
[Foo { string: ref a }, Foo { string: ref b }] => {
let _ = <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
let <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
let 0 ..= <<A>::B>::C; //~ ERROR cannot find type `A` in this scope
- //~^ ERROR only char and numeric types are allowed in range patterns
<<A>::B>::C; //~ ERROR cannot find type `A` in this scope
}
| ^ not found in this scope
error[E0412]: cannot find type `A` in this scope
- --> $DIR/associated-path-shl.rs:9:7
+ --> $DIR/associated-path-shl.rs:8:7
|
LL | <<A>::B>::C;
| ^ not found in this scope
-error[E0029]: only char and numeric types are allowed in range patterns
- --> $DIR/associated-path-shl.rs:7:15
- |
-LL | let 0 ..= <<A>::B>::C;
- | ^^^^^^^^^^^ ranges require char or numeric types
- |
- = note: start type: {integer}
- = note: end type: [type error]
-
-error: aborting due to 6 previous errors
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0029, E0412.
-For more information about an error, try `rustc --explain E0029`.
+For more information about this error, try `rustc --explain E0412`.
-error[E0720]: opaque type expands to a recursive type
+error[E0733]: recursion in an `async fn` requires boxing
--> $DIR/recursive-async-impl-trait-type.rs:7:40
|
LL | async fn recursive_async_function() -> () {
- | ^^ expands to a recursive type
+ | ^^ an `async fn` cannot invoke itself directly
|
- = note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-async-impl-trait-type.rs:7:43: 9:2 {impl std::future::Future, ()}]>`
+ = note: a recursive `async fn` must be rewritten to return a boxed future.
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0720`.
+For more information about this error, try `rustc --explain E0733`.
#![feature(slice_patterns)]
fn foo(s: &[i32]) -> &[i32] {
- let &[ref xs..] = s;
+ let &[ref xs @ ..] = s;
xs
}
// The subslice used to go out of bounds for zero-sized array items, check that this doesn't
// happen anymore
match x {
- [_, ref y..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
+ [_, ref y @ ..] => assert_eq!(&x[1] as *const (), &y[0] as *const ())
}
}
LL | let x = &mut v;
| ------ borrow of `v` occurs here
LL | match v {
-LL | &[x..] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[x @ ..] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[_, x..] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[_, x @ ..] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[x.., _] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[x @ .., _] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[_, x.., _] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[_, x @ .., _] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
let mut v = &[1, 2, 3, 4, 5];
let x = &mut v;
match v {
- &[x..] => println!("{:?}", x),
+ &[x @ ..] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
- &[_, x..] => println!("{:?}", x),
+ &[_, x @ ..] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
- &[x.., _] => println!("{:?}", x),
+ &[x @ .., _] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
match v {
- &[_, x.., _] => println!("{:?}", x),
+ &[_, x @ .., _] => println!("{:?}", x),
//~^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
LL | let x = &mut v;
| ------ borrow of `v` occurs here
LL | match v {
-LL | &[x..] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[x @ ..] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[_, x..] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[_, x @ ..] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[x.., _] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[x @ .., _] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
LL | let x = &mut v;
| ------ borrow of `v` occurs here
...
-LL | &[_, x.., _] => println!("{:?}", x),
- | ^ use of borrowed `v`
+LL | &[_, x @ .., _] => println!("{:?}", x),
+ | ^^^^^^ use of borrowed `v`
...
LL | drop(x);
| - borrow later used here
fn move_out_by_const_index_and_subslice() {
let a = [box 1, box 2];
let [_x, _] = a;
- let [_y..] = a; //~ ERROR [E0382]
+ let [_y @ ..] = a; //~ ERROR [E0382]
}
fn main() {}
|
LL | let [_x, _] = a;
| -- value moved here
-LL | let [_y..] = a;
- | ^^ value used here after move
+LL | let [_y @ ..] = a;
+ | ^^^^^^^ value used here after move
|
= note: move occurs because `a[..]` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
];
let x: &[Foo] = &x;
match *x {
- [_, ref tail..] => {
+ [_, ref tail @ ..] => {
match tail {
//~^ ERROR cannot move out of type `[Foo]`
&[Foo { string: a },
fn mut_head_tail<'a, A>(v: &'a mut [A]) -> Option<(&'a mut A, &'a mut [A])> {
match *v {
- [ref mut head, ref mut tail..] => {
+ [ref mut head, ref mut tail @ ..] => {
Some((head, tail))
}
[] => None
fn const_index_and_subslice_ok(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s {
- if let [_, _, ref mut tail..] = *s {
+ if let [_, _, ref mut tail @ ..] = *s {
nop(&[first, second]);
nop_subslice(tail);
}
fn const_index_and_subslice_err(s: &mut [i32]) {
if let [ref first, ref second, ..] = *s {
- if let [_, ref mut tail..] = *s { //~ERROR
+ if let [_, ref mut tail @ ..] = *s { //~ERROR
nop(&[first, second]);
nop_subslice(tail);
}
fn const_index_and_subslice_from_end_ok(s: &mut [i32]) {
if let [.., ref second, ref first] = *s {
- if let [ref mut tail.., _, _] = *s {
+ if let [ref mut tail @ .., _, _] = *s {
nop(&[first, second]);
nop_subslice(tail);
}
fn const_index_and_subslice_from_end_err(s: &mut [i32]) {
if let [.., ref second, ref first] = *s {
- if let [ref mut tail.., _] = *s { //~ERROR
+ if let [ref mut tail @ .., _] = *s { //~ERROR
nop(&[first, second]);
nop_subslice(tail);
}
}
fn subslices(s: &mut [i32]) {
- if let [_, _, _, ref s1..] = *s {
- if let [ref mut s2.., _, _, _] = *s { //~ERROR
+ if let [_, _, _, ref s1 @ ..] = *s {
+ if let [ref mut s2 @ .., _, _, _] = *s { //~ERROR
nop_subslice(s1);
nop_subslice(s2);
}
|
LL | if let [ref first, ref second, ..] = *s {
| ---------- immutable borrow occurs here
-LL | if let [_, ref mut tail..] = *s {
- | ^^^^^^^^^^^^ mutable borrow occurs here
+LL | if let [_, ref mut tail @ ..] = *s {
+ | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]);
| ------ immutable borrow later used here
|
LL | if let [.., ref second, ref first] = *s {
| ---------- immutable borrow occurs here
-LL | if let [ref mut tail.., _] = *s {
- | ^^^^^^^^^^^^ mutable borrow occurs here
+LL | if let [ref mut tail @ .., _] = *s {
+ | ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop(&[first, second]);
| ------ immutable borrow later used here
error[E0502]: cannot borrow `s[..]` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-slice-pattern-element-loan.rs:109:17
|
-LL | if let [_, _, _, ref s1..] = *s {
- | ------ immutable borrow occurs here
-LL | if let [ref mut s2.., _, _, _] = *s {
- | ^^^^^^^^^^ mutable borrow occurs here
+LL | if let [_, _, _, ref s1 @ ..] = *s {
+ | ----------- immutable borrow occurs here
+LL | if let [ref mut s2 @ .., _, _, _] = *s {
+ | ^^^^^^^^^^^^^^^ mutable borrow occurs here
LL | nop_subslice(s1);
| -- immutable borrow later used here
let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec;
let tail = match vec {
- &[_, ref tail..] => tail,
+ &[_, ref tail @ ..] => tail,
_ => panic!("a")
};
tail //~ ERROR cannot return value referencing local variable `vec`
let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec;
let init = match vec {
- &[ref init.., _] => init,
+ &[ref init @ .., _] => init,
_ => panic!("b")
};
init //~ ERROR cannot return value referencing local variable `vec`
let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec;
let slice = match vec {
- &[_, ref slice.., _] => slice,
+ &[_, ref slice @ .., _] => slice,
_ => panic!("c")
};
slice //~ ERROR cannot return value referencing local variable `vec`
let mut v = vec![1, 2, 3];
let vb: &mut [isize] = &mut v;
match vb {
- &mut [_a, ref tail..] => {
+ &mut [_a, ref tail @ ..] => {
v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
}
_ => {}
fn main() {
let mut a = [1, 2, 3, 4];
let t = match a {
- [1, 2, ref tail..] => tail,
+ [1, 2, ref tail @ ..] => tail,
_ => unreachable!()
};
println!("t[0]: {}", t[0]);
error[E0506]: cannot assign to `a[_]` because it is borrowed
--> $DIR/borrowck-vec-pattern-move-tail.rs:12:5
|
-LL | [1, 2, ref tail..] => tail,
- | -------- borrow of `a[_]` occurs here
+LL | [1, 2, ref tail @ ..] => tail,
+ | ------------- borrow of `a[_]` occurs here
...
LL | a[2] = 0;
| ^^^^^^^^ assignment to borrowed `a[_]` occurs here
let mut vec = vec![box 1, box 2, box 3];
let vec: &mut [Box<isize>] = &mut vec;
match vec {
- &mut [ref _b..] => {
+ &mut [ref _b @ ..] => {
//~^ borrow of `vec[_]` occurs here
vec[0] = box 4; //~ ERROR cannot assign
//~^ NOTE assignment to borrowed `vec[_]` occurs here
error[E0506]: cannot assign to `vec[_]` because it is borrowed
--> $DIR/borrowck-vec-pattern-nesting.rs:24:13
|
-LL | &mut [ref _b..] => {
- | ------ borrow of `vec[_]` occurs here
+LL | &mut [ref _b @ ..] => {
+ | ----------- borrow of `vec[_]` occurs here
LL |
LL | vec[0] = box 4;
| ^^^^^^ assignment to borrowed `vec[_]` occurs here
let vec = vec![1, 2, 3, 4];
let vec: &[isize] = &vec;
let tail = match vec {
- &[_a, ref tail..] => &tail[0],
+ &[_a, ref tail @ ..] => &tail[0],
_ => panic!("foo")
};
tail //~ ERROR cannot return value referencing local variable `vec`
--- /dev/null
+// To avoid leaking the names of local bindings from expressions like for loops, #60984
+// explicitly ignored them, but an assertion that `LocalKind::Var` *must* have a name would
+// trigger an ICE. Before this change, this file's output would be:
+// ```
+// error[E0515]: cannot return value referencing local variable `__next`
+// --> return-local-binding-from-desugaring.rs:LL:CC
+// |
+// LL | for ref x in xs {
+// | ----- `__next` is borrowed here
+// ...
+// LL | result
+// | ^^^^^^ returns a value referencing data owned by the current function
+// ```
+// FIXME: ideally `LocalKind` would carry more information to more accurately explain the problem.
+
+use std::collections::HashMap;
+use std::hash::Hash;
+
+fn group_by<I, F, T>(xs: &mut I, f: F) -> HashMap<T, Vec<&I::Item>>
+where
+ I: Iterator,
+ F: Fn(&I::Item) -> T,
+ T: Eq + Hash,
+{
+ let mut result = HashMap::new();
+ for ref x in xs {
+ let key = f(x);
+ result.entry(key).or_insert(Vec::new()).push(x);
+ }
+ result //~ ERROR cannot return value referencing local binding
+}
+
+fn main() {}
--- /dev/null
+error[E0515]: cannot return value referencing local binding
+ --> $DIR/return-local-binding-from-desugaring.rs:30:5
+ |
+LL | for ref x in xs {
+ | -- local binding introduced here
+...
+LL | result
+ | ^^^^^^ returns a value referencing data owned by the current function
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0515`.
--- /dev/null
+// check-pass
+
+pub fn yes_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 32]>
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+pub fn yes_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 32]>
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+use std::collections::VecDeque;
+
+pub fn yes_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 32]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn yes_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 32]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn yes_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 32]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+fn main() {}
--- /dev/null
+pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+//~^ ERROR arrays only have std trait implementations for lengths 0..=32
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+//~^ ERROR arrays only have std trait implementations for lengths 0..=32
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+use std::collections::VecDeque;
+
+pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+//~^ ERROR arrays only have std trait implementations for lengths 0..=32
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+//~^ ERROR arrays only have std trait implementations for lengths 0..=32
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
+//~^ ERROR arrays only have std trait implementations for lengths 0..=32
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+ --> $DIR/alloc-traits-no-impls-length-33.rs:1:43
+ |
+LL | pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+ | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+ |
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec<A>`
+ = note: the return type of a function must have a statically known size
+
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+ --> $DIR/alloc-traits-no-impls-length-33.rs:9:51
+ |
+LL | pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+ |
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec<A>`
+ = note: the return type of a function must have a statically known size
+
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+ --> $DIR/alloc-traits-no-impls-length-33.rs:19:48
+ |
+LL | pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+ | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+ |
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque<A>`
+ = note: the return type of a function must have a statically known size
+
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+ --> $DIR/alloc-traits-no-impls-length-33.rs:27:56
+ |
+LL | pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+ |
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque<A>`
+ = note: the return type of a function must have a statically known size
+
+error[E0277]: arrays only have std trait implementations for lengths 0..=32
+ --> $DIR/alloc-traits-no-impls-length-33.rs:35:60
+ |
+LL | pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
+ |
+ = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque<A>`
+ = note: the return type of a function must have a statically known size
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
if arg {
let [.., _x, _] = arr;
} else {
- let [_, _y..] = arr;
+ let [_, _y @ ..] = arr;
}
a.alloc().await;
}
let mut ar = [a.alloc().await, a.alloc().await, a.alloc().await];
let [_, _, _x] = ar;
ar = [a.alloc().await, a.alloc().await, a.alloc().await];
- let [_, _y..] = ar;
+ let [_, _y @ ..] = ar;
a.alloc().await;
}
if arg {
let[.., _x, _] = a;
} else {
- let[_, _y..] = a;
+ let[_, _y @ ..] = a;
}
}
if arg {
let[.., _x, _] = a;
} else {
- let[_, _y..] = a;
+ let[_, _y @ ..] = a;
}
}
let mut ar = [a.alloc(), a.alloc(), a.alloc()];
let[_, _, _x] = ar;
ar = [a.alloc(), a.alloc(), a.alloc()];
- let[_, _y..] = ar;
+ let[_, _y @ ..] = ar;
}
fn panic_after_return(a: &Allocator) -> Ptr<'_> {
#![deny(non_snake_case)] // To trigger a hard error
// Shouldn't generate a warning about unstable features
-#[allow(unused_extern_crates)]
extern crate stability_cfg2;
pub fn BOGUS() { } //~ ERROR
error: function `BOGUS` should have a snake case name
- --> $DIR/enable-unstable-lib-feature.rs:12:8
+ --> $DIR/enable-unstable-lib-feature.rs:11:8
|
LL | pub fn BOGUS() { }
| ^^^^^ help: convert the identifier to snake case: `bogus`
-#![allow(unused_extern_crates, non_camel_case_types)]
+#![allow(non_camel_case_types)]
extern crate alloc;
#![feature(rustc_private)]
-#![allow(unused_extern_crates)]
extern crate alloc;
error[E0259]: the name `alloc` is defined multiple times
- --> $DIR/E0259.rs:6:1
+ --> $DIR/E0259.rs:5:1
|
LL | extern crate alloc;
| ------------------- previous import of the extern crate `alloc` here
-#![allow(unused_extern_crates)]
-
extern crate alloc;
mod alloc {
error[E0260]: the name `alloc` is defined multiple times
- --> $DIR/E0260.rs:5:1
+ --> $DIR/E0260.rs:3:1
|
LL | extern crate alloc;
| ------------------- previous import of the extern crate `alloc` here
fn main() {
let r = &[1, 2];
match r {
- &[a, b, c, rest..] => {
+ &[a, b, c, rest @ ..] => {
//~^ ERROR E0528
}
}
error[E0528]: pattern requires at least 3 elements but array has 2
--> $DIR/E0528.rs:6:10
|
-LL | &[a, b, c, rest..] => {
- | ^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements
+LL | &[a, b, c, rest @ ..] => {
+ | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 2 elements
error: aborting due to previous error
}
pub trait LolFrom<T> {
- fn from(T) -> Self;
+ fn from(_: T) -> Self;
}
impl<'a, T: ?Sized, U> LolInto<U> for &'a T where T: LolTo<U> {
fn main() {
match [5..4, 99..105, 43..44] {
- [_, 99.., _] => {}, //~ ERROR unexpected token: `,`
+ [_, 99.., _] => {},
+ //~^ ERROR `X..` range patterns are not supported
+ //~| ERROR mismatched types
_ => {},
}
}
-error: unexpected token: `,`
- --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17
+error: `X..` range patterns are not supported
+ --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
|
LL | [_, 99.., _] => {},
- | ^
+ | ^^^^ help: try using the maximum value for the type: `99..MAX`
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:13
+ |
+LL | match [5..4, 99..105, 43..44] {
+ | ----------------------- this match expression has type `std::ops::Range<{integer}>`
+LL | [_, 99.., _] => {},
+ | ^^^^ expected struct `std::ops::Range`, found integer
+ |
+ = note: expected type `std::ops::Range<{integer}>`
+ found type `{integer}`
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
fn main() {
match [5..4, 99..105, 43..44] {
- [_, 99..] => {}, //~ ERROR unexpected token: `]`
+ [_, 99..] => {},
+ //~^ ERROR `X..` range patterns are not supported
+ //~| ERROR pattern requires 2 elements but array has 3
+ //~| ERROR mismatched types
_ => {},
}
}
-error: unexpected token: `]`
- --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17
+error: `X..` range patterns are not supported
+ --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
|
LL | [_, 99..] => {},
- | ^
+ | ^^^^ help: try using the maximum value for the type: `99..MAX`
-error: aborting due to previous error
+error[E0527]: pattern requires 2 elements but array has 3
+ --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:9
+ |
+LL | [_, 99..] => {},
+ | ^^^^^^^^^ expected 3 elements
+
+error[E0308]: mismatched types
+ --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:13
+ |
+LL | match [5..4, 99..105, 43..44] {
+ | ----------------------- this match expression has type `std::ops::Range<{integer}>`
+LL | [_, 99..] => {},
+ | ^^^^ expected struct `std::ops::Range`, found integer
+ |
+ = note: expected type `std::ops::Range<{integer}>`
+ found type `{integer}`
+
+error: aborting due to 3 previous errors
+Some errors have detailed explanations: E0308, E0527.
+For more information about an error, try `rustc --explain E0308`.
fn main() {
match [5..4, 99..105, 43..44] {
- [..9, 99..100, _] => {}, //~ ERROR expected one of `,` or `]`, found `9`
+ [..9, 99..100, _] => {},
+ //~^ ERROR `..X` range patterns are not supported
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
_ => {},
}
}
-error: expected one of `,` or `]`, found `9`
- --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:12
+error: `..X` range patterns are not supported
+ --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10
|
LL | [..9, 99..100, _] => {},
- | ^ expected one of `,` or `]` here
+ | ^^^ help: try using the minimum value for the type: `MIN..9`
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:10
+ |
+LL | match [5..4, 99..105, 43..44] {
+ | ----------------------- this match expression has type `std::ops::Range<{integer}>`
+LL | [..9, 99..100, _] => {},
+ | ^^^ expected struct `std::ops::Range`, found integer
+ |
+ = note: expected type `std::ops::Range<{integer}>`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/exclusive_range_pattern_syntax_collision3.rs:5:15
+ |
+LL | match [5..4, 99..105, 43..44] {
+ | ----------------------- this match expression has type `std::ops::Range<{integer}>`
+LL | [..9, 99..100, _] => {},
+ | ^^^^^^^ expected struct `std::ops::Range`, found integer
+ |
+ = note: expected type `std::ops::Range<{integer}>`
+ found type `{integer}`
+
+error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0308`.
fn main() {
let x = [1, 2, 3, 4, 5];
match x {
- [1, 2, ..] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
- [1, .., 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
- [.., 4, 5] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
+ [1, 2, ..] => {} //~ ERROR subslice patterns are unstable
+ [1, .., 5] => {} //~ ERROR subslice patterns are unstable
+ [.., 4, 5] => {} //~ ERROR subslice patterns are unstable
}
let x = [ 1, 2, 3, 4, 5 ];
match x {
- [ xs.., 4, 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
- [ 1, xs.., 5 ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
- [ 1, 2, xs.. ] => {} //~ ERROR syntax for subslices in slice patterns is not yet stabilized
+ [ xs @ .., 4, 5 ] => {} //~ ERROR subslice patterns are unstable
+ [ 1, xs @ .., 5 ] => {} //~ ERROR subslice patterns are unstable
+ [ 1, 2, xs @ .. ] => {} //~ ERROR subslice patterns are unstable
}
}
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:6:16
|
LL | [1, 2, ..] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:7:13
|
LL | [1, .., 5] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:8:10
|
LL | [.., 4, 5] => {}
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:13:11
|
-LL | [ xs.., 4, 5 ] => {}
- | ^^
+LL | [ xs @ .., 4, 5 ] => {}
+ | ^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:14:14
|
-LL | [ 1, xs.., 5 ] => {}
- | ^^
+LL | [ 1, xs @ .., 5 ] => {}
+ | ^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
-error[E0658]: syntax for subslices in slice patterns is not yet stabilized
+error[E0658]: subslice patterns are unstable
--> $DIR/feature-gate-slice-patterns.rs:15:17
|
-LL | [ 1, 2, xs.. ] => {}
- | ^^
+LL | [ 1, 2, xs @ .. ] => {}
+ | ^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/62254
= help: add `#![feature(slice_patterns)]` to the crate attributes to enable
let v: isize = match &*sl {
&[] => 0,
&[a,b,c] => 3,
- &[a, ref rest..] => a,
- &[10,a, ref rest..] => 10 //~ ERROR: unreachable pattern
+ &[a, ref rest @ ..] => a,
+ &[10,a, ref rest @ ..] => 10 //~ ERROR: unreachable pattern
};
}
error: unreachable pattern
--> $DIR/issue-12369.rs:10:9
|
-LL | &[10,a, ref rest..] => 10
- | ^^^^^^^^^^^^^^^^^^^
+LL | &[10,a, ref rest @ ..] => 10
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
note: lint level defined here
--> $DIR/issue-12369.rs:2:9
let mut result = vec![];
loop {
x = match *x {
- [1, n, 3, ref rest..] => {
+ [1, n, 3, ref rest @ ..] => {
result.push(n);
rest
}
- [n, ref rest..] => {
+ [n, ref rest @ ..] => {
result.push(n);
rest
}
match *v {
[] => 0,
[_] => 1,
- [_, ref xs..] => 1 + count_members(xs)
+ [_, ref xs @ ..] => 1 + count_members(xs)
}
}
}, 42_usize);
assert_eq!(match [0u8; 1024] {
- [1, _..] => 0_usize,
- [0, _..] => 1_usize,
+ [1, ..] => 0_usize,
+ [0, ..] => 1_usize,
_ => 2_usize
}, 1_usize);
}
+++ /dev/null
-#![feature(slice_patterns)]
-
-fn main() {
- let x: &[u32] = &[];
- let &[[ref _a, ref _b..]..] = x; //~ ERROR refutable pattern
-}
+++ /dev/null
-error[E0005]: refutable pattern in local binding: `&[]` not covered
- --> $DIR/issue-26158.rs:5:9
- |
-LL | let &[[ref _a, ref _b..]..] = x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ pattern `&[]` not covered
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0005`.
// aux-build:issue-36881-aux.rs
fn main() {
- #[allow(unused_extern_crates)]
extern crate issue_36881_aux;
use issue_36881_aux::Foo; //~ ERROR unresolved import
}
error[E0432]: unresolved import `issue_36881_aux`
- --> $DIR/issue-36881.rs:6:9
+ --> $DIR/issue-36881.rs:5:9
|
LL | use issue_36881_aux::Foo;
| ^^^^^^^^^^^^^^^ maybe a missing `extern crate issue_36881_aux;`?
-// build-pass (FIXME(62277): could be check-pass?)
-#![allow(dead_code)]
+// check-pass
#![feature(slice_patterns)]
fn check(list: &[u8]) {
match list {
&[] => {},
- &[_u1, _u2, ref _next..] => {},
+ &[_u1, _u2, ref _next @ ..] => {},
&[_u1] => {},
}
}
error: an inner attribute is not permitted in this context
- --> $DIR/issue-45296.rs:4:7
+ --> $DIR/issue-45296.rs:4:5
|
LL | #![allow(unused_variables)]
- | ^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
assert_eq!(d, "baz");
let out = bar("baz", "foo");
- let [a, xs.., d] = out;
+ let [a, xs @ .., d] = out;
assert_eq!(a, "baz");
assert_eq!(xs, ["foo", "foo"]);
assert_eq!(d, "baz");
// aux-build:stability-cfg2.rs
// ignore-tidy-linelength
#![warn(deprecated)]
-#![allow(dead_code, unused_extern_crates)]
#![feature(staged_api, unstable_test_feature)]
#![stable(feature = "rust1", since = "1.0.0")]
warning: use of deprecated item 'lint_stability::deprecated': text
- --> $DIR/lint-stability-deprecated.rs:26:9
+ --> $DIR/lint-stability-deprecated.rs:25:9
|
LL | deprecated();
| ^^^^^^^^^^
| ^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:31:9
+ --> $DIR/lint-stability-deprecated.rs:30:9
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:33:9
+ --> $DIR/lint-stability-deprecated.rs:32:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:35:9
+ --> $DIR/lint-stability-deprecated.rs:34:9
|
LL | deprecated_text();
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:40:9
+ --> $DIR/lint-stability-deprecated.rs:39:9
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:42:9
+ --> $DIR/lint-stability-deprecated.rs:41:9
|
LL | <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:44:9
+ --> $DIR/lint-stability-deprecated.rs:43:9
|
LL | deprecated_unstable();
| ^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:49:9
+ --> $DIR/lint-stability-deprecated.rs:48:9
|
LL | Trait::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:51:9
+ --> $DIR/lint-stability-deprecated.rs:50:9
|
LL | <Foo as Trait>::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:53:9
+ --> $DIR/lint-stability-deprecated.rs:52:9
|
LL | deprecated_unstable_text();
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:58:9
+ --> $DIR/lint-stability-deprecated.rs:57:9
|
LL | Trait::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:60:9
+ --> $DIR/lint-stability-deprecated.rs:59:9
|
LL | <Foo as Trait>::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedStruct': text
- --> $DIR/lint-stability-deprecated.rs:107:17
+ --> $DIR/lint-stability-deprecated.rs:106:17
|
LL | let _ = DeprecatedStruct {
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct': text
- --> $DIR/lint-stability-deprecated.rs:110:17
+ --> $DIR/lint-stability-deprecated.rs:109:17
|
LL | let _ = DeprecatedUnstableStruct {
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedUnitStruct': text
- --> $DIR/lint-stability-deprecated.rs:117:17
+ --> $DIR/lint-stability-deprecated.rs:116:17
|
LL | let _ = DeprecatedUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedUnstableUnitStruct': text
- --> $DIR/lint-stability-deprecated.rs:118:17
+ --> $DIR/lint-stability-deprecated.rs:117:17
|
LL | let _ = DeprecatedUnstableUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Enum::DeprecatedVariant': text
- --> $DIR/lint-stability-deprecated.rs:122:17
+ --> $DIR/lint-stability-deprecated.rs:121:17
|
LL | let _ = Enum::DeprecatedVariant;
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Enum::DeprecatedUnstableVariant': text
- --> $DIR/lint-stability-deprecated.rs:123:17
+ --> $DIR/lint-stability-deprecated.rs:122:17
|
LL | let _ = Enum::DeprecatedUnstableVariant;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedTupleStruct': text
- --> $DIR/lint-stability-deprecated.rs:127:17
+ --> $DIR/lint-stability-deprecated.rs:126:17
|
LL | let _ = DeprecatedTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedUnstableTupleStruct': text
- --> $DIR/lint-stability-deprecated.rs:128:17
+ --> $DIR/lint-stability-deprecated.rs:127:17
|
LL | let _ = DeprecatedUnstableTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:137:25
+ --> $DIR/lint-stability-deprecated.rs:136:25
|
LL | macro_test_arg!(deprecated_text());
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:138:25
+ --> $DIR/lint-stability-deprecated.rs:137:25
|
LL | macro_test_arg!(deprecated_unstable_text());
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:139:41
+ --> $DIR/lint-stability-deprecated.rs:138:41
|
LL | macro_test_arg!(macro_test_arg!(deprecated_text()));
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:144:9
+ --> $DIR/lint-stability-deprecated.rs:143:9
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:146:9
+ --> $DIR/lint-stability-deprecated.rs:145:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:148:9
+ --> $DIR/lint-stability-deprecated.rs:147:9
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:150:9
+ --> $DIR/lint-stability-deprecated.rs:149:9
|
LL | <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:152:9
+ --> $DIR/lint-stability-deprecated.rs:151:9
|
LL | Trait::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:154:9
+ --> $DIR/lint-stability-deprecated.rs:153:9
|
LL | <Foo as Trait>::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:156:9
+ --> $DIR/lint-stability-deprecated.rs:155:9
|
LL | Trait::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:158:9
+ --> $DIR/lint-stability-deprecated.rs:157:9
|
LL | <Foo as Trait>::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedTrait': text
- --> $DIR/lint-stability-deprecated.rs:186:10
+ --> $DIR/lint-stability-deprecated.rs:185:10
|
LL | impl DeprecatedTrait for S {}
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedTrait': text
- --> $DIR/lint-stability-deprecated.rs:188:25
+ --> $DIR/lint-stability-deprecated.rs:187:25
|
LL | trait LocalTrait2 : DeprecatedTrait { }
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'inheritance::inherited_stability::unstable_mod::deprecated': text
- --> $DIR/lint-stability-deprecated.rs:207:9
+ --> $DIR/lint-stability-deprecated.rs:206:9
|
LL | unstable_mod::deprecated();
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::deprecated': text
- --> $DIR/lint-stability-deprecated.rs:329:9
+ --> $DIR/lint-stability-deprecated.rs:328:9
|
LL | deprecated();
| ^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:334:9
+ --> $DIR/lint-stability-deprecated.rs:333:9
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:336:9
+ --> $DIR/lint-stability-deprecated.rs:335:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:338:9
+ --> $DIR/lint-stability-deprecated.rs:337:9
|
LL | deprecated_text();
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:343:9
+ --> $DIR/lint-stability-deprecated.rs:342:9
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:345:9
+ --> $DIR/lint-stability-deprecated.rs:344:9
|
LL | <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedStruct': text
- --> $DIR/lint-stability-deprecated.rs:383:17
+ --> $DIR/lint-stability-deprecated.rs:382:17
|
LL | let _ = DeprecatedStruct {
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedUnitStruct': text
- --> $DIR/lint-stability-deprecated.rs:390:17
+ --> $DIR/lint-stability-deprecated.rs:389:17
|
LL | let _ = DeprecatedUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Enum::DeprecatedVariant': text
- --> $DIR/lint-stability-deprecated.rs:394:17
+ --> $DIR/lint-stability-deprecated.rs:393:17
|
LL | let _ = Enum::DeprecatedVariant;
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedTupleStruct': text
- --> $DIR/lint-stability-deprecated.rs:398:17
+ --> $DIR/lint-stability-deprecated.rs:397:17
|
LL | let _ = DeprecatedTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:405:9
+ --> $DIR/lint-stability-deprecated.rs:404:9
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:407:9
+ --> $DIR/lint-stability-deprecated.rs:406:9
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:409:9
+ --> $DIR/lint-stability-deprecated.rs:408:9
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:411:9
+ --> $DIR/lint-stability-deprecated.rs:410:9
|
LL | <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::test_fn_body::fn_in_body': text
- --> $DIR/lint-stability-deprecated.rs:438:9
+ --> $DIR/lint-stability-deprecated.rs:437:9
|
LL | fn_in_body();
| ^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedTrait': text
- --> $DIR/lint-stability-deprecated.rs:458:10
+ --> $DIR/lint-stability-deprecated.rs:457:10
|
LL | impl DeprecatedTrait for S { }
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedTrait': text
- --> $DIR/lint-stability-deprecated.rs:460:24
+ --> $DIR/lint-stability-deprecated.rs:459:24
|
LL | trait LocalTrait : DeprecatedTrait { }
| ^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::test_method_body::fn_in_body': text
- --> $DIR/lint-stability-deprecated.rs:446:13
+ --> $DIR/lint-stability-deprecated.rs:445:13
|
LL | fn_in_body();
| ^^^^^^^^^^
warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
- --> $DIR/lint-stability-deprecated.rs:99:48
+ --> $DIR/lint-stability-deprecated.rs:98:48
|
LL | struct S2<T: TraitWithAssociatedTypes>(T::TypeDeprecated);
| ^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::TraitWithAssociatedTypes::TypeDeprecated': text
- --> $DIR/lint-stability-deprecated.rs:103:13
+ --> $DIR/lint-stability-deprecated.rs:102:13
|
LL | TypeDeprecated = u16,
| ^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:27:13
+ --> $DIR/lint-stability-deprecated.rs:26:13
|
LL | foo.method_deprecated();
| ^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:28:9
+ --> $DIR/lint-stability-deprecated.rs:27:9
|
LL | Foo::method_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:29:9
+ --> $DIR/lint-stability-deprecated.rs:28:9
|
LL | <Foo>::method_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:30:13
+ --> $DIR/lint-stability-deprecated.rs:29:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:32:9
+ --> $DIR/lint-stability-deprecated.rs:31:9
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:36:13
+ --> $DIR/lint-stability-deprecated.rs:35:13
|
LL | foo.method_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:37:9
+ --> $DIR/lint-stability-deprecated.rs:36:9
|
LL | Foo::method_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:38:9
+ --> $DIR/lint-stability-deprecated.rs:37:9
|
LL | <Foo>::method_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:39:13
+ --> $DIR/lint-stability-deprecated.rs:38:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:41:9
+ --> $DIR/lint-stability-deprecated.rs:40:9
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:45:13
+ --> $DIR/lint-stability-deprecated.rs:44:13
|
LL | foo.method_deprecated_unstable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:46:9
+ --> $DIR/lint-stability-deprecated.rs:45:9
|
LL | Foo::method_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:47:9
+ --> $DIR/lint-stability-deprecated.rs:46:9
|
LL | <Foo>::method_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:48:13
+ --> $DIR/lint-stability-deprecated.rs:47:13
|
LL | foo.trait_deprecated_unstable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:50:9
+ --> $DIR/lint-stability-deprecated.rs:49:9
|
LL | <Foo>::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:54:13
+ --> $DIR/lint-stability-deprecated.rs:53:13
|
LL | foo.method_deprecated_unstable_text();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:55:9
+ --> $DIR/lint-stability-deprecated.rs:54:9
|
LL | Foo::method_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::MethodTester::method_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:56:9
+ --> $DIR/lint-stability-deprecated.rs:55:9
|
LL | <Foo>::method_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:57:13
+ --> $DIR/lint-stability-deprecated.rs:56:13
|
LL | foo.trait_deprecated_unstable_text();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:59:9
+ --> $DIR/lint-stability-deprecated.rs:58:9
|
LL | <Foo>::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::DeprecatedStruct::i': text
- --> $DIR/lint-stability-deprecated.rs:108:13
+ --> $DIR/lint-stability-deprecated.rs:107:13
|
LL | i: 0
| ^^^^
warning: use of deprecated item 'lint_stability::DeprecatedUnstableStruct::i': text
- --> $DIR/lint-stability-deprecated.rs:112:13
+ --> $DIR/lint-stability-deprecated.rs:111:13
|
LL | i: 0
| ^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:143:13
+ --> $DIR/lint-stability-deprecated.rs:142:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:145:9
+ --> $DIR/lint-stability-deprecated.rs:144:9
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:147:13
+ --> $DIR/lint-stability-deprecated.rs:146:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:149:9
+ --> $DIR/lint-stability-deprecated.rs:148:9
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:151:13
+ --> $DIR/lint-stability-deprecated.rs:150:13
|
LL | foo.trait_deprecated_unstable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:153:9
+ --> $DIR/lint-stability-deprecated.rs:152:9
|
LL | <Foo>::trait_deprecated_unstable(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:155:13
+ --> $DIR/lint-stability-deprecated.rs:154:13
|
LL | foo.trait_deprecated_unstable_text();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:157:9
+ --> $DIR/lint-stability-deprecated.rs:156:9
|
LL | <Foo>::trait_deprecated_unstable_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:174:13
+ --> $DIR/lint-stability-deprecated.rs:173:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:175:13
+ --> $DIR/lint-stability-deprecated.rs:174:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable': text
- --> $DIR/lint-stability-deprecated.rs:176:13
+ --> $DIR/lint-stability-deprecated.rs:175:13
|
LL | foo.trait_deprecated_unstable();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'lint_stability::Trait::trait_deprecated_unstable_text': text
- --> $DIR/lint-stability-deprecated.rs:177:13
+ --> $DIR/lint-stability-deprecated.rs:176:13
|
LL | foo.trait_deprecated_unstable_text();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:330:13
+ --> $DIR/lint-stability-deprecated.rs:329:13
|
LL | foo.method_deprecated();
| ^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:331:9
+ --> $DIR/lint-stability-deprecated.rs:330:9
|
LL | Foo::method_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:332:9
+ --> $DIR/lint-stability-deprecated.rs:331:9
|
LL | <Foo>::method_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:333:13
+ --> $DIR/lint-stability-deprecated.rs:332:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:335:9
+ --> $DIR/lint-stability-deprecated.rs:334:9
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:339:13
+ --> $DIR/lint-stability-deprecated.rs:338:13
|
LL | foo.method_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:340:9
+ --> $DIR/lint-stability-deprecated.rs:339:9
|
LL | Foo::method_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::MethodTester::method_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:341:9
+ --> $DIR/lint-stability-deprecated.rs:340:9
|
LL | <Foo>::method_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:342:13
+ --> $DIR/lint-stability-deprecated.rs:341:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:344:9
+ --> $DIR/lint-stability-deprecated.rs:343:9
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::DeprecatedStruct::i': text
- --> $DIR/lint-stability-deprecated.rs:385:13
+ --> $DIR/lint-stability-deprecated.rs:384:13
|
LL | i: 0
| ^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:404:13
+ --> $DIR/lint-stability-deprecated.rs:403:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:406:9
+ --> $DIR/lint-stability-deprecated.rs:405:9
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:408:13
+ --> $DIR/lint-stability-deprecated.rs:407:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:410:9
+ --> $DIR/lint-stability-deprecated.rs:409:9
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated': text
- --> $DIR/lint-stability-deprecated.rs:427:13
+ --> $DIR/lint-stability-deprecated.rs:426:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
warning: use of deprecated item 'this_crate::Trait::trait_deprecated_text': text
- --> $DIR/lint-stability-deprecated.rs:428:13
+ --> $DIR/lint-stability-deprecated.rs:427:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
+// edition:2018
+
// Exercise the unused_mut attribute in some positive and negative cases
-#![allow(unused_assignments)]
-#![allow(unused_variables)]
-#![allow(dead_code)]
#![deny(unused_mut)]
+#![feature(async_await, async_closure, param_attrs)]
+
+async fn baz_async(
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+) {}
+fn baz(
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ #[allow(unused_mut)] (mut c, d): (i32, i32)
+) {}
+
+struct RefStruct {}
+impl RefStruct {
+ async fn baz_async(
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ ) {}
+ fn baz(
+ &self,
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ #[allow(unused_mut)] (mut c, d): (i32, i32)
+ ) {}
+}
+trait RefTrait {
+ fn baz(
+ &self,
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ #[allow(unused_mut)] (mut c, d): (i32, i32)
+ ) {}
+}
+impl RefTrait for () {
+ fn baz(
+ &self,
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ #[allow(unused_mut)] (mut c, d): (i32, i32)
+ ) {}
+}
fn main() {
+ let _ = async move |
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ | {};
+ let _ = |
+ mut a: i32,
+ //~^ ERROR: variable does not need to be mutable
+ #[allow(unused_mut)] mut b: i32,
+ #[allow(unused_mut)] (mut c, d): (i32, i32)
+ | {};
+
// negative cases
let mut a = 3; //~ ERROR: variable does not need to be mutable
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:46:14
+ --> $DIR/lint-unused-mut-variables.rs:9:5
|
-LL | let x = |mut y: isize| 10;
- | ----^
- | |
- | help: remove this `mut`
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
|
note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:6:9
+ --> $DIR/lint-unused-mut-variables.rs:5:9
|
LL | #![deny(unused_mut)]
| ^^^^^^^^^^
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:11:9
+ --> $DIR/lint-unused-mut-variables.rs:14:5
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:23:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:29:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:39:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:48:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:57:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:62:9
+ |
+LL | mut a: i32,
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:104:14
+ |
+LL | let x = |mut y: isize| 10;
+ | ----^
+ | |
+ | help: remove this `mut`
+
+error: variable does not need to be mutable
+ --> $DIR/lint-unused-mut-variables.rs:69:9
|
LL | let mut a = 3;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:13:9
+ --> $DIR/lint-unused-mut-variables.rs:71:9
|
LL | let mut a = 2;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:15:9
+ --> $DIR/lint-unused-mut-variables.rs:73:9
|
LL | let mut b = 3;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:17:9
+ --> $DIR/lint-unused-mut-variables.rs:75:9
|
LL | let mut a = vec![3];
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:19:10
+ --> $DIR/lint-unused-mut-variables.rs:77:10
|
LL | let (mut a, b) = (1, 2);
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:21:9
+ --> $DIR/lint-unused-mut-variables.rs:79:9
|
LL | let mut a;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:25:9
+ --> $DIR/lint-unused-mut-variables.rs:83:9
|
LL | let mut b;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:34:9
+ --> $DIR/lint-unused-mut-variables.rs:92:9
|
LL | mut x => {}
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:38:8
+ --> $DIR/lint-unused-mut-variables.rs:96:8
|
LL | (mut x, 1) |
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:51:9
+ --> $DIR/lint-unused-mut-variables.rs:109:9
|
LL | let mut a = &mut 5;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:56:9
+ --> $DIR/lint-unused-mut-variables.rs:114:9
|
LL | let mut b = (&mut a,);
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:59:9
+ --> $DIR/lint-unused-mut-variables.rs:117:9
|
LL | let mut x = &mut 1;
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:71:9
+ --> $DIR/lint-unused-mut-variables.rs:129:9
|
LL | let mut v : &mut Vec<()> = &mut vec![];
| ----^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:48:13
+ --> $DIR/lint-unused-mut-variables.rs:106:13
|
LL | fn what(mut foo: isize) {}
| ----^^^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:66:20
+ --> $DIR/lint-unused-mut-variables.rs:124:20
|
LL | fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] {
| ----^^^
| help: remove this `mut`
error: variable does not need to be mutable
- --> $DIR/lint-unused-mut-variables.rs:138:9
+ --> $DIR/lint-unused-mut-variables.rs:196:9
|
LL | let mut b = vec![2];
| ----^
| help: remove this `mut`
|
note: lint level defined here
- --> $DIR/lint-unused-mut-variables.rs:134:8
+ --> $DIR/lint-unused-mut-variables.rs:192:8
|
LL | #[deny(unused_mut)]
| ^^^^^^^^^^
-error: aborting due to 17 previous errors
+error: aborting due to 25 previous errors
--- /dev/null
+// compile-flags: --cfg something
+// edition:2018
+
+#![feature(async_await, async_closure, param_attrs)]
+#![deny(unused_variables)]
+
+async fn foo_async(
+ a: i32,
+ //~^ ERROR unused variable: `a`
+ #[allow(unused_variables)] b: i32,
+) {}
+fn foo(
+ #[allow(unused_variables)] a: i32,
+ b: i32,
+ //~^ ERROR unused variable: `b`
+) {}
+
+struct RefStruct {}
+impl RefStruct {
+ async fn bar_async(
+ &self,
+ a: i32,
+ //~^ ERROR unused variable: `a`
+ #[allow(unused_variables)] b: i32,
+ ) {}
+ fn bar(
+ &self,
+ #[allow(unused_variables)] a: i32,
+ b: i32,
+ //~^ ERROR unused variable: `b`
+ ) {}
+}
+trait RefTrait {
+ fn bar(
+ &self,
+ #[allow(unused_variables)] a: i32,
+ b: i32,
+ //~^ ERROR unused variable: `b`
+ ) {}
+}
+impl RefTrait for RefStruct {
+ fn bar(
+ &self,
+ #[allow(unused_variables)] a: i32,
+ b: i32,
+ //~^ ERROR unused variable: `b`
+ ) {}
+}
+
+fn main() {
+ let _: fn(_, _) = foo;
+ let a = async move |
+ a: i32,
+ //~^ ERROR unused variable: `a`
+ #[allow(unused_variables)] b: i32,
+ | {};
+ let b = |
+ #[allow(unused_variables)] a: i32,
+ b: i32,
+ //~^ ERROR unused variable: `b`
+ | {};
+ let _ = a(1, 2);
+ let _ = b(1, 2);
+}
--- /dev/null
+error: unused variable: `a`
+ --> $DIR/lint-unused-variables.rs:8:5
+ |
+LL | a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
+ |
+note: lint level defined here
+ --> $DIR/lint-unused-variables.rs:5:9
+ |
+LL | #![deny(unused_variables)]
+ | ^^^^^^^^^^^^^^^^
+
+error: unused variable: `b`
+ --> $DIR/lint-unused-variables.rs:14:5
+ |
+LL | b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/lint-unused-variables.rs:53:9
+ |
+LL | a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/lint-unused-variables.rs:59:9
+ |
+LL | b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `b`
+ --> $DIR/lint-unused-variables.rs:37:9
+ |
+LL | b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `a`
+ --> $DIR/lint-unused-variables.rs:22:9
+ |
+LL | a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
+
+error: unused variable: `b`
+ --> $DIR/lint-unused-variables.rs:29:9
+ |
+LL | b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
+error: unused variable: `b`
+ --> $DIR/lint-unused-variables.rs:45:9
+ |
+LL | b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
+error: aborting due to 8 previous errors
+
#![no_std]
-#[allow(unused_extern_crates)]
#[macro_use(foo(bar))] //~ ERROR bad macro import
extern crate std;
error[E0466]: bad macro import
- --> $DIR/macro-use-bad-args-1.rs:4:13
+ --> $DIR/macro-use-bad-args-1.rs:3:13
|
LL | #[macro_use(foo(bar))]
| ^^^^^^^^
#![no_std]
-#[allow(unused_extern_crates)]
#[macro_use(foo="bar")] //~ ERROR bad macro import
extern crate std;
error[E0466]: bad macro import
- --> $DIR/macro-use-bad-args-2.rs:4:13
+ --> $DIR/macro-use-bad-args-2.rs:3:13
|
LL | #[macro_use(foo="bar")]
| ^^^^^^^^^
--- /dev/null
+#[derive(PartialEq, Eq)]
+pub struct Tag(pub Context, pub u16);
+
+#[derive(PartialEq, Eq)]
+pub enum Context {
+ Tiff,
+ Exif,
+}
+
+impl Tag {
+ const ExifIFDPointer: Tag = Tag(Context::Tiff, 34665);
+}
+
+fn main() {
+ match Tag::ExifIFDPointer {
+ //~^ ERROR: non-exhaustive patterns: `Tag(Exif, _)` not covered
+ Tag::ExifIFDPointer => {}
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `Tag(Exif, _)` not covered
+ --> $DIR/issue-50900.rs:15:11
+ |
+LL | pub struct Tag(pub Context, pub u16);
+ | ------------------------------------- `Tag` defined here
+...
+LL | match Tag::ExifIFDPointer {
+ | ^^^^^^^^^^^^^^^^^^^ pattern `Tag(Exif, _)` not covered
+ |
+ = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
match [0, 1, 2] {
[0] => {}, //~ ERROR pattern requires
- [0, 1, x..] => {
+ [0, 1, x @ ..] => {
let a: [_; 1] = x;
}
- [0, 1, 2, 3, x..] => {} //~ ERROR pattern requires
+ [0, 1, 2, 3, x @ ..] => {} //~ ERROR pattern requires
};
match does_not_exist { //~ ERROR cannot find value `does_not_exist` in this scope
error[E0528]: pattern requires at least 4 elements but array has 3
--> $DIR/match-vec-mismatch.rs:25:9
|
-LL | [0, 1, 2, 3, x..] => {}
- | ^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements
+LL | [0, 1, 2, 3, x @ ..] => {}
+ | ^^^^^^^^^^^^^^^^^^^^ pattern cannot match array of 3 elements
error[E0282]: type annotations needed
--> $DIR/match-vec-mismatch.rs:36:9
let x: Vec<char> = vec!['a', 'b', 'c'];
let x: &[char] = &x;
match *x {
- ['a', 'b', 'c', ref _tail..] => {}
+ ['a', 'b', 'c', ref _tail @ ..] => {}
['a', 'b', 'c'] => {} //~ ERROR unreachable pattern
_ => {}
}
--> $DIR/issue-38371.rs:4:8
|
LL | fn foo(&foo: Foo) {
- | ^^^^ expected struct `Foo`, found reference
+ | ^^^^------
+ | |
+ | expected struct `Foo`, found reference
+ | help: did you mean `foo`: `&Foo`
|
= note: expected type `Foo`
found type `&_`
- = help: did you mean `foo: &Foo`?
error[E0308]: mismatched types
--> $DIR/issue-38371.rs:18:9
#![no_std]
-#![allow(unused_extern_crates)]
extern crate core; //~ ERROR: the name `core` is defined multiple times
extern crate std;
error[E0259]: the name `core` is defined multiple times
- --> $DIR/no-std-inject.rs:4:1
+ --> $DIR/no-std-inject.rs:3:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ `core` reimported here
let vec = vec![Some(42), None, Some(21)];
let vec: &[Option<isize>] = &vec;
match *vec { //~ ERROR non-exhaustive patterns: `[]` not covered
- [Some(..), None, ref tail..] => {}
- [Some(..), Some(..), ref tail..] => {}
+ [Some(..), None, ref tail @ ..] => {}
+ [Some(..), Some(..), ref tail @ ..] => {}
[None] => {}
}
let vec = vec![1];
let vec: &[isize] = &vec;
match *vec {
- [_, ref tail..] => (),
+ [_, ref tail @ ..] => (),
[] => ()
}
let vec = vec![0.5f32];
let vec = vec![Some(42), None, Some(21)];
let vec: &[Option<isize>] = &vec;
match *vec {
- [Some(..), None, ref tail..] => {}
- [Some(..), Some(..), ref tail..] => {}
- [None, None, ref tail..] => {}
- [None, Some(..), ref tail..] => {}
+ [Some(..), None, ref tail @ ..] => {}
+ [Some(..), Some(..), ref tail @ ..] => {}
+ [None, None, ref tail @ ..] => {}
+ [None, Some(..), ref tail @ ..] => {}
[Some(_)] => {}
[None] => {}
[] => {}
[Enum::Second(true), Enum::First] => (),
[Enum::Second(true), Enum::Second(true)] => (),
[Enum::Second(false), _] => (),
- [_, _, ref tail.., _] => ()
+ [_, _, ref tail @ .., _] => ()
}
}
error: an inner attribute is not permitted in this context
- --> $DIR/attr.rs:5:3
+ --> $DIR/attr.rs:5:1
|
LL | #![lang = "foo"]
- | ^
+ | ^^^^^^^^^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
error: an inner attribute is not permitted following an outer doc comment
- --> $DIR/inner-attr-after-doc-comment.rs:6:3
+ --> $DIR/inner-attr-after-doc-comment.rs:6:1
|
-LL | #![recursion_limit="100"]
- | ^
+LL | / /**
+LL | | * My module
+LL | | */
+ | |___- previous doc comment
+LL |
+LL | #![recursion_limit="100"]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
error: an inner attribute is not permitted following an outer attribute
- --> $DIR/inner-attr.rs:3:3
+ --> $DIR/inner-attr.rs:3:1
|
+LL | #[feature(lang_items)]
+ | ---------------------- previous outer attribute
+LL |
LL | #![recursion_limit="100"]
- | ^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes, like `#[test]`, annotate the item following them.
--- /dev/null
+// ignore-tidy-trailing-newlines
+// error-pattern: aborting due to 6 previous errors
+
+fn main() {}
+
+fn p() { match s { v, E { [) {) }
+
+
--- /dev/null
+error: this file contains an un-closed delimiter
+ --> $DIR/issue-62973.rs:8:2
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | - - un-closed delimiter
+ | |
+ | un-closed delimiter
+LL |
+LL |
+ | ^
+
+error: expected one of `,` or `}`, found `{`
+ --> $DIR/issue-62973.rs:6:25
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | - ^ expected one of `,` or `}` here
+ | |
+ | while parsing this struct
+
+error: struct literals are not allowed here
+ --> $DIR/issue-62973.rs:6:16
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | ________________^
+LL | |
+LL | |
+ | |_^
+help: surround the struct literal with parentheses
+ |
+LL | fn p() { match (s { v, E { [) {) }
+LL |
+LL | )
+ |
+
+error: expected one of `.`, `?`, `{`, or an operator, found `}`
+ --> $DIR/issue-62973.rs:8:1
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | ----- while parsing this match expression
+LL |
+LL |
+ | ^ expected one of `.`, `?`, `{`, or an operator here
+
+error: incorrect close delimiter: `)`
+ --> $DIR/issue-62973.rs:6:28
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | -^ incorrect close delimiter
+ | |
+ | un-closed delimiter
+
+error: incorrect close delimiter: `)`
+ --> $DIR/issue-62973.rs:6:31
+ |
+LL | fn p() { match s { v, E { [) {) }
+ | -^ incorrect close delimiter
+ | |
+ | un-closed delimiter
+
+error: aborting due to 6 previous errors
+
fn main() {
- let a = Vec::new();
+ let a: &[u8] = &[];
match a {
- [1, tail.., tail..] => {}, //~ ERROR: expected one of `,` or `@`, found `..`
+ [1, tail @ .., tail @ ..] => {},
+ //~^ ERROR identifier `tail` is bound more than once in the same pattern
+ //~| ERROR subslice patterns are unstable
+ //~| ERROR subslice patterns are unstable
+ //~| ERROR `..` can only be used once per slice pattern
_ => ()
}
}
+
+const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
-error: expected one of `,` or `@`, found `..`
- --> $DIR/match-vec-invalid.rs:4:25
+error[E0416]: identifier `tail` is bound more than once in the same pattern
+ --> $DIR/match-vec-invalid.rs:4:24
|
-LL | [1, tail.., tail..] => {},
- | ^^ expected one of `,` or `@` here
+LL | [1, tail @ .., tail @ ..] => {},
+ | ^^^^ used in a pattern more than once
-error: aborting due to previous error
+error[E0658]: subslice patterns are unstable
+ --> $DIR/match-vec-invalid.rs:4:13
+ |
+LL | [1, tail @ .., tail @ ..] => {},
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/62254
+ = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
+
+error[E0658]: subslice patterns are unstable
+ --> $DIR/match-vec-invalid.rs:4:24
+ |
+LL | [1, tail @ .., tail @ ..] => {},
+ | ^^^^^^^^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/62254
+ = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
+
+error: `..` can only be used once per slice pattern
+ --> $DIR/match-vec-invalid.rs:4:31
+ |
+LL | [1, tail @ .., tail @ ..] => {},
+ | -- ^^ can only be used once per slice pattern
+ | |
+ | previously used here
+
+error[E0308]: mismatched types
+ --> $DIR/match-vec-invalid.rs:13:30
+ |
+LL | const RECOVERY_WITNESS: () = 0;
+ | ^ expected (), found integer
+ |
+ = note: expected type `()`
+ found type `{integer}`
+
+error: aborting due to 5 previous errors
+Some errors have detailed explanations: E0308, E0416, E0658.
+For more information about an error, try `rustc --explain E0308`.
fn main() {
+ struct Test(&'static u8, [u8; 0]);
+ let x = Test(&0, []);
+
let Test(&desc[..]) = x; //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
+ //~^ ERROR subslice patterns are unstable
}
+
+const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
error: expected one of `)`, `,`, or `@`, found `[`
- --> $DIR/pat-lt-bracket-6.rs:2:19
+ --> $DIR/pat-lt-bracket-6.rs:5:19
|
LL | let Test(&desc[..]) = x;
| ^ expected one of `)`, `,`, or `@` here
-error: aborting due to previous error
+error[E0658]: subslice patterns are unstable
+ --> $DIR/pat-lt-bracket-6.rs:5:20
+ |
+LL | let Test(&desc[..]) = x;
+ | ^^
+ |
+ = note: for more information, see https://github.com/rust-lang/rust/issues/62254
+ = help: add `#![feature(slice_patterns)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+ --> $DIR/pat-lt-bracket-6.rs:9:30
+ |
+LL | const RECOVERY_WITNESS: () = 0;
+ | ^ expected (), found integer
+ |
+ = note: expected type `()`
+ found type `{integer}`
+
+error: aborting due to 3 previous errors
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
fn main() {
- for thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
+ struct Thing(u8, [u8; 0]);
+ let foo = core::iter::empty();
+
+ for Thing(x[]) in foo {} //~ ERROR: expected one of `)`, `,`, or `@`, found `[`
}
+
+const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
error: expected one of `)`, `,`, or `@`, found `[`
- --> $DIR/pat-lt-bracket-7.rs:2:16
+ --> $DIR/pat-lt-bracket-7.rs:5:16
|
-LL | for thing(x[]) in foo {}
+LL | for Thing(x[]) in foo {}
| ^ expected one of `)`, `,`, or `@` here
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/pat-lt-bracket-7.rs:8:30
+ |
+LL | const RECOVERY_WITNESS: () = 0;
+ | ^ expected (), found integer
+ |
+ = note: expected type `()`
+ found type `{integer}`
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
+// check-pass
+
fn main() {
match (0, 1, 2) {
(pat, ..,) => {}
- //~^ ERROR trailing comma is not permitted after `..`
}
}
+++ /dev/null
-error: trailing comma is not permitted after `..`
- --> $DIR/pat-tuple-2.rs:3:17
- |
-LL | (pat, ..,) => {}
- | ^ trailing comma is not permitted after `..`
-
-error: aborting due to previous error
-
fn main() {
match (0, 1, 2) {
(.., pat, ..) => {}
- //~^ ERROR `..` can only be used once per tuple or tuple struct pattern
+ //~^ ERROR `..` can only be used once per tuple pattern
}
}
-error: `..` can only be used once per tuple or tuple struct pattern
+error: `..` can only be used once per tuple pattern
--> $DIR/pat-tuple-3.rs:3:19
|
LL | (.., pat, ..) => {}
- | -- ^^ can only be used once per pattern
+ | -- ^^ can only be used once per tuple pattern
| |
- | previously present here
+ | previously used here
error: aborting due to previous error
fn main() {
+ const PAT: u8 = 0;
+
match 0 {
- (.. pat) => {} //~ ERROR expected one of `)` or `,`, found `pat`
+ (.. PAT) => {}
+ //~^ ERROR `..X` range patterns are not supported
+ //~| ERROR exclusive range pattern syntax is experimental
}
}
+
+const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types
-error: expected one of `)` or `,`, found `pat`
- --> $DIR/pat-tuple-4.rs:3:13
+error: `..X` range patterns are not supported
+ --> $DIR/pat-tuple-4.rs:5:10
|
-LL | (.. pat) => {}
- | ^^^ expected one of `)` or `,` here
+LL | (.. PAT) => {}
+ | ^^^^^^ help: try using the minimum value for the type: `MIN..PAT`
-error: aborting due to previous error
+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:11:30
+ |
+LL | const RECOVERY_WITNESS: () = 0;
+ | ^ expected (), found integer
+ |
+ = note: expected type `()`
+ found type `{integer}`
+
+error: aborting due to 3 previous errors
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
fn main() {
+ const PAT: u8 = 0;
+
match (0, 1) {
- (pat ..) => {} //~ ERROR unexpected token: `)`
+ (PAT ..) => {}
+ //~^ ERROR `X..` range patterns are not supported
+ //~| ERROR exclusive range pattern syntax is experimental
+ //~| ERROR mismatched types
}
}
-error: unexpected token: `)`
- --> $DIR/pat-tuple-5.rs:3:16
+error: `X..` range patterns are not supported
+ --> $DIR/pat-tuple-5.rs:5:10
|
-LL | (pat ..) => {}
- | ^
+LL | (PAT ..) => {}
+ | ^^^^^^ help: try using the maximum value for the type: `PAT..MAX`
-error: aborting due to previous error
+error[E0658]: exclusive range pattern syntax is experimental
+ --> $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[E0308]: mismatched types
+ --> $DIR/pat-tuple-5.rs:5:10
+ |
+LL | match (0, 1) {
+ | ------ this match expression has type `({integer}, {integer})`
+LL | (PAT ..) => {}
+ | ^^^^^^ expected tuple, found u8
+ |
+ = note: expected type `({integer}, {integer})`
+ found type `u8`
+
+error: aborting due to 3 previous errors
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// Here we test all kinds of range patterns in terms of parsing / recovery.
+// We want to ensure that:
+// 1. Things parse as they should.
+// 2. Or at least we have parser recovery if they don't.
+
+#![feature(exclusive_range_pattern)]
+#![deny(ellipsis_inclusive_range_patterns)]
+
+fn main() {}
+
+const X: u8 = 0;
+const Y: u8 = 3;
+
+fn exclusive_from_to() {
+ if let 0..3 = 0 {} // OK.
+ if let 0..Y = 0 {} // OK.
+ if let X..3 = 0 {} // OK.
+ if let X..Y = 0 {} // OK.
+ if let true..Y = 0 {} //~ ERROR only char and numeric types
+ if let X..true = 0 {} //~ ERROR only char and numeric types
+ if let .0..Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ if let X.. .0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+}
+
+fn inclusive_from_to() {
+ if let 0..=3 = 0 {} // OK.
+ if let 0..=Y = 0 {} // OK.
+ if let X..=3 = 0 {} // OK.
+ if let X..=Y = 0 {} // OK.
+ if let true..=Y = 0 {} //~ ERROR only char and numeric types
+ if let X..=true = 0 {} //~ ERROR only char and numeric types
+ if let .0..=Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ if let X..=.0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+}
+
+fn inclusive2_from_to() {
+ if let 0...3 = 0 {} //~ ERROR `...` range patterns are deprecated
+ if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated
+ if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated
+ if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated
+ if let true...Y = 0 {} //~ ERROR only char and numeric types
+ //~^ ERROR `...` range patterns are deprecated
+ if let X...true = 0 {} //~ ERROR only char and numeric types
+ //~^ ERROR `...` range patterns are deprecated
+ if let .0...Y = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR `...` range patterns are deprecated
+ if let X... .0 = 0 {} //~ ERROR mismatched types
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR `...` range patterns are deprecated
+}
+
+fn exclusive_from() {
+ if let 0.. = 0 {} //~ ERROR `X..` range patterns are not supported
+ if let X.. = 0 {} //~ ERROR `X..` range patterns are not supported
+ if let true.. = 0 {} //~ ERROR `X..` range patterns are not supported
+ //~^ ERROR only char and numeric types
+ if let .0.. = 0 {} //~ ERROR `X..` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive_from() {
+ if let 0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+ if let X..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+ if let true..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+ //~| ERROR only char and numeric types
+ if let .0..= = 0 {} //~ ERROR `X..=` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive2_from() {
+ if let 0... = 0 {} //~ ERROR `X...` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ if let X... = 0 {} //~ ERROR `X...` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ if let true... = 0 {} //~ ERROR `X...` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ //~| ERROR only char and numeric types
+ if let .0... = 0 {} //~ ERROR `X...` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR `...` range patterns are deprecated
+ //~| ERROR mismatched types
+}
+
+fn exclusive_to() {
+ if let ..0 = 0 {} //~ ERROR `..X` range patterns are not supported
+ if let ..Y = 0 {} //~ ERROR `..X` range patterns are not supported
+ if let ..true = 0 {} //~ ERROR `..X` range patterns are not supported
+ //~| ERROR only char and numeric types
+ if let .. .0 = 0 {} //~ ERROR `..X` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive_to() {
+ if let ..=3 = 0 {} //~ ERROR `..=X` range patterns are not supported
+ if let ..=Y = 0 {} //~ ERROR `..=X` range patterns are not supported
+ if let ..=true = 0 {} //~ ERROR `..=X` range patterns are not supported
+ //~| ERROR only char and numeric types
+ if let ..=.0 = 0 {} //~ ERROR `..=X` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
+
+fn inclusive2_to() {
+ if let ...3 = 0 {} //~ ERROR `...X` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ if let ...Y = 0 {} //~ ERROR `...X` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ if let ...true = 0 {} //~ ERROR `...X` range patterns are not supported
+ //~^ ERROR `...` range patterns are deprecated
+ //~| ERROR only char and numeric types
+ if let ....3 = 0 {} //~ ERROR `...X` range patterns are not supported
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR `...` range patterns are deprecated
+ //~| ERROR mismatched types
+}
--- /dev/null
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:21:12
+ |
+LL | if let .0..Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:23:16
+ |
+LL | if let X.. .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:34:12
+ |
+LL | if let .0..=Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:36:16
+ |
+LL | if let X..=.0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:49:12
+ |
+LL | if let .0...Y = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:52:17
+ |
+LL | if let X... .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `X..` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:58:12
+ |
+LL | if let 0.. = 0 {}
+ | ^^^ help: try using the maximum value for the type: `0..MAX`
+
+error: `X..` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:59:12
+ |
+LL | if let X.. = 0 {}
+ | ^^^ help: try using the maximum value for the type: `X..MAX`
+
+error: `X..` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:60:12
+ |
+LL | if let true.. = 0 {}
+ | ^^^^^^ help: try using the maximum value for the type: `true..MAX`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:62:12
+ |
+LL | if let .0.. = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `X..` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:62:12
+ |
+LL | if let .0.. = 0 {}
+ | ^^^^ help: try using the maximum value for the type: `0.0..MAX`
+
+error: `X..=` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:68:12
+ |
+LL | if let 0..= = 0 {}
+ | ^^^^ help: try using the maximum value for the type: `0..=MAX`
+
+error: `X..=` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:69:12
+ |
+LL | if let X..= = 0 {}
+ | ^^^^ help: try using the maximum value for the type: `X..=MAX`
+
+error: `X..=` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:70:12
+ |
+LL | if let true..= = 0 {}
+ | ^^^^^^^ help: try using the maximum value for the type: `true..=MAX`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:72:12
+ |
+LL | if let .0..= = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `X..=` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:72:12
+ |
+LL | if let .0..= = 0 {}
+ | ^^^^^ help: try using the maximum value for the type: `0.0..=MAX`
+
+error: `X...` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:78:12
+ |
+LL | if let 0... = 0 {}
+ | ^^^^ help: try using the maximum value for the type: `0...MAX`
+
+error: `X...` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:80:12
+ |
+LL | if let X... = 0 {}
+ | ^^^^ help: try using the maximum value for the type: `X...MAX`
+
+error: `X...` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:82:12
+ |
+LL | if let true... = 0 {}
+ | ^^^^^^^ help: try using the maximum value for the type: `true...MAX`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:85:12
+ |
+LL | if let .0... = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `X...` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:85:12
+ |
+LL | if let .0... = 0 {}
+ | ^^^^^ help: try using the maximum value for the type: `0.0...MAX`
+
+error: `..X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:92:12
+ |
+LL | if let ..0 = 0 {}
+ | ^^^ help: try using the minimum value for the type: `MIN..0`
+
+error: `..X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:93:12
+ |
+LL | if let ..Y = 0 {}
+ | ^^^ help: try using the minimum value for the type: `MIN..Y`
+
+error: `..X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:94:12
+ |
+LL | if let ..true = 0 {}
+ | ^^^^^^ help: try using the minimum value for the type: `MIN..true`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:96:15
+ |
+LL | if let .. .0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `..X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:96:12
+ |
+LL | if let .. .0 = 0 {}
+ | ^^^^^ help: try using the minimum value for the type: `MIN..0.0`
+
+error: `..=X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:102:12
+ |
+LL | if let ..=3 = 0 {}
+ | ^^^^ help: try using the minimum value for the type: `MIN..=3`
+
+error: `..=X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:103:12
+ |
+LL | if let ..=Y = 0 {}
+ | ^^^^ help: try using the minimum value for the type: `MIN..=Y`
+
+error: `..=X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:104:12
+ |
+LL | if let ..=true = 0 {}
+ | ^^^^^^^ help: try using the minimum value for the type: `MIN..=true`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:106:15
+ |
+LL | if let ..=.0 = 0 {}
+ | ^^ help: must have an integer part: `0.0`
+
+error: `..=X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:106:12
+ |
+LL | if let ..=.0 = 0 {}
+ | ^^^^^ help: try using the minimum value for the type: `MIN..=0.0`
+
+error: `...X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:112:12
+ |
+LL | if let ...3 = 0 {}
+ | ^^^^ help: try using the minimum value for the type: `MIN...3`
+
+error: `...X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:114:12
+ |
+LL | if let ...Y = 0 {}
+ | ^^^^ help: try using the minimum value for the type: `MIN...Y`
+
+error: `...X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:116:12
+ |
+LL | if let ...true = 0 {}
+ | ^^^^^^^ help: try using the minimum value for the type: `MIN...true`
+
+error: float literals must have an integer part
+ --> $DIR/recover-range-pats.rs:119:15
+ |
+LL | if let ....3 = 0 {}
+ | ^^ help: must have an integer part: `0.3`
+
+error: `...X` range patterns are not supported
+ --> $DIR/recover-range-pats.rs:119:12
+ |
+LL | if let ....3 = 0 {}
+ | ^^^^^ help: try using the minimum value for the type: `MIN...0.3`
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:41:13
+ |
+LL | if let 0...3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+ |
+note: lint level defined here
+ --> $DIR/recover-range-pats.rs:7:9
+ |
+LL | #![deny(ellipsis_inclusive_range_patterns)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:42:13
+ |
+LL | if let 0...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:43:13
+ |
+LL | if let X...3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:44:13
+ |
+LL | if let X...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:45:16
+ |
+LL | if let true...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:47:13
+ |
+LL | if let X...true = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:49:14
+ |
+LL | if let .0...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:52:13
+ |
+LL | if let X... .0 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:78:13
+ |
+LL | if let 0... = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:80:13
+ |
+LL | if let X... = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:82:16
+ |
+LL | if let true... = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:85:14
+ |
+LL | if let .0... = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:112:12
+ |
+LL | if let ...3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:114:12
+ |
+LL | if let ...Y = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:116:12
+ |
+LL | if let ...true = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error: `...` range patterns are deprecated
+ --> $DIR/recover-range-pats.rs:119:12
+ |
+LL | if let ....3 = 0 {}
+ | ^^^ help: use `..=` for an inclusive range
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:19:12
+ |
+LL | if let true..Y = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: u8
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:20:15
+ |
+LL | if let X..true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: u8
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:21:12
+ |
+LL | if let .0..Y = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:23:12
+ |
+LL | if let X.. .0 = 0 {}
+ | ^^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:32:12
+ |
+LL | if let true..=Y = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: u8
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:33:16
+ |
+LL | if let X..=true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: u8
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:34:12
+ |
+LL | if let .0..=Y = 0 {}
+ | ^^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:36:12
+ |
+LL | if let X..=.0 = 0 {}
+ | ^^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:45:12
+ |
+LL | if let true...Y = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: u8
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:47:16
+ |
+LL | if let X...true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: u8
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:49:12
+ |
+LL | if let .0...Y = 0 {}
+ | ^^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:52:12
+ |
+LL | if let X... .0 = 0 {}
+ | ^^^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `u8`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:60:12
+ |
+LL | if let true.. = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: [type error]
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:62:12
+ |
+LL | if let .0.. = 0 {}
+ | ^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:70:12
+ |
+LL | if let true..= = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: [type error]
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:72:12
+ |
+LL | if let .0..= = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:82:12
+ |
+LL | if let true... = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: bool
+ = note: end type: [type error]
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:85:12
+ |
+LL | if let .0... = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:94:14
+ |
+LL | if let ..true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: [type error]
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:96:12
+ |
+LL | if let .. .0 = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:104:15
+ |
+LL | if let ..=true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: [type error]
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:106:12
+ |
+LL | if let ..=.0 = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error[E0029]: only char and numeric types are allowed in range patterns
+ --> $DIR/recover-range-pats.rs:116:15
+ |
+LL | if let ...true = 0 {}
+ | ^^^^ ranges require char or numeric types
+ |
+ = note: start type: [type error]
+ = note: end type: bool
+
+error[E0308]: mismatched types
+ --> $DIR/recover-range-pats.rs:119:12
+ |
+LL | if let ....3 = 0 {}
+ | ^^^^^ expected integer, found floating-point number
+ |
+ = note: expected type `{integer}`
+ found type `{float}`
+
+error: aborting due to 76 previous errors
+
+Some errors have detailed explanations: E0029, E0308.
+For more information about an error, try `rustc --explain E0029`.
+// NOTE: This doesn't recover anymore.
+
fn main() {
let x = (1, 2, 3, 4);
match x {
(1, .., 4) => {}
(1, .=., 4) => { let _: usize = ""; }
//~^ ERROR expected pattern, found `.`
- //~| ERROR mismatched types
(.=., 4) => {}
- //~^ ERROR expected pattern, found `.`
(1, 2, 3, 4) => {}
}
}
error: expected pattern, found `.`
- --> $DIR/recover-tuple-pat.rs:5:13
+ --> $DIR/recover-tuple-pat.rs:7:13
|
LL | (1, .=., 4) => { let _: usize = ""; }
| ^ expected pattern
-error: expected pattern, found `.`
- --> $DIR/recover-tuple-pat.rs:8:10
- |
-LL | (.=., 4) => {}
- | ^ expected pattern
-
-error[E0308]: mismatched types
- --> $DIR/recover-tuple-pat.rs:5:41
- |
-LL | (1, .=., 4) => { let _: usize = ""; }
- | ^^ expected usize, found reference
- |
- = note: expected type `usize`
- found type `&'static str`
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
-#[allow(unused_extern_crates)]
extern crate std;
//~^ ERROR the name `std` is defined multiple times
error[E0259]: the name `std` is defined multiple times
- --> $DIR/resolve-conflict-extern-crate-vs-extern-crate.rs:2:1
- |
-LL | extern crate std;
- | ^^^^^^^^^^^^^^^^^ `std` reimported here
|
= note: `std` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
-#![allow(unused_extern_crates)]
-
mod a {
extern crate alloc;
use alloc::HashMap;
error[E0432]: unresolved import `alloc`
- --> $DIR/resolve_self_super_hint.rs:5:9
+ --> $DIR/resolve_self_super_hint.rs:3:9
|
LL | use alloc::HashMap;
| ^^^^^ help: a similar path exists: `self::alloc`
error[E0432]: unresolved import `alloc`
- --> $DIR/resolve_self_super_hint.rs:10:13
+ --> $DIR/resolve_self_super_hint.rs:8:13
|
LL | use alloc::HashMap;
| ^^^^^ help: a similar path exists: `super::alloc`
error[E0432]: unresolved import `alloc`
- --> $DIR/resolve_self_super_hint.rs:15:17
+ --> $DIR/resolve_self_super_hint.rs:13:17
|
LL | use alloc::HashMap;
| ^^^^^
| help: a similar path exists: `a::alloc`
error[E0432]: unresolved import `alloc`
- --> $DIR/resolve_self_super_hint.rs:20:21
+ --> $DIR/resolve_self_super_hint.rs:18:21
|
LL | use alloc::HashMap;
| ^^^^^
let sl: &[u8] = b"foo";
match sl { //~ ERROR non-exhaustive patterns
- [first, remainder..] => {},
+ [first, remainder @ ..] => {},
};
}
+// check-pass
// compile-flags: --cfg something
-// build-pass (FIXME(62277): could be check-pass?)
+#![deny(unused_mut)]
#![feature(param_attrs)]
extern "C" {
fn ffi(
- #[allow(C)] a: i32,
+ #[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
- #[deny(C)] d: i32,
- #[forbid(C)] #[warn(C)] ...
+ #[deny(unused_mut)] d: i32,
+ #[forbid(unused_mut)] #[warn(unused_mut)] ...
);
}
type FnType = fn(
- #[allow(C)] a: i32,
+ #[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
- #[deny(C)] d: i32,
- #[forbid(C)] #[warn(C)] e: i32
+ #[deny(unused_mut)] d: i32,
+ #[forbid(unused_mut)] #[warn(unused_mut)] e: i32
);
pub fn foo(
- #[allow(C)] a: i32,
+ #[allow(unused_mut)] a: i32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))] c: i32,
- #[deny(C)] d: i32,
- #[forbid(C)] #[warn(C)] e: i32
+ #[deny(unused_mut)] d: i32,
+ #[forbid(unused_mut)] #[warn(unused_mut)] _e: i32
) {}
-// self, &self and &mut self
+// self
struct SelfStruct {}
impl SelfStruct {
fn foo(
- #[allow(C)] self,
+ #[allow(unused_mut)] self,
#[cfg(something)] a: i32,
#[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
+ #[deny(unused_mut)] b: i32,
) {}
}
struct RefStruct {}
impl RefStruct {
fn foo(
- #[allow(C)] &self,
+ #[allow(unused_mut)] &self,
#[cfg(something)] a: i32,
#[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
+ #[deny(unused_mut)] b: i32,
) {}
}
trait RefTrait {
fn foo(
- #[forbid(C)] &self,
- #[warn(C)] a: i32
+ #[forbid(unused_mut)] &self,
+ #[warn(unused_mut)] a: i32
) {}
}
impl RefTrait for RefStruct {
fn foo(
- #[forbid(C)] &self,
- #[warn(C)] a: i32
- ) {}
-}
-
-struct MutStruct {}
-impl MutStruct {
- fn foo(
- #[allow(C)] &mut self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-trait MutTrait {
- fn foo(
- #[forbid(C)] &mut self,
- #[warn(C)] a: i32
- ) {}
-}
-impl MutTrait for MutStruct {
- fn foo(
- #[forbid(C)] &mut self,
- #[warn(C)] a: i32
- ) {}
-}
-
-// self: Self, self: &Self and self: &mut Self
-
-struct NamedSelfSelfStruct {}
-impl NamedSelfSelfStruct {
- fn foo(
- #[allow(C)] self: Self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-
-struct NamedSelfRefStruct {}
-impl NamedSelfRefStruct {
- fn foo(
- #[allow(C)] self: &Self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-trait NamedSelfRefTrait {
- fn foo(
- #[forbid(C)] self: &Self,
- #[warn(C)] a: i32
- ) {}
-}
-impl NamedSelfRefTrait for NamedSelfRefStruct {
- fn foo(
- #[forbid(C)] self: &Self,
- #[warn(C)] a: i32
- ) {}
-}
-
-struct NamedSelfMutStruct {}
-impl NamedSelfMutStruct {
- fn foo(
- #[allow(C)] self: &mut Self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-trait NamedSelfMutTrait {
- fn foo(
- #[forbid(C)] self: &mut Self,
- #[warn(C)] a: i32
- ) {}
-}
-impl NamedSelfMutTrait for NamedSelfMutStruct {
- fn foo(
- #[forbid(C)] self: &mut Self,
- #[warn(C)] a: i32
- ) {}
-}
-
-// &'a self and &'a mut self
-
-struct NamedLifetimeRefStruct {}
-impl NamedLifetimeRefStruct {
- fn foo<'a>(
- #[allow(C)] self: &'a Self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-trait NamedLifetimeRefTrait {
- fn foo<'a>(
- #[forbid(C)] &'a self,
- #[warn(C)] a: i32
- ) {}
-}
-impl NamedLifetimeRefTrait for NamedLifetimeRefStruct {
- fn foo<'a>(
- #[forbid(C)] &'a self,
- #[warn(C)] a: i32
- ) {}
-}
-
-struct NamedLifetimeMutStruct {}
-impl NamedLifetimeMutStruct {
- fn foo<'a>(
- #[allow(C)] self: &'a mut Self,
- #[cfg(something)] a: i32,
- #[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
- ) {}
-}
-trait NamedLifetimeMutTrait {
- fn foo<'a>(
- #[forbid(C)] &'a mut self,
- #[warn(C)] a: i32
- ) {}
-}
-impl NamedLifetimeMutTrait for NamedLifetimeMutStruct {
- fn foo<'a>(
- #[forbid(C)] &'a mut self,
- #[warn(C)] a: i32
+ #[forbid(unused_mut)] &self,
+ #[warn(unused_mut)] a: i32
) {}
}
struct BoxSelfStruct {}
impl BoxSelfStruct {
fn foo(
- #[allow(C)] self: Box<Self>,
+ #[allow(unused_mut)] self: Box<Self>,
#[cfg(something)] a: i32,
#[cfg_attr(something, cfg(nothing))]
- #[deny(C)] b: i32,
+ #[deny(unused_mut)] b: i32,
) {}
}
trait BoxSelfTrait {
fn foo(
- #[forbid(C)] self: Box<Self>,
- #[warn(C)] a: i32
+ #[forbid(unused_mut)] self: Box<Self>,
+ #[warn(unused_mut)] a: i32
) {}
}
impl BoxSelfTrait for BoxSelfStruct {
fn foo(
- #[forbid(C)] self: Box<Self>,
- #[warn(C)] a: i32
+ #[forbid(unused_mut)] self: Box<Self>,
+ #[warn(unused_mut)] a: i32
) {}
}
let _: fn(_, _, _, _) = foo;
let _: FnType = |_, _, _, _| {};
let c = |
- #[allow(C)] a: u32,
+ #[allow(unused_mut)] a: u32,
#[cfg(something)] b: i32,
#[cfg_attr(something, cfg(nothing))]
- #[deny(C)] c: i32,
+ #[deny(unused_mut)] c: i32,
| {};
let _ = c(1, 2);
}
// compile-flags: --cfg something
+// edition:2018
-#![feature(param_attrs)]
+#![feature(async_await, async_closure, param_attrs)]
#![deny(unused_variables)]
extern "C" {
#[cfg_attr(something, cfg(nothing))] d: i32,
);
+async fn foo_async(
+ #[cfg(something)] a: i32,
+ //~^ ERROR unused variable: `a`
+ #[cfg(nothing)] b: i32,
+) {}
fn foo(
#[cfg(nothing)] a: i32,
#[cfg(something)] b: i32,
- //~^ ERROR unused variable: `b` [unused_variables]
+ //~^ ERROR unused variable: `b`
#[cfg_attr(nothing, cfg(nothing))] c: i32,
- //~^ ERROR unused variable: `c` [unused_variables]
+ //~^ ERROR unused variable: `c`
#[cfg_attr(something, cfg(nothing))] d: i32,
) {}
struct RefStruct {}
impl RefStruct {
+ async fn bar_async(
+ &self,
+ #[cfg(something)] a: i32,
+ //~^ ERROR unused variable: `a`
+ #[cfg(nothing)] b: i32,
+ ) {}
fn bar(
&self,
#[cfg(nothing)] a: i32,
#[cfg(something)] b: i32,
- //~^ ERROR unused variable: `b` [unused_variables]
+ //~^ ERROR unused variable: `b`
#[cfg_attr(nothing, cfg(nothing))] c: i32,
- //~^ ERROR unused variable: `c` [unused_variables]
+ //~^ ERROR unused variable: `c`
#[cfg_attr(something, cfg(nothing))] d: i32,
) {}
}
&self,
#[cfg(nothing)] a: i32,
#[cfg(something)] b: i32,
- //~^ ERROR unused variable: `b` [unused_variables]
+ //~^ ERROR unused variable: `b`
#[cfg_attr(nothing, cfg(nothing))] c: i32,
- //~^ ERROR unused variable: `c` [unused_variables]
+ //~^ ERROR unused variable: `c`
#[cfg_attr(something, cfg(nothing))] d: i32,
) {}
}
&self,
#[cfg(nothing)] a: i32,
#[cfg(something)] b: i32,
- //~^ ERROR unused variable: `b` [unused_variables]
+ //~^ ERROR unused variable: `b`
#[cfg_attr(nothing, cfg(nothing))] c: i32,
- //~^ ERROR unused variable: `c` [unused_variables]
+ //~^ ERROR unused variable: `c`
#[cfg_attr(something, cfg(nothing))] d: i32,
) {}
}
let _: unsafe extern "C" fn(_, ...) = ffi;
let _: fn(_, _) = foo;
let _: FnType = |_, _| {};
+ let a = async move |
+ #[cfg(something)] a: i32,
+ //~^ ERROR unused variable: `a`
+ #[cfg(nothing)] b: i32,
+ | {};
let c = |
#[cfg(nothing)] a: i32,
#[cfg(something)] b: i32,
- //~^ ERROR unused variable: `b` [unused_variables]
+ //~^ ERROR unused variable: `b`
#[cfg_attr(nothing, cfg(nothing))] c: i32,
- //~^ ERROR unused variable: `c` [unused_variables]
+ //~^ ERROR unused variable: `c`
#[cfg_attr(something, cfg(nothing))] d: i32,
| {};
+ let _ = a(1);
let _ = c(1, 2);
}
-error: unused variable: `b`
+error: unused variable: `a`
--> $DIR/param-attrs-cfg.rs:24:23
|
-LL | #[cfg(something)] b: i32,
- | ^ help: consider prefixing with an underscore: `_b`
+LL | #[cfg(something)] a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
|
note: lint level defined here
- --> $DIR/param-attrs-cfg.rs:4:9
+ --> $DIR/param-attrs-cfg.rs:5:9
|
LL | #![deny(unused_variables)]
| ^^^^^^^^^^^^^^^^
+error: unused variable: `b`
+ --> $DIR/param-attrs-cfg.rs:30:23
+ |
+LL | #[cfg(something)] b: i32,
+ | ^ help: consider prefixing with an underscore: `_b`
+
error: unused variable: `c`
- --> $DIR/param-attrs-cfg.rs:26:40
+ --> $DIR/param-attrs-cfg.rs:32:40
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
+error: unused variable: `a`
+ --> $DIR/param-attrs-cfg.rs:83:27
+ |
+LL | #[cfg(something)] a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
+
error: unused variable: `b`
- --> $DIR/param-attrs-cfg.rs:72:27
+ --> $DIR/param-attrs-cfg.rs:89:27
|
LL | #[cfg(something)] b: i32,
| ^ help: consider prefixing with an underscore: `_b`
error: unused variable: `c`
- --> $DIR/param-attrs-cfg.rs:74:44
+ --> $DIR/param-attrs-cfg.rs:91:44
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
error: unused variable: `b`
- --> $DIR/param-attrs-cfg.rs:47:27
+ --> $DIR/param-attrs-cfg.rs:59:27
|
LL | #[cfg(something)] b: i32,
| ^ help: consider prefixing with an underscore: `_b`
error: unused variable: `c`
- --> $DIR/param-attrs-cfg.rs:49:44
+ --> $DIR/param-attrs-cfg.rs:61:44
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
+error: unused variable: `a`
+ --> $DIR/param-attrs-cfg.rs:41:27
+ |
+LL | #[cfg(something)] a: i32,
+ | ^ help: consider prefixing with an underscore: `_a`
+
error: unused variable: `b`
- --> $DIR/param-attrs-cfg.rs:36:27
+ --> $DIR/param-attrs-cfg.rs:48:27
|
LL | #[cfg(something)] b: i32,
| ^ help: consider prefixing with an underscore: `_b`
error: unused variable: `c`
- --> $DIR/param-attrs-cfg.rs:38:44
+ --> $DIR/param-attrs-cfg.rs:50:44
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
error: unused variable: `b`
- --> $DIR/param-attrs-cfg.rs:58:27
+ --> $DIR/param-attrs-cfg.rs:70:27
|
LL | #[cfg(something)] b: i32,
| ^ help: consider prefixing with an underscore: `_b`
error: unused variable: `c`
- --> $DIR/param-attrs-cfg.rs:60:44
+ --> $DIR/param-attrs-cfg.rs:72:44
|
LL | #[cfg_attr(nothing, cfg(nothing))] c: i32,
| ^ help: consider prefixing with an underscore: `_c`
-error: aborting due to 10 previous errors
+error: aborting due to 13 previous errors
// gate-test-param_attrs
+#![deny(unused_variables)]
+
fn foo(
/// Foo
//~^ ERROR documentation comments cannot be applied to function parameters
//~| NOTE doc comments are not allowed here
//~| ERROR attributes on function parameters are unstable
//~| NOTE https://github.com/rust-lang/rust/issues/60406
- #[allow(C)] a: u8
+ #[allow(unused_variables)] a: u8
//~^ ERROR attributes on function parameters are unstable
//~| NOTE https://github.com/rust-lang/rust/issues/60406
) {}
error: documentation comments cannot be applied to function parameters
- --> $DIR/param-attrs-feature-gate.rs:4:5
+ --> $DIR/param-attrs-feature-gate.rs:6:5
|
LL | /// Foo
| ^^^^^^^ doc comments are not allowed here
error[E0658]: attributes on function parameters are unstable
- --> $DIR/param-attrs-feature-gate.rs:4:5
+ --> $DIR/param-attrs-feature-gate.rs:6:5
|
LL | /// Foo
| ^^^^^^^
= help: add `#![feature(param_attrs)]` to the crate attributes to enable
error[E0658]: attributes on function parameters are unstable
- --> $DIR/param-attrs-feature-gate.rs:9:5
+ --> $DIR/param-attrs-feature-gate.rs:11:5
|
-LL | #[allow(C)] a: u8
- | ^^^^^^^^^^^
+LL | #[allow(unused_variables)] a: u8
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: for more information, see https://github.com/rust-lang/rust/issues/60406
= help: add `#![feature(param_attrs)]` to the crate attributes to enable
let sl: &[u8] = b"foo";
match sl {
- [first, remainder..] => {
+ [first, remainder @ ..] => {
let _: &u8 = first;
assert_eq!(first, &b'f');
assert_eq!(remainder, b"oo");
--- /dev/null
+// check-pass
+
+use std::pin::Pin;
+use std::task::{Context, Poll};
+
+struct Foo;
+
+impl Foo {
+ fn pin_ref(self: Pin<&Self>) -> Pin<&Self> { self }
+
+ fn pin_mut(self: Pin<&mut Self>) -> Pin<&mut Self> { self }
+
+ fn pin_pin_pin_ref(self: Pin<Pin<Pin<&Self>>>) -> Pin<Pin<Pin<&Self>>> { self }
+
+ fn pin_ref_impl_trait(self: Pin<&Self>) -> impl Clone + '_ { self }
+
+ fn b(self: Pin<&Foo>, f: &Foo) -> Pin<&Foo> { self }
+}
+
+type Alias<T> = Pin<T>;
+impl Foo {
+ fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> Alias<&Self> { self }
+}
+
+struct Bar<T: Unpin, U: Unpin> {
+ field1: T,
+ field2: U,
+}
+
+impl<T: Unpin, U: Unpin> Bar<T, U> {
+ fn fields(self: Pin<&mut Self>) -> (Pin<&mut T>, Pin<&mut U>) {
+ let this = self.get_mut();
+ (Pin::new(&mut this.field1), Pin::new(&mut this.field2))
+ }
+}
+
+trait AsyncBufRead {
+ fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+ -> Poll<std::io::Result<&[u8]>>;
+}
+
+struct Baz(Vec<u8>);
+
+impl AsyncBufRead for Baz {
+ fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>)
+ -> Poll<std::io::Result<&[u8]>>
+ {
+ Poll::Ready(Ok(&self.get_mut().0))
+ }
+}
+
+fn main() {
+ let mut foo = Foo;
+ { Pin::new(&foo).pin_ref() };
+ { Pin::new(&mut foo).pin_mut() };
+ { Pin::new(Pin::new(Pin::new(&foo))).pin_pin_pin_ref() };
+ { Pin::new(&foo).pin_ref_impl_trait() };
+ let mut bar = Bar { field1: 0u8, field2: 1u8 };
+ { Pin::new(&mut bar).fields() };
+}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:31
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone { self }
+ | - ^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
+ | |
+ | let's call the lifetime of this reference `'1`
+help: to allow this `impl Trait` to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+ fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+}
+
+fn main() {
+ { Pin::new(&Foo).f() };
+}
--- /dev/null
+error: cannot infer an appropriate lifetime
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:44
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone { self }
+ | ---------- ^^^^ ...but this borrow...
+ | |
+ | this return type evaluates to the `'static` lifetime...
+ |
+note: ...can't outlive the anonymous lifetime #1 defined on the method body at 8:5
+ --> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:8:5
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone { self }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: you can add a constraint to the return type to make it last less than `'static` and match the anonymous lifetime #1 defined on the method body at 8:5
+ |
+LL | fn f(self: Pin<&Self>) -> impl Clone + '_ { self }
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46
+ |
+LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | - - ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:69
+ |
+LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | - - ^^^^^^^^^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+ |
+LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+ | |
+ | lifetime `'a` defined here
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// compile-fail
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+ fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f } //~ ERROR E0623
+
+ fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) } //~ ERROR E0623
+}
+
+type Alias<T> = Pin<T>;
+impl Foo {
+ fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } //~ ERROR E0623
+}
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:8:46
+ |
+LL | fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
+ | ---- ---- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:10:76
+ |
+LL | fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
+ | ---- ----------------- ^ ...but data from `f` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error[E0623]: lifetime mismatch
+ --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+ |
+LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
+ | ------ --- ^^^ ...but data from `arg` is returned here
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+Test cases intended to document behavior and try to exhaustively
+explore the combinations.
+
+## Confidence
+
+These tests are not yet considered 100% normative, in that some
+aspects of the current behavior are not desirable. This is expressed
+in the "confidence" field in the following table. Values:
+
+| Confidence | Interpretation |
+| --- | --- |
+| 100% | this will remain recommended behavior |
+| 75% | unclear whether we will continue to accept this |
+| 50% | this will likely be deprecated but remain valid |
+| 25% | this could change in the future |
+| 0% | this is definitely bogus and will likely change in the future in *some* way |
+
+## Tests
+
+| Test file | `Self` type | Pattern | Current elision behavior | Confidence |
+| --- | --- | --- | --- | --- |
+| `self.rs` | `Struct` | `Self` | ignore `self` parameter | 100% |
+| `struct.rs` | `Struct` | `Struct` | ignore `self` parameter | 100% |
+| `alias.rs` | `Struct` | `Alias` | ignore `self` parameter | 100% |
+| `ref-self.rs` | `Struct` | `&Self` | take lifetime from `&Self` | 100% |
+| `ref-mut-self.rs` | `Struct` | `&mut Self` | take lifetime from `&mut Self` | 100% |
+| `ref-struct.rs` | `Struct` | `&Struct` | take lifetime from `&Self` | 50% |
+| `ref-mut-struct.rs` | `Struct` | `&mut Struct` | take lifetime from `&mut Self` | 50% |
+| `ref-alias.rs` | `Struct` | `&Alias` | ignore `Alias` | 0% |
+| `ref-mut-alias.rs` | `Struct` | `&mut Alias` | ignore `Alias` | 0% |
+| `lt-self.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 25% |
+| `lt-struct.rs` | `Struct<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% |
+| `lt-alias.rs` | `Alias<'a>` | `Self` | ignore `Self` (and hence `'a`) | 0% |
+| `lt-ref-self.rs` | `Struct<'a>` | `&Self` | take lifetime from `&Self` | 75% |
+
+In each case, we test the following patterns:
+
+- `self: XXX`
+- `self: Box<XXX>`
+- `self: Pin<XXX>`
+- `self: Box<Box<XXX>>`
+- `self: Box<Pin<XXX>>`
+
+In the non-reference cases, `Pin` causes errors so we substitute `Rc`.
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+ // Test using an alias for `Struct`:
+
+ fn alias(self: Alias, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_Alias(self: Box<Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn rc_Alias(self: Rc<Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_Alias(self: Box<Box<Alias>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_rc_Alias(self: Box<Rc<Alias>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+trait Trait {
+ type AssocType;
+}
+
+struct Struct { }
+
+impl Trait for Struct {
+ type AssocType = Self;
+}
+
+impl Struct {
+ fn assoc(self: <Struct as Trait>::AssocType, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_AssocType(self: Box<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn rc_AssocType(self: Rc<<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_AssocType(self: Box<Box<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_rc_AssocType(self: Box<Rc<<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct<'a> { x: &'a u32 }
+
+type Alias<'a> = Struct<'a>;
+
+impl<'a> Alias<'a> {
+ fn take_self(self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Alias(self: Alias<'a>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Alias(self: Box<Alias<'a>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Box_Alias(self: Box<Box<Alias<'a>>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Rc_Alias(self: Rc<Alias<'a>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Rc_Alias(self: Box<Rc<Alias<'a>>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+trait Trait {
+ type AssocType;
+}
+
+struct Struct<'a> { x: &'a u32 }
+
+impl<'a> Trait for Struct<'a> {
+ type AssocType = Self;
+}
+
+impl<'a> Struct<'a> {
+ fn take_self(self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_AssocType(self: <Struct<'a> as Trait>::AssocType, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_AssocType(self: Box<<Struct<'a> as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Box_AssocType(self: Box<Box<<Struct<'a> as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Rc_AssocType(self: Rc<<Struct<'a> as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Rc_AssocType(self: Box<Rc<<Struct<'a> as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:12:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:18:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:22:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:26:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:30:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/lt-ref-self.rs:34:9
+ |
+LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct<'a> { data: &'a u32 }
+
+impl<'a> Struct<'a> {
+ // Test using `&self` sugar:
+
+ fn ref_self(&self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ // Test using `&Self` explicitly:
+
+ fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:12:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:18:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:22:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:26:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:30:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/lt-ref-self.rs:34:9
+ |
+LL | fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+use std::rc::Rc;
+
+struct Struct<'a> {
+ x: &'a u32
+}
+
+impl<'a> Struct<'a> {
+ fn take_self(self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Self(self: Self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Self(self: Box<Self>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Box_Self(self: Box<Box<Self>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Rc_Self(self: Rc<Self>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Rc_Self(self: Box<Rc<Self>>, f: &u32) -> &u32 {
+ f
+ }
+
+ // N/A
+ //fn take_Pin_Self(self: Pin<Self>, f: &u32) -> &u32 {
+ // f
+ //}
+
+ // N/A
+ //fn take_Box_Pin_Self(self: Box<Pin<Self>>, f: &u32) -> &u32 {
+ // f
+ //}
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct<'a> { x: &'a u32 }
+
+impl<'a> Struct<'a> {
+ fn take_self(self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Struct(self: Struct<'a>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Struct(self: Box<Struct<'a>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Box_Struct(self: Box<Box<Struct<'a>>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Rc_Struct(self: Rc<Struct<'a>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Rc_Struct(self: Box<Rc<Struct<'a>>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct { }
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+ type Target = T;
+ fn deref(&self) -> &T { &self.0 }
+}
+
+impl Struct {
+ // Test using multiple `&Self`:
+
+ fn wrap_ref_Self_ref_Self(self: Wrap<&Self, &Self>, f: &u8) -> &u8 {
+ f
+ }
+
+ fn box_wrap_ref_Self_ref_Self(self: Box<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn pin_wrap_ref_Self_ref_Self(self: Pin<Wrap<&Self, &Self>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_wrap_ref_Self_ref_Self(self: Box<Box<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_pin_wrap_ref_Self_ref_Self(self: Box<Pin<Wrap<&Self, &Self>>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+ // Test using an alias for `Struct`:
+ //
+ // FIXME. We currently fail to recognize this as the self type, which
+ // feels like a bug.
+
+ fn ref_Alias(self: &Alias, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_ref_Alias(self: Box<&Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn pin_ref_Alias(self: Pin<&Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_ref_Alias(self: Box<Box<&Alias>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_pin_ref_Alias(self: Box<Pin<&Alias>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+trait Trait {
+ type AssocType;
+}
+
+struct Struct { }
+
+impl Trait for Struct {
+ type AssocType = Self;
+}
+
+impl Struct {
+ fn ref_AssocType(self: &<Struct as Trait>::AssocType, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_ref_AssocType(self: Box<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn pin_ref_AssocType(self: Pin<&<Struct as Trait>::AssocType>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_ref_AssocType(self: Box<Box<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_pin_ref_AssocType(self: Box<Pin<&<Struct as Trait>::AssocType>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+type Alias = Struct;
+
+impl Struct {
+ // Test using an alias for `Struct`:
+
+ fn ref_Alias(self: &mut Alias, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_ref_Alias(self: Box<&mut Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn pin_ref_Alias(self: Pin<&mut Alias>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_ref_Alias(self: Box<Box<&mut Alias>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_pin_ref_Alias(self: Box<Pin<&mut Alias>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:12:9
+ |
+LL | fn ref_self(&mut self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:18:9
+ |
+LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:22:9
+ |
+LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:26:9
+ |
+LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:30:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-self.rs:34:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+ // Test using `&mut self` sugar:
+
+ fn ref_self(&mut self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ // Test using `&mut Self` explicitly:
+
+ fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:12:9
+ |
+LL | fn ref_self(&mut self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:18:9
+ |
+LL | fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:22:9
+ |
+LL | fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:26:9
+ |
+LL | fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:30:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-self.rs:34:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-struct.rs:12:9
+ |
+LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-struct.rs:16:9
+ |
+LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-struct.rs:20:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-struct.rs:24:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-mut-struct.rs:28:9
+ |
+LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+ // Test using `&mut Struct` explicitly:
+
+ fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:12:9
+ |
+LL | fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:16:9
+ |
+LL | fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:20:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:24:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-mut-struct.rs:28:9
+ |
+LL | fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:21:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:27:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:31:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:39:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:43:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-self.rs:47:9
+ |
+LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct { }
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+ type Target = T;
+ fn deref(&self) -> &T { &self.0 }
+}
+
+impl Struct {
+ // Test using `&self` sugar:
+
+ fn ref_self(&self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ // Test using `&Self` explicitly:
+
+ fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ f //~ ERROR lifetime mismatch
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:21:9
+ |
+LL | fn ref_self(&self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:27:9
+ |
+LL | fn ref_Self(self: &Self, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:31:9
+ |
+LL | fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:35:9
+ |
+LL | fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:39:9
+ |
+LL | fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:43:9
+ |
+LL | fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-self.rs:47:9
+ |
+LL | fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
+ | --- ---
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/ref-struct.rs:12:9
+ |
+LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-struct.rs:16:9
+ |
+LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-struct.rs:20:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-struct.rs:24:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: lifetime may not live long enough
+ --> $DIR/ref-struct.rs:28:9
+ |
+LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | - - let's call the lifetime of this reference `'1`
+ | |
+ | let's call the lifetime of this reference `'2`
+LL | f
+ | ^ function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::pin::Pin;
+
+struct Struct { }
+
+impl Struct {
+ // Test using `&Struct` explicitly:
+
+ fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+
+ fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ f //~ ERROR lifetime mismatch
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:12:9
+ |
+LL | fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:16:9
+ |
+LL | fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:20:9
+ |
+LL | fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:24:9
+ |
+LL | fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error[E0623]: lifetime mismatch
+ --> $DIR/ref-struct.rs:28:9
+ |
+LL | fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
+ | ---- ----
+ | |
+ | this parameter and the return type are declared with different lifetimes...
+LL | f
+ | ^ ...but data from `f` is returned here
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+impl Struct {
+ fn take_self(self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Self(self: Self, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Self(self: Box<Self>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Box_Self(self: Box<Box<Self>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Rc_Self(self: Rc<Self>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn take_Box_Rc_Self(self: Box<Rc<Self>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case)]
+
+use std::rc::Rc;
+
+struct Struct { }
+
+impl Struct {
+ fn ref_Struct(self: Struct, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_Struct(self: Box<Struct>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn rc_Struct(self: Rc<Struct>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_box_Struct(self: Box<Box<Struct>>, f: &u32) -> &u32 {
+ f
+ }
+
+ fn box_rc_Struct(self: Box<Rc<Struct>>, f: &u32) -> &u32 {
+ f
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+// https://github.com/rust-lang/rust/pull/60944#issuecomment-495346120
+
+struct Foo<'a>(&'a ());
+impl<'a> Foo<'a> {
+ fn foo<'b>(self: &'b Foo<'a>) -> &() { self.0 }
+}
+
+type Alias = Foo<'static>;
+impl Alias {
+ fn bar<'a>(self: &Alias, arg: &'a ()) -> &() { arg }
+}
+
+fn main() {}
let (_, _,) = (1, 1,);
let [_, _,] = [1, 1,];
let [_, _, .., _,] = [1, 1, 1, 1,];
- let [_, _, _.., _,] = [1, 1, 1, 1,];
+ let [_, _, _, ..,] = [1, 1, 1, 1,];
let x: Foo<isize,> = Foo::<isize,>(1);
-#![deny(rust_2018_idioms)]
-
use toml;
use serde::Serialize;
-#![deny(rust_2018_idioms)]
-
use std::env;
use std::process::Command;
use std::path::{Path, PathBuf};
-Subproject commit 164310dd8d09dd4db4065ee569a70380e793dc72
+Subproject commit dc69a5c0b610df452217291db1a0ebc4f76401e3
#![crate_name = "compiletest"]
#![feature(test)]
#![feature(vec_remove_item)]
-#![deny(warnings, rust_2018_idioms)]
extern crate test;
#![feature(rustc_private)]
-#![deny(rust_2018_idioms)]
-
extern crate env_logger;
extern crate syntax;
extern crate serialize as rustc_serialize;
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.
-#![deny(rust_2018_idioms)]
-
use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::env;
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+## This script publishes the new "current" toolstate in the toolstate repo (not to be
+## confused with publishing the test results, which happens in
+## `src/ci/docker/x86_64-gnu-tools/checktools.sh`).
+## It is set as callback for `src/ci/docker/x86_64-gnu-tools/repo.sh` by the CI scripts
+## when a new commit lands on `master` (i.e., after it passed all checks on `auto`).
+
import sys
import re
import os
-#![deny(rust_2018_idioms)]
-
/// This is a small client program intended to pair with `remote-test-server` in
/// this repository. This client connects to the server over TCP and is used to
/// push artifacts and run tests on the server instead of locally.
-#![deny(rust_2018_idioms)]
-
/// This is a small server which is intended to run inside of an emulator or
/// on a remote test device. This server pairs with the `remote-test-client`
/// program in this repository. The `remote-test-client` connects to this
-#![deny(rust_2018_idioms)]
-
use clap::{crate_version};
use std::env;
#![feature(no_core)]
#![no_core]
-#![deny(rust_2018_idioms)]
pub use core::*;
-#![deny(rust_2018_idioms)]
-
use std::env::args;
use std::fs::read_dir;
use std::path::Path;
-#![deny(rust_2018_idioms)]
-
fn main() { rustdoc::main() }
pub mod deps;
pub mod extdeps;
pub mod ui_tests;
+pub mod unit_tests;
pub mod unstable_book;
-pub mod libcoretest;
fn filter_dirs(path: &Path) -> bool {
let skip = [
- "src/llvm",
- "src/llvm-project",
"src/llvm-emscripten",
- "src/libbacktrace",
- "src/librustc_data_structures/owning_ref",
- "src/vendor",
+ "src/llvm-project",
+ "src/stdarch",
"src/tools/cargo",
- "src/tools/clang",
- "src/tools/rls",
"src/tools/clippy",
+ "src/tools/miri",
+ "src/tools/rls",
"src/tools/rust-installer",
"src/tools/rustfmt",
- "src/tools/miri",
- "src/tools/lld",
- "src/tools/lldb",
- "src/target",
- "src/stdarch",
- "src/rust-sgx",
- "target",
- "vendor",
];
skip.iter().any(|p| path.ends_with(p))
}
-
fn walk_many(
paths: &[&Path], skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)
) {
+++ /dev/null
-//! Tidy check to ensure `#[test]` is not used directly inside `libcore`.
-//!
-//! `#![no_core]` libraries cannot be tested directly due to duplicating lang
-//! item. All tests must be written externally in `libcore/tests`.
-
-use std::path::Path;
-
-pub fn check(path: &Path, bad: &mut bool) {
- let libcore_path = path.join("libcore");
- super::walk(
- &libcore_path,
- &mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
- &mut |entry, contents| {
- let subpath = entry.path();
- if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
- let contents = contents.trim();
- if !contents.starts_with("//") && contents.contains("#[test]") {
- tidy_error!(
- bad,
- "`{}` contains `#[test]`; libcore tests must be placed inside \
- `src/libcore/tests/`",
- subpath.display()
- );
- }
- }
- },
- );
-}
//! etc. This is run by default on `make check` and as part of the auto
//! builders.
-#![deny(warnings)]
-
use tidy::*;
use std::process;
let collected = features::check(&path, &mut bad, verbose);
pal::check(&path, &mut bad);
unstable_book::check(&path, collected, &mut bad);
- libcoretest::check(&path, &mut bad);
+ unit_tests::check(&path, &mut bad);
if !args.iter().any(|s| *s == "--no-vendor") {
deps::check(&path, &mut bad);
}
let mut skip_file_length = contains_ignore_directive(can_contain, &contents, "filelength");
let mut skip_end_whitespace =
contains_ignore_directive(can_contain, &contents, "end-whitespace");
+ let mut skip_trailing_newlines =
+ contains_ignore_directive(can_contain, &contents, "trailing-newlines");
let mut skip_copyright = contains_ignore_directive(can_contain, &contents, "copyright");
let mut leading_new_lines = false;
let mut trailing_new_lines = 0;
if leading_new_lines {
tidy_error!(bad, "{}: leading newline", file.display());
}
+ let mut err = |msg: &str| {
+ tidy_error!(bad, "{}: {}", file.display(), msg);
+ };
match trailing_new_lines {
- 0 => tidy_error!(bad, "{}: missing trailing newline", file.display()),
+ 0 => suppressible_tidy_err!(err, skip_trailing_newlines, "missing trailing newline"),
1 => {}
- n => tidy_error!(bad, "{}: too many trailing newlines ({})", file.display(), n),
+ n => suppressible_tidy_err!(
+ err,
+ skip_trailing_newlines,
+ &format!("too many trailing newlines ({})", n)
+ ),
};
if lines > LINES {
let mut err = |_| {
if let Directive::Ignore(false) = skip_end_whitespace {
tidy_error!(bad, "{}: ignoring trailing whitespace unnecessarily", file.display());
}
+ if let Directive::Ignore(false) = skip_trailing_newlines {
+ tidy_error!(bad, "{}: ignoring trailing newlines unnecessarily", file.display());
+ }
if let Directive::Ignore(false) = skip_copyright {
tidy_error!(bad, "{}: ignoring copyright unnecessarily", file.display());
}
--- /dev/null
+//! Tidy check to ensure `#[test]` and `#[bench]` are not used directly inside
+//! `libcore` or `liballoc`.
+//!
+//! `#![no_std]` libraries cannot be tested directly due to duplicating lang
+//! items. All tests and benchmarks must be written externally in `libcore/{tests,benches}`
+//! or `liballoc/{tests,benches}`.
+//!
+//! Outside of libcore and liballoc tests and benchmarks should be outlined into separate files
+//! named `tests.rs` or `benches.rs`, or directories named `tests` or `benches` unconfigured
+//! during normal build.
+
+use std::path::Path;
+
+pub fn check(root_path: &Path, bad: &mut bool) {
+ let libcore = &root_path.join("libcore");
+ let liballoc = &root_path.join("liballoc");
+ let libcore_tests = &root_path.join("libcore/tests");
+ let liballoc_tests = &root_path.join("liballoc/tests");
+ let libcore_benches = &root_path.join("libcore/benches");
+ let liballoc_benches = &root_path.join("liballoc/benches");
+ let is_core_or_alloc = |path: &Path| {
+ let is_core = path.starts_with(libcore) &&
+ !(path.starts_with(libcore_tests) || path.starts_with(libcore_benches));
+ let is_alloc = path.starts_with(liballoc) &&
+ !(path.starts_with(liballoc_tests) || path.starts_with(liballoc_benches));
+ is_core || is_alloc
+ };
+ let fixme = [
+ "liballoc",
+ "libpanic_unwind/dwarf",
+ "librustc",
+ "librustc_data_structures",
+ "librustc_incremental/persist",
+ "librustc_lexer/src",
+ "librustc_target/spec",
+ "librustdoc",
+ "libserialize",
+ "libstd",
+ "libsyntax",
+ "libsyntax_pos",
+ "libterm/terminfo",
+ "libtest",
+ "tools/compiletest/src",
+ "tools/tidy/src",
+ ];
+
+ let mut skip = |path: &Path| {
+ let file_name = path.file_name().unwrap_or_default();
+ if path.is_dir() {
+ super::filter_dirs(path) ||
+ path.ends_with("src/test") ||
+ path.ends_with("src/doc") ||
+ (file_name == "tests" || file_name == "benches") && !is_core_or_alloc(path) ||
+ fixme.iter().any(|p| path.ends_with(p))
+ } else {
+ let extension = path.extension().unwrap_or_default();
+ extension != "rs" ||
+ (file_name == "tests.rs" || file_name == "benches.rs") && !is_core_or_alloc(path)
+ }
+ };
+
+ super::walk(
+ root_path,
+ &mut skip,
+ &mut |entry, contents| {
+ let path = entry.path();
+ let is_libcore = path.starts_with(libcore);
+ let is_liballoc = path.starts_with(liballoc);
+ for (i, line) in contents.lines().enumerate() {
+ let line = line.trim();
+ let is_test = || line.contains("#[test]") && !line.contains("`#[test]");
+ let is_bench = || line.contains("#[bench]") && !line.contains("`#[bench]");
+ if !line.starts_with("//") && (is_test() || is_bench()) {
+ let explanation = if is_libcore {
+ "libcore unit tests and benchmarks must be placed into \
+ `libcore/tests` or `libcore/benches`"
+ } else if is_liballoc {
+ "liballoc unit tests and benchmarks must be placed into \
+ `liballoc/tests` or `liballoc/benches`"
+ } else {
+ "unit tests and benchmarks must be placed into \
+ separate files or directories named \
+ `tests.rs`, `benches.rs`, `tests` or `benches`"
+ };
+ let name = if is_test() { "test" } else { "bench" };
+ tidy_error!(
+ bad, "`{}:{}` contains `#[{}]`; {}",
+ path.display(), i + 1, name, explanation,
+ );
+ return;
+ }
+ }
+ },
+ );
+}
//! Auto-generate stub docs for the unstable book
-#![deny(rust_2018_idioms)]
-#![deny(warnings)]
-
-
-
use tidy::features::{Feature, Features, collect_lib_features, collect_lang_features};
use tidy::unstable_book::{collect_unstable_feature_names, collect_unstable_book_section_file_names,
PATH_STR, LANG_FEATURES_DIR, LIB_FEATURES_DIR};
[relabel]
allow-unauthenticated = [
- "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*",
+ "C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
+ "requires-nightly",
# I-* without I-nominated
"I-compilemem", "I-compiletime", "I-crash", "I-hang", "I-ICE", "I-slow",
]