Auto merge of #31210 - Manishearth:rollup, r=Manishearth

- Successful merges: #31152, #31184, #31189, #31192, #31197, #31199, #31201
- Failed merges:
This commit is contained in:
bors 2016-01-26 07:42:10 +00:00
commit acf4aeeda0
12 changed files with 332 additions and 519 deletions

View File

@ -1512,7 +1512,7 @@ and [`rustc-serialize`](https://crates.io/crates/rustc-serialize) crates.
We're not going to spend a lot of time on setting up a project with
Cargo because it is already covered well in [the Cargo
section](../book/hello-cargo.html) and [Cargo's documentation][14].
section](getting-started.html#hello-cargo) and [Cargo's documentation][14].
To get started from scratch, run `cargo new --bin city-pop` and make sure your
`Cargo.toml` looks something like this:

View File

@ -167,6 +167,10 @@ variable. If it isn't, run the installer again, select "Change" on the "Change,
repair, or remove installation" page and ensure "Add to PATH" is installed on
the local hard drive.
Rust does not do its own linking, and so youll need to have a linker
installed. Doing so will depend on your specific system, consult its
documentation for more details.
If not, there are a number of places where we can get help. The easiest is
[the #rust IRC channel on irc.mozilla.org][irc], which we can access through
[Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans
@ -604,11 +608,11 @@ This chapter covered the basics that will serve you well through the rest of
this book, and the rest of your time with Rust. Now that youve got the tools
down, we'll cover more about the Rust language itself.
You have two options: Dive into a project with [Learn Rust][learnrust], or
You have two options: Dive into a project with [Tutorial: Guessing Game][guessinggame], or
start from the bottom and work your way up with [Syntax and
Semantics][syntax]. More experienced systems programmers will probably prefer
Learn Rust, while those from dynamic backgrounds may enjoy either. Different
Tutorial: Guessing Game, while those from dynamic backgrounds may enjoy either. Different
people learn differently! Choose whatevers right for you.
[learnrust]: learn-rust.html
[guessinggame]: guessing-game.html
[syntax]: syntax-and-semantics.html

View File

@ -1,9 +0,0 @@
% Learn Rust
Welcome! This chapter has a few tutorials that teach you Rust through building
projects. Youll get a high-level overview, but well skim over the details.
If youd prefer a more from the ground up-style experience, check
out [Syntax and Semantics][ss].
[ss]: syntax-and-semantics.html

View File

@ -195,7 +195,7 @@ for x in 0..10 {
You may also encounter situations where you have nested loops and need to
specify which one your `break` or `continue` statement is for. Like most
other languages, by default a `break` or `continue` will apply to innermost
loop. In a situation where you would like to a `break` or `continue` for one
loop. In a situation where you would like to `break` or `continue` for one
of the outer loops, you can use labels to specify which loop the `break` or
`continue` statement applies to. This will only print when both `x` and `y` are
odd:

View File

@ -414,7 +414,9 @@ impl<T: ?Sized> RefCell<T> {
///
/// let c = RefCell::new(5);
///
/// let borrowed_five = c.borrow_mut();
/// *c.borrow_mut() = 7;
///
/// assert_eq!(*c.borrow(), 7);
/// ```
///
/// An example of panic:

View File

@ -2740,7 +2740,13 @@ pub trait Extend<A> {
/// It is important to note that both back and forth work on the same range,
/// and do not cross: iteration is over when they meet in the middle.
///
/// In a similar fashion to the [`Iterator`] protocol, once a
/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again
/// may or may not ever return `Some` again. `next()` and `next_back()` are
/// interchangable for this purpose.
///
/// [`Iterator`]: trait.Iterator.html
///
/// # Examples
///
/// Basic usage:

View File

@ -108,7 +108,6 @@ pub mod middle {
pub mod free_region;
pub mod intrinsicck;
pub mod infer;
pub mod implicator;
pub mod lang_items;
pub mod liveness;
pub mod mem_categorization;

View File

@ -1,454 +0,0 @@
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// #![warn(deprecated_mode)]
use middle::def_id::DefId;
use middle::infer::{InferCtxt, GenericKind};
use middle::subst::Substs;
use middle::traits;
use middle::ty::{self, ToPredicate, Ty};
use middle::ty::fold::{TypeFoldable, TypeFolder};
use syntax::ast;
use syntax::codemap::Span;
use util::common::ErrorReported;
use util::nodemap::FnvHashSet;
// Helper functions related to manipulating region types.
#[derive(Debug)]
pub enum Implication<'tcx> {
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
Predicate(DefId, ty::Predicate<'tcx>),
}
struct Implicator<'a, 'tcx: 'a> {
infcx: &'a InferCtxt<'a,'tcx>,
body_id: ast::NodeId,
stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
span: Span,
out: Vec<Implication<'tcx>>,
visited: FnvHashSet<Ty<'tcx>>,
}
/// This routine computes the well-formedness constraints that must hold for the type `ty` to
/// appear in a context with lifetime `outer_region`
pub fn implications<'a,'tcx>(
infcx: &'a InferCtxt<'a,'tcx>,
body_id: ast::NodeId,
ty: Ty<'tcx>,
outer_region: ty::Region,
span: Span)
-> Vec<Implication<'tcx>>
{
debug!("implications(body_id={}, ty={:?}, outer_region={:?})",
body_id,
ty,
outer_region);
let mut stack = Vec::new();
stack.push((outer_region, None));
let mut wf = Implicator { infcx: infcx,
body_id: body_id,
span: span,
stack: stack,
out: Vec::new(),
visited: FnvHashSet() };
wf.accumulate_from_ty(ty);
debug!("implications: out={:?}", wf.out);
wf.out
}
impl<'a, 'tcx> Implicator<'a, 'tcx> {
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
self.infcx.tcx
}
fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
debug!("accumulate_from_ty(ty={:?})",
ty);
// When expanding out associated types, we can visit a cyclic
// set of types. Issue #23003.
if !self.visited.insert(ty) {
return;
}
match ty.sty {
ty::TyBool |
ty::TyChar |
ty::TyInt(..) |
ty::TyUint(..) |
ty::TyFloat(..) |
ty::TyBareFn(..) |
ty::TyError |
ty::TyStr => {
// No borrowed content reachable here.
}
ty::TyClosure(_, ref substs) => {
// FIXME(#27086). We do not accumulate from substs, since they
// don't represent reachable data. This means that, in
// practice, some of the lifetime parameters might not
// be in scope when the body runs, so long as there is
// no reachable data with that lifetime. For better or
// worse, this is consistent with fn types, however,
// which can also encapsulate data in this fashion
// (though it's somewhat harder, and typically
// requires virtual dispatch).
//
// Note that changing this (in a naive way, at least)
// causes regressions for what appears to be perfectly
// reasonable code like this:
//
// ```
// fn foo<'a>(p: &Data<'a>) {
// bar(|q: &mut Parser| q.read_addr())
// }
// fn bar(p: Box<FnMut(&mut Parser)+'static>) {
// }
// ```
//
// Note that `p` (and `'a`) are not used in the
// closure at all, but to meet the requirement that
// the closure type `C: 'static` (so it can be coerced
// to the object type), we get the requirement that
// `'a: 'static` since `'a` appears in the closure
// type `C`.
//
// A smarter fix might "prune" unused `func_substs` --
// this would avoid breaking simple examples like
// this, but would still break others (which might
// indeed be invalid, depending on your POV). Pruning
// would be a subtle process, since we have to see
// what func/type parameters are used and unused,
// taking into consideration UFCS and so forth.
for &upvar_ty in &substs.upvar_tys {
self.accumulate_from_ty(upvar_ty);
}
}
ty::TyTrait(ref t) => {
let required_region_bounds =
object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
}
ty::TyEnum(def, substs) |
ty::TyStruct(def, substs) => {
let item_scheme = def.type_scheme(self.tcx());
self.accumulate_from_adt(ty, def.did, &item_scheme.generics, substs)
}
ty::TyArray(t, _) |
ty::TySlice(t) |
ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) |
ty::TyBox(t) => {
self.accumulate_from_ty(t)
}
ty::TyRef(r_b, mt) => {
self.accumulate_from_rptr(ty, *r_b, mt.ty);
}
ty::TyParam(p) => {
self.push_param_constraint_from_top(p);
}
ty::TyProjection(ref data) => {
// `<T as TraitRef<..>>::Name`
self.push_projection_constraint_from_top(data);
}
ty::TyTuple(ref tuptys) => {
for &tupty in tuptys {
self.accumulate_from_ty(tupty);
}
}
ty::TyInfer(_) => {
// This should not happen, BUT:
//
// Currently we uncover region relationships on
// entering the fn check. We should do this after
// the fn check, then we can call this case a bug().
}
}
}
fn accumulate_from_rptr(&mut self,
ty: Ty<'tcx>,
r_b: ty::Region,
ty_b: Ty<'tcx>) {
// We are walking down a type like this, and current
// position is indicated by caret:
//
// &'a &'b ty_b
// ^
//
// At this point, top of stack will be `'a`. We must
// require that `'a <= 'b`.
self.push_region_constraint_from_top(r_b);
// Now we push `'b` onto the stack, because it must
// constrain any borrowed content we find within `T`.
self.stack.push((r_b, Some(ty)));
self.accumulate_from_ty(ty_b);
self.stack.pop().unwrap();
}
/// Pushes a constraint that `r_b` must outlive the top region on the stack.
fn push_region_constraint_from_top(&mut self,
r_b: ty::Region) {
// Indicates that we have found borrowed content with a lifetime
// of at least `r_b`. This adds a constraint that `r_b` must
// outlive the region `r_a` on top of the stack.
//
// As an example, imagine walking a type like:
//
// &'a &'b T
// ^
//
// when we hit the inner pointer (indicated by caret), `'a` will
// be on top of stack and `'b` will be the lifetime of the content
// we just found. So we add constraint that `'a <= 'b`.
let &(r_a, opt_ty) = self.stack.last().unwrap();
self.push_sub_region_constraint(opt_ty, r_a, r_b);
}
/// Pushes a constraint that `r_a <= r_b`, due to `opt_ty`
fn push_sub_region_constraint(&mut self,
opt_ty: Option<Ty<'tcx>>,
r_a: ty::Region,
r_b: ty::Region) {
self.out.push(Implication::RegionSubRegion(opt_ty, r_a, r_b));
}
/// Pushes a constraint that `param_ty` must outlive the top region on the stack.
fn push_param_constraint_from_top(&mut self,
param_ty: ty::ParamTy) {
let &(region, opt_ty) = self.stack.last().unwrap();
self.push_param_constraint(region, opt_ty, param_ty);
}
/// Pushes a constraint that `projection_ty` must outlive the top region on the stack.
fn push_projection_constraint_from_top(&mut self,
projection_ty: &ty::ProjectionTy<'tcx>) {
let &(region, opt_ty) = self.stack.last().unwrap();
self.out.push(Implication::RegionSubGeneric(
opt_ty, region, GenericKind::Projection(projection_ty.clone())));
}
/// Pushes a constraint that `region <= param_ty`, due to `opt_ty`
fn push_param_constraint(&mut self,
region: ty::Region,
opt_ty: Option<Ty<'tcx>>,
param_ty: ty::ParamTy) {
self.out.push(Implication::RegionSubGeneric(
opt_ty, region, GenericKind::Param(param_ty)));
}
fn accumulate_from_adt(&mut self,
ty: Ty<'tcx>,
def_id: DefId,
_generics: &ty::Generics<'tcx>,
substs: &Substs<'tcx>)
{
let predicates =
self.tcx().lookup_predicates(def_id).instantiate(self.tcx(), substs);
let predicates = match self.fully_normalize(&predicates) {
Ok(predicates) => predicates,
Err(ErrorReported) => { return; }
};
for predicate in predicates.predicates.as_slice() {
match *predicate {
ty::Predicate::Trait(..) => { }
ty::Predicate::Equate(..) => { }
ty::Predicate::Projection(..) => { }
ty::Predicate::RegionOutlives(ref data) => {
match self.tcx().no_late_bound_regions(data) {
None => { }
Some(ty::OutlivesPredicate(r_a, r_b)) => {
self.push_sub_region_constraint(Some(ty), r_b, r_a);
}
}
}
ty::Predicate::TypeOutlives(ref data) => {
match self.tcx().no_late_bound_regions(data) {
None => { }
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
self.stack.push((r_b, Some(ty)));
self.accumulate_from_ty(ty_a);
self.stack.pop().unwrap();
}
}
}
ty::Predicate::ObjectSafe(_) |
ty::Predicate::WellFormed(_) => {
}
}
}
let obligations = predicates.predicates
.into_iter()
.map(|pred| Implication::Predicate(def_id, pred));
self.out.extend(obligations);
let variances = self.tcx().item_variances(def_id);
self.accumulate_from_substs(substs, Some(&variances));
}
fn accumulate_from_substs(&mut self,
substs: &Substs<'tcx>,
variances: Option<&ty::ItemVariances>)
{
let mut tmp_variances = None;
let variances = variances.unwrap_or_else(|| {
tmp_variances = Some(ty::ItemVariances {
types: substs.types.map(|_| ty::Variance::Invariant),
regions: substs.regions().map(|_| ty::Variance::Invariant),
});
tmp_variances.as_ref().unwrap()
});
for (&region, &variance) in substs.regions().iter().zip(&variances.regions) {
match variance {
ty::Contravariant | ty::Invariant => {
// If any data with this lifetime is reachable
// within, it must be at least contravariant.
self.push_region_constraint_from_top(region)
}
ty::Covariant | ty::Bivariant => { }
}
}
for (&ty, &variance) in substs.types.iter().zip(&variances.types) {
match variance {
ty::Covariant | ty::Invariant => {
// If any data of this type is reachable within,
// it must be at least covariant.
self.accumulate_from_ty(ty);
}
ty::Contravariant | ty::Bivariant => { }
}
}
}
fn accumulate_from_object_ty(&mut self,
ty: Ty<'tcx>,
region_bound: ty::Region,
required_region_bounds: Vec<ty::Region>)
{
// Imagine a type like this:
//
// trait Foo { }
// trait Bar<'c> : 'c { }
//
// &'b (Foo+'c+Bar<'d>)
// ^
//
// In this case, the following relationships must hold:
//
// 'b <= 'c
// 'd <= 'c
//
// The first conditions is due to the normal region pointer
// rules, which say that a reference cannot outlive its
// referent.
//
// The final condition may be a bit surprising. In particular,
// you may expect that it would have been `'c <= 'd`, since
// usually lifetimes of outer things are conservative
// approximations for inner things. However, it works somewhat
// differently with trait objects: here the idea is that if the
// user specifies a region bound (`'c`, in this case) it is the
// "master bound" that *implies* that bounds from other traits are
// all met. (Remember that *all bounds* in a type like
// `Foo+Bar+Zed` must be met, not just one, hence if we write
// `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and
// 'y.)
//
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
// am looking forward to the future here.
// The content of this object type must outlive
// `bounds.region_bound`:
let r_c = region_bound;
self.push_region_constraint_from_top(r_c);
// And then, in turn, to be well-formed, the
// `region_bound` that user specified must imply the
// region bounds required from all of the trait types:
for &r_d in &required_region_bounds {
// Each of these is an instance of the `'c <= 'b`
// constraint above
self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
}
}
fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
where T : TypeFoldable<'tcx>
{
let value =
traits::fully_normalize(self.infcx,
traits::ObligationCause::misc(self.span, self.body_id),
value);
match value {
Ok(value) => Ok(value),
Err(errors) => {
// I don't like reporting these errors here, but I
// don't know where else to report them just now. And
// I don't really expect errors to arise here
// frequently. I guess the best option would be to
// propagate them out.
traits::report_fulfillment_errors(self.infcx, &errors);
Err(ErrorReported)
}
}
}
}
/// Given an object type like `SomeTrait+Send`, computes the lifetime
/// bounds that must hold on the elided self type. These are derived
/// from the declarations of `SomeTrait`, `Send`, and friends -- if
/// they declare `trait SomeTrait : 'static`, for example, then
/// `'static` would appear in the list. The hard work is done by
/// `ty::required_region_bounds`, see that for more information.
pub fn object_region_bounds<'tcx>(
tcx: &ty::ctxt<'tcx>,
principal: &ty::PolyTraitRef<'tcx>,
others: ty::BuiltinBounds)
-> Vec<ty::Region>
{
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
// a skolemized type.
let open_ty = tcx.mk_infer(ty::FreshTy(0));
// Note that we preserve the overall binding levels here.
assert!(!open_ty.has_escaping_regions());
let substs = tcx.mk_substs(principal.0.substs.with_self_ty(open_ty));
let trait_refs = vec!(ty::Binder(ty::TraitRef::new(principal.0.def_id, substs)));
let mut predicates = others.to_predicates(tcx, open_ty);
predicates.extend(trait_refs.iter().map(|t| t.to_predicate()));
tcx.required_region_bounds(open_ty, predicates)
}

View File

@ -86,7 +86,6 @@ use astconv::AstConv;
use check::dropck;
use check::FnCtxt;
use middle::free_region::FreeRegionMap;
use middle::implicator::{self, Implication};
use middle::mem_categorization as mc;
use middle::mem_categorization::Categorization;
use middle::region::{self, CodeExtent};
@ -365,12 +364,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
r_o, r_o.cause);
let sup_type = self.resolve_type(r_o.sup_type);
let origin = self.code_to_origin(r_o.cause.span, sup_type, &r_o.cause.code);
if r_o.sub_region != ty::ReEmpty {
type_must_outlive(self, origin, sup_type, r_o.sub_region);
} else {
self.visit_old_school_wf(node_id, sup_type, origin);
}
type_must_outlive(self, origin, sup_type, r_o.sub_region);
}
// Processing the region obligations should not cause the list to grow further:
@ -378,47 +372,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len());
}
fn visit_old_school_wf(&mut self,
body_id: ast::NodeId,
ty: Ty<'tcx>,
origin: infer::SubregionOrigin<'tcx>) {
// As a weird kind of hack, we use a region of empty as a signal
// to mean "old-school WF rules". The only reason the old-school
// WF rules are not encoded using WF is that this leads to errors,
// and we want to phase those in gradually.
// FIXME(#27579) remove this weird special case once we phase in new WF rules completely
let implications = implicator::implications(self.infcx(),
body_id,
ty,
ty::ReEmpty,
origin.span());
let origin_for_ty = |ty: Option<Ty<'tcx>>| match ty {
None => origin.clone(),
Some(ty) => infer::ReferenceOutlivesReferent(ty, origin.span()),
};
for implication in implications {
match implication {
Implication::RegionSubRegion(ty, r1, r2) => {
self.fcx.mk_subr(origin_for_ty(ty), r1, r2);
}
Implication::RegionSubGeneric(ty, r1, GenericKind::Param(param_ty)) => {
param_ty_must_outlive(self, origin_for_ty(ty), r1, param_ty);
}
Implication::RegionSubGeneric(ty, r1, GenericKind::Projection(proj_ty)) => {
projection_must_outlive(self, origin_for_ty(ty), r1, proj_ty);
}
Implication::Predicate(def_id, predicate) => {
let cause = traits::ObligationCause::new(origin.span(),
body_id,
traits::ItemObligation(def_id));
let obligation = traits::Obligation::new(cause, predicate);
self.fcx.register_predicate(obligation);
}
}
}
}
fn code_to_origin(&self,
span: Span,
sup_type: Ty<'tcx>,

View File

@ -1005,7 +1005,7 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
},
"path" | "ty" => {
match *tok {
OpenDelim(token::DelimToken::Brace) |
OpenDelim(token::DelimToken::Brace) | OpenDelim(token::DelimToken::Bracket) |
Comma | FatArrow | Colon | Eq | Gt | Semi | BinOp(token::Or) => Ok(true),
Ident(i, _) if (i.name.as_str() == "as" ||
i.name.as_str() == "where") => Ok(true),

View File

@ -0,0 +1,122 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// Check the macro follow sets (see corresponding rpass test).
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
macro_rules! follow_pat {
($p:pat ()) => {}; //~WARN `$p:pat` is followed by `(`
($p:pat []) => {}; //~WARN `$p:pat` is followed by `[`
($p:pat {}) => {}; //~WARN `$p:pat` is followed by `{`
($p:pat :) => {}; //~ERROR `$p:pat` is followed by `:`
($p:pat >) => {}; //~ERROR `$p:pat` is followed by `>`
($p:pat +) => {}; //~ERROR `$p:pat` is followed by `+`
($p:pat ident) => {}; //~ERROR `$p:pat` is followed by `ident`
($p:pat $p:pat) => {}; //~ERROR `$p:pat` is followed by `$p:pat`
($p:pat $e:expr) => {}; //~ERROR `$p:pat` is followed by `$e:expr`
($p:pat $t:ty) => {}; //~ERROR `$p:pat` is followed by `$t:ty`
($p:pat $s:stmt) => {}; //~ERROR `$p:pat` is followed by `$s:stmt`
($p:pat $p:path) => {}; //~ERROR `$p:pat` is followed by `$p:path`
($p:pat $b:block) => {}; //~ERROR `$p:pat` is followed by `$b:block`
($p:pat $i:ident) => {}; //~ERROR `$p:pat` is followed by `$i:ident`
($p:pat $t:tt) => {}; //~ERROR `$p:pat` is followed by `$t:tt`
($p:pat $i:item) => {}; //~ERROR `$p:pat` is followed by `$i:item`
($p:pat $m:meta) => {}; //~ERROR `$p:pat` is followed by `$m:meta`
}
// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
macro_rules! follow_expr {
($e:expr ()) => {}; //~WARN `$e:expr` is followed by `(`
($e:expr []) => {}; //~WARN `$e:expr` is followed by `[`
($e:expr {}) => {}; //~WARN `$e:expr` is followed by `{`
($e:expr =) => {}; //~ERROR `$e:expr` is followed by `=`
($e:expr |) => {}; //~ERROR `$e:expr` is followed by `|`
($e:expr :) => {}; //~ERROR `$e:expr` is followed by `:`
($e:expr >) => {}; //~ERROR `$e:expr` is followed by `>`
($e:expr +) => {}; //~ERROR `$e:expr` is followed by `+`
($e:expr ident) => {}; //~ERROR `$e:expr` is followed by `ident`
($e:expr if) => {}; //~ERROR `$e:expr` is followed by `if`
($e:expr in) => {}; //~ERROR `$e:expr` is followed by `in`
($e:expr $p:pat) => {}; //~ERROR `$e:expr` is followed by `$p:pat`
($e:expr $e:expr) => {}; //~ERROR `$e:expr` is followed by `$e:expr`
($e:expr $t:ty) => {}; //~ERROR `$e:expr` is followed by `$t:ty`
($e:expr $s:stmt) => {}; //~ERROR `$e:expr` is followed by `$s:stmt`
($e:expr $p:path) => {}; //~ERROR `$e:expr` is followed by `$p:path`
($e:expr $b:block) => {}; //~ERROR `$e:expr` is followed by `$b:block`
($e:expr $i:ident) => {}; //~ERROR `$e:expr` is followed by `$i:ident`
($e:expr $t:tt) => {}; //~ERROR `$e:expr` is followed by `$t:tt`
($e:expr $i:item) => {}; //~ERROR `$e:expr` is followed by `$i:item`
($e:expr $m:meta) => {}; //~ERROR `$e:expr` is followed by `$m:meta`
}
// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
// Ident(as), Ident(where), OpenDelim(Bracket)}
macro_rules! follow_ty {
($t:ty ()) => {}; //~WARN `$t:ty` is followed by `(`
($t:ty []) => {}; // ok (RFC 1462)
($t:ty +) => {}; //~ERROR `$t:ty` is followed by `+`
($t:ty ident) => {}; //~ERROR `$t:ty` is followed by `ident`
($t:ty if) => {}; //~ERROR `$t:ty` is followed by `if`
($t:ty $p:pat) => {}; //~ERROR `$t:ty` is followed by `$p:pat`
($t:ty $e:expr) => {}; //~ERROR `$t:ty` is followed by `$e:expr`
($t:ty $t:ty) => {}; //~ERROR `$t:ty` is followed by `$t:ty`
($t:ty $s:stmt) => {}; //~ERROR `$t:ty` is followed by `$s:stmt`
($t:ty $p:path) => {}; //~ERROR `$t:ty` is followed by `$p:path`
($t:ty $b:block) => {}; //~ERROR `$t:ty` is followed by `$b:block`
($t:ty $i:ident) => {}; //~ERROR `$t:ty` is followed by `$i:ident`
($t:ty $t:tt) => {}; //~ERROR `$t:ty` is followed by `$t:tt`
($t:ty $i:item) => {}; //~ERROR `$t:ty` is followed by `$i:item`
($t:ty $m:meta) => {}; //~ERROR `$t:ty` is followed by `$m:meta`
}
// FOLLOW(stmt) = FOLLOW(expr)
macro_rules! follow_stmt {
($s:stmt ()) => {}; //~WARN `$s:stmt` is followed by `(`
($s:stmt []) => {}; //~WARN `$s:stmt` is followed by `[`
($s:stmt {}) => {}; //~WARN `$s:stmt` is followed by `{`
($s:stmt =) => {}; //~ERROR `$s:stmt` is followed by `=`
($s:stmt |) => {}; //~ERROR `$s:stmt` is followed by `|`
($s:stmt :) => {}; //~ERROR `$s:stmt` is followed by `:`
($s:stmt >) => {}; //~ERROR `$s:stmt` is followed by `>`
($s:stmt +) => {}; //~ERROR `$s:stmt` is followed by `+`
($s:stmt ident) => {}; //~ERROR `$s:stmt` is followed by `ident`
($s:stmt if) => {}; //~ERROR `$s:stmt` is followed by `if`
($s:stmt in) => {}; //~ERROR `$s:stmt` is followed by `in`
($s:stmt $p:pat) => {}; //~ERROR `$s:stmt` is followed by `$p:pat`
($s:stmt $e:expr) => {}; //~ERROR `$s:stmt` is followed by `$e:expr`
($s:stmt $t:ty) => {}; //~ERROR `$s:stmt` is followed by `$t:ty`
($s:stmt $s:stmt) => {}; //~ERROR `$s:stmt` is followed by `$s:stmt`
($s:stmt $p:path) => {}; //~ERROR `$s:stmt` is followed by `$p:path`
($s:stmt $b:block) => {}; //~ERROR `$s:stmt` is followed by `$b:block`
($s:stmt $i:ident) => {}; //~ERROR `$s:stmt` is followed by `$i:ident`
($s:stmt $t:tt) => {}; //~ERROR `$s:stmt` is followed by `$t:tt`
($s:stmt $i:item) => {}; //~ERROR `$s:stmt` is followed by `$i:item`
($s:stmt $m:meta) => {}; //~ERROR `$s:stmt` is followed by `$m:meta`
}
// FOLLOW(path) = FOLLOW(ty)
macro_rules! follow_path {
($p:path ()) => {}; //~WARN `$p:path` is followed by `(`
($p:path []) => {}; // ok (RFC 1462)
($p:path +) => {}; //~ERROR `$p:path` is followed by `+`
($p:path ident) => {}; //~ERROR `$p:path` is followed by `ident`
($p:path if) => {}; //~ERROR `$p:path` is followed by `if`
($p:path $p:pat) => {}; //~ERROR `$p:path` is followed by `$p:pat`
($p:path $e:expr) => {}; //~ERROR `$p:path` is followed by `$e:expr`
($p:path $t:ty) => {}; //~ERROR `$p:path` is followed by `$t:ty`
($p:path $s:stmt) => {}; //~ERROR `$p:path` is followed by `$s:stmt`
($p:path $p:path) => {}; //~ERROR `$p:path` is followed by `$p:path`
($p:path $b:block) => {}; //~ERROR `$p:path` is followed by `$b:block`
($p:path $i:ident) => {}; //~ERROR `$p:path` is followed by `$i:ident`
($p:path $t:tt) => {}; //~ERROR `$p:path` is followed by `$t:tt`
($p:path $i:item) => {}; //~ERROR `$p:path` is followed by `$i:item`
($p:path $m:meta) => {}; //~ERROR `$p:path` is followed by `$m:meta`
}
// FOLLOW(block) = any token
// FOLLOW(ident) = any token
fn main() {}

View File

@ -0,0 +1,190 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check the macro follow sets (see corresponding cfail test).
// FOLLOW(pat) = {FatArrow, Comma, Eq, Or, Ident(if), Ident(in)}
macro_rules! follow_pat {
($p:pat =>) => {};
($p:pat ,) => {};
($p:pat =) => {};
($p:pat |) => {};
($p:pat if) => {};
($p:pat in) => {};
}
// FOLLOW(expr) = {FatArrow, Comma, Semicolon}
macro_rules! follow_expr {
($e:expr =>) => {};
($e:expr ,) => {};
($e:expr ;) => {};
}
// FOLLOW(ty) = {OpenDelim(Brace), Comma, FatArrow, Colon, Eq, Gt, Semi, Or,
// Ident(as), Ident(where), OpenDelim(Bracket)}
macro_rules! follow_ty {
($t:ty {}) => {};
($t:ty ,) => {};
($t:ty =>) => {};
($t:ty :) => {};
($t:ty =) => {};
($t:ty >) => {};
($t:ty ;) => {};
($t:ty |) => {};
($t:ty as) => {};
($t:ty where) => {};
($t:ty []) => {};
}
// FOLLOW(stmt) = FOLLOW(expr)
macro_rules! follow_stmt {
($s:stmt =>) => {};
($s:stmt ,) => {};
($s:stmt ;) => {};
}
// FOLLOW(path) = FOLLOW(ty)
macro_rules! follow_path {
($p:path {}) => {};
($p:path ,) => {};
($p:path =>) => {};
($p:path :) => {};
($p:path =) => {};
($p:path >) => {};
($p:path ;) => {};
($p:path |) => {};
($p:path as) => {};
($p:path where) => {};
($p:path []) => {};
}
// FOLLOW(block) = any token
macro_rules! follow_block {
($b:block ()) => {};
($b:block []) => {};
($b:block {}) => {};
($b:block ,) => {};
($b:block =>) => {};
($b:block :) => {};
($b:block =) => {};
($b:block >) => {};
($b:block ;) => {};
($b:block |) => {};
($b:block +) => {};
($b:block ident) => {};
($b:block $p:pat) => {};
($b:block $e:expr) => {};
($b:block $t:ty) => {};
($b:block $s:stmt) => {};
($b:block $p:path) => {};
($b:block $b:block) => {};
($b:block $i:ident) => {};
($b:block $t:tt) => {};
($b:block $i:item) => {};
($b:block $m:meta) => {};
}
// FOLLOW(ident) = any token
macro_rules! follow_ident {
($i:ident ()) => {};
($i:ident []) => {};
($i:ident {}) => {};
($i:ident ,) => {};
($i:ident =>) => {};
($i:ident :) => {};
($i:ident =) => {};
($i:ident >) => {};
($i:ident ;) => {};
($i:ident |) => {};
($i:ident +) => {};
($i:ident ident) => {};
($i:ident $p:pat) => {};
($i:ident $e:expr) => {};
($i:ident $t:ty) => {};
($i:ident $s:stmt) => {};
($i:ident $p:path) => {};
($i:ident $b:block) => {};
($i:ident $i:ident) => {};
($i:ident $t:tt) => {};
($i:ident $i:item) => {};
($i:ident $m:meta) => {};
}
// FOLLOW(tt) = any token
macro_rules! follow_tt {
($t:tt ()) => {};
($t:tt []) => {};
($t:tt {}) => {};
($t:tt ,) => {};
($t:tt =>) => {};
($t:tt :) => {};
($t:tt =) => {};
($t:tt >) => {};
($t:tt ;) => {};
($t:tt |) => {};
($t:tt +) => {};
($t:tt ident) => {};
($t:tt $p:pat) => {};
($t:tt $e:expr) => {};
($t:tt $t:ty) => {};
($t:tt $s:stmt) => {};
($t:tt $p:path) => {};
($t:tt $b:block) => {};
($t:tt $i:ident) => {};
($t:tt $t:tt) => {};
($t:tt $i:item) => {};
($t:tt $m:meta) => {};
}
// FOLLOW(item) = any token
macro_rules! follow_item {
($i:item ()) => {};
($i:item []) => {};
($i:item {}) => {};
($i:item ,) => {};
($i:item =>) => {};
($i:item :) => {};
($i:item =) => {};
($i:item >) => {};
($i:item ;) => {};
($i:item |) => {};
($i:item +) => {};
($i:item ident) => {};
($i:item $p:pat) => {};
($i:item $e:expr) => {};
($i:item $t:ty) => {};
($i:item $s:stmt) => {};
($i:item $p:path) => {};
($i:item $b:block) => {};
($i:item $i:ident) => {};
($i:item $t:tt) => {};
($i:item $i:item) => {};
($i:item $m:meta) => {};
}
// FOLLOW(meta) = any token
macro_rules! follow_meta {
($m:meta ()) => {};
($m:meta []) => {};
($m:meta {}) => {};
($m:meta ,) => {};
($m:meta =>) => {};
($m:meta :) => {};
($m:meta =) => {};
($m:meta >) => {};
($m:meta ;) => {};
($m:meta |) => {};
($m:meta +) => {};
($m:meta ident) => {};
($m:meta $p:pat) => {};
($m:meta $e:expr) => {};
($m:meta $t:ty) => {};
($m:meta $s:stmt) => {};
($m:meta $p:path) => {};
($m:meta $b:block) => {};
($m:meta $i:ident) => {};
($m:meta $t:tt) => {};
($m:meta $i:item) => {};
($m:meta $m:meta) => {};
}
fn main() {}