Auto merge of #63057 - Centril:rollup-z3a3c6v, r=Centril
Rollup of 8 pull requests Successful merges: - #61207 (Allow lifetime elision in `Pin<&(mut) Self>`) - #62074 (squash of all commits for nth_back on ChunksMut) - #62771 (Break dependencies between `syntax_ext` and other crates) - #62883 (Refactoring use common code between option, result and accum) - #62949 (Re-enable assertions in PPC dist builder) - #62996 (tidy: Add a check for inline unit tests) - #63038 (Make more informative error on outer attribute after inner) - #63050 (ci: download awscli from our mirror) Failed merges: r? @ghost
This commit is contained in:
commit
9a239ef4de
89 changed files with 2337 additions and 900 deletions
|
@ -138,43 +138,11 @@ steps:
|
|||
|
||||
# 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.
|
||||
|
|
14
Cargo.lock
14
Cargo.lock
|
@ -2863,31 +2863,20 @@ dependencies = [
|
|||
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",
|
||||
]
|
||||
|
@ -3019,7 +3008,6 @@ dependencies = [
|
|||
"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",
|
||||
]
|
||||
|
||||
|
@ -3064,9 +3052,7 @@ dependencies = [
|
|||
"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",
|
||||
]
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
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'
|
|
@ -36,7 +36,3 @@ ENV HOSTS=powerpc-unknown-linux-gnu
|
|||
|
||||
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
|
||||
|
|
35
src/ci/install-awscli.sh
Executable file
35
src/ci/install-awscli.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/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}"
|
|
@ -2062,3 +2062,138 @@ impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
|
|||
#[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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -360,7 +360,7 @@ pub use self::adapters::Flatten;
|
|||
#[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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
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.
|
||||
///
|
||||
|
@ -114,74 +115,6 @@ macro_rules! float_sum_product {
|
|||
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>,
|
||||
|
@ -224,73 +157,6 @@ impl<T, U, E> Product<Result<U, E>> for Result<T, E>
|
|||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -135,7 +135,7 @@
|
|||
|
||||
#![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;
|
||||
|
||||
|
@ -1499,45 +1499,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
|
|||
// 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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@
|
|||
#![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`]).
|
||||
|
@ -1343,39 +1343,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
|
|||
// 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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4339,6 +4339,25 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
|
|||
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")]
|
||||
|
|
|
@ -222,6 +222,28 @@ fn test_chunks_mut_nth() {
|
|||
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];
|
||||
|
|
|
@ -63,7 +63,6 @@ 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};
|
||||
|
@ -241,7 +240,7 @@ pub fn lower_crate(
|
|||
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,
|
||||
|
|
|
@ -2146,47 +2146,76 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
// 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;
|
||||
}
|
||||
struct SelfVisitor<'a> {
|
||||
map: &'a NamedRegionMap,
|
||||
impl_self: Option<&'a hir::TyKind>,
|
||||
lifetime: Set1<Region>,
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
_ => {}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> for SelfVisitor<'a> {
|
||||
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
false
|
||||
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,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,30 +10,19 @@ path = "lib.rs"
|
|||
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" }
|
||||
|
|
|
@ -278,7 +278,12 @@ pub fn register_plugins<'a>(
|
|||
|
||||
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", || {
|
||||
|
@ -456,7 +461,7 @@ fn configure_and_expand_inner<'a>(
|
|||
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,
|
||||
|
@ -485,7 +490,7 @@ fn configure_and_expand_inner<'a>(
|
|||
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,
|
||||
|
|
|
@ -21,5 +21,4 @@ rustc_target = { path = "../librustc_target" }
|
|||
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" }
|
||||
|
|
|
@ -586,8 +586,7 @@ impl<'a> CrateLoader<'a> {
|
|||
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,
|
||||
|
|
|
@ -31,10 +31,10 @@ use syntax::attr;
|
|||
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;
|
||||
|
||||
|
|
|
@ -11,9 +11,7 @@ path = "lib.rs"
|
|||
[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" }
|
||||
|
|
|
@ -14,12 +14,12 @@ use rustc::session::Session;
|
|||
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};
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ use syntax::ext::hygiene::ExpnId;
|
|||
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};
|
||||
|
||||
|
@ -367,8 +366,10 @@ impl<'a> Resolver<'a> {
|
|||
};
|
||||
|
||||
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);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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};
|
||||
|
@ -14,7 +14,7 @@ use crate::tokenstream::{self, TokenStream, TokenTree};
|
|||
|
||||
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;
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
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));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -4,7 +4,7 @@ use crate::attr::{self, HasAttrs};
|
|||
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};
|
||||
|
|
249
src/libsyntax/ext/proc_macro.rs
Normal file
249
src/libsyntax/ext/proc_macro.rs
Normal file
|
@ -0,0 +1,249 @@
|
|||
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));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,21 +1,19 @@
|
|||
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 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::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
||||
use syntax_pos::hygiene::{SyntaxContext, Transparency};
|
||||
use syntax_pos::symbol::{kw, sym, Symbol};
|
||||
use syntax_pos::{BytePos, FileName, MultiSpan, Pos, SourceFile, Span};
|
||||
|
||||
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;
|
||||
|
@ -52,7 +50,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
|
|||
{
|
||||
fn from_internal(((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec<Self>))
|
||||
-> Self {
|
||||
use syntax::parse::token::*;
|
||||
use crate::parse::token::*;
|
||||
|
||||
let joint = is_joint == Joint;
|
||||
let Token { kind, span } = match tree {
|
||||
|
@ -193,7 +191,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec<Self>)>
|
|||
|
||||
impl ToInternal<TokenStream> for TokenTree<Group, Punct, Ident, Literal> {
|
||||
fn to_internal(self) -> TokenStream {
|
||||
use syntax::parse::token::*;
|
||||
use crate::parse::token::*;
|
||||
|
||||
let (ch, joint, span) = match self {
|
||||
TokenTree::Punct(Punct { ch, joint, span }) => (ch, joint, span),
|
|
@ -18,12 +18,17 @@
|
|||
#![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;
|
||||
|
@ -37,6 +42,7 @@ const MACRO_ARGUMENTS: Option<&'static str> = Some("macro arguments");
|
|||
// 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};
|
||||
|
@ -147,10 +153,8 @@ pub mod mut_visit;
|
|||
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;
|
||||
|
||||
|
@ -161,14 +165,15 @@ pub mod print {
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::parse::{SeqSep, PResult};
|
|||
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;
|
||||
|
@ -11,7 +12,7 @@ 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 \
|
||||
|
@ -42,7 +43,11 @@ impl<'a> Parser<'a> {
|
|||
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;
|
||||
|
@ -76,8 +81,11 @@ impl<'a> Parser<'a> {
|
|||
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)
|
||||
}
|
||||
|
@ -98,19 +106,9 @@ impl<'a> Parser<'a> {
|
|||
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
|
||||
|
@ -121,7 +119,38 @@ impl<'a> Parser<'a> {
|
|||
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();
|
||||
|
|
|
@ -794,7 +794,7 @@ mod tests {
|
|||
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()),
|
||||
|
@ -817,6 +817,7 @@ mod tests {
|
|||
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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ use crate::parse::token::TokenKind;
|
|||
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;
|
||||
|
||||
|
@ -58,6 +59,7 @@ pub struct ParseSess {
|
|||
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 {
|
||||
|
@ -86,6 +88,7 @@ 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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ use crate::parse::{self, ParseSess};
|
|||
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};
|
||||
|
||||
|
@ -114,7 +113,7 @@ pub fn print_crate<'a>(cm: &'a SourceMap,
|
|||
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
|
||||
|
|
|
@ -10,11 +10,11 @@ path = "lib.rs"
|
|||
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" }
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
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
|
||||
}
|
||||
}
|
|
@ -1770,50 +1770,6 @@ pub fn cs_fold1<F, B>(use_foldl: bool,
|
|||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
|
|
@ -18,6 +18,7 @@ pub enum PtrTy<'a> {
|
|||
/// &'lifetime mut
|
||||
Borrowed(Option<&'a str>, ast::Mutability),
|
||||
/// *mut
|
||||
#[allow(dead_code)]
|
||||
Raw(ast::Mutability),
|
||||
}
|
||||
|
||||
|
@ -107,13 +108,6 @@ pub enum Ty<'a> {
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ pub mod decodable;
|
|||
pub mod hash;
|
||||
pub mod debug;
|
||||
pub mod default;
|
||||
pub mod custom;
|
||||
|
||||
#[path="cmp/partial_eq.rs"]
|
||||
pub mod partial_eq;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
//! 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/")]
|
||||
|
||||
|
@ -7,21 +8,15 @@
|
|||
|
||||
#![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;
|
||||
|
@ -32,21 +27,21 @@ mod cfg;
|
|||
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(
|
||||
|
@ -93,7 +88,7 @@ pub fn register_builtin_macros(resolver: &mut dyn syntax::ext::base::Resolver, e
|
|||
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! {
|
||||
|
|
|
@ -7,21 +7,15 @@ 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::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,
|
||||
|
@ -44,7 +38,7 @@ struct CollectProcMacros<'a> {
|
|||
is_test_crate: bool,
|
||||
}
|
||||
|
||||
pub fn modify(sess: &ParseSess,
|
||||
pub fn inject(sess: &ParseSess,
|
||||
resolver: &mut dyn (::syntax::ext::base::Resolver),
|
||||
mut krate: ast::Crate,
|
||||
is_proc_macro_crate: bool,
|
||||
|
@ -88,10 +82,6 @@ pub fn modify(sess: &ParseSess,
|
|||
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() {
|
|
@ -1,68 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
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 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};
|
||||
|
@ -94,7 +94,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: &[tokenstrea
|
|||
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,
|
||||
None => self.p.sess.span_diagnostic.span_fatal(self.p.token.span,
|
||||
&format!("expected item, found `{}`",
|
||||
self.p.this_token_to_string()))
|
||||
.raise()
|
|
@ -1,37 +1,22 @@
|
|||
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::{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;
|
||||
|
||||
pub fn injected_crate_name() -> Option<&'static str> {
|
||||
INJECTED_CRATE_NAME.with(|name| name.get())
|
||||
}
|
||||
use std::iter;
|
||||
|
||||
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 {
|
||||
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;
|
||||
return (krate, None);
|
||||
} else if attr::contains_name(&krate.attrs, sym::no_std) {
|
||||
if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
|
||||
&["core"]
|
||||
|
@ -73,8 +58,6 @@ pub fn maybe_inject_crates_ref(
|
|||
// 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(),
|
||||
|
@ -108,5 +91,5 @@ pub fn maybe_inject_crates_ref(
|
|||
tokens: None,
|
||||
}));
|
||||
|
||||
krate
|
||||
(krate, Some(Symbol::intern(name)))
|
||||
}
|
|
@ -7,11 +7,44 @@ use syntax::ext::base::*;
|
|||
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,
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
// 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)]
|
||||
}
|
|
@ -1,35 +1,23 @@
|
|||
// 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 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 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;
|
||||
use std::{iter, mem};
|
||||
|
||||
struct Test {
|
||||
span: Span,
|
||||
|
@ -42,22 +30,21 @@ struct TestCtxt<'a> {
|
|||
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) {
|
||||
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
|
||||
|
@ -267,11 +254,7 @@ fn generate_test_harness(sess: &ParseSess,
|
|||
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
|
||||
};
|
||||
|
||||
|
@ -282,19 +265,6 @@ fn generate_test_harness(sess: &ParseSess,
|
|||
}.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> {
|
|
@ -1,8 +1,8 @@
|
|||
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.
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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.
|
||||
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
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.
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
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.
|
||||
|
||||
|
|
60
src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
Normal file
60
src/test/ui/self/arbitrary_self_types_pin_lifetime.rs
Normal file
|
@ -0,0 +1,60 @@
|
|||
// 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() };
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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() };
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
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
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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() {}
|
|
@ -0,0 +1,26 @@
|
|||
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
|
||||
|
44
src/test/ui/self/elision/README.md
Normal file
44
src/test/ui/self/elision/README.md
Normal file
|
@ -0,0 +1,44 @@
|
|||
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`.
|
36
src/test/ui/self/elision/alias.rs
Normal file
36
src/test/ui/self/elision/alias.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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() { }
|
40
src/test/ui/self/elision/assoc.rs
Normal file
40
src/test/ui/self/elision/assoc.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// 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() { }
|
38
src/test/ui/self/elision/lt-alias.rs
Normal file
38
src/test/ui/self/elision/lt-alias.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// 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() { }
|
44
src/test/ui/self/elision/lt-assoc.rs
Normal file
44
src/test/ui/self/elision/lt-assoc.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
// 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() { }
|
62
src/test/ui/self/elision/lt-ref-self.nll.stderr
Normal file
62
src/test/ui/self/elision/lt-ref-self.nll.stderr
Normal file
|
@ -0,0 +1,62 @@
|
|||
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
|
||||
|
38
src/test/ui/self/elision/lt-ref-self.rs
Normal file
38
src/test/ui/self/elision/lt-ref-self.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
#![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() { }
|
62
src/test/ui/self/elision/lt-ref-self.stderr
Normal file
62
src/test/ui/self/elision/lt-ref-self.stderr
Normal file
|
@ -0,0 +1,62 @@
|
|||
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
|
||||
|
49
src/test/ui/self/elision/lt-self.rs
Normal file
49
src/test/ui/self/elision/lt-self.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
// 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() { }
|
36
src/test/ui/self/elision/lt-struct.rs
Normal file
36
src/test/ui/self/elision/lt-struct.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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() { }
|
43
src/test/ui/self/elision/multiple-ref-self.rs
Normal file
43
src/test/ui/self/elision/multiple-ref-self.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
// 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() { }
|
39
src/test/ui/self/elision/ref-alias.rs
Normal file
39
src/test/ui/self/elision/ref-alias.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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() { }
|
40
src/test/ui/self/elision/ref-assoc.rs
Normal file
40
src/test/ui/self/elision/ref-assoc.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
// 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() { }
|
36
src/test/ui/self/elision/ref-mut-alias.rs
Normal file
36
src/test/ui/self/elision/ref-mut-alias.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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() { }
|
62
src/test/ui/self/elision/ref-mut-self.nll.stderr
Normal file
62
src/test/ui/self/elision/ref-mut-self.nll.stderr
Normal file
|
@ -0,0 +1,62 @@
|
|||
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
|
||||
|
38
src/test/ui/self/elision/ref-mut-self.rs
Normal file
38
src/test/ui/self/elision/ref-mut-self.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
#![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() { }
|
62
src/test/ui/self/elision/ref-mut-self.stderr
Normal file
62
src/test/ui/self/elision/ref-mut-self.stderr
Normal file
|
@ -0,0 +1,62 @@
|
|||
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
|
||||
|
52
src/test/ui/self/elision/ref-mut-struct.nll.stderr
Normal file
52
src/test/ui/self/elision/ref-mut-struct.nll.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
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
|
||||
|
32
src/test/ui/self/elision/ref-mut-struct.rs
Normal file
32
src/test/ui/self/elision/ref-mut-struct.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#![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() { }
|
52
src/test/ui/self/elision/ref-mut-struct.stderr
Normal file
52
src/test/ui/self/elision/ref-mut-struct.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
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
|
||||
|
72
src/test/ui/self/elision/ref-self.nll.stderr
Normal file
72
src/test/ui/self/elision/ref-self.nll.stderr
Normal file
|
@ -0,0 +1,72 @@
|
|||
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
|
||||
|
51
src/test/ui/self/elision/ref-self.rs
Normal file
51
src/test/ui/self/elision/ref-self.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
#![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() { }
|
72
src/test/ui/self/elision/ref-self.stderr
Normal file
72
src/test/ui/self/elision/ref-self.stderr
Normal file
|
@ -0,0 +1,72 @@
|
|||
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
|
||||
|
52
src/test/ui/self/elision/ref-struct.nll.stderr
Normal file
52
src/test/ui/self/elision/ref-struct.nll.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
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
|
||||
|
32
src/test/ui/self/elision/ref-struct.rs
Normal file
32
src/test/ui/self/elision/ref-struct.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#![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() { }
|
52
src/test/ui/self/elision/ref-struct.stderr
Normal file
52
src/test/ui/self/elision/ref-struct.stderr
Normal file
|
@ -0,0 +1,52 @@
|
|||
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
|
||||
|
36
src/test/ui/self/elision/self.rs
Normal file
36
src/test/ui/self/elision/self.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
// 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() { }
|
32
src/test/ui/self/elision/struct.rs
Normal file
32
src/test/ui/self/elision/struct.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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() { }
|
15
src/test/ui/self/self_lifetime.rs
Normal file
15
src/test/ui/self/self_lifetime.rs
Normal file
|
@ -0,0 +1,15 @@
|
|||
// 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() {}
|
|
@ -38,8 +38,8 @@ pub mod pal;
|
|||
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 = [
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
//! 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()
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
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);
|
||||
}
|
||||
|
|
95
src/tools/tidy/src/unit_tests.rs
Normal file
95
src/tools/tidy/src/unit_tests.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
//! 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;
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue