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

#![allow(non_camel_case_types)]

use middle::subst;
use trans::adt;
use trans::common::*;
use trans::foreign;
use trans::machine;
use middle::ty::{self, RegionEscape, Ty};

use trans::type_::Type;

use syntax::abi;
use syntax::ast;

// LLVM doesn't like objects that are too big. Issue #17913
fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                llet: Type,
                                                size: machine::llsize,
                                                scapegoat: Ty<'tcx>) {
    let esz = machine::llsize_of_alloc(ccx, llet);
    match esz.checked_mul(size) {
        Some(n) if n < ccx.obj_size_bound() => {}
        _ => { ccx.report_overbig_object(scapegoat) }
    }
}

pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 arg_ty: Ty<'tcx>) -> bool {
    !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty)
}

pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    ty: Ty<'tcx>) -> bool {
    arg_is_indirect(ccx, ty)
}

pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      arg_ty: Ty<'tcx>) -> Type {
    let llty = arg_type_of(ccx, arg_ty);
    if arg_is_indirect(ccx, arg_ty) {
        llty.ptr_to()
    } else {
        llty
    }
}

/// Yields the types of the "real" arguments for this function. For most
/// functions, these are simply the types of the arguments. For functions with
/// the `RustCall` ABI, however, this untuples the arguments of the function.
pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                inputs: &[Ty<'tcx>],
                                                abi: abi::Abi)
                                                -> Vec<Ty<'tcx>> {
    if abi != abi::RustCall {
        return inputs.iter().cloned().collect()
    }

    if inputs.is_empty() {
        return Vec::new()
    }

    let mut result = Vec::new();
    for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
        if i < inputs.len() - 1 {
            result.push(arg_prior_to_tuple);
        }
    }

    match inputs[inputs.len() - 1].sty {
        ty::TyTuple(ref tupled_arguments) => {
            debug!("untuple_arguments_if_necessary(): untupling arguments");
            for &tupled_argument in tupled_arguments {
                result.push(tupled_argument);
            }
        }
        _ => {
            ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
                                is neither a tuple nor unit")
        }
    }

    result
}

pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 llenvironment_type: Option<Type>,
                                 sig: &ty::Binder<ty::FnSig<'tcx>>,
                                 abi: abi::Abi)
                                 -> Type
{
    debug!("type_of_rust_fn(sig={:?},abi={:?})",
           sig,
           abi);

    let sig = cx.tcx().erase_late_bound_regions(sig);
    assert!(!sig.variadic); // rust fns are never variadic

    let mut atys: Vec<Type> = Vec::new();

    // First, munge the inputs, if this has the `rust-call` ABI.
    let inputs = untuple_arguments_if_necessary(cx, &sig.inputs, abi);

    // Arg 0: Output pointer.
    // (if the output type is non-immediate)
    let lloutputtype = match sig.output {
        ty::FnConverging(output) => {
            let use_out_pointer = return_uses_outptr(cx, output);
            let lloutputtype = arg_type_of(cx, output);
            // Use the output as the actual return value if it's immediate.
            if use_out_pointer {
                atys.push(lloutputtype.ptr_to());
                Type::void(cx)
            } else if return_type_is_void(cx, output) {
                Type::void(cx)
            } else {
                lloutputtype
            }
        }
        ty::FnDiverging => Type::void(cx)
    };

    // Arg 1: Environment
    match llenvironment_type {
        None => {}
        Some(llenvironment_type) => atys.push(llenvironment_type),
    }

    // ... then explicit args.
    for input in &inputs {<commit_msg>Avoid a needless vector copy in type_of_rust_fn<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_camel_case_types)]

use middle::subst;
use trans::adt;
use trans::common::*;
use trans::foreign;
use trans::machine;
use middle::ty::{self, RegionEscape, Ty};

use trans::type_::Type;

use syntax::abi;
use syntax::ast;

// LLVM doesn't like objects that are too big. Issue #17913
fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                llet: Type,
                                                size: machine::llsize,
                                                scapegoat: Ty<'tcx>) {
    let esz = machine::llsize_of_alloc(ccx, llet);
    match esz.checked_mul(size) {
        Some(n) if n < ccx.obj_size_bound() => {}
        _ => { ccx.report_overbig_object(scapegoat) }
    }
}

pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 arg_ty: Ty<'tcx>) -> bool {
    !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty)
}

pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                    ty: Ty<'tcx>) -> bool {
    arg_is_indirect(ccx, ty)
}

pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                      arg_ty: Ty<'tcx>) -> Type {
    let llty = arg_type_of(ccx, arg_ty);
    if arg_is_indirect(ccx, arg_ty) {
        llty.ptr_to()
    } else {
        llty
    }
}

/// Yields the types of the "real" arguments for a function using the `RustCall`
/// ABI by untupling the arguments of the function.
pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                   inputs: &[Ty<'tcx>])
                                   -> Vec<Ty<'tcx>> {
    if inputs.is_empty() {
        return Vec::new()
    }

    let mut result = Vec::new();
    for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
        if i < inputs.len() - 1 {
            result.push(arg_prior_to_tuple);
        }
    }

    match inputs[inputs.len() - 1].sty {
        ty::TyTuple(ref tupled_arguments) => {
            debug!("untuple_arguments(): untupling arguments");
            for &tupled_argument in tupled_arguments {
                result.push(tupled_argument);
            }
        }
        _ => {
            ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
                                is neither a tuple nor unit")
        }
    }

    result
}

pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 llenvironment_type: Option<Type>,
                                 sig: &ty::Binder<ty::FnSig<'tcx>>,
                                 abi: abi::Abi)
                                 -> Type
{
    debug!("type_of_rust_fn(sig={:?},abi={:?})",
           sig,
           abi);

    let sig = cx.tcx().erase_late_bound_regions(sig);
    assert!(!sig.variadic); // rust fns are never variadic

    let mut atys: Vec<Type> = Vec::new();

    // First, munge the inputs, if this has the `rust-call` ABI.
    let inputs = &if abi == abi::RustCall {
        untuple_arguments(cx, &sig.inputs)
    } else {
        sig.inputs
    };

    // Arg 0: Output pointer.
    // (if the output type is non-immediate)
    let lloutputtype = match sig.output {
        ty::FnConverging(output) => {
            let use_out_pointer = return_uses_outptr(cx, output);
            let lloutputtype = arg_type_of(cx, output);
            // Use the output as the actual return value if it's immediate.
            if use_out_pointer {
                atys.push(lloutputtype.ptr_to());
                Type::void(cx)
            } else if return_type_is_void(cx, output) {
                Type::void(cx)
            } else {
                lloutputtype
            }
        }
        ty::FnDiverging => Type::void(cx)
    };

    // Arg 1: Environment
    match llenvironment_type {
        None => {}
        Some(llenvironment_type) => atys.push(llenvironment_type),
    }

    // ... then explicit args.
    for input in inputs {
{'fraction_non_alphanumeric': 0.12975463409407478, 'fraction_numerical': 0.004500160720025715, 'mean_word_length': 1.8640687327401044, 'pattern_counts': {'":': 0, '<': 57, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7302407', 'n_tokens_mistral': 2946, 'n_tokens_neox': 2932, 'n_words': 695}