rollup merge of #24921: tamird/bitflags-associated-const

Conflicts:
	src/librustc/lib.rs
This commit is contained in:
Alex Crichton 2015-04-29 15:49:07 -07:00
commit 2edb6438cb
24 changed files with 341 additions and 295 deletions

View file

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

View file

@ -46,33 +46,35 @@ bitflags! {
#[derive(RustcEncodable, RustcDecodable)]
flags ConstQualif: u8 {
// 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
// &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
// 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
// there is more expensive than in-place instantiation, and/or it may
// 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.
const PREFER_IN_PLACE = 0b000100,
const PREFER_IN_PLACE = 1 << 2,
// 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.
const NON_ZERO_SIZED = 0b001000,
const NON_ZERO_SIZED = 1 << 3,
// Actually borrowed, has to always be in static memory. Does not
// propagate, and requires the expression to behave like a 'static
// lvalue. The set of expressions with this flag is the minimum
// 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).
const NOT_CONST = 0b100000,
const NOT_CONST = 1 << 5,
// Borrowing the expression won't produce &'static T if any of these
// bits are set, though the value could be copied from static memory
// 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);
self.mode = mode;
self.qualif = PURE_CONST;
self.qualif = ConstQualif::PURE_CONST;
let r = f(self);
self.mode = old_mode;
self.qualif = old_qualif;
@ -126,7 +128,7 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
Entry::Occupied(entry) => return *entry.get(),
Entry::Vacant(entry) => {
// Prevent infinite recursion on re-entry.
entry.insert(PURE_CONST);
entry.insert(ConstQualif::PURE_CONST);
}
}
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) {
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);
check_expr(self, ex, node_ty);
@ -287,7 +289,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
self.visit_expr(&**callee);
// The callee's size doesn't count in the call.
let added = self.qualif - inner;
self.qualif = inner | (added - NON_ZERO_SIZED);
self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
}
ast::ExprRepeat(ref 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.
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, _) => {
@ -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;
match node_ty.sty {
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) {
Ok(_) => {}
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
// it means that our "silent insertion of statics" could change
// 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.
let tc = ty::type_contents(self.tcx, node_ty);
if self.qualif.intersects(MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | NOT_CONST;
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | ConstQualif::NOT_CONST;
if self.mode != Mode::Var {
self.tcx.sess.span_err(ex.span,
"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
// as that will end up pointing to the stack instead.
if !self.qualif.intersects(NON_STATIC_BORROWS) {
self.qualif = self.qualif - PREFER_IN_PLACE;
self.add_qualif(HAS_STATIC_BORROWS);
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
Some(ast::MutMutable) => {
// `&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 {
outer = outer | NOT_CONST;
self.add_qualif(MUTABLE_MEM);
outer = outer | ConstQualif::NOT_CONST;
self.add_qualif(ConstQualif::MUTABLE_MEM);
} else {
span_err!(self.tcx.sess, ex.span, E0017,
"references in {}s may only refer \
to immutable values", self.msg())
}
}
if !self.qualif.intersects(NON_STATIC_BORROWS) {
self.add_qualif(HAS_STATIC_BORROWS);
if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
}
}
None => {}
}
self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
// 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 {
ty::ty_struct(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 {
v.tcx.sess.span_err(e.span,
&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::ExprBinary(..) |
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 {
span_err!(v.tcx.sess, e.span, E0011,
"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::ExprUnary(ast::UnUniq, _) => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0010,
"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 {
ty::ty_ptr(_) => {
// 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_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
if !is_legal_cast {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0012,
"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) {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0018,
"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 {
Some(def::DefVariant(_, _, _)) => {
// Count the discriminator or function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStruct(_)) => {
if let ty::ty_bare_fn(..) = node_ty.sty {
// Count the function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
}
Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
// Count the function pointer.
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
Some(def::DefStatic(..)) => {
match v.mode {
@ -487,7 +489,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
"constants cannot refer to other statics, \
insert an intermediate constant instead");
}
Mode::Var => v.add_qualif(NOT_CONST)
Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
}
}
Some(def::DefConst(did)) |
@ -503,7 +505,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
}
}
def => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
debug!("(checking const) found bad def: {:?}", def);
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::DefVariant(..)) => {
// 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 {
span_err!(v.tcx.sess, e.span, E0015,
"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) => {
// Check all statements in the block
let mut block_span_err = |span| {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, span, E0016,
"blocks in {}s are limited to items and \
@ -574,17 +576,17 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
ast::ExprStruct(..) => {
let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
if did == v.tcx.lang_items.unsafe_cell_type() {
v.add_qualif(MUTABLE_MEM);
v.add_qualif(ConstQualif::MUTABLE_MEM);
}
}
ast::ExprLit(_) |
ast::ExprAddrOf(..) => {
v.add_qualif(NON_ZERO_SIZED);
v.add_qualif(ConstQualif::NON_ZERO_SIZED);
}
ast::ExprRepeat(..) => {
v.add_qualif(PREFER_IN_PLACE);
v.add_qualif(ConstQualif::PREFER_IN_PLACE);
}
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()) {
assert!(v.mode == Mode::Var,
"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::ExprInlineAsm(_) |
ast::ExprMac(_) => {
v.add_qualif(NOT_CONST);
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0019,
"{} contains unimplemented expression type", v.msg());
@ -644,7 +646,7 @@ pub fn check_crate(tcx: &ty::ctxt) {
visit::walk_crate(&mut CheckCrateVisitor {
tcx: tcx,
mode: Mode::Var,
qualif: NOT_CONST,
qualif: ConstQualif::NOT_CONST,
rvalue_borrows: NodeMap()
}, tcx.map.krate());

View file

@ -838,20 +838,20 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
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
// is accepted.
let qualif = match expr_ty.sty {
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
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
let re = match qualif & check_const::NON_STATIC_BORROWS {
check_const::PURE_CONST => ty::ReStatic,
let re = match qualif & check_const::ConstQualif::NON_STATIC_BORROWS {
check_const::ConstQualif::PURE_CONST => ty::ReStatic,
_ => self.temporary_scope(id),
};
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.
bitflags! {
flags TypeFlags: u32 {
const NO_TYPE_FLAGS = 0b0,
const HAS_PARAMS = 0b1,
const HAS_SELF = 0b10,
const HAS_TY_INFER = 0b100,
const HAS_RE_INFER = 0b1000,
const HAS_RE_LATE_BOUND = 0b10000,
const HAS_REGIONS = 0b100000,
const HAS_TY_ERR = 0b1000000,
const HAS_PROJECTION = 0b10000000,
const NEEDS_SUBST = HAS_PARAMS.bits | HAS_SELF.bits | HAS_REGIONS.bits,
const NO_TYPE_FLAGS = 0,
const HAS_PARAMS = 1 << 0,
const HAS_SELF = 1 << 1,
const HAS_TY_INFER = 1 << 2,
const HAS_RE_INFER = 1 << 3,
const HAS_RE_LATE_BOUND = 1 << 4,
const HAS_REGIONS = 1 << 5,
const HAS_TY_ERR = 1 << 6,
const HAS_PROJECTION = 1 << 7,
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::$variant(..) => &mut $variant,)*
};
let region = t.flags.intersects(ty::HAS_RE_INFER);
let ty = t.flags.intersects(ty::HAS_TY_INFER);
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
variant.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 {
ty.flags.intersects(HAS_PARAMS)
ty.flags.intersects(TypeFlags::HAS_PARAMS)
}
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 {
ty.flags.intersects(HAS_TY_INFER)
ty.flags.intersects(TypeFlags::HAS_TY_INFER)
}
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 {
ty.flags.intersects(HAS_PROJECTION)
ty.flags.intersects(TypeFlags::HAS_PROJECTION)
}
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`.
@ -2810,7 +2812,7 @@ struct FlagComputation {
impl 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 {
@ -2855,20 +2857,20 @@ impl FlagComputation {
// You might think that we could just return ty_err for
// 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).
// But doing so caused sporadic memory corruption, and
// neither I (tjc) nor nmatsakis could figure out why,
// so we're doing it this way.
&ty_err => {
self.add_flags(HAS_TY_ERR)
self.add_flags(TypeFlags::HAS_TY_ERR)
}
&ty_param(ref p) => {
if p.space == subst::SelfSpace {
self.add_flags(HAS_SELF);
self.add_flags(TypeFlags::HAS_SELF);
} else {
self.add_flags(HAS_PARAMS);
self.add_flags(TypeFlags::HAS_PARAMS);
}
}
@ -2877,7 +2879,7 @@ impl FlagComputation {
}
&ty_infer(_) => {
self.add_flags(HAS_TY_INFER)
self.add_flags(TypeFlags::HAS_TY_INFER)
}
&ty_enum(_, substs) | &ty_struct(_, substs) => {
@ -2885,7 +2887,7 @@ impl FlagComputation {
}
&ty_projection(ref data) => {
self.add_flags(HAS_PROJECTION);
self.add_flags(TypeFlags::HAS_PROJECTION);
self.add_projection_ty(data);
}
@ -2949,11 +2951,11 @@ impl FlagComputation {
}
fn add_region(&mut self, r: Region) {
self.add_flags(HAS_REGIONS);
self.add_flags(TypeFlags::HAS_REGIONS);
match r {
ty::ReInfer(_) => { self.add_flags(HAS_RE_INFER); }
ty::ReInfer(_) => { self.add_flags(TypeFlags::HAS_RE_INFER); }
ty::ReLateBound(debruijn, _) => {
self.add_flags(HAS_RE_LATE_BOUND);
self.add_flags(TypeFlags::HAS_RE_LATE_BOUND);
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 {
ty.flags.intersects(HAS_TY_ERR)
ty.flags.intersects(TypeFlags::HAS_TY_ERR)
}
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 {