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:
bors 2019-07-28 01:03:16 +00:00
commit 9a239ef4de
89 changed files with 2337 additions and 900 deletions

View file

@ -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.

View file

@ -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",
]

View file

@ -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'

View file

@ -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
View 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}"

View file

@ -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)
}
}
}

View file

@ -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;

View file

@ -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

View file

@ -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())
}
}

View file

@ -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())
}
}

View file

@ -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")]

View file

@ -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];

View file

@ -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,

View file

@ -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;
}
}

View file

@ -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" }

View file

@ -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,

View file

@ -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" }

View file

@ -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,

View file

@ -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;

View file

@ -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" }

View file

@ -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};

View file

@ -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);

View file

@ -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;

View file

@ -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));
}
});
}

View file

@ -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};

View 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));
}
});
}

View file

@ -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),

View file

@ -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;

View file

@ -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();

View file

@ -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(),
}
}

View file

@ -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(),
}
}

View file

@ -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

View file

@ -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" }

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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)
}

View file

@ -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;

View file

@ -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! {

View file

@ -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() {

View file

@ -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();
}
}
}
}

View file

@ -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()

View file

@ -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)))
}

View file

@ -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,

View file

@ -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)]
}

View file

@ -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> {

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View 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() };
}

View file

@ -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

View file

@ -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() };
}

View file

@ -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

View file

@ -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

View file

@ -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() {}

View file

@ -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

View 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`.

View 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() { }

View 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() { }

View 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() { }

View 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() { }

View 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

View 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() { }

View 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

View 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() { }

View 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() { }

View 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() { }

View 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() { }

View 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() { }

View 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() { }

View 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

View 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() { }

View 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

View 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

View 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() { }

View 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

View 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

View 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() { }

View 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

View 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

View 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() { }

View 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

View 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() { }

View 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() { }

View 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() {}

View file

@ -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 = [

View file

@ -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()
);
}
}
},
);
}

View file

@ -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);
}

View 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;
}
}
},
);
}