Skip to content

Commit 27dfd33

Browse files
committed
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
1 parent 8b5699b commit 27dfd33

37 files changed

+326
-108
lines changed

src/librustc/diagnostics.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,5 +846,6 @@ register_diagnostics! {
846846
E0314, // closure outlives stack frame
847847
E0315, // cannot invoke closure outside of its lifetime
848848
E0316, // nested quantification of lifetimes
849-
E0370 // discriminant overflow
849+
E0370, // discriminant overflow
850+
E0378 // method calls limited to constant inherent methods
850851
}

src/librustc/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
// TODO list:
12+
// 1. Check that const fns cannot be defined in a trait or trait impl.
13+
// (This used to be enforced in the parser.) Make sure there are test cases.
14+
1115
//! The Rust compiler.
1216
//!
1317
//! # Note

src/librustc/metadata/encoder.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -879,12 +879,11 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
879879
let any_types = !scheme.generics.types.is_empty();
880880
let needs_inline = any_types || is_default_impl ||
881881
attr::requests_inline(&impl_item.attrs);
882-
let constness = ast_method.pe_constness();
883-
if needs_inline || constness == ast::Constness::Const {
882+
if needs_inline || sig.constness == ast::Constness::Const {
884883
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
885884
impl_item));
886885
}
887-
encode_constness(rbml_w, constness);
886+
encode_constness(rbml_w, sig.constness);
888887
if !any_types {
889888
encode_symbol(ecx, rbml_w, m.def_id.node);
890889
}

src/librustc/middle/check_const.rs

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ use util::nodemap::NodeMap;
3535
use util::ppaux;
3636

3737
use syntax::ast;
38-
use syntax::ast_util::PostExpansionMethod;
3938
use syntax::codemap::Span;
4039
use syntax::print::pprust;
4140
use syntax::visit::{self, Visitor};
@@ -149,16 +148,16 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
149148
Entry::Occupied(entry) => return *entry.get(),
150149
Entry::Vacant(entry) => {
151150
// Prevent infinite recursion on re-entry.
152-
entry.insert(PURE_CONST);
151+
entry.insert(ConstQualif::empty());
153152
}
154153
}
155154

156155
let mode = match fk {
157-
visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
156+
visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
158157
Mode::ConstFn
159158
}
160-
visit::FkMethod(_, _, m) => {
161-
if m.pe_constness() == ast::Constness::Const {
159+
visit::FkMethod(_, m, _) => {
160+
if m.constness == ast::Constness::Const {
162161
Mode::ConstFn
163162
} else {
164163
Mode::Var
@@ -189,7 +188,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
189188

190189
// Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
191190
// and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
192-
let qualif = qualif & (NON_ZERO_SIZED | PREFER_IN_PLACE);
191+
let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
193192

194193
self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
195194
qualif
@@ -210,7 +209,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
210209
self.add_qualif(qualif);
211210

212211
if ty::type_contents(self.tcx, ret_ty).interior_unsafe() {
213-
self.add_qualif(MUTABLE_MEM);
212+
self.add_qualif(ConstQualif::MUTABLE_MEM);
214213
}
215214

216215
true
@@ -366,7 +365,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
366365
macro in const?!")
367366
}
368367
};
369-
self.add_qualif(NOT_CONST);
368+
self.add_qualif(ConstQualif::NOT_CONST);
370369
if self.mode != Mode::Var {
371370
span_err!(self.tcx.sess, span, E0016,
372371
"blocks in {}s are limited to items and \
@@ -611,7 +610,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
611610
}
612611
Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
613612
// Sadly, we can't determine whether the types are zero-sized.
614-
v.add_qualif(NOT_CONST | NON_ZERO_SIZED);
613+
v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
615614
}
616615
def => {
617616
v.add_qualif(ConstQualif::NOT_CONST);
@@ -660,20 +659,8 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
660659
}
661660
}
662661
}
663-
ast::ExprBlock(ref block) => {
664-
// Check all statements in the block
665-
let mut block_span_err = |span| {
666-
v.add_qualif(ConstQualif::NOT_CONST);
667-
if v.mode != Mode::Var {
668-
span_err!(v.tcx.sess, e.span, E0015,
669-
"function calls in {}s are limited to \
670-
constant functions, \
671-
struct and enum constructors", v.msg());
672-
}
673-
}
674-
}
675662
ast::ExprMethodCall(..) => {
676-
let method_did = match v.tcx.method_map.borrow()[method_call].origin {
663+
let method_did = match v.tcx.method_map.borrow()[&method_call].origin {
677664
ty::MethodStatic(did) => Some(did),
678665
_ => None
679666
};
@@ -682,9 +669,9 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
682669
None => false
683670
};
684671
if !is_const {
685-
v.add_qualif(NOT_CONST);
672+
v.add_qualif(ConstQualif::NOT_CONST);
686673
if v.mode != Mode::Var {
687-
span_err!(v.tcx.sess, e.span, E0021,
674+
span_err!(v.tcx.sess, e.span, E0378,
688675
"method calls in {}s are limited to \
689676
constant inherent methods", v.msg());
690677
}

src/librustc/middle/const_eval.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use util::ppaux::Repr;
2525

2626
use syntax::ast::{self, Expr};
2727
use syntax::ast_map::blocks::FnLikeNode;
28-
use syntax::ast_util::{self, PostExpansionMethod};
28+
use syntax::ast_util;
2929
use syntax::codemap::Span;
3030
use syntax::feature_gate;
3131
use syntax::parse::token::InternedString;
@@ -216,17 +216,17 @@ fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId)
216216
let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
217217
box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
218218
csearch::FoundAst::Found(&ast::IIItem(ref item)) => Some(item.id),
219-
csearch::FoundAst::Found(&ast::IIImplItem(_, ast::MethodImplItem(ref m))) => Some(m.id),
219+
csearch::FoundAst::Found(&ast::IIImplItem(_, ref item)) => Some(item.id),
220220
_ => None
221221
};
222222
tcx.extern_const_fns.borrow_mut().insert(def_id,
223223
fn_id.unwrap_or(ast::DUMMY_NODE_ID));
224224
fn_id
225225
}
226226

227-
pub fn lookup_const_fn_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
228-
-> Option<FnLikeNode<'a>> {
229-
227+
pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: ast::DefId)
228+
-> Option<FnLikeNode<'tcx>>
229+
{
230230
let fn_id = if !ast_util::is_local(def_id) {
231231
if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
232232
fn_id
@@ -243,11 +243,11 @@ pub fn lookup_const_fn_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
243243
};
244244

245245
match fn_like.kind() {
246-
visit::FkItemFn(_, _, _, ast::Constness::Const, _) => {
246+
visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
247247
Some(fn_like)
248248
}
249-
visit::FkMethod(_, _, m) => {
250-
if m.pe_constness() == ast::Constness::Const {
249+
visit::FkMethod(_, m, _) => {
250+
if m.constness == ast::Constness::Const {
251251
Some(fn_like)
252252
} else {
253253
None

src/librustc/middle/effect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
8787
block: &'v ast::Block, span: Span, _: ast::NodeId) {
8888

8989
let (is_item_fn, is_unsafe_fn) = match fn_kind {
90-
visit::FkItemFn(_, _, unsafety, _, _) =>
90+
visit::FkItemFn(_, _, unsafety, _, _, _) =>
9191
(true, unsafety == ast::Unsafety::Unsafe),
9292
visit::FkMethod(_, sig, _) =>
9393
(true, sig.unsafety == ast::Unsafety::Unsafe),

src/librustc/middle/resolve_lifetime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ impl<'a> LifetimeContext<'a> {
447447
fb: &'b ast::Block,
448448
_span: Span) {
449449
match fk {
450-
visit::FkItemFn(_, generics, _, _, _) => {
450+
visit::FkItemFn(_, generics, _, _, _, _) => {
451451
visit::walk_fn_decl(self, fd);
452452
self.visit_generics(generics);
453453
}

src/librustc/middle/stability.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use syntax::{attr, visit};
2323
use syntax::ast;
2424
use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant};
2525
use syntax::ast::{Item, Generics, StructField};
26-
use syntax::ast_util::{is_local, PostExpansionMethod};
26+
use syntax::ast_util::is_local;
2727
use syntax::attr::{Stability, AttrMetaMethods};
2828
use syntax::visit::{FnKind, Visitor};
2929
use syntax::feature_gate::emit_feature_err;

src/librustc_lint/builtin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ impl LintPass for UnsafeCode {
13241324
fn check_fn(&mut self, cx: &Context, fk: visit::FnKind, _: &ast::FnDecl,
13251325
_: &ast::Block, span: Span, _: ast::NodeId) {
13261326
match fk {
1327-
visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _) =>
1327+
visit::FkItemFn(_, _, ast::Unsafety::Unsafe, _, _, _) =>
13281328
cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
13291329

13301330
visit::FkMethod(_, sig, _) => {

src/librustc_resolve/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
245245
_: Span,
246246
node_id: NodeId) {
247247
let rib_kind = match function_kind {
248-
visit::FkItemFn(_, generics, _, _, _) => {
248+
visit::FkItemFn(_, generics, _, _, _, _) => {
249249
self.visit_generics(generics);
250250
ItemRibKind
251251
}

src/librustc_trans/save/dump_csv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1167,7 +1167,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
11671167
&location[..],
11681168
self.cur_scope);
11691169
}
1170-
ast::ItemFn(ref decl, _, _, ref ty_params, ref body) =>
1170+
ast::ItemFn(ref decl, _, _, _, ref ty_params, ref body) =>
11711171
self.process_fn(item, &**decl, ty_params, &**body),
11721172
ast::ItemStatic(ref typ, _, ref expr) =>
11731173
self.process_static_or_const_item(item, typ, expr),

src/librustc_trans/trans/consts.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use syntax::{ast, ast_util};
4040
use syntax::parse::token;
4141
use syntax::ptr::P;
4242

43-
type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
43+
pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
4444

4545
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
4646
-> ValueRef {
@@ -851,7 +851,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
851851
_ => break
852852
};
853853
}
854-
let def = cx.tcx().def_map.borrow()[callee.id].full_def();
854+
let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
855855
let arg_vals = map_list(args);
856856
match def {
857857
def::DefFn(did, _) | def::DefMethod(did, _) => {
@@ -881,7 +881,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
881881
ast::ExprMethodCall(_, _, ref args) => {
882882
let arg_vals = map_list(args);
883883
let method_call = ty::MethodCall::expr(e.id);
884-
let method_did = match cx.tcx().method_map.borrow()[method_call].origin {
884+
let method_did = match cx.tcx().method_map.borrow()[&method_call].origin {
885885
ty::MethodStatic(did) => did,
886886
_ => cx.sess().span_bug(e.span, "expected a const method def")
887887
};

src/librustc_trans/trans/debuginfo/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
232232
}
233233

234234
match item.node {
235-
ast::ItemFn(ref fn_decl, _, _, ref generics, ref top_level_block) => {
235+
ast::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
236236
(item.ident.name, fn_decl, generics, top_level_block, item.span, true)
237237
}
238238
_ => {

src/librustc_typeck/check/mod.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -827,11 +827,15 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
827827
check_const(ccx, trait_item.span, &*expr, trait_item.id)
828828
}
829829
ast::MethodTraitItem(ref sig, Some(ref body)) => {
830+
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
831+
830832
check_method_body(ccx, &trait_def.generics, sig, body,
831833
trait_item.id, trait_item.span);
832834
}
835+
ast::MethodTraitItem(ref sig, None) => {
836+
check_trait_fn_not_const(ccx, trait_item.span, sig.constness);
837+
}
833838
ast::ConstTraitItem(_, None) |
834-
ast::MethodTraitItem(_, None) |
835839
ast::TypeTraitItem(..) => {
836840
// Nothing to do.
837841
}
@@ -842,6 +846,20 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
842846
}
843847
}
844848

849+
fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
850+
span: Span,
851+
constness: ast::Constness)
852+
{
853+
match constness {
854+
ast::Constness::NotConst => {
855+
// good
856+
}
857+
ast::Constness::Const => {
858+
span_err!(ccx.tcx.sess, span, E0379, "trait fns cannot be declared const");
859+
}
860+
}
861+
}
862+
845863
fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
846864
generics: &ast::Generics,
847865
item: &ast::Item) {
@@ -963,7 +981,9 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
963981
}
964982
}
965983
}
966-
ast::MethodImplItem(_, ref body) => {
984+
ast::MethodImplItem(ref sig, ref body) => {
985+
check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
986+
967987
let impl_method_def_id = local_def(impl_item.id);
968988
let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
969989
impl_method_def_id);

src/librustc_typeck/diagnostics.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ register_diagnostics! {
898898
// fields need coercions
899899
E0376, // the trait `CoerceUnsized` may only be implemented for a coercion
900900
// between structures
901-
E0377 // the trait `CoerceUnsized` may only be implemented for a coercion
901+
E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
902902
// between structures with the same definition
903+
E0379 // trait fns cannot be const
903904
}

src/librustdoc/clean/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,15 +1352,18 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
13521352
generics: generics,
13531353
self_: self_,
13541354
decl: decl,
1355-
abi: self.fty.abi
1355+
abi: self.fty.abi,
1356+
1357+
// trait methods canot (currently, at least) be const
1358+
constness: ast::Constness::NotConst,
13561359
})
13571360
} else {
13581361
TyMethodItem(TyMethod {
13591362
unsafety: self.fty.unsafety,
13601363
generics: generics,
13611364
self_: self_,
13621365
decl: decl,
1363-
abi: self.fty.abi
1366+
abi: self.fty.abi,
13641367
})
13651368
};
13661369

src/librustdoc/html/format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct VisSpace(pub Option<ast::Visibility>);
3737
pub struct UnsafetySpace(pub ast::Unsafety);
3838
/// Similarly to VisSpace, this structure is used to render a function constness
3939
/// with a space after it.
40-
#[derive(Copy)]
40+
#[derive(Copy, Clone)]
4141
pub struct ConstnessSpace(pub ast::Constness);
4242
/// Wrapper struct for properly emitting a method declaration.
4343
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);

src/librustdoc/visit_ast.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
125125
name: ast::Ident, fd: &ast::FnDecl,
126126
unsafety: &ast::Unsafety,
127127
constness: ast::Constness,
128-
_abi: &abi::Abi,
128+
abi: &abi::Abi,
129129
gen: &ast::Generics) -> Function {
130130
debug!("Visiting fn");
131131
Function {
@@ -294,7 +294,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
294294
om.enums.push(self.visit_enum_def(item, name, ed, gen)),
295295
ast::ItemStruct(ref sd, ref gen) =>
296296
om.structs.push(self.visit_struct_def(item, name, &**sd, gen)),
297-
ast::ItemFn(ref fd, unsafety, constness, ref abi, ref gen, _) =>
297+
ast::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
298298
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
299299
constness, abi, gen)),
300300
ast::ItemTy(ref ty, ref gen) => {

src/libsyntax/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,7 @@ pub struct TypeField {
12151215
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
12161216
pub struct MethodSig {
12171217
pub unsafety: Unsafety,
1218+
pub constness: Constness,
12181219
pub abi: Abi,
12191220
pub decl: P<FnDecl>,
12201221
pub generics: Generics,
@@ -1549,7 +1550,6 @@ pub enum ExplicitSelf_ {
15491550
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
15501551

15511552
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
1552-
Constness,
15531553
pub struct Mod {
15541554
/// A span from the first token past `{` to the last token until `}`.
15551555
/// For `mod foo;`, the inner span ranges from the first token

0 commit comments

Comments
 (0)