about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-01-26 07:42:10 +0000
committerbors <bors@rust-lang.org>2016-01-26 07:42:10 +0000
commitacf4aeeda06b5355060e3dd8316e096465242f94 (patch)
tree812b6e0d57a0f74ed7e698db3133b8d86615b314 /src
parentfaf6d1e87391b25196b35909c3c95e5d873cacf0 (diff)
parent79157b3fb5d534500caf9c5f2a40161bea01e79d (diff)
downloadrust-acf4aeeda06b5355060e3dd8316e096465242f94.tar.gz
rust-acf4aeeda06b5355060e3dd8316e096465242f94.zip
Auto merge of #31210 - Manishearth:rollup, r=Manishearth
- Successful merges: #31152, #31184, #31189, #31192, #31197, #31199, #31201
- Failed merges:
Diffstat (limited to 'src')
-rw-r--r--src/doc/book/error-handling.md2
-rw-r--r--src/doc/book/getting-started.md10
-rw-r--r--src/doc/book/learn-rust.md9
-rw-r--r--src/doc/book/loops.md2
-rw-r--r--src/libcore/cell.rs4
-rw-r--r--src/libcore/iter.rs6
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/implicator.rs454
-rw-r--r--src/librustc_typeck/check/regionck.rs49
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs2
-rw-r--r--src/test/compile-fail/macro-follow.rs122
-rw-r--r--src/test/run-pass/macro-follow.rs190
12 files changed, 332 insertions, 519 deletions
diff --git a/src/doc/book/error-handling.md b/src/doc/book/error-handling.md
index 9b1d16170b9..40891dbe191 100644
--- a/src/doc/book/error-handling.md
+++ b/src/doc/book/error-handling.md
@@ -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:
diff --git a/src/doc/book/getting-started.md b/src/doc/book/getting-started.md
index 77d468254b6..d7b6e15794e 100644
--- a/src/doc/book/getting-started.md
+++ b/src/doc/book/getting-started.md
@@ -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 you’ll 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 you’ve 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 whatever’s right for you.
 
-[learnrust]: learn-rust.html
+[guessinggame]: guessing-game.html
 [syntax]: syntax-and-semantics.html
diff --git a/src/doc/book/learn-rust.md b/src/doc/book/learn-rust.md
deleted file mode 100644
index 7be7fa4f039..00000000000
--- a/src/doc/book/learn-rust.md
+++ /dev/null
@@ -1,9 +0,0 @@
-% Learn Rust
-
-Welcome! This chapter has a few tutorials that teach you Rust through building
-projects. You’ll get a high-level overview, but we’ll skim over the details.
-
-If you’d prefer a more ‘from the ground up’-style experience, check
-out [Syntax and Semantics][ss].
-
-[ss]: syntax-and-semantics.html
diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md
index 68bb49d2c29..5b08c2fb04d 100644
--- a/src/doc/book/loops.md
+++ b/src/doc/book/loops.md
@@ -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:
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 789b75836d0..6041355e9db 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -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:
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index e3e783329ec..ddc4fb32cde 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -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:
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 4d772de7835..4f6c1305f76 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -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;
diff --git a/src/librustc/middle/implicator.rs b/src/librustc/middle/implicator.rs
deleted file mode 100644
index d25084bbdff..00000000000
--- a/src/librustc/middle/implicator.rs
+++ /dev/null
@@ -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)
-}
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 47cd31d9898..56b02412c31 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -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>,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 9f069cb17ed..bfd76db0359 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -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),
diff --git a/src/test/compile-fail/macro-follow.rs b/src/test/compile-fail/macro-follow.rs
new file mode 100644
index 00000000000..35944bada4d
--- /dev/null
+++ b/src/test/compile-fail/macro-follow.rs
@@ -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() {}
+
diff --git a/src/test/run-pass/macro-follow.rs b/src/test/run-pass/macro-follow.rs
new file mode 100644
index 00000000000..ce6498f67f9
--- /dev/null
+++ b/src/test/run-pass/macro-follow.rs
@@ -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() {}
+