<commit_before>use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
use rustc_target::spec::abi;
use std::borrow::Cow;
use syntax_pos::Span;

type McfResult = Result<(), (Span, Cow<'static, str>)>;

pub fn is_min_const_fn(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    mir: &'a Mir<'tcx>,
) -> McfResult {
    let mut current = def_id;
    loop {
        let predicates = tcx.predicates_of(current);
        for (predicate, _) in &predicates.predicates {
            match predicate {
                | Predicate::RegionOutlives(_)
                | Predicate::TypeOutlives(_)
                | Predicate::WellFormed(_)
                | Predicate::Projection(_)
                | Predicate::ConstEvaluatable(..) => continue,
                | Predicate::ObjectSafe(_) => {
                    bug!("object safe predicate on function: {:#?}", predicate)
                }
                Predicate::ClosureKind(..) => {
                    bug!("closure kind predicate on function: {:#?}", predicate)
                }
                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
                Predicate::Trait(pred) => {
                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                        continue;
                    }
                    match pred.skip_binder().self_ty().sty {
                        ty::Param(ref p) => {
                            let generics = tcx.generics_of(current);
                            let def = generics.type_param(p, tcx);
                            let span = tcx.def_span(def.def_id);
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        // other kinds of bounds are either tautologies
                        // or cause errors in other passes
                        _ => continue,
                    }
                }
            }
        }
        match predicates.parent {
            Some(parent) => current = parent,
            None => break,
        }
    }

    for local in &mir.local_decls {
        check_ty(tcx, local.ty, local.source_info.span, def_id)?;
    }
    // impl trait is gone in MIR, so check the return type manually
    check_ty(
        tcx,
        tcx.fn_sig(def_id).output().skip_binder(),
        mir.local_decls.iter().next().unwrap().source_info.span,
        def_id,
    )?;

    for bb in mir.basic_blocks() {
        check_terminator(tcx, mir, bb.terminator())?;
        for stmt in &bb.statements {
            check_statement(tcx, mir, stmt)?;
        }
    }
    Ok(())
}

fn check_ty(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    fn_def_id: DefId,
) -> McfResult {
    for ty in ty.walk() {
        match ty.sty {
            ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
                span,
                "mutable references in const fn are unstable".into(),
            )),
            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
            ty::FnPtr(..) => {
                if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
                    return Err((span, "function pointers in const fn are unstable".into()))
                }
            }
            ty::Dynamic(preds, _) => {
                for pred in preds.iter() {
                    match pred.skip_binder() {
                        | ty::ExistentialPredicate::AutoTrait(_)
                        | ty::ExistentialPredicate::Projection(_) => {
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ))
                        }
                        ty::ExistentialPredicate::Trait(trait_ref) => {
                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                return Err((
                                    span,
                                    "trait bounds other than `Sized` \
                                     on const fn parameters are unstable"
                                        .into(),
                                ));
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }
    Ok(())
}

fn check_rvalue(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    rvalue: &Rvalue<'tcx>,
    span: Span,
) -> McfResult {
    match rvalue {
        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
            check_operand(operand, span)
        }
        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
            check_place(place, span)
        }
        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
            use rustc::ty::cast::CastTy;
            let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast");
            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
            match (cast_in, cast_out) {
                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err((
                    span,
                    "casting pointers to ints is unstable in const fn".into(),
                )),
                (CastTy::RPtr(_), CastTy::Float) => bug!(),
                (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
                (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
                _ => check_operand(operand, span),
            }
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
            check_operand(operand, span)
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |
        Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) |
        Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => Err((
            span,
            "function pointer casts are not allowed in const fn".into(),
        )),
        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => Err((
            span,
            "unsizing casts are not allowed in const fn".into(),
        )),
        // binops are fine on integers
        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
            check_operand(lhs, span)?;
            check_operand(rhs, span)?;
            let ty = lhs.ty(mir, tcx);
            if ty.is_integral() || ty.is_bool() || ty.is_char() {
                Ok(())
            } else {
                Err((
                    span,
                    "only int, `bool` and `char` operations are stable in const fn".into(),
                ))
            }
        }
        Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
        Rvalue::NullaryOp(NullOp::Box, _) => Err((
            span,
            "heap allocations are not allowed in const fn".into(),
        )),
        Rvalue::UnaryOp(_, operand) => {
            let ty = operand.ty(mir, tcx);
            if ty.is_integral() || ty.is_bool() {
                check_operand(operand, span)
            } else {
                Err((
                    span,
                    "only int and `bool` operations are stable in const fn".into(),
                ))
            }
        }
        Rvalue::Aggregate(_, operands) => {
            for operand in operands {
                check_operand(operand, span)?;
            }
            Ok(())
        }
    }
}

fn check_statement(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    statement: &Statement<'tcx>,
) -> McfResult {
    let span = statement.source_info.span;
    match &statement.kind {
        StatementKind::Assign(place, rval) => {
            check_place(place, span)?;
            check_rvalue(tcx, mir, rval, span)
        }

        StatementKind::FakeRead(_, place) => check_place(place, span),

        // just an assignment
        StatementKind::SetDiscriminant { .. } => Ok(()),

        | StatementKind::InlineAsm { .. } => {
            Err((span, "cannot use inline assembly in const fn".into()))
        }

        // These are all NOPs
        | StatementKind::StorageLive(_)
        | StatementKind::StorageDead(_)
        | StatementKind::Retag { .. }
        | StatementKind::AscribeUserType(..)
        | StatementKind::Nop => Ok(()),
    }
}

fn check_operand(
    operand: &Operand<'tcx>,
    span: Span,
) -> McfResult {
    match operand {
        Operand::Move(place) | Operand::Copy(place) => {
            check_place(place, span)
        }
        Operand::Constant(_) => Ok(()),
    }
}

fn check_place(
    place: &Place<'tcx>,
    span: Span,
) -> McfResult {
    match place {
        Place::Base(PlaceBase::Local(_)) => Ok(()),
        // promoteds are always fine, they are essentially constants
        Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. })) => Ok(()),
        Place::Base(PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. })) =>
            Err((span, "cannot access `static` items in const fn".into())),
        Place::Projection(proj) => {
            match proj.elem {
                | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }
                | ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {
                    check_place(&proj.base, span)
                }
                | ProjectionElem::Downcast(..) => {
                    Err((span, "`match` or `if let` in `const fn` is unstable".into()))
                }
            }
        }
    }
}

fn check_terminator(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    terminator: &Terminator<'tcx>,
) -> McfResult {
    let span = terminator.source_info.span;
    match &terminator.kind {
        | TerminatorKind::Goto { .. }
        | TerminatorKind::Return
        | TerminatorKind::Resume => Ok(()),

        TerminatorKind::Drop { location, .. } => {
            check_place(location, span)
        }
        TerminatorKind::DropAndReplace { location, value, .. } => {
            check_place(location, span)?;
            check_operand(value, span)
        },

        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err((
            span,
            "`if`, `match`, `&&` and `||` are not stable in const fn".into(),
        )),
        | TerminatorKind::Abort | TerminatorKind::Unreachable => {
            Err((span, "const fn with unreachable code is not stable".into()))
        }
        | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
            Err((span, "const fn generators are unstable".into()))
        }

        TerminatorKind::Call {
            func,
            args,
            from_hir_call: _,
            destination: _,
            cleanup: _,
        } => {
            let fn_ty = func.ty(mir, tcx);
            if let ty::FnDef(def_id, _) = fn_ty.sty {

                // some intrinsics are waved through if called inside the
                // standard library. Users never need to call them directly
                match tcx.fn_sig(def_id).abi() {
                    abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
                        return Err((
                            span,
                            "can only call a curated list of intrinsics in `min_const_fn`".into(),
                        ))
                    },
                    abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
                    abi::Abi::Rust => return Err((
                        span,
                        format!(
                            "can only call other `const fn` within a `const fn`, \
                             but `{:?}` is not stable as `const fn`",
                            func,
                        )
                        .into(),
                    )),
                    abi => return Err((
                        span,
                        format!(
                            "cannot call functions with `{}` abi in `min_const_fn`",
                            abi,
                        ).into(),
                    )),
                }

                check_operand(func, span)?;

                for arg in args {
                    check_operand(arg, span)?;
                }
                Ok(())
            } else {
                Err((span, "can only call other const fns within const fn".into()))
            }
        }

        TerminatorKind::Assert {
            cond,
            expected: _,
            msg: _,
            target: _,
            cleanup: _,
        } => check_operand(cond, span),

        TerminatorKind::FalseUnwind { .. } => {
            Err((span, "loops are not allowed in const fn".into()))
        },
    }
}

/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
/// for being called from stable `const fn`s (`min_const_fn`).
///
/// Adding more intrinsics requires sign-off from @rust-lang/lang.
fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
    match &tcx.item_name(def_id).as_str()[..] {
        | "size_of"
        | "min_align_of"
        | "needs_drop"
        // Arithmetic:
        | "add_with_overflow" // ~> .overflowing_add
        | "sub_with_overflow" // ~> .overflowing_sub
        | "mul_with_overflow" // ~> .overflowing_mul
        | "overflowing_add" // ~> .wrapping_add
        | "overflowing_sub" // ~> .wrapping_sub
        | "overflowing_mul" // ~> .wrapping_mul
        | "saturating_add" // ~> .saturating_add
        | "saturating_sub" // ~> .saturating_sub
        | "unchecked_shl" // ~> .wrapping_shl
        | "unchecked_shr" // ~> .wrapping_shr
        | "rotate_left" // ~> .rotate_left
        | "rotate_right" // ~> .rotate_right
        | "ctpop" // ~> .count_ones
        | "ctlz" // ~> .leading_zeros
        | "cttz" // ~> .trailing_zeros
        | "bswap" // ~> .swap_bytes
        | "bitreverse" // ~> .reverse_bits
        => true,
        _ => false,
    }
}
<commit_msg>Make check_place iterate instead of recurse<commit_after>use rustc::hir::def_id::DefId;
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, Predicate, Ty, TyCtxt, adjustment::{PointerCast}};
use rustc_target::spec::abi;
use std::borrow::Cow;
use syntax_pos::Span;

type McfResult = Result<(), (Span, Cow<'static, str>)>;

pub fn is_min_const_fn(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    def_id: DefId,
    mir: &'a Mir<'tcx>,
) -> McfResult {
    let mut current = def_id;
    loop {
        let predicates = tcx.predicates_of(current);
        for (predicate, _) in &predicates.predicates {
            match predicate {
                | Predicate::RegionOutlives(_)
                | Predicate::TypeOutlives(_)
                | Predicate::WellFormed(_)
                | Predicate::Projection(_)
                | Predicate::ConstEvaluatable(..) => continue,
                | Predicate::ObjectSafe(_) => {
                    bug!("object safe predicate on function: {:#?}", predicate)
                }
                Predicate::ClosureKind(..) => {
                    bug!("closure kind predicate on function: {:#?}", predicate)
                }
                Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
                Predicate::Trait(pred) => {
                    if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
                        continue;
                    }
                    match pred.skip_binder().self_ty().sty {
                        ty::Param(ref p) => {
                            let generics = tcx.generics_of(current);
                            let def = generics.type_param(p, tcx);
                            let span = tcx.def_span(def.def_id);
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ));
                        }
                        // other kinds of bounds are either tautologies
                        // or cause errors in other passes
                        _ => continue,
                    }
                }
            }
        }
        match predicates.parent {
            Some(parent) => current = parent,
            None => break,
        }
    }

    for local in &mir.local_decls {
        check_ty(tcx, local.ty, local.source_info.span, def_id)?;
    }
    // impl trait is gone in MIR, so check the return type manually
    check_ty(
        tcx,
        tcx.fn_sig(def_id).output().skip_binder(),
        mir.local_decls.iter().next().unwrap().source_info.span,
        def_id,
    )?;

    for bb in mir.basic_blocks() {
        check_terminator(tcx, mir, bb.terminator())?;
        for stmt in &bb.statements {
            check_statement(tcx, mir, stmt)?;
        }
    }
    Ok(())
}

fn check_ty(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    ty: Ty<'tcx>,
    span: Span,
    fn_def_id: DefId,
) -> McfResult {
    for ty in ty.walk() {
        match ty.sty {
            ty::Ref(_, _, hir::Mutability::MutMutable) => return Err((
                span,
                "mutable references in const fn are unstable".into(),
            )),
            ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())),
            ty::FnPtr(..) => {
                if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) {
                    return Err((span, "function pointers in const fn are unstable".into()))
                }
            }
            ty::Dynamic(preds, _) => {
                for pred in preds.iter() {
                    match pred.skip_binder() {
                        | ty::ExistentialPredicate::AutoTrait(_)
                        | ty::ExistentialPredicate::Projection(_) => {
                            return Err((
                                span,
                                "trait bounds other than `Sized` \
                                 on const fn parameters are unstable"
                                    .into(),
                            ))
                        }
                        ty::ExistentialPredicate::Trait(trait_ref) => {
                            if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() {
                                return Err((
                                    span,
                                    "trait bounds other than `Sized` \
                                     on const fn parameters are unstable"
                                        .into(),
                                ));
                            }
                        }
                    }
                }
            }
            _ => {}
        }
    }
    Ok(())
}

fn check_rvalue(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    rvalue: &Rvalue<'tcx>,
    span: Span,
) -> McfResult {
    match rvalue {
        Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => {
            check_operand(operand, span)
        }
        Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) => {
            check_place(place, span)
        }
        Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
            use rustc::ty::cast::CastTy;
            let cast_in = CastTy::from_ty(operand.ty(mir, tcx)).expect("bad input type for cast");
            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
            match (cast_in, cast_out) {
                (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => Err((
                    span,
                    "casting pointers to ints is unstable in const fn".into(),
                )),
                (CastTy::RPtr(_), CastTy::Float) => bug!(),
                (CastTy::RPtr(_), CastTy::Int(_)) => bug!(),
                (CastTy::Ptr(_), CastTy::RPtr(_)) => bug!(),
                _ => check_operand(operand, span),
            }
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::MutToConstPointer), operand, _) => {
            check_operand(operand, span)
        }
        Rvalue::Cast(CastKind::Pointer(PointerCast::UnsafeFnPointer), _, _) |
        Rvalue::Cast(CastKind::Pointer(PointerCast::ClosureFnPointer(_)), _, _) |
        Rvalue::Cast(CastKind::Pointer(PointerCast::ReifyFnPointer), _, _) => Err((
            span,
            "function pointer casts are not allowed in const fn".into(),
        )),
        Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => Err((
            span,
            "unsizing casts are not allowed in const fn".into(),
        )),
        // binops are fine on integers
        Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
            check_operand(lhs, span)?;
            check_operand(rhs, span)?;
            let ty = lhs.ty(mir, tcx);
            if ty.is_integral() || ty.is_bool() || ty.is_char() {
                Ok(())
            } else {
                Err((
                    span,
                    "only int, `bool` and `char` operations are stable in const fn".into(),
                ))
            }
        }
        Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()),
        Rvalue::NullaryOp(NullOp::Box, _) => Err((
            span,
            "heap allocations are not allowed in const fn".into(),
        )),
        Rvalue::UnaryOp(_, operand) => {
            let ty = operand.ty(mir, tcx);
            if ty.is_integral() || ty.is_bool() {
                check_operand(operand, span)
            } else {
                Err((
                    span,
                    "only int and `bool` operations are stable in const fn".into(),
                ))
            }
        }
        Rvalue::Aggregate(_, operands) => {
            for operand in operands {
                check_operand(operand, span)?;
            }
            Ok(())
        }
    }
}

fn check_statement(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    statement: &Statement<'tcx>,
) -> McfResult {
    let span = statement.source_info.span;
    match &statement.kind {
        StatementKind::Assign(place, rval) => {
            check_place(place, span)?;
            check_rvalue(tcx, mir, rval, span)
        }

        StatementKind::FakeRead(_, place) => check_place(place, span),

        // just an assignment
        StatementKind::SetDiscriminant { .. } => Ok(()),

        | StatementKind::InlineAsm { .. } => {
            Err((span, "cannot use inline assembly in const fn".into()))
        }

        // These are all NOPs
        | StatementKind::StorageLive(_)
        | StatementKind::StorageDead(_)
        | StatementKind::Retag { .. }
        | StatementKind::AscribeUserType(..)
        | StatementKind::Nop => Ok(()),
    }
}

fn check_operand(
    operand: &Operand<'tcx>,
    span: Span,
) -> McfResult {
    match operand {
        Operand::Move(place) | Operand::Copy(place) => {
            check_place(place, span)
        }
        Operand::Constant(_) => Ok(()),
    }
}

fn check_place(place: &Place<'tcx>, span: Span) -> McfResult {
    place.iterate(|place_base, place_projection| {
        for proj in place_projection {
            match proj.elem {
                ProjectionElem::Downcast(..) => {
                    return Err((span, "`match` or `if let` in `const fn` is unstable".into()));
                }
                ProjectionElem::ConstantIndex { .. }
                | ProjectionElem::Subslice { .. }
                | ProjectionElem::Deref
                | ProjectionElem::Field(..)
                | ProjectionElem::Index(_) => {}
            }
        }

        match place_base {
            PlaceBase::Static(box Static { kind: StaticKind::Static(_), .. }) => {
                Err((span, "cannot access `static` items in const fn".into()))
            }
            PlaceBase::Local(_)
            | PlaceBase::Static(box Static { kind: StaticKind::Promoted(_), .. }) => Ok(()),
        }
    })
}

fn check_terminator(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    terminator: &Terminator<'tcx>,
) -> McfResult {
    let span = terminator.source_info.span;
    match &terminator.kind {
        | TerminatorKind::Goto { .. }
        | TerminatorKind::Return
        | TerminatorKind::Resume => Ok(()),

        TerminatorKind::Drop { location, .. } => {
            check_place(location, span)
        }
        TerminatorKind::DropAndReplace { location, value, .. } => {
            check_place(location, span)?;
            check_operand(value, span)
        },

        TerminatorKind::FalseEdges { .. } | TerminatorKind::SwitchInt { .. } => Err((
            span,
            "`if`, `match`, `&&` and `||` are not stable in const fn".into(),
        )),
        | TerminatorKind::Abort | TerminatorKind::Unreachable => {
            Err((span, "const fn with unreachable code is not stable".into()))
        }
        | TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
            Err((span, "const fn generators are unstable".into()))
        }

        TerminatorKind::Call {
            func,
            args,
            from_hir_call: _,
            destination: _,
            cleanup: _,
        } => {
            let fn_ty = func.ty(mir, tcx);
            if let ty::FnDef(def_id, _) = fn_ty.sty {

                // some intrinsics are waved through if called inside the
                // standard library. Users never need to call them directly
                match tcx.fn_sig(def_id).abi() {
                    abi::Abi::RustIntrinsic => if !is_intrinsic_whitelisted(tcx, def_id) {
                        return Err((
                            span,
                            "can only call a curated list of intrinsics in `min_const_fn`".into(),
                        ))
                    },
                    abi::Abi::Rust if tcx.is_min_const_fn(def_id) => {},
                    abi::Abi::Rust => return Err((
                        span,
                        format!(
                            "can only call other `const fn` within a `const fn`, \
                             but `{:?}` is not stable as `const fn`",
                            func,
                        )
                        .into(),
                    )),
                    abi => return Err((
                        span,
                        format!(
                            "cannot call functions with `{}` abi in `min_const_fn`",
                            abi,
                        ).into(),
                    )),
                }

                check_operand(func, span)?;

                for arg in args {
                    check_operand(arg, span)?;
                }
                Ok(())
            } else {
                Err((span, "can only call other const fns within const fn".into()))
            }
        }

        TerminatorKind::Assert {
            cond,
            expected: _,
            msg: _,
            target: _,
            cleanup: _,
        } => check_operand(cond, span),

        TerminatorKind::FalseUnwind { .. } => {
            Err((span, "loops are not allowed in const fn".into()))
        },
    }
}

/// Returns `true` if the `def_id` refers to an intrisic which we've whitelisted
/// for being called from stable `const fn`s (`min_const_fn`).
///
/// Adding more intrinsics requires sign-off from @rust-lang/lang.
fn is_intrinsic_whitelisted(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
    match &tcx.item_name(def_id).as_str()[..] {
        | "size_of"
        | "min_align_of"
        | "needs_drop"
        // Arithmetic:
        | "add_with_overflow" // ~> .overflowing_add
        | "sub_with_overflow" // ~> .overflowing_sub
        | "mul_with_overflow" // ~> .overflowing_mul
        | "overflowing_add" // ~> .wrapping_add
        | "overflowing_sub" // ~> .wrapping_sub
        | "overflowing_mul" // ~> .wrapping_mul
        | "saturating_add" // ~> .saturating_add
        | "saturating_sub" // ~> .saturating_sub
        | "unchecked_shl" // ~> .wrapping_shl
        | "unchecked_shr" // ~> .wrapping_shr
        | "rotate_left" // ~> .rotate_left
        | "rotate_right" // ~> .rotate_right
        | "ctpop" // ~> .count_ones
        | "ctlz" // ~> .leading_zeros
        | "cttz" // ~> .trailing_zeros
        | "bswap" // ~> .swap_bytes
        | "bitreverse" // ~> .reverse_bits
        => true,
        _ => false,
    }
}
<|endoftext|>


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

extern crate collections;
extern crate serialize;
extern crate debug;

use std::collections::HashMap;
use serialize::json;
use std::option;

enum object {
    bool_value(bool),
    int_value(i64),
}

fn lookup(table: Box<json::Object>, key: String, default: String) -> String
{
    match table.find(&key.to_string()) {
        option::Some(&json::String(ref s)) => {
            (*s).to_string()
        }
        option::Some(value) => {
            println!("{} was expected to be a string but is a {:?}", key, value);
            default
        }
        option::None => {
            default
        }
    }
}

fn add_interface(_store: int, managed_ip: String, data: json::Json) -> (String, object)
{
    match &data {
        &json::Object(ref interface) => {
            let name = lookup((*interface).clone(),
                              "ifDescr".to_string(),
                              "".to_string());
            let label = format!("{}-{}", managed_ip, name);

            (label, bool_value(false))
        }
        _ => {
            println!("Expected dict for {} interfaces but found {:?}", managed_ip, data);
            ("gnos:missing-interface".to_string(), bool_value(true))
        }
    }
}

fn add_interfaces(store: int, managed_ip: String, device: HashMap<String, json::Json>)
-> Vec<(String, object)> {
    match device.get(&"interfaces".to_string())
    {
        &json::List(ref interfaces) =>
        {
          interfaces.iter().map(|interface| {
                add_interface(store, managed_ip.clone(), (*interface).clone())
          }).collect()
        }
        _ =>
        {
            println!("Expected list for {} interfaces but found {:?}", managed_ip,
                   device.get(&"interfaces".to_string()));
            Vec::new()
        }
    }
}

pub fn main() {}
<commit_msg>Fix issue with tests<commit_after>
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate collections;
extern crate serialize;
extern crate debug;

use std::collections::HashMap;
use serialize::json;
use std::option;

enum object {
    bool_value(bool),
    int_value(i64),
}

fn lookup(table: json::Object, key: String, default: String) -> String
{
    match table.find(&key.to_string()) {
        option::Some(&json::String(ref s)) => {
            s.to_string()
        }
        option::Some(value) => {
            println!("{} was expected to be a string but is a {:?}", key, value);
            default
        }
        option::None => {
            default
        }
    }
}

fn add_interface(_store: int, managed_ip: String, data: json::Json) -> (String, object)
{
    match &data {
        &json::Object(ref interface) => {
            let name = lookup(interface.clone(),
                              "ifDescr".to_string(),
                              "".to_string());
            let label = format!("{}-{}", managed_ip, name);

            (label, bool_value(false))
        }
        _ => {
            println!("Expected dict for {} interfaces but found {:?}", managed_ip, data);
            ("gnos:missing-interface".to_string(), bool_value(true))
        }
    }
}

fn add_interfaces(store: int, managed_ip: String, device: HashMap<String, json::Json>)
-> Vec<(String, object)> {
    match device.get(&"interfaces".to_string())
    {
        &json::List(ref interfaces) =>
        {
          interfaces.iter().map(|interface| {
                add_interface(store, managed_ip.clone(), (*interface).clone())
          }).collect()
        }
        _ =>
        {
            println!("Expected list for {} interfaces but found {:?}", managed_ip,
                   device.get(&"interfaces".to_string()));
            Vec::new()
        }
    }
}

pub fn main() {}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Tests for the identity challenge.

use manticore::cert;
use manticore::cert::CertFormat;
use manticore::cert::TrustChain as _;
use manticore::crypto::hash;
use manticore::crypto::hash::EngineExt as _;
use manticore::crypto::ring;
use manticore::crypto::sig;
use manticore::crypto::sig::Ciphers as _;
use manticore::io::Cursor;
use manticore::mem::Arena as _;
use manticore::mem::BumpArena;
use manticore::protocol::wire::ToWire;
use testutil::data::keys;
use testutil::data::x509;

use crate::pa_rot;

#[test]
fn challenge() {
    use manticore::protocol::challenge::*;
    use manticore::protocol::get_cert::*;
    use manticore::protocol::get_digests::*;

    let mut h = ring::hash::Engine::new();
    let virt = pa_rot::Virtual::spawn(&pa_rot::Options {
        cert_chain: vec![
            x509::CHAIN1.to_vec(),
            x509::CHAIN2.to_vec(),
            x509::CHAIN3.to_vec(),
        ],
        cert_format: CertFormat::RiotX509,
        alias_keypair: Some(pa_rot::KeyPairFormat::RsaPkcs8(
            keys::KEY3_RSA_KEYPAIR.to_vec(),
        )),
        ..Default::default()
    });

    let mut arena = BumpArena::new(vec![0; 1024]);
    let resp = virt
        .send_local::<GetDigests, _>(
            GetDigestsRequest {
                slot: 0,
                key_exchange: KeyExchangeAlgo::None,
            },
            &arena,
        )
        .unwrap()
        .unwrap();
    log::info!("got digests: {:#?}", resp);

    // Ensure that the root certificate is one that we implicitly trust.
    // We won't request this certificate; only the two after it.
    let mut root_hash = [0; 32];
    h.contiguous_hash(hash::Algo::Sha256, x509::CHAIN1, &mut root_hash)
        .unwrap();
    assert_eq!(resp.digests[0], root_hash);
    let digests = resp.digests.to_vec();
    arena.reset();

    let mut certs = vec![x509::CHAIN1.to_vec()];
    for (i, digest) in digests.iter().enumerate().skip(1) {
        let mut cert = Vec::new();
        loop {
            let resp = virt
                .send_local::<GetCert, _>(
                    GetCertRequest {
                        slot: 0,
                        cert_number: i as u8,
                        offset: cert.len() as u16,
                        len: 256,
                    },
                    &arena,
                )
                .unwrap()
                .unwrap();
            assert_eq!(resp.slot, 0);
            assert_eq!(resp.cert_number, i as u8);
            cert.extend_from_slice(resp.data);

            let len = resp.data.len();
            arena.reset();
            if len < 256 {
                break;
            }
        }
        let mut cert_hash = [0; 32];
        h.contiguous_hash(hash::Algo::Sha256, &cert, &mut cert_hash)
            .unwrap();
        assert!(&cert_hash == digest, "got wrong cert #{} from RoT!", i);
        certs.push(cert);
    }

    // Check that we have a valid cert chain.
    let certs = certs.iter().map(Vec::as_ref).collect::<Vec<_>>();
    let mut ciphers = ring::sig::Ciphers::new();
    let certs = cert::SimpleChain::<8>::parse(
        &certs,
        CertFormat::RiotX509,
        &mut ciphers,
        None,
    )
    .unwrap();

    // Issue a challenge.
    let req = ChallengeRequest {
        slot: 0,
        nonce: &[99; 32],
    };
    let resp = virt
        .send_local::<Challenge, _>(req, &arena)
        .unwrap()
        .unwrap();
    log::info!("got nonce: {:?}", resp.tbs.nonce);

    // Compute the expected signee: our challenge, plus the response's
    // TBS portion.
    let mut buf = vec![0; 1024];
    let mut cursor = Cursor::new(&mut buf);
    ToWire::to_wire(&req, &mut cursor).unwrap();
    ToWire::to_wire(&resp.tbs, &mut cursor).unwrap();

    let alias_cert = certs.cert(0, digests.len() - 1).unwrap();
    let verifier = ciphers
        .verifier(sig::Algo::RsaPkcs1Sha256, alias_cert.subject_key())
        .unwrap();

    assert!(verifier
        .verify(&[cursor.consumed_bytes()], &resp.signature)
        .is_ok());
}
<commit_msg>[e2e] Add an end-to-end test for key exchange<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Tests for the identity challenge.

use manticore::cert;
use manticore::cert::CertFormat;
use manticore::cert::TrustChain as _;
use manticore::crypto::hash;
use manticore::crypto::hash::EngineExt as _;
use manticore::crypto::ring;
use manticore::crypto::sig;
use manticore::crypto::sig::Ciphers as _;
use manticore::io::Cursor;
use manticore::mem::Arena as _;
use manticore::mem::BumpArena;
use manticore::protocol::wire::ToWire;
use manticore::session;
use manticore::session::Session as _;
use testutil::data::keys;
use testutil::data::x509;

use crate::pa_rot;

#[test]
fn challenge() {
    use manticore::protocol::challenge::*;
    use manticore::protocol::get_cert::*;
    use manticore::protocol::get_digests::*;
    use manticore::protocol::key_exchange::*;

    let mut h = ring::hash::Engine::new();
    let virt = pa_rot::Virtual::spawn(&pa_rot::Options {
        cert_chain: vec![
            x509::CHAIN1.to_vec(),
            x509::CHAIN2.to_vec(),
            x509::CHAIN3.to_vec(),
        ],
        cert_format: CertFormat::RiotX509,
        alias_keypair: Some(pa_rot::KeyPairFormat::RsaPkcs8(
            keys::KEY3_RSA_KEYPAIR.to_vec(),
        )),
        ..Default::default()
    });

    let mut arena = BumpArena::new(vec![0; 1024]);
    let resp = virt
        .send_local::<GetDigests, _>(
            GetDigestsRequest {
                slot: 0,
                key_exchange: KeyExchangeAlgo::Ecdh,
            },
            &arena,
        )
        .unwrap()
        .unwrap();
    log::info!("got digests: {:#?}", resp);

    // Ensure that the root certificate is one that we implicitly trust.
    // We won't request this certificate; only the two after it.
    let mut root_hash = [0; 32];
    h.contiguous_hash(hash::Algo::Sha256, x509::CHAIN1, &mut root_hash)
        .unwrap();
    assert_eq!(resp.digests[0], root_hash);
    let digests = resp.digests.to_vec();
    arena.reset();

    let mut certs = vec![x509::CHAIN1.to_vec()];
    for (i, digest) in digests.iter().enumerate().skip(1) {
        let mut cert = Vec::new();
        loop {
            let resp = virt
                .send_local::<GetCert, _>(
                    GetCertRequest {
                        slot: 0,
                        cert_number: i as u8,
                        offset: cert.len() as u16,
                        len: 256,
                    },
                    &arena,
                )
                .unwrap()
                .unwrap();
            assert_eq!(resp.slot, 0);
            assert_eq!(resp.cert_number, i as u8);
            cert.extend_from_slice(resp.data);

            let len = resp.data.len();
            arena.reset();
            if len < 256 {
                break;
            }
        }
        let mut cert_hash = [0; 32];
        h.contiguous_hash(hash::Algo::Sha256, &cert, &mut cert_hash)
            .unwrap();
        assert!(&cert_hash == digest, "got wrong cert #{} from RoT!", i);
        certs.push(cert);
    }

    // Check that we have a valid cert chain.
    let certs = certs.iter().map(Vec::as_ref).collect::<Vec<_>>();
    let mut ciphers = ring::sig::Ciphers::new();
    let certs = cert::SimpleChain::<8>::parse(
        &certs,
        CertFormat::RiotX509,
        &mut ciphers,
        None,
    )
    .unwrap();

    // Issue a challenge.
    let req = ChallengeRequest {
        slot: 0,
        nonce: &[99; 32],
    };
    let resp = virt
        .send_local::<Challenge, _>(req, &arena)
        .unwrap()
        .unwrap();
    log::info!("got nonce: {:?}", resp.tbs.nonce);

    // Compute the expected signee: our challenge, plus the response's
    // TBS portion.
    let mut buf = vec![0; 1024];
    let mut cursor = Cursor::new(&mut buf);
    ToWire::to_wire(&req, &mut cursor).unwrap();
    ToWire::to_wire(&resp.tbs, &mut cursor).unwrap();

    let alias_cert = certs.cert(0, digests.len() - 1).unwrap();
    let verifier = ciphers
        .verifier(sig::Algo::RsaPkcs1Sha256, alias_cert.subject_key())
        .unwrap();

    verifier
        .verify(&[cursor.consumed_bytes()], &resp.signature)
        .unwrap();

    let mut session = session::ring::Session::new();
    session.create_session(&[99; 32], resp.tbs.nonce).unwrap();

    let mut pk_req = vec![0; session.ephemeral_bytes()];
    let pk_len = session.begin_ecdh(&mut pk_req).unwrap();
    let pk_req = &pk_req[..pk_len];

    let req = KeyExchangeRequest::SessionKey {
        hmac_algorithm: hash::Algo::Sha256,
        pk_req,
    };
    let resp = virt
        .send_local::<KeyExchange, _>(req, &arena)
        .unwrap()
        .unwrap();
    let (pk_resp, pk_sig, alias_hmac) = match resp {
        KeyExchangeResponse::SessionKey {
            pk_resp,
            signature,
            alias_cert_hmac,
        } => (pk_resp, signature, alias_cert_hmac),
        _ => panic!(),
    };
    verifier.verify(&[pk_req, pk_resp], pk_sig).unwrap();

    session.finish_ecdh(hash::Algo::Sha256, pk_resp).unwrap();
    let (_, hmac_key) = session.hmac_key().unwrap();
    let mut hasher = h.new_hmac(hash::Algo::Sha256, hmac_key).unwrap();
    hasher.write(alias_cert.raw()).unwrap();
    hasher.expect(alias_hmac).unwrap();
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::iter::FromIterator;

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StarredMessage {
	pub starrers: Vec<String>,
	pub stars   : u64,
	pub sender  : String,
	pub message : String,
}

impl StarredMessage {
	pub fn from_message_content(message: &str, starrer: Option<String>) -> Option<StarredMessage> {
		starrer.and_then(move |starrer| Self::regex().captures(message).map(move |captures| StarredMessage{
			starrers: vec![starrer],
			stars   : 1u64,
			sender  : captures[1].to_string(),
			message : captures[2].to_string(),
		}))
	}

	fn regex() -> Regex {
		Regex::new(r#"[[:blank:]]*<([[:alnum:]\[\]`_^{|}-]{0,16})>[[:blank:]]*(.+)[[:blank:]]*"#).unwrap()
	}
}

#[cfg(test)]
mod tests {
	use starred_message::StarredMessage;

	#[test]
	fn message_extracts_correctly() {
		let msg = StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", Some("thecoshman".to_string())).unwrap();
		assert_eq!(msg.sender, "nabijaczleweli");
		assert_eq!(msg.message, "I only clean 'round these parts");
	}

	#[test]
	fn message_fails_properly() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweclean 'round these parts", Some("thecoshman".to_string())), None);
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli>", Some("thecoshman".to_string())), None);
	}

	#[test]
	fn message_propagates_starrer() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", None), None);
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts",
		                                                Some("thecoshman".to_string())).unwrap().starrers, vec!["thecoshman".to_string()]);
	}

	#[test]
	fn message_defaults_to_1_star() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", Some("thecoshman".to_string())).unwrap().stars, 1);
	}
}
<commit_msg>Fix unused import<commit_after>use regex::Regex;

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct StarredMessage {
	pub starrers: Vec<String>,
	pub stars   : u64,
	pub sender  : String,
	pub message : String,
}

impl StarredMessage {
	pub fn from_message_content(message: &str, starrer: Option<String>) -> Option<StarredMessage> {
		starrer.and_then(move |starrer| Self::regex().captures(message).map(move |captures| StarredMessage{
			starrers: vec![starrer],
			stars   : 1u64,
			sender  : captures[1].to_string(),
			message : captures[2].to_string(),
		}))
	}

	fn regex() -> Regex {
		Regex::new(r#"[[:blank:]]*<([[:alnum:]\[\]`_^{|}-]{0,16})>[[:blank:]]*(.+)[[:blank:]]*"#).unwrap()
	}
}

#[cfg(test)]
mod tests {
	use starred_message::StarredMessage;

	#[test]
	fn message_extracts_correctly() {
		let msg = StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", Some("thecoshman".to_string())).unwrap();
		assert_eq!(msg.sender, "nabijaczleweli");
		assert_eq!(msg.message, "I only clean 'round these parts");
	}

	#[test]
	fn message_fails_properly() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweclean 'round these parts", Some("thecoshman".to_string())), None);
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli>", Some("thecoshman".to_string())), None);
	}

	#[test]
	fn message_propagates_starrer() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", None), None);
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts",
		                                                Some("thecoshman".to_string())).unwrap().starrers, vec!["thecoshman".to_string()]);
	}

	#[test]
	fn message_defaults_to_1_star() {
		assert_eq!(StarredMessage::from_message_content("<nabijaczleweli> I only clean 'round these parts", Some("thecoshman".to_string())).unwrap().stars, 1);
	}
}
<|endoftext|>


<commit_before>//! Module for generating dep-info files.
//!
//! `rustc` generates a dep-info file with a `.d` extension at the same
//! location of the output artifacts as a result of using `--emit=dep-info`.
//! This dep-info file is a Makefile-like syntax that indicates the
//! dependencies needed to build the artifact. Example:
//!
//! ```makefile
//! /path/to/target/debug/deps/cargo-b6219d178925203d: src/bin/main.rs src/bin/cargo/cli.rs # … etc.
//! ```
//!
//! The fingerprint module has code to parse these files, and stores them as
//! binary format in the fingerprint directory. These are used to quickly scan
//! for any changed files.
//!
//! On top of all this, Cargo emits its own dep-info files in the output
//! directory. This is done for every "uplifted" artifact. These are intended
//! to be used with external build systems so that they can detect if Cargo
//! needs to be re-executed. It includes all the entries from the `rustc`
//! dep-info file, and extends it with any `rerun-if-changed` entries from
//! build scripts. It also includes sources from any path dependencies. Registry
//! dependencies are not included under the assumption that changes to them can
//! be detected via changes to `Cargo.lock`.

use std::collections::{BTreeSet, HashSet};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

use super::{fingerprint, Context, FileFlavor, Unit};
use crate::util::{internal, CargoResult};
use cargo_util::paths;
use log::debug;

fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
    let path = path.as_ref();
    let relpath = match basedir {
        None => path,
        Some(base) => match path.strip_prefix(base) {
            Ok(relpath) => relpath,
            _ => path,
        },
    };
    relpath
        .to_str()
        .ok_or_else(|| internal(format!("path `{:?}` not utf-8", relpath)))
        .map(|f| f.replace(" ", "\\ "))
}

fn add_deps_for_unit(
    deps: &mut BTreeSet<PathBuf>,
    cx: &mut Context<'_, '_>,
    unit: &Unit,
    visited: &mut HashSet<Unit>,
) -> CargoResult<()> {
    if !visited.insert(unit.clone()) {
        return Ok(());
    }

    // units representing the execution of a build script don't actually
    // generate a dep info file, so we just keep on going below
    if !unit.mode.is_run_custom_build() {
        // Add dependencies from rustc dep-info output (stored in fingerprint directory)
        let dep_info_loc = fingerprint::dep_info_loc(cx, unit);
        if let Some(paths) =
            fingerprint::parse_dep_info(unit.pkg.root(), cx.files().host_root(), &dep_info_loc)?
        {
            for path in paths.files {
                deps.insert(path);
            }
        } else {
            debug!(
                "can't find dep_info for {:?} {}",
                unit.pkg.package_id(),
                unit.target
            );
            return Err(internal("dep_info missing"));
        }
    }

    // Add rerun-if-changed dependencies
    if let Some(metadata) = cx.find_build_script_metadata(unit) {
        if let Some(output) = cx.build_script_outputs.lock().unwrap().get(metadata) {
            for path in &output.rerun_if_changed {
                // The paths we have saved from the unit are of arbitrary relativeness and may be
                // relative to the crate root of the dependency.
                let path = unit.pkg.root().join(path);
                deps.insert(path.into());
            }
        }
    }

    // Recursively traverse all transitive dependencies
    let unit_deps = Vec::from(cx.unit_deps(unit)); // Create vec due to mutable borrow.
    for dep in unit_deps {
        if dep.unit.is_local() {
            add_deps_for_unit(deps, cx, &dep.unit, visited)?;
        }
    }
    Ok(())
}

/// Save a `.d` dep-info file for the given unit.
///
/// This only saves files for uplifted artifacts.
pub fn output_depinfo(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<()> {
    let bcx = cx.bcx;
    let mut deps = BTreeSet::new();
    let mut visited = HashSet::new();
    let success = add_deps_for_unit(&mut deps, cx, unit, &mut visited).is_ok();
    let basedir_string;
    let basedir = match bcx.config.build_config()?.dep_info_basedir.clone() {
        Some(value) => {
            basedir_string = value
                .resolve_path(bcx.config)
                .as_os_str()
                .to_str()
                .ok_or_else(|| anyhow::format_err!("build.dep-info-basedir path not utf-8"))?
                .to_string();
            Some(basedir_string.as_str())
        }
        None => None,
    };
    let deps = deps
        .iter()
        .map(|f| render_filename(f, basedir))
        .collect::<CargoResult<Vec<_>>>()?;

    for output in cx
        .outputs(unit)?
        .iter()
        .filter(|o| !matches!(o.flavor, FileFlavor::DebugInfo | FileFlavor::Auxiliary))
    {
        if let Some(ref link_dst) = output.hardlink {
            let output_path = link_dst.with_extension("d");
            if success {
                let target_fn = render_filename(link_dst, basedir)?;

                // If nothing changed don't recreate the file which could alter
                // its mtime
                if let Ok(previous) = fingerprint::parse_rustc_dep_info(&output_path) {
                    if previous.files.iter().eq(deps.iter().map(Path::new)) {
                        continue;
                    }
                }

                // Otherwise write it all out
                let mut outfile = BufWriter::new(paths::create(output_path)?);
                write!(outfile, "{}:", target_fn)?;
                for dep in &deps {
                    write!(outfile, " {}", dep)?;
                }
                writeln!(outfile)?;

            // dep-info generation failed, so delete output file. This will
            // usually cause the build system to always rerun the build
            // rule, which is correct if inefficient.
            } else if output_path.exists() {
                paths::remove_file(output_path)?;
            }
        }
    }
    Ok(())
}
<commit_msg>Auto merge of #9617 - danieleades:refactor/useless-conversions, r=ehuss<commit_after>//! Module for generating dep-info files.
//!
//! `rustc` generates a dep-info file with a `.d` extension at the same
//! location of the output artifacts as a result of using `--emit=dep-info`.
//! This dep-info file is a Makefile-like syntax that indicates the
//! dependencies needed to build the artifact. Example:
//!
//! ```makefile
//! /path/to/target/debug/deps/cargo-b6219d178925203d: src/bin/main.rs src/bin/cargo/cli.rs # … etc.
//! ```
//!
//! The fingerprint module has code to parse these files, and stores them as
//! binary format in the fingerprint directory. These are used to quickly scan
//! for any changed files.
//!
//! On top of all this, Cargo emits its own dep-info files in the output
//! directory. This is done for every "uplifted" artifact. These are intended
//! to be used with external build systems so that they can detect if Cargo
//! needs to be re-executed. It includes all the entries from the `rustc`
//! dep-info file, and extends it with any `rerun-if-changed` entries from
//! build scripts. It also includes sources from any path dependencies. Registry
//! dependencies are not included under the assumption that changes to them can
//! be detected via changes to `Cargo.lock`.

use std::collections::{BTreeSet, HashSet};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};

use super::{fingerprint, Context, FileFlavor, Unit};
use crate::util::{internal, CargoResult};
use cargo_util::paths;
use log::debug;

fn render_filename<P: AsRef<Path>>(path: P, basedir: Option<&str>) -> CargoResult<String> {
    let path = path.as_ref();
    let relpath = match basedir {
        None => path,
        Some(base) => match path.strip_prefix(base) {
            Ok(relpath) => relpath,
            _ => path,
        },
    };
    relpath
        .to_str()
        .ok_or_else(|| internal(format!("path `{:?}` not utf-8", relpath)))
        .map(|f| f.replace(" ", "\\ "))
}

fn add_deps_for_unit(
    deps: &mut BTreeSet<PathBuf>,
    cx: &mut Context<'_, '_>,
    unit: &Unit,
    visited: &mut HashSet<Unit>,
) -> CargoResult<()> {
    if !visited.insert(unit.clone()) {
        return Ok(());
    }

    // units representing the execution of a build script don't actually
    // generate a dep info file, so we just keep on going below
    if !unit.mode.is_run_custom_build() {
        // Add dependencies from rustc dep-info output (stored in fingerprint directory)
        let dep_info_loc = fingerprint::dep_info_loc(cx, unit);
        if let Some(paths) =
            fingerprint::parse_dep_info(unit.pkg.root(), cx.files().host_root(), &dep_info_loc)?
        {
            for path in paths.files {
                deps.insert(path);
            }
        } else {
            debug!(
                "can't find dep_info for {:?} {}",
                unit.pkg.package_id(),
                unit.target
            );
            return Err(internal("dep_info missing"));
        }
    }

    // Add rerun-if-changed dependencies
    if let Some(metadata) = cx.find_build_script_metadata(unit) {
        if let Some(output) = cx.build_script_outputs.lock().unwrap().get(metadata) {
            for path in &output.rerun_if_changed {
                // The paths we have saved from the unit are of arbitrary relativeness and may be
                // relative to the crate root of the dependency.
                let path = unit.pkg.root().join(path);
                deps.insert(path);
            }
        }
    }

    // Recursively traverse all transitive dependencies
    let unit_deps = Vec::from(cx.unit_deps(unit)); // Create vec due to mutable borrow.
    for dep in unit_deps {
        if dep.unit.is_local() {
            add_deps_for_unit(deps, cx, &dep.unit, visited)?;
        }
    }
    Ok(())
}

/// Save a `.d` dep-info file for the given unit.
///
/// This only saves files for uplifted artifacts.
pub fn output_depinfo(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<()> {
    let bcx = cx.bcx;
    let mut deps = BTreeSet::new();
    let mut visited = HashSet::new();
    let success = add_deps_for_unit(&mut deps, cx, unit, &mut visited).is_ok();
    let basedir_string;
    let basedir = match bcx.config.build_config()?.dep_info_basedir.clone() {
        Some(value) => {
            basedir_string = value
                .resolve_path(bcx.config)
                .as_os_str()
                .to_str()
                .ok_or_else(|| anyhow::format_err!("build.dep-info-basedir path not utf-8"))?
                .to_string();
            Some(basedir_string.as_str())
        }
        None => None,
    };
    let deps = deps
        .iter()
        .map(|f| render_filename(f, basedir))
        .collect::<CargoResult<Vec<_>>>()?;

    for output in cx
        .outputs(unit)?
        .iter()
        .filter(|o| !matches!(o.flavor, FileFlavor::DebugInfo | FileFlavor::Auxiliary))
    {
        if let Some(ref link_dst) = output.hardlink {
            let output_path = link_dst.with_extension("d");
            if success {
                let target_fn = render_filename(link_dst, basedir)?;

                // If nothing changed don't recreate the file which could alter
                // its mtime
                if let Ok(previous) = fingerprint::parse_rustc_dep_info(&output_path) {
                    if previous.files.iter().eq(deps.iter().map(Path::new)) {
                        continue;
                    }
                }

                // Otherwise write it all out
                let mut outfile = BufWriter::new(paths::create(output_path)?);
                write!(outfile, "{}:", target_fn)?;
                for dep in &deps {
                    write!(outfile, " {}", dep)?;
                }
                writeln!(outfile)?;

            // dep-info generation failed, so delete output file. This will
            // usually cause the build system to always rerun the build
            // rule, which is correct if inefficient.
            } else if output_path.exists() {
                paths::remove_file(output_path)?;
            }
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>/// The datatype used for the ioctl number
#[cfg(any(target_os = "android", target_env = "musl"))]
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_int;
#[cfg(not(any(target_os = "android", target_env = "musl")))]
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_ulong;
/// The datatype used for the 3rd argument
#[doc(hidden)]
pub type ioctl_param_type = ::libc::c_ulong;

#[doc(hidden)]
pub const NRBITS: ioctl_num_type = 8;
#[doc(hidden)]
pub const TYPEBITS: ioctl_num_type = 8;

#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64"))]
mod consts {
    #[doc(hidden)]
    pub const NONE: u8 = 1;
    #[doc(hidden)]
    pub const READ: u8 = 2;
    #[doc(hidden)]
    pub const WRITE: u8 = 4;
    #[doc(hidden)]
    pub const SIZEBITS: u8 = 13;
    #[doc(hidden)]
    pub const DIRBITS: u8 = 3;
}

// "Generic" ioctl protocol
#[cfg(any(target_arch = "x86",
          target_arch = "arm",
          target_arch = "s390x",
          target_arch = "x86_64",
          target_arch = "aarch64"))]
mod consts {
    #[doc(hidden)]
    pub const NONE: u8 = 0;
    #[doc(hidden)]
    pub const READ: u8 = 2;
    #[doc(hidden)]
    pub const WRITE: u8 = 1;
    #[doc(hidden)]
    pub const SIZEBITS: u8 = 14;
    #[doc(hidden)]
    pub const DIRBITS: u8 = 2;
}

pub use self::consts::*;

#[doc(hidden)]
pub const NRSHIFT: ioctl_num_type = 0;
#[doc(hidden)]
pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
#[doc(hidden)]
pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
#[doc(hidden)]
pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;

#[doc(hidden)]
pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
#[doc(hidden)]
pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
#[doc(hidden)]
pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
#[doc(hidden)]
pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;

/// Encode an ioctl command.
#[macro_export]
#[doc(hidden)]
macro_rules! ioc {
    ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
        (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
        (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
        (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
        (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
}

/// Generate an ioctl request code for a command that passes no data.
///
/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_none!()` directly.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate nix;
/// const KVMIO: u8 = 0xAE;
/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! request_code_none {
    ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
}

/// Generate an ioctl request code for a command that reads.
///
/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_read!()` directly.
///
/// The read/write direction is relative to userland, so this
/// command would be userland is reading and the kernel is
/// writing.
#[macro_export]
macro_rules! request_code_read {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
}

/// Generate an ioctl request code for a command that writes.
///
/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_write!()` directly.
///
/// The read/write direction is relative to userland, so this
/// command would be userland is writing and the kernel is
/// reading.
#[macro_export]
macro_rules! request_code_write {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}

/// Generate an ioctl request code for a command that reads and writes.
///
/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
#[macro_export]
macro_rules! request_code_readwrite {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}
<commit_msg>Add ioctl definitions for sparc64-linux<commit_after>/// The datatype used for the ioctl number
#[cfg(any(target_os = "android", target_env = "musl"))]
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_int;
#[cfg(not(any(target_os = "android", target_env = "musl")))]
#[doc(hidden)]
pub type ioctl_num_type = ::libc::c_ulong;
/// The datatype used for the 3rd argument
#[doc(hidden)]
pub type ioctl_param_type = ::libc::c_ulong;

#[doc(hidden)]
pub const NRBITS: ioctl_num_type = 8;
#[doc(hidden)]
pub const TYPEBITS: ioctl_num_type = 8;

#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
mod consts {
    #[doc(hidden)]
    pub const NONE: u8 = 1;
    #[doc(hidden)]
    pub const READ: u8 = 2;
    #[doc(hidden)]
    pub const WRITE: u8 = 4;
    #[doc(hidden)]
    pub const SIZEBITS: u8 = 13;
    #[doc(hidden)]
    pub const DIRBITS: u8 = 3;
}

// "Generic" ioctl protocol
#[cfg(any(target_arch = "x86",
          target_arch = "arm",
          target_arch = "s390x",
          target_arch = "x86_64",
          target_arch = "aarch64"))]
mod consts {
    #[doc(hidden)]
    pub const NONE: u8 = 0;
    #[doc(hidden)]
    pub const READ: u8 = 2;
    #[doc(hidden)]
    pub const WRITE: u8 = 1;
    #[doc(hidden)]
    pub const SIZEBITS: u8 = 14;
    #[doc(hidden)]
    pub const DIRBITS: u8 = 2;
}

pub use self::consts::*;

#[doc(hidden)]
pub const NRSHIFT: ioctl_num_type = 0;
#[doc(hidden)]
pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
#[doc(hidden)]
pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
#[doc(hidden)]
pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;

#[doc(hidden)]
pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
#[doc(hidden)]
pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
#[doc(hidden)]
pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
#[doc(hidden)]
pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;

/// Encode an ioctl command.
#[macro_export]
#[doc(hidden)]
macro_rules! ioc {
    ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
        (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
        (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
        (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
        (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
}

/// Generate an ioctl request code for a command that passes no data.
///
/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_none!()` directly.
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate nix;
/// const KVMIO: u8 = 0xAE;
/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! request_code_none {
    ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
}

/// Generate an ioctl request code for a command that reads.
///
/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_read!()` directly.
///
/// The read/write direction is relative to userland, so this
/// command would be userland is reading and the kernel is
/// writing.
#[macro_export]
macro_rules! request_code_read {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
}

/// Generate an ioctl request code for a command that writes.
///
/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_write!()` directly.
///
/// The read/write direction is relative to userland, so this
/// command would be userland is writing and the kernel is
/// reading.
#[macro_export]
macro_rules! request_code_write {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}

/// Generate an ioctl request code for a command that reads and writes.
///
/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
///
/// You should only use this macro directly if the `ioctl` you're working
/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
#[macro_export]
macro_rules! request_code_readwrite {
    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
}
<|endoftext|>


<commit_before>//! Tests the serialization of the various datatypes, i.e. the files read.rs
//! and write.rs
use read::*;
use write::*;

use std::io::Cursor;
use std::i32;

/// Given a value, the same correctly encoded, and a reader and write function
/// for that type of value, test that the reader and writer create values that
/// correctly match the supplied ones.
macro_rules! read_and_write {
    ($val:expr, $binary:expr, $reader:path, $writer:path) =>
    {
        let binary = $binary;
        let mut cursor = Cursor::new(binary);
        assert_eq!($reader(&mut cursor).unwrap(), $val);
        let mut tmp = Vec::new();
        $writer(&$val, &mut tmp).unwrap();
        assert_eq!(&tmp, binary);
    };
}

#[test]
fn byteorder() {
    read_and_write!(true, &[1], read_bool, write_bool);
    read_and_write!(-1, &[255], read_i8, write_i8);
    read_and_write!(42, &[42], read_u8, write_u8);
    read_and_write!(-5, &[255, 251], read_i16, write_i16);
    read_and_write!(65535, &[255, 255], read_u16, write_u16);
    read_and_write!(-9, &[255, 255, 255, 247], read_i32, write_i32);
    read_and_write!(-2,
                    &[255, 255, 255, 255, 255, 255, 255, 254],
                    read_i64,
                    write_i64);
    read_and_write!(8898902191272547,
                    &[0x00, 0x1f, 0x9d, 0x81, 0x20, 0x00, 0x72, 0x63],
                    read_u64,
                    write_u64);
    read_and_write!(7546.57470703125,
                    &[0x45, 0xeb, 0xd4, 0x99],
                    read_f32,
                    write_f32);
    read_and_write!(7546.5746871564779212349094450473785400390625,
                    &[0x40, 0xbd, 0x7a, 0x93, 0x1e, 0xb2, 0x8e, 0x81],
                    read_f64,
                    write_f64);
}

#[test]
fn string() {
    read_and_write!("ozelot".to_string(),
                    &[6, b'o', b'z', b'e', b'l', b'o', b't'],
                    read_String,
                    write_String);
    read_and_write!("オゼロット".to_string(),
                    &[15, 0xe3, 0x82, 0xaa, 0xe3, 0x82, 0xbc, 0xe3, 0x83,
                      0xad, 0xe3, 0x83, 0x83, 0xe3, 0x83, 0x88],
                    read_String,
                    write_String);
}

#[test]
fn varint() {
    /* Test some special values */
    read_and_write!(0, &[0], read_varint, write_varint);
    read_and_write!(-1, &[255, 255, 255, 255, 15], read_varint, write_varint);
    read_and_write!(i32::MAX, &[255, 255, 255, 255, 7], read_varint, write_varint);
    read_and_write!(i32::MIN, &[128, 128, 128, 128, 8], read_varint, write_varint);

    /* Test some random numbers */
    read_and_write!(16, &[16], read_varint, write_varint);
    read_and_write!(128, &[0x80, 0x01], read_varint, write_varint);
    read_and_write!(255, &[0xff, 0x01], read_varint, write_varint);
    read_and_write!(300, &[(1 << 7) | 44, 2], read_varint, write_varint);
    read_and_write!(2649887, &[0x9f, 0xde, 0xa1, 0x01], read_varint, write_varint);
}

#[test]
fn varint_too_large() {
    let mut cursor = Cursor::new([128, 128, 128, 128, 16]);
    assert!(read_varint(&mut cursor).is_err());
    let mut cursor = Cursor::new([128, 128, 128, 128, 128]);
    assert!(read_varint(&mut cursor).is_err());
}

#[test]
fn varlong() {
    read_and_write!(0, &[0], read_varlong, write_varlong);
    read_and_write!(1, &[1], read_varlong, write_varlong);
    read_and_write!(2, &[2], read_varlong, write_varlong);
    read_and_write!(127, &[127], read_varlong, write_varlong);
    read_and_write!(128, &[128, 1], read_varlong, write_varlong);
    read_and_write!(255, &[255, 1], read_varlong, write_varlong);
    read_and_write!(300, &[(1 << 7) | 44, 2], read_varlong, write_varlong);
    read_and_write!(2147483647, &[255, 255, 255, 255, 7], read_varlong, write_varlong);
    read_and_write!(9223372036854775807, &[255, 255, 255, 255, 255, 255, 255, 255, 127], read_varlong, write_varlong);
    read_and_write!(-1, &[255, 255, 255, 255, 255, 255, 255, 255, 255, 1], read_varlong, write_varlong);
    read_and_write!(-2147483648, &[128, 128, 128, 128, 248, 255, 255, 255, 255, 1], read_varlong, write_varlong);
    read_and_write!(-9223372036854775808, &[128, 128, 128, 128, 128, 128, 128, 128, 128, 1], read_varlong, write_varlong);
}

#[test]
fn varlong_too_large() {
    let mut cursor = Cursor::new([128, 128, 128, 128, 128, 128, 128, 128, 128, 2]);
    assert!(read_varlong(&mut cursor).is_err());
    let mut cursor = Cursor::new([128, 128, 128, 128, 128, 128, 128, 128, 128, 128]);
    assert!(read_varlong(&mut cursor).is_err());
}

#[test]
fn position() {
    read_and_write!((0, 63, 0),
                    &[0, 0, 0, 0, 0xfc, 0, 0, 0],
                    read_position,
                    write_position);
    read_and_write!((32374, 72, 29283),
                    &[0x00, 0x1f, 0x9d, 0x81, 0x20, 0x00, 0x72, 0x63],
                    read_position,
                    write_position);
    read_and_write!((-32374, -72, 29283),
                    &[0xff, 0xe0, 0x62, 0xbe, 0xe0, 0x00, 0x72, 0x63],
                    read_position,
                    write_position);
    read_and_write!((-109, 64, -120),
                    &[0xff, 0xff, 0xe4, 0xc1, 0x03, 0xff, 0xff, 0x88],
                    read_position,
                    write_position);
}

#[test]
fn uuid_str_without_dashes() {
        let mut binary = vec![32];
        for _ in 0..32 {
            binary.push(48); /* Ascii 0 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str(&mut cursor).unwrap(), 0);
        let mut tmp = Vec::new();
        write_uuid_str(&0, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);

        let mut binary = vec![32];
        for i in 0..10 {
            binary.push(48 + i); /* Ascii 0 - 10 */
        }
        for i in 0..6 {
            binary.push(97 + i); /* Ascii a - f */
        }
        for i in 0..10 {
            binary.push(48 + i); /* Ascii 0 - 10 */
        }
        for i in 0..6 {
            binary.push(97 + i); /* Ascii a - f */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str(&mut cursor).unwrap(), 1512366075204170929049582354406559215);
        let mut tmp = Vec::new();
        write_uuid_str(&1512366075204170929049582354406559215, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);
}

#[test]
fn uuid_str_with_dashes() {
        let mut binary = vec![36];
        for _ in 0..8 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..12 {
            binary.push(48); /* Ascii 0 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str_dashes(&mut cursor).unwrap(), 0);
        let mut tmp = Vec::new();
        write_uuid_str_dashes(&0, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);

        let mut binary = vec![36];
        for i in 0..8 {
            binary.push(48 + i); /* Ascii 0 .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(97 + i); /* Ascii a .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(48 + i); /* Ascii 0 .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(99 + i); /* Ascii c .. */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..12 {
            binary.push(57); /* Ascii 9 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str_dashes(&mut cursor).unwrap(), 1512366085766797629701178291595614617);
        let mut tmp = Vec::new();
        write_uuid_str_dashes(&1512366085766797629701178291595614617, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);
}
<commit_msg>Update position test<commit_after>//! Tests the serialization of the various datatypes, i.e. the files read.rs
//! and write.rs
use read::*;
use write::*;

use std::io::Cursor;
use std::i32;

/// Given a value, the same correctly encoded, and a reader and write function
/// for that type of value, test that the reader and writer create values that
/// correctly match the supplied ones.
macro_rules! read_and_write {
    ($val:expr, $binary:expr, $reader:path, $writer:path) =>
    {
        let binary = $binary;
        let mut cursor = Cursor::new(binary);
        assert_eq!($reader(&mut cursor).unwrap(), $val);
        let mut tmp = Vec::new();
        $writer(&$val, &mut tmp).unwrap();
        assert_eq!(&tmp, binary);
    };
}

#[test]
fn byteorder() {
    read_and_write!(true, &[1], read_bool, write_bool);
    read_and_write!(-1, &[255], read_i8, write_i8);
    read_and_write!(42, &[42], read_u8, write_u8);
    read_and_write!(-5, &[255, 251], read_i16, write_i16);
    read_and_write!(65535, &[255, 255], read_u16, write_u16);
    read_and_write!(-9, &[255, 255, 255, 247], read_i32, write_i32);
    read_and_write!(-2,
                    &[255, 255, 255, 255, 255, 255, 255, 254],
                    read_i64,
                    write_i64);
    read_and_write!(8898902191272547,
                    &[0x00, 0x1f, 0x9d, 0x81, 0x20, 0x00, 0x72, 0x63],
                    read_u64,
                    write_u64);
    read_and_write!(7546.57470703125,
                    &[0x45, 0xeb, 0xd4, 0x99],
                    read_f32,
                    write_f32);
    read_and_write!(7546.5746871564779212349094450473785400390625,
                    &[0x40, 0xbd, 0x7a, 0x93, 0x1e, 0xb2, 0x8e, 0x81],
                    read_f64,
                    write_f64);
}

#[test]
fn string() {
    read_and_write!("ozelot".to_string(),
                    &[6, b'o', b'z', b'e', b'l', b'o', b't'],
                    read_String,
                    write_String);
    read_and_write!("オゼロット".to_string(),
                    &[15, 0xe3, 0x82, 0xaa, 0xe3, 0x82, 0xbc, 0xe3, 0x83,
                      0xad, 0xe3, 0x83, 0x83, 0xe3, 0x83, 0x88],
                    read_String,
                    write_String);
}

#[test]
fn varint() {
    /* Test some special values */
    read_and_write!(0, &[0], read_varint, write_varint);
    read_and_write!(-1, &[255, 255, 255, 255, 15], read_varint, write_varint);
    read_and_write!(i32::MAX, &[255, 255, 255, 255, 7], read_varint, write_varint);
    read_and_write!(i32::MIN, &[128, 128, 128, 128, 8], read_varint, write_varint);

    /* Test some random numbers */
    read_and_write!(16, &[16], read_varint, write_varint);
    read_and_write!(128, &[0x80, 0x01], read_varint, write_varint);
    read_and_write!(255, &[0xff, 0x01], read_varint, write_varint);
    read_and_write!(300, &[(1 << 7) | 44, 2], read_varint, write_varint);
    read_and_write!(2649887, &[0x9f, 0xde, 0xa1, 0x01], read_varint, write_varint);
}

#[test]
fn varint_too_large() {
    let mut cursor = Cursor::new([128, 128, 128, 128, 16]);
    assert!(read_varint(&mut cursor).is_err());
    let mut cursor = Cursor::new([128, 128, 128, 128, 128]);
    assert!(read_varint(&mut cursor).is_err());
}

#[test]
fn varlong() {
    read_and_write!(0, &[0], read_varlong, write_varlong);
    read_and_write!(1, &[1], read_varlong, write_varlong);
    read_and_write!(2, &[2], read_varlong, write_varlong);
    read_and_write!(127, &[127], read_varlong, write_varlong);
    read_and_write!(128, &[128, 1], read_varlong, write_varlong);
    read_and_write!(255, &[255, 1], read_varlong, write_varlong);
    read_and_write!(300, &[(1 << 7) | 44, 2], read_varlong, write_varlong);
    read_and_write!(2147483647, &[255, 255, 255, 255, 7], read_varlong, write_varlong);
    read_and_write!(9223372036854775807, &[255, 255, 255, 255, 255, 255, 255, 255, 127], read_varlong, write_varlong);
    read_and_write!(-1, &[255, 255, 255, 255, 255, 255, 255, 255, 255, 1], read_varlong, write_varlong);
    read_and_write!(-2147483648, &[128, 128, 128, 128, 248, 255, 255, 255, 255, 1], read_varlong, write_varlong);
    read_and_write!(-9223372036854775808, &[128, 128, 128, 128, 128, 128, 128, 128, 128, 1], read_varlong, write_varlong);
}

#[test]
fn varlong_too_large() {
    let mut cursor = Cursor::new([128, 128, 128, 128, 128, 128, 128, 128, 128, 2]);
    assert!(read_varlong(&mut cursor).is_err());
    let mut cursor = Cursor::new([128, 128, 128, 128, 128, 128, 128, 128, 128, 128]);
    assert!(read_varlong(&mut cursor).is_err());
}

#[test]
fn position() {
    read_and_write!((0, 63, 0),
                    &[0, 0, 0, 0, 0, 0, 0, 0x3f],
                    read_position,
                    write_position);
    read_and_write!((32374, 72, 29283),
                    &[0x00, 0x1f, 0x9d, 0x80, 0x07, 0x26, 0x30, 0x48],
                    read_position,
                    write_position);
    read_and_write!((-32374, -72, 29283),
                    &[0xff, 0xe0, 0x62, 0x80, 0x07, 0x26, 0x3f, 0xb8],
                    read_position,
                    write_position);
    read_and_write!((-109, 64, -120),
                    &[0xff, 0xff, 0xe4, 0xff, 0xff, 0xf8, 0x80, 0x40],
                    read_position,
                    write_position);
}

#[test]
fn uuid_str_without_dashes() {
        let mut binary = vec![32];
        for _ in 0..32 {
            binary.push(48); /* Ascii 0 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str(&mut cursor).unwrap(), 0);
        let mut tmp = Vec::new();
        write_uuid_str(&0, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);

        let mut binary = vec![32];
        for i in 0..10 {
            binary.push(48 + i); /* Ascii 0 - 10 */
        }
        for i in 0..6 {
            binary.push(97 + i); /* Ascii a - f */
        }
        for i in 0..10 {
            binary.push(48 + i); /* Ascii 0 - 10 */
        }
        for i in 0..6 {
            binary.push(97 + i); /* Ascii a - f */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str(&mut cursor).unwrap(), 1512366075204170929049582354406559215);
        let mut tmp = Vec::new();
        write_uuid_str(&1512366075204170929049582354406559215, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);
}

#[test]
fn uuid_str_with_dashes() {
        let mut binary = vec![36];
        for _ in 0..8 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..4 {
            binary.push(48); /* Ascii 0 */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..12 {
            binary.push(48); /* Ascii 0 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str_dashes(&mut cursor).unwrap(), 0);
        let mut tmp = Vec::new();
        write_uuid_str_dashes(&0, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);

        let mut binary = vec![36];
        for i in 0..8 {
            binary.push(48 + i); /* Ascii 0 .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(97 + i); /* Ascii a .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(48 + i); /* Ascii 0 .. */
        }
        binary.push(45); /* Ascii - */
        for i in 0..4 {
            binary.push(99 + i); /* Ascii c .. */
        }
        binary.push(45); /* Ascii - */
        for _ in 0..12 {
            binary.push(57); /* Ascii 9 */
        }
        let mut cursor = Cursor::new(&binary);
        assert_eq!(read_uuid_str_dashes(&mut cursor).unwrap(), 1512366085766797629701178291595614617);
        let mut tmp = Vec::new();
        write_uuid_str_dashes(&1512366085766797629701178291595614617, &mut tmp).unwrap();
        assert_eq!(&tmp, &binary);
}
<|endoftext|>


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

use std::fmt;
use std::str::FromStr;
use regex::Regex;

#[derive(Clone, PartialEq, Debug)]
pub enum Mode {
    CompileFail,
    RunFail,
    RunPass,
    RunPassValgrind,
    Pretty,
    DebugInfoGdb,
    DebugInfoLldb,
    Codegen
}

impl Copy for Mode {}

impl FromStr for Mode {
    fn from_str(s: &str) -> Option<Mode> {
        match s {
          "compile-fail" => Some(CompileFail),
          "run-fail" => Some(RunFail),
          "run-pass" => Some(RunPass),
          "run-pass-valgrind" => Some(RunPassValgrind),
          "pretty" => Some(Pretty),
          "debuginfo-lldb" => Some(DebugInfoLldb),
          "debuginfo-gdb" => Some(DebugInfoGdb),
          "codegen" => Some(Codegen),
          _ => None,
        }
    }
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(match *self {
            CompileFail => "compile-fail",
            RunFail => "run-fail",
            RunPass => "run-pass",
            RunPassValgrind => "run-pass-valgrind",
            Pretty => "pretty",
            DebugInfoGdb => "debuginfo-gdb",
            DebugInfoLldb => "debuginfo-lldb",
            Codegen => "codegen",
        }, f)
    }
}

#[derive(Clone)]
pub struct Config {
    // The library paths required for running the compiler
    pub compile_lib_path: String,

    // The library paths required for running compiled programs
    pub run_lib_path: String,

    // The rustc executable
    pub rustc_path: Path,

    // The clang executable
    pub clang_path: Option<Path>,

    // The llvm binaries path
    pub llvm_bin_path: Option<Path>,

    // The valgrind path
    pub valgrind_path: Option<String>,

    // Whether to fail if we can't run run-pass-valgrind tests under valgrind
    // (or, alternatively, to silently run them like regular run-pass tests).
    pub force_valgrind: bool,

    // The directory containing the tests to run
    pub src_base: Path,

    // The directory where programs should be built
    pub build_base: Path,

    // Directory for auxiliary libraries
    pub aux_base: Path,

    // The name of the stage being built (stage1, etc)
    pub stage_id: String,

    // The test mode, compile-fail, run-fail, run-pass
    pub mode: Mode,

    // Run ignored tests
    pub run_ignored: bool,

    // Only run tests that match this filter
    pub filter: Option<Regex>,

    // Precompiled regex for finding expected errors in cfail
    pub cfail_regex: Regex,

    // Write out a parseable log of tests that were run
    pub logfile: Option<Path>,

    // A command line to prefix program execution with,
    // for running under valgrind
    pub runtool: Option<String>,

    // Flags to pass to the compiler when building for the host
    pub host_rustcflags: Option<String>,

    // Flags to pass to the compiler when building for the target
    pub target_rustcflags: Option<String>,

    // Run tests using the JIT
    pub jit: bool,

    // Target system to be tested
    pub target: String,

    // Host triple for the compiler being invoked
    pub host: String,

    // Version of GDB
    pub gdb_version: Option<String>,

    // Version of LLDB
    pub lldb_version: Option<String>,

    // Path to the android tools
    pub android_cross_path: Path,

    // Extra parameter to run adb on arm-linux-androideabi
    pub adb_path: String,

    // Extra parameter to run test suite on arm-linux-androideabi
    pub adb_test_dir: String,

    // status whether android device available or not
    pub adb_device_status: bool,

    // the path containing LLDB's Python module
    pub lldb_python_dir: Option<String>,

    // Explain what's going on
    pub verbose: bool
}
<commit_msg>Fix compile test for stage0<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub use self::Mode::*;

use std::fmt;
use std::str::FromStr;
use regex::Regex;

#[cfg(stage0)] // NOTE: remove impl after snapshot
#[derive(Clone, PartialEq, Show)]
pub enum Mode {
    CompileFail,
    RunFail,
    RunPass,
    RunPassValgrind,
    Pretty,
    DebugInfoGdb,
    DebugInfoLldb,
    Codegen
}

#[cfg(not(stage0))] // NOTE: remove cfg after snapshot
#[derive(Clone, PartialEq, Debug)]
pub enum Mode {
    CompileFail,
    RunFail,
    RunPass,
    RunPassValgrind,
    Pretty,
    DebugInfoGdb,
    DebugInfoLldb,
    Codegen
}

impl Copy for Mode {}

impl FromStr for Mode {
    fn from_str(s: &str) -> Option<Mode> {
        match s {
          "compile-fail" => Some(CompileFail),
          "run-fail" => Some(RunFail),
          "run-pass" => Some(RunPass),
          "run-pass-valgrind" => Some(RunPassValgrind),
          "pretty" => Some(Pretty),
          "debuginfo-lldb" => Some(DebugInfoLldb),
          "debuginfo-gdb" => Some(DebugInfoGdb),
          "codegen" => Some(Codegen),
          _ => None,
        }
    }
}

impl fmt::Display for Mode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(match *self {
            CompileFail => "compile-fail",
            RunFail => "run-fail",
            RunPass => "run-pass",
            RunPassValgrind => "run-pass-valgrind",
            Pretty => "pretty",
            DebugInfoGdb => "debuginfo-gdb",
            DebugInfoLldb => "debuginfo-lldb",
            Codegen => "codegen",
        }, f)
    }
}

#[derive(Clone)]
pub struct Config {
    // The library paths required for running the compiler
    pub compile_lib_path: String,

    // The library paths required for running compiled programs
    pub run_lib_path: String,

    // The rustc executable
    pub rustc_path: Path,

    // The clang executable
    pub clang_path: Option<Path>,

    // The llvm binaries path
    pub llvm_bin_path: Option<Path>,

    // The valgrind path
    pub valgrind_path: Option<String>,

    // Whether to fail if we can't run run-pass-valgrind tests under valgrind
    // (or, alternatively, to silently run them like regular run-pass tests).
    pub force_valgrind: bool,

    // The directory containing the tests to run
    pub src_base: Path,

    // The directory where programs should be built
    pub build_base: Path,

    // Directory for auxiliary libraries
    pub aux_base: Path,

    // The name of the stage being built (stage1, etc)
    pub stage_id: String,

    // The test mode, compile-fail, run-fail, run-pass
    pub mode: Mode,

    // Run ignored tests
    pub run_ignored: bool,

    // Only run tests that match this filter
    pub filter: Option<Regex>,

    // Precompiled regex for finding expected errors in cfail
    pub cfail_regex: Regex,

    // Write out a parseable log of tests that were run
    pub logfile: Option<Path>,

    // A command line to prefix program execution with,
    // for running under valgrind
    pub runtool: Option<String>,

    // Flags to pass to the compiler when building for the host
    pub host_rustcflags: Option<String>,

    // Flags to pass to the compiler when building for the target
    pub target_rustcflags: Option<String>,

    // Run tests using the JIT
    pub jit: bool,

    // Target system to be tested
    pub target: String,

    // Host triple for the compiler being invoked
    pub host: String,

    // Version of GDB
    pub gdb_version: Option<String>,

    // Version of LLDB
    pub lldb_version: Option<String>,

    // Path to the android tools
    pub android_cross_path: Path,

    // Extra parameter to run adb on arm-linux-androideabi
    pub adb_path: String,

    // Extra parameter to run test suite on arm-linux-androideabi
    pub adb_test_dir: String,

    // status whether android device available or not
    pub adb_device_status: bool,

    // the path containing LLDB's Python module
    pub lldb_python_dir: Option<String>,

    // Explain what's going on
    pub verbose: bool
}
<|endoftext|>