From af3795721cd9ffc591eeeb077df16d3658be150f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 25 Feb 2015 22:05:07 +0200 Subject: syntax: parse `const fn` for free functions and inherent methods. --- src/libsyntax/parse/parser.rs | 51 +++++++++++++++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 12 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2b6f91bbc99..6fba8fd47fd 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -17,7 +17,7 @@ use ast::{Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; -use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig}; +use ast::{Constness, ConstImplItem, ConstTraitItem, Crate, CrateConfig}; use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn}; use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; @@ -1175,7 +1175,7 @@ impl<'a> Parser<'a> { }; (ident, ConstTraitItem(ty, default)) } else { - let style = try!(p.parse_unsafety()); + 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 { @@ -1195,7 +1195,8 @@ impl<'a> Parser<'a> { generics.where_clause = try!(p.parse_where_clause()); let sig = ast::MethodSig { - unsafety: style, + unsafety: unsafety, + constness: ast::Constness::NotConst; decl: d, generics: generics, abi: abi, @@ -4359,12 +4360,16 @@ impl<'a> Parser<'a> { } /// Parse an item-position function declaration. - fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> PResult { + fn parse_item_fn(&mut self, + unsafety: Unsafety, + constness: Constness, + abi: abi::Abi) + -> PResult { let (ident, mut generics) = try!(self.parse_fn_header()); let decl = try!(self.parse_fn_decl(false)); generics.where_clause = try!(self.parse_where_clause()); let (inner_attrs, body) = try!(self.parse_inner_attrs_and_block()); - Ok((ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs))) + Ok((ident, ItemFn(decl, unsafety, constness, abi, generics, body), Some(inner_attrs))) } /// Parse an impl item. @@ -4445,11 +4450,17 @@ impl<'a> Parser<'a> { } Ok((token::special_idents::invalid, vec![], ast::MacImplItem(m))) } 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) + 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 { - abi::Rust + 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 ident = try!(self.parse_ident()); @@ -4464,6 +4475,7 @@ impl<'a> Parser<'a> { abi: abi, explicit_self: explicit_self, unsafety: unsafety, + constness: constness; decl: decl }, body))) } @@ -5252,7 +5264,7 @@ impl<'a> Parser<'a> { // EXTERN FUNCTION ITEM let abi = opt_abi.unwrap_or(abi::C); let (ident, item_, extra_attrs) = - try!(self.parse_item_fn(Unsafety::Normal, abi)); + try!(self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5287,6 +5299,21 @@ impl<'a> Parser<'a> { return Ok(Some(item)); } if try!(self.eat_keyword(keywords::Const) ){ + if self.check_keyword(keywords::Fn) { + // CONST FUNCTION ITEM + self.bump(); + let (ident, item_, extra_attrs) = + 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, + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(item); + } + // CONST ITEM if try!(self.eat_keyword(keywords::Mut) ){ let last_span = self.last_span; @@ -5340,7 +5367,7 @@ impl<'a> Parser<'a> { // FUNCTION ITEM try!(self.bump()); let (ident, item_, extra_attrs) = - try!(self.parse_item_fn(Unsafety::Normal, abi::Rust)); + try!(self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi::Rust)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5361,7 +5388,7 @@ impl<'a> Parser<'a> { }; try!(self.expect_keyword(keywords::Fn)); let (ident, item_, extra_attrs) = - try!(self.parse_item_fn(Unsafety::Unsafe, abi)); + try!(self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi)); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, -- cgit 1.4.1-3-g733a5 From df93deab10850d52252829770895b0249b0d7f1e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 5 May 2015 08:47:04 -0400 Subject: 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 --- src/librustc/diagnostics.rs | 3 +- src/librustc/metadata/encoder.rs | 5 +- src/librustc/middle/check_const.rs | 35 ++++------- src/librustc/middle/const_eval.rs | 16 ++--- src/librustc/middle/effect.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 2 +- src/librustc/middle/stability.rs | 2 +- src/librustc_lint/builtin.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_trans/save/dump_csv.rs | 2 +- src/librustc_trans/trans/consts.rs | 6 +- src/librustc_trans/trans/debuginfo/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 24 +++++++- src/librustc_typeck/diagnostics.rs | 3 +- src/librustdoc/clean/mod.rs | 7 ++- src/librustdoc/html/format.rs | 2 +- src/librustdoc/visit_ast.rs | 4 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ast_map/blocks.rs | 5 +- src/libsyntax/ast_util.rs | 3 +- src/libsyntax/ext/expand.rs | 1 + src/libsyntax/feature_gate.rs | 26 +++++++++ src/libsyntax/fold.rs | 3 +- src/libsyntax/parse/parser.rs | 68 +++++++++++++--------- src/libsyntax/print/pprust.rs | 16 +---- src/libsyntax/visit.rs | 2 +- .../check-static-values-constraints.rs | 2 +- src/test/compile-fail/const-fn-mismatch.rs | 26 +++++++++ src/test/compile-fail/const-fn-not-in-trait.rs | 21 +++++++ .../compile-fail/const-fn-not-safe-for-const.rs | 47 +++++++++++++++ src/test/compile-fail/const-fn-stability.rs | 28 +++++++++ src/test/compile-fail/issue-16538.rs | 2 +- src/test/compile-fail/issue-7364.rs | 2 +- .../compile-fail/static-vec-repeat-not-constant.rs | 2 +- src/test/run-pass/const-fn-nested.rs | 23 ++++++++ src/test/run-pass/const-fn.rs | 32 ++++++++++ 36 files changed, 322 insertions(+), 108 deletions(-) create mode 100644 src/test/compile-fail/const-fn-mismatch.rs create mode 100644 src/test/compile-fail/const-fn-not-in-trait.rs create mode 100644 src/test/compile-fail/const-fn-not-safe-for-const.rs create mode 100644 src/test/compile-fail/const-fn-stability.rs create mode 100644 src/test/run-pass/const-fn-nested.rs create mode 100644 src/test/run-pass/const-fn.rs (limited to 'src/libsyntax/parse') 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> { - +pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId) + -> Option> +{ 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>; +pub type FnArgMap<'a> = Option<&'a NodeMap>; 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 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 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); 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, pub generics: Generics, @@ -1549,7 +1550,6 @@ pub enum ExplicitSelf_ { pub type ExplicitSelf = Spanned; #[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, 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, 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(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(p: P, folder: &mut T) -> P { 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> { 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] = &[ 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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 or the MIT license +// , 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> = 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 or the MIT license +// , 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 or the MIT license +// , 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); + +} -- cgit 1.4.1-3-g733a5 From 82ded3cd03e001e82b9dce9aedac621a5292231b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 22 May 2015 08:45:05 -0400 Subject: Two more small fixes. --- src/libsyntax/parse/mod.rs | 1 + src/libsyntax/print/pprust.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 68574560533..d6c28d41447 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -923,6 +923,7 @@ mod tests { variadic: false }), ast::Unsafety::Normal, + ast::Constness::NotConst, abi::Rust, ast::Generics{ // no idea on either of these: lifetimes: Vec::new(), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0b211cd0733..8958370fda5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2997,7 +2997,7 @@ impl<'a> State<'a> { match constness { ast::Constness::NotConst => {} - ast::Constness::Const => try!(self.word_nbsp("unsafe")) + ast::Constness::Const => try!(self.word_nbsp("const")) } if abi != abi::Rust { -- cgit 1.4.1-3-g733a5