about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/region.rs46
-rw-r--r--src/librustc/middle/typeck/astconv.rs62
-rw-r--r--src/librustc/middle/typeck/check/mod.rs10
-rw-r--r--src/libsyntax/ast.rs32
-rw-r--r--src/libsyntax/ext/auto_encode.rs10
-rw-r--r--src/libsyntax/ext/deriving.rs5
-rw-r--r--src/libsyntax/parse/obsolete.rs6
-rw-r--r--src/libsyntax/parse/parser.rs165
-rw-r--r--src/libsyntax/print/pprust.rs59
-rw-r--r--src/test/compile-fail/prim-with-args.rs24
-rw-r--r--src/test/compile-fail/regions-in-consts.rs2
-rw-r--r--src/test/compile-fail/regions-in-enums.rs4
-rw-r--r--src/test/compile-fail/regions-in-structs.rs2
-rw-r--r--src/test/compile-fail/regions-infer-not-param.rs11
-rw-r--r--src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs2
15 files changed, 195 insertions, 245 deletions
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 12c08ffb435..a96ed9b8fa6 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -31,6 +31,7 @@ use std::oldmap::HashMap;
 use syntax::ast_map;
 use syntax::codemap::span;
 use syntax::print::pprust;
+use syntax::parse::token::special_idents;
 use syntax::{ast, visit};
 
 pub type parent = Option<ast::node_id>;
@@ -546,29 +547,20 @@ pub impl DetermineRpCtxt {
     // with &self type, &self is also bound.  We detect those last two
     // cases via flags (anon_implies_rp and self_implies_rp) that are
     // true when the anon or self region implies RP.
-    fn region_is_relevant(&self, r: @ast::region) -> bool {
-        match r.node {
-            ast::re_static => false,
-            ast::re_anon => self.anon_implies_rp,
-            ast::re_self => self.self_implies_rp,
-            ast::re_named(_) => false
-        }
-    }
-
-    // For named types like Foo, if there is no explicit region
-    // parameter, then we will add the anonymous region, so there is
-    // a dependency if the anonymous region implies rp.
-    //
-    // If the region is explicitly specified, then we follows the
-    // normal rules.
-    fn opt_region_is_relevant(&self,
-                              opt_r: Option<@ast::region>)
-                           -> bool {
-        debug!("opt_region_is_relevant: %? (anon_implies_rp=%b)",
-               opt_r, self.anon_implies_rp);
-        match opt_r {
-          None => self.anon_implies_rp,
-          Some(r) => self.region_is_relevant(r)
+    fn region_is_relevant(&self, r: Option<@ast::Lifetime>) -> bool {
+        match r {
+            None => {
+                self.anon_implies_rp
+            }
+            Some(ref l) if l.ident == special_idents::static => {
+                false
+            }
+            Some(ref l) if l.ident == special_idents::self_ => {
+                self.self_implies_rp
+            }
+            Some(_) => {
+                false
+            }
         }
     }
 
@@ -672,8 +664,8 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
             debug!("referenced fn type: %s",
                    pprust::ty_to_str(ty, sess.intr()));
             match f.region {
-                Some(r) => {
-                    if cx.region_is_relevant(r) {
+                Some(_) => {
+                    if cx.region_is_relevant(f.region) {
                         cx.add_rp(cx.item_id,
                                   cx.add_variance(rv_contravariant))
                     }
@@ -699,7 +691,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
         match cx.def_map.find(&id) {
           Some(ast::def_ty(did)) | Some(ast::def_struct(did)) => {
             if did.crate == ast::local_crate {
-                if cx.opt_region_is_relevant(path.rp) {
+                if cx.region_is_relevant(path.rp) {
                     cx.add_dep(did.node);
                 }
             } else {
@@ -709,7 +701,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty,
                   Some(variance) => {
                     debug!("reference to external, rp'd type %s",
                            pprust::ty_to_str(ty, sess.intr()));
-                    if cx.opt_region_is_relevant(path.rp) {
+                    if cx.region_is_relevant(path.rp) {
                         cx.add_rp(cx.item_id, cx.add_variance(variance))
                     }
                   }
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index 0b6c07832f6..8152200bf04 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -65,7 +65,8 @@ use core::result;
 use core::vec;
 use syntax::ast;
 use syntax::codemap::span;
-use syntax::print::pprust::{region_to_str, path_to_str};
+use syntax::print::pprust::{lifetime_to_str, path_to_str};
+use syntax::parse::token::special_idents;
 use util::common::indenter;
 
 pub trait AstConv {
@@ -79,7 +80,7 @@ pub trait AstConv {
 pub fn get_region_reporting_err(
     tcx: ty::ctxt,
     span: span,
-    a_r: Option<@ast::region>,
+    a_r: Option<@ast::Lifetime>,
     res: Result<ty::Region, RegionError>) -> ty::Region
 {
     match res {
@@ -87,13 +88,8 @@ pub fn get_region_reporting_err(
         result::Err(ref e) => {
             let descr = match a_r {
                 None => ~"anonymous lifetime",
-                Some(a) if a.node == ast::re_anon => {
-                    ~"anonymous lifetime"
-                }
-                Some(a) => {
-                    fmt!("lifetime %s",
-                         region_to_str(a, tcx.sess.intr()))
-                }
+                Some(a) => fmt!("lifetime %s",
+                                lifetime_to_str(a, tcx.sess.intr()))
             };
             tcx.sess.span_err(
                 span,
@@ -105,19 +101,28 @@ pub fn get_region_reporting_err(
 }
 
 pub fn ast_region_to_region<AC:AstConv,RS:region_scope + Copy + Durable>(
-        self: &AC,
-        rscope: &RS,
-        span: span,
-        a_r: @ast::region)
-     -> ty::Region {
-    let res = match a_r.node {
-        ast::re_static => Ok(ty::re_static),
-        ast::re_anon => rscope.anon_region(span),
-        ast::re_self => rscope.self_region(span),
-        ast::re_named(id) => rscope.named_region(span, id)
+    self: &AC,
+    rscope: &RS,
+    default_span: span,
+    opt_lifetime: Option<@ast::Lifetime>) -> ty::Region
+{
+    let (span, res) = match opt_lifetime {
+        None => {
+            (default_span, rscope.anon_region(default_span))
+        }
+        Some(ref lifetime) if lifetime.ident == special_idents::static => {
+            (lifetime.span, Ok(ty::re_static))
+        }
+        Some(ref lifetime) if lifetime.ident == special_idents::self_ => {
+            (lifetime.span, rscope.self_region(lifetime.span))
+        }
+        Some(ref lifetime) => {
+            (lifetime.span, rscope.named_region(lifetime.span,
+                                                lifetime.ident))
+        }
     };
 
-    get_region_reporting_err(self.tcx(), span, Some(a_r), res)
+    get_region_reporting_err(self.tcx(), span, opt_lifetime, res)
 }
 
 pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
@@ -156,8 +161,8 @@ pub fn ast_path_to_substs_and_ty<AC:AstConv,RS:region_scope + Copy + Durable>(
         let r = get_region_reporting_err(self.tcx(), path.span, None, res);
         Some(r)
       }
-      (Some(_), Some(r)) => {
-        Some(ast_region_to_region(self, rscope, path.span, r))
+      (Some(_), Some(_)) => {
+        Some(ast_region_to_region(self, rscope, path.span, path.rp))
       }
     };
 
@@ -504,7 +509,7 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
         sigil: ast::Sigil,
         purity: ast::purity,
         onceness: ast::Onceness,
-        opt_region: Option<@ast::region>,
+        opt_lifetime: Option<@ast::Lifetime>,
         decl: &ast::fn_decl,
         expected_tys: Option<ty::FnSig>,
         span: span)
@@ -514,9 +519,9 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
 
     // resolve the function bound region in the original region
     // scope `rscope`, not the scope of the function parameters
-    let bound_region = match opt_region {
-        Some(region) => {
-            ast_region_to_region(self, rscope, span, region)
+    let bound_region = match opt_lifetime {
+        Some(_) => {
+            ast_region_to_region(self, rscope, span, opt_lifetime)
         }
         None => {
             match sigil {
@@ -526,9 +531,8 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + Durable>(
                     ty::re_static
                 }
                 ast::BorrowedSigil => {
-                    // &fn() defaults to an anonymous region:
-                    let r_result = rscope.anon_region(span);
-                    get_region_reporting_err(self.tcx(), span, None, r_result)
+                    // &fn() defaults as normal for an omitted lifetime:
+                    ast_region_to_region(self, rscope, span, opt_lifetime)
                 }
             }
         }
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index 6efa62c55cc..0798e2b7afe 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -2950,19 +2950,19 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
     // determine the region bound, using the value given by the user
     // (if any) and otherwise using a fresh region variable
     let self_r = match pth.rp {
-      Some(r) => {
+      Some(_) => { // user supplied a lifetime parameter...
         match tpt.region_param {
-          None => {
+          None => { // ...but the type is not lifetime parameterized!
             fcx.ccx.tcx.sess.span_err
                 (span, ~"this item is not region-parameterized");
             None
           }
-          Some(_) => {
-            Some(ast_region_to_region(fcx, fcx, span, r))
+          Some(_) => { // ...and the type is lifetime parameterized, ok.
+            Some(ast_region_to_region(fcx, fcx, span, pth.rp))
           }
         }
       }
-      None => {
+      None => { // no lifetime parameter supplied, insert default
         fcx.region_var_if_parameterized(
             tpt.region_param, span, region_lb)
       }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index a6ccd69dd06..3782208eb85 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -116,7 +116,7 @@ pub struct path {
     span: span,
     global: bool,
     idents: ~[ident],
-    rp: Option<@region>,
+    rp: Option<@Lifetime>,
     types: ~[@Ty],
 }
 
@@ -374,10 +374,10 @@ impl ToStr for Sigil {
 #[deriving_eq]
 pub enum vstore {
     // FIXME (#3469): Change uint to @expr (actually only constant exprs)
-    vstore_fixed(Option<uint>),   // [1,2,3,4]
-    vstore_uniq,                  // ~[1,2,3,4]
-    vstore_box,                   // @[1,2,3,4]
-    vstore_slice(@region)         // &[1,2,3,4](foo)?
+    vstore_fixed(Option<uint>),     // [1,2,3,4]
+    vstore_uniq,                    // ~[1,2,3,4]
+    vstore_box,                     // @[1,2,3,4]
+    vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4]
 }
 
 #[auto_encode]
@@ -860,24 +860,6 @@ pub enum prim_ty {
 #[auto_encode]
 #[auto_decode]
 #[deriving_eq]
-pub struct region {
-    id: node_id,
-    node: region_,
-}
-
-#[auto_encode]
-#[auto_decode]
-#[deriving_eq]
-pub enum region_ {
-    re_anon,
-    re_static,
-    re_self,
-    re_named(ident)
-}
-
-#[auto_encode]
-#[auto_decode]
-#[deriving_eq]
 pub enum Onceness {
     Once,
     Many
@@ -903,7 +885,7 @@ impl to_bytes::IterBytes for Onceness {
 #[deriving_eq]
 pub struct TyClosure {
     sigil: Sigil,
-    region: Option<@region>,
+    region: Option<@Lifetime>,
     purity: purity,
     onceness: Onceness,
     decl: fn_decl
@@ -929,7 +911,7 @@ pub enum ty_ {
     ty_vec(mt),
     ty_fixed_length_vec(mt, uint),
     ty_ptr(mt),
-    ty_rptr(@region, mt),
+    ty_rptr(Option<@Lifetime>, mt),
     ty_closure(@TyClosure),
     ty_bare_fn(@TyBareFn),
     ty_tup(~[@Ty]),
diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs
index 644afaff37c..ecb5be6cc3c 100644
--- a/src/libsyntax/ext/auto_encode.rs
+++ b/src/libsyntax/ext/auto_encode.rs
@@ -594,10 +594,7 @@ fn mk_ser_method(
     let ty_s = @ast::Ty {
         id: cx.next_id(),
         node: ast::ty_rptr(
-            @ast::region {
-                id: cx.next_id(),
-                node: ast::re_anon,
-            },
+            None,
             ast::mt {
                 ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]),
                 mutbl: ast::m_imm
@@ -658,10 +655,7 @@ fn mk_deser_method(
     let ty_d = @ast::Ty {
         id: cx.next_id(),
         node: ast::ty_rptr(
-            @ast::region {
-                id: cx.next_id(),
-                node: ast::re_anon,
-            },
+            None,
             ast::mt {
                 ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]),
                 mutbl: ast::m_imm
diff --git a/src/libsyntax/ext/deriving.rs b/src/libsyntax/ext/deriving.rs
index a1514bc3eab..efea962a089 100644
--- a/src/libsyntax/ext/deriving.rs
+++ b/src/libsyntax/ext/deriving.rs
@@ -19,7 +19,7 @@ use ast::{enum_variant_kind, expr, expr_match, ident, impure_fn, item, item_};
 use ast::{item_enum, item_impl, item_struct, Generics};
 use ast::{m_imm, meta_item, method};
 use ast::{named_field, or, pat, pat_ident, pat_wild, public, pure_fn};
-use ast::{re_anon, stmt, struct_def, struct_variant_kind};
+use ast::{stmt, struct_def, struct_variant_kind};
 use ast::{sty_by_ref, sty_region, tuple_variant_kind, ty_nil, TyParam};
 use ast::{TyParamBound, ty_path, ty_rptr, unnamed_field, variant};
 use ext::base::ext_ctxt;
@@ -147,9 +147,8 @@ fn create_eq_method(cx: ext_ctxt,
                                                      span,
                                                      type_ident,
                                                      generics);
-    let arg_region = @ast::region { id: cx.next_id(), node: re_anon };
     let arg_type = ty_rptr(
-        arg_region,
+        None,
         ast::mt { ty: arg_path_type, mutbl: m_imm }
     );
     let arg_type = @ast::Ty {
diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs
index 6f2d2c554aa..97ff175da07 100644
--- a/src/libsyntax/parse/obsolete.rs
+++ b/src/libsyntax/parse/obsolete.rs
@@ -52,6 +52,7 @@ pub enum ObsoleteSyntax {
     ObsoleteRecordType,
     ObsoleteRecordPattern,
     ObsoleteAssertion,
+    ObsoletePostFnTySigil,
 }
 
 impl to_bytes::IterBytes for ObsoleteSyntax {
@@ -160,6 +161,11 @@ pub impl Parser {
                 "assertion",
                 "use `fail_unless!()` instead"
             ),
+            ObsoletePostFnTySigil => (
+                "fn sigil in postfix position",
+                "Rather than `fn@`, `fn~`, or `fn&`, \
+                 write `@fn`, `~fn`, and `&fn` respectively"
+            ),
         };
 
         self.report(sp, kind, kind_str, desc);
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 384cf4f0e95..adcaa006247 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -14,7 +14,7 @@ use ast::{Sigil, BorrowedSigil, ManagedSigil, OwnedSigil, RustAbi};
 use ast::{CallSugar, NoSugar, DoSugar, ForSugar};
 use ast::{TyBareFn, TyClosure};
 use ast::{RegionTyParamBound, TraitTyParamBound};
-use ast::{provided, public, pure_fn, purity, re_static};
+use ast::{provided, public, pure_fn, purity};
 use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer};
 use ast::{bind_by_copy, bitand, bitor, bitxor, blk};
 use ast::{blk_check_mode, box, by_copy, by_ref, by_val};
@@ -40,9 +40,9 @@ use ast::{lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const};
 use ast::{m_imm, m_mutbl, mac_, mac_invoc_tt, matcher, match_nonterminal};
 use ast::{match_seq, match_tok, method, mode, module_ns, mt, mul, mutability};
 use ast::{named_field, neg, node_id, noreturn, not, pat, pat_box, pat_enum};
-use ast::{pat_ident, pat_lit, pat_range, pat_region, pat_struct, pat_tup};
-use ast::{pat_uniq, pat_wild, path, private};
-use ast::{re_self, re_anon, re_named, region, rem, required};
+use ast::{pat_ident, pat_lit, pat_range, pat_region, pat_struct};
+use ast::{pat_tup, pat_uniq, pat_wild, path, private};
+use ast::{rem, required};
 use ast::{ret_style, return_val, self_ty, shl, shr, stmt, stmt_decl};
 use ast::{stmt_expr, stmt_semi, stmt_mac, struct_def, struct_field};
 use ast::{struct_immutable, struct_mutable, struct_variant_kind, subtract};
@@ -76,7 +76,7 @@ use parse::obsolete::{ObsoleteUnsafeBlock, ObsoleteImplSyntax};
 use parse::obsolete::{ObsoleteTraitBoundSeparator, ObsoleteMutOwnedPointer};
 use parse::obsolete::{ObsoleteMutVector, ObsoleteTraitImplVisibility};
 use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
-use parse::obsolete::{ObsoleteAssertion};
+use parse::obsolete::{ObsoleteAssertion, ObsoletePostFnTySigil};
 use parse::prec::{as_prec, token_to_binop};
 use parse::token::{can_begin_expr, is_ident, is_ident_or_path};
 use parse::token::{is_plain_ident, INTERPOLATED, special_idents};
@@ -363,12 +363,13 @@ pub impl Parser {
         });
     }
 
-    fn parse_ty_closure(&self, pre_sigil: Option<ast::Sigil>,
-                        pre_region_name: Option<ident>) -> ty_
+    fn parse_ty_closure(&self,
+                        sigil: ast::Sigil,
+                        region: Option<@ast::Lifetime>) -> ty_
     {
         /*
 
-        (&|~|@) [r/] [pure|unsafe] [once] fn <'lt> (S) -> T
+        (&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T
         ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^    ^~~~^ ^~^    ^
            |     |     |             |         |    |     |
            |     |     |             |         |    |   Return type
@@ -388,13 +389,10 @@ pub impl Parser {
         let onceness = parse_onceness(self);
         self.expect_keyword(&~"fn");
 
-        let sigil = match pre_sigil { None => BorrowedSigil, Some(p) => p };
-
-        let region = if pre_region_name.is_some() {
-            Some(self.region_from_name(pre_region_name))
-        } else {
-            None
-        };
+        if self.parse_fn_ty_sigil().is_some() {
+            self.obsolete(*self.span,
+                          ObsoletePostFnTySigil);
+        }
 
         return ty_closure(@TyClosure {
             sigil: sigil,
@@ -432,7 +430,7 @@ pub impl Parser {
         */
         if self.eat(&token::LT) {
             let _lifetimes = self.parse_lifetimes();
-            self.expect(&token::GT);
+            self.expect_gt();
         }
         let inputs = self.parse_unspanned_seq(
             &token::LPAREN,
@@ -575,38 +573,6 @@ pub impl Parser {
         }
     }
 
-    fn region_from_name(&self, s: Option<ident>) -> @region {
-        let r = match s {
-            Some(id) if id == special_idents::static => ast::re_static,
-            Some(id) if id == special_idents::self_ => re_self,
-            Some(id) => re_named(id),
-            None => re_anon
-        };
-
-        @ast::region { id: self.get_id(), node: r }
-    }
-
-    // Parses something like "&x"
-    fn parse_region(&self) -> @region {
-        self.expect(&token::BINOP(token::AND));
-
-        match *self.token {
-          token::IDENT(sid, _) => {
-            self.bump();
-            self.region_from_name(Some(sid))
-          }
-          _ => {
-            self.region_from_name(None)
-          }
-        }
-    }
-
-    fn region_from_lifetime(&self, l: &ast::Lifetime) -> @region {
-        // eventually `ast::region` should go away in favor of
-        // `ast::Lifetime`.  For now we convert between them.
-        self.region_from_name(Some(l.ident))
-    }
-
     fn parse_ty(&self, colons_before_params: bool) -> @Ty {
         maybe_whole!(self, nt_ty);
 
@@ -681,7 +647,8 @@ pub impl Parser {
         } else if self.eat_keyword(&~"extern") {
             self.parse_ty_bare_fn()
         } else if self.token_is_closure_keyword(&copy *self.token) {
-            self.parse_ty_closure(None, None)
+            // self.warn(fmt!("Old-school closure keyword"));
+            self.parse_ty_closure(ast::BorrowedSigil, None)
         } else if *self.token == token::MOD_SEP
             || is_ident_or_path(&*self.token) {
             let path = self.parse_path_with_tps(colons_before_params);
@@ -701,20 +668,20 @@ pub impl Parser {
     {
         // @'foo fn() or @foo/fn() or @fn() are parsed directly as fn types:
         match *self.token {
-            token::LIFETIME(rname) => {
+            token::LIFETIME(*) => {
+                let lifetime = @self.parse_lifetime();
                 self.bump();
-                return self.parse_ty_closure(Some(sigil), Some(rname));
+                return self.parse_ty_closure(sigil, Some(lifetime));
             }
 
-            token::IDENT(rname, _) => {
+            token::IDENT(*) => {
                 if self.look_ahead(1u) == token::BINOP(token::SLASH) &&
                     self.token_is_closure_keyword(&self.look_ahead(2u))
                 {
-                    self.bump();
-                    self.bump();
-                    return self.parse_ty_closure(Some(sigil), Some(rname));
+                    let lifetime = @self.parse_lifetime();
+                    return self.parse_ty_closure(sigil, Some(lifetime));
                 } else if self.token_is_closure_keyword(&copy *self.token) {
-                    return self.parse_ty_closure(Some(sigil), None);
+                    return self.parse_ty_closure(sigil, None);
                 }
             }
             _ => {}
@@ -735,31 +702,14 @@ pub impl Parser {
 
     fn parse_borrowed_pointee(&self) -> ty_ {
         // look for `&'lt` or `&foo/` and interpret `foo` as the region name:
-        let rname = match *self.token {
-            token::LIFETIME(sid) => {
-                self.bump();
-                Some(sid)
-            }
-
-            token::IDENT(sid, _) => {
-                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
-                    self.bump(); self.bump();
-                    Some(sid)
-                } else {
-                    None
-                }
-            }
-
-            _ => { None }
-        };
+        let opt_lifetime = self.parse_opt_lifetime();
 
         if self.token_is_closure_keyword(&copy *self.token) {
-            return self.parse_ty_closure(Some(BorrowedSigil), rname);
+            return self.parse_ty_closure(BorrowedSigil, opt_lifetime);
         }
 
-        let r = self.region_from_name(rname);
         let mt = self.parse_mt();
-        return ty_rptr(r, mt);
+        return ty_rptr(opt_lifetime, mt);
     }
 
     fn parse_arg_mode(&self) -> mode {
@@ -939,19 +889,27 @@ pub impl Parser {
             return path;
         }
 
-        // Parse the region parameter, if any, which will
+        // Parse the (obsolete) trailing region parameter, if any, which will
         // be written "foo/&x"
         let rp_slash = {
-            // Hack: avoid parsing vstores like /@ and /~.  This is painful
-            // because the notation for region bounds and the notation for
-            // vstores is... um... the same.  I guess that's my fault.  This
-            // is still not ideal as for &str we end up parsing more than we
-            // ought to and have to sort it out later.
             if *self.token == token::BINOP(token::SLASH)
-                && self.look_ahead(1u) == token::BINOP(token::AND) {
-
-                self.expect(&token::BINOP(token::SLASH));
-                Some(self.parse_region())
+                && self.look_ahead(1u) == token::BINOP(token::AND)
+            {
+                self.bump(); self.bump();
+                match *self.token {
+                    token::IDENT(sid, _) => {
+                        let span = copy self.span;
+                        self.bump();
+                        Some(@ast::Lifetime {
+                            id: self.get_id(),
+                            span: *span,
+                            ident: sid
+                        })
+                    }
+                    _ => {
+                        self.fatal(fmt!("Expected a lifetime name"));
+                    }
+                }
             } else {
                 None
             }
@@ -967,7 +925,7 @@ pub impl Parser {
                 if v.len() == 0 {
                     None
                 } else if v.len() == 1 {
-                    Some(self.region_from_lifetime(v.get(0)))
+                    Some(@*v.get(0))
                 } else {
                     self.fatal(fmt!("Expected at most one \
                                      lifetime name (for now)"));
@@ -981,16 +939,26 @@ pub impl Parser {
                      .. copy *path }
     }
 
-    fn parse_opt_lifetime(&self) -> Option<ast::Lifetime> {
+    fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> {
         /*!
          *
          * Parses 0 or 1 lifetime.
          */
 
         match *self.token {
-            token::LIFETIME(_) => {
-                Some(self.parse_lifetime())
+            token::LIFETIME(*) => {
+                Some(@self.parse_lifetime())
+            }
+
+            // Also accept the (obsolete) syntax `foo/`
+            token::IDENT(*) => {
+                if self.look_ahead(1u) == token::BINOP(token::SLASH) {
+                    Some(@self.parse_lifetime())
+                } else {
+                    None
+                }
             }
+
             _ => {
                 None
             }
@@ -1005,13 +973,27 @@ pub impl Parser {
 
         match *self.token {
             token::LIFETIME(i) => {
+                let span = copy self.span;
+                self.bump();
+                return ast::Lifetime {
+                    id: self.get_id(),
+                    span: *span,
+                    ident: i
+                };
+            }
+
+            // Also accept the (obsolete) syntax `foo/`
+            token::IDENT(i, _) => {
+                let span = copy self.span;
                 self.bump();
+                self.expect(&token::BINOP(token::SLASH));
                 return ast::Lifetime {
                     id: self.get_id(),
-                    span: *self.span,
+                    span: *span,
                     ident: i
                 };
             }
+
             _ => {
                 self.fatal(fmt!("Expected a lifetime name"));
             }
@@ -1041,6 +1023,7 @@ pub impl Parser {
             match *self.token {
                 token::COMMA => { self.bump();}
                 token::GT => { return res; }
+                token::BINOP(token::SHR) => { return res; }
                 _ => {
                     self.fatal(~"expected `,` or `>` after lifetime name");
                 }
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c68341c20fa..3744b7a8f6c 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -146,8 +146,8 @@ pub fn expr_to_str(e: @ast::expr, intr: @ident_interner) -> ~str {
     to_str(e, print_expr, intr)
 }
 
-pub fn region_to_str(e: @ast::region, intr: @ident_interner) -> ~str {
-    to_str(e, |s, e| print_region(s, ~"&", e, ~""), intr)
+pub fn lifetime_to_str(e: &ast::Lifetime, intr: @ident_interner) -> ~str {
+    to_str(e, print_lifetime, intr)
 }
 
 pub fn tt_to_str(tt: ast::token_tree, intr: @ident_interner) -> ~str {
@@ -355,23 +355,11 @@ pub fn print_foreign_mod(s: @ps, nmod: ast::foreign_mod,
     for nmod.items.each |item| { print_foreign_item(s, *item); }
 }
 
-pub fn print_region(s: @ps, prefix: ~str, region: @ast::region, sep: ~str) {
-    word(s.s, prefix);
-    match region.node {
-        ast::re_anon => {
-            return;
-        }
-        ast::re_static => {
-            word_space(s, ~"static")
-        }
-        ast::re_self => {
-            word_space(s, ~"self")
-        }
-        ast::re_named(name) => {
-            print_ident(s, name);
-        }
+pub fn print_opt_lifetime(s: @ps, lifetime: Option<@ast::Lifetime>) {
+    for lifetime.each |l| {
+        print_lifetime(s, *l);
+        nbsp(s);
     }
-    word(s.s, sep);
 }
 
 pub fn print_type(s: @ps, &&ty: @ast::Ty) {
@@ -397,8 +385,9 @@ pub fn print_type_ex(s: @ps, &&ty: @ast::Ty, print_colons: bool) {
         word(s.s, ~"]");
       }
       ast::ty_ptr(mt) => { word(s.s, ~"*"); print_mt(s, mt); }
-      ast::ty_rptr(region, mt) => {
-          print_region(s, ~"&", region, ~"/");
+      ast::ty_rptr(lifetime, mt) => {
+          word(s.s, ~"&");
+          print_opt_lifetime(s, lifetime);
           print_mt(s, mt);
       }
       ast::ty_tup(elts) => {
@@ -1048,7 +1037,10 @@ pub fn print_vstore(s: @ps, t: ast::vstore) {
         ast::vstore_fixed(None) => word(s.s, ~"_"),
         ast::vstore_uniq => word(s.s, ~"~"),
         ast::vstore_box => word(s.s, ~"@"),
-        ast::vstore_slice(r) => print_region(s, ~"&", r, ~"/")
+        ast::vstore_slice(r) => {
+            word(s.s, ~"&");
+            print_opt_lifetime(s, r);
+        }
     }
 }
 
@@ -1501,17 +1493,18 @@ pub fn print_path(s: @ps, &&path: @ast::path, colons_before_params: bool) {
     if path.rp.is_some() || !path.types.is_empty() {
         if colons_before_params { word(s.s, ~"::"); }
 
-        match path.rp {
-          None => { /* ok */ }
-          Some(r) => {
-            word(s.s, ~"/");
-            print_region(s, ~"&", r, ~"");
-          }
-        }
-
-        if !path.types.is_empty() {
+        if path.rp.is_some() || !path.types.is_empty() {
             word(s.s, ~"<");
+
+            for path.rp.each |r| {
+                print_lifetime(s, *r);
+                if !path.types.is_empty() {
+                    word_space(s, ~",");
+                }
+            }
+
             commasep(s, inconsistent, path.types, print_type);
+
             word(s.s, ~">");
         }
     }
@@ -1749,7 +1742,7 @@ pub fn print_bounds(s: @ps, bounds: @OptVec<ast::TyParamBound>) {
     }
 }
 
-pub fn print_lifetime(s: @ps, lifetime: &ast::Lifetime) {
+pub fn print_lifetime(s: @ps, &&lifetime: &ast::Lifetime) {
     word(s.s, ~"'");
     print_ident(s, lifetime.ident);
 }
@@ -1908,7 +1901,7 @@ pub fn print_arg(s: @ps, input: ast::arg) {
 pub fn print_ty_fn(s: @ps,
                    opt_abi: Option<ast::Abi>,
                    opt_sigil: Option<ast::Sigil>,
-                   opt_region: Option<@ast::region>,
+                   opt_region: Option<@ast::Lifetime>,
                    purity: ast::purity,
                    onceness: ast::Onceness,
                    decl: &ast::fn_decl, id: Option<ast::ident>,
@@ -1921,7 +1914,7 @@ pub fn print_ty_fn(s: @ps,
     print_self_ty_if_static(s, opt_self_ty);
     print_opt_abi(s, opt_abi);
     print_opt_sigil(s, opt_sigil);
-    for opt_region.each |r| { print_region(s, ~"", *r, ~"/"); }
+    print_opt_lifetime(s, opt_region);
     print_purity(s, purity);
     print_onceness(s, onceness);
     word(s.s, ~"fn");
diff --git a/src/test/compile-fail/prim-with-args.rs b/src/test/compile-fail/prim-with-args.rs
index be57f88fd0a..40d5a441241 100644
--- a/src/test/compile-fail/prim-with-args.rs
+++ b/src/test/compile-fail/prim-with-args.rs
@@ -23,17 +23,17 @@ let x: u64<int>; //~ ERROR type parameters are not allowed on this type
 let x: float<int>; //~ ERROR type parameters are not allowed on this type
 let x: char<int>; //~ ERROR type parameters are not allowed on this type
 
-let x: int/&; //~ ERROR region parameters are not allowed on this type
-let x: i8/&; //~ ERROR region parameters are not allowed on this type
-let x: i16/&; //~ ERROR region parameters are not allowed on this type
-let x: i32/&; //~ ERROR region parameters are not allowed on this type
-let x: i64/&; //~ ERROR region parameters are not allowed on this type
-let x: uint/&; //~ ERROR region parameters are not allowed on this type
-let x: u8/&; //~ ERROR region parameters are not allowed on this type
-let x: u16/&; //~ ERROR region parameters are not allowed on this type
-let x: u32/&; //~ ERROR region parameters are not allowed on this type
-let x: u64/&; //~ ERROR region parameters are not allowed on this type
-let x: float/&; //~ ERROR region parameters are not allowed on this type
-let x: char/&; //~ ERROR region parameters are not allowed on this type
+let x: int<'static>; //~ ERROR region parameters are not allowed on this type
+let x: i8<'static>; //~ ERROR region parameters are not allowed on this type
+let x: i16<'static>; //~ ERROR region parameters are not allowed on this type
+let x: i32<'static>; //~ ERROR region parameters are not allowed on this type
+let x: i64<'static>; //~ ERROR region parameters are not allowed on this type
+let x: uint<'static>; //~ ERROR region parameters are not allowed on this type
+let x: u8<'static>; //~ ERROR region parameters are not allowed on this type
+let x: u16<'static>; //~ ERROR region parameters are not allowed on this type
+let x: u32<'static>; //~ ERROR region parameters are not allowed on this type
+let x: u64<'static>; //~ ERROR region parameters are not allowed on this type
+let x: float<'static>; //~ ERROR region parameters are not allowed on this type
+let x: char<'static>; //~ ERROR region parameters are not allowed on this type
 
 }
diff --git a/src/test/compile-fail/regions-in-consts.rs b/src/test/compile-fail/regions-in-consts.rs
index 19dea9a57ee..2ba27e888cb 100644
--- a/src/test/compile-fail/regions-in-consts.rs
+++ b/src/test/compile-fail/regions-in-consts.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-const c_x: &'blk int = &22; //~ ERROR Illegal lifetime &blk: only 'static is allowed here
+const c_x: &'blk int = &22; //~ ERROR Illegal lifetime 'blk: only 'static is allowed here
 const c_y: &int = &22; //~ ERROR Illegal anonymous lifetime: only 'static is allowed here
 const c_z: &'static int = &22;
 
diff --git a/src/test/compile-fail/regions-in-enums.rs b/src/test/compile-fail/regions-in-enums.rs
index 5c2269977d1..0adfaccdc01 100644
--- a/src/test/compile-fail/regions-in-enums.rs
+++ b/src/test/compile-fail/regions-in-enums.rs
@@ -10,7 +10,7 @@
 
 enum yes0<'lt> {
     // This will eventually be legal (and in fact the only way):
-    X3(&'lt uint) //~ ERROR Illegal lifetime &lt: only 'self is allowed allowed as part of a type declaration
+    X3(&'lt uint) //~ ERROR Illegal lifetime 'lt: only 'self is allowed allowed as part of a type declaration
 }
 
 enum yes1 {
@@ -18,7 +18,7 @@ enum yes1 {
 }
 
 enum yes2 {
-    X5(&'foo uint) //~ ERROR Illegal lifetime &foo: only 'self is allowed allowed as part of a type declaration
+    X5(&'foo uint) //~ ERROR Illegal lifetime 'foo: only 'self is allowed allowed as part of a type declaration
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-in-structs.rs b/src/test/compile-fail/regions-in-structs.rs
index 10d7a921ed0..b425a40114a 100644
--- a/src/test/compile-fail/regions-in-structs.rs
+++ b/src/test/compile-fail/regions-in-structs.rs
@@ -17,7 +17,7 @@ struct yes1<'self> {
 }
 
 struct yes2<'self> {
-  x: &'foo uint, //~ ERROR Illegal lifetime &foo: only 'self is allowed allowed as part of a type declaration
+  x: &'foo uint, //~ ERROR Illegal lifetime 'foo: only 'self is allowed allowed as part of a type declaration
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/regions-infer-not-param.rs b/src/test/compile-fail/regions-infer-not-param.rs
index b5f8d998298..a0ecb08a089 100644
--- a/src/test/compile-fail/regions-infer-not-param.rs
+++ b/src/test/compile-fail/regions-infer-not-param.rs
@@ -13,19 +13,16 @@ struct direct<'self> {
 }
 
 struct indirect1 {
+    // Here the lifetime parameter of direct is bound by the fn()
     g: @fn(direct)
 }
 
-struct indirect2 {
-    g: @fn(direct/&)
-}
-
-struct indirect3 {
+struct indirect2<'self> {
+    // But here it is set to 'self
     g: @fn(direct<'self>)
 }
 
 fn take_direct(p: direct) -> direct { p } //~ ERROR mismatched types
 fn take_indirect1(p: indirect1) -> indirect1 { p }
-fn take_indirect2(p: indirect2) -> indirect2 { p }
-fn take_indirect3(p: indirect3) -> indirect3 { p } //~ ERROR mismatched types
+fn take_indirect2(p: indirect2) -> indirect2 { p } //~ ERROR mismatched types
 fn main() {}
diff --git a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
index 11414a11108..fe37d899098 100644
--- a/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
+++ b/src/test/compile-fail/regions-infer-region-in-fn-but-not-type.rs
@@ -13,7 +13,7 @@
 // contains region pointers
 enum foo = ~fn(x: &int);
 
-fn take_foo(x: foo/&) {} //~ ERROR no region bound is allowed on `foo`
+fn take_foo(x: foo<'static>) {} //~ ERROR no region bound is allowed on `foo`
 
 fn main() {
 }