about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-05-05 08:47:04 -0400
committerNiko Matsakis <niko@alum.mit.edu>2015-05-21 11:47:30 -0400
commitdf93deab10850d52252829770895b0249b0d7f1e (patch)
tree4e8a7657c0d2714319800a07c485bff473043bad /src
parentfb206bf34a2463317b9fa1ef3c0ff35d921f8920 (diff)
Make various fixes:
- add feature gate
- add basic tests
- adjust parser to eliminate conflict between `const fn` and associated
constants
- allow `const fn` in traits/trait-impls, but forbid later in type check
- correct some merge conflicts
Diffstat (limited to 'src')
-rw-r--r--src/librustc/diagnostics.rs3
-rw-r--r--src/librustc/metadata/encoder.rs5
-rw-r--r--src/librustc/middle/check_const.rs35
-rw-r--r--src/librustc/middle/const_eval.rs16
-rw-r--r--src/librustc/middle/effect.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc/middle/stability.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_resolve/lib.rs2
-rw-r--r--src/librustc_trans/save/dump_csv.rs2
-rw-r--r--src/librustc_trans/trans/consts.rs6
-rw-r--r--src/librustc_trans/trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs24
-rw-r--r--src/librustc_typeck/diagnostics.rs3
-rw-r--r--src/librustdoc/clean/mod.rs7
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/visit_ast.rs4
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/ast_map/blocks.rs5
-rw-r--r--src/libsyntax/ast_util.rs3
-rw-r--r--src/libsyntax/ext/expand.rs1
-rw-r--r--src/libsyntax/feature_gate.rs26
-rw-r--r--src/libsyntax/fold.rs3
-rw-r--r--src/libsyntax/parse/parser.rs68
-rw-r--r--src/libsyntax/print/pprust.rs16
-rw-r--r--src/libsyntax/visit.rs2
-rw-r--r--src/test/compile-fail/check-static-values-constraints.rs2
-rw-r--r--src/test/compile-fail/const-fn-mismatch.rs26
-rw-r--r--src/test/compile-fail/const-fn-not-in-trait.rs21
-rw-r--r--src/test/compile-fail/const-fn-not-safe-for-const.rs47
-rw-r--r--src/test/compile-fail/const-fn-stability.rs28
-rw-r--r--src/test/compile-fail/issue-16538.rs2
-rw-r--r--src/test/compile-fail/issue-7364.rs2
-rw-r--r--src/test/compile-fail/static-vec-repeat-not-constant.rs2
-rw-r--r--src/test/run-pass/const-fn-nested.rs23
-rw-r--r--src/test/run-pass/const-fn.rs32
36 files changed, 322 insertions, 108 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index f5cb1bd25d6..b70d73c9141 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -845,5 +845,6 @@ register_diagnostics! {
     E0314, // closure outlives stack frame
     E0315, // cannot invoke closure outside of its lifetime
     E0316, // nested quantification of lifetimes
-    E0370  // discriminant overflow
+    E0370, // discriminant overflow
+    E0378  // method calls limited to constant inherent methods
 }
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index f721bb700ed..88e0b739a0f 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -879,12 +879,11 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
             let any_types = !scheme.generics.types.is_empty();
             let needs_inline = any_types || is_default_impl ||
                                attr::requests_inline(&impl_item.attrs);
-            let constness = ast_method.pe_constness();
-            if needs_inline || constness == ast::Constness::Const {
+            if needs_inline || sig.constness == ast::Constness::Const {
                 encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
                                                                impl_item));
             }
-            encode_constness(rbml_w, constness);
+            encode_constness(rbml_w, sig.constness);
             if !any_types {
                 encode_symbol(ecx, rbml_w, m.def_id.node);
             }
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index aca2e2b473e..a70df34bd70 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -36,7 +36,6 @@ use util::nodemap::NodeMap;
 use util::ppaux::Repr;
 
 use syntax::ast;
-use syntax::ast_util::PostExpansionMethod;
 use syntax::codemap::Span;
 use syntax::visit::{self, Visitor};
 
@@ -149,16 +148,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
             Entry::Occupied(entry) => return *entry.get(),
             Entry::Vacant(entry) => {
                 // Prevent infinite recursion on re-entry.
-                entry.insert(PURE_CONST);
+                entry.insert(ConstQualif::empty());
             }
         }
 
         let mode = match fk {
-            visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
+            visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
                 Mode::ConstFn
             }
-            visit::FkMethod(_, _, m) => {
-                if m.pe_constness() == ast::Constness::Const {
+            visit::FkMethod(_, m, _) => {
+                if m.constness == ast::Constness::Const {
                     Mode::ConstFn
                 } else {
                     Mode::Var
@@ -189,7 +188,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
 
         // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
         // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
-        let qualif = qualif & (NON_ZERO_SIZED | PREFER_IN_PLACE);
+        let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
 
         self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
         qualif
@@ -210,7 +209,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
             self.add_qualif(qualif);
 
             if ty::type_contents(self.tcx, ret_ty).interior_unsafe() {
-                self.add_qualif(MUTABLE_MEM);
+                self.add_qualif(ConstQualif::MUTABLE_MEM);
             }
 
             true
@@ -366,7 +365,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                                                        macro in const?!")
                 }
             };
-            self.add_qualif(NOT_CONST);
+            self.add_qualif(ConstQualif::NOT_CONST);
             if self.mode != Mode::Var {
                 span_err!(self.tcx.sess, span, E0016,
                           "blocks in {}s are limited to items and \
@@ -602,7 +601,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 }
                 Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
                     // Sadly, we can't determine whether the types are zero-sized.
-                    v.add_qualif(NOT_CONST | NON_ZERO_SIZED);
+                    v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
                 }
                 def => {
                     v.add_qualif(ConstQualif::NOT_CONST);
@@ -651,20 +650,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 }
             }
         }
-        ast::ExprBlock(ref block) => {
-            // Check all statements in the block
-            let mut block_span_err = |span| {
-                v.add_qualif(ConstQualif::NOT_CONST);
-                if v.mode != Mode::Var {
-                    span_err!(v.tcx.sess, e.span, E0015,
-                              "function calls in {}s are limited to \
-                               constant functions, \
-                               struct and enum constructors", v.msg());
-                }
-            }
-        }
         ast::ExprMethodCall(..) => {
-            let method_did = match v.tcx.method_map.borrow()[method_call].origin {
+            let method_did = match v.tcx.method_map.borrow()[&method_call].origin {
                 ty::MethodStatic(did) => Some(did),
                 _ => None
             };
@@ -673,9 +660,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                 None => false
             };
             if !is_const {
-                v.add_qualif(NOT_CONST);
+                v.add_qualif(ConstQualif::NOT_CONST);
                 if v.mode != Mode::Var {
-                    span_err!(v.tcx.sess, e.span, E0021,
+                    span_err!(v.tcx.sess, e.span, E0378,
                               "method calls in {}s are limited to \
                                constant inherent methods", v.msg());
                 }
diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs
index 8daf17cb003..e5100c32cc2 100644
--- a/src/librustc/middle/const_eval.rs
+++ b/src/librustc/middle/const_eval.rs
@@ -25,7 +25,7 @@ use util::ppaux::Repr;
 
 use syntax::ast::{self, Expr};
 use syntax::ast_map::blocks::FnLikeNode;
-use syntax::ast_util::{self, PostExpansionMethod};
+use syntax::ast_util;
 use syntax::codemap::Span;
 use syntax::feature_gate;
 use syntax::parse::token::InternedString;
@@ -216,7 +216,7 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId)
     let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
         box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
         csearch::FoundAst::Found(&ast::IIItem(ref item)) => Some(item.id),
-        csearch::FoundAst::Found(&ast::IIImplItem(_, ast::MethodImplItem(ref m))) => Some(m.id),
+        csearch::FoundAst::Found(&ast::IIImplItem(_, ref item)) => Some(item.id),
         _ => None
     };
     tcx.extern_const_fns.borrow_mut().insert(def_id,
@@ -224,9 +224,9 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId)
     fn_id
 }
 
-pub fn lookup_const_fn_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
-                                 -> Option<FnLikeNode<'a>> {
-
+pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId)
+                                   -> Option<FnLikeNode<'tcx>>
+{
     let fn_id = if !ast_util::is_local(def_id) {
         if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
             fn_id
@@ -243,11 +243,11 @@ pub fn lookup_const_fn_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
     };
 
     match fn_like.kind() {
-        visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
+        visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
             Some(fn_like)
         }
-        visit::FkMethod(_, _, m) => {
-            if m.pe_constness() == ast::Constness::Const {
+        visit::FkMethod(_, m, _) => {
+            if m.constness == ast::Constness::Const {
                 Some(fn_like)
             } else {
                 None
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 963d8cf61bc..cfff439f02d 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -87,7 +87,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 block: &'v ast::Block, span: Span, _: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
-            visit::FkItemFn(_, _, unsafety, _, _) =>
+            visit::FkItemFn(_, _, unsafety, _, _, _) =>
                 (true, unsafety == ast::Unsafety::Unsafe),
             visit::FkMethod(_, sig, _) =>
                 (true, sig.unsafety == ast::Unsafety::Unsafe),
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 467e4045811..dfdcba1678f 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -447,7 +447,7 @@ impl<'a> LifetimeContext<'a> {
                    fb: &'b ast::Block,
                    _span: Span) {
         match fk {
-            visit::FkItemFn(_, generics, _, _, _) => {
+            visit::FkItemFn(_, generics, _, _, _, _) => {
                 visit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 8a9e957f02a..d75dc861e83 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -23,7 +23,7 @@ use syntax::{attr, visit};
 use syntax::ast;
 use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
 use syntax::ast::{Item, Generics, StructField};
-use syntax::ast_util::{is_local, PostExpansionMethod};
+use syntax::ast_util::is_local;
 use syntax::attr::{Stability, AttrMetaMethods};
 use syntax::visit::{FnKind, Visitor};
 use syntax::feature_gate::emit_feature_err;
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index abf0332b4a2..e9a459b9119 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1324,7 +1324,7 @@ impl LintPass for UnsafeCode {
     fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl,
                 _: &ast::Block, span: Span, _: ast::NodeId) {
         match fk {
-            visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _) =>
+            visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _, _) =>
                 cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
 
             visit::FkMethod(_, sig, _) => {
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 1723313f015..7afc1afc224 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -245,7 +245,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
                 _: Span,
                 node_id: NodeId) {
         let rib_kind = match function_kind {
-            visit::FkItemFn(_, generics, _, _, _) => {
+            visit::FkItemFn(_, generics, _, _, _, _) => {
                 self.visit_generics(generics);
                 ItemRibKind
             }
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 7f66d3a833f..00a1f728b9b 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -1167,7 +1167,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
                                           &location[..],
                                           self.cur_scope);
             }
-            ast::ItemFn(ref decl, _, _, ref ty_params, ref body) =>
+            ast::ItemFn(ref decl, _, _, _, ref ty_params, ref body) =>
                 self.process_fn(item, &**decl, ty_params, &**body),
             ast::ItemStatic(ref typ, _, ref expr) =>
                 self.process_static_or_const_item(item, typ, expr),
diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs
index 38272ca8bf4..c11bb922f1c 100644
--- a/src/librustc_trans/trans/consts.rs
+++ b/src/librustc_trans/trans/consts.rs
@@ -41,7 +41,7 @@ use syntax::{ast, ast_util};
 use syntax::parse::token;
 use syntax::ptr::P;
 
-type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
+pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
 
 pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
     -> ValueRef {
@@ -863,7 +863,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                       _ => break
                   };
               }
-              let def = cx.tcx().def_map.borrow()[callee.id].full_def();
+              let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
               let arg_vals = map_list(args);
               match def {
                   def::DefFn(did, _) | def::DefMethod(did, _) => {
@@ -893,7 +893,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
           ast::ExprMethodCall(_, _, ref args) => {
               let arg_vals = map_list(args);
               let method_call = ty::MethodCall::expr(e.id);
-              let method_did = match cx.tcx().method_map.borrow()[method_call].origin {
+              let method_did = match cx.tcx().method_map.borrow()[&method_call].origin {
                   ty::MethodStatic(did) => did,
                   _ => cx.sess().span_bug(e.span, "expected a const method def")
               };
diff --git a/src/librustc_trans/trans/debuginfo/mod.rs b/src/librustc_trans/trans/debuginfo/mod.rs
index 4e5407016ba..f9ad3d1a857 100644
--- a/src/librustc_trans/trans/debuginfo/mod.rs
+++ b/src/librustc_trans/trans/debuginfo/mod.rs
@@ -232,7 +232,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
 
             match item.node {
-                ast::ItemFn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
+                ast::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
                     (item.ident.name, fn_decl, generics, top_level_block, item.span, true)
                 }
                 _ => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 344d525d4cb..24f429a9ca0 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -830,11 +830,15 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
                     check_const(ccx, trait_item.span, &*expr, trait_item.id)
                 }
                 ast::MethodTraitItem(ref sig, Some(ref body)) => {
+                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
+
                     check_method_body(ccx, &trait_def.generics, sig, body,
                                       trait_item.id, trait_item.span);
                 }
+                ast::MethodTraitItem(ref sig, None) => {
+                    check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
+                }
                 ast::ConstTraitItem(_, None) |
-                ast::MethodTraitItem(_, None) |
                 ast::TypeTraitItem(..) => {
                     // Nothing to do.
                 }
@@ -845,6 +849,20 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
     }
 }
 
+fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                     span: Span,
+                                     constness: ast::Constness)
+{
+    match constness {
+        ast::Constness::NotConst => {
+            // good
+        }
+        ast::Constness::Const => {
+            span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const");
+        }
+    }
+}
+
 fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                generics: &ast::Generics,
                                item: &ast::Item) {
@@ -966,7 +984,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                     }
                 }
             }
-            ast::MethodImplItem(_, ref body) => {
+            ast::MethodImplItem(ref sig, ref body) => {
+                check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
+
                 let impl_method_def_id = local_def(impl_item.id);
                 let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
                                                           impl_method_def_id);
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index b3db7405cfd..5796a5599ce 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -1113,6 +1113,7 @@ register_diagnostics! {
            // fields need coercions
     E0376, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures
-    E0377  // the trait `CoerceUnsized` may only be implemented for a coercion
+    E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures with the same definition
+    E0379  // trait fns cannot be const
 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index c2ae8020f28..045a38228c6 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1352,7 +1352,10 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
                 generics: generics,
                 self_: self_,
                 decl: decl,
-                abi: self.fty.abi
+                abi: self.fty.abi,
+
+                // trait methods canot (currently, at least) be const
+                constness: ast::Constness::NotConst,
             })
         } else {
             TyMethodItem(TyMethod {
@@ -1360,7 +1363,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
                 generics: generics,
                 self_: self_,
                 decl: decl,
-                abi: self.fty.abi
+                abi: self.fty.abi,
             })
         };
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index a68e21aa01d..6e70b3711e4 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -37,7 +37,7 @@ pub struct VisSpace(pub Option<ast::Visibility>);
 pub struct UnsafetySpace(pub ast::Unsafety);
 /// Similarly to VisSpace, this structure is used to render a function constness
 /// with a space after it.
-#[derive(Copy)]
+#[derive(Copy, Clone)]
 pub struct ConstnessSpace(pub ast::Constness);
 /// Wrapper struct for properly emitting a method declaration.
 pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 92348aa648d..e86d77a3be0 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -125,7 +125,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     name: ast::Ident, fd: &ast::FnDecl,
                     unsafety: &ast::Unsafety,
                     constness: ast::Constness,
-                    _abi: &abi::Abi,
+                    abi: &abi::Abi,
                     gen: &ast::Generics) -> Function {
         debug!("Visiting fn");
         Function {
@@ -294,7 +294,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.enums.push(self.visit_enum_def(item, name, ed, gen)),
             ast::ItemStruct(ref sd, ref gen) =>
                 om.structs.push(self.visit_struct_def(item, name, &**sd, gen)),
-            ast::ItemFn(ref fd, unsafety, constness, ref abi, ref gen, _) =>
+            ast::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
                 om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
                                           constness, abi, gen)),
             ast::ItemTy(ref ty, ref gen) => {
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index bd7fb441bf5..5b03b3bf038 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1215,6 +1215,7 @@ pub struct TypeField {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct MethodSig {
     pub unsafety: Unsafety,
+    pub constness: Constness,
     pub abi: Abi,
     pub decl: P<FnDecl>,
     pub generics: Generics,
@@ -1549,7 +1550,6 @@ pub enum ExplicitSelf_ {
 pub type ExplicitSelf = Spanned<ExplicitSelf_>;
 
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-             Constness,
 pub struct Mod {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs
index 58627b37a87..99686d54ce5 100644
--- a/src/libsyntax/ast_map/blocks.rs
+++ b/src/libsyntax/ast_map/blocks.rs
@@ -189,7 +189,7 @@ impl<'a> FnLikeNode<'a> {
 
     pub fn kind(self) -> visit::FnKind<'a> {
         let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
-            visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.constness, p.vis)
+            visit::FkItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi, p.vis)
         };
         let closure = |_: ClosureParts| {
             visit::FkFnBlock
@@ -213,13 +213,12 @@ impl<'a> FnLikeNode<'a> {
     {
         match self.node {
             ast_map::NodeItem(i) => match i.node {
-                ast::ItemFn(ref decl, unsafety, constness, ref abi, ref generics, ref block) =>
+                ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) =>
                     item_fn(ItemFnParts {
                         id: i.id,
                         ident: i.ident,
                         decl: &**decl,
                         unsafety: unsafety,
-                        constness: constness,
                         body: &**block,
                         generics: generics,
                         abi: abi,
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 45db8cc7b25..bb8096f2770 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -251,7 +251,6 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: Option<&Ty>) -> Ident
     token::gensym_ident(&pretty[..])
 }
 
-                 _,
 pub fn struct_field_visibility(field: ast::StructField) -> Visibility {
     match field.node.kind {
         ast::NamedField(_, v) | ast::UnnamedField(v) => v
@@ -441,7 +440,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
         self.operation.visit_id(node_id);
 
         match function_kind {
-            visit::FkItemFn(_, generics, _, _, _) => {
+            visit::FkItemFn(_, generics, _, _, _, _) => {
                 self.visit_generics_helper(generics)
             }
             visit::FkMethod(_, sig, _) => {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 912cc841a64..5f0efd14eec 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -1396,6 +1396,7 @@ fn expand_and_rename_method(sig: ast::MethodSig, body: P<ast::Block>,
         abi: sig.abi,
         explicit_self: fld.fold_explicit_self(sig.explicit_self),
         unsafety: sig.unsafety,
+        constness: sig.constness,
         decl: rewritten_fn_decl
     }, rewritten_body)
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 84546679b23..2b749dd890e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -155,6 +155,9 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
     // Allows the definition of associated constants in `trait` or `impl`
     // blocks.
     ("associated_consts", "1.0.0", Active),
+
+    // Allows the definition of `const fn` functions.
+    ("const_fn", "1.2.0", Active),
 ];
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -640,6 +643,19 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                 block: &'v ast::Block,
                 span: Span,
                 _node_id: NodeId) {
+        // check for const fn declarations
+        match fn_kind {
+            visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
+                self.gate_feature("const_fn", span, "const fn is unstable");
+            }
+            _ => {
+                // stability of const fn methods are covered in
+                // visit_trait_item and visit_impl_item below; this is
+                // because default methods don't pass through this
+                // point.
+            }
+        }
+
         match fn_kind {
             visit::FkItemFn(_, _, _, _, abi, _) if abi == Abi::RustIntrinsic => {
                 self.gate_feature("intrinsics",
@@ -664,6 +680,11 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                                   ti.span,
                                   "associated constants are experimental")
             }
+            ast::MethodTraitItem(ref sig, _) => {
+                if sig.constness == ast::Constness::Const {
+                    self.gate_feature("const_fn", ti.span, "const fn is unstable");
+                }
+            }
             _ => {}
         }
         visit::walk_trait_item(self, ti);
@@ -676,6 +697,11 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
                                   ii.span,
                                   "associated constants are experimental")
             }
+            ast::MethodImplItem(ref sig, _) => {
+                if sig.constness == ast::Constness::Const {
+                    self.gate_feature("const_fn", ii.span, "const fn is unstable");
+                }
+            }
             _ => {}
         }
         visit::walk_impl_item(self, ii);
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index c2382eaf82e..7806a27c53e 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -1125,10 +1125,9 @@ pub fn noop_fold_method_sig<T: Folder>(sig: MethodSig, folder: &mut T) -> Method
         abi: sig.abi,
         explicit_self: folder.fold_explicit_self(sig.explicit_self),
         unsafety: sig.unsafety,
+        constness: sig.constness,
         decl: folder.fold_fn_decl(sig.decl)
     }
-                     constness,
-                         constness,
 }
 
 pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 6fba8fd47fd..eb6420165da 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1160,7 +1160,8 @@ impl<'a> Parser<'a> {
                 let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
                 try!(p.expect(&token::Semi));
                 (ident, TypeTraitItem(bounds, default))
-            } else if try!(p.eat_keyword(keywords::Const)) {
+            } else if p.is_const_item() {
+                try!(p.expect_keyword(keywords::Const));
                 let ident = try!(p.parse_ident());
                 try!(p.expect(&token::Colon));
                 let ty = try!(p.parse_ty_sum());
@@ -1175,13 +1176,7 @@ impl<'a> Parser<'a> {
                 };
                 (ident, ConstTraitItem(ty, default))
             } else {
-                let unsafety = try!(p.parse_unsafety());
-                let abi = if try!(p.eat_keyword(keywords::Extern)) {
-                    try!(p.parse_opt_abi()).unwrap_or(abi::C)
-                } else {
-                    abi::Rust
-                };
-                try!(p.expect_keyword(keywords::Fn));
+                let (constness, unsafety, abi) = try!(p.parse_fn_front_matter());
 
                 let ident = try!(p.parse_ident());
                 let mut generics = try!(p.parse_generics());
@@ -1196,7 +1191,7 @@ impl<'a> Parser<'a> {
                 generics.where_clause = try!(p.parse_where_clause());
                 let sig = ast::MethodSig {
                     unsafety: unsafety,
-                    constness: ast::Constness::NotConst;
+                    constness: constness,
                     decl: d,
                     generics: generics,
                     abi: abi,
@@ -4372,6 +4367,36 @@ impl<'a> Parser<'a> {
         Ok((ident, ItemFn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs)))
     }
 
+    /// true if we are looking at `const ID`, false for things like `const fn` etc
+    pub fn is_const_item(&mut self) -> bool {
+        self.token.is_keyword(keywords::Const) &&
+            !self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
+    }
+
+    /// parses all the "front matter" for a `fn` declaration, up to
+    /// and including the `fn` keyword:
+    ///
+    /// - `const fn`
+    /// - `unsafe fn`
+    /// - `extern fn`
+    /// - etc
+    pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> {
+        let is_const_fn = try!(self.eat_keyword(keywords::Const));
+        let (constness, unsafety, abi) = if is_const_fn {
+            (Constness::Const, Unsafety::Normal, abi::Rust)
+        } else {
+            let unsafety = try!(self.parse_unsafety());
+            let abi = if try!(self.eat_keyword(keywords::Extern)) {
+                try!(self.parse_opt_abi()).unwrap_or(abi::C)
+            } else {
+                abi::Rust
+            };
+            (Constness::NotConst, unsafety, abi)
+        };
+        try!(self.expect_keyword(keywords::Fn));
+        Ok((constness, unsafety, abi))
+    }
+
     /// Parse an impl item.
     pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> {
         maybe_whole!(no_clone self, NtImplItem);
@@ -4385,7 +4410,8 @@ impl<'a> Parser<'a> {
             let typ = try!(self.parse_ty_sum());
             try!(self.expect(&token::Semi));
             (name, TypeImplItem(typ))
-        } else if try!(self.eat_keyword(keywords::Const)) {
+        } else if self.is_const_item() {
+            try!(self.expect_keyword(keywords::Const));
             let name = try!(self.parse_ident());
             try!(self.expect(&token::Colon));
             let typ = try!(self.parse_ty_sum());
@@ -4450,19 +4476,7 @@ impl<'a> Parser<'a> {
             }
             Ok((token::special_idents::invalid, vec![], ast::MacImplItem(m)))
         } else {
-            let is_const_fn = !is_trait_impl && self.eat_keyword(keywords::Const);
-            let (constness, unsafety, abi) = if is_const_fn {
-                (Constness::Const, Unsafety::Normal, abi::Rust)
-            } else {
-                let unsafety = try!(self.parse_unsafety());
-                let abi = if try!(self.eat_keyword(keywords::Extern)) {
-                    try!(self.parse_opt_abi()).unwrap_or(abi::C)
-                } else {
-                    abi::Rust
-                };
-                (Constness::NotConst, unsafety, abi)
-            };
-            try!(self.expect_keyword(keywords::Fn));
+            let (constness, unsafety, abi) = try!(self.parse_fn_front_matter());
             let ident = try!(self.parse_ident());
             let mut generics = try!(self.parse_generics());
             let (explicit_self, decl) = try!(self.parse_fn_decl_with_self(|p| {
@@ -4475,7 +4489,7 @@ impl<'a> Parser<'a> {
                 abi: abi,
                 explicit_self: explicit_self,
                 unsafety: unsafety,
-                constness: constness;
+                constness: constness,
                 decl: decl
              }, body)))
         }
@@ -5301,9 +5315,9 @@ impl<'a> Parser<'a> {
         if try!(self.eat_keyword(keywords::Const) ){
             if self.check_keyword(keywords::Fn) {
                 // CONST FUNCTION ITEM
-                self.bump();
+                try!(self.bump());
                 let (ident, item_, extra_attrs) =
-                    self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust);
+                    try!(self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust));
                 let last_span = self.last_span;
                 let item = self.mk_item(lo,
                                         last_span.hi,
@@ -5311,7 +5325,7 @@ impl<'a> Parser<'a> {
                                         item_,
                                         visibility,
                                         maybe_append(attrs, extra_attrs));
-                return Ok(item);
+                return Ok(Some(item));
             }
 
             // CONST ITEM
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 5889b968f41..0b211cd0733 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -378,17 +378,6 @@ pub fn ident_to_string(id: &ast::Ident) -> String {
     to_string(|s| s.print_ident(*id))
 }
 
-<<<<<<< HEAD
-pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
-                  opt_explicit_self: Option<&ast::ExplicitSelf_>,
-                  generics: &ast::Generics) -> String {
-    to_string(|s| {
-||||||| parent of 61a958e... syntax: parse `const fn` for free functions and inherent methods.
-pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident,
-                  opt_explicit_self: Option<&ast::ExplicitSelf_>,
-                  generics: &ast::Generics) -> String {
-    $to_string(|s| {
-=======
 pub fn fun_to_string(decl: &ast::FnDecl,
                      unsafety: ast::Unsafety,
                      constness: ast::Constness,
@@ -396,8 +385,7 @@ pub fn fun_to_string(decl: &ast::FnDecl,
                      opt_explicit_self: Option<&ast::ExplicitSelf_>,
                      generics: &ast::Generics)
                      -> String {
-    $to_string(|s| {
->>>>>>> 61a958e... syntax: parse `const fn` for free functions and inherent methods.
+    to_string(|s| {
         try!(s.head(""));
         try!(s.print_fn(decl, unsafety, constness, abi::Rust, Some(name),
                         generics, opt_explicit_self, ast::Inherited));
@@ -2751,7 +2739,7 @@ impl<'a> State<'a> {
                            ast::Constness::NotConst,
                            abi,
                            name,
-                           generics,
+                           &generics,
                            opt_explicit_self,
                            ast::Inherited));
         self.end()
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index b9b81bd7c6f..61fddd6bed8 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -605,7 +605,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
     walk_fn_decl(visitor, function_declaration);
 
     match function_kind {
-        FkItemFn(_, generics, _, _, _) => {
+        FkItemFn(_, generics, _, _, _, _) => {
             visitor.visit_generics(generics);
         }
         FkMethod(_, sig, _) => {
diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs
index 0180bccbca4..c3a1de11752 100644
--- a/src/test/compile-fail/check-static-values-constraints.rs
+++ b/src/test/compile-fail/check-static-values-constraints.rs
@@ -117,7 +117,7 @@ static mut STATIC14: SafeStruct = SafeStruct {
 //~^ ERROR mutable statics are not allowed to have destructors
     field1: SafeEnum::Variant1,
     field2: SafeEnum::Variant4("str".to_string())
-//~^ ERROR static contains unimplemented expression type
+//~^ ERROR method calls in statics are limited to constant inherent methods
 };
 
 static STATIC15: &'static [Box<MyOwned>] = &[
diff --git a/src/test/compile-fail/const-fn-mismatch.rs b/src/test/compile-fail/const-fn-mismatch.rs
new file mode 100644
index 00000000000..d813cf32954
--- /dev/null
+++ b/src/test/compile-fail/const-fn-mismatch.rs
@@ -0,0 +1,26 @@
+// Copyright 2015 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.
+
+// Test that we can't declare a const fn in an impl -- right now it's
+// just not allowed at all, though eventually it'd make sense to allow
+// it if the trait fn is const (but right now no trait fns can be
+// const).
+
+#![feature(const_fn)]
+
+trait Foo {
+    fn f() -> u32;
+}
+
+impl Foo for u32 {
+    const fn f() -> u32 { 22 } //~ ERROR E0379
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/const-fn-not-in-trait.rs b/src/test/compile-fail/const-fn-not-in-trait.rs
new file mode 100644
index 00000000000..191f3e02527
--- /dev/null
+++ b/src/test/compile-fail/const-fn-not-in-trait.rs
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+// Test that const fn is illegal in a trait declaration, whether or
+// not a default is provided.
+
+#![feature(const_fn)]
+
+trait Foo {
+    const fn f() -> u32; //~ ERROR trait fns cannot be declared const
+    const fn g() -> u32 { 0 } //~ ERROR trait fns cannot be declared const
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/const-fn-not-safe-for-const.rs b/src/test/compile-fail/const-fn-not-safe-for-const.rs
new file mode 100644
index 00000000000..baa3eba0680
--- /dev/null
+++ b/src/test/compile-fail/const-fn-not-safe-for-const.rs
@@ -0,0 +1,47 @@
+// Copyright 2015 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.
+
+// Test that we can't call random fns in a const fn or do other bad things.
+
+#![feature(const_fn)]
+
+use std::mem::transmute;
+
+fn random() -> u32 { 0 }
+
+const fn sub(x: &u32) -> usize {
+    unsafe { transmute(x) } //~ ERROR E0015
+}
+
+const fn sub1() -> u32 {
+    random() //~ ERROR E0015
+}
+
+static Y: u32 = 0;
+
+const fn get_Y() -> u32 {
+    Y
+        //~^ ERROR E0013
+        //~| ERROR cannot refer to other statics by value
+}
+
+const fn get_Y_addr() -> &'static u32 {
+    &Y
+        //~^ ERROR E0013
+}
+
+const fn get() -> u32 {
+    let x = 22; //~ ERROR E0016
+    let y = 44; //~ ERROR E0016
+    x + y
+}
+
+fn main() {
+}
diff --git a/src/test/compile-fail/const-fn-stability.rs b/src/test/compile-fail/const-fn-stability.rs
new file mode 100644
index 00000000000..8aa5189bcd6
--- /dev/null
+++ b/src/test/compile-fail/const-fn-stability.rs
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+// Test use of const fn without feature gate.
+
+const fn foo() -> usize { 0 } //~ ERROR const fn is unstable
+
+trait Foo {
+    const fn foo() -> u32; //~ ERROR const fn is unstable
+    const fn bar() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo {
+    const fn baz() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+impl Foo for u32 {
+    const fn foo() -> u32 { 0 } //~ ERROR const fn is unstable
+}
+
+fn main() { }
diff --git a/src/test/compile-fail/issue-16538.rs b/src/test/compile-fail/issue-16538.rs
index a4e0f69b63b..2b53e92d9bc 100644
--- a/src/test/compile-fail/issue-16538.rs
+++ b/src/test/compile-fail/issue-16538.rs
@@ -20,6 +20,6 @@ mod Y {
 
 static foo: *const Y::X = Y::foo(Y::x as *const Y::X);
 //~^ ERROR the trait `core::marker::Sync` is not implemented for the type
-//~| ERROR function calls in statics are limited to struct and enum constructors
+//~| ERROR E0015
 
 fn main() {}
diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs
index 6a36b2f84bf..5d85fe93a48 100644
--- a/src/test/compile-fail/issue-7364.rs
+++ b/src/test/compile-fail/issue-7364.rs
@@ -17,6 +17,6 @@ static boxed: Box<RefCell<isize>> = box RefCell::new(0);
 //~^ ERROR allocations are not allowed in statics
 //~| ERROR the trait `core::marker::Sync` is not implemented for the type
 //~| ERROR the trait `core::marker::Sync` is not implemented for the type
-//~| ERROR function calls in statics are limited to struct and enum constructors
+//~| ERROR E0015
 
 fn main() { }
diff --git a/src/test/compile-fail/static-vec-repeat-not-constant.rs b/src/test/compile-fail/static-vec-repeat-not-constant.rs
index 7a957564587..a533a5bd54d 100644
--- a/src/test/compile-fail/static-vec-repeat-not-constant.rs
+++ b/src/test/compile-fail/static-vec-repeat-not-constant.rs
@@ -11,6 +11,6 @@
 fn foo() -> isize { 23 }
 
 static a: [isize; 2] = [foo(); 2];
-//~^ ERROR: function calls in statics are limited to struct and enum constructors
+//~^ ERROR: E0015
 
 fn main() {}
diff --git a/src/test/run-pass/const-fn-nested.rs b/src/test/run-pass/const-fn-nested.rs
new file mode 100644
index 00000000000..86f5dedc4d1
--- /dev/null
+++ b/src/test/run-pass/const-fn-nested.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// Test a call whose argument is the result of another call.
+
+#![feature(const_fn)]
+
+const fn sub(x: u32, y: u32) -> u32 {
+    x - y
+}
+
+const X: u32 = sub(sub(88, 44), 22);
+
+fn main() {
+    assert_eq!(X, 22);
+}
diff --git a/src/test/run-pass/const-fn.rs b/src/test/run-pass/const-fn.rs
new file mode 100644
index 00000000000..9bd8eb55cc3
--- /dev/null
+++ b/src/test/run-pass/const-fn.rs
@@ -0,0 +1,32 @@
+// Copyright 2015 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.
+
+// A very basic test of const fn functionality.
+
+#![feature(const_fn)]
+
+const fn add(x: u32, y: u32) -> u32 {
+    x + y
+}
+
+const fn sub(x: u32, y: u32) -> u32 {
+    x - y
+}
+
+const SUM: u32 = add(44, 22);
+const DIFF: u32 = sub(44, 22);
+
+fn main() {
+    assert_eq!(SUM, 66);
+    assert!(SUM != 88);
+
+    assert_eq!(DIFF, 22);
+
+}