<commit_before>//! Register commands on the registry.

use std::process::{Command, Stdio};
use std::thread;
use std::io::prelude::*;
use layout::commands as layout_cmds;
use ::modes::commands as mode_cmds;

use commands::{self, CommandFn};
use layout::try_lock_tree;
use lua::{self, LuaQuery};
use super::super::keys;

/// Register the default commands in the API.
///
/// Some of this code will be moved to be called after the config,
/// and will be registered dynamically.
pub fn register_defaults() {
    let mut coms = commands::write_lock();

    let mut register = |name: &'static str, val: CommandFn| {
        coms.insert(name.to_string(), val);
    };

    register("way_cooler_quit", way_cooler_quit);
    register("print_pointer", print_pointer);

    register("dmenu_eval", dmenu_eval);
    register("way_cooler_restart", way_cooler_restart);
    register("dmenu_lua_dofile", dmenu_lua_dofile);

    /// Generate switch_workspace methods and register them
    macro_rules! gen_switch_workspace {
        ( $($b:ident, $n:expr);+ ) => {
            $(fn $b() {
                trace!("Switching to workspace {}", $n);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.switch_to_workspace(&$n.to_string())
                        .unwrap_or_else(|err| {
                            warn!("Could not switch workspace: {:#?}", err);
                        });
                }
            }
            register(stringify!($b), $b); )+
        }
    }

    //// Generates move_to_workspace methods and registers them
    macro_rules! gen_move_to_workspace {
        ( $($b:ident, $n:expr);+ ) => {
            $(fn $b() {
                trace!("Switching to workspace {}", $n);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.send_active_to_workspace(&$n.to_string())
                        .unwrap_or_else(|err| {
                            warn!("Could not send to a different workspace,\
                                   {:#?}", err);
                        })
                }
            }
              register(stringify!($b), $b); )+
        }
    }

    gen_switch_workspace!(switch_workspace_1, "1";
                          switch_workspace_2, "2";
                          switch_workspace_3, "3";
                          switch_workspace_4, "4";
                          switch_workspace_5, "5";
                          switch_workspace_6, "6";
                          switch_workspace_7, "7";
                          switch_workspace_8, "8";
                          switch_workspace_9, "9";
                          switch_workspace_0, "0");

    gen_move_to_workspace!(move_to_workspace_1, "1";
                           move_to_workspace_2, "2";
                           move_to_workspace_3, "3";
                           move_to_workspace_4, "4";
                           move_to_workspace_5, "5";
                           move_to_workspace_6, "6";
                           move_to_workspace_7, "7";
                           move_to_workspace_8, "8";
                           move_to_workspace_9, "9";
                           move_to_workspace_0, "0");

    // Tiling and window controls
    register("horizontal_vertical_switch", layout_cmds::tile_switch);
    register("split_vertical", layout_cmds::split_vertical);
    register("split_horizontal", layout_cmds::split_horizontal);
    register("tile_tabbed", layout_cmds::tile_tabbed);
    register("tile_stacked", layout_cmds::tile_stacked);
    register("fullscreen_toggle", layout_cmds::fullscreen_toggle);
    register("focus_left", layout_cmds::focus_left);
    register("focus_right", layout_cmds::focus_right);
    register("focus_up", layout_cmds::focus_up);
    register("focus_down", layout_cmds::focus_down);
    register("move_active_left", layout_cmds::move_active_left);
    register("move_active_right", layout_cmds::move_active_right);
    register("move_active_up", layout_cmds::move_active_up);
    register("move_active_down", layout_cmds::move_active_down);
    register("close_window", layout_cmds::remove_active);
    register("toggle_float_active", layout_cmds::toggle_float);
    register("toggle_float_focus", layout_cmds::toggle_float_focus);

    // Modes
    register("default_mode", mode_cmds::set_default_mode);
    register("custom_mode", mode_cmds::set_custom_mode);
    // Command that spawns the lock screen and moves to lock screen mode.
    // Must have one specified in the registry first in order for it to work.
    register("lock_screen", mode_cmds::spawn_lock_screen);

}

// All of the methods defined should be registered.
#[deny(dead_code)]

fn print_pointer() {
    use lua;
    use lua::LuaQuery;

    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::send(LuaQuery::Execute(code))
        .expect("Error telling Lua to get pointer coords");
}

fn way_cooler_quit() {
    info!("Closing way cooler!!");
    ::rustwlc::terminate();
}

fn dmenu_lua_dofile() {
    thread::Builder::new().name("dmenu_dofile".to_string()).spawn(|| {
        let child = Command::new("dmenu").arg("-p").arg("Eval Lua file")
            .stdin(Stdio::piped()).stdout(Stdio::piped())
            .spawn().expect("Unable to launch dmenu!");

        {
            // Write \d to stdin to prevent options from being given
            let mut stdin = child.stdin.expect("Unable to access stdin");
            stdin.write_all(b"\n").expect("Unable to write to stdin");
        }

        let mut stdout = child.stdout.expect("Unable to access stdout");
        let mut output = String::new();
        stdout.read_to_string(&mut output).expect("Unable to read stdout");

        let result = lua::send(LuaQuery::ExecFile(output))
            .expect("unable to contact Lua").recv().expect("Can't get reply");
        trace!("Lua result: {:?}", result);
    }).expect("Unable to spawn thread");
}

fn dmenu_eval() {
       thread::Builder::new().name("dmenu_eval".to_string()).spawn(|| {
           let child = Command::new("dmenu").arg("-p").arg("Eval Lua code")
               .stdin(Stdio::piped()).stdout(Stdio::piped())
               .spawn().expect("Unable to launch dmenu!");
           {
               // Write \d to stdin to prevent options from being given
               let mut stdin = child.stdin.expect("Unable to access stdin");
               stdin.write_all(b"\n").expect("Unable to write to stdin");
           }
           let mut stdout = child.stdout.expect("Unable to access stdout");
           let mut output = String::new();
           stdout.read_to_string(&mut output).expect("Unable to read stdout");

           let result = lua::send(LuaQuery::Execute(output))
               .expect("Unable to contact Lua").recv().expect("Can't get reply");
           trace!("Lua result: {:?}", result)
    }).expect("Unable to spawn thread");
}

fn way_cooler_restart() {
    keys::clear_keys();
    if let Err(err) = lua::send(lua::LuaQuery::Restart) {
        warn!("Could not send restart signal, {:?}", err);
    }
}
<commit_msg>Add noop command<commit_after>//! Register commands on the registry.

use std::process::{Command, Stdio};
use std::thread;
use std::io::prelude::*;
use layout::commands as layout_cmds;
use ::modes::commands as mode_cmds;

use commands::{self, CommandFn};
use layout::try_lock_tree;
use lua::{self, LuaQuery};
use super::super::keys;

/// Register the default commands in the API.
///
/// Some of this code will be moved to be called after the config,
/// and will be registered dynamically.
pub fn register_defaults() {
    let mut coms = commands::write_lock();

    let mut register = |name: &'static str, val: CommandFn| {
        coms.insert(name.to_string(), val);
    };

    register("way_cooler_quit", way_cooler_quit);
    register("print_pointer", print_pointer);

    register("dmenu_eval", dmenu_eval);
    register("way_cooler_restart", way_cooler_restart);
    register("dmenu_lua_dofile", dmenu_lua_dofile);

    register("noop", noop);

    /// Generate switch_workspace methods and register them
    macro_rules! gen_switch_workspace {
        ( $($b:ident, $n:expr);+ ) => {
            $(fn $b() {
                trace!("Switching to workspace {}", $n);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.switch_to_workspace(&$n.to_string())
                        .unwrap_or_else(|err| {
                            warn!("Could not switch workspace: {:#?}", err);
                        });
                }
            }
            register(stringify!($b), $b); )+
        }
    }

    //// Generates move_to_workspace methods and registers them
    macro_rules! gen_move_to_workspace {
        ( $($b:ident, $n:expr);+ ) => {
            $(fn $b() {
                trace!("Switching to workspace {}", $n);
                if let Ok(mut tree) = try_lock_tree() {
                    tree.send_active_to_workspace(&$n.to_string())
                        .unwrap_or_else(|err| {
                            warn!("Could not send to a different workspace,\
                                   {:#?}", err);
                        })
                }
            }
              register(stringify!($b), $b); )+
        }
    }

    gen_switch_workspace!(switch_workspace_1, "1";
                          switch_workspace_2, "2";
                          switch_workspace_3, "3";
                          switch_workspace_4, "4";
                          switch_workspace_5, "5";
                          switch_workspace_6, "6";
                          switch_workspace_7, "7";
                          switch_workspace_8, "8";
                          switch_workspace_9, "9";
                          switch_workspace_0, "0");

    gen_move_to_workspace!(move_to_workspace_1, "1";
                           move_to_workspace_2, "2";
                           move_to_workspace_3, "3";
                           move_to_workspace_4, "4";
                           move_to_workspace_5, "5";
                           move_to_workspace_6, "6";
                           move_to_workspace_7, "7";
                           move_to_workspace_8, "8";
                           move_to_workspace_9, "9";
                           move_to_workspace_0, "0");

    // Tiling and window controls
    register("horizontal_vertical_switch", layout_cmds::tile_switch);
    register("split_vertical", layout_cmds::split_vertical);
    register("split_horizontal", layout_cmds::split_horizontal);
    register("tile_tabbed", layout_cmds::tile_tabbed);
    register("tile_stacked", layout_cmds::tile_stacked);
    register("fullscreen_toggle", layout_cmds::fullscreen_toggle);
    register("focus_left", layout_cmds::focus_left);
    register("focus_right", layout_cmds::focus_right);
    register("focus_up", layout_cmds::focus_up);
    register("focus_down", layout_cmds::focus_down);
    register("move_active_left", layout_cmds::move_active_left);
    register("move_active_right", layout_cmds::move_active_right);
    register("move_active_up", layout_cmds::move_active_up);
    register("move_active_down", layout_cmds::move_active_down);
    register("close_window", layout_cmds::remove_active);
    register("toggle_float_active", layout_cmds::toggle_float);
    register("toggle_float_focus", layout_cmds::toggle_float_focus);

    // Modes
    register("default_mode", mode_cmds::set_default_mode);
    register("custom_mode", mode_cmds::set_custom_mode);
    // Command that spawns the lock screen and moves to lock screen mode.
    // Must have one specified in the registry first in order for it to work.
    register("lock_screen", mode_cmds::spawn_lock_screen);

}

// All of the methods defined should be registered.
#[deny(dead_code)]

fn print_pointer() {
    use lua;
    use lua::LuaQuery;

    let code = "if wm == nil then print('wm table does not exist')\n\
                elseif wm.pointer == nil then print('wm.pointer table does not exist')\n\
                else\n\
                local x, y = wm.pointer.get_position()\n\
                print('The cursor is at ' .. x .. ', ' .. y)\n\
                end".to_string();
    lua::send(LuaQuery::Execute(code))
        .expect("Error telling Lua to get pointer coords");
}

fn way_cooler_quit() {
    info!("Closing way cooler!!");
    ::rustwlc::terminate();
}

fn dmenu_lua_dofile() {
    thread::Builder::new().name("dmenu_dofile".to_string()).spawn(|| {
        let child = Command::new("dmenu").arg("-p").arg("Eval Lua file")
            .stdin(Stdio::piped()).stdout(Stdio::piped())
            .spawn().expect("Unable to launch dmenu!");

        {
            // Write \d to stdin to prevent options from being given
            let mut stdin = child.stdin.expect("Unable to access stdin");
            stdin.write_all(b"\n").expect("Unable to write to stdin");
        }

        let mut stdout = child.stdout.expect("Unable to access stdout");
        let mut output = String::new();
        stdout.read_to_string(&mut output).expect("Unable to read stdout");

        let result = lua::send(LuaQuery::ExecFile(output))
            .expect("unable to contact Lua").recv().expect("Can't get reply");
        trace!("Lua result: {:?}", result);
    }).expect("Unable to spawn thread");
}

fn dmenu_eval() {
       thread::Builder::new().name("dmenu_eval".to_string()).spawn(|| {
           let child = Command::new("dmenu").arg("-p").arg("Eval Lua code")
               .stdin(Stdio::piped()).stdout(Stdio::piped())
               .spawn().expect("Unable to launch dmenu!");
           {
               // Write \d to stdin to prevent options from being given
               let mut stdin = child.stdin.expect("Unable to access stdin");
               stdin.write_all(b"\n").expect("Unable to write to stdin");
           }
           let mut stdout = child.stdout.expect("Unable to access stdout");
           let mut output = String::new();
           stdout.read_to_string(&mut output).expect("Unable to read stdout");

           let result = lua::send(LuaQuery::Execute(output))
               .expect("Unable to contact Lua").recv().expect("Can't get reply");
           trace!("Lua result: {:?}", result)
    }).expect("Unable to spawn thread");
}

fn way_cooler_restart() {
    keys::clear_keys();
    if let Err(err) = lua::send(lua::LuaQuery::Restart) {
        warn!("Could not send restart signal, {:?}", err);
    }
}

/// A no-op(eration) command.
/// This can be used to register keys without assigning them an action (yet).
/// The Lua configuration script could also create an empty Lua function,
/// but doing it in Rust avoids a round-trip to Lua just to no nothing.
fn noop () {
}
<|endoftext|>


<commit_before>#![feature(allocator)]
#![feature(const_fn)]

#![allocator]
#![no_std]

use spin::Mutex;
use linked_list_allocator::Heap;

extern crate spin;
extern crate linked_list_allocator;

static HEAP: Mutex<Option<Heap>> = Mutex::new(None);

pub unsafe fn init(offset: usize, size: usize) {
    *HEAP.lock() = Some(Heap::new(offset, size));
}

#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    if let Some(ref mut heap) = *HEAP.lock() {
        heap.allocate_first_fit(size, align).expect("out of memory")
    } else {
        panic!("__rust_allocate: heap not initialized");
    }
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {
    if let Some(ref mut heap) = *HEAP.lock() {
        unsafe { heap.deallocate(ptr, size, align) };
    } else {
        panic!("__rust_deallocate: heap not initialized");
    }
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize,
    _new_size: usize, _align: usize) -> usize
{
    size
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
                                align: usize) -> *mut u8 {
    use core::{ptr, cmp};

    // from: https://github.com/rust-lang/rust/blob/
    //     c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/
    //     src/liballoc_system/lib.rs#L98-L101

    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
    __rust_deallocate(ptr, size, align);
    new_ptr
}
<commit_msg>Add __rust_allocate_zeroed to work with newest nightly<commit_after>#![feature(allocator)]
#![feature(const_fn)]

#![allocator]
#![no_std]

use core::ptr;
use spin::Mutex;
use linked_list_allocator::Heap;

extern crate spin;
extern crate linked_list_allocator;

static HEAP: Mutex<Option<Heap>> = Mutex::new(None);

pub unsafe fn init(offset: usize, size: usize) {
    *HEAP.lock() = Some(Heap::new(offset, size));
}

#[no_mangle]
pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    if let Some(ref mut heap) = *HEAP.lock() {
        heap.allocate_first_fit(size, align).expect("out of memory")
    } else {
        panic!("__rust_allocate: heap not initialized");
    }
}

#[no_mangle]
pub extern fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 {
    let ptr = __rust_allocate(size, align);
    unsafe {
        ptr::write_bytes(ptr, 0, size);
    }
    ptr
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, size: usize, align: usize) {
    if let Some(ref mut heap) = *HEAP.lock() {
        unsafe { heap.deallocate(ptr, size, align) };
    } else {
        panic!("__rust_deallocate: heap not initialized");
    }
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, size: usize,
    _new_size: usize, _align: usize) -> usize
{
    size
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, size: usize, new_size: usize,
                                align: usize) -> *mut u8 {
    use core::{ptr, cmp};

    // from: https://github.com/rust-lang/rust/blob/
    //     c66d2380a810c9a2b3dbb4f93a830b101ee49cc2/
    //     src/liballoc_system/lib.rs#L98-L101

    let new_ptr = __rust_allocate(new_size, align);
    unsafe { ptr::copy(ptr, new_ptr, cmp::min(size, new_size)) };
    __rust_deallocate(ptr, size, align);
    new_ptr
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

//! Handles translation of callees as well as other call-related
//! things.  Callees are a superset of normal rust values and sometimes
//! have different representations.  In particular, top-level fn items
//! and methods are represented as just a fn ptr and not a full
//! closure.

use attributes;
use common::{self, CrateContext};
use consts;
use declare;
use llvm::{self, ValueRef};
use monomorphize::Instance;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::ty::subst::Substs;
use type_of;

/// Translates a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
///
/// # Parameters
///
/// - `ccx`: the crate context
/// - `instance`: the instance to be instantiated
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                        instance: Instance<'tcx>)
                        -> ValueRef
{
    let tcx = ccx.tcx();

    debug!("get_fn(instance={:?})", instance);

    assert!(!instance.substs.needs_infer());
    assert!(!instance.substs.has_escaping_regions());
    assert!(!instance.substs.has_param_types());

    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
        return llfn;
    }

    let sym = tcx.symbol_name(instance);
    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);

    // Create a fn pointer with the substituted signature.
    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
    let llptrty = type_of::type_of(ccx, fn_ptr_ty);

    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
        // This is subtle and surprising, but sometimes we have to bitcast
        // the resulting fn pointer.  The reason has to do with external
        // functions.  If you have two crates that both bind the same C
        // library, they may not use precisely the same types: for
        // example, they will probably each declare their own structs,
        // which are distinct types from LLVM's point of view (nominal
        // types).
        //
        // Now, if those two crates are linked into an application, and
        // they contain inlined code, you can wind up with a situation
        // where both of those functions wind up being loaded into this
        // application simultaneously. In that case, the same function
        // (from LLVM's point of view) requires two types. But of course
        // LLVM won't allow one function to have two types.
        //
        // What we currently do, therefore, is declare the function with
        // one of the two types (whichever happens to come first) and then
        // bitcast as needed when the function is referenced to make sure
        // it has the type we expect.
        //
        // This can occur on either a crate-local or crate-external
        // reference. It also occurs when testing libcore and in some
        // other weird situations. Annoying.
        if common::val_ty(llfn) != llptrty {
            debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
            consts::ptrcast(llfn, llptrty)
        } else {
            debug!("get_fn: not casting pointer!");
            llfn
        }
    } else {
        let llfn = declare::declare_fn(ccx, &sym, fn_ty);
        assert_eq!(common::val_ty(llfn), llptrty);
        debug!("get_fn: not casting pointer!");

        if common::is_inline_instance(tcx, &instance) {
            attributes::inline(llfn, attributes::InlineAttr::Hint);
        }
        let attrs = instance.def.attrs(ccx.tcx());
        attributes::from_fn_attrs(ccx, &attrs, llfn);

        let instance_def_id = instance.def_id();

        // Perhaps questionable, but we assume that anything defined
        // *in Rust code* may unwind. Foreign items like `extern "C" {
        // fn foo(); }` are assumed not to unwind **unless** they have
        // a `#[unwind]` attribute.
        if !tcx.is_foreign_item(instance_def_id) {
            attributes::unwind(llfn, true);
        }

        // Apply an appropriate linkage/visibility value to our item that we
        // just declared.
        //
        // This is sort of subtle. Inside our codegen unit we started off
        // compilation by predefining all our own `TransItem` instances. That
        // is, everything we're translating ourselves is already defined. That
        // means that anything we're actually translating ourselves will have
        // hit the above branch in `get_declared_value`. As a result, we're
        // guaranteed here that we're declaring a symbol that won't get defined,
        // or in other words we're referencing a foreign value.
        //
        // So because this is a foreign value we blanket apply an external
        // linkage directive because it's coming from a different object file.
        // The visibility here is where it gets tricky. This symbol could be
        // referencing some foreign crate or foreign library (an `extern`
        // block) in which case we want to leave the default visibility. We may
        // also, though, have multiple codegen units.
        //
        // In the situation of multiple codegen units this function may be
        // referencing a function from another codegen unit. If we're
        // indeed referencing a symbol in another codegen unit then we're in one
        // of two cases:
        //
        //  * This is a symbol defined in a foreign crate and we're just
        //    monomorphizing in another codegen unit. In this case this symbols
        //    is for sure not exported, so both codegen units will be using
        //    hidden visibility. Hence, we apply a hidden visibility here.
        //
        //  * This is a symbol defined in our local crate. If the symbol in the
        //    other codegen unit is also not exported then like with the foreign
        //    case we apply a hidden visibility. If the symbol is exported from
        //    the foreign object file, however, then we leave this at the
        //    default visibility as we'll just import it naturally.
        unsafe {
            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);

            if ccx.tcx().is_translated_function(instance_def_id) {
                if instance_def_id.is_local() {
                    if !ccx.tcx().is_exported_symbol(instance_def_id) {
                        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                    }
                } else {
                    llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                }
            }
        }

        // FIXME(#42293) we should actually track this, but fails too many tests
        // today.
        tcx.dep_graph.with_ignore(|| {
            if ccx.use_dll_storage_attrs() &&
                tcx.is_dllimport_foreign_item(instance_def_id)
            {
                unsafe {
                    llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
                }
            }
        });
        llfn
    };

    ccx.instances().borrow_mut().insert(instance, llfn);

    llfn
}

pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    def_id: DefId,
                                    substs: &'tcx Substs<'tcx>)
                                    -> ValueRef
{
    get_fn(
        ccx,
        ty::Instance::resolve(
            ccx.tcx(),
            ty::ParamEnv::empty(traits::Reveal::All),
            def_id,
            substs,)
        .unwrap()
    )
}
<commit_msg>weird formatting<commit_after>// Copyright 2012 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.

//! Handles translation of callees as well as other call-related
//! things.  Callees are a superset of normal rust values and sometimes
//! have different representations.  In particular, top-level fn items
//! and methods are represented as just a fn ptr and not a full
//! closure.

use attributes;
use common::{self, CrateContext};
use consts;
use declare;
use llvm::{self, ValueRef};
use monomorphize::Instance;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
use rustc::traits;
use rustc::ty::subst::Substs;
use type_of;

/// Translates a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
///
/// # Parameters
///
/// - `ccx`: the crate context
/// - `instance`: the instance to be instantiated
pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                        instance: Instance<'tcx>)
                        -> ValueRef
{
    let tcx = ccx.tcx();

    debug!("get_fn(instance={:?})", instance);

    assert!(!instance.substs.needs_infer());
    assert!(!instance.substs.has_escaping_regions());
    assert!(!instance.substs.has_param_types());

    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
    if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
        return llfn;
    }

    let sym = tcx.symbol_name(instance);
    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);

    // Create a fn pointer with the substituted signature.
    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
    let llptrty = type_of::type_of(ccx, fn_ptr_ty);

    let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
        // This is subtle and surprising, but sometimes we have to bitcast
        // the resulting fn pointer.  The reason has to do with external
        // functions.  If you have two crates that both bind the same C
        // library, they may not use precisely the same types: for
        // example, they will probably each declare their own structs,
        // which are distinct types from LLVM's point of view (nominal
        // types).
        //
        // Now, if those two crates are linked into an application, and
        // they contain inlined code, you can wind up with a situation
        // where both of those functions wind up being loaded into this
        // application simultaneously. In that case, the same function
        // (from LLVM's point of view) requires two types. But of course
        // LLVM won't allow one function to have two types.
        //
        // What we currently do, therefore, is declare the function with
        // one of the two types (whichever happens to come first) and then
        // bitcast as needed when the function is referenced to make sure
        // it has the type we expect.
        //
        // This can occur on either a crate-local or crate-external
        // reference. It also occurs when testing libcore and in some
        // other weird situations. Annoying.
        if common::val_ty(llfn) != llptrty {
            debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
            consts::ptrcast(llfn, llptrty)
        } else {
            debug!("get_fn: not casting pointer!");
            llfn
        }
    } else {
        let llfn = declare::declare_fn(ccx, &sym, fn_ty);
        assert_eq!(common::val_ty(llfn), llptrty);
        debug!("get_fn: not casting pointer!");

        if common::is_inline_instance(tcx, &instance) {
            attributes::inline(llfn, attributes::InlineAttr::Hint);
        }
        let attrs = instance.def.attrs(ccx.tcx());
        attributes::from_fn_attrs(ccx, &attrs, llfn);

        let instance_def_id = instance.def_id();

        // Perhaps questionable, but we assume that anything defined
        // *in Rust code* may unwind. Foreign items like `extern "C" {
        // fn foo(); }` are assumed not to unwind **unless** they have
        // a `#[unwind]` attribute.
        if !tcx.is_foreign_item(instance_def_id) {
            attributes::unwind(llfn, true);
        }

        // Apply an appropriate linkage/visibility value to our item that we
        // just declared.
        //
        // This is sort of subtle. Inside our codegen unit we started off
        // compilation by predefining all our own `TransItem` instances. That
        // is, everything we're translating ourselves is already defined. That
        // means that anything we're actually translating ourselves will have
        // hit the above branch in `get_declared_value`. As a result, we're
        // guaranteed here that we're declaring a symbol that won't get defined,
        // or in other words we're referencing a foreign value.
        //
        // So because this is a foreign value we blanket apply an external
        // linkage directive because it's coming from a different object file.
        // The visibility here is where it gets tricky. This symbol could be
        // referencing some foreign crate or foreign library (an `extern`
        // block) in which case we want to leave the default visibility. We may
        // also, though, have multiple codegen units.
        //
        // In the situation of multiple codegen units this function may be
        // referencing a function from another codegen unit. If we're
        // indeed referencing a symbol in another codegen unit then we're in one
        // of two cases:
        //
        //  * This is a symbol defined in a foreign crate and we're just
        //    monomorphizing in another codegen unit. In this case this symbols
        //    is for sure not exported, so both codegen units will be using
        //    hidden visibility. Hence, we apply a hidden visibility here.
        //
        //  * This is a symbol defined in our local crate. If the symbol in the
        //    other codegen unit is also not exported then like with the foreign
        //    case we apply a hidden visibility. If the symbol is exported from
        //    the foreign object file, however, then we leave this at the
        //    default visibility as we'll just import it naturally.
        unsafe {
            llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);

            if ccx.tcx().is_translated_function(instance_def_id) {
                if instance_def_id.is_local() {
                    if !ccx.tcx().is_exported_symbol(instance_def_id) {
                        llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                    }
                } else {
                    llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                }
            }
        }

        // FIXME(#42293) we should actually track this, but fails too many tests
        // today.
        tcx.dep_graph.with_ignore(|| {
            if ccx.use_dll_storage_attrs() &&
                tcx.is_dllimport_foreign_item(instance_def_id)
            {
                unsafe {
                    llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport);
                }
            }
        });
        llfn
    };

    ccx.instances().borrow_mut().insert(instance, llfn);

    llfn
}

pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    def_id: DefId,
                                    substs: &'tcx Substs<'tcx>)
                                    -> ValueRef
{
    get_fn(
        ccx,
        ty::Instance::resolve(
            ccx.tcx(),
            ty::ParamEnv::empty(traits::Reveal::All),
            def_id,
            substs,
        ).unwrap()
    )
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate.
//! It has to be run really early, before transformations like inlining, because
//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part
//! of MIR building, and only after this pass we think of the program has having the
//! normal MIR semantics.

use syntax_pos::Span;
use syntax::ast::NodeId;
use rustc::ty::{self, TyCtxt, RegionKind};
use rustc::hir;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
use rustc::middle::region::CodeExtent;

pub struct AddValidation;

/// Determine the "context" of the lval: Mutability and region.
fn lval_context<'a, 'tcx, D>(
    lval: &Lvalue<'tcx>,
    local_decls: &D,
    tcx: TyCtxt<'a, 'tcx, 'tcx>
) -> (Option<CodeExtent>, hir::Mutability)
    where D: HasLocalDecls<'tcx>
{
    use rustc::mir::Lvalue::*;

    match *lval {
        Local { .. } => (None, hir::MutMutable),
        Static(_) => (None, hir::MutImmutable),
        Projection(ref proj) => {
            match proj.elem {
                ProjectionElem::Deref => {
                    // Computing the inside the recursion makes this quadratic.
                    // We don't expect deep paths though.
                    let ty = proj.base.ty(local_decls, tcx).to_ty(tcx);
                    // A Deref projection may restrict the context, this depends on the type
                    // being deref'd.
                    let context = match ty.sty {
                        ty::TyRef(re, tam) => {
                            let re = match re {
                                &RegionKind::ReScope(ce) => Some(ce),
                                &RegionKind::ReErased =>
                                    bug!("AddValidation pass must be run before erasing lifetimes"),
                                _ => None
                            };
                            (re, tam.mutbl)
                        }
                        ty::TyRawPtr(_) =>
                            // There is no guarantee behind even a mutable raw pointer,
                            // no write locks are acquired there, so we also don't want to
                            // release any.
                            (None, hir::MutImmutable),
                        ty::TyAdt(adt, _) if adt.is_box() => (None, hir::MutMutable),
                        _ => bug!("Deref on a non-pointer type {:?}", ty),
                    };
                    // "Intersect" this restriction with proj.base.
                    if let (Some(_), hir::MutImmutable) = context {
                        // This is already as restricted as it gets, no need to even recurse
                        context
                    } else {
                        let base_context = lval_context(&proj.base, local_decls, tcx);
                        // The region of the outermost Deref is always most restrictive.
                        let re = context.0.or(base_context.0);
                        let mutbl = context.1.and(base_context.1);
                        (re, mutbl)
                    }

                }
                _ => lval_context(&proj.base, local_decls, tcx),
            }
        }
    }
}

/// Check if this function contains an unsafe block or is an unsafe function.
fn fn_contains_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource) -> bool {
    use rustc::hir::intravisit::{self, Visitor};
    use rustc::hir::map::Node;

    fn block_is_unsafe(block: &hir::Block) -> bool {
        use rustc::hir::BlockCheckMode::*;

        match block.rules {
            UnsafeBlock(_) | PushUnsafeBlock(_) => true,
            // For PopUnsafeBlock, we don't actually know -- but we will always also check all
            // parent blocks, so we can safely declare the PopUnsafeBlock to not be unsafe.
            DefaultBlock | PopUnsafeBlock(_) => false,
        }
    }

    let fn_node_id = match src {
        MirSource::Fn(node_id) => node_id,
        _ => return false, // only functions can have unsafe
    };

    struct FindUnsafe<'b, 'tcx> where 'tcx : 'b {
        map: &'b hir::map::Map<'tcx>,
        found_unsafe: bool,
    }
    let mut finder = FindUnsafe { map: &tcx.hir, found_unsafe: false };
    // Run the visitor on the NodeId we got.  Seems like there is no uniform way to do that.
    match tcx.hir.find(fn_node_id) {
        Some(Node::NodeItem(item)) => finder.visit_item(item),
        Some(Node::NodeImplItem(item)) => finder.visit_impl_item(item),
        Some(Node::NodeExpr(item)) => {
            // This is a closure.
            // We also have to walk up the parents and check that there is no unsafe block
            // there.
            let mut cur = fn_node_id;
            loop {
                // Go further upwards.
                let parent = tcx.hir.get_parent_node(cur);
                if cur == parent {
                    break;
                }
                cur = parent;
                // Check if this is a a block
                match tcx.hir.find(cur) {
                    Some(Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block), ..})) => {
                        if block_is_unsafe(&*block) {
                            // Found an unsafe block, we can bail out here.
                            return true;
                        }
                    }
                    _ => {},
                }
            }
            // Finally, visit the closure itself.
            finder.visit_expr(item);
        }
        Some(Node::NodeStructCtor(_)) => {
            // Auto-generated tuple struct ctor.  Cannot contain unsafe code.
            return false;
        },
        Some(_) | None =>
            bug!("Expected function, method or closure, found {}",
                 tcx.hir.node_to_string(fn_node_id)),
    };

    impl<'b, 'tcx> Visitor<'tcx> for FindUnsafe<'b, 'tcx> {
        fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
            intravisit::NestedVisitorMap::OnlyBodies(self.map)
        }

        fn visit_fn(&mut self, fk: intravisit::FnKind<'tcx>, fd: &'tcx hir::FnDecl,
                    b: hir::BodyId, s: Span, id: NodeId)
        {
            assert!(!self.found_unsafe, "We should never see a fn when we already saw unsafe");
            let is_unsafe = match fk {
                intravisit::FnKind::ItemFn(_, _, unsafety, ..) => unsafety == hir::Unsafety::Unsafe,
                intravisit::FnKind::Method(_, sig, ..) => sig.unsafety == hir::Unsafety::Unsafe,
                intravisit::FnKind::Closure(_) => false,
            };
            if is_unsafe {
                // This is unsafe, and we are done.
                self.found_unsafe = true;
            } else {
                // Go on searching.
                intravisit::walk_fn(self, fk, fd, b, s, id)
            }
        }

        fn visit_block(&mut self, b: &'tcx hir::Block) {
            if self.found_unsafe { return; } // short-circuit

            if block_is_unsafe(b) {
                // We found an unsafe block.  We can stop searching.
                self.found_unsafe = true;
            } else {
                // No unsafe block here, go on searching.
                intravisit::walk_block(self, b);
            }
        }
    }

    finder.found_unsafe
}

impl MirPass for AddValidation {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          src: MirSource,
                          mir: &mut Mir<'tcx>)
    {
        let emit_validate = tcx.sess.opts.debugging_opts.mir_emit_validate;
        if emit_validate == 0 {
            return;
        }
        let restricted_validation = emit_validate == 1 && fn_contains_unsafe(tcx, src);
        let local_decls = mir.local_decls.clone(); // FIXME: Find a way to get rid of this clone.

        // Convert an lvalue to a validation operand.
        let lval_to_operand = |lval: Lvalue<'tcx>| -> ValidationOperand<'tcx, Lvalue<'tcx>> {
            let (re, mutbl) = lval_context(&lval, &local_decls, tcx);
            let ty = lval.ty(&local_decls, tcx).to_ty(tcx);
            ValidationOperand { lval, ty, re, mutbl }
        };

        // Emit an Acquire at the beginning of the given block.  If we are in restricted emission
        // mode (mir_emit_validate=1), also emit a Release immediately after the Acquire.
        let emit_acquire = |block: &mut BasicBlockData<'tcx>, source_info, operands: Vec<_>| {
            if operands.len() == 0 {
                return; // Nothing to do
            }
            // Emit the release first, to avoid cloning if we do not emit it
            if restricted_validation {
                let release_stmt = Statement {
                    source_info,
                    kind: StatementKind::Validate(ValidationOp::Release, operands.clone()),
                };
                block.statements.insert(0, release_stmt);
            }
            // Now, the acquire
            let acquire_stmt = Statement {
                source_info,
                kind: StatementKind::Validate(ValidationOp::Acquire, operands),
            };
            block.statements.insert(0, acquire_stmt);
        };

        // PART 1
        // Add an AcquireValid at the beginning of the start block.
        {
            let source_info = SourceInfo {
                scope: ARGUMENT_VISIBILITY_SCOPE,
                span: mir.span, // FIXME: Consider using just the span covering the function
                                // argument declaration.
            };
            // Gather all arguments, skip return value.
            let operands = mir.local_decls.iter_enumerated().skip(1).take(mir.arg_count)
                    .map(|(local, _)| lval_to_operand(Lvalue::Local(local))).collect();
            emit_acquire(&mut mir.basic_blocks_mut()[START_BLOCK], source_info, operands);
        }

        // PART 2
        // Add ReleaseValid/AcquireValid around function call terminators.  We don't use a visitor
        // because we need to access the block that a Call jumps to.
        let mut returns : Vec<(SourceInfo, Lvalue<'tcx>, BasicBlock)> = Vec::new();
        for block_data in mir.basic_blocks_mut() {
            match block_data.terminator {
                Some(Terminator { kind: TerminatorKind::Call { ref args, ref destination, .. },
                                  source_info }) => {
                    // Before the call: Release all arguments
                    if !restricted_validation {
                        let release_stmt = Statement {
                            source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                args.iter().filter_map(|op| {
                                    match op {
                                        &Operand::Consume(ref lval) =>
                                            Some(lval_to_operand(lval.clone())),
                                        &Operand::Constant(..) => { None },
                                    }
                                }).collect())
                        };
                        block_data.statements.push(release_stmt);
                    }
                    // Remember the return destination for later
                    if let &Some(ref destination) = destination {
                        returns.push((source_info, destination.0.clone(), destination.1));
                    }
                }
                Some(Terminator { kind: TerminatorKind::Drop { location: ref lval, .. },
                                  source_info }) |
                Some(Terminator { kind: TerminatorKind::DropAndReplace { location: ref lval, .. },
                                  source_info }) => {
                    // Before the call: Release all arguments
                    if !restricted_validation {
                        let release_stmt = Statement {
                            source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                    vec![lval_to_operand(lval.clone())]),
                        };
                        block_data.statements.push(release_stmt);
                    }
                    // drop doesn't return anything, so we need no acquire.
                }
                _ => {
                    // Not a block ending in a Call -> ignore.
                }
            }
        }
        // Now we go over the returns we collected to acquire the return values.
        for (source_info, dest_lval, dest_block) in returns {
            emit_acquire(
                &mut mir.basic_blocks_mut()[dest_block],
                source_info,
                vec![lval_to_operand(dest_lval)]
            );
        }

        if restricted_validation {
            // No part 3 for us.
            return;
        }

        // PART 3
        // Add ReleaseValid/AcquireValid around Ref and Cast.  Again an iterator does not seem very
        // suited as we need to add new statements before and after each Ref.
        for block_data in mir.basic_blocks_mut() {
            // We want to insert statements around Ref commands as we iterate.  To this end, we
            // iterate backwards using indices.
            for i in (0..block_data.statements.len()).rev() {
                match block_data.statements[i].kind {
                    // When the borrow of this ref expires, we need to recover validation.
                    StatementKind::Assign(_, Rvalue::Ref(_, _, _)) => {
                        // Due to a lack of NLL; we can't capture anything directly here.
                        // Instead, we have to re-match and clone there.
                        let (dest_lval, re, src_lval) = match block_data.statements[i].kind {
                            StatementKind::Assign(ref dest_lval,
                                                  Rvalue::Ref(re, _, ref src_lval)) => {
                                (dest_lval.clone(), re, src_lval.clone())
                            },
                            _ => bug!("We already matched this."),
                        };
                        // So this is a ref, and we got all the data we wanted.
                        // Do an acquire of the result -- but only what it points to, so add a Deref
                        // projection.
                        let dest_lval = Projection { base: dest_lval, elem: ProjectionElem::Deref };
                        let dest_lval = Lvalue::Projection(Box::new(dest_lval));
                        let acquire_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Acquire,
                                    vec![lval_to_operand(dest_lval)]),
                        };
                        block_data.statements.insert(i+1, acquire_stmt);

                        // The source is released until the region of the borrow ends.
                        let op = match re {
                            &RegionKind::ReScope(ce) => ValidationOp::Suspend(ce),
                            &RegionKind::ReErased =>
                                bug!("AddValidation pass must be run before erasing lifetimes"),
                            _ => ValidationOp::Release,
                        };
                        let release_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(op, vec![lval_to_operand(src_lval)]),
                        };
                        block_data.statements.insert(i, release_stmt);
                    }
                    // Casts can change what validation does (e.g. unsizing)
                    StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Consume(_), _))
                        if kind != CastKind::Misc =>
                    {
                        // Due to a lack of NLL; we can't capture anything directly here.
                        // Instead, we have to re-match and clone there.
                        let (dest_lval, src_lval) = match block_data.statements[i].kind {
                            StatementKind::Assign(ref dest_lval,
                                    Rvalue::Cast(_, Operand::Consume(ref src_lval), _)) =>
                            {
                                (dest_lval.clone(), src_lval.clone())
                            },
                            _ => bug!("We already matched this."),
                        };

                        // Acquire of the result
                        let acquire_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Acquire,
                                    vec![lval_to_operand(dest_lval)]),
                        };
                        block_data.statements.insert(i+1, acquire_stmt);

                        // Release of the input
                        let release_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                                            vec![lval_to_operand(src_lval)]),
                        };
                        block_data.statements.insert(i, release_stmt);
                    }
                    _ => {},
                }
            }
        }
    }
}
<commit_msg>handle trait items as well<commit_after>// Copyright 2015 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.

//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate.
//! It has to be run really early, before transformations like inlining, because
//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part
//! of MIR building, and only after this pass we think of the program has having the
//! normal MIR semantics.

use syntax_pos::Span;
use syntax::ast::NodeId;
use rustc::ty::{self, TyCtxt, RegionKind};
use rustc::hir;
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
use rustc::middle::region::CodeExtent;

pub struct AddValidation;

/// Determine the "context" of the lval: Mutability and region.
fn lval_context<'a, 'tcx, D>(
    lval: &Lvalue<'tcx>,
    local_decls: &D,
    tcx: TyCtxt<'a, 'tcx, 'tcx>
) -> (Option<CodeExtent>, hir::Mutability)
    where D: HasLocalDecls<'tcx>
{
    use rustc::mir::Lvalue::*;

    match *lval {
        Local { .. } => (None, hir::MutMutable),
        Static(_) => (None, hir::MutImmutable),
        Projection(ref proj) => {
            match proj.elem {
                ProjectionElem::Deref => {
                    // Computing the inside the recursion makes this quadratic.
                    // We don't expect deep paths though.
                    let ty = proj.base.ty(local_decls, tcx).to_ty(tcx);
                    // A Deref projection may restrict the context, this depends on the type
                    // being deref'd.
                    let context = match ty.sty {
                        ty::TyRef(re, tam) => {
                            let re = match re {
                                &RegionKind::ReScope(ce) => Some(ce),
                                &RegionKind::ReErased =>
                                    bug!("AddValidation pass must be run before erasing lifetimes"),
                                _ => None
                            };
                            (re, tam.mutbl)
                        }
                        ty::TyRawPtr(_) =>
                            // There is no guarantee behind even a mutable raw pointer,
                            // no write locks are acquired there, so we also don't want to
                            // release any.
                            (None, hir::MutImmutable),
                        ty::TyAdt(adt, _) if adt.is_box() => (None, hir::MutMutable),
                        _ => bug!("Deref on a non-pointer type {:?}", ty),
                    };
                    // "Intersect" this restriction with proj.base.
                    if let (Some(_), hir::MutImmutable) = context {
                        // This is already as restricted as it gets, no need to even recurse
                        context
                    } else {
                        let base_context = lval_context(&proj.base, local_decls, tcx);
                        // The region of the outermost Deref is always most restrictive.
                        let re = context.0.or(base_context.0);
                        let mutbl = context.1.and(base_context.1);
                        (re, mutbl)
                    }

                }
                _ => lval_context(&proj.base, local_decls, tcx),
            }
        }
    }
}

/// Check if this function contains an unsafe block or is an unsafe function.
fn fn_contains_unsafe<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource) -> bool {
    use rustc::hir::intravisit::{self, Visitor};
    use rustc::hir::map::Node;

    fn block_is_unsafe(block: &hir::Block) -> bool {
        use rustc::hir::BlockCheckMode::*;

        match block.rules {
            UnsafeBlock(_) | PushUnsafeBlock(_) => true,
            // For PopUnsafeBlock, we don't actually know -- but we will always also check all
            // parent blocks, so we can safely declare the PopUnsafeBlock to not be unsafe.
            DefaultBlock | PopUnsafeBlock(_) => false,
        }
    }

    let fn_node_id = match src {
        MirSource::Fn(node_id) => node_id,
        _ => return false, // only functions can have unsafe
    };

    struct FindUnsafe<'b, 'tcx> where 'tcx : 'b {
        map: &'b hir::map::Map<'tcx>,
        found_unsafe: bool,
    }
    let mut finder = FindUnsafe { map: &tcx.hir, found_unsafe: false };
    // Run the visitor on the NodeId we got.  Seems like there is no uniform way to do that.
    match tcx.hir.find(fn_node_id) {
        Some(Node::NodeItem(item)) => finder.visit_item(item),
        Some(Node::NodeImplItem(item)) => finder.visit_impl_item(item),
        Some(Node::NodeTraitItem(item)) => finder.visit_trait_item(item),
        Some(Node::NodeExpr(item)) => {
            // This is a closure.
            // We also have to walk up the parents and check that there is no unsafe block
            // there.
            let mut cur = fn_node_id;
            loop {
                // Go further upwards.
                let parent = tcx.hir.get_parent_node(cur);
                if cur == parent {
                    break;
                }
                cur = parent;
                // Check if this is a a block
                match tcx.hir.find(cur) {
                    Some(Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block), ..})) => {
                        if block_is_unsafe(&*block) {
                            // Found an unsafe block, we can bail out here.
                            return true;
                        }
                    }
                    _ => {},
                }
            }
            // Finally, visit the closure itself.
            finder.visit_expr(item);
        }
        Some(Node::NodeStructCtor(_)) => {
            // Auto-generated tuple struct ctor.  Cannot contain unsafe code.
            return false;
        },
        Some(_) | None =>
            bug!("Expected function, method or closure, found {}",
                 tcx.hir.node_to_string(fn_node_id)),
    };

    impl<'b, 'tcx> Visitor<'tcx> for FindUnsafe<'b, 'tcx> {
        fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
            intravisit::NestedVisitorMap::OnlyBodies(self.map)
        }

        fn visit_fn(&mut self, fk: intravisit::FnKind<'tcx>, fd: &'tcx hir::FnDecl,
                    b: hir::BodyId, s: Span, id: NodeId)
        {
            assert!(!self.found_unsafe, "We should never see a fn when we already saw unsafe");
            let is_unsafe = match fk {
                intravisit::FnKind::ItemFn(_, _, unsafety, ..) => unsafety == hir::Unsafety::Unsafe,
                intravisit::FnKind::Method(_, sig, ..) => sig.unsafety == hir::Unsafety::Unsafe,
                intravisit::FnKind::Closure(_) => false,
            };
            if is_unsafe {
                // This is unsafe, and we are done.
                self.found_unsafe = true;
            } else {
                // Go on searching.
                intravisit::walk_fn(self, fk, fd, b, s, id)
            }
        }

        fn visit_block(&mut self, b: &'tcx hir::Block) {
            if self.found_unsafe { return; } // short-circuit

            if block_is_unsafe(b) {
                // We found an unsafe block.  We can stop searching.
                self.found_unsafe = true;
            } else {
                // No unsafe block here, go on searching.
                intravisit::walk_block(self, b);
            }
        }
    }

    finder.found_unsafe
}

impl MirPass for AddValidation {
    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          src: MirSource,
                          mir: &mut Mir<'tcx>)
    {
        let emit_validate = tcx.sess.opts.debugging_opts.mir_emit_validate;
        if emit_validate == 0 {
            return;
        }
        let restricted_validation = emit_validate == 1 && fn_contains_unsafe(tcx, src);
        let local_decls = mir.local_decls.clone(); // FIXME: Find a way to get rid of this clone.

        // Convert an lvalue to a validation operand.
        let lval_to_operand = |lval: Lvalue<'tcx>| -> ValidationOperand<'tcx, Lvalue<'tcx>> {
            let (re, mutbl) = lval_context(&lval, &local_decls, tcx);
            let ty = lval.ty(&local_decls, tcx).to_ty(tcx);
            ValidationOperand { lval, ty, re, mutbl }
        };

        // Emit an Acquire at the beginning of the given block.  If we are in restricted emission
        // mode (mir_emit_validate=1), also emit a Release immediately after the Acquire.
        let emit_acquire = |block: &mut BasicBlockData<'tcx>, source_info, operands: Vec<_>| {
            if operands.len() == 0 {
                return; // Nothing to do
            }
            // Emit the release first, to avoid cloning if we do not emit it
            if restricted_validation {
                let release_stmt = Statement {
                    source_info,
                    kind: StatementKind::Validate(ValidationOp::Release, operands.clone()),
                };
                block.statements.insert(0, release_stmt);
            }
            // Now, the acquire
            let acquire_stmt = Statement {
                source_info,
                kind: StatementKind::Validate(ValidationOp::Acquire, operands),
            };
            block.statements.insert(0, acquire_stmt);
        };

        // PART 1
        // Add an AcquireValid at the beginning of the start block.
        {
            let source_info = SourceInfo {
                scope: ARGUMENT_VISIBILITY_SCOPE,
                span: mir.span, // FIXME: Consider using just the span covering the function
                                // argument declaration.
            };
            // Gather all arguments, skip return value.
            let operands = mir.local_decls.iter_enumerated().skip(1).take(mir.arg_count)
                    .map(|(local, _)| lval_to_operand(Lvalue::Local(local))).collect();
            emit_acquire(&mut mir.basic_blocks_mut()[START_BLOCK], source_info, operands);
        }

        // PART 2
        // Add ReleaseValid/AcquireValid around function call terminators.  We don't use a visitor
        // because we need to access the block that a Call jumps to.
        let mut returns : Vec<(SourceInfo, Lvalue<'tcx>, BasicBlock)> = Vec::new();
        for block_data in mir.basic_blocks_mut() {
            match block_data.terminator {
                Some(Terminator { kind: TerminatorKind::Call { ref args, ref destination, .. },
                                  source_info }) => {
                    // Before the call: Release all arguments
                    if !restricted_validation {
                        let release_stmt = Statement {
                            source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                args.iter().filter_map(|op| {
                                    match op {
                                        &Operand::Consume(ref lval) =>
                                            Some(lval_to_operand(lval.clone())),
                                        &Operand::Constant(..) => { None },
                                    }
                                }).collect())
                        };
                        block_data.statements.push(release_stmt);
                    }
                    // Remember the return destination for later
                    if let &Some(ref destination) = destination {
                        returns.push((source_info, destination.0.clone(), destination.1));
                    }
                }
                Some(Terminator { kind: TerminatorKind::Drop { location: ref lval, .. },
                                  source_info }) |
                Some(Terminator { kind: TerminatorKind::DropAndReplace { location: ref lval, .. },
                                  source_info }) => {
                    // Before the call: Release all arguments
                    if !restricted_validation {
                        let release_stmt = Statement {
                            source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                    vec![lval_to_operand(lval.clone())]),
                        };
                        block_data.statements.push(release_stmt);
                    }
                    // drop doesn't return anything, so we need no acquire.
                }
                _ => {
                    // Not a block ending in a Call -> ignore.
                }
            }
        }
        // Now we go over the returns we collected to acquire the return values.
        for (source_info, dest_lval, dest_block) in returns {
            emit_acquire(
                &mut mir.basic_blocks_mut()[dest_block],
                source_info,
                vec![lval_to_operand(dest_lval)]
            );
        }

        if restricted_validation {
            // No part 3 for us.
            return;
        }

        // PART 3
        // Add ReleaseValid/AcquireValid around Ref and Cast.  Again an iterator does not seem very
        // suited as we need to add new statements before and after each Ref.
        for block_data in mir.basic_blocks_mut() {
            // We want to insert statements around Ref commands as we iterate.  To this end, we
            // iterate backwards using indices.
            for i in (0..block_data.statements.len()).rev() {
                match block_data.statements[i].kind {
                    // When the borrow of this ref expires, we need to recover validation.
                    StatementKind::Assign(_, Rvalue::Ref(_, _, _)) => {
                        // Due to a lack of NLL; we can't capture anything directly here.
                        // Instead, we have to re-match and clone there.
                        let (dest_lval, re, src_lval) = match block_data.statements[i].kind {
                            StatementKind::Assign(ref dest_lval,
                                                  Rvalue::Ref(re, _, ref src_lval)) => {
                                (dest_lval.clone(), re, src_lval.clone())
                            },
                            _ => bug!("We already matched this."),
                        };
                        // So this is a ref, and we got all the data we wanted.
                        // Do an acquire of the result -- but only what it points to, so add a Deref
                        // projection.
                        let dest_lval = Projection { base: dest_lval, elem: ProjectionElem::Deref };
                        let dest_lval = Lvalue::Projection(Box::new(dest_lval));
                        let acquire_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Acquire,
                                    vec![lval_to_operand(dest_lval)]),
                        };
                        block_data.statements.insert(i+1, acquire_stmt);

                        // The source is released until the region of the borrow ends.
                        let op = match re {
                            &RegionKind::ReScope(ce) => ValidationOp::Suspend(ce),
                            &RegionKind::ReErased =>
                                bug!("AddValidation pass must be run before erasing lifetimes"),
                            _ => ValidationOp::Release,
                        };
                        let release_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(op, vec![lval_to_operand(src_lval)]),
                        };
                        block_data.statements.insert(i, release_stmt);
                    }
                    // Casts can change what validation does (e.g. unsizing)
                    StatementKind::Assign(_, Rvalue::Cast(kind, Operand::Consume(_), _))
                        if kind != CastKind::Misc =>
                    {
                        // Due to a lack of NLL; we can't capture anything directly here.
                        // Instead, we have to re-match and clone there.
                        let (dest_lval, src_lval) = match block_data.statements[i].kind {
                            StatementKind::Assign(ref dest_lval,
                                    Rvalue::Cast(_, Operand::Consume(ref src_lval), _)) =>
                            {
                                (dest_lval.clone(), src_lval.clone())
                            },
                            _ => bug!("We already matched this."),
                        };

                        // Acquire of the result
                        let acquire_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Acquire,
                                    vec![lval_to_operand(dest_lval)]),
                        };
                        block_data.statements.insert(i+1, acquire_stmt);

                        // Release of the input
                        let release_stmt = Statement {
                            source_info: block_data.statements[i].source_info,
                            kind: StatementKind::Validate(ValidationOp::Release,
                                                            vec![lval_to_operand(src_lval)]),
                        };
                        block_data.statements.insert(i, release_stmt);
                    }
                    _ => {},
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::ffi::CStr;

use super::{Binds, Statement, StatementMetadata};
use crate::mysql::{Mysql, MysqlType, MysqlValue};
use crate::result::QueryResult;
use crate::row::*;

pub struct StatementIterator<'a> {
    stmt: &'a mut Statement,
    output_binds: Binds,
}

#[allow(clippy::should_implement_trait)] // don't neet `Iterator` here
impl<'a> StatementIterator<'a> {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(stmt: &'a mut Statement, types: Vec<Option<MysqlType>>) -> QueryResult<Self> {
        let mut output_binds = if types.iter().any(Option::is_none) {
            let metadata = stmt.metadata()?;
            Binds::from_output_types(types, Some(metadata.fields()))
        } else {
            Binds::from_output_types(types, None)
        };

        stmt.execute_statement(&mut output_binds)?;

        Ok(StatementIterator { stmt, output_binds })
    }

    pub fn map<F, T>(mut self, mut f: F) -> QueryResult<Vec<T>>
    where
        F: FnMut(MysqlRow) -> QueryResult<T>,
    {
        let mut results = Vec::new();
        while let Some(row) = self.next() {
            results.push(f(row?)?);
        }
        Ok(results)
    }

    fn next(&mut self) -> Option<QueryResult<MysqlRow>> {
        match self.stmt.populate_row_buffers(&mut self.output_binds) {
            Ok(Some(())) => Some(Ok(MysqlRow {
                col_idx: 0,
                binds: &mut self.output_binds,
                stmt: &self.stmt,
            })),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

pub struct MysqlRow<'a> {
    col_idx: usize,
    binds: &'a Binds,
    stmt: &'a Statement,
}

impl<'a> Row<Mysql> for MysqlRow<'a> {
    fn take(&mut self) -> Option<MysqlValue<'_>> {
        let current_idx = self.col_idx;
        self.col_idx += 1;
        self.binds.field_data(current_idx)
    }

    fn next_is_null(&self, count: usize) -> bool {
        (0..count).all(|i| self.binds.field_data(self.col_idx + i).is_none())
    }

    fn column_count(&self) -> usize {
        self.binds.len()
    }

    fn column_name(&self) -> Option<&str> {
        let metadata = self
            .stmt
            .metadata()
            .expect("Failed to get result metadata from the mysql backend");
        let field = if self.col_idx == 0 {
            metadata.fields()[0]
        } else {
            metadata.fields()[self.col_idx - 1]
        };
        unsafe {
            Some(CStr::from_ptr(field.name).to_str().expect(
                "Diesel assumes that your mysql database uses the \
                 utf8mb4 encoding. That's not the case if you hit \
                 this error message.",
            ))
        }
    }
}

pub struct NamedStatementIterator<'a> {
    stmt: &'a mut Statement,
    output_binds: Binds,
    metadata: StatementMetadata,
}

#[allow(clippy::should_implement_trait)] // don't need `Iterator` here
impl<'a> NamedStatementIterator<'a> {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(stmt: &'a mut Statement) -> QueryResult<Self> {
        let metadata = stmt.metadata()?;
        let mut output_binds = Binds::from_result_metadata(metadata.fields());

        stmt.execute_statement(&mut output_binds)?;

        Ok(NamedStatementIterator {
            stmt,
            output_binds,
            metadata,
        })
    }

    pub fn map<F, T>(mut self, mut f: F) -> QueryResult<Vec<T>>
    where
        F: FnMut(NamedMysqlRow) -> QueryResult<T>,
    {
        let mut results = Vec::new();
        while let Some(row) = self.next() {
            results.push(f(row?)?);
        }
        Ok(results)
    }

    fn next(&mut self) -> Option<QueryResult<NamedMysqlRow>> {
        match self.stmt.populate_row_buffers(&mut self.output_binds) {
            Ok(Some(())) => Some(Ok(NamedMysqlRow {
                binds: &self.output_binds,
                column_indices: self.metadata.column_indices(),
            })),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

pub struct NamedMysqlRow<'a> {
    binds: &'a Binds,
    column_indices: &'a HashMap<&'a str, usize>,
}

impl<'a> NamedRow<Mysql> for NamedMysqlRow<'a> {
    fn index_of(&self, column_name: &str) -> Option<usize> {
        self.column_indices.get(column_name).cloned()
    }

    fn get_raw_value(&self, idx: usize) -> Option<MysqlValue<'_>> {
        self.binds.field_data(idx)
    }
}
<commit_msg>Fix a off by one error in the mysql row implementation<commit_after>use std::collections::HashMap;
use std::ffi::CStr;

use super::{Binds, Statement, StatementMetadata};
use crate::mysql::{Mysql, MysqlType, MysqlValue};
use crate::result::QueryResult;
use crate::row::*;

pub struct StatementIterator<'a> {
    stmt: &'a mut Statement,
    output_binds: Binds,
}

#[allow(clippy::should_implement_trait)] // don't neet `Iterator` here
impl<'a> StatementIterator<'a> {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(stmt: &'a mut Statement, types: Vec<Option<MysqlType>>) -> QueryResult<Self> {
        let mut output_binds = if types.iter().any(Option::is_none) {
            let metadata = stmt.metadata()?;
            Binds::from_output_types(types, Some(metadata.fields()))
        } else {
            Binds::from_output_types(types, None)
        };

        stmt.execute_statement(&mut output_binds)?;

        Ok(StatementIterator { stmt, output_binds })
    }

    pub fn map<F, T>(mut self, mut f: F) -> QueryResult<Vec<T>>
    where
        F: FnMut(MysqlRow) -> QueryResult<T>,
    {
        let mut results = Vec::new();
        while let Some(row) = self.next() {
            results.push(f(row?)?);
        }
        Ok(results)
    }

    fn next(&mut self) -> Option<QueryResult<MysqlRow>> {
        match self.stmt.populate_row_buffers(&mut self.output_binds) {
            Ok(Some(())) => Some(Ok(MysqlRow {
                col_idx: 0,
                binds: &mut self.output_binds,
                stmt: &self.stmt,
            })),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

pub struct MysqlRow<'a> {
    col_idx: usize,
    binds: &'a Binds,
    stmt: &'a Statement,
}

impl<'a> Row<Mysql> for MysqlRow<'a> {
    fn take(&mut self) -> Option<MysqlValue<'_>> {
        let current_idx = self.col_idx;
        self.col_idx += 1;
        self.binds.field_data(current_idx)
    }

    fn next_is_null(&self, count: usize) -> bool {
        (0..count).all(|i| self.binds.field_data(self.col_idx + i).is_none())
    }

    fn column_count(&self) -> usize {
        self.binds.len()
    }

    fn column_name(&self) -> Option<&str> {
        let metadata = self
            .stmt
            .metadata()
            .expect("Failed to get result metadata from the mysql backend");
        let field = metadata.fields()[self.col_idx];
        unsafe {
            Some(CStr::from_ptr(field.name).to_str().expect(
                "Diesel assumes that your mysql database uses the \
                 utf8mb4 encoding. That's not the case if you hit \
                 this error message.",
            ))
        }
    }
}

pub struct NamedStatementIterator<'a> {
    stmt: &'a mut Statement,
    output_binds: Binds,
    metadata: StatementMetadata,
}

#[allow(clippy::should_implement_trait)] // don't need `Iterator` here
impl<'a> NamedStatementIterator<'a> {
    #[allow(clippy::new_ret_no_self)]
    pub fn new(stmt: &'a mut Statement) -> QueryResult<Self> {
        let metadata = stmt.metadata()?;
        let mut output_binds = Binds::from_result_metadata(metadata.fields());

        stmt.execute_statement(&mut output_binds)?;

        Ok(NamedStatementIterator {
            stmt,
            output_binds,
            metadata,
        })
    }

    pub fn map<F, T>(mut self, mut f: F) -> QueryResult<Vec<T>>
    where
        F: FnMut(NamedMysqlRow) -> QueryResult<T>,
    {
        let mut results = Vec::new();
        while let Some(row) = self.next() {
            results.push(f(row?)?);
        }
        Ok(results)
    }

    fn next(&mut self) -> Option<QueryResult<NamedMysqlRow>> {
        match self.stmt.populate_row_buffers(&mut self.output_binds) {
            Ok(Some(())) => Some(Ok(NamedMysqlRow {
                binds: &self.output_binds,
                column_indices: self.metadata.column_indices(),
            })),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        }
    }
}

pub struct NamedMysqlRow<'a> {
    binds: &'a Binds,
    column_indices: &'a HashMap<&'a str, usize>,
}

impl<'a> NamedRow<Mysql> for NamedMysqlRow<'a> {
    fn index_of(&self, column_name: &str) -> Option<usize> {
        self.column_indices.get(column_name).cloned()
    }

    fn get_raw_value(&self, idx: usize) -> Option<MysqlValue<'_>> {
        self.binds.field_data(idx)
    }
}
<|endoftext|>