about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/resolve.rs31
-rw-r--r--src/librustc/middle/trans/debuginfo.rs4
-rw-r--r--src/librustc/middle/typeck/collect.rs173
-rw-r--r--src/librustc/middle/typeck/infer/error_reporting.rs13
-rw-r--r--src/librustdoc/clean/mod.rs24
-rw-r--r--src/librustdoc/doctree.rs18
-rw-r--r--src/librustdoc/visit_ast.rs18
-rw-r--r--src/libsyntax/ast.rs17
-rw-r--r--src/libsyntax/ast_map/mod.rs21
-rw-r--r--src/libsyntax/ast_util.rs10
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs8
-rw-r--r--src/libsyntax/ext/deriving/generic/ty.rs9
-rw-r--r--src/libsyntax/fold.rs43
-rw-r--r--src/libsyntax/parse/lexer/mod.rs24
-rw-r--r--src/libsyntax/parse/mod.rs4
-rw-r--r--src/libsyntax/parse/parser.rs92
-rw-r--r--src/libsyntax/parse/token.rs21
-rw-r--r--src/libsyntax/print/pprust.rs139
-rw-r--r--src/libsyntax/visit.rs14
-rw-r--r--src/test/auxiliary/where_clauses_xc.rs30
-rw-r--r--src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs23
-rw-r--r--src/test/compile-fail/where-clauses-not-parameter.rs17
-rw-r--r--src/test/compile-fail/where-clauses-unsatisfied.rs20
-rw-r--r--src/test/run-pass/where-clauses-cross-crate.rs23
-rw-r--r--src/test/run-pass/where-clauses.rs37
25 files changed, 626 insertions, 207 deletions
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index 9edf9fcbdba..3ce6f726100 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -3671,6 +3671,7 @@ impl<'a> Resolver<'a> {
                                                                ItemRibKind),
                                              |this| {
                     this.resolve_type_parameters(&generics.ty_params);
+                    this.resolve_where_clause(&generics.where_clause);
                     visit::walk_item(this, item, ());
                 });
             }
@@ -3713,6 +3714,7 @@ impl<'a> Resolver<'a> {
                                                                NormalRibKind),
                                              |this| {
                     this.resolve_type_parameters(&generics.ty_params);
+                    this.resolve_where_clause(&generics.where_clause);
 
                     // Resolve derived traits.
                     for trt in traits.iter() {
@@ -3744,6 +3746,8 @@ impl<'a> Resolver<'a> {
                                 // parameters.
                                 this.resolve_type_parameters(
                                     &ty_m.generics.ty_params);
+                                this.resolve_where_clause(&ty_m.generics
+                                                               .where_clause);
 
                                 for argument in ty_m.decl.inputs.iter() {
                                     this.resolve_type(&*argument.ty);
@@ -3907,6 +3911,7 @@ impl<'a> Resolver<'a> {
                 }
                 HasTypeParameters(ref generics, _, _, _) => {
                     this.resolve_type_parameters(&generics.ty_params);
+                    this.resolve_where_clause(&generics.where_clause);
                 }
             }
 
@@ -4022,6 +4027,30 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn resolve_where_clause(&mut self, where_clause: &ast::WhereClause) {
+        for predicate in where_clause.predicates.iter() {
+            match self.resolve_identifier(predicate.ident,
+                                          TypeNS,
+                                          true,
+                                          predicate.span) {
+                Some((def @ DefTyParam(_, _, _), last_private)) => {
+                    self.record_def(predicate.id, (def, last_private));
+                }
+                _ => {
+                    self.resolve_error(
+                        predicate.span,
+                        format!("undeclared type parameter `{}`",
+                                token::get_ident(
+                                    predicate.ident)).as_slice());
+                }
+            }
+
+            for bound in predicate.bounds.iter() {
+                self.resolve_type_parameter_bound(predicate.id, bound);
+            }
+        }
+    }
+
     fn resolve_struct(&mut self,
                       id: NodeId,
                       generics: &Generics,
@@ -4035,6 +4064,7 @@ impl<'a> Resolver<'a> {
                                      |this| {
             // Resolve the type parameters.
             this.resolve_type_parameters(&generics.ty_params);
+            this.resolve_where_clause(&generics.where_clause);
 
             // Resolve the super struct.
             match super_struct {
@@ -4146,6 +4176,7 @@ impl<'a> Resolver<'a> {
                                      |this| {
             // Resolve the type parameters.
             this.resolve_type_parameters(&generics.ty_params);
+            this.resolve_where_clause(&generics.where_clause);
 
             // Resolve the trait reference, if necessary.
             this.with_optional_trait_ref(id, opt_trait_reference, |this| {
diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs
index 9b78cedd4ac..de5e718206d 100644
--- a/src/librustc/middle/trans/debuginfo.rs
+++ b/src/librustc/middle/trans/debuginfo.rs
@@ -208,7 +208,6 @@ use syntax::util::interner::Interner;
 use syntax::codemap::{Span, Pos};
 use syntax::{abi, ast, codemap, ast_util, ast_map};
 use syntax::ast_util::PostExpansionMethod;
-use syntax::owned_slice::OwnedSlice;
 use syntax::parse::token;
 use syntax::parse::token::special_idents;
 
@@ -1123,8 +1122,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
         return FunctionDebugContext { repr: FunctionWithoutDebugInfo };
     }
 
-    let empty_generics = ast::Generics { lifetimes: Vec::new(),
-                                         ty_params: OwnedSlice::empty() };
+    let empty_generics = ast_util::empty_generics();
 
     let fnitem = cx.tcx.map.get(fn_ast_id);
 
diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs
index 284330c51c8..0c5d58ae930 100644
--- a/src/librustc/middle/typeck/collect.rs
+++ b/src/librustc/middle/typeck/collect.rs
@@ -987,20 +987,26 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt,
 
 fn ty_generics_for_type(ccx: &CrateCtxt,
                         generics: &ast::Generics)
-                        -> ty::Generics
-{
-    ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
-                &generics.ty_params, ty::Generics::empty())
+                        -> ty::Generics {
+    ty_generics(ccx,
+                subst::TypeSpace,
+                &generics.lifetimes,
+                &generics.ty_params,
+                ty::Generics::empty(),
+                &generics.where_clause)
 }
 
 fn ty_generics_for_trait(ccx: &CrateCtxt,
                          trait_id: ast::NodeId,
                          substs: &subst::Substs,
                          generics: &ast::Generics)
-                         -> ty::Generics
-{
-    let mut generics = ty_generics(ccx, subst::TypeSpace, &generics.lifetimes,
-                                   &generics.ty_params, ty::Generics::empty());
+                         -> ty::Generics {
+    let mut generics = ty_generics(ccx,
+                                   subst::TypeSpace,
+                                   &generics.lifetimes,
+                                   &generics.ty_params,
+                                   ty::Generics::empty(),
+                                   &generics.where_clause);
 
     // Something of a hack: use the node id for the trait, also as
     // the node id for the Self type parameter.
@@ -1032,11 +1038,14 @@ fn ty_generics_for_trait(ccx: &CrateCtxt,
 fn ty_generics_for_fn_or_method(ccx: &CrateCtxt,
                                 generics: &ast::Generics,
                                 base_generics: ty::Generics)
-                                -> ty::Generics
-{
+                                -> ty::Generics {
     let early_lifetimes = resolve_lifetime::early_bound_lifetimes(generics);
-    ty_generics(ccx, subst::FnSpace, &early_lifetimes,
-                &generics.ty_params, base_generics)
+    ty_generics(ccx,
+                subst::FnSpace,
+                &early_lifetimes,
+                &generics.ty_params,
+                base_generics,
+                &generics.where_clause)
 }
 
 // Add the Sized bound, unless the type parameter is marked as `Sized?`.
@@ -1080,9 +1089,9 @@ fn ty_generics(ccx: &CrateCtxt,
                space: subst::ParamSpace,
                lifetimes: &Vec<ast::LifetimeDef>,
                types: &OwnedSlice<ast::TyParam>,
-               base_generics: ty::Generics)
-               -> ty::Generics
-{
+               base_generics: ty::Generics,
+               where_clause: &ast::WhereClause)
+               -> ty::Generics {
     let mut result = base_generics;
 
     for (i, l) in lifetimes.iter().enumerate() {
@@ -1095,7 +1104,11 @@ fn ty_generics(ccx: &CrateCtxt,
     }
 
     for (i, param) in types.iter().enumerate() {
-        let def = get_or_create_type_parameter_def(ccx, space, param, i);
+        let def = get_or_create_type_parameter_def(ccx,
+                                                   space,
+                                                   param,
+                                                   i,
+                                                   where_clause);
         debug!("ty_generics: def for type param: {}", def.repr(ccx.tcx));
         result.types.push(space, def);
     }
@@ -1105,9 +1118,9 @@ fn ty_generics(ccx: &CrateCtxt,
     fn get_or_create_type_parameter_def(ccx: &CrateCtxt,
                                         space: subst::ParamSpace,
                                         param: &ast::TyParam,
-                                        index: uint)
-                                        -> ty::TypeParameterDef
-    {
+                                        index: uint,
+                                        where_clause: &ast::WhereClause)
+                                        -> ty::TypeParameterDef {
         match ccx.tcx.ty_param_defs.borrow().find(&param.id) {
             Some(d) => { return (*d).clone(); }
             None => { }
@@ -1121,7 +1134,8 @@ fn ty_generics(ccx: &CrateCtxt,
                                             &param.bounds,
                                             &param.unbound,
                                             param.ident,
-                                            param.span));
+                                            param.span,
+                                            where_clause));
         let default = param.default.map(|path| {
             let ty = ast_ty_to_ty(ccx, &ExplicitRscope, &*path);
             let cur_idx = param_ty.idx;
@@ -1154,14 +1168,14 @@ fn ty_generics(ccx: &CrateCtxt,
         def
     }
 
-    fn compute_bounds(
-        ccx: &CrateCtxt,
-        param_ty: ty::ParamTy,
-        ast_bounds: &OwnedSlice<ast::TyParamBound>,
-        unbound: &Option<ast::TyParamBound>,
-        ident: ast::Ident,
-        span: Span) -> ty::ParamBounds
-    {
+    fn compute_bounds(ccx: &CrateCtxt,
+                      param_ty: ty::ParamTy,
+                      ast_bounds: &OwnedSlice<ast::TyParamBound>,
+                      unbound: &Option<ast::TyParamBound>,
+                      ident: ast::Ident,
+                      span: Span,
+                      where_clause: &ast::WhereClause)
+                      -> ty::ParamBounds {
         /*!
          * Translate the AST's notion of ty param bounds (which are an
          * enum consisting of a newtyped Ty or a region) to ty's
@@ -1174,44 +1188,23 @@ fn ty_generics(ccx: &CrateCtxt,
             trait_bounds: Vec::new()
         };
         for ast_bound in ast_bounds.iter() {
-            match *ast_bound {
-                TraitTyParamBound(ref b) => {
-                    let ty = ty::mk_param(ccx.tcx, param_ty.space,
-                                          param_ty.idx, param_ty.def_id);
-                    let trait_ref = instantiate_trait_ref(ccx, b, ty);
-                    if !ty::try_add_builtin_trait(
-                            ccx.tcx, trait_ref.def_id,
-                            &mut param_bounds.builtin_bounds) {
-                        // Must be a user-defined trait
-                        param_bounds.trait_bounds.push(trait_ref);
-                    }
-                }
-
-                StaticRegionTyParamBound => {
-                    param_bounds.builtin_bounds.add(ty::BoundStatic);
-                }
-
-                UnboxedFnTyParamBound(ref unboxed_function) => {
-                    let rscope = ExplicitRscope;
-                    let self_ty = ty::mk_param(ccx.tcx,
-                                               param_ty.space,
-                                               param_ty.idx,
-                                               param_ty.def_id);
-                    let trait_ref =
-                        astconv::trait_ref_for_unboxed_function(ccx,
-                                                                &rscope,
-                                                                unboxed_function,
-                                                                Some(self_ty));
-                    param_bounds.trait_bounds.push(Rc::new(trait_ref));
-                }
-
-                OtherRegionTyParamBound(span) => {
-                    if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
-                        ccx.tcx.sess.span_err(
-                            span,
-                            "only the 'static lifetime is accepted here.");
-                    }
-                }
+            compute_bound(ccx, &mut param_bounds, param_ty, ast_bound);
+        }
+        for predicate in where_clause.predicates.iter() {
+            let predicate_param_id = ccx.tcx
+                                        .def_map
+                                        .borrow()
+                                        .find(&predicate.id)
+                                        .expect("compute_bounds(): resolve \
+                                                 didn't resolve the type \
+                                                 parameter identifier in a \
+                                                 `where` clause")
+                                        .def_id();
+            if param_ty.def_id != predicate_param_id {
+                continue
+            }
+            for bound in predicate.bounds.iter() {
+                compute_bound(ccx, &mut param_bounds, param_ty, bound);
             }
         }
 
@@ -1228,6 +1221,54 @@ fn ty_generics(ccx: &CrateCtxt,
         param_bounds
     }
 
+    /// Translates the AST's notion of a type parameter bound to
+    /// typechecking's notion of the same, and pushes the resulting bound onto
+    /// the appropriate section of `param_bounds`.
+    fn compute_bound(ccx: &CrateCtxt,
+                     param_bounds: &mut ty::ParamBounds,
+                     param_ty: ty::ParamTy,
+                     ast_bound: &ast::TyParamBound) {
+        match *ast_bound {
+            TraitTyParamBound(ref b) => {
+                let ty = ty::mk_param(ccx.tcx, param_ty.space,
+                                      param_ty.idx, param_ty.def_id);
+                let trait_ref = instantiate_trait_ref(ccx, b, ty);
+                if !ty::try_add_builtin_trait(
+                        ccx.tcx, trait_ref.def_id,
+                        &mut param_bounds.builtin_bounds) {
+                    // Must be a user-defined trait
+                    param_bounds.trait_bounds.push(trait_ref);
+                }
+            }
+
+            StaticRegionTyParamBound => {
+                param_bounds.builtin_bounds.add(ty::BoundStatic);
+            }
+
+            UnboxedFnTyParamBound(ref unboxed_function) => {
+                let rscope = ExplicitRscope;
+                let self_ty = ty::mk_param(ccx.tcx,
+                                           param_ty.space,
+                                           param_ty.idx,
+                                           param_ty.def_id);
+                let trait_ref =
+                    astconv::trait_ref_for_unboxed_function(ccx,
+                                                            &rscope,
+                                                            unboxed_function,
+                                                            Some(self_ty));
+                param_bounds.trait_bounds.push(Rc::new(trait_ref));
+            }
+
+            OtherRegionTyParamBound(span) => {
+                if !ccx.tcx.sess.features.issue_5723_bootstrap.get() {
+                    ccx.tcx.sess.span_err(
+                        span,
+                        "only the 'static lifetime is accepted here.");
+                }
+            }
+        }
+    }
+
     fn check_bounds_compatible(tcx: &ty::ctxt,
                                param_bounds: &ty::ParamBounds,
                                ident: ast::Ident,
diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs
index a4e7f28b450..beaf81409a3 100644
--- a/src/librustc/middle/typeck/infer/error_reporting.rs
+++ b/src/librustc/middle/typeck/infer/error_reporting.rs
@@ -781,6 +781,7 @@ impl<'a> Rebuilder<'a> {
         let mut inputs = self.fn_decl.inputs.clone();
         let mut output = self.fn_decl.output;
         let mut ty_params = self.generics.ty_params.clone();
+        let where_clause = self.generics.where_clause.clone();
         let mut kept_lifetimes = HashSet::new();
         for sr in self.same_regions.iter() {
             self.cur_anon.set(0);
@@ -807,7 +808,8 @@ impl<'a> Rebuilder<'a> {
                                              &fresh_lifetimes,
                                              &kept_lifetimes,
                                              &all_region_names,
-                                             ty_params);
+                                             ty_params,
+                                             where_clause);
         let new_fn_decl = ast::FnDecl {
             inputs: inputs,
             output: output,
@@ -981,7 +983,8 @@ impl<'a> Rebuilder<'a> {
                         add: &Vec<ast::Lifetime>,
                         keep: &HashSet<ast::Name>,
                         remove: &HashSet<ast::Name>,
-                        ty_params: OwnedSlice<ast::TyParam>)
+                        ty_params: OwnedSlice<ast::TyParam>,
+                        where_clause: ast::WhereClause)
                         -> ast::Generics {
         let mut lifetimes = Vec::new();
         for lt in add.iter() {
@@ -990,14 +993,14 @@ impl<'a> Rebuilder<'a> {
         }
         for lt in generics.lifetimes.iter() {
             if keep.contains(&lt.lifetime.name) ||
-                !remove.contains(&lt.lifetime.name)
-            {
+                !remove.contains(&lt.lifetime.name) {
                 lifetimes.push((*lt).clone());
             }
         }
         ast::Generics {
             lifetimes: lifetimes,
-            ty_params: ty_params
+            ty_params: ty_params,
+            where_clause: where_clause,
         }
     }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c5d3c73c9bc..68e1529fb17 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -363,7 +363,7 @@ impl Clean<Item> for doctree::Module {
 
         // determine if we should display the inner contents or
         // the outer `mod` item for the source code.
-        let where = {
+        let whence = {
             let ctxt = super::ctxtkey.get().unwrap();
             let cm = ctxt.sess().codemap();
             let outer = cm.lookup_char_pos(self.where_outer.lo);
@@ -380,7 +380,7 @@ impl Clean<Item> for doctree::Module {
         Item {
             name: Some(name),
             attrs: self.attrs.clean(),
-            source: where.clean(),
+            source: whence.clean(),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
@@ -781,7 +781,7 @@ impl Clean<Item> for doctree::Function {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
@@ -917,7 +917,7 @@ impl Clean<Item> for doctree::Trait {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -1397,7 +1397,7 @@ impl Clean<Item> for doctree::Struct {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -1443,7 +1443,7 @@ impl Clean<Item> for doctree::Enum {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -1466,7 +1466,7 @@ impl Clean<Item> for doctree::Variant {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
@@ -1652,7 +1652,7 @@ impl Clean<Item> for doctree::Typedef {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id.clone()),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -1702,7 +1702,7 @@ impl Clean<Item> for doctree::Static {
         Item {
             name: Some(self.name.clean()),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -1748,7 +1748,7 @@ impl Clean<Item> for doctree::Impl {
         Item {
             name: None,
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             def_id: ast_util::local_def(self.id),
             visibility: self.vis.clean(),
             stability: self.stab.clean(),
@@ -2115,12 +2115,12 @@ impl Clean<Item> for doctree::Macro {
         Item {
             name: Some(format!("{}!", self.name.clean())),
             attrs: self.attrs.clean(),
-            source: self.where.clean(),
+            source: self.whence.clean(),
             visibility: ast::Public.clean(),
             stability: self.stab.clean(),
             def_id: ast_util::local_def(self.id),
             inner: MacroItem(Macro {
-                source: self.where.to_src(),
+                source: self.whence.to_src(),
             }),
         }
     }
diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs
index a5ead46384a..da45321e7fd 100644
--- a/src/librustdoc/doctree.rs
+++ b/src/librustdoc/doctree.rs
@@ -93,7 +93,7 @@ pub struct Struct {
     pub generics: ast::Generics,
     pub attrs: Vec<ast::Attribute>,
     pub fields: Vec<ast::StructField>,
-    pub where: Span,
+    pub whence: Span,
 }
 
 pub struct Enum {
@@ -103,7 +103,7 @@ pub struct Enum {
     pub generics: ast::Generics,
     pub attrs: Vec<ast::Attribute>,
     pub id: NodeId,
-    pub where: Span,
+    pub whence: Span,
     pub name: Ident,
 }
 
@@ -114,7 +114,7 @@ pub struct Variant {
     pub id: ast::NodeId,
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
-    pub where: Span,
+    pub whence: Span,
 }
 
 pub struct Function {
@@ -125,7 +125,7 @@ pub struct Function {
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
     pub fn_style: ast::FnStyle,
-    pub where: Span,
+    pub whence: Span,
     pub generics: ast::Generics,
 }
 
@@ -135,7 +135,7 @@ pub struct Typedef {
     pub name: Ident,
     pub id: ast::NodeId,
     pub attrs: Vec<ast::Attribute>,
-    pub where: Span,
+    pub whence: Span,
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
 }
@@ -149,7 +149,7 @@ pub struct Static {
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
     pub id: ast::NodeId,
-    pub where: Span,
+    pub whence: Span,
 }
 
 pub struct Trait {
@@ -159,7 +159,7 @@ pub struct Trait {
     pub parents: Vec<ast::TraitRef>,
     pub attrs: Vec<ast::Attribute>,
     pub id: ast::NodeId,
-    pub where: Span,
+    pub whence: Span,
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
 }
@@ -170,7 +170,7 @@ pub struct Impl {
     pub for_: ast::P<ast::Ty>,
     pub items: Vec<ast::ImplItem>,
     pub attrs: Vec<ast::Attribute>,
-    pub where: Span,
+    pub whence: Span,
     pub vis: ast::Visibility,
     pub stab: Option<attr::Stability>,
     pub id: ast::NodeId,
@@ -180,7 +180,7 @@ pub struct Macro {
     pub name: Ident,
     pub id: ast::NodeId,
     pub attrs: Vec<ast::Attribute>,
-    pub where: Span,
+    pub whence: Span,
     pub stab: Option<attr::Stability>,
 }
 
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index f7ccad79fda..b67b3c394d6 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -91,7 +91,7 @@ impl<'a> RustdocVisitor<'a> {
             attrs: item.attrs.iter().map(|x| *x).collect(),
             generics: generics.clone(),
             fields: sd.fields.iter().map(|x| (*x).clone()).collect(),
-            where: item.span
+            whence: item.span
         }
     }
 
@@ -107,7 +107,7 @@ impl<'a> RustdocVisitor<'a> {
                 stab: self.stability(x.node.id),
                 id: x.node.id,
                 kind: x.node.kind.clone(),
-                where: x.span,
+                whence: x.span,
             });
         }
         Enum {
@@ -118,7 +118,7 @@ impl<'a> RustdocVisitor<'a> {
             generics: params.clone(),
             attrs: it.attrs.iter().map(|x| *x).collect(),
             id: it.id,
-            where: it.span,
+            whence: it.span,
         }
     }
 
@@ -133,7 +133,7 @@ impl<'a> RustdocVisitor<'a> {
             attrs: item.attrs.iter().map(|x| *x).collect(),
             decl: fd.clone(),
             name: item.ident,
-            where: item.span,
+            whence: item.span,
             generics: gen.clone(),
             fn_style: *fn_style,
         }
@@ -297,7 +297,7 @@ impl<'a> RustdocVisitor<'a> {
                     name: item.ident,
                     id: item.id,
                     attrs: item.attrs.iter().map(|x| *x).collect(),
-                    where: item.span,
+                    whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
                 };
@@ -311,7 +311,7 @@ impl<'a> RustdocVisitor<'a> {
                     id: item.id,
                     name: item.ident,
                     attrs: item.attrs.iter().map(|x| *x).collect(),
-                    where: item.span,
+                    whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
                 };
@@ -325,7 +325,7 @@ impl<'a> RustdocVisitor<'a> {
                     parents: tr.iter().map(|x| (*x).clone()).collect(),
                     id: item.id,
                     attrs: item.attrs.iter().map(|x| *x).collect(),
-                    where: item.span,
+                    whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
                 };
@@ -339,7 +339,7 @@ impl<'a> RustdocVisitor<'a> {
                     items: items.iter().map(|x| *x).collect(),
                     attrs: item.attrs.iter().map(|x| *x).collect(),
                     id: item.id,
-                    where: item.span,
+                    whence: item.span,
                     vis: item.vis,
                     stab: self.stability(item.id),
                 };
@@ -360,7 +360,7 @@ impl<'a> RustdocVisitor<'a> {
             id: item.id,
             attrs: item.attrs.iter().map(|x| *x).collect(),
             name: item.ident,
-            where: item.span,
+            whence: item.span,
             stab: self.stability(item.id),
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 1ff8ca10fff..c658a5c3192 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -245,6 +245,7 @@ pub struct TyParam {
 pub struct Generics {
     pub lifetimes: Vec<LifetimeDef>,
     pub ty_params: OwnedSlice<TyParam>,
+    pub where_clause: WhereClause,
 }
 
 impl Generics {
@@ -259,9 +260,23 @@ impl Generics {
     }
 }
 
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct WhereClause {
+    pub id: NodeId,
+    pub predicates: Vec<WherePredicate>,
+}
+
+#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
+pub struct WherePredicate {
+    pub id: NodeId,
+    pub span: Span,
+    pub ident: Ident,
+    pub bounds: OwnedSlice<TyParamBound>,
+}
+
 /// The set of MetaItems that define the compilation environment of the crate,
 /// used to drive conditional compilation
-pub type CrateConfig = Vec<Gc<MetaItem>> ;
+pub type CrateConfig = Vec<Gc<MetaItem>>;
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
 pub struct Crate {
diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs
index 78afa8441c5..5fccf6cc3f0 100644
--- a/src/libsyntax/ast_map/mod.rs
+++ b/src/libsyntax/ast_map/mod.rs
@@ -431,11 +431,14 @@ impl Map {
     /// the iterator will produce node id's for items with paths
     /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and
     /// any other such items it can find in the map.
-    pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S]) -> NodesMatchingSuffix<'a,S> {
-        NodesMatchingSuffix { map: self,
-                              item_name: parts.last().unwrap(),
-                              where: parts.slice_to(parts.len() - 1),
-                              idx: 0 }
+    pub fn nodes_matching_suffix<'a, S:Str>(&'a self, parts: &'a [S])
+                                 -> NodesMatchingSuffix<'a,S> {
+        NodesMatchingSuffix {
+            map: self,
+            item_name: parts.last().unwrap(),
+            in_which: parts.slice_to(parts.len() - 1),
+            idx: 0,
+        }
     }
 
     pub fn opt_span(&self, id: NodeId) -> Option<Span> {
@@ -478,20 +481,20 @@ impl Map {
 pub struct NodesMatchingSuffix<'a, S> {
     map: &'a Map,
     item_name: &'a S,
-    where: &'a [S],
+    in_which: &'a [S],
     idx: NodeId,
 }
 
 impl<'a,S:Str> NodesMatchingSuffix<'a,S> {
     /// Returns true only if some suffix of the module path for parent
-    /// matches `self.where`.
+    /// matches `self.in_which`.
     ///
-    /// In other words: let `[x_0,x_1,...,x_k]` be `self.where`;
+    /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`;
     /// returns true if parent's path ends with the suffix
     /// `x_0::x_1::...::x_k`.
     fn suffix_matches(&self, parent: NodeId) -> bool {
         let mut cursor = parent;
-        for part in self.where.iter().rev() {
+        for part in self.in_which.iter().rev() {
             let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) {
                 None => return false,
                 Some((node_id, name)) => (node_id, name),
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 7689646d373..5674c6675f9 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -320,8 +320,14 @@ pub fn operator_prec(op: ast::BinOp) -> uint {
 pub static as_prec: uint = 12u;
 
 pub fn empty_generics() -> Generics {
-    Generics {lifetimes: Vec::new(),
-              ty_params: OwnedSlice::empty()}
+    Generics {
+        lifetimes: Vec::new(),
+        ty_params: OwnedSlice::empty(),
+        where_clause: WhereClause {
+            id: DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        }
+    }
 }
 
 // ______________________________________________________________________
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 7a8ee6d1416..f9f2a86d182 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -390,7 +390,7 @@ impl<'a> TraitDef<'a> {
                            methods: Vec<Gc<ast::Method>> ) -> Gc<ast::Item> {
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
-        let Generics { mut lifetimes, ty_params } =
+        let Generics { mut lifetimes, ty_params, where_clause: _ } =
             self.generics.to_generics(cx, self.span, type_ident, generics);
         let mut ty_params = ty_params.into_vec();
 
@@ -418,7 +418,11 @@ impl<'a> TraitDef<'a> {
         }));
         let trait_generics = Generics {
             lifetimes: lifetimes,
-            ty_params: OwnedSlice::from_vec(ty_params)
+            ty_params: OwnedSlice::from_vec(ty_params),
+            where_clause: ast::WhereClause {
+                id: ast::DUMMY_NODE_ID,
+                predicates: Vec::new(),
+            },
         };
 
         // Create the reference to the trait.
diff --git a/src/libsyntax/ext/deriving/generic/ty.rs b/src/libsyntax/ext/deriving/generic/ty.rs
index 2130b6f4e9d..f4a9b85f75d 100644
--- a/src/libsyntax/ext/deriving/generic/ty.rs
+++ b/src/libsyntax/ext/deriving/generic/ty.rs
@@ -202,10 +202,15 @@ fn mk_ty_param(cx: &ExtCtxt, span: Span, name: &str,
     cx.typaram(span, cx.ident_of(name), bounds, unbound, None)
 }
 
-fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam> ) -> Generics {
+fn mk_generics(lifetimes: Vec<ast::LifetimeDef>, ty_params: Vec<ast::TyParam>)
+               -> Generics {
     Generics {
         lifetimes: lifetimes,
-        ty_params: OwnedSlice::from_vec(ty_params)
+        ty_params: OwnedSlice::from_vec(ty_params),
+        where_clause: ast::WhereClause {
+            id: ast::DUMMY_NODE_ID,
+            predicates: Vec::new(),
+        },
     }
 }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 4ed2a3ed4c2..9ad28f02e80 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -244,6 +244,16 @@ pub trait Folder {
         noop_fold_field(field, self)
     }
 
+    fn fold_where_clause(&mut self, where_clause: &WhereClause)
+                         -> WhereClause {
+        noop_fold_where_clause(where_clause, self)
+    }
+
+    fn fold_where_predicate(&mut self, where_predicate: &WherePredicate)
+                            -> WherePredicate {
+        noop_fold_where_predicate(where_predicate, self)
+    }
+
 // Helper methods:
 
     fn map_exprs(&self, f: |Gc<Expr>| -> Gc<Expr>,
@@ -698,8 +708,37 @@ pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: &Option<Lifetime>, fld: &mut T)
 }
 
 pub fn noop_fold_generics<T: Folder>(generics: &Generics, fld: &mut T) -> Generics {
-    Generics {ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
-              lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice())}
+    Generics {
+        ty_params: fld.fold_ty_params(generics.ty_params.as_slice()),
+        lifetimes: fld.fold_lifetime_defs(generics.lifetimes.as_slice()),
+        where_clause: fld.fold_where_clause(&generics.where_clause),
+    }
+}
+
+pub fn noop_fold_where_clause<T: Folder>(
+                              where_clause: &WhereClause,
+                              fld: &mut T)
+                              -> WhereClause {
+    WhereClause {
+        id: fld.new_id(where_clause.id),
+        predicates: where_clause.predicates.iter().map(|predicate| {
+            fld.fold_where_predicate(predicate)
+        }).collect(),
+    }
+}
+
+pub fn noop_fold_where_predicate<T: Folder>(
+                                 predicate: &WherePredicate,
+                                 fld: &mut T)
+                                 -> WherePredicate {
+    WherePredicate {
+        id: fld.new_id(predicate.id),
+        span: fld.new_span(predicate.span),
+        ident: fld.fold_ident(predicate.ident),
+        bounds: predicate.bounds.map(|x| {
+            fld.fold_ty_param_bound(x)
+        }),
+    }
 }
 
 pub fn noop_fold_struct_def<T: Folder>(struct_def: Gc<StructDef>,
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index e5275af5cca..17249628989 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -543,7 +543,7 @@ impl<'a> StringReader<'a> {
     // favors rustc debugging effectiveness over runtime efficiency.
 
     /// Scan through input of form \x00name_NNNNNN,ctxt_CCCCCCC\x00
-    /// where: `NNNNNN` is a string of characters forming an integer
+    /// whence: `NNNNNN` is a string of characters forming an integer
     /// (the name) and `CCCCCCC` is a string of characters forming an
     /// integer (the ctxt), separate by a comma and delimited by a
     /// `\x00` marker.
@@ -552,22 +552,22 @@ impl<'a> StringReader<'a> {
         fn bump_expecting_char<'a,D:fmt::Show>(r: &mut StringReader<'a>,
                                                c: char,
                                                described_c: D,
-                                               where: &str) {
+                                               whence: &str) {
             match r.curr {
                 Some(r_c) if r_c == c => r.bump(),
-                Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, where),
-                None      => fail!("expected {}, hit EOF, {}", described_c, where),
+                Some(r_c) => fail!("expected {}, hit {}, {}", described_c, r_c, whence),
+                None      => fail!("expected {}, hit EOF, {}", described_c, whence),
             }
         }
 
-        let where = "while scanning embedded hygienic ident";
+        let whence = "while scanning embedded hygienic ident";
 
         // skip over the leading `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", where);
+        bump_expecting_char(self, '\x00', "nul-byte", whence);
 
         // skip over the "name_"
         for c in "name_".chars() {
-            bump_expecting_char(self, c, c, where);
+            bump_expecting_char(self, c, c, whence);
         }
 
         let start_bpos = self.last_pos;
@@ -578,16 +578,16 @@ impl<'a> StringReader<'a> {
         let encoded_name : u32 = self.with_str_from(start_bpos, |s| {
             num::from_str_radix(s, 10).unwrap_or_else(|| {
                 fail!("expected digits representing a name, got `{}`, {}, range [{},{}]",
-                      s, where, start_bpos, self.last_pos);
+                      s, whence, start_bpos, self.last_pos);
             })
         });
 
         // skip over the `,`
-        bump_expecting_char(self, ',', "comma", where);
+        bump_expecting_char(self, ',', "comma", whence);
 
         // skip over the "ctxt_"
         for c in "ctxt_".chars() {
-            bump_expecting_char(self, c, c, where);
+            bump_expecting_char(self, c, c, whence);
         }
 
         // find the integer representing the ctxt
@@ -595,12 +595,12 @@ impl<'a> StringReader<'a> {
         self.scan_digits(base);
         let encoded_ctxt : ast::SyntaxContext = self.with_str_from(start_bpos, |s| {
             num::from_str_radix(s, 10).unwrap_or_else(|| {
-                fail!("expected digits representing a ctxt, got `{}`, {}", s, where);
+                fail!("expected digits representing a ctxt, got `{}`, {}", s, whence);
             })
         });
 
         // skip over the `\x00`
-        bump_expecting_char(self, '\x00', "nul-byte", where);
+        bump_expecting_char(self, '\x00', "nul-byte", whence);
 
         ast::Ident { name: ast::Name(encoded_name),
                      ctxt: encoded_ctxt, }
diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs
index af1f296a6ca..271cefeaf03 100644
--- a/src/libsyntax/parse/mod.rs
+++ b/src/libsyntax/parse/mod.rs
@@ -1053,6 +1053,10 @@ mod test {
                                     ast::Generics{ // no idea on either of these:
                                         lifetimes: Vec::new(),
                                         ty_params: OwnedSlice::empty(),
+                                        where_clause: ast::WhereClause {
+                                            id: ast::DUMMY_NODE_ID,
+                                            predicates: Vec::new(),
+                                        }
                                     },
                                     ast::P(ast::Block {
                                         view_items: Vec::new(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index f272f7e1887..577959ea36a 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -60,7 +60,7 @@ use ast::{UnboxedClosureKind, UnboxedFnTy, UnboxedFnTyParamBound};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
-use ast::Visibility;
+use ast::{Visibility, WhereClause, WherePredicate};
 use ast;
 use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
 use ast_util;
@@ -1264,7 +1264,7 @@ impl<'a> Parser<'a> {
             let style = p.parse_fn_style();
             let ident = p.parse_ident();
 
-            let generics = p.parse_generics();
+            let mut generics = p.parse_generics();
 
             let (explicit_self, d) = p.parse_fn_decl_with_self(|p| {
                 // This is somewhat dubious; We don't want to allow argument
@@ -1272,6 +1272,8 @@ impl<'a> Parser<'a> {
                 p.parse_arg_general(false)
             });
 
+            p.parse_where_clause(&mut generics);
+
             let hi = p.last_span.hi;
             match p.token {
               token::SEMI => {
@@ -3742,7 +3744,10 @@ impl<'a> Parser<'a> {
         }
     }
 
-    /// Parse a set of optional generic type parameter declarations
+    /// Parse a set of optional generic type parameter declarations. Where
+    /// clauses are not parsed here, and must be added later via
+    /// `parse_where_clause()`.
+    ///
     /// matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > )
     ///                  | ( < lifetimes , typaramseq ( , )? > )
     /// where   typaramseq = ( typaram ) | ( typaram , typaramseq )
@@ -3762,7 +3767,14 @@ impl<'a> Parser<'a> {
                 }
                 ty_param
             });
-            ast::Generics { lifetimes: lifetime_defs, ty_params: ty_params }
+            ast::Generics {
+                lifetimes: lifetime_defs,
+                ty_params: ty_params,
+                where_clause: WhereClause {
+                    id: ast::DUMMY_NODE_ID,
+                    predicates: Vec::new(),
+                }
+            }
         } else {
             ast_util::empty_generics()
         }
@@ -3788,6 +3800,52 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Parses an optional `where` clause and places it in `generics`.
+    fn parse_where_clause(&mut self, generics: &mut ast::Generics) {
+        if !self.eat_keyword(keywords::Where) {
+            return
+        }
+
+        let mut parsed_something = false;
+        loop {
+            let lo = self.span.lo;
+            let ident = match self.token {
+                token::IDENT(..) => self.parse_ident(),
+                _ => break,
+            };
+            self.expect(&token::COLON);
+
+            let (_, bounds) = self.parse_ty_param_bounds(false);
+            let hi = self.span.hi;
+            let span = mk_sp(lo, hi);
+
+            if bounds.len() == 0 {
+                self.span_err(span,
+                              "each predicate in a `where` clause must have \
+                               at least one bound in it");
+            }
+
+            generics.where_clause.predicates.push(ast::WherePredicate {
+                id: ast::DUMMY_NODE_ID,
+                span: span,
+                ident: ident,
+                bounds: bounds,
+            });
+            parsed_something = true;
+
+            if !self.eat(&token::COMMA) {
+                break
+            }
+        }
+
+        if !parsed_something {
+            let last_span = self.last_span;
+            self.span_err(last_span,
+                          "a `where` clause must have at least one predicate \
+                           in it");
+        }
+    }
+
     fn parse_fn_args(&mut self, named_args: bool, allow_variadic: bool)
                      -> (Vec<Arg> , bool) {
         let sp = self.span;
@@ -4143,8 +4201,9 @@ impl<'a> Parser<'a> {
 
     /// Parse an item-position function declaration.
     fn parse_item_fn(&mut self, fn_style: FnStyle, abi: abi::Abi) -> ItemInfo {
-        let (ident, generics) = self.parse_fn_header();
+        let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(false);
+        self.parse_where_clause(&mut generics);
         let (inner_attrs, body) = self.parse_inner_attrs_and_block();
         (ident, ItemFn(decl, fn_style, abi, generics, body), Some(inner_attrs))
     }
@@ -4200,10 +4259,11 @@ impl<'a> Parser<'a> {
                 };
                 let fn_style = self.parse_fn_style();
                 let ident = self.parse_ident();
-                let generics = self.parse_generics();
+                let mut generics = self.parse_generics();
                 let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| {
                         p.parse_arg()
                     });
+                self.parse_where_clause(&mut generics);
                 let (inner_attrs, body) = self.parse_inner_attrs_and_block();
                 let new_attrs = attrs.append(inner_attrs.as_slice());
                 (ast::MethDecl(ident,
@@ -4228,7 +4288,7 @@ impl<'a> Parser<'a> {
     /// Parse trait Foo { ... }
     fn parse_item_trait(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
-        let tps = self.parse_generics();
+        let mut tps = self.parse_generics();
         let sized = self.parse_for_sized();
 
         // Parse traits, if necessary.
@@ -4240,6 +4300,8 @@ impl<'a> Parser<'a> {
             traits = Vec::new();
         }
 
+        self.parse_where_clause(&mut tps);
+
         let meths = self.parse_trait_methods();
         (ident, ItemTrait(tps, sized, traits, meths), None)
     }
@@ -4261,7 +4323,7 @@ impl<'a> Parser<'a> {
     ///    impl<T> ToString for ~[T] { ... }
     fn parse_item_impl(&mut self) -> ItemInfo {
         // First, parse type parameters if necessary.
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
 
         // Special case: if the next identifier that follows is '(', don't
         // allow this to be parsed as a trait.
@@ -4297,6 +4359,7 @@ impl<'a> Parser<'a> {
             None
         };
 
+        self.parse_where_clause(&mut generics);
         let (impl_items, attrs) = self.parse_impl_items();
 
         let ident = ast_util::impl_pretty_name(&opt_trait, &*ty);
@@ -4326,7 +4389,7 @@ impl<'a> Parser<'a> {
     /// Parse struct Foo { ... }
     fn parse_item_struct(&mut self, is_virtual: bool) -> ItemInfo {
         let class_name = self.parse_ident();
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
 
         let super_struct = if self.eat(&token::COLON) {
             let ty = self.parse_ty(true);
@@ -4343,6 +4406,8 @@ impl<'a> Parser<'a> {
             None
         };
 
+        self.parse_where_clause(&mut generics);
+
         let mut fields: Vec<StructField>;
         let is_tuple_like;
 
@@ -4683,8 +4748,9 @@ impl<'a> Parser<'a> {
         let lo = self.span.lo;
         self.expect_keyword(keywords::Fn);
 
-        let (ident, generics) = self.parse_fn_header();
+        let (ident, mut generics) = self.parse_fn_header();
         let decl = self.parse_fn_decl(true);
+        self.parse_where_clause(&mut generics);
         let hi = self.span.hi;
         self.expect(&token::SEMI);
         box(GC) ast::ForeignItem { ident: ident,
@@ -4834,7 +4900,8 @@ impl<'a> Parser<'a> {
     /// Parse type Foo = Bar;
     fn parse_item_type(&mut self) -> ItemInfo {
         let ident = self.parse_ident();
-        let tps = self.parse_generics();
+        let mut tps = self.parse_generics();
+        self.parse_where_clause(&mut tps);
         self.expect(&token::EQ);
         let ty = self.parse_ty(true);
         self.expect(&token::SEMI);
@@ -4925,7 +4992,8 @@ impl<'a> Parser<'a> {
     /// Parse an "enum" declaration
     fn parse_item_enum(&mut self) -> ItemInfo {
         let id = self.parse_ident();
-        let generics = self.parse_generics();
+        let mut generics = self.parse_generics();
+        self.parse_where_clause(&mut generics);
         self.expect(&token::LBRACE);
 
         let enum_definition = self.parse_enum_def(&generics);
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index f1ef7980151..4c959932f41 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -499,18 +499,19 @@ declare_special_idents_and_keywords! {
         (41,                         Proc,       "proc");
         (42,                         Box,        "box");
         (43,                         Const,      "const");
+        (44,                         Where,      "where");
 
         'reserved:
-        (44,                         Alignof,    "alignof");
-        (45,                         Be,         "be");
-        (46,                         Offsetof,   "offsetof");
-        (47,                         Priv,       "priv");
-        (48,                         Pure,       "pure");
-        (49,                         Sizeof,     "sizeof");
-        (50,                         Typeof,     "typeof");
-        (51,                         Unsized,    "unsized");
-        (52,                         Yield,      "yield");
-        (53,                         Do,         "do");
+        (45,                         Alignof,    "alignof");
+        (46,                         Be,         "be");
+        (47,                         Offsetof,   "offsetof");
+        (48,                         Priv,       "priv");
+        (49,                         Pure,       "pure");
+        (50,                         Sizeof,     "sizeof");
+        (51,                         Typeof,     "typeof");
+        (52,                         Unsized,    "unsized");
+        (53,                         Yield,      "yield");
+        (54,                         Do,         "do");
     }
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index c573cc0c0ad..998049b83cc 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -584,7 +584,11 @@ impl<'a> State<'a> {
             ast::TyBareFn(f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(Some(f.abi),
                                       None,
@@ -601,7 +605,11 @@ impl<'a> State<'a> {
             ast::TyClosure(f, ref region) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(None,
                                       Some('&'),
@@ -618,7 +626,11 @@ impl<'a> State<'a> {
             ast::TyProc(ref f) => {
                 let generics = ast::Generics {
                     lifetimes: f.lifetimes.clone(),
-                    ty_params: OwnedSlice::empty()
+                    ty_params: OwnedSlice::empty(),
+                    where_clause: ast::WhereClause {
+                        id: ast::DUMMY_NODE_ID,
+                        predicates: Vec::new(),
+                    },
                 };
                 try!(self.print_ty_fn(None,
                                       Some('~'),
@@ -765,6 +777,7 @@ impl<'a> State<'a> {
                 try!(space(&mut self.s));
                 try!(self.word_space("="));
                 try!(self.print_type(&**ty));
+                try!(self.print_where_clause(params));
                 try!(word(&mut self.s, ";"));
                 try!(self.end()); // end the outer ibox
             }
@@ -808,6 +821,7 @@ impl<'a> State<'a> {
                 }
 
                 try!(self.print_type(&**ty));
+                try!(self.print_where_clause(generics));
 
                 try!(space(&mut self.s));
                 try!(self.bopen());
@@ -845,6 +859,7 @@ impl<'a> State<'a> {
                         try!(self.print_path(&trait_.path, false));
                     }
                 }
+                try!(self.print_where_clause(generics));
                 try!(word(&mut self.s, " "));
                 try!(self.bopen());
                 for meth in methods.iter() {
@@ -880,6 +895,7 @@ impl<'a> State<'a> {
         try!(self.head(visibility_qualified(visibility, "enum").as_slice()));
         try!(self.print_ident(ident));
         try!(self.print_generics(generics));
+        try!(self.print_where_clause(generics));
         try!(space(&mut self.s));
         self.print_variants(enum_definition.variants.as_slice(), span)
     }
@@ -2010,7 +2026,8 @@ impl<'a> State<'a> {
         try!(self.nbsp());
         try!(self.print_ident(name));
         try!(self.print_generics(generics));
-        self.print_fn_args_and_ret(decl, opt_explicit_self)
+        try!(self.print_fn_args_and_ret(decl, opt_explicit_self))
+        self.print_where_clause(generics)
     }
 
     pub fn print_fn_args(&mut self, decl: &ast::FnDecl,
@@ -2201,54 +2218,83 @@ impl<'a> State<'a> {
         Ok(())
     }
 
-    pub fn print_generics(&mut self,
-                          generics: &ast::Generics) -> IoResult<()> {
-        let total = generics.lifetimes.len() + generics.ty_params.len();
-        if total > 0 {
-            try!(word(&mut self.s, "<"));
+    fn print_type_parameters(&mut self,
+                             lifetimes: &[ast::LifetimeDef],
+                             ty_params: &[ast::TyParam])
+                             -> IoResult<()> {
+        let total = lifetimes.len() + ty_params.len();
+        let mut ints = Vec::new();
+        for i in range(0u, total) {
+            ints.push(i);
+        }
 
-            let mut ints = Vec::new();
-            for i in range(0u, total) {
-                ints.push(i);
-            }
-
-            try!(self.commasep(
-                Inconsistent, ints.as_slice(),
-                |s, &idx| {
-                    if idx < generics.lifetimes.len() {
-                        let lifetime = generics.lifetimes.get(idx);
-                        s.print_lifetime_def(lifetime)
-                    } else {
-                        let idx = idx - generics.lifetimes.len();
-                        let param = generics.ty_params.get(idx);
-                        match param.unbound {
-                            Some(TraitTyParamBound(ref tref)) => {
-                                try!(s.print_trait_ref(tref));
-                                try!(s.word_space("?"));
-                            }
-                            _ => {}
-                        }
-                        try!(s.print_ident(param.ident));
-                        try!(s.print_bounds(&None,
-                                            &param.bounds,
-                                            false,
-                                            false));
-                        match param.default {
-                            Some(ref default) => {
-                                try!(space(&mut s.s));
-                                try!(s.word_space("="));
-                                s.print_type(&**default)
-                            }
-                            _ => Ok(())
-                        }
+        self.commasep(Inconsistent, ints.as_slice(), |s, &idx| {
+            if idx < lifetimes.len() {
+                let lifetime = &lifetimes[idx];
+                s.print_lifetime_def(lifetime)
+            } else {
+                let idx = idx - lifetimes.len();
+                let param = &ty_params[idx];
+                match param.unbound {
+                    Some(TraitTyParamBound(ref tref)) => {
+                        try!(s.print_trait_ref(tref));
+                        try!(s.word_space("?"));
                     }
-                }));
+                    _ => {}
+                }
+                try!(s.print_ident(param.ident));
+                try!(s.print_bounds(&None,
+                                    &param.bounds,
+                                    false,
+                                    false));
+                match param.default {
+                    Some(ref default) => {
+                        try!(space(&mut s.s));
+                        try!(s.word_space("="));
+                        s.print_type(&**default)
+                    }
+                    _ => Ok(())
+                }
+            }
+        })
+    }
+
+    pub fn print_generics(&mut self, generics: &ast::Generics)
+                          -> IoResult<()> {
+        if generics.lifetimes.len() + generics.ty_params.len() > 0 {
+            try!(word(&mut self.s, "<"));
+            try!(self.print_type_parameters(generics.lifetimes.as_slice(),
+                                            generics.ty_params.as_slice()));
             word(&mut self.s, ">")
         } else {
             Ok(())
         }
     }
 
+    pub fn print_where_clause(&mut self, generics: &ast::Generics)
+                              -> IoResult<()> {
+        if generics.where_clause.predicates.len() == 0 {
+            return Ok(())
+        }
+
+        try!(space(&mut self.s));
+        try!(self.word_space("where"));
+
+        for (i, predicate) in generics.where_clause
+                                      .predicates
+                                      .iter()
+                                      .enumerate() {
+            if i != 0 {
+                try!(self.word_space(","));
+            }
+
+            try!(self.print_ident(predicate.ident));
+            try!(self.print_bounds(&None, &predicate.bounds, false, false));
+        }
+
+        Ok(())
+    }
+
     pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> IoResult<()> {
         try!(self.ibox(indent_unit));
         match item.node {
@@ -2472,6 +2518,11 @@ impl<'a> State<'a> {
             }
         }
 
+        match generics {
+            Some(generics) => try!(self.print_where_clause(generics)),
+            None => {}
+        }
+
         self.end()
     }
 
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 18cbf797d03..ac1dbdc439c 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -27,6 +27,7 @@
 use abi::Abi;
 use ast::*;
 use ast;
+use ast_util;
 use codemap::Span;
 use parse;
 use owned_slice::OwnedSlice;
@@ -58,12 +59,7 @@ pub fn generics_of_fn(fk: &FnKind) -> Generics {
         FkMethod(_, generics, _) => {
             (*generics).clone()
         }
-        FkFnBlock(..) => {
-            Generics {
-                lifetimes: Vec::new(),
-                ty_params: OwnedSlice::empty(),
-            }
-        }
+        FkFnBlock(..) => ast_util::empty_generics(),
     }
 }
 
@@ -559,7 +555,11 @@ pub fn walk_generics<E: Clone, V: Visitor<E>>(visitor: &mut V,
             None => {}
         }
     }
-    walk_lifetime_decls(visitor, &generics.lifetimes, env);
+    walk_lifetime_decls(visitor, &generics.lifetimes, env.clone());
+    for predicate in generics.where_clause.predicates.iter() {
+        visitor.visit_ident(predicate.span, predicate.ident, env.clone());
+        walk_ty_param_bounds(visitor, &predicate.bounds, env.clone());
+    }
 }
 
 pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,
diff --git a/src/test/auxiliary/where_clauses_xc.rs b/src/test/auxiliary/where_clauses_xc.rs
new file mode 100644
index 00000000000..002b31f099f
--- /dev/null
+++ b/src/test/auxiliary/where_clauses_xc.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 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.
+
+pub trait Equal {
+    fn equal(&self, other: &Self) -> bool;
+    fn equals<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
+            where T: Eq, U: Eq;
+}
+
+impl<T> Equal for T where T: Eq {
+    fn equal(&self, other: &T) -> bool {
+        self == other
+    }
+    fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
+            where U: Eq, X: Eq {
+        this == other && x == y
+    }
+}
+
+pub fn equal<T>(x: &T, y: &T) -> bool where T: Eq {
+    x == y
+}
+
diff --git a/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs b/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs
new file mode 100644
index 00000000000..b96c7c2de6b
--- /dev/null
+++ b/src/test/compile-fail/where-clauses-no-bounds-or-predicates.rs
@@ -0,0 +1,23 @@
+// Copyright 2014 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.
+
+fn equal1<T>(_: &T, _: &T) -> bool where {
+//~^ ERROR a `where` clause must have at least one predicate in it
+    true
+}
+
+fn equal2<T>(_: &T, _: &T) -> bool where T: {
+//~^ ERROR each predicate in a `where` clause must have at least one bound
+    true
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/where-clauses-not-parameter.rs b/src/test/compile-fail/where-clauses-not-parameter.rs
new file mode 100644
index 00000000000..2817aa16e8e
--- /dev/null
+++ b/src/test/compile-fail/where-clauses-not-parameter.rs
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+fn equal<T>(_: &T, _: &T) -> bool where int : Eq {
+    //~^ ERROR undeclared type parameter
+}
+
+fn main() {
+}
+
diff --git a/src/test/compile-fail/where-clauses-unsatisfied.rs b/src/test/compile-fail/where-clauses-unsatisfied.rs
new file mode 100644
index 00000000000..1d21313975f
--- /dev/null
+++ b/src/test/compile-fail/where-clauses-unsatisfied.rs
@@ -0,0 +1,20 @@
+// Copyright 2014 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.
+
+fn equal<T>(_: &T, _: &T) -> bool where T : Eq {
+}
+
+struct Struct;
+
+fn main() {
+    equal(&Struct, &Struct)
+    //~^ ERROR failed to find an implementation of trait
+}
+
diff --git a/src/test/run-pass/where-clauses-cross-crate.rs b/src/test/run-pass/where-clauses-cross-crate.rs
new file mode 100644
index 00000000000..648f646b637
--- /dev/null
+++ b/src/test/run-pass/where-clauses-cross-crate.rs
@@ -0,0 +1,23 @@
+// Copyright 2014 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.
+
+// aux-build:where_clauses_xc.rs
+
+extern crate where_clauses_xc;
+
+use where_clauses_xc::{Equal, equal};
+
+fn main() {
+    println!("{}", equal(&1i, &2i));
+    println!("{}", equal(&1i, &1i));
+    println!("{}", "hello".equal(&"hello"));
+    println!("{}", "hello".equals::<int,&str>(&1i, &1i, &"foo", &"bar"));
+}
+
diff --git a/src/test/run-pass/where-clauses.rs b/src/test/run-pass/where-clauses.rs
new file mode 100644
index 00000000000..807d95691f4
--- /dev/null
+++ b/src/test/run-pass/where-clauses.rs
@@ -0,0 +1,37 @@
+// Copyright 2014 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.
+
+trait Equal {
+    fn equal(&self, other: &Self) -> bool;
+    fn equals<T,U>(&self, this: &T, that: &T, x: &U, y: &U) -> bool
+            where T: Eq, U: Eq;
+}
+
+impl<T> Equal for T where T: Eq {
+    fn equal(&self, other: &T) -> bool {
+        self == other
+    }
+    fn equals<U,X>(&self, this: &U, other: &U, x: &X, y: &X) -> bool
+            where U: Eq, X: Eq {
+        this == other && x == y
+    }
+}
+
+fn equal<T>(x: &T, y: &T) -> bool where T: Eq {
+    x == y
+}
+
+fn main() {
+    println!("{}", equal(&1i, &2i));
+    println!("{}", equal(&1i, &1i));
+    println!("{}", "hello".equal(&"hello"));
+    println!("{}", "hello".equals::<int,&str>(&1i, &1i, &"foo", &"bar"));
+}
+