<commit_before>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&alloc_id.0.to_string(), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(reloc_offset as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<commit_msg>Improve global name for anonymous allocations<commit_after>use std::borrow::Cow;

use rustc::mir::interpret::{
    read_target_uint, AllocId, AllocKind, Allocation, ConstValue, EvalResult, GlobalId, Scalar,
};
use rustc::ty::{Const, LazyConst};
use rustc_mir::interpret::{
    EvalContext, MPlaceTy, Machine, Memory, MemoryKind, OpTy, PlaceTy, Pointer, StackPopCleanup,
};

use cranelift_module::*;

use crate::prelude::*;

#[derive(Default)]
pub struct ConstantCx {
    todo: HashSet<TodoItem>,
    done: HashSet<DataId>,
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
enum TodoItem {
    Alloc(AllocId),
    Static(DefId),
}

impl ConstantCx {
    pub fn finalize<'a, 'tcx: 'a, B: Backend>(
        mut self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        module: &mut Module<B>,
    ) {
        //println!("todo {:?}", self.todo);
        define_all_allocs(tcx, module, &mut self);
        //println!("done {:?}", self.done);
        self.done.clear();
    }
}

pub fn codegen_static<'a, 'tcx: 'a>(ccx: &mut ConstantCx, def_id: DefId) {
    ccx.todo.insert(TodoItem::Static(def_id));
}

pub fn codegen_static_ref<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    static_: &Static<'tcx>,
) -> CPlace<'tcx> {
    let data_id = data_id_for_static(fx.tcx, fx.module, static_.def_id, Linkage::Import);
    cplace_for_dataid(fx, static_.ty, data_id)
}

pub fn trans_promoted<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    promoted: Promoted,
) -> CPlace<'tcx> {
    let const_ = fx
        .tcx
        .const_eval(ParamEnv::reveal_all().and(GlobalId {
            instance: fx.instance,
            promoted: Some(promoted),
        }))
        .unwrap();

    trans_const_place(fx, const_)
}

pub fn trans_constant<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    constant: &Constant<'tcx>,
) -> CValue<'tcx> {
    let const_ = fx.monomorphize(&constant.literal);
    let const_ = force_eval_const(fx, const_);
    trans_const_value(fx, const_)
}

pub fn force_eval_const<'a, 'tcx: 'a>(
    fx: &FunctionCx<'a, 'tcx, impl Backend>,
    const_: &'tcx LazyConst<'tcx>,
) -> Const<'tcx> {
    match *const_ {
        LazyConst::Unevaluated(def_id, ref substs) => {
            let param_env = ParamEnv::reveal_all();
            let instance = Instance::resolve(fx.tcx, param_env, def_id, substs).unwrap();
            let cid = GlobalId {
                instance,
                promoted: None,
            };
            fx.tcx.const_eval(param_env.and(cid)).unwrap()
        }
        LazyConst::Evaluated(const_) => const_,
    }
}

fn trans_const_value<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CValue<'tcx> {
    let ty = fx.monomorphize(&const_.ty);
    let layout = fx.layout_of(ty);
    match ty.sty {
        ty::Bool => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Uint(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as u64 as i64)
        }
        ty::Int(_) => {
            let bits = const_.val.try_to_bits(layout.size).unwrap();
            CValue::const_val(fx, ty, bits as i128 as i64)
        }
        ty::FnDef(def_id, substs) => {
            let func_ref = fx.get_function_ref(
                Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap(),
            );
            let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);
            CValue::ByVal(func_addr, layout)
        }
        _ => trans_const_place(fx, const_).to_cvalue(fx),
    }
}

fn trans_const_place<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    const_: Const<'tcx>,
) -> CPlace<'tcx> {
    // Adapted from https://github.com/rust-lang/rust/pull/53671/files#diff-e0b58bb6712edaa8595ad7237542c958L551
    let result = || -> EvalResult<'tcx, &'tcx Allocation> {
        let mut ecx = EvalContext::new(
            fx.tcx.at(DUMMY_SP),
            ty::ParamEnv::reveal_all(),
            TransPlaceInterpreter,
        );
        ecx.push_stack_frame(
            fx.instance,
            DUMMY_SP,
            fx.mir,
            None,
            StackPopCleanup::None { cleanup: false },
        )
        .unwrap();
        let op = ecx.eval_operand(
            &Operand::Constant(Box::new(Constant {
                span: DUMMY_SP,
                ty: const_.ty,
                user_ty: None,
                literal: fx.tcx.intern_lazy_const(LazyConst::Evaluated(const_)),
            })),
            None,
        )?;
        let ptr = ecx.allocate(op.layout, MemoryKind::Stack);
        ecx.copy_op(op, ptr.into())?;
        let alloc = ecx.memory().get(ptr.to_ptr()?.alloc_id)?;
        Ok(fx.tcx.intern_const_alloc(alloc.clone()))
    };
    let alloc = result().expect("unable to convert ConstValue to Allocation");

    //println!("const value: {:?} allocation: {:?}", value, alloc);
    let alloc_id = fx.tcx.alloc_map.lock().allocate(alloc);
    fx.constants.todo.insert(TodoItem::Alloc(alloc_id));
    let data_id = data_id_for_alloc_id(fx.module, alloc_id);
    cplace_for_dataid(fx, const_.ty, data_id)
}

fn data_id_for_alloc_id<B: Backend>(module: &mut Module<B>, alloc_id: AllocId) -> DataId {
    module
        .declare_data(&format!("__alloc_{}", alloc_id.0), Linkage::Local, false)
        .unwrap()
}

fn data_id_for_static<'a, 'tcx: 'a, B: Backend>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    def_id: DefId,
    linkage: Linkage,
) -> DataId {
    let symbol_name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str();
    let is_mutable = if let ::rustc::hir::Mutability::MutMutable = tcx.is_static(def_id).unwrap() {
        true
    } else {
        !tcx.type_of(def_id)
            .is_freeze(tcx, ParamEnv::reveal_all(), DUMMY_SP)
    };
    module
        .declare_data(&*symbol_name, linkage, is_mutable)
        .unwrap()
}

fn cplace_for_dataid<'a, 'tcx: 'a>(
    fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
    ty: Ty<'tcx>,
    data_id: DataId,
) -> CPlace<'tcx> {
    let local_data_id = fx.module.declare_data_in_func(data_id, &mut fx.bcx.func);
    let global_ptr = fx.bcx.ins().global_value(fx.pointer_type, local_data_id);
    let layout = fx.layout_of(fx.monomorphize(&ty));
    assert!(!layout.is_unsized(), "unsized statics aren't supported");
    CPlace::Addr(global_ptr, None, layout)
}

fn define_all_allocs<'a, 'tcx: 'a, B: Backend + 'a>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    module: &mut Module<B>,
    cx: &mut ConstantCx,
) {
    let memory = Memory::<TransPlaceInterpreter>::new(tcx.at(DUMMY_SP));

    while let Some(todo_item) = pop_set(&mut cx.todo) {
        let (data_id, alloc) = match todo_item {
            TodoItem::Alloc(alloc_id) => {
                //println!("alloc_id {}", alloc_id);
                let data_id = data_id_for_alloc_id(module, alloc_id);
                let alloc = memory.get(alloc_id).unwrap();
                (data_id, alloc)
            }
            TodoItem::Static(def_id) => {
                //println!("static {:?}", def_id);
                let instance = ty::Instance::mono(tcx, def_id);
                let cid = GlobalId {
                    instance,
                    promoted: None,
                };
                let const_ = tcx.const_eval(ParamEnv::reveal_all().and(cid)).unwrap();

                let alloc = match const_.val {
                    ConstValue::ByRef(_alloc_id, alloc, n) if n.bytes() == 0 => alloc,
                    _ => bug!("static const eval returned {:#?}", const_),
                };

                let data_id = data_id_for_static(tcx, module, def_id, Linkage::Export);
                (data_id, alloc)
            }
        };

        //("data_id {}", data_id);
        if cx.done.contains(&data_id) {
            continue;
        }

        let mut data_ctx = DataContext::new();

        data_ctx.define(alloc.bytes.to_vec().into_boxed_slice());

        for &(offset, (_tag, reloc)) in alloc.relocations.iter() {
            let reloc_offset = {
                let endianness = tcx.data_layout.endian;
                let offset = offset.bytes() as usize;
                let ptr_size = tcx.data_layout.pointer_size;
                let bytes = &alloc.bytes[offset..offset + ptr_size.bytes() as usize];
                read_target_uint(endianness, bytes).unwrap()
            };

            let data_id = match tcx.alloc_map.lock().get(reloc).unwrap() {
                AllocKind::Function(instance) => {
                    let func_id = crate::abi::import_function(tcx, module, instance);
                    let local_func_id = module.declare_func_in_data(func_id, &mut data_ctx);
                    data_ctx.write_function_addr(reloc_offset as u32, local_func_id);
                    continue;
                }
                AllocKind::Memory(_) => {
                    cx.todo.insert(TodoItem::Alloc(reloc));
                    data_id_for_alloc_id(module, reloc)
                }
                AllocKind::Static(def_id) => {
                    cx.todo.insert(TodoItem::Static(def_id));
                    data_id_for_static(tcx, module, def_id, Linkage::Import)
                }
            };

            let global_value = module.declare_data_in_data(data_id, &mut data_ctx);
            data_ctx.write_data_addr(reloc_offset as u32, global_value, 0);
        }

        module.define_data(data_id, &data_ctx).unwrap();
        cx.done.insert(data_id);
    }

    assert!(cx.todo.is_empty(), "{:?}", cx.todo);
}

fn pop_set<T: Copy + Eq + ::std::hash::Hash>(set: &mut HashSet<T>) -> Option<T> {
    if let Some(elem) = set.iter().next().map(|elem| *elem) {
        set.remove(&elem);
        Some(elem)
    } else {
        None
    }
}

struct TransPlaceInterpreter;

impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for TransPlaceInterpreter {
    type MemoryKinds = !;
    type PointerTag = ();
    type AllocExtra = ();
    type MemoryExtra = ();
    type FrameExtra = ();
    type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
    const STATIC_KIND: Option<!> = None;

    fn enforce_validity(_: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool {
        false
    }

    fn before_terminator(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_fn(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: Option<PlaceTy<'tcx>>,
        _: Option<BasicBlock>,
    ) -> EvalResult<'tcx, Option<&'mir Mir<'tcx>>> {
        panic!();
    }

    fn call_intrinsic(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        _: Instance<'tcx>,
        _: &[OpTy<'tcx>],
        _: PlaceTy<'tcx>,
    ) -> EvalResult<'tcx> {
        panic!();
    }

    fn find_foreign_static(
        _: DefId,
        _: ::rustc::ty::query::TyCtxtAt<'a, 'tcx, 'tcx>,
        _: &(),
    ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> {
        panic!();
    }

    fn ptr_op(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: mir::BinOp,
        _: Scalar,
        _: TyLayout<'tcx>,
        _: Scalar,
        _: TyLayout<'tcx>,
    ) -> EvalResult<'tcx, (Scalar, bool)> {
        panic!();
    }

    fn box_alloc(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: PlaceTy<'tcx>) -> EvalResult<'tcx> {
        panic!();
    }

    fn tag_dereference(
        _: &EvalContext<'a, 'mir, 'tcx, Self>,
        _: MPlaceTy<'tcx>,
        _: Option<::rustc::hir::Mutability>,
    ) -> EvalResult<'tcx, Scalar> {
        panic!();
    }

    fn adjust_static_allocation<'alloc>(
        alloc: &'alloc Allocation,
        _: &(),
    ) -> Cow<'alloc, Allocation> {
        Cow::Borrowed(alloc)
    }

    fn tag_new_allocation(
        _: &mut EvalContext<'a, 'mir, 'tcx, Self>,
        ptr: Pointer,
        _: MemoryKind<!>,
    ) -> Pointer {
        ptr
    }

    fn stack_push(_: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>{
        Ok(())
    }

    fn stack_pop(_: &mut EvalContext<'a, 'mir, 'tcx, Self>, _: ()) -> EvalResult<'tcx> {
        Ok(())
    }
}
<|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.

use rustc::hir::def_id::{DefId, DefIndex};
use rbml;
use std::io::{Cursor, Write};
use std::slice;
use std::u32;

/// As part of the metadata, we generate an index that stores, for
/// each DefIndex, the position of the corresponding RBML document (if
/// any).  This is just a big `[u32]` slice, where an entry of
/// `u32::MAX` indicates that there is no RBML document. This little
/// struct just stores the offsets within the metadata of the start
/// and end of this slice. These are actually part of an RBML
/// document, but for looking things up in the metadata, we just
/// discard the RBML positioning and jump directly to the data.
pub struct Index {
    data_start: usize,
    data_end: usize,
}

impl Index {
    /// Given the RBML doc representing the index, save the offests
    /// for later.
    pub fn from_rbml(index: rbml::Doc) -> Index {
        Index { data_start: index.start, data_end: index.end }
    }

    /// Given the metadata, extract out the offset of a particular
    /// DefIndex (if any).
    #[inline(never)]
    pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
        let index = def_index.as_usize();

        debug!("lookup_item: index={:?} words.len={:?}",
               index, words.len());

        let position = u32::from_be(words[index]);
        if position == u32::MAX {
            debug!("lookup_item: position=u32::MAX");
            None
        } else {
            debug!("lookup_item: position={:?}", position);
            Some(position)
        }
    }

    pub fn iter_enumerated<'a>(&self, bytes: &'a [u8])
                               -> impl Iterator<Item=(DefIndex, u32)> + 'a {
        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
        words.iter().enumerate().filter_map(|(index, &position)| {
            if position == u32::MAX {
                None
            } else {
                Some((DefIndex::new(index), u32::from_be(position)))
            }
        })
    }
}

/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct IndexData {
    positions: Vec<u32>,
}

impl IndexData {
    pub fn new(max_index: usize) -> IndexData {
        IndexData {
            positions: vec![u32::MAX; max_index]
        }
    }

    pub fn record(&mut self, def_id: DefId, position: usize) {
        assert!(def_id.is_local());
        self.record_index(def_id.index, position);
    }

    pub fn record_index(&mut self, item: DefIndex, position: usize) {
        let item = item.as_usize();

        assert!(position < (u32::MAX as usize));
        let position = position as u32;

        assert!(self.positions[item] == u32::MAX,
                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
                item, self.positions[item], position);

        self.positions[item] = position;
    }

    pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
        for &position in &self.positions {
            write_be_u32(buf, position);
        }
    }
}

/// A dense index with integer keys. Different API from IndexData (should
/// these be merged?)
pub struct DenseIndex {
    start: usize,
    end: usize
}

impl DenseIndex {
    pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> {
        let data = bytes_to_words(&buf[self.start..self.end]);
        data.get(ix as usize).map(|d| u32::from_be(*d))
    }
    pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
        assert!((end-start)%4 == 0 && start <= end && end <= buf.len());
        DenseIndex {
            start: start,
            end: end
        }
    }
}

pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) {
    let elen = entries.len();
    assert!(elen < u32::MAX as usize);

    for entry in entries {
        write_be_u32(buf, entry);
    }

    info!("write_dense_index: {} entries", elen);
}

fn write_be_u32<W: Write>(w: &mut W, u: u32) {
    let _ = w.write_all(&[
        (u >> 24) as u8,
        (u >> 16) as u8,
        (u >>  8) as u8,
        (u >>  0) as u8,
    ]);
}

fn bytes_to_words(b: &[u8]) -> &[u32] {
    assert!(b.len() % 4 == 0);
    unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
}
<commit_msg>rustc_metadata: store dense indexes in little-endian instead of big.<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.

use rustc::hir::def_id::{DefId, DefIndex};
use rbml;
use std::io::{Cursor, Write};
use std::slice;
use std::u32;

/// As part of the metadata, we generate an index that stores, for
/// each DefIndex, the position of the corresponding RBML document (if
/// any).  This is just a big `[u32]` slice, where an entry of
/// `u32::MAX` indicates that there is no RBML document. This little
/// struct just stores the offsets within the metadata of the start
/// and end of this slice. These are actually part of an RBML
/// document, but for looking things up in the metadata, we just
/// discard the RBML positioning and jump directly to the data.
pub struct Index {
    data_start: usize,
    data_end: usize,
}

impl Index {
    /// Given the RBML doc representing the index, save the offests
    /// for later.
    pub fn from_rbml(index: rbml::Doc) -> Index {
        Index { data_start: index.start, data_end: index.end }
    }

    /// Given the metadata, extract out the offset of a particular
    /// DefIndex (if any).
    #[inline(never)]
    pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
        let index = def_index.as_usize();

        debug!("lookup_item: index={:?} words.len={:?}",
               index, words.len());

        let position = u32::from_le(words[index]);
        if position == u32::MAX {
            debug!("lookup_item: position=u32::MAX");
            None
        } else {
            debug!("lookup_item: position={:?}", position);
            Some(position)
        }
    }

    pub fn iter_enumerated<'a>(&self, bytes: &'a [u8])
                               -> impl Iterator<Item=(DefIndex, u32)> + 'a {
        let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
        words.iter().enumerate().filter_map(|(index, &position)| {
            if position == u32::MAX {
                None
            } else {
                Some((DefIndex::new(index), u32::from_le(position)))
            }
        })
    }
}

/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct IndexData {
    positions: Vec<u32>,
}

impl IndexData {
    pub fn new(max_index: usize) -> IndexData {
        IndexData {
            positions: vec![u32::MAX; max_index]
        }
    }

    pub fn record(&mut self, def_id: DefId, position: usize) {
        assert!(def_id.is_local());
        self.record_index(def_id.index, position);
    }

    pub fn record_index(&mut self, item: DefIndex, position: usize) {
        let item = item.as_usize();

        assert!(position < (u32::MAX as usize));
        let position = position as u32;

        assert!(self.positions[item] == u32::MAX,
                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
                item, self.positions[item], position);

        self.positions[item] = position.to_le();
    }

    pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
        buf.write_all(words_to_bytes(&self.positions)).unwrap();
    }
}

/// A dense index with integer keys. Different API from IndexData (should
/// these be merged?)
pub struct DenseIndex {
    start: usize,
    end: usize
}

impl DenseIndex {
    pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> {
        let data = bytes_to_words(&buf[self.start..self.end]);
        data.get(ix as usize).map(|d| u32::from_le(*d))
    }
    pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
        assert!((end-start)%4 == 0 && start <= end && end <= buf.len());
        DenseIndex {
            start: start,
            end: end
        }
    }
}

pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) {
    let elen = entries.len();
    assert!(elen < u32::MAX as usize);

    buf.write_all(words_to_bytes(&entries)).unwrap();

    info!("write_dense_index: {} entries", elen);
}

fn bytes_to_words(b: &[u8]) -> &[u32] {
    assert!(b.len() % 4 == 0);
    unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
}

fn words_to_bytes(w: &[u32]) -> &[u8] {
    unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len()*4) }
}
<|endoftext|>


<commit_before>use crate::schema::*;

use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace};
use rustc_serialize::opaque::Encoder;
use std::slice;
use std::u32;
use log::debug;

/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct Index {
    positions: [Vec<u32>; 2]
}

impl Index {
    pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index {
        Index {
            positions: [vec![u32::MAX; max_index_lo],
                        vec![u32::MAX; max_index_hi]],
        }
    }

    pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'_>>) {
        assert!(def_id.is_local());
        self.record_index(def_id.index, entry);
    }

    pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
        assert!(entry.position < (u32::MAX as usize));
        let position = entry.position as u32;
        let space_index = item.address_space().index();
        let array_index = item.as_array_index();

        assert!(self.positions[space_index][array_index] == u32::MAX,
                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
                item,
                self.positions[space_index][array_index],
                position);

        self.positions[space_index][array_index] = position.to_le();
    }

    pub fn write_index(&self, buf: &mut Encoder) -> LazySeq<Index> {
        let pos = buf.position();

        // First we write the length of the lower range ...
        buf.emit_raw_bytes(words_to_bytes(&[(self.positions[0].len() as u32).to_le()]));
        // ... then the values in the lower range ...
        buf.emit_raw_bytes(words_to_bytes(&self.positions[0][..]));
        // ... then the values in the higher range.
        buf.emit_raw_bytes(words_to_bytes(&self.positions[1][..]));
        LazySeq::with_position_and_length(pos as usize,
            self.positions[0].len() + self.positions[1].len() + 1)
    }
}

impl<'tcx> LazySeq<Index> {
    /// Given the metadata, extract out the offset of a particular
    /// DefIndex (if any).
    #[inline(never)]
    pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
        let words = &bytes_to_words(&bytes[self.position..])[..self.len];

        debug!("Index::lookup: index={:?} words.len={:?}",
               def_index,
               words.len());

        let positions = match def_index.address_space() {
            DefIndexAddressSpace::Low => &words[1..],
            DefIndexAddressSpace::High => {
                // This is a DefIndex in the higher range, so find out where
                // that starts:
                let lo_count = u32::from_le(words[0].get()) as usize;
                &words[lo_count + 1 .. ]
            }
        };

        let array_index = def_index.as_array_index();
        let position = u32::from_le(positions[array_index].get());
        if position == u32::MAX {
            debug!("Index::lookup: position=u32::MAX");
            None
        } else {
            debug!("Index::lookup: position={:?}", position);
            Some(Lazy::with_position(position as usize))
        }
    }
}

#[repr(packed)]
#[derive(Copy)]
struct Unaligned<T>(T);

// The derived Clone impl is unsafe for this packed struct since it needs to pass a reference to
// the field to `T::clone`, but this reference may not be properly aligned.
impl<T: Copy> Clone for Unaligned<T> {
    fn clone(&self) -> Self {
        *self
    }
}

impl<T> Unaligned<T> {
    fn get(self) -> T { self.0 }
}

fn bytes_to_words(b: &[u8]) -> &[Unaligned<u32>] {
    unsafe { slice::from_raw_parts(b.as_ptr() as *const Unaligned<u32>, b.len() / 4) }
}

fn words_to_bytes(w: &[u32]) -> &[u8] {
    unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) }
}
<commit_msg>Auto merge of #59887 - eddyb:safer-metadata, r=Zoxc<commit_after>use crate::schema::*;

use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace};
use rustc_serialize::opaque::Encoder;
use std::u32;
use log::debug;

/// Helper trait, for encoding to, and decoding from, a fixed number of bytes.
pub trait FixedSizeEncoding {
    const BYTE_LEN: usize;

    // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
    // once that starts being allowed by the compiler (i.e. lazy normalization).
    fn from_bytes(b: &[u8]) -> Self;
    fn write_to_bytes(self, b: &mut [u8]);

    // FIXME(eddyb) make these generic functions, or at least defaults here.
    // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
    // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
    fn read_from_bytes_at(b: &[u8], i: usize) -> Self;
    fn write_to_bytes_at(self, b: &mut [u8], i: usize);
}

// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
macro_rules! fixed_size_encoding_byte_len_and_defaults {
    ($byte_len:expr) => {
        const BYTE_LEN: usize = $byte_len;
        fn read_from_bytes_at(b: &[u8], i: usize) -> Self {
            const BYTE_LEN: usize = $byte_len;
            // HACK(eddyb) ideally this would be done with fully safe code,
            // but slicing `[u8]` with `i * N..` is optimized worse, due to the
            // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
            let b = unsafe {
                std::slice::from_raw_parts(
                    b.as_ptr() as *const [u8; BYTE_LEN],
                    b.len() / BYTE_LEN,
                )
            };
            Self::from_bytes(&b[i])
        }
        fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
            const BYTE_LEN: usize = $byte_len;
            // HACK(eddyb) ideally this would be done with fully safe code,
            // see similar comment in `read_from_bytes_at` for why it can't yet.
            let b = unsafe {
                std::slice::from_raw_parts_mut(
                    b.as_mut_ptr() as *mut [u8; BYTE_LEN],
                    b.len() / BYTE_LEN,
                )
            };
            self.write_to_bytes(&mut b[i]);
        }
    }
}

impl FixedSizeEncoding for u32 {
    fixed_size_encoding_byte_len_and_defaults!(4);

    fn from_bytes(b: &[u8]) -> Self {
        let mut bytes = [0; Self::BYTE_LEN];
        bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
        Self::from_le_bytes(bytes)
    }

    fn write_to_bytes(self, b: &mut [u8]) {
        b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
    }
}

/// While we are generating the metadata, we also track the position
/// of each DefIndex. It is not required that all definitions appear
/// in the metadata, nor that they are serialized in order, and
/// therefore we first allocate the vector here and fill it with
/// `u32::MAX`. Whenever an index is visited, we fill in the
/// appropriate spot by calling `record_position`. We should never
/// visit the same index twice.
pub struct Index {
    positions: [Vec<u8>; 2]
}

impl Index {
    pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index {
        Index {
            positions: [vec![0xff; max_index_lo * 4],
                        vec![0xff; max_index_hi * 4]],
        }
    }

    pub fn record(&mut self, def_id: DefId, entry: Lazy<Entry<'_>>) {
        assert!(def_id.is_local());
        self.record_index(def_id.index, entry);
    }

    pub fn record_index(&mut self, item: DefIndex, entry: Lazy<Entry<'_>>) {
        assert!(entry.position < (u32::MAX as usize));
        let position = entry.position as u32;
        let space_index = item.address_space().index();
        let array_index = item.as_array_index();

        let positions = &mut self.positions[space_index];
        assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX,
                "recorded position for item {:?} twice, first at {:?} and now at {:?}",
                item,
                u32::read_from_bytes_at(positions, array_index),
                position);

        position.write_to_bytes_at(positions, array_index)
    }

    pub fn write_index(&self, buf: &mut Encoder) -> LazySeq<Index> {
        let pos = buf.position();

        // First we write the length of the lower range ...
        buf.emit_raw_bytes(&(self.positions[0].len() as u32 / 4).to_le_bytes());
        // ... then the values in the lower range ...
        buf.emit_raw_bytes(&self.positions[0]);
        // ... then the values in the higher range.
        buf.emit_raw_bytes(&self.positions[1]);
        LazySeq::with_position_and_length(pos as usize,
            (self.positions[0].len() + self.positions[1].len()) / 4 + 1)
    }
}

impl<'tcx> LazySeq<Index> {
    /// Given the metadata, extract out the offset of a particular
    /// DefIndex (if any).
    #[inline(never)]
    pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option<Lazy<Entry<'tcx>>> {
        let bytes = &bytes[self.position..];
        debug!("Index::lookup: index={:?} len={:?}",
               def_index,
               self.len);

        let i = def_index.as_array_index() + match def_index.address_space() {
            DefIndexAddressSpace::Low => 0,
            DefIndexAddressSpace::High => {
                // This is a DefIndex in the higher range, so find out where
                // that starts:
                u32::read_from_bytes_at(bytes, 0) as usize
            }
        };

        let position = u32::read_from_bytes_at(bytes, 1 + i);
        if position == u32::MAX {
            debug!("Index::lookup: position=u32::MAX");
            None
        } else {
            debug!("Index::lookup: position={:?}", position);
            Some(Lazy::with_position(position as usize))
        }
    }
}
<|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.

//! Miscellaneous builder routines that are not specific to building any particular
//! kind of thing.

use build::Builder;

use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};

use rustc::mir::repr::*;
use std::u32;
use syntax::ast;
use syntax::codemap::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Add a new temporary value of type `ty` storing the result of
    /// evaluating `expr`.
    ///
    /// NB: **No cleanup is scheduled for this temporary.** You should
    /// call `schedule_drop` once the temporary is initialized.
    pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
        let index = self.temp_decls.len();
        self.temp_decls.push(TempDecl { ty: ty });
        assert!(index < (u32::MAX) as usize);
        let lvalue = Lvalue::Temp(index as u32);
        debug!("temp: created temp {:?} with type {:?}",
               lvalue, self.temp_decls.last().unwrap().ty);
        lvalue
    }

    pub fn literal_operand(&mut self,
                           span: Span,
                           ty: Ty<'tcx>,
                           literal: Literal<'tcx>)
                           -> Operand<'tcx> {
        let constant = Constant {
            span: span,
            ty: ty,
            literal: literal,
        };
        Operand::Constant(constant)
    }

    pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
        Rvalue::Aggregate(AggregateKind::Tuple, vec![])
    }

    // Returns a zero literal operand for the appropriate type, works for
    // bool, char, integers and floats.
    pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
        let literal = match ty.sty {
            ty::TyBool => {
                self.hir.false_literal()
            }
            ty::TyChar => Literal::Value { value: ConstVal::Char('\0') },
            ty::TyUint(ity) => {
                let val = match ity {
                    ast::UintTy::U8  => ConstInt::U8(0),
                    ast::UintTy::U16 => ConstInt::U16(0),
                    ast::UintTy::U32 => ConstInt::U32(0),
                    ast::UintTy::U64 => ConstInt::U64(0),
                    ast::UintTy::Us => {
                        let uint_ty = self.hir.tcx().sess.target.uint_type;
                        let val = ConstUsize::new(0, uint_ty).unwrap();
                        ConstInt::Usize(val)
                    }
                };

                Literal::Value { value: ConstVal::Integral(val) }
            }
            ty::TyInt(ity) => {
                let val = match ity {
                    ast::IntTy::I8  => ConstInt::I8(0),
                    ast::IntTy::I16 => ConstInt::I16(0),
                    ast::IntTy::I32 => ConstInt::I32(0),
                    ast::IntTy::I64 => ConstInt::I64(0),
                    ast::IntTy::Is => {
                        let int_ty = self.hir.tcx().sess.target.int_type;
                        let val = ConstIsize::new(0, int_ty).unwrap();
                        ConstInt::Isize(val)
                    }
                };

                Literal::Value { value: ConstVal::Integral(val) }
            }
            ty::TyFloat(_) => Literal::Value { value: ConstVal::Float(0.0) },
            _ => {
                span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
            }
        };

        self.literal_operand(span, ty, literal)
    }

    pub fn push_usize(&mut self,
                      block: BasicBlock,
                      scope_id: ScopeId,
                      span: Span,
                      value: u64)
                      -> Lvalue<'tcx> {
        let usize_ty = self.hir.usize_ty();
        let temp = self.temp(usize_ty);
        self.cfg.push_assign_constant(
            block, scope_id, span, &temp,
            Constant {
                span: span,
                ty: self.hir.usize_ty(),
                literal: self.hir.usize_literal(value),
            });
        temp
    }
}
<commit_msg>mir: remove unused float support from zero_literal.<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.

//! Miscellaneous builder routines that are not specific to building any particular
//! kind of thing.

use build::Builder;

use rustc_const_math::{ConstInt, ConstUsize, ConstIsize};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};

use rustc::mir::repr::*;
use std::u32;
use syntax::ast;
use syntax::codemap::Span;

impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
    /// Add a new temporary value of type `ty` storing the result of
    /// evaluating `expr`.
    ///
    /// NB: **No cleanup is scheduled for this temporary.** You should
    /// call `schedule_drop` once the temporary is initialized.
    pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
        let index = self.temp_decls.len();
        self.temp_decls.push(TempDecl { ty: ty });
        assert!(index < (u32::MAX) as usize);
        let lvalue = Lvalue::Temp(index as u32);
        debug!("temp: created temp {:?} with type {:?}",
               lvalue, self.temp_decls.last().unwrap().ty);
        lvalue
    }

    pub fn literal_operand(&mut self,
                           span: Span,
                           ty: Ty<'tcx>,
                           literal: Literal<'tcx>)
                           -> Operand<'tcx> {
        let constant = Constant {
            span: span,
            ty: ty,
            literal: literal,
        };
        Operand::Constant(constant)
    }

    pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
        Rvalue::Aggregate(AggregateKind::Tuple, vec![])
    }

    // Returns a zero literal operand for the appropriate type, works for
    // bool, char and integers.
    pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
        let literal = match ty.sty {
            ty::TyBool => {
                self.hir.false_literal()
            }
            ty::TyChar => Literal::Value { value: ConstVal::Char('\0') },
            ty::TyUint(ity) => {
                let val = match ity {
                    ast::UintTy::U8  => ConstInt::U8(0),
                    ast::UintTy::U16 => ConstInt::U16(0),
                    ast::UintTy::U32 => ConstInt::U32(0),
                    ast::UintTy::U64 => ConstInt::U64(0),
                    ast::UintTy::Us => {
                        let uint_ty = self.hir.tcx().sess.target.uint_type;
                        let val = ConstUsize::new(0, uint_ty).unwrap();
                        ConstInt::Usize(val)
                    }
                };

                Literal::Value { value: ConstVal::Integral(val) }
            }
            ty::TyInt(ity) => {
                let val = match ity {
                    ast::IntTy::I8  => ConstInt::I8(0),
                    ast::IntTy::I16 => ConstInt::I16(0),
                    ast::IntTy::I32 => ConstInt::I32(0),
                    ast::IntTy::I64 => ConstInt::I64(0),
                    ast::IntTy::Is => {
                        let int_ty = self.hir.tcx().sess.target.int_type;
                        let val = ConstIsize::new(0, int_ty).unwrap();
                        ConstInt::Isize(val)
                    }
                };

                Literal::Value { value: ConstVal::Integral(val) }
            }
            _ => {
                span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
            }
        };

        self.literal_operand(span, ty, literal)
    }

    pub fn push_usize(&mut self,
                      block: BasicBlock,
                      scope_id: ScopeId,
                      span: Span,
                      value: u64)
                      -> Lvalue<'tcx> {
        let usize_ty = self.hir.usize_ty();
        let temp = self.temp(usize_ty);
        self.cfg.push_assign_constant(
            block, scope_id, span, &temp,
            Constant {
                span: span,
                ty: self.hir.usize_ty(),
                literal: self.hir.usize_literal(value),
            });
        temp
    }
}
<|endoftext|>


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

use Resolver;
use rustc::middle::cstore::LoadedMacro;
use rustc::util::nodemap::FnvHashMap;
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
use syntax::ast::{self, Name};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, emit_feature_err};
use syntax::parse::token::{self, intern};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;

#[derive(Clone, Default)]
pub struct ExpansionData {
    module: Rc<ModuleData>,
}

// FIXME(jseyfried): merge with `::ModuleS`.
#[derive(Default)]
struct ModuleData {
    parent: Option<Rc<ModuleData>>,
    macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
    macros_escape: bool,
}

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        self.session.next_node_id()
    }

    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
        expansion.visit_with(&mut ExpansionVisitor {
            current_module: self.expansion_data[&mark.as_u32()].module.clone(),
            resolver: self,
        });
    }

    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
        if def.use_locally {
            let ext = macro_rules::compile(&self.session.parse_sess, &def);
            self.add_ext(scope, def.ident, Rc::new(ext));
        }
        if def.export {
            def.id = self.next_node_id();
            self.exported_macros.push(def);
        }
    }

    fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        if let NormalTT(..) = *ext {
            self.macro_names.insert(ident.name);
        }

        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
        while module.macros_escape {
            module = module.parent.clone().unwrap();
        }
        module.macros.borrow_mut().insert(ident.name, ext);
    }

    fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
        self.macros_at_scope.insert(id, macros);
    }

    fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());
            match self.expansion_data[&0].module.macros.borrow().get(&name) {
                Some(ext) => match **ext {
                    MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                        return Some(attrs.remove(i))
                    }
                    _ => {}
                },
                None => {}
            }
        }
        None
    }

    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
        let (name, span) = match invoc.kind {
            InvocationKind::Bang { ref mac, .. } => {
                let path = &mac.node.path;
                if path.segments.len() > 1 || path.global ||
                   !path.segments[0].parameters.is_empty() {
                    self.session.span_err(path.span,
                                          "expected macro name without module separators");
                    return None;
                }
                (path.segments[0].identifier.name, path.span)
            }
            InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
        };

        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
        loop {
            if let Some(ext) = module.macros.borrow().get(&name) {
                return Some(ext.clone());
            }
            match module.parent.clone() {
                Some(parent) => module = parent,
                None => break,
            }
        }

        let mut err =
            self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
        self.suggest_macro_name(&name.as_str(), &mut err);
        err.emit();
        None
    }

    fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
        self.derive_modes.get(&ident.name).cloned()
    }
}

impl<'a> Resolver<'a> {
    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
            if suggestion != name {
                err.help(&format!("did you mean `{}!`?", suggestion));
            } else {
                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
            }
        }
    }

    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
        if !self.session.features.borrow().rustc_macro {
            let diagnostic = &self.session.parse_sess.span_diagnostic;
            let msg = "loading custom derive macro crates is experimentally supported";
            emit_feature_err(diagnostic, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
        }
        if self.derive_modes.insert(token::intern(name), ext).is_some() {
            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
        }
    }
}

struct ExpansionVisitor<'b, 'a: 'b> {
    resolver: &'b mut Resolver<'a>,
    current_module: Rc<ModuleData>,
}

impl<'a, 'b> ExpansionVisitor<'a, 'b> {
    fn visit_invoc(&mut self, id: ast::NodeId) {
        self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
            module: self.current_module.clone(),
        });
    }

    // does this attribute list contain "macro_use"?
    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
        for attr in attrs {
            if attr.check_name("macro_escape") {
                let msg = "macro_escape is a deprecated synonym for macro_use";
                let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
                if let ast::AttrStyle::Inner = attr.node.style {
                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
                } else {
                    err.emit();
                }
            } else if !attr.check_name("macro_use") {
                continue;
            }

            if !attr.is_word() {
                self.resolver.session.span_err(attr.span,
                                               "arguments to macro_use are not allowed here");
            }
            return true;
        }

        false
    }
}

macro_rules! method {
    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
        fn $visit(&mut self, node: &$ty) {
            match node.node {
                $invoc(..) => self.visit_invoc(node.id),
                _ => visit::$walk(self, node),
            }
        }
    }
}

impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b>  {
    method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
    method!(visit_impl_item:  ast::ImplItem,  ast::ImplItemKind::Macro,  walk_impl_item);
    method!(visit_stmt:       ast::Stmt,      ast::StmtKind::Mac,        walk_stmt);
    method!(visit_expr:       ast::Expr,      ast::ExprKind::Mac,        walk_expr);
    method!(visit_pat:        ast::Pat,       ast::PatKind::Mac,         walk_pat);
    method!(visit_ty:         ast::Ty,        ast::TyKind::Mac,          walk_ty);

    fn visit_item(&mut self, item: &ast::Item) {
        match item.node {
            ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
            ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
            ast::ItemKind::Mod(..) => {
                let module_data = ModuleData {
                    parent: Some(self.current_module.clone()),
                    macros: RefCell::new(FnvHashMap()),
                    macros_escape: self.contains_macro_use(&item.attrs),
                };
                let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
                visit::walk_item(self, item);
                self.current_module = orig_module;
            }
            ast::ItemKind::ExternCrate(..) => {
                // We need to error on `#[macro_use] extern crate` when it isn't at the
                // crate root, because `$crate` won't work properly.
                // FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
                let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
                for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
                    match def {
                        LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
                        LoadedMacro::CustomDerive(name, ext) => {
                            self.resolver.insert_custom_derive(&name, ext, item.span);
                        }
                    }
                }
                visit::walk_item(self, item);
            }
            _ => visit::walk_item(self, item),
        }
    }

    fn visit_block(&mut self, block: &ast::Block) {
        let module_data = ModuleData {
            parent: Some(self.current_module.clone()),
            macros: RefCell::new(FnvHashMap()),
            macros_escape: false,
        };
        let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
        visit::walk_block(self, block);
        self.current_module = orig_module;
    }
}
<commit_msg>fix rebase fallout<commit_after>// Copyright 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.

use Resolver;
use rustc::middle::cstore::LoadedMacro;
use rustc::util::nodemap::FnvHashMap;
use std::cell::RefCell;
use std::mem;
use std::rc::Rc;
use syntax::ast::{self, Name};
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, emit_feature_err};
use syntax::parse::token::{self, intern};
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;

#[derive(Clone, Default)]
pub struct ExpansionData {
    module: Rc<ModuleData>,
}

// FIXME(jseyfried): merge with `::ModuleS`.
#[derive(Default)]
struct ModuleData {
    parent: Option<Rc<ModuleData>>,
    macros: RefCell<FnvHashMap<Name, Rc<SyntaxExtension>>>,
    macros_escape: bool,
}

impl<'a> base::Resolver for Resolver<'a> {
    fn next_node_id(&mut self) -> ast::NodeId {
        self.session.next_node_id()
    }

    fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
        expansion.visit_with(&mut ExpansionVisitor {
            current_module: self.expansion_data[&mark.as_u32()].module.clone(),
            resolver: self,
        });
    }

    fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
        if def.use_locally {
            let ext = macro_rules::compile(&self.session.parse_sess, &def);
            self.add_ext(scope, def.ident, Rc::new(ext));
        }
        if def.export {
            def.id = self.next_node_id();
            self.exported_macros.push(def);
        }
    }

    fn add_ext(&mut self, scope: Mark, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
        if let NormalTT(..) = *ext {
            self.macro_names.insert(ident.name);
        }

        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
        while module.macros_escape {
            module = module.parent.clone().unwrap();
        }
        module.macros.borrow_mut().insert(ident.name, ext);
    }

    fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
        self.macros_at_scope.insert(id, macros);
    }

    fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
        for i in 0..attrs.len() {
            let name = intern(&attrs[i].name());
            match self.expansion_data[&0].module.macros.borrow().get(&name) {
                Some(ext) => match **ext {
                    MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                        return Some(attrs.remove(i))
                    }
                    _ => {}
                },
                None => {}
            }
        }
        None
    }

    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
        let (name, span) = match invoc.kind {
            InvocationKind::Bang { ref mac, .. } => {
                let path = &mac.node.path;
                if path.segments.len() > 1 || path.global ||
                   !path.segments[0].parameters.is_empty() {
                    self.session.span_err(path.span,
                                          "expected macro name without module separators");
                    return None;
                }
                (path.segments[0].identifier.name, path.span)
            }
            InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
        };

        let mut module = self.expansion_data[&scope.as_u32()].module.clone();
        loop {
            if let Some(ext) = module.macros.borrow().get(&name) {
                return Some(ext.clone());
            }
            match module.parent.clone() {
                Some(parent) => module = parent,
                None => break,
            }
        }

        let mut err =
            self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
        self.suggest_macro_name(&name.as_str(), &mut err);
        err.emit();
        None
    }

    fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>> {
        self.derive_modes.get(&ident.name).cloned()
    }
}

impl<'a> Resolver<'a> {
    fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
        if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) {
            if suggestion != name {
                err.help(&format!("did you mean `{}!`?", suggestion));
            } else {
                err.help(&format!("have you added the `#[macro_use]` on the module/import?"));
            }
        }
    }

    fn insert_custom_derive(&mut self, name: &str, ext: Rc<MultiItemModifier>, sp: Span) {
        if !self.session.features.borrow().rustc_macro {
            let sess = &self.session.parse_sess;
            let msg = "loading custom derive macro crates is experimentally supported";
            emit_feature_err(sess, "rustc_macro", sp, feature_gate::GateIssue::Language, msg);
        }
        if self.derive_modes.insert(token::intern(name), ext).is_some() {
            self.session.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name));
        }
    }
}

struct ExpansionVisitor<'b, 'a: 'b> {
    resolver: &'b mut Resolver<'a>,
    current_module: Rc<ModuleData>,
}

impl<'a, 'b> ExpansionVisitor<'a, 'b> {
    fn visit_invoc(&mut self, id: ast::NodeId) {
        self.resolver.expansion_data.insert(id.as_u32(), ExpansionData {
            module: self.current_module.clone(),
        });
    }

    // does this attribute list contain "macro_use"?
    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
        for attr in attrs {
            if attr.check_name("macro_escape") {
                let msg = "macro_escape is a deprecated synonym for macro_use";
                let mut err = self.resolver.session.struct_span_warn(attr.span, msg);
                if let ast::AttrStyle::Inner = attr.node.style {
                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
                } else {
                    err.emit();
                }
            } else if !attr.check_name("macro_use") {
                continue;
            }

            if !attr.is_word() {
                self.resolver.session.span_err(attr.span,
                                               "arguments to macro_use are not allowed here");
            }
            return true;
        }

        false
    }
}

macro_rules! method {
    ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
        fn $visit(&mut self, node: &$ty) {
            match node.node {
                $invoc(..) => self.visit_invoc(node.id),
                _ => visit::$walk(self, node),
            }
        }
    }
}

impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b>  {
    method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item);
    method!(visit_impl_item:  ast::ImplItem,  ast::ImplItemKind::Macro,  walk_impl_item);
    method!(visit_stmt:       ast::Stmt,      ast::StmtKind::Mac,        walk_stmt);
    method!(visit_expr:       ast::Expr,      ast::ExprKind::Mac,        walk_expr);
    method!(visit_pat:        ast::Pat,       ast::PatKind::Mac,         walk_pat);
    method!(visit_ty:         ast::Ty,        ast::TyKind::Mac,          walk_ty);

    fn visit_item(&mut self, item: &ast::Item) {
        match item.node {
            ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder
            ast::ItemKind::Mac(..) => self.visit_invoc(item.id),
            ast::ItemKind::Mod(..) => {
                let module_data = ModuleData {
                    parent: Some(self.current_module.clone()),
                    macros: RefCell::new(FnvHashMap()),
                    macros_escape: self.contains_macro_use(&item.attrs),
                };
                let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
                visit::walk_item(self, item);
                self.current_module = orig_module;
            }
            ast::ItemKind::ExternCrate(..) => {
                // We need to error on `#[macro_use] extern crate` when it isn't at the
                // crate root, because `$crate` won't work properly.
                // FIXME(jseyfried): This will be nicer once `ModuleData` is merged with `ModuleS`.
                let is_crate_root = self.current_module.parent.as_ref().unwrap().parent.is_none();
                for def in self.resolver.crate_loader.load_macros(item, is_crate_root) {
                    match def {
                        LoadedMacro::Def(def) => self.resolver.add_macro(Mark::root(), def),
                        LoadedMacro::CustomDerive(name, ext) => {
                            self.resolver.insert_custom_derive(&name, ext, item.span);
                        }
                    }
                }
                visit::walk_item(self, item);
            }
            _ => visit::walk_item(self, item),
        }
    }

    fn visit_block(&mut self, block: &ast::Block) {
        let module_data = ModuleData {
            parent: Some(self.current_module.clone()),
            macros: RefCell::new(FnvHashMap()),
            macros_escape: false,
        };
        let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data));
        visit::walk_block(self, block);
        self.current_module = orig_module;
    }
}
<|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.

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]

use os::raw::c_long;
use os::unix::raw::{uid_t, gid_t};

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[repr(C)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: ino_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: nlink_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: mode_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_padding1: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: uid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: gid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: off_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: blkcnt_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: blksize_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: fflags_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: uint32_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: int32_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare1: int64_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare2: int64_t,
}
<commit_msg>Auto merge of #28162 - mneumann:dragonfly_fix_stat, r=alexcrichton<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.

//! Dragonfly-specific raw type definitions

#![stable(feature = "raw_ext", since = "1.1.0")]

use os::raw::c_long;
use os::unix::raw::{uid_t, gid_t};

#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u16;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;

#[repr(C)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ino: ino_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_nlink: nlink_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_dev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mode: mode_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_padding1: u16,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_uid: uid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gid: gid_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_rdev: dev_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_atime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_mtime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime: time_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_ctime_nsec: c_long,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_size: off_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blocks: blkcnt_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_blksize: blksize_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_flags: fflags_t,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_gen: u32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_lspare: i32,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare1: i64,
    #[stable(feature = "raw_ext", since = "1.1.0")]
    pub st_qspare2: i64,
}
<|endoftext|>