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

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use hir::map as hir_map;
use session::Session;
use hir::def_id::DefId;
use ty;
use middle::weak_lang_items;
use util::nodemap::FxHashMap;

use syntax::ast;
use syntax::symbol::Symbol;
use hir::itemlikevisit::ItemLikeVisitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
    pub enum LangItem {
        $($variant,)*
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec![$(foo($variant)),*],
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn item_name(index: usize) -> &'static str {
        let item: Option<LangItem> = LangItem::from_u32(index as u32);
        match item {
            $( Some($variant) => $name, )*
            None => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        match self.items[it as usize] {
            Some(id) => Ok(id),
            None => {
                Err(format!("requires `{}` lang_item",
                            LanguageItems::item_name(it as usize)))
            }
        }
    }

    pub fn require_owned_box(&self) -> Result<DefId, String> {
        self.require(OwnedBoxLangItem)
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        let def_id_kinds = [
            (self.fn_trait(), ty::ClosureKind::Fn),
            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
            ];

        for &(opt_def_id, kind) in &def_id_kinds {
            if Some(id) == opt_def_id {
                return Some(kind);
            }
        }

        None
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    hir_map: &'a hir_map::Map<'tcx>,

    session: &'a Session,

    item_refs: FxHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&*value.as_str()).cloned();

            if let Some(item_index) = item_index {
                self.collect_item(item_index, self.hir_map.local_def_id(item.id))
            } else {
                let span = self.hir_map.span(item.id);
                span_err!(self.session, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          value);
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
        // at present, lang items are always items, not trait items
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
        // at present, lang items are always items, not impl items
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    pub fn new(session: &'a Session, hir_map: &'a hir_map::Map<'tcx>)
               -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FxHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            session,
            hir_map,
            items: LanguageItems::new(),
            item_refs,
        }
    }

    pub fn collect_item(&mut self, item_index: usize,
                        item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let cstore = &self.session.cstore;
                let name = LanguageItems::item_name(item_index);
                let mut err = match self.hir_map.span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.session,
                        span,
                        E0152,
                        "duplicate lang item found: `{}`.",
                        name),
                    None => self.session.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            cstore.crate_name(item_def_id.krate),
                            name)),
                };
                if let Some(span) = self.hir_map.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      cstore.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
        krate.visit_all_item_likes(self);
    }

    pub fn collect_external_language_items(&mut self) {
        let cstore = &self.session.cstore;

        for cnum in cstore.crates() {
            for (index, item_index) in cstore.lang_items(cnum) {
                let def_id = DefId { krate: cnum, index: index };
                self.collect_item(item_index, def_id);
            }
        }
    }

    pub fn collect(&mut self, krate: &hir::Crate) {
        self.collect_external_language_items();
        self.collect_local_language_items(krate);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
    for attribute in attrs {
        if attribute.check_name("lang") {
            if let Some(value) = attribute.value_str() {
                return Some(value)
            }
        }
    }

    return None;
}

pub fn collect_language_items(session: &Session,
                              map: &hir_map::Map)
                              -> LanguageItems {
    let krate: &hir::Crate = map.krate();
    let mut collector = LanguageItemCollector::new(session, map);
    collector.collect(krate);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(krate, session, &mut items);
    items
}

// End of the macro
    }
}

language_item_table! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    I128ImplItem,                     "i128",                   i128_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    U128ImplItem,                    "u128",                    u128_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    CloneTraitLangItem,              "clone",                   clone_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;
    FreezeTraitLangItem,             "freeze",                  freeze_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    CloneMethodLangItem,             "clone_method",            clone_method;
    CloneFromMethodLangItem,         "clone_from_method",       clone_from_method;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    DropInPlaceFnLangItem,             "drop_in_place",           drop_in_place_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    // Deprecated:
    CovariantTypeItem,               "covariant_type",          covariant_type;
    ContravariantTypeItem,           "contravariant_type",      contravariant_type;
    InvariantTypeItem,               "invariant_type",          invariant_type;
    CovariantLifetimeItem,           "covariant_lifetime",      covariant_lifetime;
    ContravariantLifetimeItem,       "contravariant_lifetime",  contravariant_lifetime;
    InvariantLifetimeItem,           "invariant_lifetime",      invariant_lifetime;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}

impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
    pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
        self.lang_items.require(lang_item).unwrap_or_else(|msg| {
            self.sess.fatal(&msg)
        })
    }
}
<commit_msg>Remove dummy lang items<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Detecting language items.
//
// Language items are items that represent concepts intrinsic to the language
// itself. Examples are:
//
// * Traits that specify "kinds"; e.g. "Sync", "Send".
//
// * Traits that represent operators; e.g. "Add", "Sub", "Index".
//
// * Functions called by the compiler itself.

pub use self::LangItem::*;

use hir::map as hir_map;
use session::Session;
use hir::def_id::DefId;
use ty;
use middle::weak_lang_items;
use util::nodemap::FxHashMap;

use syntax::ast;
use syntax::symbol::Symbol;
use hir::itemlikevisit::ItemLikeVisitor;
use hir;

// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
    (
        $( $variant:ident, $name:expr, $method:ident; )*
    ) => {

enum_from_u32! {
    #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
    pub enum LangItem {
        $($variant,)*
    }
}

pub struct LanguageItems {
    pub items: Vec<Option<DefId>>,
    pub missing: Vec<LangItem>,
}

impl LanguageItems {
    pub fn new() -> LanguageItems {
        fn foo(_: LangItem) -> Option<DefId> { None }

        LanguageItems {
            items: vec![$(foo($variant)),*],
            missing: Vec::new(),
        }
    }

    pub fn items(&self) -> &[Option<DefId>] {
        &*self.items
    }

    pub fn item_name(index: usize) -> &'static str {
        let item: Option<LangItem> = LangItem::from_u32(index as u32);
        match item {
            $( Some($variant) => $name, )*
            None => "???"
        }
    }

    pub fn require(&self, it: LangItem) -> Result<DefId, String> {
        match self.items[it as usize] {
            Some(id) => Ok(id),
            None => {
                Err(format!("requires `{}` lang_item",
                            LanguageItems::item_name(it as usize)))
            }
        }
    }

    pub fn require_owned_box(&self) -> Result<DefId, String> {
        self.require(OwnedBoxLangItem)
    }

    pub fn fn_trait_kind(&self, id: DefId) -> Option<ty::ClosureKind> {
        let def_id_kinds = [
            (self.fn_trait(), ty::ClosureKind::Fn),
            (self.fn_mut_trait(), ty::ClosureKind::FnMut),
            (self.fn_once_trait(), ty::ClosureKind::FnOnce),
            ];

        for &(opt_def_id, kind) in &def_id_kinds {
            if Some(id) == opt_def_id {
                return Some(kind);
            }
        }

        None
    }

    $(
        #[allow(dead_code)]
        pub fn $method(&self) -> Option<DefId> {
            self.items[$variant as usize]
        }
    )*
}

struct LanguageItemCollector<'a, 'tcx: 'a> {
    items: LanguageItems,

    hir_map: &'a hir_map::Map<'tcx>,

    session: &'a Session,

    item_refs: FxHashMap<&'static str, usize>,
}

impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> {
    fn visit_item(&mut self, item: &hir::Item) {
        if let Some(value) = extract(&item.attrs) {
            let item_index = self.item_refs.get(&*value.as_str()).cloned();

            if let Some(item_index) = item_index {
                self.collect_item(item_index, self.hir_map.local_def_id(item.id))
            } else {
                let span = self.hir_map.span(item.id);
                span_err!(self.session, span, E0522,
                          "definition of an unknown language item: `{}`.",
                          value);
            }
        }
    }

    fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
        // at present, lang items are always items, not trait items
    }

    fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
        // at present, lang items are always items, not impl items
    }
}

impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
    pub fn new(session: &'a Session, hir_map: &'a hir_map::Map<'tcx>)
               -> LanguageItemCollector<'a, 'tcx> {
        let mut item_refs = FxHashMap();

        $( item_refs.insert($name, $variant as usize); )*

        LanguageItemCollector {
            session,
            hir_map,
            items: LanguageItems::new(),
            item_refs,
        }
    }

    pub fn collect_item(&mut self, item_index: usize,
                        item_def_id: DefId) {
        // Check for duplicates.
        match self.items.items[item_index] {
            Some(original_def_id) if original_def_id != item_def_id => {
                let cstore = &self.session.cstore;
                let name = LanguageItems::item_name(item_index);
                let mut err = match self.hir_map.span_if_local(item_def_id) {
                    Some(span) => struct_span_err!(
                        self.session,
                        span,
                        E0152,
                        "duplicate lang item found: `{}`.",
                        name),
                    None => self.session.struct_err(&format!(
                            "duplicate lang item in crate `{}`: `{}`.",
                            cstore.crate_name(item_def_id.krate),
                            name)),
                };
                if let Some(span) = self.hir_map.span_if_local(original_def_id) {
                    span_note!(&mut err, span,
                               "first defined here.");
                } else {
                    err.note(&format!("first defined in crate `{}`.",
                                      cstore.crate_name(original_def_id.krate)));
                }
                err.emit();
            }
            _ => {
                // OK.
            }
        }

        // Matched.
        self.items.items[item_index] = Some(item_def_id);
    }

    pub fn collect_local_language_items(&mut self, krate: &hir::Crate) {
        krate.visit_all_item_likes(self);
    }

    pub fn collect_external_language_items(&mut self) {
        let cstore = &self.session.cstore;

        for cnum in cstore.crates() {
            for (index, item_index) in cstore.lang_items(cnum) {
                let def_id = DefId { krate: cnum, index: index };
                self.collect_item(item_index, def_id);
            }
        }
    }

    pub fn collect(&mut self, krate: &hir::Crate) {
        self.collect_external_language_items();
        self.collect_local_language_items(krate);
    }
}

pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
    for attribute in attrs {
        if attribute.check_name("lang") {
            if let Some(value) = attribute.value_str() {
                return Some(value)
            }
        }
    }

    return None;
}

pub fn collect_language_items(session: &Session,
                              map: &hir_map::Map)
                              -> LanguageItems {
    let krate: &hir::Crate = map.krate();
    let mut collector = LanguageItemCollector::new(session, map);
    collector.collect(krate);
    let LanguageItemCollector { mut items, .. } = collector;
    weak_lang_items::check_crate(krate, session, &mut items);
    items
}

// End of the macro
    }
}

language_item_table! {
//  Variant name,                    Name,                      Method name;
    CharImplItem,                    "char",                    char_impl;
    StrImplItem,                     "str",                     str_impl;
    SliceImplItem,                   "slice",                   slice_impl;
    ConstPtrImplItem,                "const_ptr",               const_ptr_impl;
    MutPtrImplItem,                  "mut_ptr",                 mut_ptr_impl;
    I8ImplItem,                      "i8",                      i8_impl;
    I16ImplItem,                     "i16",                     i16_impl;
    I32ImplItem,                     "i32",                     i32_impl;
    I64ImplItem,                     "i64",                     i64_impl;
    I128ImplItem,                     "i128",                   i128_impl;
    IsizeImplItem,                   "isize",                   isize_impl;
    U8ImplItem,                      "u8",                      u8_impl;
    U16ImplItem,                     "u16",                     u16_impl;
    U32ImplItem,                     "u32",                     u32_impl;
    U64ImplItem,                     "u64",                     u64_impl;
    U128ImplItem,                    "u128",                    u128_impl;
    UsizeImplItem,                   "usize",                   usize_impl;
    F32ImplItem,                     "f32",                     f32_impl;
    F64ImplItem,                     "f64",                     f64_impl;

    SendTraitLangItem,               "send",                    send_trait;
    SizedTraitLangItem,              "sized",                   sized_trait;
    UnsizeTraitLangItem,             "unsize",                  unsize_trait;
    CopyTraitLangItem,               "copy",                    copy_trait;
    CloneTraitLangItem,              "clone",                   clone_trait;
    SyncTraitLangItem,               "sync",                    sync_trait;
    FreezeTraitLangItem,             "freeze",                  freeze_trait;

    DropTraitLangItem,               "drop",                    drop_trait;

    CoerceUnsizedTraitLangItem,      "coerce_unsized",          coerce_unsized_trait;

    AddTraitLangItem,                "add",                     add_trait;
    SubTraitLangItem,                "sub",                     sub_trait;
    MulTraitLangItem,                "mul",                     mul_trait;
    DivTraitLangItem,                "div",                     div_trait;
    RemTraitLangItem,                "rem",                     rem_trait;
    NegTraitLangItem,                "neg",                     neg_trait;
    NotTraitLangItem,                "not",                     not_trait;
    BitXorTraitLangItem,             "bitxor",                  bitxor_trait;
    BitAndTraitLangItem,             "bitand",                  bitand_trait;
    BitOrTraitLangItem,              "bitor",                   bitor_trait;
    ShlTraitLangItem,                "shl",                     shl_trait;
    ShrTraitLangItem,                "shr",                     shr_trait;
    AddAssignTraitLangItem,          "add_assign",              add_assign_trait;
    SubAssignTraitLangItem,          "sub_assign",              sub_assign_trait;
    MulAssignTraitLangItem,          "mul_assign",              mul_assign_trait;
    DivAssignTraitLangItem,          "div_assign",              div_assign_trait;
    RemAssignTraitLangItem,          "rem_assign",              rem_assign_trait;
    BitXorAssignTraitLangItem,       "bitxor_assign",           bitxor_assign_trait;
    BitAndAssignTraitLangItem,       "bitand_assign",           bitand_assign_trait;
    BitOrAssignTraitLangItem,        "bitor_assign",            bitor_assign_trait;
    ShlAssignTraitLangItem,          "shl_assign",              shl_assign_trait;
    ShrAssignTraitLangItem,          "shr_assign",              shr_assign_trait;
    IndexTraitLangItem,              "index",                   index_trait;
    IndexMutTraitLangItem,           "index_mut",               index_mut_trait;

    UnsafeCellTypeLangItem,          "unsafe_cell",             unsafe_cell_type;

    DerefTraitLangItem,              "deref",                   deref_trait;
    DerefMutTraitLangItem,           "deref_mut",               deref_mut_trait;

    FnTraitLangItem,                 "fn",                      fn_trait;
    FnMutTraitLangItem,              "fn_mut",                  fn_mut_trait;
    FnOnceTraitLangItem,             "fn_once",                 fn_once_trait;

    EqTraitLangItem,                 "eq",                      eq_trait;
    OrdTraitLangItem,                "ord",                     ord_trait;

    StrEqFnLangItem,                 "str_eq",                  str_eq_fn;

    // A number of panic-related lang items. The `panic` item corresponds to
    // divide-by-zero and various panic cases with `match`. The
    // `panic_bounds_check` item is for indexing arrays.
    //
    // The `begin_unwind` lang item has a predefined symbol name and is sort of
    // a "weak lang item" in the sense that a crate is not required to have it
    // defined to use it, but a final product is required to define it
    // somewhere. Additionally, there are restrictions on crates that use a weak
    // lang item, but do not have it defined.
    PanicFnLangItem,                 "panic",                   panic_fn;
    PanicBoundsCheckFnLangItem,      "panic_bounds_check",      panic_bounds_check_fn;
    PanicFmtLangItem,                "panic_fmt",               panic_fmt;

    ExchangeMallocFnLangItem,        "exchange_malloc",         exchange_malloc_fn;
    BoxFreeFnLangItem,               "box_free",                box_free_fn;
    DropInPlaceFnLangItem,             "drop_in_place",           drop_in_place_fn;

    StartFnLangItem,                 "start",                   start_fn;

    EhPersonalityLangItem,           "eh_personality",          eh_personality;
    EhUnwindResumeLangItem,          "eh_unwind_resume",        eh_unwind_resume;
    MSVCTryFilterLangItem,           "msvc_try_filter",         msvc_try_filter;

    OwnedBoxLangItem,                "owned_box",               owned_box;

    PhantomDataItem,                 "phantom_data",            phantom_data;

    // Deprecated:
    CovariantTypeItem,               "covariant_type",          covariant_type;
    ContravariantTypeItem,           "contravariant_type",      contravariant_type;
    InvariantTypeItem,               "invariant_type",          invariant_type;
    CovariantLifetimeItem,           "covariant_lifetime",      covariant_lifetime;
    ContravariantLifetimeItem,       "contravariant_lifetime",  contravariant_lifetime;
    InvariantLifetimeItem,           "invariant_lifetime",      invariant_lifetime;

    NonZeroItem,                     "non_zero",                non_zero;

    DebugTraitLangItem,              "debug_trait",             debug_trait;
}

impl<'a, 'tcx, 'gcx> ty::TyCtxt<'a, 'tcx, 'gcx> {
    pub fn require_lang_item(&self, lang_item: LangItem) -> DefId {
        self.lang_items.require(lang_item).unwrap_or_else(|msg| {
            self.sess.fatal(&msg)
        })
    }
}
<|endoftext|>


<commit_before>//! Allows for producing a unique string key for a mono item.
//! These keys are used by the handwritten auto-tests, so they need to be
//! predictable and human-readable.
//!
//! Note: A lot of this could looks very similar to what's already in `ty::print`.
//! FIXME(eddyb) implement a custom `PrettyPrinter` for this.

use rustc::hir::def_id::DefId;
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Const, Instance, Ty, TyCtxt};
use rustc::{bug, hir};
use std::fmt::Write;
use std::iter;

/// Same as `unique_type_name()` but with the result pushed onto the given
/// `output` parameter.
pub struct DefPathBasedNames<'tcx> {
    tcx: TyCtxt<'tcx>,
    omit_disambiguators: bool,
    omit_local_crate_name: bool,
}

impl DefPathBasedNames<'tcx> {
    pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self {
        DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
    }

    // Pushes the type name of the specified type to the provided string.
    // If `debug` is true, printing normally unprintable types is allowed
    // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
    // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
    // When being used for codegen purposes, `debug` should be set to `false`
    // in order to catch unexpected types that should never end up in a type name.
    pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
        match t.kind {
            ty::Bool => output.push_str("bool"),
            ty::Char => output.push_str("char"),
            ty::Str => output.push_str("str"),
            ty::Never => output.push_str("!"),
            ty::Int(ty) => output.push_str(ty.name_str()),
            ty::Uint(ty) => output.push_str(ty.name_str()),
            ty::Float(ty) => output.push_str(ty.name_str()),
            ty::Adt(adt_def, substs) => {
                self.push_def_path(adt_def.did, output);
                self.push_generic_params(substs, iter::empty(), output, debug);
            }
            ty::Tuple(component_types) => {
                output.push('(');
                for &component_type in component_types {
                    self.push_type_name(component_type.expect_ty(), output, debug);
                    output.push_str(", ");
                }
                if !component_types.is_empty() {
                    output.pop();
                    output.pop();
                }
                output.push(')');
            }
            ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
                output.push('*');
                match mutbl {
                    hir::Mutability::Not => output.push_str("const "),
                    hir::Mutability::Mut => output.push_str("mut "),
                }

                self.push_type_name(inner_type, output, debug);
            }
            ty::Ref(_, inner_type, mutbl) => {
                output.push('&');
                output.push_str(mutbl.prefix_str());

                self.push_type_name(inner_type, output, debug);
            }
            ty::Array(inner_type, len) => {
                output.push('[');
                self.push_type_name(inner_type, output, debug);
                let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
                write!(output, "; {}", len).unwrap();
                output.push(']');
            }
            ty::Slice(inner_type) => {
                output.push('[');
                self.push_type_name(inner_type, output, debug);
                output.push(']');
            }
            ty::Dynamic(ref trait_data, ..) => {
                if let Some(principal) = trait_data.principal() {
                    self.push_def_path(principal.def_id(), output);
                    self.push_generic_params(
                        principal.skip_binder().substs,
                        trait_data.projection_bounds(),
                        output,
                        debug,
                    );
                } else {
                    output.push_str("dyn '_");
                }
            }
            ty::Foreign(did) => self.push_def_path(did, output),
            ty::FnDef(..) | ty::FnPtr(_) => {
                let sig = t.fn_sig(self.tcx);
                output.push_str(sig.unsafety().prefix_str());

                let abi = sig.abi();
                if abi != ::rustc_target::spec::abi::Abi::Rust {
                    output.push_str("extern \"");
                    output.push_str(abi.name());
                    output.push_str("\" ");
                }

                output.push_str("fn(");

                let sig =
                    self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);

                if !sig.inputs().is_empty() {
                    for &parameter_type in sig.inputs() {
                        self.push_type_name(parameter_type, output, debug);
                        output.push_str(", ");
                    }
                    output.pop();
                    output.pop();
                }

                if sig.c_variadic {
                    if !sig.inputs().is_empty() {
                        output.push_str(", ...");
                    } else {
                        output.push_str("...");
                    }
                }

                output.push(')');

                if !sig.output().is_unit() {
                    output.push_str(" -> ");
                    self.push_type_name(sig.output(), output, debug);
                }
            }
            ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => {
                self.push_def_path(def_id, output);
                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
                let substs = substs.truncate_to(self.tcx, generics);
                self.push_generic_params(substs, iter::empty(), output, debug);
            }
            ty::Error
            | ty::Bound(..)
            | ty::Infer(_)
            | ty::Placeholder(..)
            | ty::UnnormalizedProjection(..)
            | ty::Projection(..)
            | ty::Param(_)
            | ty::GeneratorWitness(_)
            | ty::Opaque(..) => {
                if debug {
                    output.push_str(&format!("`{:?}`", t));
                } else {
                    bug!(
                        "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
                        t,
                    );
                }
            }
        }
    }

    // Pushes the the name of the specified const to the provided string.
    // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed,
    // as well as the unprintable types of constants (see `push_type_name` for more details).
    pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) {
        if let ty::ConstKind::Value(_) = c.val {
            // FIXME(const_generics): we could probably do a better job here.
            write!(output, "{:?}", c).unwrap()
        } else if debug {
            write!(output, "{:?}", c).unwrap()
        } else {
            bug!("DefPathBasedNames: trying to create const name for unexpected const: {:?}", c,);
        }
        output.push_str(": ");
        self.push_type_name(c.ty, output, debug);
    }

    pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
        let def_path = self.tcx.def_path(def_id);

        // some_crate::
        if !(self.omit_local_crate_name && def_id.is_local()) {
            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
            output.push_str("::");
        }

        // foo::bar::ItemName::
        for part in self.tcx.def_path(def_id).data {
            if self.omit_disambiguators {
                write!(output, "{}::", part.data.as_symbol()).unwrap();
            } else {
                write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap();
            }
        }

        // remove final "::"
        output.pop();
        output.pop();
    }

    fn push_generic_params<I>(
        &self,
        substs: SubstsRef<'tcx>,
        projections: I,
        output: &mut String,
        debug: bool,
    ) where
        I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
    {
        let mut projections = projections.peekable();
        if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
            return;
        }

        output.push('<');

        for type_parameter in substs.types() {
            self.push_type_name(type_parameter, output, debug);
            output.push_str(", ");
        }

        for projection in projections {
            let projection = projection.skip_binder();
            let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
            output.push_str(name);
            output.push_str("=");
            self.push_type_name(projection.ty, output, debug);
            output.push_str(", ");
        }

        for const_parameter in substs.consts() {
            self.push_const_name(const_parameter, output, debug);
            output.push_str(", ");
        }

        output.pop();
        output.pop();

        output.push('>');
    }

    pub fn push_instance_as_string(
        &self,
        instance: Instance<'tcx>,
        output: &mut String,
        debug: bool,
    ) {
        self.push_def_path(instance.def_id(), output);
        self.push_generic_params(instance.substs, iter::empty(), output, debug);
    }
}
<commit_msg>Fix ICE in const pretty printing and resolve FIXME<commit_after>//! Allows for producing a unique string key for a mono item.
//! These keys are used by the handwritten auto-tests, so they need to be
//! predictable and human-readable.
//!
//! Note: A lot of this could looks very similar to what's already in `ty::print`.
//! FIXME(eddyb) implement a custom `PrettyPrinter` for this.

use rustc::hir::def_id::DefId;
use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Const, Instance, Ty, TyCtxt};
use rustc::{bug, hir};
use std::fmt::Write;
use std::iter;

/// Same as `unique_type_name()` but with the result pushed onto the given
/// `output` parameter.
pub struct DefPathBasedNames<'tcx> {
    tcx: TyCtxt<'tcx>,
    omit_disambiguators: bool,
    omit_local_crate_name: bool,
}

impl DefPathBasedNames<'tcx> {
    pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self {
        DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name }
    }

    // Pushes the type name of the specified type to the provided string.
    // If `debug` is true, printing normally unprintable types is allowed
    // (e.g. `ty::GeneratorWitness`). This parameter should only be set when
    // this method is being used for logging purposes (e.g. with `debug!` or `info!`)
    // When being used for codegen purposes, `debug` should be set to `false`
    // in order to catch unexpected types that should never end up in a type name.
    pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
        match t.kind {
            ty::Bool => output.push_str("bool"),
            ty::Char => output.push_str("char"),
            ty::Str => output.push_str("str"),
            ty::Never => output.push_str("!"),
            ty::Int(ty) => output.push_str(ty.name_str()),
            ty::Uint(ty) => output.push_str(ty.name_str()),
            ty::Float(ty) => output.push_str(ty.name_str()),
            ty::Adt(adt_def, substs) => {
                self.push_def_path(adt_def.did, output);
                self.push_generic_params(substs, iter::empty(), output, debug);
            }
            ty::Tuple(component_types) => {
                output.push('(');
                for &component_type in component_types {
                    self.push_type_name(component_type.expect_ty(), output, debug);
                    output.push_str(", ");
                }
                if !component_types.is_empty() {
                    output.pop();
                    output.pop();
                }
                output.push(')');
            }
            ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
                output.push('*');
                match mutbl {
                    hir::Mutability::Not => output.push_str("const "),
                    hir::Mutability::Mut => output.push_str("mut "),
                }

                self.push_type_name(inner_type, output, debug);
            }
            ty::Ref(_, inner_type, mutbl) => {
                output.push('&');
                output.push_str(mutbl.prefix_str());

                self.push_type_name(inner_type, output, debug);
            }
            ty::Array(inner_type, len) => {
                output.push('[');
                self.push_type_name(inner_type, output, debug);
                let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all());
                write!(output, "; {}", len).unwrap();
                output.push(']');
            }
            ty::Slice(inner_type) => {
                output.push('[');
                self.push_type_name(inner_type, output, debug);
                output.push(']');
            }
            ty::Dynamic(ref trait_data, ..) => {
                if let Some(principal) = trait_data.principal() {
                    self.push_def_path(principal.def_id(), output);
                    self.push_generic_params(
                        principal.skip_binder().substs,
                        trait_data.projection_bounds(),
                        output,
                        debug,
                    );
                } else {
                    output.push_str("dyn '_");
                }
            }
            ty::Foreign(did) => self.push_def_path(did, output),
            ty::FnDef(..) | ty::FnPtr(_) => {
                let sig = t.fn_sig(self.tcx);
                output.push_str(sig.unsafety().prefix_str());

                let abi = sig.abi();
                if abi != ::rustc_target::spec::abi::Abi::Rust {
                    output.push_str("extern \"");
                    output.push_str(abi.name());
                    output.push_str("\" ");
                }

                output.push_str("fn(");

                let sig =
                    self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);

                if !sig.inputs().is_empty() {
                    for &parameter_type in sig.inputs() {
                        self.push_type_name(parameter_type, output, debug);
                        output.push_str(", ");
                    }
                    output.pop();
                    output.pop();
                }

                if sig.c_variadic {
                    if !sig.inputs().is_empty() {
                        output.push_str(", ...");
                    } else {
                        output.push_str("...");
                    }
                }

                output.push(')');

                if !sig.output().is_unit() {
                    output.push_str(" -> ");
                    self.push_type_name(sig.output(), output, debug);
                }
            }
            ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => {
                self.push_def_path(def_id, output);
                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
                let substs = substs.truncate_to(self.tcx, generics);
                self.push_generic_params(substs, iter::empty(), output, debug);
            }
            ty::Error
            | ty::Bound(..)
            | ty::Infer(_)
            | ty::Placeholder(..)
            | ty::UnnormalizedProjection(..)
            | ty::Projection(..)
            | ty::Param(_)
            | ty::GeneratorWitness(_)
            | ty::Opaque(..) => {
                if debug {
                    output.push_str(&format!("`{:?}`", t));
                } else {
                    bug!(
                        "DefPathBasedNames: trying to create type name for unexpected type: {:?}",
                        t,
                    );
                }
            }
        }
    }

    // Pushes the the name of the specified const to the provided string.
    // If `debug` is true, the unprintable types of constants will be printed with `fmt::Debug`
    // (see `push_type_name` for more details).
    pub fn push_const_name(&self, ct: &Const<'tcx>, output: &mut String, debug: bool) {
        write!(output, "{}", ct).unwrap();
        output.push_str(": ");
        self.push_type_name(ct.ty, output, debug);
    }

    pub fn push_def_path(&self, def_id: DefId, output: &mut String) {
        let def_path = self.tcx.def_path(def_id);

        // some_crate::
        if !(self.omit_local_crate_name && def_id.is_local()) {
            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
            output.push_str("::");
        }

        // foo::bar::ItemName::
        for part in self.tcx.def_path(def_id).data {
            if self.omit_disambiguators {
                write!(output, "{}::", part.data.as_symbol()).unwrap();
            } else {
                write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap();
            }
        }

        // remove final "::"
        output.pop();
        output.pop();
    }

    fn push_generic_params<I>(
        &self,
        substs: SubstsRef<'tcx>,
        projections: I,
        output: &mut String,
        debug: bool,
    ) where
        I: Iterator<Item = ty::PolyExistentialProjection<'tcx>>,
    {
        let mut projections = projections.peekable();
        if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() {
            return;
        }

        output.push('<');

        for type_parameter in substs.types() {
            self.push_type_name(type_parameter, output, debug);
            output.push_str(", ");
        }

        for projection in projections {
            let projection = projection.skip_binder();
            let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
            output.push_str(name);
            output.push_str("=");
            self.push_type_name(projection.ty, output, debug);
            output.push_str(", ");
        }

        for const_parameter in substs.consts() {
            self.push_const_name(const_parameter, output, debug);
            output.push_str(", ");
        }

        output.pop();
        output.pop();

        output.push('>');
    }

    pub fn push_instance_as_string(
        &self,
        instance: Instance<'tcx>,
        output: &mut String,
        debug: bool,
    ) {
        self.push_def_path(instance.def_id(), output);
        self.push_generic_params(instance.substs, iter::empty(), output, debug);
    }
}
<|endoftext|>


<commit_before>//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic
//! blocks.
//!
//! This analysis considers references as being used only at the point of the
//! borrow. This means that this does not track uses because of references that
//! already exist:
//!
//! ```rust
//! fn foo() {
//!     x = 0;
//!     // `x` is live here ...
//!     GLOBAL = &x: *const u32;
//!     // ... but not here, even while it can be accessed through `GLOBAL`.
//!     foo();
//!     x = 1;
//!     // `x` is live again here, because it is assigned to `OTHER_GLOBAL`.
//!     OTHER_GLOBAL = &x: *const u32;
//!     // ...
//! }
//! ```
//!
//! This means that users of this analysis still have to check whether
//! pre-existing references can be used to access the value (e.g., at movable
//! generator yield points, all pre-existing references are invalidated, so this
//! doesn't matter).

use rustc::mir::visit::{
    PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext, NonUseContext,
};
use rustc::mir::Local;
use rustc::mir::*;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::work_queue::WorkQueue;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use crate::transform::MirSource;
use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro};

pub type LiveVarSet = BitSet<Local>;

/// This gives the result of the liveness analysis at the boundary of
/// basic blocks.
///
/// The `V` type defines the set of variables that we computed
/// liveness for. This is often `Local`, in which case we computed
/// liveness for all variables -- but it can also be some other type,
/// which indicates a subset of the variables within the graph.
pub struct LivenessResult {
    /// Live variables on exit to each basic block. This is equal to
    /// the union of the `ins` for each successor.
    pub outs: IndexVec<BasicBlock, LiveVarSet>,
}

/// Computes which local variables are live within the given function
/// `mir`. The liveness mode `mode` determines what sorts of uses are
/// considered to make a variable live (e.g., do drops count?).
pub fn liveness_of_locals<'tcx>(
    mir: &Mir<'tcx>,
) -> LivenessResult {
    let num_live_vars = mir.local_decls.len();

    let def_use: IndexVec<_, DefsUses> = mir
        .basic_blocks()
        .iter()
        .map(|b| block(b, num_live_vars))
        .collect();

    let mut outs: IndexVec<_, LiveVarSet> = mir
        .basic_blocks()
        .indices()
        .map(|_| LiveVarSet::new_empty(num_live_vars))
        .collect();

    let mut bits = LiveVarSet::new_empty(num_live_vars);

    // queue of things that need to be re-processed, and a set containing
    // the things currently in the queue
    let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_all(mir.basic_blocks().len());

    let predecessors = mir.predecessors();

    while let Some(bb) = dirty_queue.pop() {
        // bits = use ∪ (bits - def)
        bits.overwrite(&outs[bb]);
        def_use[bb].apply(&mut bits);

        // `bits` now contains the live variables on entry. Therefore,
        // add `bits` to the `out` set for each predecessor; if those
        // bits were not already present, then enqueue the predecessor
        // as dirty.
        //
        // (note that `union` returns true if the `self` set changed)
        for &pred_bb in &predecessors[bb] {
            if outs[pred_bb].union(&bits) {
                dirty_queue.insert(pred_bb);
            }
        }
    }

    LivenessResult { outs }
}

#[derive(Eq, PartialEq, Clone)]
pub enum DefUse {
    Def,
    Use,
    Drop,
}

pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
    match context {
        ///////////////////////////////////////////////////////////////////////////
        // DEFS

        PlaceContext::MutatingUse(MutatingUseContext::Store) |

        // This is potentially both a def and a use...
        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |

        // We let Call define the result in both the success and
        // unwind cases. This is not really correct, however it
        // does not seem to be observable due to the way that we
        // generate MIR. To do things properly, we would apply
        // the def in call only to the input from the success
        // path and not the unwind path. -nmatsakis
        PlaceContext::MutatingUse(MutatingUseContext::Call) |

        // Storage live and storage dead aren't proper defines, but we can ignore
        // values that come before them.
        PlaceContext::NonUse(NonUseContext::StorageLive) |
        PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def),

        ///////////////////////////////////////////////////////////////////////////
        // REGULAR USES
        //
        // These are uses that occur *outside* of a drop. For the
        // purposes of NLL, these are special in that **all** the
        // lifetimes appearing in the variable must be live for each regular use.

        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) |
        PlaceContext::MutatingUse(MutatingUseContext::Projection) |

        // Borrows only consider their local used at the point of the borrow.
        // This won't affect the results since we use this analysis for generators
        // and we only care about the result at suspension points. Borrows cannot
        // cross suspension points so this behavior is unproblematic.
        PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |

        PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
        PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
        PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
            Some(DefUse::Use),

        ///////////////////////////////////////////////////////////////////////////
        // DROP USES
        //
        // These are uses that occur in a DROP (a MIR drop, not a
        // call to `std::mem::drop()`). For the purposes of NLL,
        // uses in drop are special because `#[may_dangle]`
        // attributes can affect whether lifetimes must be live.

        PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
            Some(DefUse::Drop),
    }
}

struct DefsUsesVisitor
{
    defs_uses: DefsUses,
}

#[derive(Eq, PartialEq, Clone)]
struct DefsUses {
    defs: LiveVarSet,
    uses: LiveVarSet,
}

impl DefsUses {
    fn apply(&self, bits: &mut LiveVarSet) -> bool {
        bits.subtract(&self.defs) | bits.union(&self.uses)
    }

    fn add_def(&mut self, index: Local) {
        // If it was used already in the block, remove that use
        // now that we found a definition.
        //
        // Example:
        //
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.uses.remove(index);
        self.defs.insert(index);
    }

    fn add_use(&mut self, index: Local) {
        // Inverse of above.
        //
        // Example:
        //
        //     // Defs = {}, Uses = {X}
        //     use(X)
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.defs.remove(index);
        self.uses.insert(index);
    }
}

impl<'tcx> Visitor<'tcx> for DefsUsesVisitor
{
    fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
        match categorize(context) {
            Some(DefUse::Def) => self.defs_uses.add_def(local),
            Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(local),
            _ => (),
        }
    }
}

fn block<'tcx>(
    b: &BasicBlockData<'tcx>,
    locals: usize,
) -> DefsUses {
    let mut visitor = DefsUsesVisitor {
        defs_uses: DefsUses {
            defs: LiveVarSet::new_empty(locals),
            uses: LiveVarSet::new_empty(locals),
        },
    };

    let dummy_location = Location {
        block: BasicBlock::new(0),
        statement_index: 0,
    };

    // Visit the various parts of the basic block in reverse. If we go
    // forward, the logic in `add_def` and `add_use` would be wrong.
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
    for statement in b.statements.iter().rev() {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
    }

    visitor.defs_uses
}

pub fn dump_mir<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    source: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = ty::print::with_forced_impl_filename_line(|| {
        // see notes on #41697 below
        tcx.def_path_str(source.def_id())
    });
    dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    node_path: &str,
    source: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    let mut file_path = PathBuf::new();
    file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir));
    let item_id = tcx.hir().as_local_hir_id(source.def_id()).unwrap();
    let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    src: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    w: &mut dyn Write,
    result: &LivenessResult,
) -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet>| {
            let live: Vec<String> = result[block]
                .iter()
                .map(|local| format!("{:?}", local))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}
<commit_msg>Update comment for liveness_of_locals<commit_after>//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic
//! blocks.
//!
//! This analysis considers references as being used only at the point of the
//! borrow. This means that this does not track uses because of references that
//! already exist:
//!
//! ```rust
//! fn foo() {
//!     x = 0;
//!     // `x` is live here ...
//!     GLOBAL = &x: *const u32;
//!     // ... but not here, even while it can be accessed through `GLOBAL`.
//!     foo();
//!     x = 1;
//!     // `x` is live again here, because it is assigned to `OTHER_GLOBAL`.
//!     OTHER_GLOBAL = &x: *const u32;
//!     // ...
//! }
//! ```
//!
//! This means that users of this analysis still have to check whether
//! pre-existing references can be used to access the value (e.g., at movable
//! generator yield points, all pre-existing references are invalidated, so this
//! doesn't matter).

use rustc::mir::visit::{
    PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext, NonUseContext,
};
use rustc::mir::Local;
use rustc::mir::*;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::work_queue::WorkQueue;
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use crate::transform::MirSource;
use crate::util::pretty::{dump_enabled, write_basic_block, write_mir_intro};

pub type LiveVarSet = BitSet<Local>;

/// This gives the result of the liveness analysis at the boundary of
/// basic blocks.
///
/// The `V` type defines the set of variables that we computed
/// liveness for. This is often `Local`, in which case we computed
/// liveness for all variables -- but it can also be some other type,
/// which indicates a subset of the variables within the graph.
pub struct LivenessResult {
    /// Live variables on exit to each basic block. This is equal to
    /// the union of the `ins` for each successor.
    pub outs: IndexVec<BasicBlock, LiveVarSet>,
}

/// Computes which local variables are live within the given function
/// `mir`, including drops.
pub fn liveness_of_locals<'tcx>(
    mir: &Mir<'tcx>,
) -> LivenessResult {
    let num_live_vars = mir.local_decls.len();

    let def_use: IndexVec<_, DefsUses> = mir
        .basic_blocks()
        .iter()
        .map(|b| block(b, num_live_vars))
        .collect();

    let mut outs: IndexVec<_, LiveVarSet> = mir
        .basic_blocks()
        .indices()
        .map(|_| LiveVarSet::new_empty(num_live_vars))
        .collect();

    let mut bits = LiveVarSet::new_empty(num_live_vars);

    // queue of things that need to be re-processed, and a set containing
    // the things currently in the queue
    let mut dirty_queue: WorkQueue<BasicBlock> = WorkQueue::with_all(mir.basic_blocks().len());

    let predecessors = mir.predecessors();

    while let Some(bb) = dirty_queue.pop() {
        // bits = use ∪ (bits - def)
        bits.overwrite(&outs[bb]);
        def_use[bb].apply(&mut bits);

        // `bits` now contains the live variables on entry. Therefore,
        // add `bits` to the `out` set for each predecessor; if those
        // bits were not already present, then enqueue the predecessor
        // as dirty.
        //
        // (note that `union` returns true if the `self` set changed)
        for &pred_bb in &predecessors[bb] {
            if outs[pred_bb].union(&bits) {
                dirty_queue.insert(pred_bb);
            }
        }
    }

    LivenessResult { outs }
}

#[derive(Eq, PartialEq, Clone)]
pub enum DefUse {
    Def,
    Use,
    Drop,
}

pub fn categorize<'tcx>(context: PlaceContext<'tcx>) -> Option<DefUse> {
    match context {
        ///////////////////////////////////////////////////////////////////////////
        // DEFS

        PlaceContext::MutatingUse(MutatingUseContext::Store) |

        // This is potentially both a def and a use...
        PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) |

        // We let Call define the result in both the success and
        // unwind cases. This is not really correct, however it
        // does not seem to be observable due to the way that we
        // generate MIR. To do things properly, we would apply
        // the def in call only to the input from the success
        // path and not the unwind path. -nmatsakis
        PlaceContext::MutatingUse(MutatingUseContext::Call) |

        // Storage live and storage dead aren't proper defines, but we can ignore
        // values that come before them.
        PlaceContext::NonUse(NonUseContext::StorageLive) |
        PlaceContext::NonUse(NonUseContext::StorageDead) => Some(DefUse::Def),

        ///////////////////////////////////////////////////////////////////////////
        // REGULAR USES
        //
        // These are uses that occur *outside* of a drop. For the
        // purposes of NLL, these are special in that **all** the
        // lifetimes appearing in the variable must be live for each regular use.

        PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) |
        PlaceContext::MutatingUse(MutatingUseContext::Projection) |

        // Borrows only consider their local used at the point of the borrow.
        // This won't affect the results since we use this analysis for generators
        // and we only care about the result at suspension points. Borrows cannot
        // cross suspension points so this behavior is unproblematic.
        PlaceContext::MutatingUse(MutatingUseContext::Borrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow(..)) |

        PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
        PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
        PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
        PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
            Some(DefUse::Use),

        ///////////////////////////////////////////////////////////////////////////
        // DROP USES
        //
        // These are uses that occur in a DROP (a MIR drop, not a
        // call to `std::mem::drop()`). For the purposes of NLL,
        // uses in drop are special because `#[may_dangle]`
        // attributes can affect whether lifetimes must be live.

        PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
            Some(DefUse::Drop),
    }
}

struct DefsUsesVisitor
{
    defs_uses: DefsUses,
}

#[derive(Eq, PartialEq, Clone)]
struct DefsUses {
    defs: LiveVarSet,
    uses: LiveVarSet,
}

impl DefsUses {
    fn apply(&self, bits: &mut LiveVarSet) -> bool {
        bits.subtract(&self.defs) | bits.union(&self.uses)
    }

    fn add_def(&mut self, index: Local) {
        // If it was used already in the block, remove that use
        // now that we found a definition.
        //
        // Example:
        //
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.uses.remove(index);
        self.defs.insert(index);
    }

    fn add_use(&mut self, index: Local) {
        // Inverse of above.
        //
        // Example:
        //
        //     // Defs = {}, Uses = {X}
        //     use(X)
        //     // Defs = {X}, Uses = {}
        //     X = 5
        //     // Defs = {}, Uses = {X}
        //     use(X)
        self.defs.remove(index);
        self.uses.insert(index);
    }
}

impl<'tcx> Visitor<'tcx> for DefsUsesVisitor
{
    fn visit_local(&mut self, &local: &Local, context: PlaceContext<'tcx>, _: Location) {
        match categorize(context) {
            Some(DefUse::Def) => self.defs_uses.add_def(local),
            Some(DefUse::Use) | Some(DefUse::Drop) => self.defs_uses.add_use(local),
            _ => (),
        }
    }
}

fn block<'tcx>(
    b: &BasicBlockData<'tcx>,
    locals: usize,
) -> DefsUses {
    let mut visitor = DefsUsesVisitor {
        defs_uses: DefsUses {
            defs: LiveVarSet::new_empty(locals),
            uses: LiveVarSet::new_empty(locals),
        },
    };

    let dummy_location = Location {
        block: BasicBlock::new(0),
        statement_index: 0,
    };

    // Visit the various parts of the basic block in reverse. If we go
    // forward, the logic in `add_def` and `add_use` would be wrong.
    visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location);
    for statement in b.statements.iter().rev() {
        visitor.visit_statement(BasicBlock::new(0), statement, dummy_location);
    }

    visitor.defs_uses
}

pub fn dump_mir<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    source: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }
    let node_path = ty::print::with_forced_impl_filename_line(|| {
        // see notes on #41697 below
        tcx.def_path_str(source.def_id())
    });
    dump_matched_mir_node(tcx, pass_name, &node_path, source, mir, result);
}

fn dump_matched_mir_node<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    pass_name: &str,
    node_path: &str,
    source: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    result: &LivenessResult,
) {
    let mut file_path = PathBuf::new();
    file_path.push(Path::new(&tcx.sess.opts.debugging_opts.dump_mir_dir));
    let item_id = tcx.hir().as_local_hir_id(source.def_id()).unwrap();
    let file_name = format!("rustc.node{}{}-liveness.mir", item_id, pass_name);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file, result)?;
        Ok(())
    });
}

pub fn write_mir_fn<'a, 'tcx>(
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    src: MirSource<'tcx>,
    mir: &Mir<'tcx>,
    w: &mut dyn Write,
    result: &LivenessResult,
) -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        let print = |w: &mut dyn Write, prefix, result: &IndexVec<BasicBlock, LiveVarSet>| {
            let live: Vec<String> = result[block]
                .iter()
                .map(|local| format!("{:?}", local))
                .collect();
            writeln!(w, "{} {{{}}}", prefix, live.join(", "))
        };
        write_basic_block(tcx, block, mir, &mut |_, _| Ok(()), w)?;
        print(w, "   ", &result.outs)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}
<|endoftext|>


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

use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
use context::CodegenCx;
use rustc::ty::layout::{self, Size};

fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
    // Always sign extend u32 values on 64-bit mips
    if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
        if let layout::Int(i, signed) = scalar.value {
            if !signed && i.size().bits() == 32 {
                if let PassMode::Direct(ref mut attrs) = arg.mode {
                    attrs.set(ArgAttribute::SExt);
                    return;
                }
            }
        }
    }

    arg.extend_integer_width_to(bits);
}

fn bits_to_int_reg(bits: u64) -> Reg {
    if bits <= 8 {
        Reg::i8()
    } else if bits <= 16 {
        Reg::i16()
    } else if bits <= 32 {
        Reg::i32()
    } else {
        Reg::i64()
    }
}

fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
    match ret.layout.field(cx, i).abi {
        layout::Abi::Scalar(ref scalar) => match scalar.value {
            layout::F32 => Some(Reg::f32()),
            layout::F64 => Some(Reg::f64()),
            _ => None
        },
        _ => None
    }
}

fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
    if !ret.layout.is_aggregate() {
        extend_integer_width_mips(ret, 64);
        return;
    }

    let size = ret.layout.size;
    let bits = size.bits();
    if bits <= 128 {
        // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
        // use of float registers to structures (not unions) containing exactly one or two
        // float fields.

        if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
            if ret.layout.fields.count() == 1 {
                if let Some(reg) = float_reg(cx, ret, 0) {
                    ret.cast_to(reg);
                    return;
                }
            } else if ret.layout.fields.count() == 2 {
                if let Some(reg0) = float_reg(cx, ret, 0) {
                    if let Some(reg1) = float_reg(cx, ret, 1) {
                        ret.cast_to(CastTarget::pair(reg0, reg1));
                        return;
                    }
                }
            }
        }

        // Cast to a uniform int structure
        ret.cast_to(Uniform {
            unit: bits_to_int_reg(bits),
            total: size
        });
    } else {
        ret.make_indirect();
    }
}

fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
    if !arg.layout.is_aggregate() {
        extend_integer_width_mips(arg, 64);
        return;
    }

    let dl = &cx.tcx.data_layout;
    let size = arg.layout.size;
    let mut prefix = [None; 8];
    let mut prefix_index = 0;

    match arg.layout.fields {
        layout::FieldPlacement::Array { .. } => {
            // Arrays are passed indirectly
            arg.make_indirect();
            return;
        }
        layout::FieldPlacement::Union(_) => {
            // Unions and are always treated as a series of 64-bit integer chunks
        },
        layout::FieldPlacement::Arbitrary { .. } => {
            // Structures are split up into a series of 64-bit integer chunks, but any aligned
            // doubles not part of another aggregate are passed as floats.
            let mut last_offset = Size::from_bytes(0);

            for i in 0..arg.layout.fields.count() {
                let field = arg.layout.field(cx, i);
                let offset = arg.layout.fields.offset(i);

                // We only care about aligned doubles
                if let layout::Abi::Scalar(ref scalar) = field.abi {
                    if let layout::F64 = scalar.value {
                        if offset.is_abi_aligned(dl.f64_align) {
                            // Insert enough integers to cover [last_offset, offset)
                            assert!(last_offset.is_abi_aligned(dl.f64_align));
                            for _ in 0..((offset - last_offset).bits() / 64)
                                .min((prefix.len() - prefix_index) as u64) {

                                prefix[prefix_index] = Some(RegKind::Integer);
                                prefix_index += 1;
                            }

                            if prefix_index == prefix.len() {
                                break;
                            }

                            prefix[prefix_index] = Some(RegKind::Float);
                            prefix_index += 1;
                            last_offset = offset + Reg::f64().size;
                        }
                    }
                }
            }
        }
    };

    // Extract first 8 chunks as the prefix
    let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
    arg.cast_to(CastTarget {
        prefix: prefix,
        prefix_chunk: Size::from_bytes(8),
        rest: Uniform { unit: Reg::i64(), total: rest_size }
    });
}

pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    if !fty.ret.is_ignore() {
        classify_ret_ty(cx, &mut fty.ret);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(cx, arg);
    }
}
<commit_msg>Rollup merge of #49024 - draganmladjenovic:mips64_cabi_sret, r=sanxiyn<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform};
use context::CodegenCx;
use rustc::ty::layout::{self, Size};

fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) {
    // Always sign extend u32 values on 64-bit mips
    if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
        if let layout::Int(i, signed) = scalar.value {
            if !signed && i.size().bits() == 32 {
                if let PassMode::Direct(ref mut attrs) = arg.mode {
                    attrs.set(ArgAttribute::SExt);
                    return;
                }
            }
        }
    }

    arg.extend_integer_width_to(bits);
}

fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> {
    match ret.layout.field(cx, i).abi {
        layout::Abi::Scalar(ref scalar) => match scalar.value {
            layout::F32 => Some(Reg::f32()),
            layout::F64 => Some(Reg::f64()),
            _ => None
        },
        _ => None
    }
}

fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) {
    if !ret.layout.is_aggregate() {
        extend_integer_width_mips(ret, 64);
        return;
    }

    let size = ret.layout.size;
    let bits = size.bits();
    if bits <= 128 {
        // Unlike other architectures which return aggregates in registers, MIPS n64 limits the
        // use of float registers to structures (not unions) containing exactly one or two
        // float fields.

        if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields {
            if ret.layout.fields.count() == 1 {
                if let Some(reg) = float_reg(cx, ret, 0) {
                    ret.cast_to(reg);
                    return;
                }
            } else if ret.layout.fields.count() == 2 {
                if let Some(reg0) = float_reg(cx, ret, 0) {
                    if let Some(reg1) = float_reg(cx, ret, 1) {
                        ret.cast_to(CastTarget::pair(reg0, reg1));
                        return;
                    }
                }
            }
        }

        // Cast to a uniform int structure
        ret.cast_to(Uniform {
            unit: Reg::i64(),
            total: size
        });
    } else {
        ret.make_indirect();
    }
}

fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) {
    if !arg.layout.is_aggregate() {
        extend_integer_width_mips(arg, 64);
        return;
    }

    let dl = &cx.tcx.data_layout;
    let size = arg.layout.size;
    let mut prefix = [None; 8];
    let mut prefix_index = 0;

    match arg.layout.fields {
        layout::FieldPlacement::Array { .. } => {
            // Arrays are passed indirectly
            arg.make_indirect();
            return;
        }
        layout::FieldPlacement::Union(_) => {
            // Unions and are always treated as a series of 64-bit integer chunks
        },
        layout::FieldPlacement::Arbitrary { .. } => {
            // Structures are split up into a series of 64-bit integer chunks, but any aligned
            // doubles not part of another aggregate are passed as floats.
            let mut last_offset = Size::from_bytes(0);

            for i in 0..arg.layout.fields.count() {
                let field = arg.layout.field(cx, i);
                let offset = arg.layout.fields.offset(i);

                // We only care about aligned doubles
                if let layout::Abi::Scalar(ref scalar) = field.abi {
                    if let layout::F64 = scalar.value {
                        if offset.is_abi_aligned(dl.f64_align) {
                            // Insert enough integers to cover [last_offset, offset)
                            assert!(last_offset.is_abi_aligned(dl.f64_align));
                            for _ in 0..((offset - last_offset).bits() / 64)
                                .min((prefix.len() - prefix_index) as u64) {

                                prefix[prefix_index] = Some(RegKind::Integer);
                                prefix_index += 1;
                            }

                            if prefix_index == prefix.len() {
                                break;
                            }

                            prefix[prefix_index] = Some(RegKind::Float);
                            prefix_index += 1;
                            last_offset = offset + Reg::f64().size;
                        }
                    }
                }
            }
        }
    };

    // Extract first 8 chunks as the prefix
    let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
    arg.cast_to(CastTarget {
        prefix: prefix,
        prefix_chunk: Size::from_bytes(8),
        rest: Uniform { unit: Reg::i64(), total: rest_size }
    });
}

pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) {
    if !fty.ret.is_ignore() {
        classify_ret_ty(cx, &mut fty.ret);
    }

    for arg in &mut fty.args {
        if arg.is_ignore() { continue; }
        classify_arg_ty(cx, arg);
    }
}
<|endoftext|>


<commit_before>#[cfg(target_os = "macos")]
mod common;

#[cfg(target_os = "macos")]
mod tests {
    const TEST_PLATFORM: &str = "wasm32";

    use super::common::check_request_received_using;
    use std::fs;
    use std::path::PathBuf;

    // to run this test, run it as:
    // cargo test --test test_wasm32 -- --ignored
    //
    #[ignore]
    #[actix_rt::test]
    async fn test_wasm32() {
        let uri = &format!("/{}", TEST_PLATFORM);
        let ipv4 = "127.0.0.1";
        check_request_received_using(uri.into(), &ipv4, |url| {
            // modify html to use the correct url
            let mut app_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            app_dir.push("tests/test-wasm-app");
            let mut src_html = PathBuf::from(&app_dir);
            src_html.push("test.html");
            let mut dst_html = PathBuf::from(&app_dir);
            dst_html.push("pkg/test.html");
            let old_html = fs::read_to_string(&src_html).expect("failed to read test.html");
            let new_html = old_html.replace("DYNAMIC_URL_TBD", &url);
            fs::write(&dst_html, &new_html).expect("failed to update dst test.html");

            // open browser
            let html_url = url.replace(uri, "/static/wasm/test.html");
            //println!("URL: {}", html_url);
            let status = webbrowser::open(&html_url);

            // check for browser run status
            status.expect("browser open failed");
        })
        .await;
    }
}
<commit_msg>allow wasm tests to be run on linux<commit_after>#[cfg(any(target_os = "macos", target_os = "linux"))]
mod common;

#[cfg(any(target_os = "macos", target_os = "linux"))]
mod tests {
    const TEST_PLATFORM: &str = "wasm32";

    use super::common::check_request_received_using;
    use std::fs;
    use std::path::PathBuf;

    // to run this test, run it as:
    // cargo test --test test_wasm32 -- --ignored
    //
    #[ignore]
    #[actix_rt::test]
    async fn test_wasm32() {
        let uri = &format!("/{}", TEST_PLATFORM);
        let ipv4 = "127.0.0.1";
        check_request_received_using(uri.into(), &ipv4, |url| {
            // modify html to use the correct url
            let mut app_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            app_dir.push("tests/test-wasm-app");
            let mut src_html = PathBuf::from(&app_dir);
            src_html.push("test.html");
            let mut dst_html = PathBuf::from(&app_dir);
            dst_html.push("pkg/test.html");
            let old_html = fs::read_to_string(&src_html).expect("failed to read test.html");
            let new_html = old_html.replace("DYNAMIC_URL_TBD", &url);
            fs::write(&dst_html, &new_html).expect("failed to update dst test.html");

            // open browser
            let html_url = url.replace(uri, "/static/wasm/test.html");
            //println!("URL: {}", html_url);
            let status = webbrowser::open(&html_url);

            // check for browser run status
            status.expect("browser open failed");
        })
        .await;
    }
}
<|endoftext|>