<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use back::{upcall};
use driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
use lib::llvm::{mk_target_data, False};
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
use middle::trans::common::{C_i32, C_null};
use middle::ty;

use middle::trans::type_::Type;

use std::c_str::ToCStr;
use std::hash;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
use std::vec;
use std::libc::c_uint;
use syntax::ast;

use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};

use middle::trans::base::{decl_crate_map};

pub struct CrateContext {
     sess: session::Session,
     llmod: ModuleRef,
     llcx: ContextRef,
     td: TargetData,
     tn: TypeNames,
     externs: ExternMap,
     intrinsics: HashMap<&'static str, ValueRef>,
     item_vals: HashMap<ast::NodeId, ValueRef>,
     exp_map2: resolve::ExportMap2,
     reachable: @mut HashSet<ast::NodeId>,
     item_symbols: HashMap<ast::NodeId, ~str>,
     link_meta: LinkMeta,
     enum_sizes: HashMap<ty::t, uint>,
     discrims: HashMap<ast::def_id, ValueRef>,
     discrim_symbols: HashMap<ast::NodeId, @str>,
     tydescs: HashMap<ty::t, @mut tydesc_info>,
     // Set when running emit_tydescs to enforce that no more tydescs are
     // created.
     finished_tydescs: bool,
     // Track mapping of external ids to local items imported for inlining
     external: HashMap<ast::def_id, Option<ast::NodeId>>,
     // Cache instances of monomorphized functions
     monomorphized: HashMap<mono_id, ValueRef>,
     monomorphizing: HashMap<ast::def_id, uint>,
     // Cache computed type parameter uses (see type_use.rs)
     type_use_cache: HashMap<ast::def_id, @~[type_use::type_uses]>,
     // Cache generated vtables
     vtables: HashMap<mono_id, ValueRef>,
     // Cache of constant strings,
     const_cstr_cache: HashMap<@str, ValueRef>,

     // Reverse-direction for const ptrs cast from globals.
     // Key is an int, cast from a ValueRef holding a *T,
     // Val is a ValueRef holding a *[T].
     //
     // Needed because LLVM loses pointer->pointee association
     // when we ptrcast, and we have to ptrcast during translation
     // of a [T] const because we form a slice, a [*T,int] pair, not
     // a pointer to an LLVM array type.
     const_globals: HashMap<int, ValueRef>,

     // Cache of emitted const values
     const_values: HashMap<ast::NodeId, ValueRef>,

     // Cache of external const values
     extern_const_values: HashMap<ast::def_id, ValueRef>,

     impl_method_cache: HashMap<(ast::def_id, ast::ident), ast::def_id>,

     module_data: HashMap<~str, ValueRef>,
     lltypes: HashMap<ty::t, Type>,
     llsizingtypes: HashMap<ty::t, Type>,
     adt_reprs: HashMap<ty::t, @adt::Repr>,
     symbol_hasher: hash::State,
     type_hashcodes: HashMap<ty::t, @str>,
     type_short_names: HashMap<ty::t, ~str>,
     all_llvm_symbols: HashSet<@str>,
     tcx: ty::ctxt,
     maps: astencode::Maps,
     stats: @mut Stats,
     upcalls: @upcall::Upcalls,
     tydesc_type: Type,
     int_type: Type,
     float_type: Type,
     opaque_vec_type: Type,
     builder: BuilderRef_res,
     crate_map: ValueRef,
     // Set when at least one function uses GC. Needed so that
     // decl_gc_metadata knows whether to link to the module metadata, which
     // is not emitted by LLVM's GC pass when no functions use GC.
     uses_gc: bool,
     dbg_cx: Option<debuginfo::DebugContext>,
     do_not_commit_warning_issued: bool
}

impl CrateContext {
    pub fn new(sess: session::Session,
               name: &str,
               tcx: ty::ctxt,
               emap2: resolve::ExportMap2,
               maps: astencode::Maps,
               symbol_hasher: hash::State,
               link_meta: LinkMeta,
               reachable: @mut HashSet<ast::NodeId>)
               -> CrateContext {
        unsafe {
            let llcx = llvm::LLVMContextCreate();
            set_task_llcx(llcx);
            let llmod = do name.to_c_str().with_ref |buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            };
            let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
            let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
            do data_layout.to_c_str().with_ref |buf| {
                llvm::LLVMSetDataLayout(llmod, buf)
            };
            do targ_triple.to_c_str().with_ref |buf| {
                llvm::LLVMSetTarget(llmod, buf)
            };
            let targ_cfg = sess.targ_cfg;

            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
            let mut tn = TypeNames::new();

            let mut intrinsics = base::declare_intrinsics(llmod);
            if sess.opts.extra_debuginfo {
                base::declare_dbg_intrinsics(llmod, &mut intrinsics);
            }
            let int_type = Type::int(targ_cfg.arch);
            let float_type = Type::float(targ_cfg.arch);
            let tydesc_type = Type::tydesc(targ_cfg.arch);
            let opaque_vec_type = Type::opaque_vec(targ_cfg.arch);

            let mut str_slice_ty = Type::named_struct("str_slice");
            str_slice_ty.set_struct_body([Type::i8p(), int_type], false);

            tn.associate_type("tydesc", &tydesc_type);
            tn.associate_type("str_slice", &str_slice_ty);

            let crate_map = decl_crate_map(sess, link_meta, llmod);
            let dbg_cx = if sess.opts.debuginfo {
                Some(debuginfo::DebugContext::new(llmod, name.to_owned()))
            } else {
                None
            };

            if sess.count_llvm_insns() {
                base::init_insn_ctxt()
            }

            CrateContext {
                  sess: sess,
                  llmod: llmod,
                  llcx: llcx,
                  td: td,
                  tn: tn,
                  externs: HashMap::new(),
                  intrinsics: intrinsics,
                  item_vals: HashMap::new(),
                  exp_map2: emap2,
                  reachable: reachable,
                  item_symbols: HashMap::new(),
                  link_meta: link_meta,
                  enum_sizes: HashMap::new(),
                  discrims: HashMap::new(),
                  discrim_symbols: HashMap::new(),
                  tydescs: HashMap::new(),
                  finished_tydescs: false,
                  external: HashMap::new(),
                  monomorphized: HashMap::new(),
                  monomorphizing: HashMap::new(),
                  type_use_cache: HashMap::new(),
                  vtables: HashMap::new(),
                  const_cstr_cache: HashMap::new(),
                  const_globals: HashMap::new(),
                  const_values: HashMap::new(),
                  extern_const_values: HashMap::new(),
                  impl_method_cache: HashMap::new(),
                  module_data: HashMap::new(),
                  lltypes: HashMap::new(),
                  llsizingtypes: HashMap::new(),
                  adt_reprs: HashMap::new(),
                  symbol_hasher: symbol_hasher,
                  type_hashcodes: HashMap::new(),
                  type_short_names: HashMap::new(),
                  all_llvm_symbols: HashSet::new(),
                  tcx: tcx,
                  maps: maps,
                  stats: @mut Stats {
                    n_static_tydescs: 0u,
                    n_glues_created: 0u,
                    n_null_glues: 0u,
                    n_real_glues: 0u,
                    n_fns: 0u,
                    n_monos: 0u,
                    n_inlines: 0u,
                    n_closures: 0u,
                    n_llvm_insns: 0u,
                    llvm_insn_ctxt: ~[],
                    llvm_insns: HashMap::new(),
                    fn_stats: ~[]
                  },
                  upcalls: upcall::declare_upcalls(targ_cfg, llmod),
                  tydesc_type: tydesc_type,
                  int_type: int_type,
                  float_type: float_type,
                  opaque_vec_type: opaque_vec_type,
                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                  crate_map: crate_map,
                  uses_gc: false,
                  dbg_cx: dbg_cx,
                  do_not_commit_warning_issued: false
            }
        }
    }

    pub fn builder(@mut self) -> Builder {
        Builder::new(self)
    }

    pub fn const_inbounds_gepi(&self,
                               pointer: ValueRef,
                               indices: &[uint]) -> ValueRef {
        debug!("const_inbounds_gepi: pointer=%s indices=%?",
               self.tn.val_to_str(pointer), indices);
        let v: ~[ValueRef] =
            indices.iter().transform(|i| C_i32(*i as i32)).collect();
        unsafe {
            llvm::LLVMConstInBoundsGEP(pointer,
                                       vec::raw::to_ptr(v),
                                       indices.len() as c_uint)
        }
    }

    pub fn offsetof_gep(&self,
                        llptr_ty: Type,
                        indices: &[uint]) -> ValueRef {
        /*!
         * Returns the offset of applying the given GEP indices
         * to an instance of `llptr_ty`. Similar to `offsetof` in C,
         * except that `llptr_ty` must be a pointer type.
         */

        unsafe {
            let null = C_null(llptr_ty);
            llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
                                    self.int_type.to_ref())
        }
    }
}

#[unsafe_destructor]
impl Drop for CrateContext {
    fn drop(&self) {
        unset_task_llcx();
    }
}

static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;

pub fn task_llcx() -> ContextRef {
    let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
    *opt.expect("task-local LLVMContextRef wasn't ever set!")
}

fn set_task_llcx(c: ContextRef) {
    local_data::set(task_local_llcx_key, @c);
}

fn unset_task_llcx() {
    local_data::pop(task_local_llcx_key);
}
<commit_msg>Convert from transform to map<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use back::{upcall};
use driver::session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};
use lib::llvm::{mk_target_data, False};
use metadata::common::LinkMeta;
use middle::astencode;
use middle::resolve;
use middle::trans::adt;
use middle::trans::base;
use middle::trans::builder::Builder;
use middle::trans::debuginfo;
use middle::trans::type_use;
use middle::trans::common::{C_i32, C_null};
use middle::ty;

use middle::trans::type_::Type;

use std::c_str::ToCStr;
use std::hash;
use std::hashmap::{HashMap, HashSet};
use std::local_data;
use std::vec;
use std::libc::c_uint;
use syntax::ast;

use middle::trans::common::{mono_id,ExternMap,tydesc_info,BuilderRef_res,Stats};

use middle::trans::base::{decl_crate_map};

pub struct CrateContext {
     sess: session::Session,
     llmod: ModuleRef,
     llcx: ContextRef,
     td: TargetData,
     tn: TypeNames,
     externs: ExternMap,
     intrinsics: HashMap<&'static str, ValueRef>,
     item_vals: HashMap<ast::NodeId, ValueRef>,
     exp_map2: resolve::ExportMap2,
     reachable: @mut HashSet<ast::NodeId>,
     item_symbols: HashMap<ast::NodeId, ~str>,
     link_meta: LinkMeta,
     enum_sizes: HashMap<ty::t, uint>,
     discrims: HashMap<ast::def_id, ValueRef>,
     discrim_symbols: HashMap<ast::NodeId, @str>,
     tydescs: HashMap<ty::t, @mut tydesc_info>,
     // Set when running emit_tydescs to enforce that no more tydescs are
     // created.
     finished_tydescs: bool,
     // Track mapping of external ids to local items imported for inlining
     external: HashMap<ast::def_id, Option<ast::NodeId>>,
     // Cache instances of monomorphized functions
     monomorphized: HashMap<mono_id, ValueRef>,
     monomorphizing: HashMap<ast::def_id, uint>,
     // Cache computed type parameter uses (see type_use.rs)
     type_use_cache: HashMap<ast::def_id, @~[type_use::type_uses]>,
     // Cache generated vtables
     vtables: HashMap<mono_id, ValueRef>,
     // Cache of constant strings,
     const_cstr_cache: HashMap<@str, ValueRef>,

     // Reverse-direction for const ptrs cast from globals.
     // Key is an int, cast from a ValueRef holding a *T,
     // Val is a ValueRef holding a *[T].
     //
     // Needed because LLVM loses pointer->pointee association
     // when we ptrcast, and we have to ptrcast during translation
     // of a [T] const because we form a slice, a [*T,int] pair, not
     // a pointer to an LLVM array type.
     const_globals: HashMap<int, ValueRef>,

     // Cache of emitted const values
     const_values: HashMap<ast::NodeId, ValueRef>,

     // Cache of external const values
     extern_const_values: HashMap<ast::def_id, ValueRef>,

     impl_method_cache: HashMap<(ast::def_id, ast::ident), ast::def_id>,

     module_data: HashMap<~str, ValueRef>,
     lltypes: HashMap<ty::t, Type>,
     llsizingtypes: HashMap<ty::t, Type>,
     adt_reprs: HashMap<ty::t, @adt::Repr>,
     symbol_hasher: hash::State,
     type_hashcodes: HashMap<ty::t, @str>,
     type_short_names: HashMap<ty::t, ~str>,
     all_llvm_symbols: HashSet<@str>,
     tcx: ty::ctxt,
     maps: astencode::Maps,
     stats: @mut Stats,
     upcalls: @upcall::Upcalls,
     tydesc_type: Type,
     int_type: Type,
     float_type: Type,
     opaque_vec_type: Type,
     builder: BuilderRef_res,
     crate_map: ValueRef,
     // Set when at least one function uses GC. Needed so that
     // decl_gc_metadata knows whether to link to the module metadata, which
     // is not emitted by LLVM's GC pass when no functions use GC.
     uses_gc: bool,
     dbg_cx: Option<debuginfo::DebugContext>,
     do_not_commit_warning_issued: bool
}

impl CrateContext {
    pub fn new(sess: session::Session,
               name: &str,
               tcx: ty::ctxt,
               emap2: resolve::ExportMap2,
               maps: astencode::Maps,
               symbol_hasher: hash::State,
               link_meta: LinkMeta,
               reachable: @mut HashSet<ast::NodeId>)
               -> CrateContext {
        unsafe {
            let llcx = llvm::LLVMContextCreate();
            set_task_llcx(llcx);
            let llmod = do name.to_c_str().with_ref |buf| {
                llvm::LLVMModuleCreateWithNameInContext(buf, llcx)
            };
            let data_layout: &str = sess.targ_cfg.target_strs.data_layout;
            let targ_triple: &str = sess.targ_cfg.target_strs.target_triple;
            do data_layout.to_c_str().with_ref |buf| {
                llvm::LLVMSetDataLayout(llmod, buf)
            };
            do targ_triple.to_c_str().with_ref |buf| {
                llvm::LLVMSetTarget(llmod, buf)
            };
            let targ_cfg = sess.targ_cfg;

            let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
            let mut tn = TypeNames::new();

            let mut intrinsics = base::declare_intrinsics(llmod);
            if sess.opts.extra_debuginfo {
                base::declare_dbg_intrinsics(llmod, &mut intrinsics);
            }
            let int_type = Type::int(targ_cfg.arch);
            let float_type = Type::float(targ_cfg.arch);
            let tydesc_type = Type::tydesc(targ_cfg.arch);
            let opaque_vec_type = Type::opaque_vec(targ_cfg.arch);

            let mut str_slice_ty = Type::named_struct("str_slice");
            str_slice_ty.set_struct_body([Type::i8p(), int_type], false);

            tn.associate_type("tydesc", &tydesc_type);
            tn.associate_type("str_slice", &str_slice_ty);

            let crate_map = decl_crate_map(sess, link_meta, llmod);
            let dbg_cx = if sess.opts.debuginfo {
                Some(debuginfo::DebugContext::new(llmod, name.to_owned()))
            } else {
                None
            };

            if sess.count_llvm_insns() {
                base::init_insn_ctxt()
            }

            CrateContext {
                  sess: sess,
                  llmod: llmod,
                  llcx: llcx,
                  td: td,
                  tn: tn,
                  externs: HashMap::new(),
                  intrinsics: intrinsics,
                  item_vals: HashMap::new(),
                  exp_map2: emap2,
                  reachable: reachable,
                  item_symbols: HashMap::new(),
                  link_meta: link_meta,
                  enum_sizes: HashMap::new(),
                  discrims: HashMap::new(),
                  discrim_symbols: HashMap::new(),
                  tydescs: HashMap::new(),
                  finished_tydescs: false,
                  external: HashMap::new(),
                  monomorphized: HashMap::new(),
                  monomorphizing: HashMap::new(),
                  type_use_cache: HashMap::new(),
                  vtables: HashMap::new(),
                  const_cstr_cache: HashMap::new(),
                  const_globals: HashMap::new(),
                  const_values: HashMap::new(),
                  extern_const_values: HashMap::new(),
                  impl_method_cache: HashMap::new(),
                  module_data: HashMap::new(),
                  lltypes: HashMap::new(),
                  llsizingtypes: HashMap::new(),
                  adt_reprs: HashMap::new(),
                  symbol_hasher: symbol_hasher,
                  type_hashcodes: HashMap::new(),
                  type_short_names: HashMap::new(),
                  all_llvm_symbols: HashSet::new(),
                  tcx: tcx,
                  maps: maps,
                  stats: @mut Stats {
                    n_static_tydescs: 0u,
                    n_glues_created: 0u,
                    n_null_glues: 0u,
                    n_real_glues: 0u,
                    n_fns: 0u,
                    n_monos: 0u,
                    n_inlines: 0u,
                    n_closures: 0u,
                    n_llvm_insns: 0u,
                    llvm_insn_ctxt: ~[],
                    llvm_insns: HashMap::new(),
                    fn_stats: ~[]
                  },
                  upcalls: upcall::declare_upcalls(targ_cfg, llmod),
                  tydesc_type: tydesc_type,
                  int_type: int_type,
                  float_type: float_type,
                  opaque_vec_type: opaque_vec_type,
                  builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
                  crate_map: crate_map,
                  uses_gc: false,
                  dbg_cx: dbg_cx,
                  do_not_commit_warning_issued: false
            }
        }
    }

    pub fn builder(@mut self) -> Builder {
        Builder::new(self)
    }

    pub fn const_inbounds_gepi(&self,
                               pointer: ValueRef,
                               indices: &[uint]) -> ValueRef {
        debug!("const_inbounds_gepi: pointer=%s indices=%?",
               self.tn.val_to_str(pointer), indices);
        let v: ~[ValueRef] =
            indices.iter().map(|i| C_i32(*i as i32)).collect();
        unsafe {
            llvm::LLVMConstInBoundsGEP(pointer,
                                       vec::raw::to_ptr(v),
                                       indices.len() as c_uint)
        }
    }

    pub fn offsetof_gep(&self,
                        llptr_ty: Type,
                        indices: &[uint]) -> ValueRef {
        /*!
         * Returns the offset of applying the given GEP indices
         * to an instance of `llptr_ty`. Similar to `offsetof` in C,
         * except that `llptr_ty` must be a pointer type.
         */

        unsafe {
            let null = C_null(llptr_ty);
            llvm::LLVMConstPtrToInt(self.const_inbounds_gepi(null, indices),
                                    self.int_type.to_ref())
        }
    }
}

#[unsafe_destructor]
impl Drop for CrateContext {
    fn drop(&self) {
        unset_task_llcx();
    }
}

static task_local_llcx_key: local_data::Key<@ContextRef> = &local_data::Key;

pub fn task_llcx() -> ContextRef {
    let opt = local_data::get(task_local_llcx_key, |k| k.map_move(|k| *k));
    *opt.expect("task-local LLVMContextRef wasn't ever set!")
}

fn set_task_llcx(c: ContextRef) {
    local_data::set(task_local_llcx_key, @c);
}

fn unset_task_llcx() {
    local_data::pop(task_local_llcx_key);
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```compile_fail
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be
unsafe.

Another situation where this might be encountered is when spawning threads:

```compile_fail
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```compile_fail
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
}
```

To fix this, ensure that any declared variables are initialized before being
used. Example:

```
fn main() {
    let x: i32 = 0;
    let y = x; // ok!
}
```
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```compile_fail
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow().s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0383: r##"
This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized.

For example, this can happen when a drop has taken place:

```compile_fail
struct Foo {
    a: u32,
}

let mut x = Foo { a: 1 };
drop(x); // `x` is now uninitialized
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
```

This error can be fixed by fully reinitializing the structure in question:

```
struct Foo {
    a: u32,
}

let mut x = Foo { a: 1 };
drop(x);
x = Foo { a: 2 };
```
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```compile_fail
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.

For example, this can happen when storing a `&mut` inside an immutable `Box`:

```compile_fail
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
```

This error can be fixed by making the container mutable:

```
let mut x: i64 = 1;
let mut y: Box<_> = Box::new(&mut x);
**y = 2;
```

It can also be fixed by using a type with interior mutability, such as `Cell`
or `RefCell`:

```
use std::cell::Cell;

let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```compile_fail
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data. Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable`
function could be redefined as below:

```
use std::cell::Cell;

fn foo<F: Fn()>(f: F) { }

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##,

E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:

```compile_fail
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
// error: cannot borrow `i` as mutable more than once at a time
```

Please note that in rust, you can either have many immutable references, or one
mutable reference. Take a look at
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
information. Example:

```
let mut i = 0;
let mut x = &mut i; // ok!

// or:
let mut i = 0;
let a = &i; // ok!
let b = &i; // still ok!
let c = &i; // still ok!
```
"##,

E0507: r##"
You tried to move out of a value which was borrowed. Erroneous code example:

```compile_fail
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
```

Here, the `nothing_is_true` method takes the ownership of `self`. However,
`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
which is a borrow of the content owned by the `RefCell`. To fix this error,
you have three choices:

* Try to avoid moving the variable.
* Somehow reclaim the ownership.
* Implement the `Copy` trait on the type.

Examples:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(&self) {} // First case, we don't take ownership
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);
    let x = x.into_inner(); // we get back ownership

    x.nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

#[derive(Clone, Copy)] // we implement the Copy trait
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Moving out of a member of a mutably borrowed struct is fine if you put something
back. `mem::replace` can be used for that:

```ignore
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

struct Batcave {
    knight: TheDarkKnight
}

fn main() {
    use std::mem;

    let mut cave = Batcave {
        knight: TheDarkKnight
    };
    let borrowed = &mut cave;

    borrowed.knight.nothing_is_true(); // E0507
    mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
}
```

You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

}

register_diagnostics! {
    E0385, // {} in an aliasable location
    E0388, // {} in a static location
    E0389, // {} in a `&` reference
    E0500, // closure requires unique access to `..` but .. is already borrowed
    E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
    E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
    E0503, // cannot use `..` because it was mutably borrowed
    E0504, // cannot move `..` into closure because it is borrowed
    E0505, // cannot move out of `..` because it is borrowed
    E0506, // cannot assign to `..` because it is borrowed
    E0508, // cannot move out of type `..`, a non-copy fixed-size array
    E0509, // cannot move out of type `..`, which defines the `Drop` trait
    E0524, // two closures require unique access to `..` at the same time
}
<commit_msg>Add detailed error explanation for E0389<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```compile_fail
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be
unsafe.

Another situation where this might be encountered is when spawning threads:

```compile_fail
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```compile_fail
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
}
```

To fix this, ensure that any declared variables are initialized before being
used. Example:

```
fn main() {
    let x: i32 = 0;
    let y = x; // ok!
}
```
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```compile_fail
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow().s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0383: r##"
This error occurs when an attempt is made to partially reinitialize a
structure that is currently uninitialized.

For example, this can happen when a drop has taken place:

```compile_fail
struct Foo {
    a: u32,
}

let mut x = Foo { a: 1 };
drop(x); // `x` is now uninitialized
x.a = 2; // error, partial reinitialization of uninitialized structure `t`
```

This error can be fixed by fully reinitializing the structure in question:

```
struct Foo {
    a: u32,
}

let mut x = Foo { a: 1 };
drop(x);
x = Foo { a: 2 };
```
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```compile_fail
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.

For example, this can happen when storing a `&mut` inside an immutable `Box`:

```compile_fail
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
```

This error can be fixed by making the container mutable:

```
let mut x: i64 = 1;
let mut y: Box<_> = Box::new(&mut x);
**y = 2;
```

It can also be fixed by using a type with interior mutability, such as `Cell`
or `RefCell`:

```
use std::cell::Cell;

let x: i64 = 1;
let y: Box<Cell<_>> = Box::new(Cell::new(x));
y.set(2);
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```compile_fail
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data. Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable`
function could be redefined as below:

```
use std::cell::Cell;

fn foo<F: Fn()>(f: F) { }

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##,

E0389: r##"
An attempt was made to mutate data using a non-mutable reference. This
commonly occurs when attempting to assign to a non-mutable reference of a
mutable reference (`&(&mut T)`).

Example of erroneous code:

```compile_fail
struct FancyNum {
    num: u8
}

fn main() {
    let mut fancy = FancyNum{ num: 5 };
    let fancy_ref = &(&mut fancy);
    fancy_ref.num = 6; // error: cannot assign to data in a `&` reference
    println!("{}", fancy_ref.num);
}
```

Here, `&mut fancy` is mutable, but `&(&mut fancy)` is not. Creating an
immutable reference to a value borrows it immutably. There can be multiple
references of type `&(&mut T)` that point to the same value, so they must be
immutable to prevent multiple mutable references to the same value.

To fix this, either remove the outer reference:

```
struct FancyNum {
    num: u8
}

fn main() {
    let mut fancy = FancyNum{ num: 5 };

    let fancy_ref = &mut fancy;
    // `fancy_ref` is now &mut FancyNum, rather than &(&mut FancyNum)

    fancy_ref.num = 6; // No error!

    println!("{}", fancy_ref.num);
}
```

Or make the outer reference mutable:

```
struct FancyNum {
    num: u8
}

fn main() {
    let mut fancy = FancyNum{ num: 5 };

    let fancy_ref = &mut (&mut fancy);
    // `fancy_ref` is now &mut(&mut FancyNum), rather than &(&mut FancyNum)

    fancy_ref.num = 6; // No error!

    println!("{}", fancy_ref.num);
}
```
"##,

E0499: r##"
A variable was borrowed as mutable more than once. Erroneous code example:

```compile_fail
let mut i = 0;
let mut x = &mut i;
let mut a = &mut i;
// error: cannot borrow `i` as mutable more than once at a time
```

Please note that in rust, you can either have many immutable references, or one
mutable reference. Take a look at
https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
information. Example:

```
let mut i = 0;
let mut x = &mut i; // ok!

// or:
let mut i = 0;
let a = &i; // ok!
let b = &i; // still ok!
let c = &i; // still ok!
```
"##,

E0507: r##"
You tried to move out of a value which was borrowed. Erroneous code example:

```compile_fail
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // error: cannot move out of borrowed content
}
```

Here, the `nothing_is_true` method takes the ownership of `self`. However,
`self` cannot be moved because `.borrow()` only provides an `&TheDarkKnight`,
which is a borrow of the content owned by the `RefCell`. To fix this error,
you have three choices:

* Try to avoid moving the variable.
* Somehow reclaim the ownership.
* Implement the `Copy` trait on the type.

Examples:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(&self) {} // First case, we don't take ownership
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);
    let x = x.into_inner(); // we get back ownership

    x.nothing_is_true(); // ok!
}
```

Or:

```
use std::cell::RefCell;

#[derive(Clone, Copy)] // we implement the Copy trait
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

fn main() {
    let x = RefCell::new(TheDarkKnight);

    x.borrow().nothing_is_true(); // ok!
}
```

Moving out of a member of a mutably borrowed struct is fine if you put something
back. `mem::replace` can be used for that:

```ignore
struct TheDarkKnight;

impl TheDarkKnight {
    fn nothing_is_true(self) {}
}

struct Batcave {
    knight: TheDarkKnight
}

fn main() {
    use std::mem;

    let mut cave = Batcave {
        knight: TheDarkKnight
    };
    let borrowed = &mut cave;

    borrowed.knight.nothing_is_true(); // E0507
    mem::replace(&mut borrowed.knight, TheDarkKnight).nothing_is_true(); // ok!
}
```

You can find more information about borrowing in the rust-book:
http://doc.rust-lang.org/stable/book/references-and-borrowing.html
"##,

}

register_diagnostics! {
    E0385, // {} in an aliasable location
    E0388, // {} in a static location
    E0500, // closure requires unique access to `..` but .. is already borrowed
    E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
    E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
    E0503, // cannot use `..` because it was mutably borrowed
    E0504, // cannot move `..` into closure because it is borrowed
    E0505, // cannot move out of `..` because it is borrowed
    E0506, // cannot assign to `..` because it is borrowed
    E0508, // cannot move out of type `..`, a non-copy fixed-size array
    E0509, // cannot move out of type `..`, which defines the `Drop` trait
    E0524, // two closures require unique access to `..` at the same time
}
<|endoftext|>


<commit_before>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// FIXME: move this to `rustc_data_structures`

use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut, Range};
use bitslice::{BitSlice, Word};
use bitslice::{bitwise, Union, Subtract};

pub trait Idx: 'static {
    fn new(usize) -> Self;
    fn idx(&self) -> usize;
}

pub struct OwnIdxSet<T: Idx> {
    _pd: PhantomData<fn(&[T], usize) -> &T>,
    bits: Vec<Word>,
}

impl<T: Idx> Clone for OwnIdxSet<T> {
    fn clone(&self) -> Self {
        OwnIdxSet { _pd: PhantomData, bits: self.bits.clone() }
    }
}

// pnkfelix wants to have this be `IdxSet<T>([Word]) and then pass
// around `&mut IdxSet<T>` or `&IdxSet<T>`.
//
// WARNING: Mapping a `&OwnIdxSet<T>` to `&IdxSet<T>` (at least today)
// requires a transmute relying on representation guarantees that may
// not hold in the future.

pub struct IdxSet<T: Idx> {
    _pd: PhantomData<fn(&[T], usize) -> &T>,
    bits: [Word],
}

impl<T: Idx> fmt::Debug for OwnIdxSet<T> {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
}

impl<T: Idx> fmt::Debug for IdxSet<T> {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
}

impl<T: Idx> OwnIdxSet<T> {
    fn new(init: Word, universe_size: usize) -> Self {
        let bits_per_word = mem::size_of::<Word>() * 8;
        let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word;
        OwnIdxSet {
            _pd: Default::default(),
            bits: vec![init; num_words],
        }
    }

    /// Creates set holding every element whose index falls in range 0..universe_size.
    pub fn new_filled(universe_size: usize) -> Self {
        Self::new(!0, universe_size)
    }

    /// Creates set holding no elements.
    pub fn new_empty(universe_size: usize) -> Self {
        Self::new(0, universe_size)
    }
}

impl<T: Idx> IdxSet<T> {
    unsafe fn from_slice(s: &[Word]) -> &Self {
        mem::transmute(s) // (see above WARNING)
    }

    unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self {
        mem::transmute(s) // (see above WARNING)
    }
}

impl<T: Idx> Deref for OwnIdxSet<T> {
    type Target = IdxSet<T>;
    fn deref(&self) -> &IdxSet<T> {
        unsafe { IdxSet::from_slice(&self.bits[..]) }
    }
}

impl<T: Idx> DerefMut for OwnIdxSet<T> {
    fn deref_mut(&mut self) -> &mut IdxSet<T> {
        unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) }
    }
}

impl<T: Idx> IdxSet<T> {
    pub fn to_owned(&self) -> OwnIdxSet<T> {
        OwnIdxSet {
            _pd: Default::default(),
            bits: self.bits.to_owned(),
        }
    }

    /// Removes `elem` from the set `self`; returns true iff this changed `self`.
    pub fn remove(&mut self, elem: &T) -> bool {
        self.bits.clear_bit(elem.idx())
    }

    /// Adds `elem` to the set `self`; returns true iff this changed `self`.
    pub fn add(&mut self, elem: &T) -> bool {
        self.bits.set_bit(elem.idx())
    }

    pub fn range(&self, elems: &Range<T>) -> &Self {
        let elems = elems.start.idx()..elems.end.idx();
        unsafe { Self::from_slice(&self.bits[elems]) }
    }

    pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
        let elems = elems.start.idx()..elems.end.idx();
        unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
    }

    /// Returns true iff set `self` contains `elem`.
    pub fn contains(&self, elem: &T) -> bool {
        self.bits.get_bit(elem.idx())
    }

    pub fn words(&self) -> &[Word] {
        &self.bits[..]
    }

    pub fn words_mut(&mut self) -> &mut [Word] {
        &mut self.bits[..]
    }

    pub fn clone_from(&mut self, other: &IdxSet<T>) {
        self.words_mut().clone_from_slice(other.words());
    }

    pub fn union(&mut self, other: &IdxSet<T>) -> bool {
        bitwise(self.words_mut(), other.words(), &Union)
    }

    pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
        bitwise(self.words_mut(), other.words(), &Subtract)
    }
}
<commit_msg>fixes to `indexed_set`: add comments and fix `PhantomData` def'n.<commit_after>// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// FIXME: move this to `rustc_data_structures`

use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Deref, DerefMut, Range};
use bitslice::{BitSlice, Word};
use bitslice::{bitwise, Union, Subtract};

/// Represents some newtyped `usize` wrapper.
///
/// (purpose: avoid mixing indexes for different bitvector domains.)
pub trait Idx: 'static {
    fn new(usize) -> Self;
    fn idx(&self) -> usize;
}

/// Represents a set (or packed family of sets), of some element type
/// E, where each E is identified by some unique index type `T`.
///
/// In other words, `T` is the type used to index into the bitvector
/// this type uses to represent the set of object it holds.
pub struct OwnIdxSet<T: Idx> {
    _pd: PhantomData<fn(&T)>,
    bits: Vec<Word>,
}

impl<T: Idx> Clone for OwnIdxSet<T> {
    fn clone(&self) -> Self {
        OwnIdxSet { _pd: PhantomData, bits: self.bits.clone() }
    }
}

// pnkfelix wants to have this be `IdxSet<T>([Word]) and then pass
// around `&mut IdxSet<T>` or `&IdxSet<T>`.
//
// WARNING: Mapping a `&OwnIdxSet<T>` to `&IdxSet<T>` (at least today)
// requires a transmute relying on representation guarantees that may
// not hold in the future.

/// Represents a set (or packed family of sets), of some element type
/// E, where each E is identified by some unique index type `T`.
///
/// In other words, `T` is the type used to index into the bitslice
/// this type uses to represent the set of object it holds.
pub struct IdxSet<T: Idx> {
    _pd: PhantomData<fn(&T)>,
    bits: [Word],
}

impl<T: Idx> fmt::Debug for OwnIdxSet<T> {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
}

impl<T: Idx> fmt::Debug for IdxSet<T> {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { self.bits.fmt(w) }
}

impl<T: Idx> OwnIdxSet<T> {
    fn new(init: Word, universe_size: usize) -> Self {
        let bits_per_word = mem::size_of::<Word>() * 8;
        let num_words = (universe_size + (bits_per_word - 1)) / bits_per_word;
        OwnIdxSet {
            _pd: Default::default(),
            bits: vec![init; num_words],
        }
    }

    /// Creates set holding every element whose index falls in range 0..universe_size.
    pub fn new_filled(universe_size: usize) -> Self {
        Self::new(!0, universe_size)
    }

    /// Creates set holding no elements.
    pub fn new_empty(universe_size: usize) -> Self {
        Self::new(0, universe_size)
    }
}

impl<T: Idx> IdxSet<T> {
    unsafe fn from_slice(s: &[Word]) -> &Self {
        mem::transmute(s) // (see above WARNING)
    }

    unsafe fn from_slice_mut(s: &mut [Word]) -> &mut Self {
        mem::transmute(s) // (see above WARNING)
    }
}

impl<T: Idx> Deref for OwnIdxSet<T> {
    type Target = IdxSet<T>;
    fn deref(&self) -> &IdxSet<T> {
        unsafe { IdxSet::from_slice(&self.bits[..]) }
    }
}

impl<T: Idx> DerefMut for OwnIdxSet<T> {
    fn deref_mut(&mut self) -> &mut IdxSet<T> {
        unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) }
    }
}

impl<T: Idx> IdxSet<T> {
    pub fn to_owned(&self) -> OwnIdxSet<T> {
        OwnIdxSet {
            _pd: Default::default(),
            bits: self.bits.to_owned(),
        }
    }

    /// Removes `elem` from the set `self`; returns true iff this changed `self`.
    pub fn remove(&mut self, elem: &T) -> bool {
        self.bits.clear_bit(elem.idx())
    }

    /// Adds `elem` to the set `self`; returns true iff this changed `self`.
    pub fn add(&mut self, elem: &T) -> bool {
        self.bits.set_bit(elem.idx())
    }

    pub fn range(&self, elems: &Range<T>) -> &Self {
        let elems = elems.start.idx()..elems.end.idx();
        unsafe { Self::from_slice(&self.bits[elems]) }
    }

    pub fn range_mut(&mut self, elems: &Range<T>) -> &mut Self {
        let elems = elems.start.idx()..elems.end.idx();
        unsafe { Self::from_slice_mut(&mut self.bits[elems]) }
    }

    /// Returns true iff set `self` contains `elem`.
    pub fn contains(&self, elem: &T) -> bool {
        self.bits.get_bit(elem.idx())
    }

    pub fn words(&self) -> &[Word] {
        &self.bits[..]
    }

    pub fn words_mut(&mut self) -> &mut [Word] {
        &mut self.bits[..]
    }

    pub fn clone_from(&mut self, other: &IdxSet<T>) {
        self.words_mut().clone_from_slice(other.words());
    }

    pub fn union(&mut self, other: &IdxSet<T>) -> bool {
        bitwise(self.words_mut(), other.words(), &Union)
    }

    pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
        bitwise(self.words_mut(), other.words(), &Subtract)
    }
}
<|endoftext|>


<commit_before>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::layout::LayoutOf;
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    EvalResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

use syntax::ast::Mutability;
use syntax_pos::Span;

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references don't change the `mutability` field to `Immutable`
    StaticMut,
    /// Mutable references must in fact be immutable due to their surrounding immutability
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'a, 'mir, 'tcx> InternVisitor<'rt, 'a, 'mir, 'tcx> {
    fn intern(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> EvalResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'a, 'mir, 'tcx>
    ValueVisitor<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
for
    InternVisitor<'rt, 'a, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'a, 'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
    ) -> EvalResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> EvalResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, _, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                let layout = self.ecx.layout_of(ty.builtin_deref(true).unwrap().ty)?;
                if layout.is_unsized() {
                    if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(layout.ty).sty {
                        if let Ok(vtable) = meta.unwrap().to_ptr() {
                            // explitly choose `Immutable` here, since vtables are immutable, even
                            // if the reference of the fat pointer is mutable
                            self.intern(vtable, Mutability::Immutable)?;
                        }
                    }
                }
            }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // In the future we will probably allow `& &mut T`, and thus will want to merge
                // `mutability` with `self.mutability` to only choose `Mutable` if both are
                // `Mutable`.

                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                match (self.mode, mutability) {
                    // all is "good and well" in the unsoundness of `static mut`
                    (InternMode::StaticMut, _) => {},
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) =>
                        bug!("const qualif failed to prevent mutable references"),
                }
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx> {
    let tcx = ecx.tcx;
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::StaticMut),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<commit_msg>Elaborate on why we don't look at frozenness<commit_after>//! This module specifies the type based interner for constants.
//!
//! After a const evaluation has computed a value, before we destroy the const evaluator's session
//! memory, we need to extract all memory allocations to the global memory pool so they stay around.

use rustc::ty::layout::LayoutOf;
use rustc::ty::{Ty, TyCtxt, ParamEnv, self};
use rustc::mir::interpret::{
    EvalResult, ErrorHandled,
};
use rustc::hir;
use rustc::hir::def_id::DefId;
use super::validity::RefTracking;
use rustc_data_structures::fx::FxHashSet;

use syntax::ast::Mutability;
use syntax_pos::Span;

use super::{
    ValueVisitor, MemoryKind, Pointer, AllocId, MPlaceTy, InterpError, Scalar,
};
use crate::const_eval::{CompileTimeInterpreter, CompileTimeEvalContext};

struct InternVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir> {
    /// previously encountered safe references
    ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, Mutability, InternMode)>,
    ecx: &'rt mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    param_env: ParamEnv<'tcx>,
    /// The root node of the value that we're looking at. This field is never mutated and only used
    /// for sanity assertions that will ICE when `const_qualif` screws up.
    mode: InternMode,
    /// This field stores the mutability of the value *currently* being checked.
    /// It is set to mutable when an `UnsafeCell` is encountered
    /// When recursing across a reference, we don't recurse but store the
    /// value to be checked in `ref_tracking` together with the mutability at which we are checking
    /// the value.
    /// When encountering an immutable reference, we treat everything as immutable that is behind
    /// it.
    mutability: Mutability,
    /// A list of all encountered relocations. After type-based interning, we traverse this list to
    /// also intern allocations that are only referenced by a raw pointer or inside a union.
    leftover_relocations: &'rt mut FxHashSet<AllocId>,
}

#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
enum InternMode {
    /// Mutable references don't change the `mutability` field to `Immutable`
    StaticMut,
    /// Mutable references must in fact be immutable due to their surrounding immutability
    Static,
    /// UnsafeCell is OK in the value of a constant, but not behind references in a constant
    ConstBase,
    /// `UnsafeCell` ICEs
    Const,
}

/// Signalling data structure to ensure we don't recurse
/// into the memory of other constants or statics
struct IsStaticOrFn;

impl<'rt, 'a, 'mir, 'tcx> InternVisitor<'rt, 'a, 'mir, 'tcx> {
    fn intern(
        &mut self,
        ptr: Pointer,
        mutability: Mutability,
    ) -> EvalResult<'tcx, Option<IsStaticOrFn>> {
        trace!(
            "InternVisitor::intern {:?} with {:?}",
            ptr, mutability,
        );
        // remove allocation
        let tcx = self.ecx.tcx;
        let memory = self.ecx.memory_mut();
        let (kind, mut alloc) = match memory.alloc_map.remove(&ptr.alloc_id) {
            Some(entry) => entry,
            None => {
                // if the pointer is dangling (neither in local nor global memory), we leave it
                // to validation to error. The `delay_span_bug` ensures that we don't forget such
                // a check in validation.
                if tcx.alloc_map.lock().get(ptr.alloc_id).is_none() {
                    tcx.sess.delay_span_bug(self.ecx.tcx.span, "tried to intern dangling pointer");
                }
                // treat dangling pointers like other statics
                // just to stop trying to recurse into them
                return Ok(Some(IsStaticOrFn));
            },
        };
        // This match is just a canary for future changes to `MemoryKind`, which most likely need
        // changes in this function.
        match kind {
            MemoryKind::Stack | MemoryKind::Vtable => {},
        }
        // Ensure llvm knows to only put this into immutable memory if the value is immutable either
        // by being behind a reference or by being part of a static or const without interior
        // mutability
        alloc.mutability = mutability;
        // link the alloc id to the actual allocation
        let alloc = tcx.intern_const_alloc(alloc);
        self.leftover_relocations.extend(alloc.relocations.iter().map(|&(_, ((), reloc))| reloc));
        tcx.alloc_map.lock().set_alloc_id_memory(ptr.alloc_id, alloc);
        Ok(None)
    }
}

impl<'rt, 'a, 'mir, 'tcx>
    ValueVisitor<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
for
    InternVisitor<'rt, 'a, 'mir, 'tcx>
{
    type V = MPlaceTy<'tcx>;

    #[inline(always)]
    fn ecx(&self) -> &CompileTimeEvalContext<'a, 'mir, 'tcx> {
        &self.ecx
    }

    fn visit_aggregate(
        &mut self,
        mplace: MPlaceTy<'tcx>,
        fields: impl Iterator<Item=EvalResult<'tcx, Self::V>>,
    ) -> EvalResult<'tcx> {
        if let Some(def) = mplace.layout.ty.ty_adt_def() {
            if Some(def.did) == self.ecx.tcx.lang_items().unsafe_cell_type() {
                // We are crossing over an `UnsafeCell`, we can mutate again
                let old = std::mem::replace(&mut self.mutability, Mutability::Mutable);
                assert_ne!(
                    self.mode, InternMode::Const,
                    "UnsafeCells are not allowed behind references in constants. This should have \
                    been prevented statically by const qualification. If this were allowed one \
                    would be able to change a constant at one use site and other use sites may \
                    arbitrarily decide to change, too.",
                );
                let walked = self.walk_aggregate(mplace, fields);
                self.mutability = old;
                return walked;
            }
        }
        self.walk_aggregate(mplace, fields)
    }

    fn visit_primitive(&mut self, mplace: MPlaceTy<'tcx>) -> EvalResult<'tcx> {
        // Handle Reference types, as these are the only relocations supported by const eval.
        // Raw pointers (and boxes) are handled by the `leftover_relocations` logic.
        let ty = mplace.layout.ty;
        if let ty::Ref(_, _, mutability) = ty.sty {
            let value = self.ecx.read_immediate(mplace.into())?;
            // Handle trait object vtables
            if let Ok(meta) = value.to_meta() {
                let layout = self.ecx.layout_of(ty.builtin_deref(true).unwrap().ty)?;
                if layout.is_unsized() {
                    if let ty::Dynamic(..) = self.ecx.tcx.struct_tail(layout.ty).sty {
                        if let Ok(vtable) = meta.unwrap().to_ptr() {
                            // explitly choose `Immutable` here, since vtables are immutable, even
                            // if the reference of the fat pointer is mutable
                            self.intern(vtable, Mutability::Immutable)?;
                        }
                    }
                }
            }
            let mplace = self.ecx.ref_to_mplace(value)?;
            // Check if we have encountered this pointer+layout combination before.
            // Only recurse for allocation-backed pointers.
            if let Scalar::Ptr(ptr) = mplace.ptr {
                // In the future we will probably allow `& &mut T`, and thus will want to merge
                // `mutability` with `self.mutability` to only choose `Mutable` if both are
                // `Mutable`.

                // We do not have any `frozen` logic here, because it's essentially equivalent to
                // the mutability except for the outermost item. Only `UnsafeCell` can "unfreeze",
                // and we check that in `visit_aggregate`.
                // This is not an inherent limitation, but one that we know to be true, because
                // const qualification enforces it. We can lift it in the future.
                match (self.mode, mutability) {
                    // all is "good and well" in the unsoundness of `static mut`
                    (InternMode::StaticMut, _) => {},
                    // immutable references are fine everywhere
                    (_, hir::Mutability::MutImmutable) => {},
                    // mutable references are ok in `static`. Either they are treated as immutable
                    // because they are behind an immutable one, or they are behind an `UnsafeCell`
                    // and thus ok.
                    (InternMode::Static, hir::Mutability::MutMutable) => {},
                    // we statically prevent `&mut T` via `const_qualif` and double check this here
                    (InternMode::ConstBase, hir::Mutability::MutMutable) |
                    (InternMode::Const, hir::Mutability::MutMutable) =>
                        bug!("const qualif failed to prevent mutable references"),
                }
                let mutability = match (self.mutability, mutability) {
                    // The only way a mutable reference actually works as a mutable reference is
                    // by being in a `static mut` directly or behind another mutable reference.
                    // If there's an immutable reference or we are inside a static, then our
                    // mutable reference is equivalent to an immutable one. As an example:
                    // `&&mut Foo` is semantically equivalent to `&&Foo`
                    (Mutability::Mutable, hir::Mutability::MutMutable) => Mutability::Mutable,
                    _ => Mutability::Immutable,
                };
                let intern_mutability = intern_mutability(
                    self.ecx.tcx.tcx,
                    self.param_env,
                    mplace.layout.ty,
                    self.ecx.tcx.span,
                    mutability,
                );
                // Recursing behind references changes the intern mode for constants in order to
                // cause assertions to trigger if we encounter any `UnsafeCell`s.
                let mode = match self.mode {
                    InternMode::ConstBase => InternMode::Const,
                    other => other,
                };
                match self.intern(ptr, intern_mutability)? {
                    // No need to recurse, these are interned already and statics may have
                    // cycles, so we don't want to recurse there
                    Some(IsStaticOrFn) => {},
                    // intern everything referenced by this value. The mutability is taken from the
                    // reference. It is checked above that mutable references only happen in
                    // `static mut`
                    None => self.ref_tracking.track((mplace, mutability, mode), || ()),
                }
            }
        }
        Ok(())
    }
}

/// Figure out the mutability of the allocation.
/// Mutable if it has interior mutability *anywhere* in the type.
fn intern_mutability<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    param_env: ParamEnv<'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    mutability: Mutability,
) -> Mutability {
    let has_interior_mutability = !ty.is_freeze(tcx, param_env, span);
    if has_interior_mutability {
        Mutability::Mutable
    } else {
        mutability
    }
}

pub fn intern_const_alloc_recursive(
    ecx: &mut CompileTimeEvalContext<'a, 'mir, 'tcx>,
    def_id: DefId,
    ret: MPlaceTy<'tcx>,
    // FIXME(oli-obk): can we scrap the param env? I think we can, the final value of a const eval
    // must always be monomorphic, right?
    param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx> {
    let tcx = ecx.tcx;
    let (mutability, base_intern_mode) = match tcx.static_mutability(def_id) {
        Some(hir::Mutability::MutImmutable) => (Mutability::Immutable, InternMode::Static),
        None => (Mutability::Immutable, InternMode::ConstBase),
        // `static mut` doesn't care about interior mutability, it's mutable anyway
        Some(hir::Mutability::MutMutable) => (Mutability::Mutable, InternMode::StaticMut),
    };

    // type based interning
    let mut ref_tracking = RefTracking::new((ret, mutability, base_intern_mode));
    let leftover_relocations = &mut FxHashSet::default();

    let alloc_mutability = intern_mutability(
        tcx.tcx, param_env, ret.layout.ty, tcx.span, mutability,
    );

    // start with the outermost allocation
    InternVisitor {
        ref_tracking: &mut ref_tracking,
        ecx,
        mode: base_intern_mode,
        leftover_relocations,
        param_env,
        mutability,
    }.intern(ret.ptr.to_ptr()?, alloc_mutability)?;

    while let Some(((mplace, mutability, mode), _)) = ref_tracking.todo.pop() {
        let interned = InternVisitor {
            ref_tracking: &mut ref_tracking,
            ecx,
            mode,
            leftover_relocations,
            param_env,
            mutability,
        }.visit_value(mplace);
        if let Err(error) = interned {
            // This can happen when e.g. the tag of an enum is not a valid discriminant. We do have
            // to read enum discriminants in order to find references in enum variant fields.
            if let InterpError::ValidationFailure(_) = error.kind {
                let err = crate::const_eval::error_to_const_error(&ecx, error);
                match err.struct_error(ecx.tcx, "it is undefined behavior to use this value") {
                    Ok(mut diag) => {
                        diag.note("The rules on what exactly is undefined behavior aren't clear, \
                            so this check might be overzealous. Please open an issue on the rust \
                            compiler repository if you believe it should not be considered \
                            undefined behavior",
                        );
                        diag.emit();
                    }
                    Err(ErrorHandled::TooGeneric) |
                    Err(ErrorHandled::Reported) => {},
                }
            }
        }
    }

    // Intern the rest of the allocations as mutable. These might be inside unions, padding, raw
    // pointers, ... So we can't intern them according to their type rules

    let mut todo: Vec<_> = leftover_relocations.iter().cloned().collect();
    while let Some(alloc_id) = todo.pop() {
        if let Some((_, alloc)) = ecx.memory_mut().alloc_map.remove(&alloc_id) {
            // We can't call the `intern` method here, as its logic is tailored to safe references.
            // So we hand-roll the interning logic here again
            let alloc = tcx.intern_const_alloc(alloc);
            tcx.alloc_map.lock().set_alloc_id_memory(alloc_id, alloc);
            for &(_, ((), reloc)) in alloc.relocations.iter() {
                if leftover_relocations.insert(reloc) {
                    todo.push(reloc);
                }
            }
        } else if ecx.memory().dead_alloc_map.contains_key(&alloc_id) {
            // dangling pointer
            return err!(ValidationFailure(
                "encountered dangling pointer in final constant".into(),
            ))
        }
    }
    Ok(())
}
<|endoftext|>