Skip to content

Commit

Permalink
Make various fixes:
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
nikomatsakis committed May 20, 2015
1 parent 332fada commit 86ee5f9
Show file tree
Hide file tree
Showing 36 changed files with 322 additions and 108 deletions.
3 changes: 2 additions & 1 deletion src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
5 changes: 2 additions & 3 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
35 changes: 11 additions & 24 deletions src/librustc/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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 \
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
};
Expand All @@ -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());
}
Expand Down
16 changes: 8 additions & 8 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -216,17 +216,17 @@ 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,
fn_id.unwrap_or(ast::DUMMY_NODE_ID));
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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/resolve_lifetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/stability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/save/dump_csv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
6 changes: 3 additions & 3 deletions src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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, _) => {
Expand Down Expand Up @@ -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")
};
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
_ => {
Expand Down
24 changes: 22 additions & 2 deletions src/librustc_typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_typeck/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,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
}
7 changes: 5 additions & 2 deletions src/librustdoc/clean/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1352,15 +1352,18 @@ 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 {
unsafety: self.fty.unsafety,
generics: generics,
self_: self_,
decl: decl,
abi: self.fty.abi
abi: self.fty.abi,
})
};

Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 86ee5f9

Please sign in to comment.