1
Fork 0

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
This commit is contained in:
Niko Matsakis 2015-05-05 08:47:04 -04:00
parent fb206bf34a
commit df93deab10
36 changed files with 322 additions and 108 deletions

View file

@ -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
}

View file

@ -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);
}

View file

@ -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());
}

View file

@ -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

View file

@ -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),

View file

@ -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);
}

View file

@ -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;

View file

@ -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, _) => {

View file

@ -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
}

View file

@ -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),

View file

@ -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")
};

View file

@ -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)
}
_ => {

View file

@ -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);

View file

@ -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
}

View file

@ -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,
})
};

View file

@ -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);

View file

@ -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) => {

View file

@ -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

View file

@ -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,

View file

@ -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, _) => {

View file

@ -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)
}

View file

@ -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);

View file

@ -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> {

View file

@ -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

View file

@ -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()

View file

@ -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, _) => {

View file

@ -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>] = &[

View file

@ -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() { }

View file

@ -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() { }

View file

@ -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() {
}

View file

@ -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() { }

View file

@ -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() {}

View file

@ -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() { }

View file

@ -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() {}

View file

@ -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);
}

View file

@ -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);
}