<commit_before>use hir::Semantics;
use ide_db::{
    base_db::FilePosition,
    defs::Definition,
    helpers::pick_best_token,
    search::{FileReference, ReferenceAccess, SearchScope},
    RootDatabase,
};
use syntax::{
    ast, match_ast, AstNode,
    SyntaxKind::{ASYNC_KW, AWAIT_KW, QUESTION, RETURN_KW, THIN_ARROW},
    SyntaxNode, SyntaxToken, TextRange, WalkEvent,
};

use crate::{display::TryToNav, references, NavigationTarget};

pub struct DocumentHighlight {
    pub range: TextRange,
    pub access: Option<ReferenceAccess>,
}

// Feature: Highlight related
//
// Highlights exit points, yield points or the definition and all references of the item at the cursor location in the current file.
pub(crate) fn highlight_related(
    sema: &Semantics<RootDatabase>,
    position: FilePosition,
) -> Option<Vec<DocumentHighlight>> {
    let _p = profile::span("document_highlight");
    let syntax = sema.parse(position.file_id).syntax().clone();

    let token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
        QUESTION => 2, // prefer `?` when the cursor is sandwiched like `await$0?`
        AWAIT_KW | ASYNC_KW | THIN_ARROW | RETURN_KW => 1,
        _ => 0,
    })?;

    match token.kind() {
        QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(token),
        AWAIT_KW | ASYNC_KW => highlight_yield_points(token),
        _ => highlight_references(sema, &syntax, position),
    }
}

fn highlight_references(
    sema: &Semantics<RootDatabase>,
    syntax: &SyntaxNode,
    FilePosition { offset, file_id }: FilePosition,
) -> Option<Vec<DocumentHighlight>> {
    let def = references::find_def(sema, syntax, offset)?;
    let usages = def.usages(sema).set_scope(Some(SearchScope::single_file(file_id))).all();

    let declaration = match def {
        Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
            Some(NavigationTarget::from_module_to_decl(sema.db, module))
        }
        def => def.try_to_nav(sema.db),
    }
    .filter(|decl| decl.file_id == file_id)
    .and_then(|decl| {
        let range = decl.focus_range?;
        let access = references::decl_access(&def, syntax, range);
        Some(DocumentHighlight { range, access })
    });

    let file_refs = usages.references.get(&file_id).map_or(&[][..], Vec::as_slice);
    let mut res = Vec::with_capacity(file_refs.len() + 1);
    res.extend(declaration);
    res.extend(
        file_refs
            .iter()
            .map(|&FileReference { access, range, .. }| DocumentHighlight { range, access }),
    );
    Some(res)
}

fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
    fn hl(body: Option<ast::Expr>) -> Option<Vec<DocumentHighlight>> {
        let mut highlights = Vec::new();
        let body = body?;
        walk(body.syntax(), |node| {
            match_ast! {
                match node {
                    ast::ReturnExpr(expr) => if let Some(token) = expr.return_token() {
                        highlights.push(DocumentHighlight {
                            access: None,
                            range: token.text_range(),
                        });
                    },
                    ast::TryExpr(try_) => if let Some(token) = try_.question_mark_token() {
                        highlights.push(DocumentHighlight {
                            access: None,
                            range: token.text_range(),
                        });
                    },
                    ast::EffectExpr(effect) => if effect.async_token().is_some() {
                        return true;
                    },
                    ast::ClosureExpr(__) => return true,
                    ast::Item(__) => return true,
                    ast::Path(__) => return true,
                    _ => (),
                }
            }
            false
        });
        let tail = match body {
            ast::Expr::BlockExpr(b) => b.tail_expr(),
            e => Some(e),
        };
        if let Some(tail) = tail {
            highlights.push(DocumentHighlight { access: None, range: tail.syntax().text_range() });
        }
        Some(highlights)
    }
    for anc in token.ancestors() {
        return match_ast! {
            match anc {
                ast::Fn(fn_) => hl(fn_.body().map(ast::Expr::BlockExpr)),
                ast::ClosureExpr(closure) => hl(closure.body()),
                ast::EffectExpr(effect) => if effect.async_token().is_some() {
                    None
                } else {
                    continue;
                },
                _ => continue,
            }
        };
    }
    None
}

fn highlight_yield_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
    fn hl(
        async_token: Option<SyntaxToken>,
        body: Option<ast::BlockExpr>,
    ) -> Option<Vec<DocumentHighlight>> {
        let mut highlights = Vec::new();
        highlights.push(DocumentHighlight { access: None, range: async_token?.text_range() });
        if let Some(body) = body {
            walk(body.syntax(), |node| {
                match_ast! {
                    match node {
                        ast::AwaitExpr(expr) => if let Some(token) = expr.await_token() {
                            highlights.push(DocumentHighlight {
                                access: None,
                                range: token.text_range(),
                            });
                        },
                        ast::EffectExpr(effect) => if effect.async_token().is_some() {
                            return true;
                        },
                        ast::ClosureExpr(__) => return true,
                        ast::Item(__) => return true,
                        ast::Path(__) => return true,
                        _ => (),
                    }
                }
                false
            });
        }
        Some(highlights)
    }
    for anc in token.ancestors() {
        return match_ast! {
            match anc {
                ast::Fn(fn_) => hl(fn_.async_token(), fn_.body()),
                ast::EffectExpr(effect) => hl(effect.async_token(), effect.block_expr()),
                ast::ClosureExpr(__) => None,
                _ => continue,
            }
        };
    }
    None
}

fn walk(syntax: &SyntaxNode, mut cb: impl FnMut(SyntaxNode) -> bool) {
    let mut preorder = syntax.preorder();
    while let Some(event) = preorder.next() {
        let node = match event {
            WalkEvent::Enter(node) => node,
            WalkEvent::Leave(_) => continue,
        };
        if cb(node) {
            preorder.skip_subtree();
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::fixture;

    use super::*;

    fn check(ra_fixture: &str) {
        let (analysis, pos, annotations) = fixture::annotations(ra_fixture);
        let hls = analysis.highlight_related(pos).unwrap().unwrap();

        let mut expected = annotations
            .into_iter()
            .map(|(r, access)| (r.range, (!access.is_empty()).then(|| access)))
            .collect::<Vec<_>>();

        let mut actual = hls
            .into_iter()
            .map(|hl| {
                (
                    hl.range,
                    hl.access.map(|it| {
                        match it {
                            ReferenceAccess::Read => "read",
                            ReferenceAccess::Write => "write",
                        }
                        .to_string()
                    }),
                )
            })
            .collect::<Vec<_>>();
        actual.sort_by_key(|(range, _)| range.start());
        expected.sort_by_key(|(range, _)| range.start());

        assert_eq!(expected, actual);
    }

    #[test]
    fn test_hl_module() {
        check(
            r#"
//- /lib.rs
mod foo$0;
 // ^^^
//- /foo.rs
struct Foo;
"#,
        );
    }

    #[test]
    fn test_hl_self_in_crate_root() {
        check(
            r#"
use self$0;
"#,
        );
    }

    #[test]
    fn test_hl_self_in_module() {
        check(
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
use self$0;
"#,
        );
    }

    #[test]
    fn test_hl_local() {
        check(
            r#"
fn foo() {
    let mut bar = 3;
         // ^^^ write
    bar$0;
 // ^^^ read
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_points() {
        check(
            r#"
pub async fn foo() {
 // ^^^^^
    let x = foo()
        .await$0
      // ^^^^^
        .await;
      // ^^^^^
    || { 0.await };
    (async { 0.await }).await
                     // ^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_points2() {
        check(
            r#"
pub async$0 fn foo() {
 // ^^^^^
    let x = foo()
        .await
      // ^^^^^
        .await;
      // ^^^^^
    || { 0.await };
    (async { 0.await }).await
                     // ^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_nested_fn() {
        check(
            r#"
async fn foo() {
    async fn foo2() {
 // ^^^^^
        async fn foo3() {
            0.await
        }
        0.await$0
       // ^^^^^
    }
    0.await
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_nested_async_blocks() {
        check(
            r#"
async fn foo() {
    (async {
  // ^^^^^
        (async {
           0.await
        }).await$0 }
        // ^^^^^
    ).await;
}
"#,
        );
    }

    #[test]
    fn test_hl_exit_points() {
        check(
            r#"
fn foo() -> u32 {
    if true {
        return$0 0;
     // ^^^^^^
    }

    0?;
  // ^
    0xDEAD_BEEF
 // ^^^^^^^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_exit_points2() {
        check(
            r#"
fn foo() ->$0 u32 {
    if true {
        return 0;
     // ^^^^^^
    }

    0?;
  // ^
    0xDEAD_BEEF
 // ^^^^^^^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_prefer_ref_over_tail_exit() {
        check(
            r#"
fn foo() -> u32 {
// ^^^
    if true {
        return 0;
    }

    0?;

    foo$0()
 // ^^^
}
"#,
        );
    }
}
<commit_msg>Simplify<commit_after>use hir::Semantics;
use ide_db::{
    base_db::FilePosition,
    defs::Definition,
    helpers::pick_best_token,
    search::{FileReference, ReferenceAccess, SearchScope},
    RootDatabase,
};
use syntax::{
    ast, match_ast, AstNode,
    SyntaxKind::{ASYNC_KW, AWAIT_KW, QUESTION, RETURN_KW, THIN_ARROW},
    SyntaxNode, SyntaxToken, TextRange, WalkEvent,
};

use crate::{display::TryToNav, references, NavigationTarget};

pub struct DocumentHighlight {
    pub range: TextRange,
    pub access: Option<ReferenceAccess>,
}

// Feature: Highlight Related
//
// Highlights exit points, yield points or the definition and all references of the item at the cursor location in the current file.
pub(crate) fn highlight_related(
    sema: &Semantics<RootDatabase>,
    position: FilePosition,
) -> Option<Vec<DocumentHighlight>> {
    let _p = profile::span("document_highlight");
    let syntax = sema.parse(position.file_id).syntax().clone();

    let token = pick_best_token(syntax.token_at_offset(position.offset), |kind| match kind {
        QUESTION => 2, // prefer `?` when the cursor is sandwiched like `await$0?`
        AWAIT_KW | ASYNC_KW | THIN_ARROW | RETURN_KW => 1,
        _ => 0,
    })?;

    match token.kind() {
        QUESTION | RETURN_KW | THIN_ARROW => highlight_exit_points(token),
        AWAIT_KW | ASYNC_KW => highlight_yield_points(token),
        _ => highlight_references(sema, &syntax, position),
    }
}

fn highlight_references(
    sema: &Semantics<RootDatabase>,
    syntax: &SyntaxNode,
    FilePosition { offset, file_id }: FilePosition,
) -> Option<Vec<DocumentHighlight>> {
    let def = references::find_def(sema, syntax, offset)?;
    let usages = def.usages(sema).set_scope(Some(SearchScope::single_file(file_id))).all();

    let declaration = match def {
        Definition::ModuleDef(hir::ModuleDef::Module(module)) => {
            Some(NavigationTarget::from_module_to_decl(sema.db, module))
        }
        def => def.try_to_nav(sema.db),
    }
    .filter(|decl| decl.file_id == file_id)
    .and_then(|decl| {
        let range = decl.focus_range?;
        let access = references::decl_access(&def, syntax, range);
        Some(DocumentHighlight { range, access })
    });

    let file_refs = usages.references.get(&file_id).map_or(&[][..], Vec::as_slice);
    let mut res = Vec::with_capacity(file_refs.len() + 1);
    res.extend(declaration);
    res.extend(
        file_refs
            .iter()
            .map(|&FileReference { access, range, .. }| DocumentHighlight { range, access }),
    );
    Some(res)
}

fn highlight_exit_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
    fn hl(body: Option<ast::Expr>) -> Option<Vec<DocumentHighlight>> {
        let mut highlights = Vec::new();
        let body = body?;
        walk(&body, |node| {
            match_ast! {
                match node {
                    ast::ReturnExpr(expr) => if let Some(token) = expr.return_token() {
                        highlights.push(DocumentHighlight {
                            access: None,
                            range: token.text_range(),
                        });
                    },
                    ast::TryExpr(try_) => if let Some(token) = try_.question_mark_token() {
                        highlights.push(DocumentHighlight {
                            access: None,
                            range: token.text_range(),
                        });
                    },
                    // All the following are different contexts so skip them
                    ast::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(),
                    ast::ClosureExpr(__) => return true,
                    ast::Item(__) => return true,
                    // Don't look into const args
                    ast::Path(__) => return true,
                    _ => (),
                }
            }
            false
        });
        let tail = match body {
            ast::Expr::BlockExpr(b) => b.tail_expr(),
            e => Some(e),
        };
        if let Some(tail) = tail {
            highlights.push(DocumentHighlight { access: None, range: tail.syntax().text_range() });
        }
        Some(highlights)
    }
    for anc in token.ancestors() {
        return match_ast! {
            match anc {
                ast::Fn(fn_) => hl(fn_.body().map(ast::Expr::BlockExpr)),
                ast::ClosureExpr(closure) => hl(closure.body()),
                ast::EffectExpr(effect) => if effect.async_token().is_some() || effect.try_token().is_some() {
                    hl(effect.block_expr().map(ast::Expr::BlockExpr))
                } else {
                    continue;
                },
                _ => continue,
            }
        };
    }
    None
}

fn highlight_yield_points(token: SyntaxToken) -> Option<Vec<DocumentHighlight>> {
    fn hl(
        async_token: Option<SyntaxToken>,
        body: Option<ast::Expr>,
    ) -> Option<Vec<DocumentHighlight>> {
        let mut highlights = Vec::new();
        highlights.push(DocumentHighlight { access: None, range: async_token?.text_range() });
        if let Some(body) = body {
            walk(&body, |node| {
                match_ast! {
                    match node {
                        ast::AwaitExpr(expr) => if let Some(token) = expr.await_token() {
                            highlights.push(DocumentHighlight {
                                access: None,
                                range: token.text_range(),
                            });
                        },
                        // All the following are different contexts so skip them
                        ast::EffectExpr(effect) => return effect.async_token().is_some() || effect.try_token().is_some(),
                        ast::ClosureExpr(__) => return true,
                        ast::Item(__) => return true,
                        // Don't look into const args
                        ast::Path(__) => return true,
                        _ => (),
                    }
                }
                false
            });
        }
        Some(highlights)
    }
    for anc in token.ancestors() {
        return match_ast! {
            match anc {
                ast::Fn(fn_) => hl(fn_.async_token(), fn_.body().map(ast::Expr::BlockExpr)),
                ast::EffectExpr(effect) => hl(effect.async_token(), effect.block_expr().map(ast::Expr::BlockExpr)),
                ast::ClosureExpr(closure) => hl(closure.async_token(), closure.body()),
                _ => continue,
            }
        };
    }
    None
}

/// Preorder walk the expression node skipping a node's subtrees if the callback returns `true` for the node.
fn walk(expr: &ast::Expr, mut cb: impl FnMut(SyntaxNode) -> bool) {
    let mut preorder = expr.syntax().preorder();
    while let Some(event) = preorder.next() {
        let node = match event {
            WalkEvent::Enter(node) => node,
            WalkEvent::Leave(_) => continue,
        };
        if cb(node) {
            preorder.skip_subtree();
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::fixture;

    use super::*;

    fn check(ra_fixture: &str) {
        let (analysis, pos, annotations) = fixture::annotations(ra_fixture);
        let hls = analysis.highlight_related(pos).unwrap().unwrap();

        let mut expected = annotations
            .into_iter()
            .map(|(r, access)| (r.range, (!access.is_empty()).then(|| access)))
            .collect::<Vec<_>>();

        let mut actual = hls
            .into_iter()
            .map(|hl| {
                (
                    hl.range,
                    hl.access.map(|it| {
                        match it {
                            ReferenceAccess::Read => "read",
                            ReferenceAccess::Write => "write",
                        }
                        .to_string()
                    }),
                )
            })
            .collect::<Vec<_>>();
        actual.sort_by_key(|(range, _)| range.start());
        expected.sort_by_key(|(range, _)| range.start());

        assert_eq!(expected, actual);
    }

    #[test]
    fn test_hl_module() {
        check(
            r#"
//- /lib.rs
mod foo$0;
 // ^^^
//- /foo.rs
struct Foo;
"#,
        );
    }

    #[test]
    fn test_hl_self_in_crate_root() {
        check(
            r#"
use self$0;
"#,
        );
    }

    #[test]
    fn test_hl_self_in_module() {
        check(
            r#"
//- /lib.rs
mod foo;
//- /foo.rs
use self$0;
"#,
        );
    }

    #[test]
    fn test_hl_local() {
        check(
            r#"
fn foo() {
    let mut bar = 3;
         // ^^^ write
    bar$0;
 // ^^^ read
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_points() {
        check(
            r#"
pub async fn foo() {
 // ^^^^^
    let x = foo()
        .await$0
      // ^^^^^
        .await;
      // ^^^^^
    || { 0.await };
    (async { 0.await }).await
                     // ^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_points2() {
        check(
            r#"
pub async$0 fn foo() {
 // ^^^^^
    let x = foo()
        .await
      // ^^^^^
        .await;
      // ^^^^^
    || { 0.await };
    (async { 0.await }).await
                     // ^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_nested_fn() {
        check(
            r#"
async fn foo() {
    async fn foo2() {
 // ^^^^^
        async fn foo3() {
            0.await
        }
        0.await$0
       // ^^^^^
    }
    0.await
}
"#,
        );
    }

    #[test]
    fn test_hl_yield_nested_async_blocks() {
        check(
            r#"
async fn foo() {
    (async {
  // ^^^^^
        (async {
           0.await
        }).await$0 }
        // ^^^^^
    ).await;
}
"#,
        );
    }

    #[test]
    fn test_hl_exit_points() {
        check(
            r#"
fn foo() -> u32 {
    if true {
        return$0 0;
     // ^^^^^^
    }

    0?;
  // ^
    0xDEAD_BEEF
 // ^^^^^^^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_exit_points2() {
        check(
            r#"
fn foo() ->$0 u32 {
    if true {
        return 0;
     // ^^^^^^
    }

    0?;
  // ^
    0xDEAD_BEEF
 // ^^^^^^^^^^^
}
"#,
        );
    }

    #[test]
    fn test_hl_prefer_ref_over_tail_exit() {
        check(
            r#"
fn foo() -> u32 {
// ^^^
    if true {
        return 0;
    }

    0?;

    foo$0()
 // ^^^
}
"#,
        );
    }
}
<|endoftext|>


<commit_before>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

use cfg_if::cfg_if;

#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            #[doc(hidden)]
            pub(crate) enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub(crate) fn to_str(self) -> &'static str { "" }
            }
        }
    }
}

// This module needs to be public because the `is_{arch}_feature_detected!`
// macros expand calls to items within it in user crates.
#[doc(hidden)]
pub use self::arch::__is_feature_detected;

pub(crate) use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(target_os = "freebsd")] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] {
        #[path = "os/windows/aarch64.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
fn check_for(x: Feature) -> bool {
    cache::test(x as u32, self::os::detect_features)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                let f: Feature = unsafe { crate::mem::transmute(discriminant) };
                let name: &'static str = f.to_str();
                let enabled: bool = check_for(f);
                (name, enabled)
            })
        } else {
            None.into_iter()
        }
    }
}
<commit_msg>Unbreak non-x86 build on FreeBSD<commit_after>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

use cfg_if::cfg_if;

#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        mod arch {
            #[doc(hidden)]
            pub(crate) enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub(crate) fn to_str(self) -> &'static str { "" }
            }
        }
    }
}

// This module needs to be public because the `is_{arch}_feature_detected!`
// macros expand calls to items within it in user crates.
#[doc(hidden)]
pub use self::arch::__is_feature_detected;

pub(crate) use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "use_std"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "freebsd", feature = "use_std"))] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] {
        #[path = "os/windows/aarch64.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
fn check_for(x: Feature) -> bool {
    cache::test(x as u32, self::os::detect_features)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                let f: Feature = unsafe { crate::mem::transmute(discriminant) };
                let name: &'static str = f.to_str();
                let enabled: bool = check_for(f);
                (name, enabled)
            })
        } else {
            None.into_iter()
        }
    }
}
<|endoftext|>


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

//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics::{min_align_of_val, size_of_val};
use core::ptr::{NonNull, Unique};
use core::usize;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use core::alloc::*;

extern "Rust" {
    #[allocator]
    #[rustc_allocator_nounwind]
    fn __rust_alloc(size: usize, align: usize) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
    #[rustc_allocator_nounwind]
    fn __rust_realloc(ptr: *mut u8,
                      old_size: usize,
                      align: usize,
                      new_size: usize) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}

/// The global memory allocator.
///
/// This type implements the [`Alloc`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)]
pub struct Global;

/// Allocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `alloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
    __rust_alloc(layout.size(), layout.align())
}

/// Deallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::dealloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `dealloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::dealloc`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
    __rust_dealloc(ptr, layout.size(), layout.align())
}

/// Reallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::realloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `realloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::realloc`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
    __rust_realloc(ptr, layout.size(), layout.align(), new_size)
}

/// Allocate zero-initialized memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `alloc_zeroed` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc_zeroed`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
    __rust_alloc_zeroed(layout.size(), layout.align())
}

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(alloc(layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        dealloc(ptr.as_ptr(), layout)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: NonNull<u8>,
                      layout: Layout,
                      new_size: usize)
                      -> Result<NonNull<u8>, AllocErr>
    {
        NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
    }
}

/// The allocator for unique pointers.
// This function must not unwind. If it does, MIR codegen will fail.
#[cfg(not(test))]
#[lang = "exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
    if size == 0 {
        align as *mut u8
    } else {
        let layout = Layout::from_size_align_unchecked(size, align);
        let ptr = alloc(layout);
        if !ptr.is_null() {
            ptr
        } else {
            oom(layout)
        }
    }
}

#[cfg_attr(not(test), lang = "box_free")]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
    let ptr = ptr.as_ptr();
    let size = size_of_val(&*ptr);
    let align = min_align_of_val(&*ptr);
    // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
    if size != 0 {
        let layout = Layout::from_size_align_unchecked(size, align);
        dealloc(ptr as *mut u8, layout);
    }
}

/// Abort on memory allocation error or failure.
///
/// Callers of memory allocation APIs wishing to abort computation
/// in response to an allocation error are encouraged to call this function,
/// rather than directly invoking `panic!` or similar.
///
/// The default behavior of this function is to print a message to standard error
/// and abort the process.
/// It can be replaced with [`std::alloc::set_oom_hook`]
/// and [`std::alloc::take_oom_hook`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_allocator_nounwind]
pub fn oom(layout: Layout) -> ! {
    #[allow(improper_ctypes)]
    extern "Rust" {
        #[lang = "oom"]
        fn oom_impl(layout: Layout) -> !;
    }
    unsafe { oom_impl(layout) }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use boxed::Box;
    use alloc::{Global, Alloc, Layout, oom};

    #[test]
    fn allocate_zeroed() {
        unsafe {
            let layout = Layout::from_size_align(1024, 1).unwrap();
            let ptr = Global.alloc_zeroed(layout.clone())
                .unwrap_or_else(|_| oom(layout));

            let mut i = ptr.cast::<u8>().as_ptr();
            let end = i.offset(layout.size() as isize);
            while i < end {
                assert_eq!(*i, 0);
                i = i.offset(1);
            }
            Global.dealloc(ptr, layout);
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = box 10;
        })
    }
}
<commit_msg>Stabilize alloc free functions for the global allocators.<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

use core::intrinsics::{min_align_of_val, size_of_val};
use core::ptr::{NonNull, Unique};
use core::usize;

#[stable(feature = "alloc_module", since = "1.28.0")]
#[doc(inline)]
pub use core::alloc::*;

extern "Rust" {
    #[allocator]
    #[rustc_allocator_nounwind]
    fn __rust_alloc(size: usize, align: usize) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
    #[rustc_allocator_nounwind]
    fn __rust_realloc(ptr: *mut u8,
                      old_size: usize,
                      align: usize,
                      new_size: usize) -> *mut u8;
    #[rustc_allocator_nounwind]
    fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
}

/// The global memory allocator.
///
/// This type implements the [`Alloc`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Copy, Clone, Default, Debug)]
pub struct Global;

/// Allocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `alloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
    __rust_alloc(layout.size(), layout.align())
}

/// Deallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::dealloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `dealloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::dealloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
    __rust_dealloc(ptr, layout.size(), layout.align())
}

/// Reallocate memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::realloc`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `realloc` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::realloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
    __rust_realloc(ptr, layout.size(), layout.align(), new_size)
}

/// Allocate zero-initialized memory with the global allocator.
///
/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
/// of the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// This function is expected to be deprecated in favor of the `alloc_zeroed` method
/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
///
/// # Safety
///
/// See [`GlobalAlloc::alloc_zeroed`].
#[stable(feature = "global_alloc", since = "1.28.0")]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
    __rust_alloc_zeroed(layout.size(), layout.align())
}

#[unstable(feature = "allocator_api", issue = "32838")]
unsafe impl Alloc for Global {
    #[inline]
    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(alloc(layout)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
        dealloc(ptr.as_ptr(), layout)
    }

    #[inline]
    unsafe fn realloc(&mut self,
                      ptr: NonNull<u8>,
                      layout: Layout,
                      new_size: usize)
                      -> Result<NonNull<u8>, AllocErr>
    {
        NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
    }

    #[inline]
    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
        NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
    }
}

/// The allocator for unique pointers.
// This function must not unwind. If it does, MIR codegen will fail.
#[cfg(not(test))]
#[lang = "exchange_malloc"]
#[inline]
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
    if size == 0 {
        align as *mut u8
    } else {
        let layout = Layout::from_size_align_unchecked(size, align);
        let ptr = alloc(layout);
        if !ptr.is_null() {
            ptr
        } else {
            oom(layout)
        }
    }
}

#[cfg_attr(not(test), lang = "box_free")]
#[inline]
pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
    let ptr = ptr.as_ptr();
    let size = size_of_val(&*ptr);
    let align = min_align_of_val(&*ptr);
    // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
    if size != 0 {
        let layout = Layout::from_size_align_unchecked(size, align);
        dealloc(ptr as *mut u8, layout);
    }
}

/// Abort on memory allocation error or failure.
///
/// Callers of memory allocation APIs wishing to abort computation
/// in response to an allocation error are encouraged to call this function,
/// rather than directly invoking `panic!` or similar.
///
/// The default behavior of this function is to print a message to standard error
/// and abort the process.
/// It can be replaced with [`std::alloc::set_oom_hook`]
/// and [`std::alloc::take_oom_hook`].
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_allocator_nounwind]
pub fn oom(layout: Layout) -> ! {
    #[allow(improper_ctypes)]
    extern "Rust" {
        #[lang = "oom"]
        fn oom_impl(layout: Layout) -> !;
    }
    unsafe { oom_impl(layout) }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use self::test::Bencher;
    use boxed::Box;
    use alloc::{Global, Alloc, Layout, oom};

    #[test]
    fn allocate_zeroed() {
        unsafe {
            let layout = Layout::from_size_align(1024, 1).unwrap();
            let ptr = Global.alloc_zeroed(layout.clone())
                .unwrap_or_else(|_| oom(layout));

            let mut i = ptr.cast::<u8>().as_ptr();
            let end = i.offset(layout.size() as isize);
            while i < end {
                assert_eq!(*i, 0);
                i = i.offset(1);
            }
            Global.dealloc(ptr, layout);
        }
    }

    #[bench]
    fn alloc_owned_small(b: &mut Bencher) {
        b.iter(|| {
            let _: Box<_> = box 10;
        })
    }
}
<|endoftext|>


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

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##

}

register_diagnostics! {
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<commit_msg>Add detailed diagnostics for E0386.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0386: r##"
This error occurs when an attempt is made to mutate the target of a mutable
reference stored inside an immutable container.

For example, this can happen when storing a `&mut` inside an immutable `Box`:

```
let mut x: i64 = 1;
let y: Box<_> = Box::new(&mut x);
**y = 2; // error, cannot assign to data in an immutable container
```

This error can be fixed by making the container mutable:

```
let mut x: i64 = 1;
let mut y: Box<_> = Box::new(&mut x);
**y = 2;
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##

}

register_diagnostics! {
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<|endoftext|>


<commit_before>/*
Module: either

A type that represents one of two alternatives
*/

/*
Tag: t

The either type
*/
tag t<T, U> {
    /* Variant: left */
    left(T);
    /* Variant: right */
    right(U);
}

/* Section: Operations */

/*
Function: either

Applies a function based on the given either value

If `value` is left(T) then `f_left` is applied to its contents, if
`value` is right(U) then `f_right` is applied to its contents, and
the result is returned.
*/
fn either<T, U,
          V>(f_left: block(T) -> V, f_right: block(U) -> V, value: t<T, U>) ->
   V {
    alt value { left(l) { f_left(l) } right(r) { f_right(r) } }
}

/*
Function: lefts

Extracts from a vector of either all the left values.
*/
fn lefts<copy T, U>(eithers: [t<T, U>]) -> [T] {
    let result: [T] = [];
    for elt: t<T, U> in eithers {
        alt elt { left(l) { result += [l]; } _ {/* fallthrough */ } }
    }
    ret result;
}

/*
Function: rights

Extracts from a vector of either all the right values
*/
fn rights<T, copy U>(eithers: [t<T, U>]) -> [U] {
    let result: [U] = [];
    for elt: t<T, U> in eithers {
        alt elt { right(r) { result += [r]; } _ {/* fallthrough */ } }
    }
    ret result;
}

/*
Function: partition

Extracts from a vector of either all the left values and right values

Returns a structure containing a vector of left values and a vector of
right values.
*/
fn partition<copy T, copy U>(eithers: [t<T, U>])
    -> {lefts: [T], rights: [U]} {
    let lefts: [T] = [];
    let rights: [U] = [];
    for elt: t<T, U> in eithers {
        alt elt { left(l) { lefts += [l]; } right(r) { rights += [r]; } }
    }
    ret {lefts: lefts, rights: rights};
}

/*
Function: flip

Flips between left and right of a given either
*/
pure fn flip<copy T, copy U>(eith: t<T, U>) -> t<U, T> {
    alt eith {
      right(r) { left(r) }
      left(l) { right(l) }
    }
}

/*
Function: to_result

Converts either::t to a result::t, making the "right" choice
an ok result, and the "left" choice a fail
*/
pure fn to_result<copy T, copy U>(eith: t<T, U>) -> result::t<U, T> {
    alt eith {
      right(r) { result::ok(r) }
      left(l) { result::err(l) }
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Add either::is_left and either::is_right<commit_after>/*
Module: either

A type that represents one of two alternatives
*/

/*
Tag: t

The either type
*/
tag t<T, U> {
    /* Variant: left */
    left(T);
    /* Variant: right */
    right(U);
}

/* Section: Operations */

/*
Function: either

Applies a function based on the given either value

If `value` is left(T) then `f_left` is applied to its contents, if
`value` is right(U) then `f_right` is applied to its contents, and
the result is returned.
*/
fn either<T, U,
          V>(f_left: block(T) -> V, f_right: block(U) -> V, value: t<T, U>) ->
   V {
    alt value { left(l) { f_left(l) } right(r) { f_right(r) } }
}

/*
Function: lefts

Extracts from a vector of either all the left values.
*/
fn lefts<copy T, U>(eithers: [t<T, U>]) -> [T] {
    let result: [T] = [];
    for elt: t<T, U> in eithers {
        alt elt { left(l) { result += [l]; } _ {/* fallthrough */ } }
    }
    ret result;
}

/*
Function: rights

Extracts from a vector of either all the right values
*/
fn rights<T, copy U>(eithers: [t<T, U>]) -> [U] {
    let result: [U] = [];
    for elt: t<T, U> in eithers {
        alt elt { right(r) { result += [r]; } _ {/* fallthrough */ } }
    }
    ret result;
}

/*
Function: partition

Extracts from a vector of either all the left values and right values

Returns a structure containing a vector of left values and a vector of
right values.
*/
fn partition<copy T, copy U>(eithers: [t<T, U>])
    -> {lefts: [T], rights: [U]} {
    let lefts: [T] = [];
    let rights: [U] = [];
    for elt: t<T, U> in eithers {
        alt elt { left(l) { lefts += [l]; } right(r) { rights += [r]; } }
    }
    ret {lefts: lefts, rights: rights};
}

/*
Function: flip

Flips between left and right of a given either
*/
pure fn flip<copy T, copy U>(eith: t<T, U>) -> t<U, T> {
    alt eith {
      right(r) { left(r) }
      left(l) { right(l) }
    }
}

/*
Function: to_result

Converts either::t to a result::t, making the "right" choice
an ok result, and the "left" choice a fail
*/
pure fn to_result<copy T, copy U>(eith: t<T, U>) -> result::t<U, T> {
    alt eith {
      right(r) { result::ok(r) }
      left(l) { result::err(l) }
    }
}

/*
Function: is_left

Checks whether the given value is a left
*/
pure fn is_left<T, U>(eith: t<T, U>) -> bool {
    alt eith { left(_) { true } _ { false } }
}

/*
Function: is_left

Checks whether the given value is a right
*/
pure fn is_right<T, U>(eith: t<T, U>) -> bool {
    alt eith { right(_) { true } _ { false } }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>use super::{FnVal, InterpCx, Machine, MemoryKind};

use rustc::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
use rustc::ty::layout::{Align, HasDataLayout, LayoutOf, Size};
use rustc::ty::{self, Instance, Ty, TypeFoldable};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
    /// objects.
    ///
    /// The `trait_ref` encodes the erased self type. Hence, if we are
    /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
    /// `trait_ref` would map `T: Trait`.
    pub fn get_vtable(
        &mut self,
        ty: Ty<'tcx>,
        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
        trace!("get_vtable(trait_ref={:?})", poly_trait_ref);

        let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));

        // All vtables must be monomorphic, bail out otherwise.
        if ty.needs_subst() || poly_trait_ref.needs_subst() {
            throw_inval!(TooGeneric);
        }

        if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
            // This means we guarantee that there are no duplicate vtables, we will
            // always use the same vtable for the same (Type, Trait) combination.
            // That's not what happens in rustc, but emulating per-crate deduplication
            // does not sound like it actually makes anything any better.
            return Ok(vtable);
        }

        let methods = if let Some(poly_trait_ref) = poly_trait_ref {
            let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
            let trait_ref = self.tcx.erase_regions(&trait_ref);

            self.tcx.vtable_methods(trait_ref)
        } else {
            &[]
        };

        let layout = self.layout_of(ty)?;
        assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
        let size = layout.size.bytes();
        let align = layout.align.abi.bytes();

        let ptr_size = self.pointer_size();
        let ptr_align = self.tcx.data_layout.pointer_align.abi;
        // /////////////////////////////////////////////////////////////////////////////////////////
        // If you touch this code, be sure to also make the corresponding changes to
        // `get_vtable` in `rust_codegen_llvm/meth.rs`.
        // /////////////////////////////////////////////////////////////////////////////////////////
        let vtable = self.memory.allocate(
            ptr_size * (3 + methods.len() as u64),
            ptr_align,
            MemoryKind::Vtable,
        );
        let tcx = &*self.tcx;

        let drop = Instance::resolve_drop_in_place(*tcx, ty);
        let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));

        // No need to do any alignment checks on the memory accesses below, because we know the
        // allocation is correctly aligned as we created it above. Also we're only offsetting by
        // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
        let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?;
        vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?;

        let size_ptr = vtable.offset(ptr_size, tcx)?;
        vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?;
        let align_ptr = vtable.offset(ptr_size * 2, tcx)?;
        vtable_alloc.write_ptr_sized(tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?;

        for (i, method) in methods.iter().enumerate() {
            if let Some((def_id, substs)) = *method {
                // resolve for vtable: insert shims where needed
                let instance =
                    ty::Instance::resolve_for_vtable(*tcx, self.param_env, def_id, substs)
                        .ok_or_else(|| err_inval!(TooGeneric))?;
                let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                // We cannot use `vtable_allic` as we are creating fn ptrs in this loop.
                let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?;
                self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized(
                    tcx,
                    method_ptr,
                    fn_ptr.into(),
                )?;
            }
        }

        self.memory.mark_immutable(vtable.alloc_id)?;
        assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none());

        Ok(vtable)
    }

    /// Resolves the function at the specified slot in the provided
    /// vtable. An index of '0' corresponds to the first method
    /// declared in the trait of the provided vtable.
    pub fn get_vtable_slot(
        &self,
        vtable: Scalar<M::PointerTag>,
        idx: usize,
    ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
        let ptr_size = self.pointer_size();
        // Skip over the 'drop_ptr', 'size', and 'align' fields.
        let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?;
        let vtable_slot = self
            .memory
            .check_ptr_access(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
            .expect("cannot be a ZST");
        let fn_ptr = self
            .memory
            .get_raw(vtable_slot.alloc_id)?
            .read_ptr_sized(self, vtable_slot)?
            .not_undef()?;
        Ok(self.memory.get_fn(fn_ptr)?)
    }

    /// Returns the drop fn instance as well as the actual dynamic type.
    pub fn read_drop_type_from_vtable(
        &self,
        vtable: Scalar<M::PointerTag>,
    ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
        // We don't care about the pointee type; we just want a pointer.
        let vtable = self
            .memory
            .check_ptr_access(
                vtable,
                self.tcx.data_layout.pointer_size,
                self.tcx.data_layout.pointer_align.abi,
            )?
            .expect("cannot be a ZST");
        let drop_fn =
            self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.not_undef()?;
        // We *need* an instance here, no other kind of function value, to be able
        // to determine the type.
        let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
        trace!("Found drop fn: {:?}", drop_instance);
        let fn_sig = drop_instance.monomorphic_ty(*self.tcx).fn_sig(*self.tcx);
        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
        // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
        let args = fn_sig.inputs();
        if args.len() != 1 {
            throw_ub_format!("drop fn should have 1 argument, but signature is {:?}", fn_sig);
        }
        let ty = args[0]
            .builtin_deref(true)
            .ok_or_else(|| {
                err_ub_format!("drop fn argument type {} is not a pointer type", args[0])
            })?
            .ty;
        Ok((drop_instance, ty))
    }

    pub fn read_size_and_align_from_vtable(
        &self,
        vtable: Scalar<M::PointerTag>,
    ) -> InterpResult<'tcx, (Size, Align)> {
        let pointer_size = self.pointer_size();
        // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
        // the size, and the align (which we read below).
        let vtable = self
            .memory
            .check_ptr_access(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
            .expect("cannot be a ZST");
        let alloc = self.memory.get_raw(vtable.alloc_id)?;
        let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.not_undef()?;
        let size = self.force_bits(size, pointer_size)? as u64;
        let align =
            alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?;
        let align = self.force_bits(align, pointer_size)? as u64;

        if size >= self.tcx.data_layout().obj_size_bound() {
            throw_ub_format!(
                "invalid vtable: \
                size is bigger than largest supported object"
            );
        }
        Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
    }
}
<commit_msg>Use Instance.ty_env instead of Instance.monomorphic_ty in interpreter<commit_after>use super::{FnVal, InterpCx, Machine, MemoryKind};

use rustc::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
use rustc::ty::layout::{Align, HasDataLayout, LayoutOf, Size};
use rustc::ty::{self, Instance, Ty, TypeFoldable};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    /// Creates a dynamic vtable for the given type and vtable origin. This is used only for
    /// objects.
    ///
    /// The `trait_ref` encodes the erased self type. Hence, if we are
    /// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
    /// `trait_ref` would map `T: Trait`.
    pub fn get_vtable(
        &mut self,
        ty: Ty<'tcx>,
        poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
    ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
        trace!("get_vtable(trait_ref={:?})", poly_trait_ref);

        let (ty, poly_trait_ref) = self.tcx.erase_regions(&(ty, poly_trait_ref));

        // All vtables must be monomorphic, bail out otherwise.
        if ty.needs_subst() || poly_trait_ref.needs_subst() {
            throw_inval!(TooGeneric);
        }

        if let Some(&vtable) = self.vtables.get(&(ty, poly_trait_ref)) {
            // This means we guarantee that there are no duplicate vtables, we will
            // always use the same vtable for the same (Type, Trait) combination.
            // That's not what happens in rustc, but emulating per-crate deduplication
            // does not sound like it actually makes anything any better.
            return Ok(vtable);
        }

        let methods = if let Some(poly_trait_ref) = poly_trait_ref {
            let trait_ref = poly_trait_ref.with_self_ty(*self.tcx, ty);
            let trait_ref = self.tcx.erase_regions(&trait_ref);

            self.tcx.vtable_methods(trait_ref)
        } else {
            &[]
        };

        let layout = self.layout_of(ty)?;
        assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
        let size = layout.size.bytes();
        let align = layout.align.abi.bytes();

        let ptr_size = self.pointer_size();
        let ptr_align = self.tcx.data_layout.pointer_align.abi;
        // /////////////////////////////////////////////////////////////////////////////////////////
        // If you touch this code, be sure to also make the corresponding changes to
        // `get_vtable` in `rust_codegen_llvm/meth.rs`.
        // /////////////////////////////////////////////////////////////////////////////////////////
        let vtable = self.memory.allocate(
            ptr_size * (3 + methods.len() as u64),
            ptr_align,
            MemoryKind::Vtable,
        );
        let tcx = &*self.tcx;

        let drop = Instance::resolve_drop_in_place(*tcx, ty);
        let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));

        // No need to do any alignment checks on the memory accesses below, because we know the
        // allocation is correctly aligned as we created it above. Also we're only offsetting by
        // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
        let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?;
        vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?;

        let size_ptr = vtable.offset(ptr_size, tcx)?;
        vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?;
        let align_ptr = vtable.offset(ptr_size * 2, tcx)?;
        vtable_alloc.write_ptr_sized(tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?;

        for (i, method) in methods.iter().enumerate() {
            if let Some((def_id, substs)) = *method {
                // resolve for vtable: insert shims where needed
                let instance =
                    ty::Instance::resolve_for_vtable(*tcx, self.param_env, def_id, substs)
                        .ok_or_else(|| err_inval!(TooGeneric))?;
                let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                // We cannot use `vtable_allic` as we are creating fn ptrs in this loop.
                let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?;
                self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized(
                    tcx,
                    method_ptr,
                    fn_ptr.into(),
                )?;
            }
        }

        self.memory.mark_immutable(vtable.alloc_id)?;
        assert!(self.vtables.insert((ty, poly_trait_ref), vtable).is_none());

        Ok(vtable)
    }

    /// Resolves the function at the specified slot in the provided
    /// vtable. An index of '0' corresponds to the first method
    /// declared in the trait of the provided vtable.
    pub fn get_vtable_slot(
        &self,
        vtable: Scalar<M::PointerTag>,
        idx: usize,
    ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
        let ptr_size = self.pointer_size();
        // Skip over the 'drop_ptr', 'size', and 'align' fields.
        let vtable_slot = vtable.ptr_offset(ptr_size * (idx as u64 + 3), self)?;
        let vtable_slot = self
            .memory
            .check_ptr_access(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)?
            .expect("cannot be a ZST");
        let fn_ptr = self
            .memory
            .get_raw(vtable_slot.alloc_id)?
            .read_ptr_sized(self, vtable_slot)?
            .not_undef()?;
        Ok(self.memory.get_fn(fn_ptr)?)
    }

    /// Returns the drop fn instance as well as the actual dynamic type.
    pub fn read_drop_type_from_vtable(
        &self,
        vtable: Scalar<M::PointerTag>,
    ) -> InterpResult<'tcx, (ty::Instance<'tcx>, Ty<'tcx>)> {
        // We don't care about the pointee type; we just want a pointer.
        let vtable = self
            .memory
            .check_ptr_access(
                vtable,
                self.tcx.data_layout.pointer_size,
                self.tcx.data_layout.pointer_align.abi,
            )?
            .expect("cannot be a ZST");
        let drop_fn =
            self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.not_undef()?;
        // We *need* an instance here, no other kind of function value, to be able
        // to determine the type.
        let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
        trace!("Found drop fn: {:?}", drop_instance);
        let fn_sig = drop_instance.ty_env(*self.tcx, self.param_env).fn_sig(*self.tcx);
        let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
        // The drop function takes `*mut T` where `T` is the type being dropped, so get that.
        let args = fn_sig.inputs();
        if args.len() != 1 {
            throw_ub_format!("drop fn should have 1 argument, but signature is {:?}", fn_sig);
        }
        let ty = args[0]
            .builtin_deref(true)
            .ok_or_else(|| {
                err_ub_format!("drop fn argument type {} is not a pointer type", args[0])
            })?
            .ty;
        Ok((drop_instance, ty))
    }

    pub fn read_size_and_align_from_vtable(
        &self,
        vtable: Scalar<M::PointerTag>,
    ) -> InterpResult<'tcx, (Size, Align)> {
        let pointer_size = self.pointer_size();
        // We check for `size = 3 * ptr_size`, which covers the drop fn (unused here),
        // the size, and the align (which we read below).
        let vtable = self
            .memory
            .check_ptr_access(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
            .expect("cannot be a ZST");
        let alloc = self.memory.get_raw(vtable.alloc_id)?;
        let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.not_undef()?;
        let size = self.force_bits(size, pointer_size)? as u64;
        let align =
            alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?;
        let align = self.force_bits(align, pointer_size)? as u64;

        if size >= self.tcx.data_layout().obj_size_bound() {
            throw_ub_format!(
                "invalid vtable: \
                size is bigger than largest supported object"
            );
        }
        Ok((Size::from_bytes(size), Align::from_bytes(align).unwrap()))
    }
}
<|endoftext|>


<commit_before>use redox::Box;
use redox::fs::file::File;
use redox::io::{Read, Write, SeekFrom};
use redox::mem;
use redox::net::*;
use redox::ptr;
use redox::rand;
use redox::slice;
use redox::{String, ToString};
use redox::to_num::*;
use redox::Vec;
use redox::URL;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct UDPHeader {
    pub src: n16,
    pub dst: n16,
    pub len: n16,
    pub checksum: Checksum,
}

pub struct UDP {
    pub header: UDPHeader,
    pub data: Vec<u8>,
}

impl FromBytes for UDP {
    fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() >= mem::size_of::<UDPHeader>() {
            unsafe {
                return Option::Some(UDP {
                    header: ptr::read(bytes.as_ptr() as *const UDPHeader),
                    data: bytes[mem::size_of::<UDPHeader>().. bytes.len()].to_vec(),
                });
            }
        }
        Option::None
    }
}

impl ToBytes for UDP {
    fn to_bytes(&self) -> Vec<u8> {
        unsafe {
            let header_ptr: *const UDPHeader = &self.header;
            let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8, mem::size_of::<UDPHeader>()));
            ret.push_all(&self.data);
            ret
        }
    }
}

/// UDP resource
pub struct Resource {
    ip: File,
    data: Vec<u8>,
    peer_addr: IPv4Addr,
    peer_port: u16,
    host_port: u16,
}

impl Resource {
    pub fn dup(&self) -> Option<Box<Self>> {
        match self.ip.dup() {
            Some(ip) => Some(box Resource {
                ip: ip,
                data: self.data.clone(),
                peer_addr: self.peer_addr,
                peer_port: self.peer_port,
                host_port: self.host_port,
            }),
            None => None
        }
    }

    pub fn path(&self) -> Option<String> {
        Some(format!("udp://{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port))
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        if self.data.len() > 0 {
            let mut bytes: Vec<u8> = Vec::new();
            mem::swap(&mut self.data, &mut bytes);

            //TODO: Allow splitting
            let i = 0;
            while i < buf.len() && i < bytes.len() {
                 buf[i] = bytes[i];
            }
            return Some(i);
        }

        loop {
            let mut bytes: Vec<u8> = Vec::new();
            match self.ip.read_to_end(&mut bytes) {
                Some(_) => {
                    if let Some(datagram) = UDP::from_bytes(bytes) {
                        if datagram.header.dst.get() == self.host_port &&
                           datagram.header.src.get() == self.peer_port {
                            //TODO: Allow splitting
                            let i = 0;
                            while i < buf.len() && i < datagram.data.len() {
                                buf[i] = datagram.data[i];
                            }
                            return Some(i);
                        }
                    }
                }
                None => break,
            }
        }

        None
    }

    pub fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let udp_data = Vec::from(buf);

        let mut udp = UDP {
            header: UDPHeader {
                src: n16::new(self.host_port),
                dst: n16::new(self.peer_port),
                len: n16::new((mem::size_of::<UDPHeader>() + udp_data.len()) as u16),
                checksum: Checksum { data: 0 },
            },
            data: udp_data,
        };

        unsafe {
            let proto = n16::new(0x11);
            let datagram_len = n16::new((mem::size_of::<UDPHeader>() + udp.data.len()) as u16);
            udp.header.checksum.data =
                Checksum::compile(Checksum::sum((&IP_ADDR as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&self.peer_addr as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&proto as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&datagram_len as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&udp.header as *const UDPHeader) as usize,
                                                mem::size_of::<UDPHeader>()) +
                                  Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
        }

        match self.ip.write(udp.to_bytes().as_slice()) {
            Some(_) => return Some(buf.len()),
            None => return None,
        }
    }

    pub fn seek(&mut self, pos: SeekFrom) -> Option<usize> {
        None
    }

    pub fn sync(&mut self) -> bool {
        self.ip.sync()
    }
}

/// UDP scheme
pub struct Scheme;

impl Scheme {
    pub fn new() -> Box<Self> {
        box Scheme
    }

    pub fn open(&mut self, url_str: &str) -> Option<Box<Resource>> {
        let url = URL::from_str(&url_str);

        //Check host and port vs path
        if url.path().len() > 0 {
            let host_port = url.port().to_num();
            if host_port > 0 && host_port < 65536 {
                if let Some(mut ip) = File::open("ip:///11") {
                    let mut bytes: Vec<u8> = Vec::new();
                    if ip.read_to_end(&mut bytes).is_some() {
                        if let Some(datagram) = UDP::from_bytes(bytes) {
                            if datagram.header.dst.get() as usize == host_port {
                                let url_bytes = [0; 4096];
                                if let Some(path) = ip.path() {
                                    let url = URL::from_string(&path);

                                    return Some(box Resource {
                                        ip: ip,
                                        data: datagram.data,
                                        peer_addr: IPv4Addr::from_string(&url.host()),
                                        peer_port: datagram.header.src.get(),
                                        host_port: host_port as u16,
                                    });
                                }
                            }
                        }
                    }
                }
            }
        } else {
            let peer_port = url.port().to_num();
            if peer_port > 0 && peer_port < 65536 {
                let host_port = (rand() % 32768 + 32768) as u16;

                if let Some(ip) = File::open(&format!("ip://{}/11", url.host())) {
                    return Some(box Resource {
                        ip: ip,
                        data: Vec::new(),
                        peer_addr: IPv4Addr::from_string(&url.host()),
                        peer_port: peer_port as u16,
                        host_port: host_port,
                    });
                }
            }
        }

        None
    }
}
<commit_msg>Code cleanup: round 3<commit_after>use redox::Box;
use redox::fs::file::File;
use redox::io::{Read, Write, SeekFrom};
use redox::mem;
use redox::net::*;
use redox::ptr;
use redox::rand;
use redox::slice;
use redox::{String, ToString};
use redox::to_num::*;
use redox::Vec;
use redox::URL;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct UDPHeader {
    pub src: n16,
    pub dst: n16,
    pub len: n16,
    pub checksum: Checksum,
}

pub struct UDP {
    pub header: UDPHeader,
    pub data: Vec<u8>,
}

impl FromBytes for UDP {
    fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
        if bytes.len() >= mem::size_of::<UDPHeader>() {
            unsafe {
                return Option::Some(UDP {
                    header: ptr::read(bytes.as_ptr() as *const UDPHeader),
                    data: bytes[mem::size_of::<UDPHeader>().. bytes.len()].to_vec(),
                });
            }
        }
        Option::None
    }
}

impl ToBytes for UDP {
    fn to_bytes(&self) -> Vec<u8> {
        unsafe {
            let header_ptr: *const UDPHeader = &self.header;
            let mut ret = Vec::from(slice::from_raw_parts(header_ptr as *const u8, mem::size_of::<UDPHeader>()));
            ret.push_all(&self.data);
            ret
        }
    }
}

/// UDP resource
pub struct Resource {
    ip: File,
    data: Vec<u8>,
    peer_addr: IPv4Addr,
    peer_port: u16,
    host_port: u16,
}

impl Resource {
    pub fn dup(&self) -> Option<Box<Self>> {
        match self.ip.dup() {
            Some(ip) => Some(box Resource {
                ip: ip,
                data: self.data.clone(),
                peer_addr: self.peer_addr,
                peer_port: self.peer_port,
                host_port: self.host_port,
            }),
            None => None
        }
    }

    pub fn path(&self) -> Option<String> {
        Some(format!("udp://{}:{}/{}", self.peer_addr.to_string(), self.peer_port, self.host_port))
    }

    pub fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        if self.data.len() > 0 {
            let mut bytes: Vec<u8> = Vec::new();
            mem::swap(&mut self.data, &mut bytes);

            //TODO: Allow splitting
            let i = 0;
            while i < buf.len() && i < bytes.len() {
                 buf[i] = bytes[i];
            }
            return Some(i);
        }

        loop {
            let mut bytes: Vec<u8> = Vec::new();
            match self.ip.read_to_end(&mut bytes) {
                Some(_) => {
                    if let Some(datagram) = UDP::from_bytes(bytes) {
                        if datagram.header.dst.get() == self.host_port &&
                           datagram.header.src.get() == self.peer_port {
                            //TODO: Allow splitting
                            let i = 0;
                            while i < buf.len() && i < datagram.data.len() {
                                buf[i] = datagram.data[i];
                            }
                            return Some(i);
                        }
                    }
                }
                None => break,
            }
        }

        None
    }

    pub fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let udp_data = Vec::from(buf);

        let mut udp = UDP {
            header: UDPHeader {
                src: n16::new(self.host_port),
                dst: n16::new(self.peer_port),
                len: n16::new((mem::size_of::<UDPHeader>() + udp_data.len()) as u16),
                checksum: Checksum { data: 0 },
            },
            data: udp_data,
        };

        unsafe {
            let proto = n16::new(0x11);
            let datagram_len = n16::new((mem::size_of::<UDPHeader>() + udp.data.len()) as u16);
            udp.header.checksum.data =
                Checksum::compile(Checksum::sum((&IP_ADDR as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&self.peer_addr as *const IPv4Addr) as usize,
                                                mem::size_of::<IPv4Addr>()) +
                                  Checksum::sum((&proto as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&datagram_len as *const n16) as usize,
                                                mem::size_of::<n16>()) +
                                  Checksum::sum((&udp.header as *const UDPHeader) as usize,
                                                mem::size_of::<UDPHeader>()) +
                                  Checksum::sum(udp.data.as_ptr() as usize, udp.data.len()));
        }

        match self.ip.write(udp.to_bytes().as_slice()) {
            Some(_) => return Some(buf.len()),
            None => return None,
        }
    }

    pub fn seek(&mut self, pos: SeekFrom) -> Option<usize> {
        None
    }

    pub fn sync(&mut self) -> bool {
        self.ip.sync()
    }
}

/// UDP scheme
pub struct Scheme;

impl Scheme {
    pub fn new() -> Box<Self> {
        box Scheme
    }

    pub fn open(&mut self, url_str: &str) -> Option<Box<Resource>> {
        let url = URL::from_str(&url_str);

        //Check host and port vs path
        if url.path().len() > 0 {
            let host_port = url.port().to_num();
            if host_port > 0 && host_port < 65536 {
                if let Some(mut ip) = File::open("ip:///11") {
                    let mut bytes: Vec<u8> = Vec::new();
                    if ip.read_to_end(&mut bytes).is_some() {
                        if let Some(datagram) = UDP::from_bytes(bytes) {
                            if datagram.header.dst.get() as usize == host_port {
                                if let Some(path) = ip.path() {
                                    let url = URL::from_string(&path);

                                    return Some(box Resource {
                                        ip: ip,
                                        data: datagram.data,
                                        peer_addr: IPv4Addr::from_string(&url.host()),
                                        peer_port: datagram.header.src.get(),
                                        host_port: host_port as u16,
                                    });
                                }
                            }
                        }
                    }
                }
            }
        } else {
            let peer_port = url.port().to_num();
            if peer_port > 0 && peer_port < 65536 {
                let host_port = (rand() % 32768 + 32768) as u16;

                if let Some(ip) = File::open(&format!("ip://{}/11", url.host())) {
                    return Some(box Resource {
                        ip: ip,
                        data: Vec::new(),
                        peer_addr: IPv4Addr::from_string(&url.host()),
                        peer_port: peer_port as u16,
                        host_port: host_port,
                    });
                }
            }
        }

        None
    }
}
<|endoftext|>