1
Fork 0
This commit is contained in:
Tamir Duberstein 2015-04-28 16:36:22 -07:00
parent 9504d8cdae
commit 8c58fe1739
24 changed files with 335 additions and 290 deletions

View file

@ -25,21 +25,22 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")] html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(collections)] #![feature(collections)]
#![feature(core)] #![feature(core)]
#![feature(hash)] #![feature(hash)]
#![feature(into_cow)]
#![feature(libc)] #![feature(libc)]
#![feature(path_ext)]
#![feature(quote)] #![feature(quote)]
#![feature(rustc_diagnostic_macros)] #![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(std_misc)] #![feature(std_misc)]
#![feature(path_ext)]
#![feature(str_char)] #![feature(str_char)]
#![feature(into_cow)]
#![feature(slice_patterns)]
#![cfg_attr(test, feature(test))] #![cfg_attr(test, feature(test))]
#![allow(trivial_casts)] #![allow(trivial_casts)]

View file

@ -46,33 +46,35 @@ bitflags! {
#[derive(RustcEncodable, RustcDecodable)] #[derive(RustcEncodable, RustcDecodable)]
flags ConstQualif: u8 { flags ConstQualif: u8 {
// Const rvalue which can be placed behind a reference. // Const rvalue which can be placed behind a reference.
const PURE_CONST = 0b000000, const PURE_CONST = 0,
// Inner mutability (can not be placed behind a reference) or behind // Inner mutability (can not be placed behind a reference) or behind
// &mut in a non-global expression. Can be copied from static memory. // &mut in a non-global expression. Can be copied from static memory.
const MUTABLE_MEM = 0b000001, const MUTABLE_MEM = 1 << 0,
// Constant value with a type that implements Drop. Can be copied // Constant value with a type that implements Drop. Can be copied
// from static memory, similar to MUTABLE_MEM. // from static memory, similar to MUTABLE_MEM.
const NEEDS_DROP = 0b000010, const NEEDS_DROP = 1 << 1,
// Even if the value can be placed in static memory, copying it from // Even if the value can be placed in static memory, copying it from
// there is more expensive than in-place instantiation, and/or it may // there is more expensive than in-place instantiation, and/or it may
// be too large. This applies to [T; N] and everything containing it. // be too large. This applies to [T; N] and everything containing it.
// N.B.: references need to clear this flag to not end up on the stack. // N.B.: references need to clear this flag to not end up on the stack.
const PREFER_IN_PLACE = 0b000100, const PREFER_IN_PLACE = 1 << 2,
// May use more than 0 bytes of memory, doesn't impact the constness // May use more than 0 bytes of memory, doesn't impact the constness
// directly, but is not allowed to be borrowed mutably in a constant. // directly, but is not allowed to be borrowed mutably in a constant.
const NON_ZERO_SIZED = 0b001000, const NON_ZERO_SIZED = 1 << 3,
// Actually borrowed, has to always be in static memory. Does not // Actually borrowed, has to always be in static memory. Does not
// propagate, and requires the expression to behave like a 'static // propagate, and requires the expression to behave like a 'static
// lvalue. The set of expressions with this flag is the minimum // lvalue. The set of expressions with this flag is the minimum
// that have to be promoted. // that have to be promoted.
const HAS_STATIC_BORROWS = 0b010000, const HAS_STATIC_BORROWS = 1 << 4,
// Invalid const for miscellaneous reasons (e.g. not implemented). // Invalid const for miscellaneous reasons (e.g. not implemented).
const NOT_CONST = 0b100000, const NOT_CONST = 1 << 5,
// Borrowing the expression won't produce &'static T if any of these // Borrowing the expression won't produce &'static T if any of these
// bits are set, though the value could be copied from static memory // bits are set, though the value could be copied from static memory
// if `NOT_CONST` isn't set. // if `NOT_CONST` isn't set.
const NON_STATIC_BORROWS = MUTABLE_MEM.bits | NEEDS_DROP.bits | NOT_CONST.bits const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
ConstQualif::NEEDS_DROP.bits |
ConstQualif::NOT_CONST.bits
} }
} }
@ -102,7 +104,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
{ {
let (old_mode, old_qualif) = (self.mode, self.qualif); let (old_mode, old_qualif) = (self.mode, self.qualif);
self.mode = mode; self.mode = mode;
self.qualif = PURE_CONST; self.qualif = ConstQualif::PURE_CONST;
let r = f(self); let r = f(self);
self.mode = old_mode; self.mode = old_mode;
self.qualif = old_qualif; self.qualif = old_qualif;
@ -126,7 +128,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
Entry::Occupied(entry) => return *entry.get(), Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry. // Prevent infinite recursion on re-entry.
entry.insert(PURE_CONST); entry.insert(ConstQualif::PURE_CONST);
} }
} }
self.with_mode(mode, |this| { self.with_mode(mode, |this| {
@ -271,7 +273,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_expr(&mut self, ex: &ast::Expr) { fn visit_expr(&mut self, ex: &ast::Expr) {
let mut outer = self.qualif; let mut outer = self.qualif;
self.qualif = PURE_CONST; self.qualif = ConstQualif::PURE_CONST;
let node_ty = ty::node_id_to_type(self.tcx, ex.id); let node_ty = ty::node_id_to_type(self.tcx, ex.id);
check_expr(self, ex, node_ty); check_expr(self, ex, node_ty);
@ -287,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.visit_expr(&**callee); self.visit_expr(&**callee);
// The callee's size doesn't count in the call. // The callee's size doesn't count in the call.
let added = self.qualif - inner; let added = self.qualif - inner;
self.qualif = inner | (added - NON_ZERO_SIZED); self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
} }
ast::ExprRepeat(ref element, _) => { ast::ExprRepeat(ref element, _) => {
self.visit_expr(&**element); self.visit_expr(&**element);
@ -298,7 +300,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
}; };
// [element; 0] is always zero-sized. // [element; 0] is always zero-sized.
if count == 0 { if count == 0 {
self.qualif = self.qualif - (NON_ZERO_SIZED | PREFER_IN_PLACE); self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
} }
} }
ast::ExprMatch(ref discr, ref arms, _) => { ast::ExprMatch(ref discr, ref arms, _) => {
@ -325,7 +327,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem; let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem;
match node_ty.sty { match node_ty.sty {
ty::ty_uint(_) | ty::ty_int(_) if div_or_rem => { ty::ty_uint(_) | ty::ty_int(_) if div_or_rem => {
if !self.qualif.intersects(NOT_CONST) { if !self.qualif.intersects(ConstQualif::NOT_CONST) {
match const_eval::eval_const_expr_partial(self.tcx, ex, None) { match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
Ok(_) => {} Ok(_) => {}
Err(msg) => { Err(msg) => {
@ -348,11 +350,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
// Constants cannot be borrowed if they contain interior mutability as // Constants cannot be borrowed if they contain interior mutability as
// it means that our "silent insertion of statics" could change // it means that our "silent insertion of statics" could change
// initializer values (very bad). // initializer values (very bad).
// If the type doesn't have interior mutability, then `MUTABLE_MEM` has // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
// propagated from another error, so erroring again would be just noise. // propagated from another error, so erroring again would be just noise.
let tc = ty::type_contents(self.tcx, node_ty); let tc = ty::type_contents(self.tcx, node_ty);
if self.qualif.intersects(MUTABLE_MEM) && tc.interior_unsafe() { if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | NOT_CONST; outer = outer | ConstQualif::NOT_CONST;
if self.mode != Mode::Var { if self.mode != Mode::Var {
self.tcx.sess.span_err(ex.span, self.tcx.sess.span_err(ex.span,
"cannot borrow a constant which contains \ "cannot borrow a constant which contains \
@ -361,32 +363,32 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
} }
// If the reference has to be 'static, avoid in-place initialization // If the reference has to be 'static, avoid in-place initialization
// as that will end up pointing to the stack instead. // as that will end up pointing to the stack instead.
if !self.qualif.intersects(NON_STATIC_BORROWS) { if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.qualif = self.qualif - PREFER_IN_PLACE; self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
self.add_qualif(HAS_STATIC_BORROWS); self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
} }
} }
Some(ast::MutMutable) => { Some(ast::MutMutable) => {
// `&mut expr` means expr could be mutated, unless it's zero-sized. // `&mut expr` means expr could be mutated, unless it's zero-sized.
if self.qualif.intersects(NON_ZERO_SIZED) { if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
if self.mode == Mode::Var { if self.mode == Mode::Var {
outer = outer | NOT_CONST; outer = outer | ConstQualif::NOT_CONST;
self.add_qualif(MUTABLE_MEM); self.add_qualif(ConstQualif::MUTABLE_MEM);
} else { } else {
span_err!(self.tcx.sess, ex.span, E0017, span_err!(self.tcx.sess, ex.span, E0017,
"references in {}s may only refer \ "references in {}s may only refer \
to immutable values", self.msg()) to immutable values", self.msg())
} }
} }
if !self.qualif.intersects(NON_STATIC_BORROWS) { if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.add_qualif(HAS_STATIC_BORROWS); self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
} }
} }
None => {} None => {}
} }
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif); self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
// Don't propagate certain flags. // Don't propagate certain flags.
self.qualif = outer | (self.qualif - HAS_STATIC_BORROWS); self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
} }
} }
@ -401,7 +403,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match node_ty.sty { match node_ty.sty {
ty::ty_struct(did, _) | ty::ty_struct(did, _) |
ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => { ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => {
v.add_qualif(NEEDS_DROP); v.add_qualif(ConstQualif::NEEDS_DROP);
if v.mode != Mode::Var { if v.mode != Mode::Var {
v.tcx.sess.span_err(e.span, v.tcx.sess.span_err(e.span,
&format!("{}s are not allowed to have destructors", &format!("{}s are not allowed to have destructors",
@ -416,7 +418,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprUnary(..) | ast::ExprUnary(..) |
ast::ExprBinary(..) | ast::ExprBinary(..) |
ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => { ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0011, span_err!(v.tcx.sess, e.span, E0011,
"user-defined operators are not allowed in {}s", v.msg()); "user-defined operators are not allowed in {}s", v.msg());
@ -424,7 +426,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
} }
ast::ExprBox(..) | ast::ExprBox(..) |
ast::ExprUnary(ast::UnUniq, _) => { ast::ExprUnary(ast::UnUniq, _) => {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0010, span_err!(v.tcx.sess, e.span, E0010,
"allocations are not allowed in {}s", v.msg()); "allocations are not allowed in {}s", v.msg());
@ -434,7 +436,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match ty::node_id_to_type(v.tcx, ptr.id).sty { match ty::node_id_to_type(v.tcx, ptr.id).sty {
ty::ty_ptr(_) => { ty::ty_ptr(_) => {
// This shouldn't be allowed in constants at all. // This shouldn't be allowed in constants at all.
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
} }
_ => {} _ => {}
} }
@ -447,7 +449,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ty::type_is_unsafe_ptr(toty) || ty::type_is_unsafe_ptr(toty) ||
(ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty)); (ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
if !is_legal_cast { if !is_legal_cast {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0012, span_err!(v.tcx.sess, e.span, E0012,
"can not cast to `{}` in {}s", "can not cast to `{}` in {}s",
@ -455,7 +457,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
} }
} }
if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) { if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0018, span_err!(v.tcx.sess, e.span, E0018,
"can not cast a pointer to an integer in {}s", v.msg()); "can not cast a pointer to an integer in {}s", v.msg());
@ -467,17 +469,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
match def { match def {
Some(def::DefVariant(_, _, _)) => { Some(def::DefVariant(_, _, _)) => {
// Count the discriminator or function pointer. // Count the discriminator or function pointer.
v.add_qualif(NON_ZERO_SIZED); v.add_qualif(ConstQualif::NON_ZERO_SIZED);
} }
Some(def::DefStruct(_)) => { Some(def::DefStruct(_)) => {
if let ty::ty_bare_fn(..) = node_ty.sty { if let ty::ty_bare_fn(..) = node_ty.sty {
// Count the function pointer. // Count the function pointer.
v.add_qualif(NON_ZERO_SIZED); v.add_qualif(ConstQualif::NON_ZERO_SIZED);
} }
} }
Some(def::DefFn(..)) | Some(def::DefMethod(..)) => { Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
// Count the function pointer. // Count the function pointer.
v.add_qualif(NON_ZERO_SIZED); v.add_qualif(ConstQualif::NON_ZERO_SIZED);
} }
Some(def::DefStatic(..)) => { Some(def::DefStatic(..)) => {
match v.mode { match v.mode {
@ -487,7 +489,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
"constants cannot refer to other statics, \ "constants cannot refer to other statics, \
insert an intermediate constant instead"); insert an intermediate constant instead");
} }
Mode::Var => v.add_qualif(NOT_CONST) Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
} }
} }
Some(def::DefConst(did)) | Some(def::DefConst(did)) |
@ -503,7 +505,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
} }
} }
def => { def => {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
debug!("(checking const) found bad def: {:?}", def); debug!("(checking const) found bad def: {:?}", def);
span_err!(v.tcx.sess, e.span, E0014, span_err!(v.tcx.sess, e.span, E0014,
@ -530,10 +532,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
Some(def::DefStruct(..)) => {} Some(def::DefStruct(..)) => {}
Some(def::DefVariant(..)) => { Some(def::DefVariant(..)) => {
// Count the discriminator. // Count the discriminator.
v.add_qualif(NON_ZERO_SIZED); v.add_qualif(ConstQualif::NON_ZERO_SIZED);
} }
_ => { _ => {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0015, span_err!(v.tcx.sess, e.span, E0015,
"function calls in {}s are limited to \ "function calls in {}s are limited to \
@ -545,7 +547,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprBlock(ref block) => { ast::ExprBlock(ref block) => {
// Check all statements in the block // Check all statements in the block
let mut block_span_err = |span| { let mut block_span_err = |span| {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, span, E0016, span_err!(v.tcx.sess, span, E0016,
"blocks in {}s are limited to items and \ "blocks in {}s are limited to items and \
@ -574,17 +576,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprStruct(..) => { ast::ExprStruct(..) => {
let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id()); let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
if did == v.tcx.lang_items.unsafe_cell_type() { if did == v.tcx.lang_items.unsafe_cell_type() {
v.add_qualif(MUTABLE_MEM); v.add_qualif(ConstQualif::MUTABLE_MEM);
} }
} }
ast::ExprLit(_) | ast::ExprLit(_) |
ast::ExprAddrOf(..) => { ast::ExprAddrOf(..) => {
v.add_qualif(NON_ZERO_SIZED); v.add_qualif(ConstQualif::NON_ZERO_SIZED);
} }
ast::ExprRepeat(..) => { ast::ExprRepeat(..) => {
v.add_qualif(PREFER_IN_PLACE); v.add_qualif(ConstQualif::PREFER_IN_PLACE);
} }
ast::ExprClosure(..) => { ast::ExprClosure(..) => {
@ -593,7 +595,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) { if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) {
assert!(v.mode == Mode::Var, assert!(v.mode == Mode::Var,
"global closures can't capture anything"); "global closures can't capture anything");
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
} }
} }
@ -631,7 +633,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprAssignOp(..) | ast::ExprAssignOp(..) |
ast::ExprInlineAsm(_) | ast::ExprInlineAsm(_) |
ast::ExprMac(_) => { ast::ExprMac(_) => {
v.add_qualif(NOT_CONST); v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var { if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0019, span_err!(v.tcx.sess, e.span, E0019,
"{} contains unimplemented expression type", v.msg()); "{} contains unimplemented expression type", v.msg());
@ -644,7 +646,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
visit::walk_crate(&mut CheckCrateVisitor { visit::walk_crate(&mut CheckCrateVisitor {
tcx: tcx, tcx: tcx,
mode: Mode::Var, mode: Mode::Var,
qualif: NOT_CONST, qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap() rvalue_borrows: NodeMap()
}, tcx.map.krate()); }, tcx.map.krate());

View file

@ -838,20 +838,20 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
expr_ty: Ty<'tcx>) expr_ty: Ty<'tcx>)
-> cmt<'tcx> { -> cmt<'tcx> {
let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned() let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
.unwrap_or(check_const::NOT_CONST); .unwrap_or(check_const::ConstQualif::NOT_CONST);
// Only promote `[T; 0]` before an RFC for rvalue promotions // Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted. // is accepted.
let qualif = match expr_ty.sty { let qualif = match expr_ty.sty {
ty::ty_vec(_, Some(0)) => qualif, ty::ty_vec(_, Some(0)) => qualif,
_ => check_const::NOT_CONST _ => check_const::ConstQualif::NOT_CONST
}; };
// Compute maximum lifetime of this rvalue. This is 'static if // Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp // we can promote to a constant, otherwise equal to enclosing temp
// lifetime. // lifetime.
let re = match qualif & check_const::NON_STATIC_BORROWS { let re = match qualif & check_const::ConstQualif::NON_STATIC_BORROWS {
check_const::PURE_CONST => ty::ReStatic, check_const::ConstQualif::PURE_CONST => ty::ReStatic,
_ => self.temporary_scope(id), _ => self.temporary_scope(id),
}; };
let ret = self.cat_rvalue(id, span, re, expr_ty); let ret = self.cat_rvalue(id, span, re, expr_ty);

View file

@ -848,16 +848,18 @@ impl<'tcx> ctxt<'tcx> {
// recursing over the type itself. // recursing over the type itself.
bitflags! { bitflags! {
flags TypeFlags: u32 { flags TypeFlags: u32 {
const NO_TYPE_FLAGS = 0b0, const NO_TYPE_FLAGS = 0,
const HAS_PARAMS = 0b1, const HAS_PARAMS = 1 << 0,
const HAS_SELF = 0b10, const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 0b100, const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 0b1000, const HAS_RE_INFER = 1 << 3,
const HAS_RE_LATE_BOUND = 0b10000, const HAS_RE_LATE_BOUND = 1 << 4,
const HAS_REGIONS = 0b100000, const HAS_REGIONS = 1 << 5,
const HAS_TY_ERR = 0b1000000, const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 0b10000000, const HAS_PROJECTION = 1 << 7,
const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits, const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_REGIONS.bits,
} }
} }
@ -890,8 +892,8 @@ macro_rules! sty_debug_print {
ty::ty_err => /* unimportant */ continue, ty::ty_err => /* unimportant */ continue,
$(ty::$variant(..) => &mut $variant,)* $(ty::$variant(..) => &mut $variant,)*
}; };
let region = t.flags.intersects(ty::HAS_RE_INFER); let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
let ty = t.flags.intersects(ty::HAS_TY_INFER); let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
variant.total += 1; variant.total += 1;
total.total += 1; total.total += 1;
@ -993,23 +995,23 @@ impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
} }
pub fn type_has_params(ty: Ty) -> bool { pub fn type_has_params(ty: Ty) -> bool {
ty.flags.intersects(HAS_PARAMS) ty.flags.intersects(TypeFlags::HAS_PARAMS)
} }
pub fn type_has_self(ty: Ty) -> bool { pub fn type_has_self(ty: Ty) -> bool {
ty.flags.intersects(HAS_SELF) ty.flags.intersects(TypeFlags::HAS_SELF)
} }
pub fn type_has_ty_infer(ty: Ty) -> bool { pub fn type_has_ty_infer(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_INFER) ty.flags.intersects(TypeFlags::HAS_TY_INFER)
} }
pub fn type_needs_infer(ty: Ty) -> bool { pub fn type_needs_infer(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_INFER | HAS_RE_INFER) ty.flags.intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
} }
pub fn type_has_projection(ty: Ty) -> bool { pub fn type_has_projection(ty: Ty) -> bool {
ty.flags.intersects(HAS_PROJECTION) ty.flags.intersects(TypeFlags::HAS_PROJECTION)
} }
pub fn type_has_late_bound_regions(ty: Ty) -> bool { pub fn type_has_late_bound_regions(ty: Ty) -> bool {
ty.flags.intersects(HAS_RE_LATE_BOUND) ty.flags.intersects(TypeFlags::HAS_RE_LATE_BOUND)
} }
/// An "escaping region" is a bound region whose binder is not part of `t`. /// An "escaping region" is a bound region whose binder is not part of `t`.
@ -2810,7 +2812,7 @@ struct FlagComputation {
impl FlagComputation { impl FlagComputation {
fn new() -> FlagComputation { fn new() -> FlagComputation {
FlagComputation { flags: NO_TYPE_FLAGS, depth: 0 } FlagComputation { flags: TypeFlags::NO_TYPE_FLAGS, depth: 0 }
} }
fn for_sty(st: &sty) -> FlagComputation { fn for_sty(st: &sty) -> FlagComputation {
@ -2855,20 +2857,20 @@ impl FlagComputation {
// You might think that we could just return ty_err for // You might think that we could just return ty_err for
// any type containing ty_err as a component, and get // any type containing ty_err as a component, and get
// rid of the HAS_TY_ERR flag -- likewise for ty_bot (with // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
// the exception of function types that return bot). // the exception of function types that return bot).
// But doing so caused sporadic memory corruption, and // But doing so caused sporadic memory corruption, and
// neither I (tjc) nor nmatsakis could figure out why, // neither I (tjc) nor nmatsakis could figure out why,
// so we're doing it this way. // so we're doing it this way.
&ty_err => { &ty_err => {
self.add_flags(HAS_TY_ERR) self.add_flags(TypeFlags::HAS_TY_ERR)
} }
&ty_param(ref p) => { &ty_param(ref p) => {
if p.space == subst::SelfSpace { if p.space == subst::SelfSpace {
self.add_flags(HAS_SELF); self.add_flags(TypeFlags::HAS_SELF);
} else { } else {
self.add_flags(HAS_PARAMS); self.add_flags(TypeFlags::HAS_PARAMS);
} }
} }
@ -2877,7 +2879,7 @@ impl FlagComputation {
} }
&ty_infer(_) => { &ty_infer(_) => {
self.add_flags(HAS_TY_INFER) self.add_flags(TypeFlags::HAS_TY_INFER)
} }
&ty_enum(_, substs) | &ty_struct(_, substs) => { &ty_enum(_, substs) | &ty_struct(_, substs) => {
@ -2885,7 +2887,7 @@ impl FlagComputation {
} }
&ty_projection(ref data) => { &ty_projection(ref data) => {
self.add_flags(HAS_PROJECTION); self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_projection_ty(data); self.add_projection_ty(data);
} }
@ -2949,11 +2951,11 @@ impl FlagComputation {
} }
fn add_region(&mut self, r: Region) { fn add_region(&mut self, r: Region) {
self.add_flags(HAS_REGIONS); self.add_flags(TypeFlags::HAS_REGIONS);
match r { match r {
ty::ReInfer(_) => { self.add_flags(HAS_RE_INFER); } ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
ty::ReLateBound(debruijn, _) => { ty::ReLateBound(debruijn, _) => {
self.add_flags(HAS_RE_LATE_BOUND); self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
self.add_depth(debruijn.depth); self.add_depth(debruijn.depth);
} }
_ => { } _ => { }
@ -3307,11 +3309,11 @@ pub fn type_is_nil(ty: Ty) -> bool {
} }
pub fn type_is_error(ty: Ty) -> bool { pub fn type_is_error(ty: Ty) -> bool {
ty.flags.intersects(HAS_TY_ERR) ty.flags.intersects(TypeFlags::HAS_TY_ERR)
} }
pub fn type_needs_subst(ty: Ty) -> bool { pub fn type_needs_subst(ty: Ty) -> bool {
ty.flags.intersects(NEEDS_SUBST) ty.flags.intersects(TypeFlags::NEEDS_SUBST)
} }
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {

View file

@ -43,19 +43,19 @@
/// const FLAG_A = 0b00000001, /// const FLAG_A = 0b00000001,
/// const FLAG_B = 0b00000010, /// const FLAG_B = 0b00000010,
/// const FLAG_C = 0b00000100, /// const FLAG_C = 0b00000100,
/// const FLAG_ABC = FLAG_A.bits /// const FLAG_ABC = Flags::FLAG_A.bits
/// | FLAG_B.bits /// | Flags::FLAG_B.bits
/// | FLAG_C.bits, /// | Flags::FLAG_C.bits,
/// } /// }
/// } /// }
/// ///
/// fn main() { /// fn main() {
/// let e1 = FLAG_A | FLAG_C; /// let e1 = Flags::FLAG_A | Flags::FLAG_C;
/// let e2 = FLAG_B | FLAG_C; /// let e2 = Flags::FLAG_B | Flags::FLAG_C;
/// assert!((e1 | e2) == FLAG_ABC); // union /// assert!((e1 | e2) == Flags::FLAG_ABC); // union
/// assert!((e1 & e2) == FLAG_C); // intersection /// assert!((e1 & e2) == Flags::FLAG_C); // intersection
/// assert!((e1 - e2) == FLAG_A); // set difference /// assert!((e1 - e2) == Flags::FLAG_A); // set difference
/// assert!(!e2 == FLAG_A); // set complement /// assert!(!e2 == Flags::FLAG_A); // set complement
/// } /// }
/// ``` /// ```
/// ///
@ -88,7 +88,7 @@
/// } /// }
/// ///
/// fn main() { /// fn main() {
/// let mut flags = FLAG_A | FLAG_B; /// let mut flags = Flags::FLAG_A | Flags::FLAG_B;
/// flags.clear(); /// flags.clear();
/// assert!(flags.is_empty()); /// assert!(flags.is_empty());
/// assert_eq!(format!("{:?}", flags), "hi!"); /// assert_eq!(format!("{:?}", flags), "hi!");
@ -316,9 +316,9 @@ mod tests {
#[doc = "* cmr bed"] #[doc = "* cmr bed"]
#[doc = "* strcat table"] #[doc = "* strcat table"]
#[doc = "<strcat> wait what?"] #[doc = "<strcat> wait what?"]
const FlagABC = FlagA.bits const FlagABC = Flags::FlagA.bits
| FlagB.bits | Flags::FlagB.bits
| FlagC.bits, | Flags::FlagC.bits,
} }
} }
@ -331,32 +331,32 @@ mod tests {
#[test] #[test]
fn test_bits(){ fn test_bits(){
assert_eq!(Flags::empty().bits(), 0b00000000); assert_eq!(Flags::empty().bits(), 0b00000000);
assert_eq!(FlagA.bits(), 0b00000001); assert_eq!(Flags::FlagA.bits(), 0b00000001);
assert_eq!(FlagABC.bits(), 0b00000111); assert_eq!(Flags::FlagABC.bits(), 0b00000111);
assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
assert_eq!(AnotherFlag.bits(), !0); assert_eq!(AnotherSetOfFlags::AnotherFlag.bits(), !0);
} }
#[test] #[test]
fn test_from_bits() { fn test_from_bits() {
assert!(Flags::from_bits(0) == Some(Flags::empty())); assert!(Flags::from_bits(0) == Some(Flags::empty()));
assert!(Flags::from_bits(0b1) == Some(FlagA)); assert!(Flags::from_bits(0b1) == Some(Flags::FlagA));
assert!(Flags::from_bits(0b10) == Some(FlagB)); assert!(Flags::from_bits(0b10) == Some(Flags::FlagB));
assert!(Flags::from_bits(0b11) == Some(FlagA | FlagB)); assert!(Flags::from_bits(0b11) == Some(Flags::FlagA | Flags::FlagB));
assert!(Flags::from_bits(0b1000) == None); assert!(Flags::from_bits(0b1000) == None);
assert!(AnotherSetOfFlags::from_bits(!0) == Some(AnotherFlag)); assert!(AnotherSetOfFlags::from_bits(!0) == Some(AnotherSetOfFlags::AnotherFlag));
} }
#[test] #[test]
fn test_from_bits_truncate() { fn test_from_bits_truncate() {
assert!(Flags::from_bits_truncate(0) == Flags::empty()); assert!(Flags::from_bits_truncate(0) == Flags::empty());
assert!(Flags::from_bits_truncate(0b1) == FlagA); assert!(Flags::from_bits_truncate(0b1) == Flags::FlagA);
assert!(Flags::from_bits_truncate(0b10) == FlagB); assert!(Flags::from_bits_truncate(0b10) == Flags::FlagB);
assert!(Flags::from_bits_truncate(0b11) == (FlagA | FlagB)); assert!(Flags::from_bits_truncate(0b11) == (Flags::FlagA | Flags::FlagB));
assert!(Flags::from_bits_truncate(0b1000) == Flags::empty()); assert!(Flags::from_bits_truncate(0b1000) == Flags::empty());
assert!(Flags::from_bits_truncate(0b1001) == FlagA); assert!(Flags::from_bits_truncate(0b1001) == Flags::FlagA);
assert!(AnotherSetOfFlags::from_bits_truncate(0) == AnotherSetOfFlags::empty()); assert!(AnotherSetOfFlags::from_bits_truncate(0) == AnotherSetOfFlags::empty());
} }
@ -364,19 +364,19 @@ mod tests {
#[test] #[test]
fn test_is_empty(){ fn test_is_empty(){
assert!(Flags::empty().is_empty()); assert!(Flags::empty().is_empty());
assert!(!FlagA.is_empty()); assert!(!Flags::FlagA.is_empty());
assert!(!FlagABC.is_empty()); assert!(!Flags::FlagABC.is_empty());
assert!(!AnotherFlag.is_empty()); assert!(!AnotherSetOfFlags::AnotherFlag.is_empty());
} }
#[test] #[test]
fn test_is_all() { fn test_is_all() {
assert!(Flags::all().is_all()); assert!(Flags::all().is_all());
assert!(!FlagA.is_all()); assert!(!Flags::FlagA.is_all());
assert!(FlagABC.is_all()); assert!(Flags::FlagABC.is_all());
assert!(AnotherFlag.is_all()); assert!(AnotherSetOfFlags::AnotherFlag.is_all());
} }
#[test] #[test]
@ -385,77 +385,77 @@ mod tests {
let e2 = Flags::empty(); let e2 = Flags::empty();
assert!(!e1.intersects(e2)); assert!(!e1.intersects(e2));
assert!(AnotherFlag.intersects(AnotherFlag)); assert!(AnotherSetOfFlags::AnotherFlag.intersects(AnotherSetOfFlags::AnotherFlag));
} }
#[test] #[test]
fn test_empty_does_not_intersect_with_full() { fn test_empty_does_not_intersect_with_full() {
let e1 = Flags::empty(); let e1 = Flags::empty();
let e2 = FlagABC; let e2 = Flags::FlagABC;
assert!(!e1.intersects(e2)); assert!(!e1.intersects(e2));
} }
#[test] #[test]
fn test_disjoint_intersects() { fn test_disjoint_intersects() {
let e1 = FlagA; let e1 = Flags::FlagA;
let e2 = FlagB; let e2 = Flags::FlagB;
assert!(!e1.intersects(e2)); assert!(!e1.intersects(e2));
} }
#[test] #[test]
fn test_overlapping_intersects() { fn test_overlapping_intersects() {
let e1 = FlagA; let e1 = Flags::FlagA;
let e2 = FlagA | FlagB; let e2 = Flags::FlagA | Flags::FlagB;
assert!(e1.intersects(e2)); assert!(e1.intersects(e2));
} }
#[test] #[test]
fn test_contains() { fn test_contains() {
let e1 = FlagA; let e1 = Flags::FlagA;
let e2 = FlagA | FlagB; let e2 = Flags::FlagA | Flags::FlagB;
assert!(!e1.contains(e2)); assert!(!e1.contains(e2));
assert!(e2.contains(e1)); assert!(e2.contains(e1));
assert!(FlagABC.contains(e2)); assert!(Flags::FlagABC.contains(e2));
assert!(AnotherFlag.contains(AnotherFlag)); assert!(AnotherSetOfFlags::AnotherFlag.contains(AnotherSetOfFlags::AnotherFlag));
} }
#[test] #[test]
fn test_insert(){ fn test_insert(){
let mut e1 = FlagA; let mut e1 = Flags::FlagA;
let e2 = FlagA | FlagB; let e2 = Flags::FlagA | Flags::FlagB;
e1.insert(e2); e1.insert(e2);
assert!(e1 == e2); assert!(e1 == e2);
let mut e3 = AnotherSetOfFlags::empty(); let mut e3 = AnotherSetOfFlags::empty();
e3.insert(AnotherFlag); e3.insert(AnotherSetOfFlags::AnotherFlag);
assert!(e3 == AnotherFlag); assert!(e3 == AnotherSetOfFlags::AnotherFlag);
} }
#[test] #[test]
fn test_remove(){ fn test_remove(){
let mut e1 = FlagA | FlagB; let mut e1 = Flags::FlagA | Flags::FlagB;
let e2 = FlagA | FlagC; let e2 = Flags::FlagA | Flags::FlagC;
e1.remove(e2); e1.remove(e2);
assert!(e1 == FlagB); assert!(e1 == Flags::FlagB);
let mut e3 = AnotherFlag; let mut e3 = AnotherSetOfFlags::AnotherFlag;
e3.remove(AnotherFlag); e3.remove(AnotherSetOfFlags::AnotherFlag);
assert!(e3 == AnotherSetOfFlags::empty()); assert!(e3 == AnotherSetOfFlags::empty());
} }
#[test] #[test]
fn test_operators() { fn test_operators() {
let e1 = FlagA | FlagC; let e1 = Flags::FlagA | Flags::FlagC;
let e2 = FlagB | FlagC; let e2 = Flags::FlagB | Flags::FlagC;
assert!((e1 | e2) == FlagABC); // union assert!((e1 | e2) == Flags::FlagABC); // union
assert!((e1 & e2) == FlagC); // intersection assert!((e1 & e2) == Flags::FlagC); // intersection
assert!((e1 - e2) == FlagA); // set difference assert!((e1 - e2) == Flags::FlagA); // set difference
assert!(!e2 == FlagA); // set complement assert!(!e2 == Flags::FlagA); // set complement
assert!(e1 ^ e2 == FlagA | FlagB); // toggle assert!(e1 ^ e2 == Flags::FlagA | Flags::FlagB); // toggle
let mut e3 = e1; let mut e3 = e1;
e3.toggle(e2); e3.toggle(e2);
assert!(e3 == FlagA | FlagB); assert!(e3 == Flags::FlagA | Flags::FlagB);
let mut m4 = AnotherSetOfFlags::empty(); let mut m4 = AnotherSetOfFlags::empty();
m4.toggle(AnotherSetOfFlags::empty()); m4.toggle(AnotherSetOfFlags::empty());
@ -468,11 +468,11 @@ mod tests {
let mut b = Flags::empty(); let mut b = Flags::empty();
assert!(!(a < b) && !(b < a)); assert!(!(a < b) && !(b < a));
b = FlagB; b = Flags::FlagB;
assert!(a < b); assert!(a < b);
a = FlagC; a = Flags::FlagC;
assert!(!(a < b) && b < a); assert!(!(a < b) && b < a);
b = FlagC | FlagB; b = Flags::FlagC | Flags::FlagB;
assert!(a < b); assert!(a < b);
} }
@ -482,10 +482,10 @@ mod tests {
let mut b = Flags::empty(); let mut b = Flags::empty();
assert!(a <= b && a >= b); assert!(a <= b && a >= b);
a = FlagA; a = Flags::FlagA;
assert!(a > b && a >= b); assert!(a > b && a >= b);
assert!(b < a && b <= a); assert!(b < a && b <= a);
b = FlagB; b = Flags::FlagB;
assert!(b > a && b >= a); assert!(b > a && b >= a);
assert!(a < b && a <= b); assert!(a < b && a <= b);
} }
@ -496,7 +496,7 @@ mod tests {
let mut y = Flags::empty(); let mut y = Flags::empty();
assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y)); assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y));
x = Flags::all(); x = Flags::all();
y = FlagABC; y = Flags::FlagABC;
assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y)); assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y));
} }
} }

View file

@ -25,6 +25,7 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")] html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(collections)] #![feature(collections)]
#![feature(libc)] #![feature(libc)]
@ -139,7 +140,7 @@ bitflags! {
const OptimizeForSizeAttribute = 1 << 13, const OptimizeForSizeAttribute = 1 << 13,
const StackProtectAttribute = 1 << 14, const StackProtectAttribute = 1 << 14,
const StackProtectReqAttribute = 1 << 15, const StackProtectReqAttribute = 1 << 15,
const AlignmentAttribute = 31 << 16, const AlignmentAttribute = 1 << 16,
const NoCaptureAttribute = 1 << 21, const NoCaptureAttribute = 1 << 21,
const NoRedZoneAttribute = 1 << 22, const NoRedZoneAttribute = 1 << 22,
const NoImplicitFloatAttribute = 1 << 23, const NoImplicitFloatAttribute = 1 << 23,

View file

@ -13,7 +13,7 @@
//! Here we build the "reduced graph": the graph of the module tree without //! Here we build the "reduced graph": the graph of the module tree without
//! any imports resolved. //! any imports resolved.
use {DefModifiers, PUBLIC, IMPORTABLE}; use DefModifiers;
use resolve_imports::ImportDirective; use resolve_imports::ImportDirective;
use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport}; use resolve_imports::ImportDirectiveSubclass::{self, SingleImport, GlobImport};
use resolve_imports::ImportResolution; use resolve_imports::ImportResolution;
@ -262,7 +262,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
let name = item.ident.name; let name = item.ident.name;
let sp = item.span; let sp = item.span;
let is_public = item.vis == ast::Public; let is_public = item.vis == ast::Public;
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; let modifiers = if is_public {
DefModifiers::PUBLIC
} else {
DefModifiers::empty()
} | DefModifiers::IMPORTABLE;
match item.node { match item.node {
ItemUse(ref view_path) => { ItemUse(ref view_path) => {
@ -533,20 +537,20 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
ast::ConstTraitItem(..) => { ast::ConstTraitItem(..) => {
let def = DefAssociatedConst(local_def(trait_item.id), let def = DefAssociatedConst(local_def(trait_item.id),
FromTrait(local_def(item.id))); FromTrait(local_def(item.id)));
// NB: not IMPORTABLE // NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, PUBLIC); name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
} }
ast::MethodTraitItem(..) => { ast::MethodTraitItem(..) => {
let def = DefMethod(local_def(trait_item.id), let def = DefMethod(local_def(trait_item.id),
FromTrait(local_def(item.id))); FromTrait(local_def(item.id)));
// NB: not IMPORTABLE // NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, PUBLIC); name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
} }
ast::TypeTraitItem(..) => { ast::TypeTraitItem(..) => {
let def = DefAssociatedTy(local_def(item.id), let def = DefAssociatedTy(local_def(item.id),
local_def(trait_item.id)); local_def(trait_item.id));
// NB: not IMPORTABLE // NB: not DefModifiers::IMPORTABLE
name_bindings.define_type(def, trait_item.span, PUBLIC); name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
} }
} }
@ -584,10 +588,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
// used // used
child.define_value(DefVariant(item_id, child.define_value(DefVariant(item_id,
local_def(variant.node.id), is_exported), local_def(variant.node.id), is_exported),
variant.span, PUBLIC | IMPORTABLE); variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
child.define_type(DefVariant(item_id, child.define_type(DefVariant(item_id,
local_def(variant.node.id), is_exported), local_def(variant.node.id), is_exported),
variant.span, PUBLIC | IMPORTABLE); variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
} }
/// Constructs the reduced graph for one foreign item. /// Constructs the reduced graph for one foreign item.
@ -596,7 +600,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
parent: &Rc<Module>) { parent: &Rc<Module>) {
let name = foreign_item.ident.name; let name = foreign_item.ident.name;
let is_public = foreign_item.vis == ast::Public; let is_public = foreign_item.vis == ast::Public;
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; let modifiers = if is_public {
DefModifiers::PUBLIC
} else {
DefModifiers::empty()
} | DefModifiers::IMPORTABLE;
let name_bindings = let name_bindings =
self.add_child(name, parent, ForbidDuplicateValues, self.add_child(name, parent, ForbidDuplicateValues,
foreign_item.span); foreign_item.span);
@ -644,7 +652,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
external crate) building external def {}, priv {:?}", external crate) building external def {}, priv {:?}",
final_ident, vis); final_ident, vis);
let is_public = vis == ast::Public; let is_public = vis == ast::Public;
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; let modifiers = if is_public {
DefModifiers::PUBLIC
} else {
DefModifiers::empty()
} | DefModifiers::IMPORTABLE;
let is_exported = is_public && match new_parent.def_id.get() { let is_exported = is_public && match new_parent.def_id.get() {
None => true, None => true,
Some(did) => self.external_exports.contains(&did) Some(did) => self.external_exports.contains(&did)
@ -695,7 +707,7 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
final_ident); final_ident);
// variants are always treated as importable to allow them to be // variants are always treated as importable to allow them to be
// glob used // glob used
let modifiers = PUBLIC | IMPORTABLE; let modifiers = DefModifiers::PUBLIC | DefModifiers::IMPORTABLE;
if is_struct { if is_struct {
child_name_bindings.define_type(def, DUMMY_SP, modifiers); child_name_bindings.define_type(def, DUMMY_SP, modifiers);
// Not adding fields for variants as they are not accessed with a self receiver // Not adding fields for variants as they are not accessed with a self receiver
@ -715,11 +727,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
crate) building value (fn/static) {}", final_ident); crate) building value (fn/static) {}", final_ident);
// impl methods have already been defined with the correct importability modifier // impl methods have already been defined with the correct importability modifier
let mut modifiers = match *child_name_bindings.value_def.borrow() { let mut modifiers = match *child_name_bindings.value_def.borrow() {
Some(ref def) => (modifiers & !IMPORTABLE) | (def.modifiers & IMPORTABLE), Some(ref def) => (modifiers & !DefModifiers::IMPORTABLE) |
(def.modifiers & DefModifiers::IMPORTABLE),
None => modifiers None => modifiers
}; };
if new_parent.kind.get() != NormalModuleKind { if new_parent.kind.get() != NormalModuleKind {
modifiers = modifiers & !IMPORTABLE; modifiers = modifiers & !DefModifiers::IMPORTABLE;
} }
child_name_bindings.define_value(def, DUMMY_SP, modifiers); child_name_bindings.define_value(def, DUMMY_SP, modifiers);
} }

View file

@ -20,6 +20,7 @@
html_root_url = "http://doc.rust-lang.org/nightly/")] html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(alloc)] #![feature(alloc)]
#![feature(associated_consts)]
#![feature(collections)] #![feature(collections)]
#![feature(rustc_diagnostic_macros)] #![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)] #![feature(rustc_private)]
@ -477,8 +478,8 @@ impl fmt::Debug for Module {
bitflags! { bitflags! {
#[derive(Debug)] #[derive(Debug)]
flags DefModifiers: u8 { flags DefModifiers: u8 {
const PUBLIC = 0b0000_0001, const PUBLIC = 1 << 0,
const IMPORTABLE = 0b0000_0010, const IMPORTABLE = 1 << 1,
} }
} }
@ -524,7 +525,11 @@ impl NameBindings {
is_public: bool, is_public: bool,
sp: Span) { sp: Span) {
// Merges the module with the existing type def or creates a new one. // Merges the module with the existing type def or creates a new one.
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; let modifiers = if is_public {
DefModifiers::PUBLIC
} else {
DefModifiers::empty()
} | DefModifiers::IMPORTABLE;
let module_ = Rc::new(Module::new(parent_link, let module_ = Rc::new(Module::new(parent_link,
def_id, def_id,
kind, kind,
@ -559,7 +564,11 @@ impl NameBindings {
external: bool, external: bool,
is_public: bool, is_public: bool,
_sp: Span) { _sp: Span) {
let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; let modifiers = if is_public {
DefModifiers::PUBLIC
} else {
DefModifiers::empty()
} | DefModifiers::IMPORTABLE;
let type_def = self.type_def.borrow().clone(); let type_def = self.type_def.borrow().clone();
match type_def { match type_def {
None => { None => {
@ -659,7 +668,7 @@ impl NameBindings {
} }
fn defined_in_public_namespace(&self, namespace: Namespace) -> bool { fn defined_in_public_namespace(&self, namespace: Namespace) -> bool {
self.defined_in_namespace_with(namespace, PUBLIC) self.defined_in_namespace_with(namespace, DefModifiers::PUBLIC)
} }
fn defined_in_namespace_with(&self, namespace: Namespace, modifiers: DefModifiers) -> bool { fn defined_in_namespace_with(&self, namespace: Namespace, modifiers: DefModifiers) -> bool {
@ -730,11 +739,11 @@ impl NameBindings {
match namespace { match namespace {
TypeNS => { TypeNS => {
let type_def = self.type_def.borrow(); let type_def = self.type_def.borrow();
type_def.as_ref().unwrap().modifiers.contains(PUBLIC) type_def.as_ref().unwrap().modifiers.contains(DefModifiers::PUBLIC)
} }
ValueNS => { ValueNS => {
let value_def = self.value_def.borrow(); let value_def = self.value_def.borrow();
value_def.as_ref().unwrap().modifiers.contains(PUBLIC) value_def.as_ref().unwrap().modifiers.contains(DefModifiers::PUBLIC)
} }
} }
} }
@ -921,7 +930,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
fn create_name_bindings_from_module(module: Rc<Module>) -> NameBindings { fn create_name_bindings_from_module(module: Rc<Module>) -> NameBindings {
NameBindings { NameBindings {
type_def: RefCell::new(Some(TypeNsDef { type_def: RefCell::new(Some(TypeNsDef {
modifiers: IMPORTABLE, modifiers: DefModifiers::IMPORTABLE,
module_def: Some(module), module_def: Some(module),
type_def: None, type_def: None,
type_span: None type_span: None

View file

@ -10,7 +10,7 @@
use self::ImportDirectiveSubclass::*; use self::ImportDirectiveSubclass::*;
use {PUBLIC, IMPORTABLE}; use DefModifiers;
use Module; use Module;
use Namespace::{self, TypeNS, ValueNS}; use Namespace::{self, TypeNS, ValueNS};
use NameBindings; use NameBindings;
@ -848,7 +848,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
// Merge the child item into the import resolution. // Merge the child item into the import resolution.
{ {
let mut merge_child_item = |namespace| { let mut merge_child_item = |namespace| {
if name_bindings.defined_in_namespace_with(namespace, IMPORTABLE | PUBLIC) { let modifier = DefModifiers::IMPORTABLE | DefModifiers::PUBLIC;
if name_bindings.defined_in_namespace_with(namespace, modifier) {
let namespace_name = match namespace { let namespace_name = match namespace {
TypeNS => "type", TypeNS => "type",
ValueNS => "value", ValueNS => "value",
@ -914,7 +916,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
import_span: Span, import_span: Span,
name: Name, name: Name,
namespace: Namespace) { namespace: Namespace) {
if !name_bindings.defined_in_namespace_with(namespace, IMPORTABLE) { if !name_bindings.defined_in_namespace_with(namespace, DefModifiers::IMPORTABLE) {
let msg = format!("`{}` is not directly importable", let msg = format!("`{}` is not directly importable",
token::get_name(name)); token::get_name(name));
span_err!(self.resolver.session, import_span, E0253, "{}", &msg[..]); span_err!(self.resolver.session, import_span, E0253, "{}", &msg[..]);

View file

@ -39,13 +39,13 @@ pub fn split_stack(val: ValueRef, set: bool) {
pub fn inline(val: ValueRef, inline: InlineAttr) { pub fn inline(val: ValueRef, inline: InlineAttr) {
use self::InlineAttr::*; use self::InlineAttr::*;
match inline { match inline {
Hint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), Hint => llvm::SetFunctionAttribute(val, llvm::Attribute::InlineHintAttribute),
Always => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), Always => llvm::SetFunctionAttribute(val, llvm::Attribute::AlwaysInlineAttribute),
Never => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), Never => llvm::SetFunctionAttribute(val, llvm::Attribute::NoInlineAttribute),
None => { None => {
let attr = llvm::InlineHintAttribute | let attr = llvm::Attribute::InlineHintAttribute |
llvm::AlwaysInlineAttribute | llvm::Attribute::AlwaysInlineAttribute |
llvm::NoInlineAttribute; llvm::Attribute::NoInlineAttribute;
unsafe { unsafe {
llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong) llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong)
} }
@ -57,10 +57,13 @@ pub fn inline(val: ValueRef, inline: InlineAttr) {
#[inline] #[inline]
pub fn emit_uwtable(val: ValueRef, emit: bool) { pub fn emit_uwtable(val: ValueRef, emit: bool) {
if emit { if emit {
llvm::SetFunctionAttribute(val, llvm::UWTableAttribute); llvm::SetFunctionAttribute(val, llvm::Attribute::UWTableAttribute);
} else { } else {
unsafe { unsafe {
llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong); llvm::LLVMRemoveFunctionAttr(
val,
llvm::Attribute::UWTableAttribute.bits() as c_ulonglong,
);
} }
} }
} }
@ -71,10 +74,13 @@ pub fn emit_uwtable(val: ValueRef, emit: bool) {
pub fn unwind(val: ValueRef, can_unwind: bool) { pub fn unwind(val: ValueRef, can_unwind: bool) {
if can_unwind { if can_unwind {
unsafe { unsafe {
llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong); llvm::LLVMRemoveFunctionAttr(
val,
llvm::Attribute::NoUnwindAttribute.bits() as c_ulonglong,
);
} }
} else { } else {
llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute); llvm::SetFunctionAttribute(val, llvm::Attribute::NoUnwindAttribute);
} }
} }
@ -83,10 +89,13 @@ pub fn unwind(val: ValueRef, can_unwind: bool) {
#[allow(dead_code)] // possibly useful function #[allow(dead_code)] // possibly useful function
pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { pub fn set_optimize_for_size(val: ValueRef, optimize: bool) {
if optimize { if optimize {
llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute); llvm::SetFunctionAttribute(val, llvm::Attribute::OptimizeForSizeAttribute);
} else { } else {
unsafe { unsafe {
llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong); llvm::LLVMRemoveFunctionAttr(
val,
llvm::Attribute::OptimizeForSizeAttribute.bits() as c_ulonglong,
);
} }
} }
} }
@ -107,7 +116,7 @@ pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRe
llvm::ColdAttribute as u64) llvm::ColdAttribute as u64)
} }
} else if attr.check_name("allocator") { } else if attr.check_name("allocator") {
llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); llvm::Attribute::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn);
} }
} }
} }
@ -176,9 +185,9 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
// The outptr can be noalias and nocapture because it's entirely // The outptr can be noalias and nocapture because it's entirely
// invisible to the program. We also know it's nonnull as well // invisible to the program. We also know it's nonnull as well
// as how many bytes we can dereference // as how many bytes we can dereference
attrs.arg(1, llvm::StructRetAttribute) attrs.arg(1, llvm::Attribute::StructRetAttribute)
.arg(1, llvm::NoAliasAttribute) .arg(1, llvm::Attribute::NoAliasAttribute)
.arg(1, llvm::NoCaptureAttribute) .arg(1, llvm::Attribute::NoCaptureAttribute)
.arg(1, llvm::DereferenceableAttribute(llret_sz)); .arg(1, llvm::DereferenceableAttribute(llret_sz));
// Add one more since there's an outptr // Add one more since there's an outptr
@ -190,7 +199,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
// `~` pointer return values never alias because ownership // `~` pointer return values never alias because ownership
// is transferred // is transferred
ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => { ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => {
attrs.ret(llvm::NoAliasAttribute); attrs.ret(llvm::Attribute::NoAliasAttribute);
} }
_ => {} _ => {}
} }
@ -207,7 +216,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
} }
if let ty::ty_bool = ret_ty.sty { if let ty::ty_bool = ret_ty.sty {
attrs.ret(llvm::ZExtAttribute); attrs.ret(llvm::Attribute::ZExtAttribute);
} }
} }
} }
@ -221,20 +230,20 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
// For non-immediate arguments the callee gets its own copy of // For non-immediate arguments the callee gets its own copy of
// the value on the stack, so there are no aliases. It's also // the value on the stack, so there are no aliases. It's also
// program-invisible so can't possibly capture // program-invisible so can't possibly capture
attrs.arg(idx, llvm::NoAliasAttribute) attrs.arg(idx, llvm::Attribute::NoAliasAttribute)
.arg(idx, llvm::NoCaptureAttribute) .arg(idx, llvm::Attribute::NoCaptureAttribute)
.arg(idx, llvm::DereferenceableAttribute(llarg_sz)); .arg(idx, llvm::DereferenceableAttribute(llarg_sz));
} }
ty::ty_bool => { ty::ty_bool => {
attrs.arg(idx, llvm::ZExtAttribute); attrs.arg(idx, llvm::Attribute::ZExtAttribute);
} }
// `~` pointer parameters never alias because ownership is transferred // `~` pointer parameters never alias because ownership is transferred
ty::ty_uniq(inner) => { ty::ty_uniq(inner) => {
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
attrs.arg(idx, llvm::NoAliasAttribute) attrs.arg(idx, llvm::Attribute::NoAliasAttribute)
.arg(idx, llvm::DereferenceableAttribute(llsz)); .arg(idx, llvm::DereferenceableAttribute(llsz));
} }
@ -247,15 +256,15 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
!ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => {
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
attrs.arg(idx, llvm::NoAliasAttribute) attrs.arg(idx, llvm::Attribute::NoAliasAttribute)
.arg(idx, llvm::DereferenceableAttribute(llsz)); .arg(idx, llvm::DereferenceableAttribute(llsz));
if mt.mutbl == ast::MutImmutable { if mt.mutbl == ast::MutImmutable {
attrs.arg(idx, llvm::ReadOnlyAttribute); attrs.arg(idx, llvm::Attribute::ReadOnlyAttribute);
} }
if let ReLateBound(_, BrAnon(_)) = *b { if let ReLateBound(_, BrAnon(_)) = *b {
attrs.arg(idx, llvm::NoCaptureAttribute); attrs.arg(idx, llvm::Attribute::NoCaptureAttribute);
} }
} }
@ -263,7 +272,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
// reference to escape this function (returned or stored beyond the call by a closure). // reference to escape this function (returned or stored beyond the call by a closure).
ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => {
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty));
attrs.arg(idx, llvm::NoCaptureAttribute) attrs.arg(idx, llvm::Attribute::NoCaptureAttribute)
.arg(idx, llvm::DereferenceableAttribute(llsz)); .arg(idx, llvm::DereferenceableAttribute(llsz));
} }

View file

@ -10,8 +10,7 @@
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
use llvm::{StructRetAttribute, ZExtAttribute};
use trans::cabi::{FnType, ArgType}; use trans::cabi::{FnType, ArgType};
use trans::context::CrateContext; use trans::context::CrateContext;
use trans::type_::Type; use trans::type_::Type;
@ -164,7 +163,7 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
return ArgType::direct(ty, None, None, attr); return ArgType::direct(ty, None, None, attr);
} }
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {
@ -186,12 +185,12 @@ fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
}; };
return ArgType::direct(ty, Some(llty), None, None); return ArgType::direct(ty, Some(llty), None, None);
} }
ArgType::indirect(ty, Some(StructRetAttribute)) ArgType::indirect(ty, Some(Attribute::StructRetAttribute))
} }
fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType { fn classify_arg_ty(ccx: &CrateContext, ty: Type) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
return ArgType::direct(ty, None, None, attr); return ArgType::direct(ty, None, None, attr);
} }
if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) { if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ty) {

View file

@ -10,8 +10,7 @@
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
use llvm::{StructRetAttribute, ZExtAttribute};
use trans::cabi::{FnType, ArgType}; use trans::cabi::{FnType, ArgType};
use trans::context::CrateContext; use trans::context::CrateContext;
use trans::type_::Type; use trans::type_::Type;
@ -132,7 +131,7 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
fn classify_ret_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { fn classify_ret_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
return ArgType::direct(ty, None, None, attr); return ArgType::direct(ty, None, None, attr);
} }
let size = ty_size(ty, align_fn); let size = ty_size(ty, align_fn);
@ -146,12 +145,12 @@ fn classify_ret_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType
}; };
return ArgType::direct(ty, Some(llty), None, None); return ArgType::direct(ty, Some(llty), None, None);
} }
ArgType::indirect(ty, Some(StructRetAttribute)) ArgType::indirect(ty, Some(Attribute::StructRetAttribute))
} }
fn classify_arg_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType { fn classify_arg_ty(ccx: &CrateContext, ty: Type, align_fn: TyAlignFn) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
return ArgType::direct(ty, None, None, attr); return ArgType::direct(ty, None, None, attr);
} }
let align = align_fn(ty); let align = align_fn(ty);

View file

@ -13,8 +13,7 @@
use libc::c_uint; use libc::c_uint;
use std::cmp; use std::cmp;
use llvm; use llvm;
use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
use llvm::{StructRetAttribute, ZExtAttribute};
use trans::cabi::{ArgType, FnType}; use trans::cabi::{ArgType, FnType};
use trans::context::CrateContext; use trans::context::CrateContext;
use trans::type_::Type; use trans::type_::Type;
@ -89,10 +88,10 @@ fn ty_size(ty: Type) -> usize {
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(ty, None, None, attr) ArgType::direct(ty, None, None, attr)
} else { } else {
ArgType::indirect(ty, Some(StructRetAttribute)) ArgType::indirect(ty, Some(Attribute::StructRetAttribute))
} }
} }
@ -106,7 +105,7 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut usize) -> ArgType
*offset += align_up_to(size, align * 8) / 8; *offset += align_up_to(size, align * 8) / 8;
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(ty, None, None, attr) ArgType::direct(ty, None, None, attr)
} else { } else {
ArgType::direct( ArgType::direct(

View file

@ -10,8 +10,7 @@
use libc::c_uint; use libc::c_uint;
use llvm; use llvm;
use llvm::{Integer, Pointer, Float, Double, Struct, Array}; use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
use llvm::{StructRetAttribute, ZExtAttribute};
use trans::cabi::{FnType, ArgType}; use trans::cabi::{FnType, ArgType};
use trans::context::CrateContext; use trans::context::CrateContext;
use trans::type_::Type; use trans::type_::Type;
@ -85,10 +84,10 @@ fn ty_size(ty: Type) -> usize {
fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType { fn classify_ret_ty(ccx: &CrateContext, ty: Type) -> ArgType {
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(ty, None, None, attr) ArgType::direct(ty, None, None, attr)
} else { } else {
ArgType::indirect(ty, Some(StructRetAttribute)) ArgType::indirect(ty, Some(Attribute::StructRetAttribute))
} }
} }
@ -102,7 +101,7 @@ fn classify_arg_ty(ccx: &CrateContext, ty: Type, offset: &mut usize) -> ArgType
*offset += align_up_to(size, align * 8) / 8; *offset += align_up_to(size, align * 8) / 8;
if is_reg_ty(ty) { if is_reg_ty(ty) {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(ty, None, None, attr) ArgType::direct(ty, None, None, attr)
} else { } else {
ArgType::direct( ArgType::direct(

View file

@ -52,11 +52,11 @@ pub fn compute_abi_info(ccx: &CrateContext,
ret_ty = ArgType::direct(rty, Some(t), None, None); ret_ty = ArgType::direct(rty, Some(t), None, None);
} }
RetPointer => { RetPointer => {
ret_ty = ArgType::indirect(rty, Some(StructRetAttribute)); ret_ty = ArgType::indirect(rty, Some(Attribute::StructRetAttribute));
} }
} }
} else { } else {
let attr = if rty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if rty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ret_ty = ArgType::direct(rty, None, None, attr); ret_ty = ArgType::direct(rty, None, None, attr);
} }
@ -67,11 +67,11 @@ pub fn compute_abi_info(ccx: &CrateContext,
if size == 0 { if size == 0 {
ArgType::ignore(t) ArgType::ignore(t)
} else { } else {
ArgType::indirect(t, Some(ByValAttribute)) ArgType::indirect(t, Some(Attribute::ByValAttribute))
} }
} }
_ => { _ => {
let attr = if t == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if t == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(t, None, None, attr) ArgType::direct(t, None, None, attr)
} }
}; };

View file

@ -16,7 +16,6 @@ use self::RegClass::*;
use llvm::{Integer, Pointer, Float, Double}; use llvm::{Integer, Pointer, Float, Double};
use llvm::{Struct, Array, Attribute, Vector}; use llvm::{Struct, Array, Attribute, Vector};
use llvm::{StructRetAttribute, ByValAttribute, ZExtAttribute};
use trans::cabi::{ArgType, FnType}; use trans::cabi::{ArgType, FnType};
use trans::context::CrateContext; use trans::context::CrateContext;
use trans::type_::Type; use trans::type_::Type;
@ -407,19 +406,19 @@ pub fn compute_abi_info(ccx: &CrateContext,
None) None)
} }
} else { } else {
let attr = if ty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if ty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(ty, None, None, attr) ArgType::direct(ty, None, None, attr)
} }
} }
let mut arg_tys = Vec::new(); let mut arg_tys = Vec::new();
for t in atys { for t in atys {
let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), ByValAttribute); let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), Attribute::ByValAttribute);
arg_tys.push(ty); arg_tys.push(ty);
} }
let ret_ty = if ret_def { let ret_ty = if ret_def {
x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), StructRetAttribute) x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), Attribute::StructRetAttribute)
} else { } else {
ArgType::direct(Type::void(ccx), None, None, None) ArgType::direct(Type::void(ccx), None, None, None)
}; };

View file

@ -31,10 +31,10 @@ pub fn compute_abi_info(ccx: &CrateContext,
2 => ArgType::direct(rty, Some(Type::i16(ccx)), None, None), 2 => ArgType::direct(rty, Some(Type::i16(ccx)), None, None),
4 => ArgType::direct(rty, Some(Type::i32(ccx)), None, None), 4 => ArgType::direct(rty, Some(Type::i32(ccx)), None, None),
8 => ArgType::direct(rty, Some(Type::i64(ccx)), None, None), 8 => ArgType::direct(rty, Some(Type::i64(ccx)), None, None),
_ => ArgType::indirect(rty, Some(StructRetAttribute)) _ => ArgType::indirect(rty, Some(Attribute::StructRetAttribute))
}; };
} else { } else {
let attr = if rty == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if rty == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ret_ty = ArgType::direct(rty, None, None, attr); ret_ty = ArgType::direct(rty, None, None, attr);
} }
@ -46,11 +46,11 @@ pub fn compute_abi_info(ccx: &CrateContext,
2 => ArgType::direct(rty, Some(Type::i16(ccx)), None, None), 2 => ArgType::direct(rty, Some(Type::i16(ccx)), None, None),
4 => ArgType::direct(rty, Some(Type::i32(ccx)), None, None), 4 => ArgType::direct(rty, Some(Type::i32(ccx)), None, None),
8 => ArgType::direct(rty, Some(Type::i64(ccx)), None, None), 8 => ArgType::direct(rty, Some(Type::i64(ccx)), None, None),
_ => ArgType::indirect(t, Some(ByValAttribute)) _ => ArgType::indirect(t, Some(Attribute::ByValAttribute))
} }
} }
_ => { _ => {
let attr = if t == Type::i1(ccx) { Some(ZExtAttribute) } else { None }; let attr = if t == Type::i1(ccx) { Some(Attribute::ZExtAttribute) } else { None };
ArgType::direct(t, None, None, attr) ArgType::direct(t, None, None, attr)
} }
}; };

View file

@ -186,7 +186,7 @@ fn get_const_val(ccx: &CrateContext,
ref_expr: &ast::Expr) -> ValueRef { ref_expr: &ast::Expr) -> ValueRef {
let expr = get_const_expr(ccx, def_id, ref_expr); let expr = get_const_expr(ccx, def_id, ref_expr);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
get_const_expr_as_global(ccx, expr, check_const::PURE_CONST, empty_substs) get_const_expr_as_global(ccx, expr, check_const::ConstQualif::PURE_CONST, empty_substs)
} }
pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@ -215,7 +215,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
Some(&val) => return val, Some(&val) => return val,
None => {} None => {}
} }
let val = if qualif.intersects(check_const::NON_STATIC_BORROWS) { let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
// Avoid autorefs as they would create global instead of stack // Avoid autorefs as they would create global instead of stack
// references, even when only the latter are correct. // references, even when only the latter are correct.
let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs, let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,

View file

@ -71,12 +71,12 @@ pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty:
llvm::SetUnnamedAddr(llfn, true); llvm::SetUnnamedAddr(llfn, true);
if output == ty::FnDiverging { if output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturnAttribute);
} }
if ccx.tcx().sess.opts.cg.no_redzone if ccx.tcx().sess.opts.cg.no_redzone
.unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZoneAttribute)
} }
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {

View file

@ -126,8 +126,11 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap(); let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) { if !qualif.intersects(
if !qualif.intersects(check_const::PREFER_IN_PLACE) { check_const::ConstQualif::NOT_CONST |
check_const::ConstQualif::NEEDS_DROP
) {
if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
if let SaveIn(lldest) = dest { if let SaveIn(lldest) = dest {
let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs); bcx.fcx.param_substs);
@ -209,12 +212,15 @@ pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let mut bcx = bcx; let mut bcx = bcx;
let fcx = bcx.fcx; let fcx = bcx.fcx;
let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap(); let qualif = *bcx.tcx().const_qualif_map.borrow().get(&expr.id).unwrap();
let adjusted_global = !qualif.intersects(check_const::NON_STATIC_BORROWS); let adjusted_global = !qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS);
let global = if !qualif.intersects(check_const::NOT_CONST | check_const::NEEDS_DROP) { let global = if !qualif.intersects(
check_const::ConstQualif::NOT_CONST |
check_const::ConstQualif::NEEDS_DROP
) {
let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif, let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
bcx.fcx.param_substs); bcx.fcx.param_substs);
if qualif.intersects(check_const::HAS_STATIC_BORROWS) { if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
// Is borrowed as 'static, must return lvalue. // Is borrowed as 'static, must return lvalue.
// Cast pointer to global, because constants have different types. // Cast pointer to global, because constants have different types.

View file

@ -349,8 +349,8 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// The outptr can be noalias and nocapture because it's entirely // The outptr can be noalias and nocapture because it's entirely
// invisible to the program. We also know it's nonnull as well // invisible to the program. We also know it's nonnull as well
// as how many bytes we can dereference // as how many bytes we can dereference
attrs.arg(1, llvm::NoAliasAttribute) attrs.arg(1, llvm::Attribute::NoAliasAttribute)
.arg(1, llvm::NoCaptureAttribute) .arg(1, llvm::Attribute::NoCaptureAttribute)
.arg(1, llvm::DereferenceableAttribute(llret_sz)); .arg(1, llvm::DereferenceableAttribute(llret_sz));
}; };

View file

@ -107,26 +107,27 @@
#![doc(test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] #![doc(test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
#![feature(alloc)] #![feature(alloc)]
#![feature(allow_internal_unstable)]
#![feature(associated_consts)]
#![feature(box_syntax)] #![feature(box_syntax)]
#![feature(collections)] #![feature(collections)]
#![feature(core)] #![feature(core)]
#![feature(debug_builders)]
#![feature(into_cow)]
#![feature(lang_items)] #![feature(lang_items)]
#![feature(libc)] #![feature(libc)]
#![feature(linkage, thread_local, asm)] #![feature(linkage, thread_local, asm)]
#![feature(macro_reexport)]
#![feature(optin_builtin_traits)] #![feature(optin_builtin_traits)]
#![feature(rand)] #![feature(rand)]
#![feature(slice_patterns)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(std_misc)]
#![feature(str_char)]
#![feature(unboxed_closures)] #![feature(unboxed_closures)]
#![feature(unicode)] #![feature(unicode)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(macro_reexport)]
#![feature(unique)] #![feature(unique)]
#![feature(allow_internal_unstable)] #![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(str_char)]
#![feature(into_cow)]
#![feature(std_misc)]
#![feature(slice_patterns)]
#![feature(debug_builders)]
#![feature(zero_one)] #![feature(zero_one)]
#![cfg_attr(test, feature(float_from_str_radix))] #![cfg_attr(test, feature(float_from_str_radix))]
#![cfg_attr(test, feature(test, rustc_private, std_misc))] #![cfg_attr(test, feature(test, rustc_private, std_misc))]

View file

@ -25,13 +25,14 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/nightly/")] html_root_url = "http://doc.rust-lang.org/nightly/")]
#![feature(associated_consts)]
#![feature(collections)] #![feature(collections)]
#![feature(core)] #![feature(core)]
#![feature(libc)] #![feature(libc)]
#![feature(rustc_private)] #![feature(rustc_private)]
#![feature(staged_api)] #![feature(staged_api)]
#![feature(unicode)]
#![feature(str_char)] #![feature(str_char)]
#![feature(unicode)]
extern crate arena; extern crate arena;
extern crate fmt_macros; extern crate fmt_macros;

View file

@ -88,9 +88,9 @@ use std::slice;
bitflags! { bitflags! {
flags Restrictions: u8 { flags Restrictions: u8 {
const UNRESTRICTED = 0b0000, const UNRESTRICTED = 0,
const RESTRICTION_STMT_EXPR = 0b0001, const RESTRICTION_STMT_EXPR = 1 << 0,
const RESTRICTION_NO_STRUCT_LITERAL = 0b0010, const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
} }
} }
@ -339,7 +339,7 @@ impl<'a> Parser<'a> {
buffer_start: 0, buffer_start: 0,
buffer_end: 0, buffer_end: 0,
tokens_consumed: 0, tokens_consumed: 0,
restrictions: UNRESTRICTED, restrictions: Restrictions::UNRESTRICTED,
quote_depth: 0, quote_depth: 0,
obsolete_set: HashSet::new(), obsolete_set: HashSet::new(),
mod_path_stack: Vec::new(), mod_path_stack: Vec::new(),
@ -2198,7 +2198,10 @@ impl<'a> Parser<'a> {
if self.check(&token::OpenDelim(token::Brace)) { if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited // This is a struct literal, unless we're prohibited
// from parsing struct literals here. // from parsing struct literals here.
if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) { let prohibited = self.restrictions.contains(
Restrictions::RESTRICTION_NO_STRUCT_LITERAL
);
if !prohibited {
// It's a struct literal. // It's a struct literal.
try!(self.bump()); try!(self.bump());
let mut fields = Vec::new(); let mut fields = Vec::new();
@ -2759,7 +2762,7 @@ impl<'a> Parser<'a> {
} }
pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> { pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> {
let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL;
let op_span = self.span; let op_span = self.span;
match self.token { match self.token {
token::Eq => { token::Eq => {
@ -2814,7 +2817,7 @@ impl<'a> Parser<'a> {
if self.token.can_begin_expr() { if self.token.can_begin_expr() {
// parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
if self.token == token::OpenDelim(token::Brace) { if self.token == token::OpenDelim(token::Brace) {
return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL); return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL);
} }
true true
} else { } else {
@ -2828,7 +2831,7 @@ impl<'a> Parser<'a> {
return self.parse_if_let_expr(); return self.parse_if_let_expr();
} }
let lo = self.last_span.lo; let lo = self.last_span.lo;
let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let thn = try!(self.parse_block()); let thn = try!(self.parse_block());
let mut els: Option<P<Expr>> = None; let mut els: Option<P<Expr>> = None;
let mut hi = thn.span.hi; let mut hi = thn.span.hi;
@ -2846,7 +2849,7 @@ impl<'a> Parser<'a> {
try!(self.expect_keyword(keywords::Let)); try!(self.expect_keyword(keywords::Let));
let pat = try!(self.parse_pat_nopanic()); let pat = try!(self.parse_pat_nopanic());
try!(self.expect(&token::Eq)); try!(self.expect(&token::Eq));
let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let thn = try!(self.parse_block()); let thn = try!(self.parse_block());
let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){ let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){
let expr = try!(self.parse_else_expr()); let expr = try!(self.parse_else_expr());
@ -2905,7 +2908,7 @@ impl<'a> Parser<'a> {
let lo = self.last_span.lo; let lo = self.last_span.lo;
let pat = try!(self.parse_pat_nopanic()); let pat = try!(self.parse_pat_nopanic());
try!(self.expect_keyword(keywords::In)); try!(self.expect_keyword(keywords::In));
let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let loop_block = try!(self.parse_block()); let loop_block = try!(self.parse_block());
let hi = self.last_span.hi; let hi = self.last_span.hi;
@ -2918,7 +2921,7 @@ impl<'a> Parser<'a> {
return self.parse_while_let_expr(opt_ident); return self.parse_while_let_expr(opt_ident);
} }
let lo = self.last_span.lo; let lo = self.last_span.lo;
let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let body = try!(self.parse_block()); let body = try!(self.parse_block());
let hi = body.span.hi; let hi = body.span.hi;
return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident))); return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident)));
@ -2930,7 +2933,7 @@ impl<'a> Parser<'a> {
try!(self.expect_keyword(keywords::Let)); try!(self.expect_keyword(keywords::Let));
let pat = try!(self.parse_pat_nopanic()); let pat = try!(self.parse_pat_nopanic());
try!(self.expect(&token::Eq)); try!(self.expect(&token::Eq));
let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let body = try!(self.parse_block()); let body = try!(self.parse_block());
let hi = body.span.hi; let hi = body.span.hi;
return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident))); return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident)));
@ -2945,7 +2948,7 @@ impl<'a> Parser<'a> {
fn parse_match_expr(&mut self) -> PResult<P<Expr>> { fn parse_match_expr(&mut self) -> PResult<P<Expr>> {
let lo = self.last_span.lo; let lo = self.last_span.lo;
let discriminant = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace))); try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace)));
let mut arms: Vec<Arm> = Vec::new(); let mut arms: Vec<Arm> = Vec::new();
while self.token != token::CloseDelim(token::Brace) { while self.token != token::CloseDelim(token::Brace) {
@ -2966,7 +2969,7 @@ impl<'a> Parser<'a> {
guard = Some(try!(self.parse_expr_nopanic())); guard = Some(try!(self.parse_expr_nopanic()));
} }
try!(self.expect(&token::FatArrow)); try!(self.expect(&token::FatArrow));
let expr = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
let require_comma = let require_comma =
!classify::expr_is_simple_block(&*expr) !classify::expr_is_simple_block(&*expr)
@ -2988,7 +2991,7 @@ impl<'a> Parser<'a> {
/// Parse an expression /// Parse an expression
pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> { pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> {
return self.parse_expr_res(UNRESTRICTED); return self.parse_expr_res(Restrictions::UNRESTRICTED);
} }
/// Parse an expression, subject to the given restrictions /// Parse an expression, subject to the given restrictions
@ -3564,7 +3567,7 @@ impl<'a> Parser<'a> {
} }
// Remainder are line-expr stmts. // Remainder are line-expr stmts.
let e = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); let e = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR));
spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)) spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID))
} }
} }
@ -3573,7 +3576,7 @@ impl<'a> Parser<'a> {
/// Is this expression a successfully-parsed statement? /// Is this expression a successfully-parsed statement?
fn expr_is_complete(&mut self, e: &Expr) -> bool { fn expr_is_complete(&mut self, e: &Expr) -> bool {
self.restrictions.contains(RESTRICTION_STMT_EXPR) && self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) &&
!classify::expr_requires_semi_to_be_stmt(e) !classify::expr_requires_semi_to_be_stmt(e)
} }