diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 133bef30e4083..532f5d544423d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -67,6 +67,7 @@ register_diagnostics! { E0018, E0019, E0020, + E0021, E0022, E0109, E0110, diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 081c64ecae881..d746173b2d760 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -256,3 +256,5 @@ pub const tag_codemap_filemap: uint = 0xa2; pub const tag_item_super_predicates: uint = 0xa3; pub const tag_defaulted_trait: uint = 0xa4; + +pub const tag_items_data_item_constness: uint = 0xa5; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ed5783c8dba66..c6ba7dac473da 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -377,6 +377,11 @@ pub fn is_typedef(cstore: &cstore::CStore, did: ast::DefId) -> bool { decoder::is_typedef(&*cdata, did.node) } +pub fn is_const_fn(cstore: &cstore::CStore, did: ast::DefId) -> bool { + let cdata = cstore.get_crate_data(did.krate); + decoder::is_const_fn(&*cdata, did.node) +} + pub fn get_stability(cstore: &cstore::CStore, def: ast::DefId) -> Option { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index dbbc17c018a2f..f2835d03da519 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -176,6 +176,19 @@ fn item_visibility(item: rbml::Doc) -> ast::Visibility { } } +fn fn_constness(item: rbml::Doc) -> ast::Constness { + match reader::maybe_get_doc(item, tag_items_data_item_constness) { + None => ast::Constness::NotConst, + Some(constness_doc) => { + match reader::doc_as_u8(constness_doc) as char { + 'c' => ast::Constness::Const, + 'n' => ast::Constness::NotConst, + _ => panic!("unknown constness character") + } + } + } +} + fn item_sort(item: rbml::Doc) -> Option { let mut ret = None; reader::tagged_docs(item, tag_item_trait_item_sort, |doc| { @@ -1451,6 +1464,14 @@ pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool { } } +pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool { + let item_doc = lookup_item(id, cdata.data()); + match fn_constness(item_doc) { + ast::Constness::Const => true, + ast::Constness::NotConst => false, + } +} + fn doc_generics<'tcx>(base_doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 611d8bc27d19d..9bbfc92cfdf85 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -581,6 +581,16 @@ fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) { rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); } +fn encode_constness(rbml_w: &mut Encoder, constness: ast::Constness) { + rbml_w.start_tag(tag_items_data_item_constness); + let ch = match constness { + ast::Constness::Const => 'c', + ast::Constness::NotConst => 'n', + }; + rbml_w.wr_str(&ch.to_string()); + rbml_w.end_tag(); +} + fn encode_explicit_self(rbml_w: &mut Encoder, explicit_self: &ty::ExplicitSelfCategory) { let tag = tag_item_trait_method_explicit_self; @@ -831,10 +841,14 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, encode_attributes(rbml_w, &impl_item.attrs); let scheme = ty::lookup_item_type(ecx.tcx, m.def_id); let any_types = !scheme.generics.types.is_empty(); - if any_types || is_default_impl || attr::requests_inline(&impl_item.attrs) { + 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 { encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), impl_item)); } + encode_constness(rbml_w, constness); if !any_types { encode_symbol(ecx, rbml_w, m.def_id.node); } @@ -1015,7 +1029,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_stability(rbml_w, stab); rbml_w.end_tag(); } - ast::ItemFn(ref decl, _, _, ref generics, _) => { + ast::ItemFn(ref decl, _, constness, _, ref generics, _) => { add_to_index(item, rbml_w, index); rbml_w.start_tag(tag_items_data_item); encode_def_id(rbml_w, def_id); @@ -1025,12 +1039,14 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(rbml_w, item.ident.name); encode_path(rbml_w, path); encode_attributes(rbml_w, &item.attrs); - if tps_len > 0 || attr::requests_inline(&item.attrs) { + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == ast::Constness::Const { encode_inlined_item(ecx, rbml_w, IIItemRef(item)); } if tps_len == 0 { encode_symbol(ecx, rbml_w, item.id); } + encode_constness(rbml_w, constness); encode_visibility(rbml_w, vis); encode_stability(rbml_w, stab); encode_method_argument_names(rbml_w, &**decl); @@ -1875,7 +1891,7 @@ fn encode_reachable_extern_fns(ecx: &EncodeContext, rbml_w: &mut Encoder) { for id in ecx.reachable { if let Some(ast_map::NodeItem(i)) = ecx.tcx.map.find(*id) { - if let ast::ItemFn(_, _, abi, ref generics, _) = i.node { + if let ast::ItemFn(_, _, _, abi, ref generics, _) = i.node { if abi != abi::Rust && !generics.is_type_parameterized() { rbml_w.wr_tagged_u32(tag_reachable_extern_fn_id, *id); } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 497022ac6ac49..d7fdb5ff6ce83 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -35,6 +35,7 @@ use util::nodemap::NodeMap; use util::ppaux; use syntax::ast; +use syntax::ast_util::PostExpansionMethod; use syntax::codemap::Span; use syntax::print::pprust; use syntax::visit::{self, Visitor}; @@ -79,6 +80,7 @@ bitflags! { #[derive(Copy, Eq, PartialEq)] enum Mode { Const, + ConstFn, Static, StaticMut, @@ -136,10 +138,87 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { }) } + fn fn_like(&mut self, + fk: visit::FnKind, + fd: &ast::FnDecl, + b: &ast::Block, + s: Span, + fn_id: ast::NodeId) + -> ConstQualif { + match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) { + Entry::Occupied(entry) => return *entry.get(), + Entry::Vacant(entry) => { + // Prevent infinite recursion on re-entry. + entry.insert(PURE_CONST); + } + } + + let mode = match fk { + visit::FkItemFn(_, _, _, ast::Constness::Const, _) => { + Mode::ConstFn + } + visit::FkMethod(_, _, m) => { + if m.pe_constness() == ast::Constness::Const { + Mode::ConstFn + } else { + Mode::Var + } + } + _ => Mode::Var + }; + + // Ensure the arguments are simple, not mutable/by-ref or patterns. + if mode == Mode::ConstFn { + for arg in &fd.inputs { + match arg.pat.node { + ast::PatIdent(ast::BindByValue(ast::MutImmutable), _, None) => {} + _ => { + span_err!(self.tcx.sess, arg.pat.span, E0022, + "arguments of constant functions can only \ + be immutable by-value bindings"); + } + } + } + } + + let qualif = self.with_mode(mode, |this| { + this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b)); + visit::walk_fn(this, fk, fd, b, s); + this.qualif + }); + + // 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); + + self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif); + qualif + } + fn add_qualif(&mut self, qualif: ConstQualif) { self.qualif = self.qualif | qualif; } + /// Returns true if the call is to a const fn or method. + fn handle_const_fn_call(&mut self, def_id: ast::DefId, ret_ty: Ty<'tcx>) -> bool { + if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) { + let qualif = self.fn_like(fn_like.kind(), + fn_like.decl(), + fn_like.body(), + fn_like.span(), + fn_like.id()); + self.add_qualif(qualif); + + if ty::type_contents(self.tcx, ret_ty).interior_unsafe() { + self.add_qualif(MUTABLE_MEM); + } + + true + } else { + false + } + } + fn record_borrow(&mut self, id: ast::NodeId, mutbl: ast::Mutability) { match self.rvalue_borrows.entry(id) { Entry::Occupied(mut entry) => { @@ -158,6 +237,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { fn msg(&self) -> &'static str { match self.mode { Mode::Const => "constant", + Mode::ConstFn => "constant function", Mode::StaticMut | Mode::Static => "static", Mode::Var => unreachable!(), } @@ -229,9 +309,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { b: &'v ast::Block, s: Span, fn_id: ast::NodeId) { - assert!(self.mode == Mode::Var); - self.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b)); - visit::walk_fn(self, fk, fd, b, s); + self.fn_like(fk, fd, b, s, fn_id); } fn visit_pat(&mut self, p: &ast::Pat) { @@ -247,6 +325,35 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { } } + fn visit_block(&mut self, block: &ast::Block) { + // Check all statements in the block + for stmt in &block.stmts { + let span = match stmt.node { + ast::StmtDecl(ref decl, _) => { + match decl.node { + ast::DeclLocal(_) => decl.span, + + // Item statements are allowed + ast::DeclItem(_) => continue + } + } + ast::StmtExpr(ref expr, _) => expr.span, + ast::StmtSemi(ref semi, _) => semi.span, + ast::StmtMac(..) => { + self.tcx.sess.span_bug(stmt.span, "unexpanded statement \ + macro in const?!") + } + }; + self.add_qualif(NOT_CONST); + if self.mode != Mode::Var { + span_err!(self.tcx.sess, span, E0016, + "blocks in {}s are limited to items and \ + tail expressions", self.msg()); + } + } + visit::walk_block(self, block); + } + fn visit_expr(&mut self, ex: &ast::Expr) { let mut outer = self.qualif; self.qualif = PURE_CONST; @@ -460,10 +567,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, Some(def::DefStatic(..)) => { match v.mode { Mode::Static | Mode::StaticMut => {} - Mode::Const => { + Mode::Const | Mode::ConstFn => { span_err!(v.tcx.sess, e.span, E0013, - "constants cannot refer to other statics, \ - insert an intermediate constant instead"); + "{}s cannot refer to other statics, insert \ + an intermediate constant instead", v.msg()); } Mode::Var => v.add_qualif(NOT_CONST) } @@ -477,6 +584,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, to an ItemConst"); } } + 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); + } def => { v.add_qualif(NOT_CONST); if v.mode != Mode::Var { @@ -501,48 +612,44 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, }; } let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()); - match def { - Some(def::DefStruct(..)) => {} + let is_const = match def { + Some(def::DefStruct(..)) => true, Some(def::DefVariant(..)) => { // Count the discriminator. v.add_qualif(NON_ZERO_SIZED); + true } - _ => { - v.add_qualif(NOT_CONST); - if v.mode != Mode::Var { - span_err!(v.tcx.sess, e.span, E0015, - "function calls in {}s are limited to \ - struct and enum constructors", v.msg()); - } + Some(def::DefMethod(did, def::FromImpl(_))) | + Some(def::DefFn(did, _)) => { + v.handle_const_fn_call(did, node_ty) } - } - } - ast::ExprBlock(ref block) => { - // Check all statements in the block - let mut block_span_err = |span| { + _ => false + }; + if !is_const { v.add_qualif(NOT_CONST); if v.mode != Mode::Var { - span_err!(v.tcx.sess, span, E0016, - "blocks in {}s are limited to items and \ - tail expressions", v.msg()); + 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 { + ty::MethodStatic(did) => Some(did), + _ => None }; - for stmt in &block.stmts { - match stmt.node { - ast::StmtDecl(ref decl, _) => { - match decl.node { - ast::DeclLocal(_) => block_span_err(decl.span), - - // Item statements are allowed - ast::DeclItem(_) => {} - } - } - ast::StmtExpr(ref expr, _) => block_span_err(expr.span), - ast::StmtSemi(ref semi, _) => block_span_err(semi.span), - ast::StmtMac(..) => { - v.tcx.sess.span_bug(e.span, "unexpanded statement \ - macro in const?!") - } + let is_const = match method_did { + Some(did) => v.handle_const_fn_call(did, node_ty), + None => false + }; + if !is_const { + v.add_qualif(NOT_CONST); + if v.mode != Mode::Var { + span_err!(v.tcx.sess, e.span, E0021, + "method calls in {}s are limited to \ + constant inherent methods", v.msg()); } } } @@ -563,7 +670,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } ast::ExprClosure(..) => { - // Paths in constant constexts cannot refer to local variables, + // Paths in constant contexts cannot refer to local variables, // as there are none, and thus closures can't have upvars there. if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) { assert!(v.mode == Mode::Var, @@ -572,6 +679,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, } } + ast::ExprBlock(_) | ast::ExprUnary(..) | ast::ExprBinary(..) | ast::ExprIndex(..) | @@ -600,8 +708,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, // Miscellaneous expressions that could be implemented. ast::ExprRange(..) | - // Various other expressions. - ast::ExprMethodCall(..) | + // Expressions with side-effects. ast::ExprAssign(..) | ast::ExprAssignOp(..) | ast::ExprInlineAsm(_) | diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 96433729a9b96..06b0fc2669020 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -20,10 +20,12 @@ use middle::ty::{self, Ty}; use middle::astconv_util::ast_ty_to_prim_ty; use syntax::ast::{self, Expr}; +use syntax::ast_map::blocks::FnLikeNode; +use syntax::ast_util::{self, PostExpansionMethod}; use syntax::codemap::Span; use syntax::parse::token::InternedString; use syntax::ptr::P; -use syntax::{ast_map, ast_util, codemap}; +use syntax::{ast_map, codemap, visit}; use std::borrow::{Cow, IntoCow}; use std::num::wrapping::OverflowingOps; @@ -132,6 +134,63 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId) } } +fn inline_const_fn_from_external_crate(tcx: &ty::ctxt, def_id: ast::DefId) + -> Option { + match tcx.extern_const_fns.borrow().get(&def_id) { + Some(&ast::DUMMY_NODE_ID) => return None, + Some(&fn_id) => return Some(fn_id), + None => {} + } + + if !csearch::is_const_fn(&tcx.sess.cstore, def_id) { + tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID); + return None; + } + + 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), + _ => 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> { + + 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 + } else { + return None; + } + } else { + def_id.node + }; + + let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) { + Some(fn_like) => fn_like, + None => return None + }; + + match fn_like.kind() { + visit::FkItemFn(_, _, _, ast::Constness::Const, _) => { + Some(fn_like) + } + visit::FkMethod(_, _, m) => { + if m.pe_constness() == ast::Constness::Const { + Some(fn_like) + } else { + None + } + } + _ => None + } +} + #[derive(Clone, PartialEq)] pub enum const_val { const_float(f64), diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 378f3db082339..38e3ee50c82a4 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -87,8 +87,8 @@ 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(_, _, fn_style, _) => - (true, fn_style == ast::Unsafety::Unsafe), + visit::FkItemFn(_, _, unsafety, _, _) => + (true, unsafety == ast::Unsafety::Unsafe), visit::FkMethod(_, sig) => (true, sig.unsafety == ast::Unsafety::Unsafe), _ => (false, false), diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 1ca56596a0147..88d69f5e081d7 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -159,6 +159,7 @@ trait ErrorReportingHelpers<'tcx> { fn give_expl_lifetime_param(&self, decl: &ast::FnDecl, unsafety: ast::Unsafety, + constness: ast::Constness, ident: ast::Ident, opt_explicit_self: Option<&ast::ExplicitSelf_>, generics: &ast::Generics, @@ -840,8 +841,9 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { Some(ref node) => match *node { ast_map::NodeItem(ref item) => { match item.node { - ast::ItemFn(ref fn_decl, pur, _, ref gen, _) => { - Some((fn_decl, gen, pur, item.ident, None, item.span)) + ast::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => { + Some((fn_decl, gen, unsafety, constness, + item.ident, None, item.span)) }, _ => None } @@ -852,6 +854,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { Some((&sig.decl, &sig.generics, sig.unsafety, + sig.constness, item.ident, Some(&sig.explicit_self.node), item.span)) @@ -866,6 +869,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { Some((&sig.decl, &sig.generics, sig.unsafety, + sig.constness, item.ident, Some(&sig.explicit_self.node), item.span)) @@ -877,12 +881,12 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { }, None => None }; - let (fn_decl, generics, unsafety, ident, expl_self, span) + let (fn_decl, generics, unsafety, constness, ident, expl_self, span) = node_inner.expect("expect item fn"); let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, generics, same_regions, &life_giver); let (fn_decl, expl_self, generics) = rebuilder.rebuild(); - self.give_expl_lifetime_param(&fn_decl, unsafety, ident, + self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident, expl_self.as_ref(), &generics, span); } } @@ -1437,12 +1441,13 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { fn give_expl_lifetime_param(&self, decl: &ast::FnDecl, unsafety: ast::Unsafety, + constness: ast::Constness, ident: ast::Ident, opt_explicit_self: Option<&ast::ExplicitSelf_>, generics: &ast::Generics, span: codemap::Span) { - let suggested_fn = pprust::fun_to_string(decl, unsafety, ident, - opt_explicit_self, generics); + let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident, + opt_explicit_self, generics); let msg = format!("consider using an explicit lifetime \ parameter as shown: {}", suggested_fn); self.tcx.sess.span_help(span, &msg[..]); @@ -1724,7 +1729,7 @@ fn lifetimes_in_scope(tcx: &ty::ctxt, let method_id_opt = match tcx.map.find(parent) { Some(node) => match node { ast_map::NodeItem(item) => match item.node { - ast::ItemFn(_, _, _, ref gen, _) => { + ast::ItemFn(_, _, _, _, ref gen, _) => { taken.push_all(&gen.lifetimes); None }, diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 7ded344414ce6..9a803da643989 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -46,7 +46,7 @@ fn item_might_be_inlined(item: &ast::Item) -> bool { match item.node { ast::ItemImpl(_, _, ref generics, _, _, _) | - ast::ItemFn(_, _, _, ref generics, _) => { + ast::ItemFn(_, _, _, _, ref generics, _) => { generics_require_inlining(generics) } _ => false, @@ -254,7 +254,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // but all other rust-only interfaces can be private (they will not // participate in linkage after this product is produced) if let ast_map::NodeItem(item) = *node { - if let ast::ItemFn(_, _, abi, _, _) = item.node { + if let ast::ItemFn(_, _, _, abi, _, _) = item.node { if abi != abi::Rust { self.reachable_symbols.insert(search_item); } @@ -271,7 +271,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - ast::ItemFn(_, _, _, _, ref search_block) => { + ast::ItemFn(_, _, _, _, _, ref search_block) => { if item_might_be_inlined(&*item) { visit::walk_block(self, &**search_block) } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index e33a255343161..d8a32cce63bbf 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -142,7 +142,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v ast::FnDecl, b: &'v ast::Block, s: Span, _: ast::NodeId) { match fk { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => self.visit_early_late(subst::FnSpace, generics, |this| { visit::walk_fn(this, fk, fd, b, s) }) diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 01766b0de085f..9b2f20e137bd5 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -23,7 +23,7 @@ use syntax::{attr, visit}; use syntax::ast; use syntax::ast::{Attribute, Block, Crate, DefId, FnDecl, NodeId, Variant}; use syntax::ast::{Item, Generics, StructField}; -use syntax::ast_util::is_local; +use syntax::ast_util::{is_local, PostExpansionMethod}; use syntax::attr::{Stability, AttrMetaMethods}; use syntax::visit::{FnKind, Visitor}; use syntax::feature_gate::emit_feature_warn; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8705e56b09425..f403cf82f2826 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -791,10 +791,10 @@ pub struct ctxt<'tcx> { /// Borrows pub upvar_capture_map: RefCell, - /// These two caches are used by const_eval when decoding external statics - /// and variants that are found. + /// These caches are used by const_eval when decoding external constants. pub extern_const_statics: RefCell>, pub extern_const_variants: RefCell>, + pub extern_const_fns: RefCell>, pub method_map: MethodMap<'tcx>, @@ -2355,7 +2355,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } Some(ast_map::NodeItem(item)) => { match item.node { - ast::ItemFn(_, _, _, _, ref body) => { + ast::ItemFn(_, _, _, _, _, ref body) => { // We assume this is a function. let fn_def_id = ast_util::local_def(id); let fn_scheme = lookup_item_type(cx, fn_def_id); @@ -2602,6 +2602,7 @@ pub fn mk_ctxt<'tcx>(s: Session, upvar_capture_map: RefCell::new(FnvHashMap()), extern_const_statics: RefCell::new(DefIdMap()), extern_const_variants: RefCell::new(DefIdMap()), + extern_const_fns: RefCell::new(DefIdMap()), method_map: RefCell::new(FnvHashMap()), dependency_formats: RefCell::new(FnvHashMap()), closure_kinds: RefCell::new(DefIdMap()), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 074591fb927d2..4b8e42adb3ffc 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -991,7 +991,7 @@ impl LintPass for NonSnakeCase { }, _ => (), }, - visit::FkItemFn(ident, _, _, _) => { + visit::FkItemFn(ident, _, _, _, _) => { self.check_snake_case(cx, "function", ident, span) }, _ => (), @@ -1315,7 +1315,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) => { @@ -1808,7 +1808,7 @@ impl LintPass for UnconditionalRecursion { ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool; let (name, checker) = match fn_kind { - visit::FkItemFn(name, _, _, _) => (name, id_refers_to_this_fn as F), + visit::FkItemFn(name, _, _, _, _) => (name, id_refers_to_this_fn as F), visit::FkMethod(name, _) => (name, id_refers_to_this_method as F), // closures can't recur, so they don't matter. visit::FkFnBlock => return diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1cbbcad955090..4aa5ded95a565 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -421,7 +421,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { .define_value(DefConst(local_def(item.id)), sp, modifiers); parent.clone() } - ItemFn(_, _, _, _, _) => { + ItemFn(_, _, _, _, _, _) => { let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp); let def = DefFn(local_def(item.id), false); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e49fdc9c5d356..cacb7159227be 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -238,7 +238,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 } @@ -2767,7 +2767,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { ItemRibKind), |this| visit::walk_item(this, item)); } - ItemFn(_, _, _, ref generics, _) => { + ItemFn(_, _, _, _, ref generics, _) => { self.with_type_parameter_rib(HasTypeParameters(generics, FnSpace, ItemRibKind), diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 83bb5efb425d2..5e870358cb7fc 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1176,7 +1176,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'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, mt, ref expr) => self.process_static(item, &**typ, mt, &**expr), diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 2ab6f5b0f9521..dd2ac9ee4f918 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -278,14 +278,14 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { match *self { ConstantValue(ConstantExpr(lit_expr), _) => { let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id); - let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs); + let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None); let lit_datum = immediate_rvalue(llval, lit_ty); let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx)); SingleResult(Result::new(bcx, lit_datum.val)) } ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => { - let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs); - let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs); + let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None); + let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None); RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } Variant(disr_val, ref repr, _, _) => { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 74326d4ea919c..ec578c80fa1f6 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1262,7 +1262,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option) let blk = match tcx.map.find(id) { Some(ast_map::NodeItem(i)) => { match i.node { - ast::ItemFn(_, _, _, _, ref blk) => { + ast::ItemFn(_, _, _, _, _, ref blk) => { blk } _ => tcx.sess.bug("unexpected item variant in has_nested_returns") @@ -2230,7 +2230,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) { let from_external = ccx.external_srcs().borrow().contains_key(&item.id); match item.node { - ast::ItemFn(ref decl, _fn_style, abi, ref generics, ref body) => { + ast::ItemFn(ref decl, _, _, abi, ref generics, ref body) => { if !generics.is_type_parameterized() { let trans_everywhere = attr::requests_inline(&item.attrs); // Ignore `trans_everywhere` for cross-crate inlined items @@ -2743,7 +2743,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); - let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs); + let (v, ty) = consts::const_expr(ccx, &**expr, empty_substs, None); ccx.static_values().borrow_mut().insert(id, v); unsafe { // boolean SSA values are i1, but they have to be stored in i8 slots, @@ -2771,7 +2771,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } } - ast::ItemFn(_, _, abi, _, _) => { + ast::ItemFn(_, _, _, abi, _, _) => { let sym = sym(); let llfn = if abi == Rust { register_fn(ccx, i.span, sym, i.id, ty) diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 8dcabe0a94bb8..ddf1fa4ae5c15 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -23,12 +23,15 @@ use trans::type_of; use middle::subst::Substs; use middle::ty::{self, Ty}; use util::ppaux::{Repr, ty_to_string}; +use util::nodemap::NodeMap; use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; use syntax::ptr::P; +type FnArgMap<'a> = Option<&'a NodeMap>; + pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) -> ValueRef { let _icx = push_ctxt("trans_lit"); @@ -157,6 +160,29 @@ fn const_deref<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } +fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + node: ExprOrMethodCall, + def_id: ast::DefId, + arg_vals: &[ValueRef], + param_substs: &'tcx Substs<'tcx>) -> ValueRef { + let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id); + let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call"); + + let args = &fn_like.decl().inputs; + assert_eq!(args.len(), arg_vals.len()); + + let arg_ids = args.iter().map(|arg| arg.pat.id); + let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect(); + + let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs)); + match fn_like.body().expr { + Some(ref expr) => { + const_expr(ccx, &**expr, substs, Some(&fn_args)).0 + } + None => C_nil(ccx) + } +} + pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: ast::DefId, ref_expr: &ast::Expr) @@ -217,9 +243,9 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // references, even when only the latter are correct. let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, &ty::expr_ty(ccx.tcx(), expr)); - const_expr_unadjusted(ccx, expr, ty, param_substs) + const_expr_unadjusted(ccx, expr, ty, param_substs, None) } else { - const_expr(ccx, expr, param_substs).0 + const_expr(ccx, expr, param_substs, None).0 }; // boolean SSA values are i1, but they have to be stored in i8 slots, @@ -239,11 +265,12 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr, - param_substs: &'tcx Substs<'tcx>) + param_substs: &'tcx Substs<'tcx>, + fn_args: FnArgMap) -> (ValueRef, Ty<'tcx>) { let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs, &ty::expr_ty(cx.tcx(), e)); - let llconst = const_expr_unadjusted(cx, e, ety, param_substs); + let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args); let mut llconst = llconst; let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs, &ty::expr_ty_adjusted(cx.tcx(), e)); @@ -352,10 +379,12 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr, ety: Ty<'tcx>, - param_substs: &'tcx Substs<'tcx>) -> ValueRef { - let map_list = |exprs: &[P]| { - exprs.iter().map(|e| const_expr(cx, &**e, param_substs).0) - .fold(Vec::new(), |mut l, val| { l.push(val); l }) + param_substs: &'tcx Substs<'tcx>, + fn_args: FnArgMap) + -> ValueRef { + let map_list = |exprs: &[P]| -> Vec { + exprs.iter().map(|e| const_expr(cx, &**e, param_substs, fn_args).0) + .collect() }; unsafe { let _icx = push_ctxt("const_expr"); @@ -366,7 +395,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprBinary(b, ref e1, ref e2) => { /* Neither type is bottom, and we expect them to be unified * already, so the following is safe. */ - let (te1, ty) = const_expr(cx, &**e1, param_substs); + let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args); let is_simd = ty::type_is_simd(cx.tcx(), ty); let intype = if is_simd { ty::simd_type(cx.tcx(), ty) @@ -376,7 +405,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let is_float = ty::type_is_fp(intype); let signed = ty::type_is_signed(intype); - let (te2, _) = const_expr(cx, &**e2, param_substs); + let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args); let te2 = base::cast_shift_const_rhs(b, te1, te2); match b.node { @@ -431,7 +460,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } }, ast::ExprUnary(u, ref e) => { - let (te, ty) = const_expr(cx, &**e, param_substs); + let (te, ty) = const_expr(cx, &**e, param_substs, fn_args); let is_float = ty::type_is_fp(ty); match u { ast::UnUniq | ast::UnDeref => { @@ -445,7 +474,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ast::ExprField(ref base, field) => { - let (bv, bt) = const_expr(cx, &**base, param_substs); + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| { let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys); @@ -453,7 +482,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }) } ast::ExprTupField(ref base, idx) => { - let (bv, bt) = const_expr(cx, &**base, param_substs); + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let brepr = adt::represent_type(cx, bt); expr::with_field_tys(cx.tcx(), bt, None, |discr, _| { adt::const_get_field(cx, &*brepr, bv, discr, idx.node) @@ -461,7 +490,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } ast::ExprIndex(ref base, ref index) => { - let (bv, bt) = const_expr(cx, &**base, param_substs); + let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args); let iv = match const_eval::eval_const_expr_partial(cx.tcx(), &**index, None) { Ok(const_eval::const_int(i)) => i as u64, Ok(const_eval::const_uint(u)) => u, @@ -512,7 +541,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } ast::ExprCast(ref base, _) => { let llty = type_of::type_of(cx, ety); - let (v, basety) = const_expr(cx, &**base, param_substs); + let (v, basety) = const_expr(cx, &**base, param_substs, fn_args); if expr::cast_is_noop(basety, ety) { return v; } @@ -590,12 +619,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } else { // If this isn't the address of a static, then keep going through // normal constant evaluation. - let (v, _) = const_expr(cx, &**sub, param_substs); + let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); addr_of(cx, v, "ref", e.id) } } ast::ExprAddrOf(ast::MutMutable, ref sub) => { - let (v, _) = const_expr(cx, &**sub, param_substs); + let (v, _) = const_expr(cx, &**sub, param_substs, fn_args); addr_of_mut(cx, v, "ref_mut_slice", e.id) } ast::ExprTup(ref es) => { @@ -607,7 +636,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let repr = adt::represent_type(cx, ety); let base_val = match *base_opt { - Some(ref base) => Some(const_expr(cx, &**base, param_substs)), + Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)), None => None }; @@ -615,7 +644,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let cs = field_tys.iter().enumerate() .map(|(ix, &field_ty)| { match fs.iter().find(|f| field_ty.name == f.ident.node.name) { - Some(ref f) => const_expr(cx, &*f.expr, param_substs).0, + Some(ref f) => const_expr(cx, &*f.expr, param_substs, fn_args).0, None => { match base_val { Some((bv, _)) => { @@ -640,7 +669,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprVec(ref es) => { let unit_ty = ty::sequence_element_type(cx.tcx(), ety); let llunitty = type_of::type_of(cx, unit_ty); - let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs).0) + let vs = es.iter().map(|e| const_expr(cx, &**e, param_substs, fn_args).0) .collect::>(); // If the vector contains enums, an LLVM array won't work. if vs.iter().any(|vi| val_ty(*vi) != llunitty) { @@ -657,7 +686,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Ok(const_eval::const_uint(i)) => i as uint, _ => cx.sess().span_bug(count.span, "count must be integral const expression.") }; - let unit_val = const_expr(cx, &**elem, param_substs).0; + let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0; let vs: Vec<_> = repeat(unit_val).take(n).collect(); if val_ty(unit_val) != llunitty { C_struct(cx, &vs[..], false) @@ -668,6 +697,13 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ast::ExprPath(..) => { let def = cx.tcx().def_map.borrow()[e.id].full_def(); match def { + def::DefLocal(id) => { + if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) { + val + } else { + cx.sess().span_bug(e.span, "const fn argument not found") + } + } def::DefFn(..) | def::DefMethod(..) => { expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val } @@ -703,10 +739,24 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } ast::ExprCall(ref callee, ref args) => { - let opt_def = cx.tcx().def_map.borrow().get(&callee.id).map(|d| d.full_def()); - let arg_vals = map_list(&args[..]); - match opt_def { - Some(def::DefStruct(_)) => { + let mut callee = &**callee; + loop { + callee = match callee.node { + ast::ExprParen(ref inner) => &**inner, + ast::ExprBlock(ref block) => match block.expr { + Some(ref tail) => &**tail, + None => break + }, + _ => break + }; + } + 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, _) => { + const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs) + } + def::DefStruct(_) => { if ty::type_is_simd(cx.tcx(), ety) { C_vector(&arg_vals[..]) } else { @@ -714,7 +764,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, adt::trans_const(cx, &*repr, 0, &arg_vals[..]) } } - Some(def::DefVariant(enum_did, variant_did, _)) => { + def::DefVariant(enum_did, variant_did, _) => { let repr = adt::represent_type(cx, ety); let vinfo = ty::enum_variant_with_id(cx.tcx(), enum_did, @@ -724,13 +774,23 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, vinfo.disr_val, &arg_vals[..]) } - _ => cx.sess().span_bug(e.span, "expected a struct or variant def") + _ => cx.sess().span_bug(e.span, "expected a struct, variant, or const fn def") } } - ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs).0, + 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 { + ty::MethodStatic(did) => did, + _ => cx.sess().span_bug(e.span, "expected a const method def") + }; + const_fn_call(cx, MethodCallKey(method_call), + method_did, &arg_vals, param_substs) + } + ast::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0, ast::ExprBlock(ref block) => { match block.expr { - Some(ref expr) => const_expr(cx, &**expr, param_substs).0, + Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0, None => C_nil(cx) } } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index b5ab2c2825127..7cd4b51ebe787 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1290,7 +1290,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, fn_decl, generics, top_level_block, item.span, true) } _ => { diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 2034c6223c134..58ac32fce4acd 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -55,7 +55,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) trans_item(ccx, &**item); let linkage = match item.node { - ast::ItemFn(_, _, _, ref generics, _) => { + ast::ItemFn(_, _, _, _, ref generics, _) => { if generics.is_type_parameterized() { // Generics have no symbol, so they can't be given any // linkage. diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 2083e737f89b1..c4637d6f21e8d 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -173,7 +173,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ast_map::NodeItem(i) => { match *i { ast::Item { - node: ast::ItemFn(ref decl, _, abi, _, ref body), + node: ast::ItemFn(ref decl, _, _, abi, _, ref body), .. } => { let d = mk_lldecl(abi); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 41951ab2b6200..9288338d20882 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -718,7 +718,7 @@ pub fn check_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) { &enum_definition.variants, it.id); } - ast::ItemFn(ref decl, _, _, _, ref body) => { + ast::ItemFn(ref decl, _, _, _, _, ref body) => { let fn_pty = ty::lookup_item_type(ccx.tcx, ast_util::local_def(it.id)); let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id); check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2372680576797..069556e46adcd 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1391,7 +1391,7 @@ fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, let ty = ccx.icx(&()).to_ty(&ExplicitRscope, &**t); ty::TypeScheme { ty: ty, generics: ty::Generics::empty() } } - ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => { + ast::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty()); let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl); let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd)); @@ -1443,7 +1443,7 @@ fn convert_typed_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::ItemStatic(..) | ast::ItemConst(..) => { ty::GenericPredicates::empty() } - ast::ItemFn(_, _, _, ref ast_generics, _) => { + ast::ItemFn(_, _, _, _, ref ast_generics, _) => { ty_generic_predicates_for_fn(ccx, ast_generics, &ty::GenericPredicates::empty()) } ast::ItemTy(_, ref generics) => { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index bbc64a54013b7..bd6fa7a8941d9 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -218,7 +218,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt, match tcx.map.find(main_id) { Some(ast_map::NodeItem(it)) => { match it.node { - ast::ItemFn(_, _, _, ref ps, _) + ast::ItemFn(_, _, _, _, ref ps, _) if ps.is_parameterized() => { span_err!(ccx.tcx.sess, main_span, E0131, "main function is not allowed to have type parameters"); @@ -265,7 +265,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt, match tcx.map.find(start_id) { Some(ast_map::NodeItem(it)) => { match it.node { - ast::ItemFn(_,_,_,ref ps,_) + ast::ItemFn(_,_,_,_,ref ps,_) if ps.is_parameterized() => { span_err!(tcx.sess, start_span, E0132, "start function is not allowed to have type parameters"); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 9f7b68f38fa6e..ec279c5c05fc0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -169,6 +169,7 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> decl: decl, generics: (&t.generics, &predicates, subst::FnSpace).clean(cx), unsafety: style, + constness: ast::Constness::NotConst } } @@ -300,6 +301,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt, }) => { clean::MethodItem(clean::Method { unsafety: unsafety, + constness: ast::Constness::NotConst, decl: decl, self_: self_, generics: generics, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e91e95961c521..51df1145712bf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -944,6 +944,7 @@ pub struct Method { pub generics: Generics, pub self_: SelfTy, pub unsafety: ast::Unsafety, + pub constness: ast::Constness, pub decl: FnDecl, pub abi: abi::Abi } @@ -965,7 +966,8 @@ impl Clean for ast::MethodSig { Method { generics: self.generics.clean(cx), self_: self.explicit_self.node.clean(cx), - unsafety: self.unsafety.clone(), + unsafety: self.unsafety, + constness: self.constness, decl: decl, abi: self.abi } @@ -1030,6 +1032,7 @@ pub struct Function { pub decl: FnDecl, pub generics: Generics, pub unsafety: ast::Unsafety, + pub constness: ast::Constness, } impl Clean for doctree::Function { @@ -1045,6 +1048,7 @@ impl Clean for doctree::Function { decl: self.decl.clean(cx), generics: self.generics.clean(cx), unsafety: self.unsafety, + constness: self.constness, }), } } @@ -2243,6 +2247,7 @@ impl Clean for ast::ForeignItem { decl: decl.clean(cx), generics: generics.clean(cx), unsafety: ast::Unsafety::Unsafe, + constness: ast::Constness::NotConst }) } ast::ForeignItemStatic(ref ty, mutbl) => { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 5a4deaa2e7266..6fd546d39aa32 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -132,6 +132,7 @@ pub struct Function { pub vis: ast::Visibility, pub stab: Option, pub unsafety: ast::Unsafety, + pub constness: ast::Constness, pub whence: Span, pub generics: ast::Generics, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 03a2d708ee43a..258a15d87eb3c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -36,6 +36,10 @@ pub struct VisSpace(pub Option); /// space after it. #[derive(Copy)] 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)] +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); /// Similar to VisSpace, but used for mutability @@ -67,6 +71,12 @@ impl UnsafetySpace { } } +impl ConstnessSpace { + pub fn get(&self) -> ast::Constness { + let ConstnessSpace(v) = *self; v + } +} + impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { for (i, item) in self.0.iter().enumerate() { @@ -613,6 +623,15 @@ impl fmt::Display for UnsafetySpace { } } +impl fmt::Display for ConstnessSpace { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.get() { + ast::Constness::Const => write!(f, "const "), + ast::Constness::NotConst => Ok(()) + } + } +} + impl fmt::Display for clean::Import { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index dba7b16eceecb..28be87952904a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -60,7 +60,7 @@ use clean; use doctree; use fold::DocFolder; use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace, Stability}; -use html::format::{ConciseStability, TyParamBounds, WhereClause}; +use html::format::{ConciseStability, ConstnessSpace, TyParamBounds, WhereClause}; use html::highlight; use html::item_type::ItemType; use html::layout; @@ -1651,10 +1651,11 @@ fn item_static(w: &mut fmt::Formatter, it: &clean::Item, fn item_function(w: &mut fmt::Formatter, it: &clean::Item, f: &clean::Function) -> fmt::Result { - try!(write!(w, "
{vis}{unsafety}fn \
+    try!(write!(w, "
{vis}{unsafety}{constness}fn \
                     {name}{generics}{decl}{where_clause}
", vis = VisSpace(it.visibility), unsafety = UnsafetySpace(f.unsafety), + constness = ConstnessSpace(f.constness), name = it.name.as_ref().unwrap(), generics = f.generics, where_clause = WhereClause(&f.generics), @@ -1818,18 +1819,20 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, } fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result { - fn method(w: &mut fmt::Formatter, it: &clean::Item, - unsafety: ast::Unsafety, abi: abi::Abi, - g: &clean::Generics, selfty: &clean::SelfTy, + fn method(w: &mut fmt::Formatter, + it: &clean::Item, + unsafety: ast::Unsafety, + constness: ast::Constness, + abi: abi::Abi, + g: &clean::Generics, + selfty: &clean::SelfTy, d: &clean::FnDecl) -> fmt::Result { use syntax::abi::Abi; - write!(w, "{}{}fn {name}\ + write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", - match unsafety { - ast::Unsafety::Unsafe => "unsafe ", - _ => "", - }, + UnsafetySpace(unsafety), + ConstnessSpace(constness), match abi { Abi::Rust => String::new(), a => format!("extern {} ", a.to_string()) @@ -1842,10 +1845,12 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item) -> fmt::Result { } match meth.inner { clean::TyMethodItem(ref m) => { - method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl) + method(w, meth, m.unsafety, ast::Constness::NotConst, + m.abi, &m.generics, &m.self_, &m.decl) } clean::MethodItem(ref m) => { - method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl) + method(w, meth, m.unsafety, m.constness, + m.abi, &m.generics, &m.self_, &m.decl) } clean::AssociatedTypeItem(ref bounds, ref default) => { assoc_type(w, meth, bounds, default) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 3e998166397bc..6ad38cb0ed850 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -120,7 +120,9 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { pub fn visit_fn(&mut self, item: &ast::Item, name: ast::Ident, fd: &ast::FnDecl, - unsafety: &ast::Unsafety, _abi: &abi::Abi, + unsafety: ast::Unsafety, + constness: ast::Constness, + _abi: &abi::Abi, gen: &ast::Generics) -> Function { debug!("Visiting fn"); Function { @@ -132,7 +134,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: name, whence: item.span, generics: gen.clone(), - unsafety: *unsafety, + unsafety: unsafety, + constness: constness } } @@ -285,8 +288,9 @@ 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, ref pur, ref abi, ref gen, _) => - om.fns.push(self.visit_fn(item, name, &**fd, pur, abi, gen)), + ast::ItemFn(ref fd, 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) => { let t = Typedef { ty: ty.clone(), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 657ffcaece9f8..51f742ab1e660 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1350,6 +1350,12 @@ pub enum Unsafety { Normal, } +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum Constness { + Const, + NotConst, +} + impl fmt::Display for Unsafety { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(match *self { @@ -1416,6 +1422,7 @@ pub enum ExplicitSelf_ { pub type ExplicitSelf = Spanned; #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] + Constness, pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token @@ -1623,7 +1630,7 @@ pub enum Item_ { ItemStatic(P, Mutability, P), ItemConst(P, P), - ItemFn(P, Unsafety, Abi, Generics, P), + ItemFn(P, Unsafety, Constness, Abi, Generics, P), ItemMod(Mod), ItemForeignMod(ForeignMod), ItemTy(P, Generics), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 16a339cdcb530..a6f574a5a4be2 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -96,20 +96,10 @@ impl<'a> Code<'a> { /// Attempts to construct a Code from presumed FnLike or Block node input. pub fn from_node(node: Node) -> Option { - fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } } - match node { - ast_map::NodeItem(item) if item.is_fn_like() => - Some(FnLikeCode(new(node))), - ast_map::NodeTraitItem(tm) if tm.is_fn_like() => - Some(FnLikeCode(new(node))), - ast_map::NodeImplItem(_) => - Some(FnLikeCode(new(node))), - ast_map::NodeExpr(e) if e.is_fn_like() => - Some(FnLikeCode(new(node))), - ast_map::NodeBlock(block) => - Some(BlockCode(block)), - _ => - None, + if let ast_map::NodeBlock(block) = node { + Some(BlockCode(block)) + } else { + FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) } } } @@ -120,6 +110,7 @@ struct ItemFnParts<'a> { ident: ast::Ident, decl: &'a ast::FnDecl, unsafety: ast::Unsafety, + constness: ast::Constness, abi: abi::Abi, generics: &'a ast::Generics, body: &'a Block, @@ -143,6 +134,24 @@ impl<'a> ClosureParts<'a> { } impl<'a> FnLikeNode<'a> { + /// Attempts to construct a FnLikeNode from presumed FnLike node input. + pub fn from_node(node: Node) -> Option { + let fn_like = match node { + ast_map::NodeItem(item) => item.is_fn_like(), + ast_map::NodeTraitItem(tm) => tm.is_fn_like(), + ast_map::NodeImplItem(_) => true, + ast_map::NodeExpr(e) => e.is_fn_like(), + _ => false + }; + if fn_like { + Some(FnLikeNode { + node: node + }) + } else { + None + } + } + pub fn to_fn_parts(self) -> FnParts<'a> { FnParts { decl: self.decl(), @@ -179,7 +188,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) + visit::FkItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi) }; let closure = |_: ClosureParts| { visit::FkFnBlock @@ -197,10 +206,17 @@ impl<'a> FnLikeNode<'a> { { match self.node { ast_map::NodeItem(i) => match i.node { - ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) => - item_fn(ItemFnParts{ - ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block, - generics: generics, abi: abi, id: i.id, span: i.span + 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, + span: i.span }), _ => panic!("item FnLikeNode that is not fn-like"), }, diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index cec824e79ff5a..e776bfba13b47 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -267,6 +267,7 @@ pub fn impl_pretty_name(trait_ref: &Option, ty: Option<&Ty>) -> Ident token::gensym_ident(&pretty[..]) } + _, pub fn struct_field_visibility(field: ast::StructField) -> Visibility { match field.node.kind { ast::NamedField(_, v) | ast::UnnamedField(v) => v @@ -456,7 +457,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { self.operation.visit_id(node_id); match function_kind { - visit::FkItemFn(_, generics, _, _) => { + visit::FkItemFn(_, generics, _, _, _) => { self.visit_generics_helper(generics) } visit::FkMethod(_, sig) => { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index d916651b05617..54deae2426b41 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -1034,6 +1034,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> { Vec::new(), ast::ItemFn(self.fn_decl(inputs, output), ast::Unsafety::Normal, + ast::Constness::NotConst, abi::Rust, generics, body)) diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 58b6d96607df7..68f73d096359d 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -729,6 +729,7 @@ impl<'a> MethodDef<'a> { abi: abi, explicit_self: explicit_self, unsafety: ast::Unsafety::Normal, + constness: ast::Constness::NotConst, decl: fn_decl }, body_block) }) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ee2cf9017bbf3..ea01054741126 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -557,11 +557,12 @@ fn expand_item_modifiers(mut it: P, fld: &mut MacroExpander) /// Expand item_underscore fn expand_item_underscore(item: ast::Item_, fld: &mut MacroExpander) -> ast::Item_ { match item { - ast::ItemFn(decl, fn_style, abi, generics, body) => { + ast::ItemFn(decl, unsafety, constness, abi, generics, body) => { let (rewritten_fn_decl, rewritten_body) = expand_and_rename_fn_decl_and_block(decl, body, fld); let expanded_generics = fold::noop_fold_generics(generics,fld); - ast::ItemFn(rewritten_fn_decl, fn_style, abi, expanded_generics, rewritten_body) + ast::ItemFn(rewritten_fn_decl, unsafety, constness, abi, + expanded_generics, rewritten_body) } _ => noop_fold_item_underscore(item, fld) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 48c045ee4f98f..c38556b078219 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -361,8 +361,7 @@ pub mod rt { parse::parse_stmt_from_source_str("".to_string(), s, self.cfg(), - Vec::new(), - self.parse_sess()) + self.parse_sess()).expect("parse error") } fn parse_expr(&self, s: String) -> P { @@ -407,7 +406,7 @@ pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts); + let expanded = expand_parse_call(cx, sp, "parse_expr", vec!(), tts); base::MacEager::expr(expanded) } @@ -415,8 +414,7 @@ pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes", - vec!(), tts); + let expanded = expand_parse_call(cx, sp, "parse_item", vec!(), tts); base::MacEager::expr(expanded) } @@ -448,9 +446,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { - let e_attrs = cx.expr_vec_ng(sp); - let expanded = expand_parse_call(cx, sp, "parse_stmt", - vec!(e_attrs), tts); + let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(), tts); base::MacEager::expr(expanded) } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index eb0daac3ab84c..c61aec0069db2 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -115,7 +115,7 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree -> Option>> { let mut ret = SmallVector::zero(); while self.p.token != token::Eof { - match self.p.parse_item_with_outer_attributes() { + match self.p.parse_item() { Some(item) => ret.push(item), None => self.p.span_fatal( self.p.span, diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index eb15d708232a0..b7d40a46f3ea2 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -521,12 +521,15 @@ pub fn parse_nt(p: &mut Parser, sp: Span, name: &str) -> Nonterminal { // check at the beginning and the parser checks after each bump p.check_unknown_macro_variable(); match name { - "item" => match p.parse_item(Vec::new()) { + "item" => match p.parse_item() { Some(i) => token::NtItem(i), None => p.fatal("expected an item keyword") }, "block" => token::NtBlock(p.parse_block()), - "stmt" => token::NtStmt(p.parse_stmt(Vec::new())), + "stmt" => match p.parse_stmt() { + Some(s) => token::NtStmt(s), + None => p.fatal("expected a statement") + }, "pat" => token::NtPat(p.parse_pat()), "expr" => token::NtExpr(p.parse_expr()), "ty" => token::NtTy(p.parse_ty()), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 7575d4b5ecdbe..7a2ae55e91494 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -17,7 +17,6 @@ use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::{parse, parse_or_else}; use parse::lexer::new_tt_reader; use parse::parser::Parser; -use parse::attr::ParserAttr; use parse::token::{self, special_idents, gensym_ident, NtTT, Token}; use parse::token::Token::*; use print; @@ -68,15 +67,8 @@ impl<'a> MacResult for ParserAnyMacro<'a> { } fn make_items(self: Box>) -> Option>> { let mut ret = SmallVector::zero(); - loop { - let mut parser = self.parser.borrow_mut(); - // so... do outer attributes attached to the macro invocation - // just disappear? This question applies to make_impl_items, as - // well. - match parser.parse_item_with_outer_attributes() { - Some(item) => ret.push(item), - None => break - } + while let Some(item) = self.parser.borrow_mut().parse_item() { + ret.push(item); } self.ensure_complete_parse(false); Some(ret) @@ -89,7 +81,7 @@ impl<'a> MacResult for ParserAnyMacro<'a> { let mut parser = self.parser.borrow_mut(); match parser.token { token::Eof => break, - _ => ret.push(parser.parse_impl_item_with_outer_attributes()) + _ => ret.push(parser.parse_impl_item()) } } self.ensure_complete_parse(false); @@ -97,10 +89,9 @@ impl<'a> MacResult for ParserAnyMacro<'a> { } fn make_stmt(self: Box>) -> Option> { - let attrs = self.parser.borrow_mut().parse_outer_attributes(); - let ret = self.parser.borrow_mut().parse_stmt(attrs); + let ret = self.parser.borrow_mut().parse_stmt(); self.ensure_complete_parse(true); - Some(ret) + ret } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c3bac0cf57c75..9ae800ba3d093 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -703,7 +703,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { span: Span, _node_id: NodeId) { match fn_kind { - visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => { + visit::FkItemFn(_, _, _, _, abi) if abi == RustIntrinsic => { self.gate_feature("intrinsics", span, "intrinsics are subject to change") diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 105a61d085725..e8dd5402a90d1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -907,10 +907,11 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { ItemConst(t, e) => { ItemConst(folder.fold_ty(t), folder.fold_expr(e)) } - ItemFn(decl, unsafety, abi, generics, body) => { + ItemFn(decl, unsafety, constness, abi, generics, body) => { ItemFn( folder.fold_fn_decl(decl), unsafety, + constness, abi, folder.fold_generics(generics), folder.fold_block(body) @@ -1109,6 +1110,8 @@ pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> Method unsafety: sig.unsafety, decl: folder.fold_fn_decl(sig.decl) } + constness, + constness, } pub fn noop_fold_pat(p: P, folder: &mut T) -> P { diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index db5583cf13ac1..a5dd4f222241d 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -19,9 +19,8 @@ use ptr::P; /// A parser that can parse attributes. pub trait ParserAttr { fn parse_outer_attributes(&mut self) -> Vec; + fn parse_inner_attributes(&mut self) -> Vec; fn parse_attribute(&mut self, permit_inner: bool) -> ast::Attribute; - fn parse_inner_attrs_and_next(&mut self) - -> (Vec, Vec); fn parse_meta_item(&mut self) -> P; fn parse_meta_seq(&mut self) -> Vec>; fn parse_optional_meta(&mut self) -> Vec>; @@ -118,45 +117,40 @@ impl<'a> ParserAttr for Parser<'a> { /// Parse attributes that appear after the opening of an item. These should /// be preceded by an exclamation mark, but we accept and warn about one - /// terminated by a semicolon. In addition to a vector of inner attributes, - /// this function also returns a vector that may contain the first outer - /// attribute of the next item (since we can't know whether the attribute - /// is an inner attribute of the containing item or an outer attribute of - /// the first contained item until we see the semi). - - /// matches inner_attrs* outer_attr? - /// you can make the 'next' field an Option, but the result is going to be - /// more useful as a vector. - fn parse_inner_attrs_and_next(&mut self) - -> (Vec , Vec ) { - let mut inner_attrs: Vec = Vec::new(); - let mut next_outer_attrs: Vec = Vec::new(); + /// terminated by a semicolon. + + /// matches inner_attrs* + fn parse_inner_attributes(&mut self) -> Vec { + let mut attrs: Vec = vec![]; loop { - let attr = match self.token { + match self.token { token::Pound => { - self.parse_attribute(true) + // Don't even try to parse if it's not an inner attribute. + if !self.look_ahead(1, |t| t == &token::Not) { + break; + } + + let attr = self.parse_attribute(true); + assert!(attr.node.style == ast::AttrInner); + attrs.push(attr); } token::DocComment(s) => { // we need to get the position of this token before we bump. let Span { lo, hi, .. } = self.span; - self.bump(); - attr::mk_sugared_doc_attr(attr::mk_attr_id(), - self.id_to_interned_str(s.ident()), - lo, - hi) - } - _ => { - break; + let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), + self.id_to_interned_str(s.ident()), + lo, hi); + if attr.node.style == ast::AttrInner { + attrs.push(attr); + self.bump(); + } else { + break; + } } - }; - if attr.node.style == ast::AttrInner { - inner_attrs.push(attr); - } else { - next_outer_attrs.push(attr); - break; + _ => break } } - (inner_attrs, next_outer_attrs) + attrs } /// matches meta_item = IDENT diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index fae305f955174..3e02b4e0752c0 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -96,9 +96,7 @@ pub fn parse_crate_attrs_from_file( cfg: ast::CrateConfig, sess: &ParseSess ) -> Vec { - let mut parser = new_parser_from_file(sess, cfg, input); - let (inner, _) = parser.parse_inner_attrs_and_next(); - inner + new_parser_from_file(sess, cfg, input).parse_inner_attributes() } pub fn parse_crate_from_source_str(name: String, @@ -122,8 +120,7 @@ pub fn parse_crate_attrs_from_source_str(name: String, cfg, name, source); - let (inner, _) = maybe_aborted(p.parse_inner_attrs_and_next(),p); - inner + maybe_aborted(p.parse_inner_attributes(), p) } pub fn parse_expr_from_source_str(name: String, @@ -141,7 +138,7 @@ pub fn parse_item_from_source_str(name: String, sess: &ParseSess) -> Option> { let mut p = new_parser_from_source_str(sess, cfg, name, source); - maybe_aborted(p.parse_item_with_outer_attributes(),p) + maybe_aborted(p.parse_item(),p) } pub fn parse_meta_from_source_str(name: String, @@ -156,16 +153,15 @@ pub fn parse_meta_from_source_str(name: String, pub fn parse_stmt_from_source_str(name: String, source: String, cfg: ast::CrateConfig, - attrs: Vec , sess: &ParseSess) - -> P { + -> Option> { let mut p = new_parser_from_source_str( sess, cfg, name, source ); - maybe_aborted(p.parse_stmt(attrs),p) + maybe_aborted(p.parse_stmt(), p) } // Note: keep in sync with `with_hygiene::parse_tts_from_source_str` diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ea1c17055141a..ba2fdb9ce7c13 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -17,7 +17,7 @@ use ast::{Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; -use ast::{Crate, CrateConfig, Decl, DeclItem}; +use ast::{Crate, CrateConfig, Constness, Decl, DeclItem}; use ast::{DeclLocal, DefaultBlock, DefaultReturn}; use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; @@ -39,7 +39,7 @@ use ast::{LitStr, LitInt, Local, LocalLet}; use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; -use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, NodeId, UnNot}; +use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; use ast::{Pat, PatEnum, PatIdent, PatLit, PatRange, PatRegion, PatStruct}; use ast::{PatTup, PatBox, PatWild, PatWildMulti, PatWildSingle}; use ast::{PolyTraitRef, QSelf}; @@ -117,11 +117,6 @@ pub enum BoundParsingMode { Modified, } -/// The `Err` case indicates a failure to parse any kind of item. -/// The attributes are returned. -type MaybeItem = Result, Vec>; - - /// Possibly accept an `token::Interpolated` expression (a pre-parsed expression /// dropped into the token stream, which happens while parsing the result of /// macro expansion). Placement of these is not as complex as I feared it would @@ -208,7 +203,7 @@ macro_rules! maybe_whole { } } ); - (Some $p:expr, $constructor:ident) => ( + (Some deref $p:expr, $constructor:ident) => ( { let found = match ($p).token { token::Interpolated(token::$constructor(_)) => { @@ -217,7 +212,7 @@ macro_rules! maybe_whole { _ => None }; if let Some(token::Interpolated(token::$constructor(x))) = found { - return Some(x.clone()); + return Some((*x).clone()); } } ); @@ -1240,41 +1235,6 @@ impl<'a> Parser<'a> { } } - /// Parses `type Foo;` in a trait declaration only. The `type` keyword has - /// already been parsed. - fn parse_assoc_ty_in_trait(&mut self, attrs: Vec) - -> P { - let TyParam {id, ident, bounds, default, span} = self.parse_ty_param(); - self.expect(&token::Semi); - P(TraitItem { - id: id, - ident: ident, - attrs: attrs, - node: TypeTraitItem(bounds, default), - span: span, - }) - } - - /// Parses `type Foo = TYPE;` in an implementation declaration only. The - /// `type` keyword has already been parsed. - fn parse_assoc_ty_in_impl(&mut self, attrs: Vec, vis: Visibility) - -> P { - let lo = self.span.lo; - let ident = self.parse_ident(); - self.expect(&token::Eq); - let typ = self.parse_ty_sum(); - let hi = self.span.hi; - self.expect(&token::Semi); - P(ImplItem { - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - ident: ident, - vis: vis, - attrs: attrs, - node: TypeImplItem(typ), - }) - } - /// Parse the items in a trait declaration pub fn parse_trait_items(&mut self) -> Vec> { self.parse_unspanned_seq( @@ -1282,14 +1242,15 @@ impl<'a> Parser<'a> { &token::CloseDelim(token::Brace), seq_sep_none(), |p| { + let lo = p.span.lo; let mut attrs = p.parse_outer_attributes(); - if p.eat_keyword(keywords::Type) { - p.parse_assoc_ty_in_trait(attrs) + let (name, node) = if p.eat_keyword(keywords::Type) { + let TyParam {ident, bounds, default, ..} = p.parse_ty_param(); + p.expect(&token::Semi); + (ident, TypeTraitItem(bounds, default)) } else { - let lo = p.span.lo; - - let style = p.parse_unsafety(); + let unsafety = p.parse_unsafety(); let abi = if p.eat_keyword(keywords::Extern) { p.parse_opt_abi().unwrap_or(abi::C) } else { @@ -1310,13 +1271,13 @@ impl<'a> Parser<'a> { p.parse_where_clause(&mut generics); let sig = ast::MethodSig { unsafety: style, + constness: ast::Constness::NotConst; decl: d, generics: generics, abi: abi, explicit_self: explicit_self, }; - let hi = p.last_span.hi; let body = match p.token { token::Semi => { p.bump(); @@ -1337,15 +1298,16 @@ impl<'a> Parser<'a> { token_str)[..]) } }; + (ident, ast::MethodTraitItem(sig, body)) + }; - P(TraitItem { - id: ast::DUMMY_NODE_ID, - ident: ident, - attrs: attrs, - node: ast::MethodTraitItem(sig, body), - span: mk_sp(lo, hi), - }) - } + P(TraitItem { + id: ast::DUMMY_NODE_ID, + ident: name, + attrs: attrs, + node: node, + span: mk_sp(lo, p.last_span.hi), + }) }) } @@ -3647,41 +3609,47 @@ impl<'a> Parser<'a> { }) } - /// Get an expected item after attributes error message. - fn expected_item_err(attrs: &[Attribute]) -> &'static str { - match attrs.last() { + /// Emit an expected item after attributes error. + fn expected_item_err(&self, attrs: &[Attribute]) { + let message = match attrs.last() { Some(&Attribute { node: ast::Attribute_ { is_sugared_doc: true, .. }, .. }) => { "expected item after doc comment" } _ => "expected item after attributes", - } + }; + + self.span_err(self.last_span, message); } /// Parse a statement. may include decl. - /// Precondition: any attributes are parsed already - pub fn parse_stmt(&mut self, item_attrs: Vec) -> P { - maybe_whole!(self, NtStmt); + pub fn parse_stmt(&mut self) -> Option> { + self.parse_stmt_().map(P) + } + + fn parse_stmt_(&mut self) -> Option { + maybe_whole!(Some deref self, NtStmt); fn check_expected_item(p: &mut Parser, attrs: &[Attribute]) { // If we have attributes then we should have an item if !attrs.is_empty() { - let last_span = p.last_span; - p.span_err(last_span, Parser::expected_item_err(attrs)); + p.expected_item_err(attrs); } } let lo = self.span.lo; - if self.check_keyword(keywords::Let) { - check_expected_item(self, &item_attrs[..]); + let attrs = self.parse_outer_attributes(); + + Some(if self.check_keyword(keywords::Let) { + check_expected_item(self, &attrs); self.expect_keyword(keywords::Let); let decl = self.parse_let(); - P(spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID))) + spanned(lo, decl.span.hi, StmtDecl(decl, ast::DUMMY_NODE_ID)) } else if self.token.is_ident() && !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) { // it's a macro invocation: - check_expected_item(self, &item_attrs[..]); + check_expected_item(self, &attrs); // Potential trouble: if we allow macros with paths instead of // idents, we'd need to look ahead past the whole path here... @@ -3728,12 +3696,11 @@ impl<'a> Parser<'a> { }; if id.name == token::special_idents::invalid.name { - P(spanned(lo, - hi, - StmtMac(P(spanned(lo, + spanned(lo, hi, + StmtMac(P(spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT))), - style))) + style)) } else { // if it has a special ident, it's definitely an item // @@ -3747,35 +3714,38 @@ impl<'a> Parser<'a> { followed by a semicolon"); } } - P(spanned(lo, hi, StmtDecl( + spanned(lo, hi, StmtDecl( P(spanned(lo, hi, DeclItem( self.mk_item( lo, hi, id /*id is good here*/, ItemMac(spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT))), Inherited, Vec::new(/*no attrs*/))))), - ast::DUMMY_NODE_ID))) + ast::DUMMY_NODE_ID)) } } else { - let found_attrs = !item_attrs.is_empty(); - let item_err = Parser::expected_item_err(&item_attrs[..]); - match self.parse_item_(item_attrs, false) { - Ok(i) => { + match self.parse_item_(attrs, false) { + Some(i) => { let hi = i.span.hi; let decl = P(spanned(lo, hi, DeclItem(i))); - P(spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID))) + spanned(lo, hi, StmtDecl(decl, ast::DUMMY_NODE_ID)) } - Err(_) => { - if found_attrs { - let last_span = self.last_span; - self.span_err(last_span, item_err); + None => { + // Do not attempt to parse an expression if we're done here. + if self.token == token::Semi { + self.bump(); + return None; + } + + if self.token == token::CloseDelim(token::Brace) { + return None; } // Remainder are line-expr stmts. let e = self.parse_expr_res(RESTRICTION_STMT_EXPR); - P(spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))) + spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)) } } - } + }) } /// Is this expression a successfully-parsed statement? @@ -3798,153 +3768,110 @@ impl<'a> Parser<'a> { "place this code inside a block"); } - return self.parse_block_tail_(lo, DefaultBlock, Vec::new()); + self.parse_block_tail(lo, DefaultBlock) } /// Parse a block. Inner attrs are allowed. - fn parse_inner_attrs_and_block(&mut self) - -> (Vec , P) { - + fn parse_inner_attrs_and_block(&mut self) -> (Vec, P) { maybe_whole!(pair_empty self, NtBlock); let lo = self.span.lo; self.expect(&token::OpenDelim(token::Brace)); - let (inner, next) = self.parse_inner_attrs_and_next(); - - (inner, self.parse_block_tail_(lo, DefaultBlock, next)) + (self.parse_inner_attributes(), + self.parse_block_tail(lo, DefaultBlock)) } + /// Parse the rest of a block expression or function body /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: BytePos, s: BlockCheckMode) -> P { - self.parse_block_tail_(lo, s, Vec::new()) - } - - /// Parse the rest of a block expression or function body - fn parse_block_tail_(&mut self, lo: BytePos, s: BlockCheckMode, - first_item_attrs: Vec) -> P { let mut stmts = vec![]; let mut expr = None; - let mut attributes_box = first_item_attrs; - while self.token != token::CloseDelim(token::Brace) { - // parsing items even when they're not allowed lets us give - // better error messages and recover more gracefully. - attributes_box.push_all(&self.parse_outer_attributes()); - match self.token { - token::Semi => { - if !attributes_box.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - Parser::expected_item_err(&attributes_box[..])); - attributes_box = Vec::new(); - } - self.bump(); // empty - } - token::CloseDelim(token::Brace) => { - // fall through and out. + while !self.eat(&token::CloseDelim(token::Brace)) { + let Spanned {node, span} = if let Some(s) = self.parse_stmt_() { + s + } else { + // Found only `;` or `}`. + continue; + }; + match node { + StmtExpr(e, _) => { + self.handle_expression_like_statement(e, span, &mut stmts, &mut expr); } - _ => { - let stmt = self.parse_stmt(attributes_box); - attributes_box = Vec::new(); - stmt.and_then(|Spanned {node, span}| match node { - StmtExpr(e, stmt_id) => { - self.handle_expression_like_statement(e, - stmt_id, - span, - &mut stmts, - &mut expr); + StmtMac(mac, MacStmtWithoutBraces) => { + // statement macro without braces; might be an + // expr depending on whether a semicolon follows + match self.token { + token::Semi => { + stmts.push(P(Spanned { + node: StmtMac(mac, MacStmtWithSemicolon), + span: span, + })); + self.bump(); } - StmtMac(mac, MacStmtWithoutBraces) => { - // statement macro without braces; might be an - // expr depending on whether a semicolon follows - match self.token { - token::Semi => { - stmts.push(P(Spanned { - node: StmtMac(mac, - MacStmtWithSemicolon), - span: span, - })); - self.bump(); - } - _ => { - let e = self.mk_mac_expr(span.lo, - span.hi, - mac.and_then(|m| m.node)); - let e = self.parse_dot_or_call_expr_with(e); - let e = self.parse_more_binops(e, 0); - let e = self.parse_assign_expr_with(e); - self.handle_expression_like_statement( - e, - ast::DUMMY_NODE_ID, - span, - &mut stmts, - &mut expr); - } - } + _ => { + let e = self.mk_mac_expr(span.lo, span.hi, + mac.and_then(|m| m.node)); + let e = self.parse_dot_or_call_expr_with(e); + let e = self.parse_more_binops(e, 0); + let e = self.parse_assign_expr_with(e); + self.handle_expression_like_statement( + e, + span, + &mut stmts, + &mut expr); } - StmtMac(m, style) => { - // statement macro; might be an expr - match self.token { - token::Semi => { - stmts.push(P(Spanned { - node: StmtMac(m, - MacStmtWithSemicolon), - span: span, - })); - self.bump(); - } - token::CloseDelim(token::Brace) => { - // if a block ends in `m!(arg)` without - // a `;`, it must be an expr - expr = Some( - self.mk_mac_expr(span.lo, - span.hi, + } + } + StmtMac(m, style) => { + // statement macro; might be an expr + match self.token { + token::Semi => { + stmts.push(P(Spanned { + node: StmtMac(m, MacStmtWithSemicolon), + span: span, + })); + self.bump(); + } + token::CloseDelim(token::Brace) => { + // if a block ends in `m!(arg)` without + // a `;`, it must be an expr + expr = Some(self.mk_mac_expr(span.lo, span.hi, m.and_then(|x| x.node))); - } - _ => { - stmts.push(P(Spanned { - node: StmtMac(m, style), - span: span - })); - } - } } - _ => { // all other kinds of statements: - if classify::stmt_ends_with_semi(&node) { - self.commit_stmt_expecting(token::Semi); - } - + _ => { stmts.push(P(Spanned { - node: node, + node: StmtMac(m, style), span: span })); } - }) + } } - } - } + _ => { // all other kinds of statements: + if classify::stmt_ends_with_semi(&node) { + self.commit_stmt_expecting(token::Semi); + } - if !attributes_box.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - Parser::expected_item_err(&attributes_box[..])); + stmts.push(P(Spanned { + node: node, + span: span + })); + } + } } - let hi = self.span.hi; - self.bump(); P(ast::Block { stmts: stmts, expr: expr, id: ast::DUMMY_NODE_ID, rules: s, - span: mk_sp(lo, hi), + span: mk_sp(lo, self.last_span.hi), }) } fn handle_expression_like_statement( &mut self, e: P, - stmt_id: NodeId, span: Span, stmts: &mut Vec>, last_block_expr: &mut Option>) { @@ -3964,14 +3891,14 @@ impl<'a> Parser<'a> { expn_id: span.expn_id, }; stmts.push(P(Spanned { - node: StmtSemi(e, stmt_id), + node: StmtSemi(e, ast::DUMMY_NODE_ID), span: span_with_semi, })); } token::CloseDelim(token::Brace) => *last_block_expr = Some(e), _ => { stmts.push(P(Spanned { - node: StmtExpr(e, stmt_id), + node: StmtExpr(e, ast::DUMMY_NODE_ID), span: span })); } @@ -4617,23 +4544,44 @@ impl<'a> Parser<'a> { } /// Parse an item-position function declaration. - fn parse_item_fn(&mut self, unsafety: Unsafety, abi: abi::Abi) -> ItemInfo { + fn parse_item_fn(&mut self, + unsafety: Unsafety, + constness: Constness, + abi: abi::Abi) -> ItemInfo { let (ident, mut generics) = self.parse_fn_header(); let decl = self.parse_fn_decl(false); self.parse_where_clause(&mut generics); let (inner_attrs, body) = self.parse_inner_attrs_and_block(); - (ident, ItemFn(decl, unsafety, abi, generics, body), Some(inner_attrs)) + (ident, ItemFn(decl, unsafety, constness, abi, generics, body), + Some(inner_attrs)) } /// Parse an impl item. - pub fn parse_impl_item_with_outer_attributes(&mut self) -> P { - let attrs = self.parse_outer_attributes(); + pub fn parse_impl_item(&mut self, is_trait_impl: bool) -> P { + let lo = self.span.lo; + let mut attrs = self.parse_outer_attributes(); let vis = self.parse_visibility(); - if self.eat_keyword(keywords::Type) { - self.parse_assoc_ty_in_impl(attrs, vis) + let (name, node) = if self.eat_keyword(keywords::Type) { + let name = self.parse_ident(); + self.expect(&token::Eq); + let typ = self.parse_ty_sum(); + self.expect(&token::Semi); + (name, TypeImplItem(typ)) } else { - self.parse_method(attrs, vis) - } + let (name, inner_attrs, node) = + self.parse_impl_method(vis, is_trait_impl); + attrs.extend(inner_attrs.into_iter()); + (name, node) + }; + + P(ImplItem { + id: ast::DUMMY_NODE_ID, + span: mk_sp(lo, self.last_span.hi), + ident: name, + vis: vis, + attrs: attrs, + node: node + }) } fn complain_if_pub_macro(&mut self, visa: Visibility, span: Span) { @@ -4647,41 +4595,40 @@ impl<'a> Parser<'a> { } } - /// Parse a method in a trait impl, starting with `attrs` attributes. - pub fn parse_method(&mut self, - attrs: Vec, - vis: Visibility) - -> P { - let lo = self.span.lo; - + /// Parse a method or a macro invocation in a trait impl. + fn parse_impl_method(&mut self, vis: Visibility, + is_trait_impl: bool) + -> (Ident, Vec, ast::ImplItem_) { // code copied from parse_macro_use_or_failure... abstraction! - let (method_, hi, new_attrs, ident) = { - if !self.token.is_any_keyword() - && self.look_ahead(1, |t| *t == token::Not) - && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) - || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { - // method macro. + if !self.token.is_any_keyword() + && self.look_ahead(1, |t| *t == token::Not) + && (self.look_ahead(2, |t| *t == token::OpenDelim(token::Paren)) + || self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace))) { + // method macro. - let last_span = self.last_span; - self.complain_if_pub_macro(vis, last_span); - - let pth = self.parse_path(NoTypesAllowed); - self.expect(&token::Not); - - // eat a matched-delimiter token tree: - let delim = self.expect_open_delim(); - let tts = self.parse_seq_to_end(&token::CloseDelim(delim), - seq_sep_none(), - |p| p.parse_token_tree()); - let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT); - let m: ast::Mac = codemap::Spanned { node: m_, - span: mk_sp(self.span.lo, - self.span.hi) }; - if delim != token::Brace { - self.expect(&token::Semi) - } - (ast::MacImplItem(m), self.span.hi, attrs, - token::special_idents::invalid) + let last_span = self.last_span; + self.complain_if_pub_macro(vis, last_span); + + let pth = self.parse_path(NoTypesAllowed); + self.expect(&token::Not); + + // eat a matched-delimiter token tree: + let delim = self.expect_open_delim(); + let tts = self.parse_seq_to_end(&token::CloseDelim(delim), + seq_sep_none(), + |p| p.parse_token_tree()); + let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT); + let m: ast::Mac = codemap::Spanned { node: m_, + span: mk_sp(self.span.lo, + self.span.hi) }; + if delim != token::Brace { + self.expect(&token::Semi) + } + (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 = self.parse_unsafety(); let abi = if self.eat_keyword(keywords::Extern) { @@ -4689,34 +4636,25 @@ impl<'a> Parser<'a> { } else { abi::Rust }; - self.expect_keyword(keywords::Fn); - let ident = self.parse_ident(); - let mut generics = self.parse_generics(); - let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { - p.parse_arg() - }); - self.parse_where_clause(&mut generics); - let (inner_attrs, body) = self.parse_inner_attrs_and_block(); - let body_span = body.span; - let mut new_attrs = attrs; - new_attrs.push_all(&inner_attrs[..]); - (MethodImplItem(ast::MethodSig { - generics: generics, - abi: abi, - explicit_self: explicit_self, - unsafety: unsafety, - decl: decl - }, body), body_span.hi, new_attrs, ident) - } - }; - P(ImplItem { - id: ast::DUMMY_NODE_ID, - attrs: new_attrs, - vis: vis, - ident: ident, - node: method_, - span: mk_sp(lo, hi), - }) + (Constness::NotConst, unsafety, abi) + }; + self.expect_keyword(keywords::Fn); + let ident = self.parse_ident(); + let mut generics = self.parse_generics(); + let (explicit_self, decl) = self.parse_fn_decl_with_self(|p| { + p.parse_arg() + }); + self.parse_where_clause(&mut generics); + let (inner_attrs, body) = self.parse_inner_attrs_and_block(); + (ident, inner_attrs, MethodImplItem(ast::MethodSig { + generics: generics, + abi: abi, + explicit_self: explicit_self, + unsafety: unsafety, + constness: constness; + decl: decl + }, body)) + } } /// Parse trait Foo { ... } @@ -4747,28 +4685,6 @@ impl<'a> Parser<'a> { (ident, ItemTrait(unsafety, tps, bounds, meths), None) } - fn parse_impl_items(&mut self) -> (Vec>, Vec) { - let mut impl_items = Vec::new(); - self.expect(&token::OpenDelim(token::Brace)); - let (inner_attrs, mut method_attrs) = - self.parse_inner_attrs_and_next(); - loop { - method_attrs.extend(self.parse_outer_attributes().into_iter()); - if method_attrs.is_empty() && self.eat(&token::CloseDelim(token::Brace)) { - break; - } - - let vis = self.parse_visibility(); - impl_items.push(if self.eat_keyword(keywords::Type) { - self.parse_assoc_ty_in_impl(method_attrs, vis) - } else { - self.parse_method(method_attrs, vis) - }); - method_attrs = vec![]; - } - (impl_items, inner_attrs) - } - /// Parses items implementations variants /// impl Foo { ... } /// impl ToString for &'static T { ... } @@ -4835,7 +4751,14 @@ impl<'a> Parser<'a> { ty = self.parse_ty_sum(); } self.parse_where_clause(&mut generics); - let (impl_items, attrs) = self.parse_impl_items(); + + self.expect(&token::OpenDelim(token::Brace)); + let attrs = self.parse_inner_attributes(); + + let mut impl_items = vec![]; + while !self.eat(&token::CloseDelim(token::Brace)) { + impl_items.push(self.parse_impl_item(opt_trait.is_some())); + } (ast_util::impl_pretty_name(&opt_trait, Some(&*ty)), ItemImpl(unsafety, polarity, generics, opt_trait, ty, impl_items), @@ -5074,53 +4997,16 @@ impl<'a> Parser<'a> { } } - /// Given a termination token and a vector of already-parsed - /// attributes (of length 0 or 1), parse all of the items in a module - fn parse_mod_items(&mut self, - term: token::Token, - first_item_attrs: Vec, - inner_lo: BytePos) - -> Mod { - // Parse all of the items up to closing or an attribute. - - let mut attrs = first_item_attrs; - attrs.push_all(&self.parse_outer_attributes()); + /// Given a termination token, parse all of the items in a module + fn parse_mod_items(&mut self, term: &token::Token, inner_lo: BytePos) -> Mod { let mut items = vec![]; - - loop { - match self.parse_item_(attrs, true) { - Err(returned_attrs) => { - attrs = returned_attrs; - break - } - Ok(item) => { - attrs = self.parse_outer_attributes(); - items.push(item) - } - } - } - - // don't think this other loop is even necessary.... - - while self.token != term { - let mut attrs = mem::replace(&mut attrs, vec![]); - attrs.push_all(&self.parse_outer_attributes()); - debug!("parse_mod_items: parse_item_(attrs={:?})", attrs); - match self.parse_item_(attrs, true /* macros allowed */) { - Ok(item) => items.push(item), - Err(_) => { - let token_str = self.this_token_to_string(); - self.fatal(&format!("expected item, found `{}`", - token_str)) - } - } + while let Some(item) = self.parse_item() { + items.push(item); } - if !attrs.is_empty() { - // We parsed attributes for the first item but didn't find it - let last_span = self.last_span; - self.span_err(last_span, - Parser::expected_item_err(&attrs[..])); + if !self.eat(term) { + let token_str = self.this_token_to_string(); + self.fatal(&format!("expected item, found `{}`", token_str)) } ast::Mod { @@ -5158,12 +5044,11 @@ impl<'a> Parser<'a> { let mod_inner_lo = self.span.lo; let old_owns_directory = self.owns_directory; self.owns_directory = true; - let (inner, next) = self.parse_inner_attrs_and_next(); - let m = self.parse_mod_items(token::CloseDelim(token::Brace), next, mod_inner_lo); - self.expect(&token::CloseDelim(token::Brace)); + let attrs = self.parse_inner_attributes(); + let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo); self.owns_directory = old_owns_directory; self.pop_mod_path(); - (id, ItemMod(m), Some(inner)) + (id, ItemMod(m), Some(attrs)) } } @@ -5290,11 +5175,10 @@ impl<'a> Parser<'a> { Some(name), id_sp); let mod_inner_lo = p0.span.lo; - let (mod_attrs, next) = p0.parse_inner_attrs_and_next(); - let first_item_outer_attrs = next; - let m0 = p0.parse_mod_items(token::Eof, first_item_outer_attrs, mod_inner_lo); + let mod_attrs = p0.parse_inner_attributes(); + let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo); self.sess.included_mod_stack.borrow_mut().pop(); - return (ast::ItemMod(m0), mod_attrs); + (ast::ItemMod(m0), mod_attrs) } /// Parse a function declaration from a foreign module @@ -5341,20 +5225,6 @@ impl<'a> Parser<'a> { }) } - /// At this point, this is essentially a wrapper for - /// parse_foreign_items. - fn parse_foreign_mod_items(&mut self, - abi: abi::Abi, - first_item_attrs: Vec) - -> ForeignMod { - let foreign_items = self.parse_foreign_items(first_item_attrs); - assert!(self.token == token::CloseDelim(token::Brace)); - ast::ForeignMod { - abi: abi, - items: foreign_items - } - } - /// Parse extern crate links /// /// # Examples @@ -5433,24 +5303,31 @@ impl<'a> Parser<'a> { lo: BytePos, opt_abi: Option, visibility: Visibility, - attrs: Vec) + mut attrs: Vec) -> P { - self.expect(&token::OpenDelim(token::Brace)); let abi = opt_abi.unwrap_or(abi::C); - let (inner, next) = self.parse_inner_attrs_and_next(); - let m = self.parse_foreign_mod_items(abi, next); + attrs.extend(self.parse_inner_attributes().into_iter()); + + let mut foreign_items = vec![]; + while let Some(item) = self.parse_foreign_item() { + foreign_items.push(item); + } self.expect(&token::CloseDelim(token::Brace)); let last_span = self.last_span; + let m = ast::ForeignMod { + abi: abi, + items: foreign_items + }; self.mk_item(lo, last_span.hi, special_idents::invalid, ItemForeignMod(m), visibility, - maybe_append(attrs, Some(inner))) + attrs) } /// Parse type Foo = Bar; @@ -5592,12 +5469,11 @@ impl<'a> Parser<'a> { } } - /// Parse one of the items allowed by the flags; on failure, - /// return `Err(remaining_attrs)`. + /// Parse one of the items allowed by the flags. /// NB: this function no longer parses the items inside an /// extern crate. fn parse_item_(&mut self, attrs: Vec, - macros_allowed: bool) -> MaybeItem { + macros_allowed: bool) -> Option> { let nt_item = match self.token { token::Interpolated(token::NtItem(ref item)) => { Some((**item).clone()) @@ -5610,7 +5486,7 @@ impl<'a> Parser<'a> { let mut attrs = attrs; mem::swap(&mut item.attrs, &mut attrs); item.attrs.extend(attrs.into_iter()); - return Ok(P(item)); + return Some(P(item)); } None => {} } @@ -5631,12 +5507,12 @@ impl<'a> Parser<'a> { item_, visibility, attrs); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Extern) { if self.eat_keyword(keywords::Crate) { - return Ok(self.parse_item_extern_crate(lo, visibility, attrs)); + return Some(self.parse_item_extern_crate(lo, visibility, attrs)); } let opt_abi = self.parse_opt_abi(); @@ -5645,7 +5521,7 @@ impl<'a> Parser<'a> { // EXTERN FUNCTION ITEM let abi = opt_abi.unwrap_or(abi::C); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, abi); + self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5653,9 +5529,9 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } else if self.check(&token::OpenDelim(token::Brace)) { - return Ok(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs)); + return Some(self.parse_item_foreign_mod(lo, opt_abi, visibility, attrs)); } let span = self.span; @@ -5681,9 +5557,24 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Const) { + if self.check_keyword(keywords::Fn) { + // CONST FUNCTION ITEM + self.bump(); + let (ident, item_, extra_attrs) = + self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust); + let last_span = self.last_span; + let item = self.mk_item(lo, + last_span.hi, + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(item); + } + // CONST ITEM if self.eat_keyword(keywords::Mut) { let last_span = self.last_span; @@ -5698,7 +5589,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Trait)) @@ -5715,7 +5606,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| t.is_keyword(keywords::Impl)) @@ -5731,13 +5622,13 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.check_keyword(keywords::Fn) { // FUNCTION ITEM self.bump(); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Normal, abi::Rust); + self.parse_item_fn(Unsafety::Normal, Constness::NotConst, abi::Rust); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5745,7 +5636,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.check_keyword(keywords::Unsafe) && self.look_ahead(1, |t| *t != token::OpenDelim(token::Brace)) { @@ -5758,7 +5649,7 @@ impl<'a> Parser<'a> { }; self.expect_keyword(keywords::Fn); let (ident, item_, extra_attrs) = - self.parse_item_fn(Unsafety::Unsafe, abi); + self.parse_item_fn(Unsafety::Unsafe, Constness::NotConst, abi); let last_span = self.last_span; let item = self.mk_item(lo, last_span.hi, @@ -5766,7 +5657,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Mod) { // MODULE ITEM @@ -5779,7 +5670,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Type) { // TYPE ITEM @@ -5791,7 +5682,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Enum) { // ENUM ITEM @@ -5803,7 +5694,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Trait) { // TRAIT ITEM @@ -5816,7 +5707,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Impl) { // IMPL ITEM @@ -5828,7 +5719,7 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } if self.eat_keyword(keywords::Struct) { // STRUCT ITEM @@ -5840,30 +5731,34 @@ impl<'a> Parser<'a> { item_, visibility, maybe_append(attrs, extra_attrs)); - return Ok(item); + return Some(item); } self.parse_macro_use_or_failure(attrs,macros_allowed,lo,visibility) } - /// Parse a foreign item; on failure, return `Err(remaining_attrs)`. - fn parse_foreign_item(&mut self, attrs: Vec) - -> Result, Vec> { + /// Parse a foreign item. + fn parse_foreign_item(&mut self) -> Option> { let lo = self.span.lo; + let attrs = self.parse_outer_attributes(); let visibility = self.parse_visibility(); if self.check_keyword(keywords::Static) { // FOREIGN STATIC ITEM - return Ok(self.parse_item_foreign_static(visibility, attrs)); + return Some(self.parse_item_foreign_static(visibility, attrs)); } if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) { // FOREIGN FUNCTION ITEM - return Ok(self.parse_item_foreign_fn(visibility, attrs)); + return Some(self.parse_item_foreign_fn(visibility, attrs)); } // FIXME #5668: this will occur for a macro invocation: - let item = try!(self.parse_macro_use_or_failure(attrs, true, lo, visibility)); - self.span_fatal(item.span, "macros cannot expand to foreign items"); + match self.parse_macro_use_or_failure(attrs, true, lo, visibility) { + Some(item) => { + self.span_fatal(item.span, "macros cannot expand to foreign items"); + } + None => None + } } /// This is the fall-through for parsing items. @@ -5873,7 +5768,7 @@ impl<'a> Parser<'a> { macros_allowed: bool, lo: BytePos, visibility: Visibility - ) -> MaybeItem { + ) -> Option> { if macros_allowed && !self.token.is_any_keyword() && self.look_ahead(1, |t| *t == token::Not) && (self.look_ahead(2, |t| t.is_plain_ident()) @@ -5925,7 +5820,7 @@ impl<'a> Parser<'a> { item_, visibility, attrs); - return Ok(item); + return Some(item); } // FAILURE TO PARSE ITEM @@ -5936,16 +5831,22 @@ impl<'a> Parser<'a> { self.span_fatal(last_span, "unmatched visibility `pub`"); } } - Err(attrs) + + if !attrs.is_empty() { + self.expected_item_err(&attrs); + } + None } + // HACK(eddyb) staging required for `quote_item!`. + #[cfg(stage0)] // SNAP 270a677 pub fn parse_item_with_outer_attributes(&mut self) -> Option> { - let attrs = self.parse_outer_attributes(); - self.parse_item(attrs) + self.parse_item() } - pub fn parse_item(&mut self, attrs: Vec) -> Option> { - self.parse_item_(attrs, true).ok() + pub fn parse_item(&mut self) -> Option> { + let attrs = self.parse_outer_attributes(); + self.parse_item_(attrs, true) } /// Matches view_path : MOD? non_global_path as IDENT @@ -6051,52 +5952,13 @@ impl<'a> Parser<'a> { P(spanned(lo, self.last_span.hi, ViewPathSimple(rename_to, path))) } - /// Parses a sequence of foreign items. Stops when it finds program - /// text that can't be parsed as an item - fn parse_foreign_items(&mut self, first_item_attrs: Vec) - -> Vec> { - let mut attrs = first_item_attrs; - attrs.push_all(&self.parse_outer_attributes()); - let mut foreign_items = Vec::new(); - loop { - match self.parse_foreign_item(attrs) { - Ok(foreign_item) => { - foreign_items.push(foreign_item); - } - Err(returned_attrs) => { - if self.check(&token::CloseDelim(token::Brace)) { - attrs = returned_attrs; - break - } - self.unexpected(); - } - } - attrs = self.parse_outer_attributes(); - } - - if !attrs.is_empty() { - let last_span = self.last_span; - self.span_err(last_span, - Parser::expected_item_err(&attrs[..])); - } - - foreign_items - } - /// Parses a source module as a crate. This is the main /// entry point for the parser. pub fn parse_crate_mod(&mut self) -> Crate { let lo = self.span.lo; - // parse the crate's inner attrs, maybe (oops) one - // of the attrs of an item: - let (inner, next) = self.parse_inner_attrs_and_next(); - let first_item_outer_attrs = next; - // parse the items inside the crate: - let m = self.parse_mod_items(token::Eof, first_item_outer_attrs, lo); - ast::Crate { - module: m, - attrs: inner, + attrs: self.parse_inner_attributes(), + module: self.parse_mod_items(&token::Eof, lo), config: self.cfg.clone(), span: mk_sp(lo, self.span.lo), exported_macros: Vec::new(), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 07303ba51ff70..d7f548f57dbbe 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -371,12 +371,16 @@ pub fn ident_to_string(id: &ast::Ident) -> String { $to_string(|s| s.print_ident(*id)) } -pub fn fun_to_string(decl: &ast::FnDecl, unsafety: ast::Unsafety, name: ast::Ident, - opt_explicit_self: Option<&ast::ExplicitSelf_>, - generics: &ast::Generics) -> String { +pub fn fun_to_string(decl: &ast::FnDecl, + unsafety: ast::Unsafety, + constness: ast::Constness, + name: ast::Ident, + opt_explicit_self: Option<&ast::ExplicitSelf_>, + generics: &ast::Generics) + -> String { $to_string(|s| { try!(s.head("")); - try!(s.print_fn(decl, unsafety, abi::Rust, Some(name), + try!(s.print_fn(decl, unsafety, constness, abi::Rust, Some(name), generics, opt_explicit_self, ast::Inherited)); try!(s.end()); // Close the head box s.end() // Close the outer box @@ -761,7 +765,8 @@ impl<'a> State<'a> { match item.node { ast::ForeignItemFn(ref decl, ref generics) => { try!(self.head("")); - try!(self.print_fn(&**decl, ast::Unsafety::Normal, + try!(self.print_fn(decl, ast::Unsafety::Normal, + ast::Constness::NotConst, abi::Rust, Some(item.ident), generics, None, item.vis)); try!(self.end()); // end head-ibox @@ -863,11 +868,12 @@ impl<'a> State<'a> { try!(word(&mut self.s, ";")); try!(self.end()); // end the outer cbox } - ast::ItemFn(ref decl, unsafety, abi, ref typarams, ref body) => { + ast::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => { try!(self.head("")); try!(self.print_fn( decl, unsafety, + constness, abi, Some(item.ident), typarams, @@ -1238,6 +1244,7 @@ impl<'a> State<'a> { -> io::Result<()> { self.print_fn(&m.decl, m.unsafety, + m.constness, m.abi, Some(ident), &m.generics, @@ -2317,12 +2324,13 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &ast::FnDecl, unsafety: ast::Unsafety, + constness: ast::Constness, abi: abi::Abi, name: Option, generics: &ast::Generics, opt_explicit_self: Option<&ast::ExplicitSelf_>, vis: ast::Visibility) -> io::Result<()> { - try!(self.print_fn_header_info(unsafety, abi, vis)); + try!(self.print_fn_header_info(unsafety, constness, abi, vis)); if let Some(name) = name { try!(self.nbsp()); @@ -2699,8 +2707,8 @@ impl<'a> State<'a> { opt_explicit_self: Option<&ast::ExplicitSelf_>) -> io::Result<()> { try!(self.ibox(indent_unit)); - try!(self.print_fn(decl, unsafety, abi, name, - generics, opt_explicit_self, + try!(self.print_fn(decl, unsafety, ast::Constness::NotConst, + abi, name, generics, opt_explicit_self, ast::Inherited)); self.end() } @@ -2949,11 +2957,17 @@ impl<'a> State<'a> { pub fn print_fn_header_info(&mut self, unsafety: ast::Unsafety, + constness: ast::Constness, abi: abi::Abi, vis: ast::Visibility) -> io::Result<()> { try!(word(&mut self.s, &visibility_qualified(vis, ""))); try!(self.print_unsafety(unsafety)); + match constness { + ast::Constness::NotConst => {} + ast::Constness::Const => try!(self.word_nbsp("unsafe")) + } + if abi != abi::Rust { try!(self.word_nbsp("extern")); try!(self.word_nbsp(&abi.to_string())); @@ -2991,8 +3005,10 @@ mod test { variadic: false }; let generics = ast_util::empty_generics(); - assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, abba_ident, - None, &generics), + assert_eq!(fun_to_string(&decl, ast::Unsafety::Normal, + ast::Constness::NotConst, + abba_ident, + None, &generics), "fn abba()"); } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 5e858d8a79f76..73fd56948c142 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -123,7 +123,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { if is_test_fn(&self.cx, &*i) || is_bench_fn(&self.cx, &*i) { match i.node { - ast::ItemFn(_, ast::Unsafety::Unsafe, _, _, _) => { + ast::ItemFn(_, ast::Unsafety::Unsafe, _, _, _, _) => { let diag = self.cx.span_diagnostic; diag.span_fatal(i.span, "unsafe functions cannot be used for \ @@ -312,7 +312,7 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_test_signature(i: &ast::Item) -> HasTestSignature { match &i.node { - &ast::ItemFn(ref decl, _, _, ref generics, _) => { + &ast::ItemFn(ref decl, _, _, _, ref generics, _) => { let no_output = match decl.output { ast::DefaultReturn(..) => true, ast::Return(ref t) if t.node == ast::TyTup(vec![]) => true, @@ -348,7 +348,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { fn has_test_signature(i: &ast::Item) -> bool { match i.node { - ast::ItemFn(ref decl, _, _, ref generics, _) => { + ast::ItemFn(ref decl, _, _, _, ref generics, _) => { let input_cnt = decl.inputs.len(); let no_output = match decl.output { ast::DefaultReturn(..) => true, @@ -469,7 +469,9 @@ fn mk_main(cx: &mut TestCtxt) -> P { let main_ret_ty = ecx.ty(sp, ast::TyTup(vec![])); let main_body = ecx.block_all(sp, vec![call_test_main], None); let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty), - ast::Unsafety::Normal, ::abi::Rust, empty_generics(), main_body); + ast::Unsafety::Normal, + ast::Constness::NotConst, + ::abi::Rust, empty_generics(), main_body); let main = P(ast::Item { ident: token::str_to_ident("main"), attrs: vec![main_attr], diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index 89854f5d979a1..9b570c2b1fe29 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -58,14 +58,14 @@ pub fn string_to_expr (source_str : String) -> P { /// Parse a string, return an item pub fn string_to_item (source_str : String) -> Option> { with_error_checking_parse(source_str, |p| { - p.parse_item(Vec::new()) + p.parse_item() }) } /// Parse a string, return a stmt pub fn string_to_stmt(source_str : String) -> P { with_error_checking_parse(source_str, |p| { - p.parse_stmt(Vec::new()) + p.parse_stmt().unwrap() }) } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 638ddd3ea2e5b..0663d49d88eee 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -35,7 +35,7 @@ use owned_slice::OwnedSlice; #[derive(Copy)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() - FkItemFn(Ident, &'a Generics, Unsafety, Abi), + FkItemFn(Ident, &'a Generics, Unsafety, Constness, Abi), /// fn foo(&self) FkMethod(Ident, &'a MethodSig), @@ -246,8 +246,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ty(&**typ); visitor.visit_expr(&**expr); } - ItemFn(ref declaration, fn_style, abi, ref generics, ref body) => { - visitor.visit_fn(FkItemFn(item.ident, generics, fn_style, abi), + ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => { + visitor.visit_fn(FkItemFn(item.ident, generics, unsafety, constness, abi), &**declaration, &**body, item.span, @@ -600,7 +600,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, walk_fn_decl(visitor, function_declaration); match function_kind { - FkItemFn(_, generics, _, _) => { + FkItemFn(_, generics, _, _, _) => { visitor.visit_generics(generics); } FkMethod(_, sig) => { diff --git a/src/test/parse-fail/column-offset-1-based.rs b/src/test/parse-fail/column-offset-1-based.rs index 621b480fe77d3..a00ded61758c2 100644 --- a/src/test/parse-fail/column-offset-1-based.rs +++ b/src/test/parse-fail/column-offset-1-based.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -# //~ ERROR 11:1: 11:2 error: expected one of `!` or `[`, found `` +# //~ ERROR 11:1: 11:2 error: expected `[`, found `` diff --git a/src/test/parse-fail/issue-1655.rs b/src/test/parse-fail/issue-1655.rs index a8704f7545f06..6bdcf5c5edced 100644 --- a/src/test/parse-fail/issue-1655.rs +++ b/src/test/parse-fail/issue-1655.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected one of `!` or `[`, found `vec` +// error-pattern:expected `[`, found `vec` mod blade_runner { #vec[doc( brief = "Blade Runner is probably the best movie ever", diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 7f7ed586878e5..020f5f562d2c3 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -25,7 +25,7 @@ fn syntax_extension(cx: &ExtCtxt) { let a: P = quote_expr!(cx, 1 + 2); let _b: Option> = quote_item!(cx, static foo : int = $e_toks; ); let _c: P = quote_pat!(cx, (x, 1 .. 4, *) ); - let _d: P = quote_stmt!(cx, let x = $a; ); + let _d: Option> = quote_stmt!(cx, let x = $a; ); let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) ); let _e: P = quote_expr!(cx, match foo { $p_toks => 10 } );