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:
parent
fb206bf34a
commit
df93deab10
36 changed files with 322 additions and 108 deletions
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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")
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -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>] = &[
|
||||
|
|
26
src/test/compile-fail/const-fn-mismatch.rs
Normal file
26
src/test/compile-fail/const-fn-mismatch.rs
Normal 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() { }
|
21
src/test/compile-fail/const-fn-not-in-trait.rs
Normal file
21
src/test/compile-fail/const-fn-not-in-trait.rs
Normal 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() { }
|
47
src/test/compile-fail/const-fn-not-safe-for-const.rs
Normal file
47
src/test/compile-fail/const-fn-not-safe-for-const.rs
Normal 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() {
|
||||
}
|
28
src/test/compile-fail/const-fn-stability.rs
Normal file
28
src/test/compile-fail/const-fn-stability.rs
Normal 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() { }
|
|
@ -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() {}
|
||||
|
|
|
@ -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() { }
|
||||
|
|
|
@ -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() {}
|
||||
|
|
23
src/test/run-pass/const-fn-nested.rs
Normal file
23
src/test/run-pass/const-fn-nested.rs
Normal 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);
|
||||
}
|
32
src/test/run-pass/const-fn.rs
Normal file
32
src/test/run-pass/const-fn.rs
Normal 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);
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue