<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.

// no-pretty-expanded unnecessary unsafe block generated

#![deny(warnings)]
#![allow(unused_must_use)]
#![allow(unused_features)]
#![feature(box_syntax)]
#![feature(question_mark)]

use std::fmt::{self, Write};
use std::usize;

struct A;
struct B;
struct C;
struct D;

impl fmt::LowerHex for A {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("aloha")
    }
}
impl fmt::UpperHex for B {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("adios")
    }
}
impl fmt::Display for C {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad_integral(true, "☃", "123")
    }
}
impl fmt::Binary for D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("aa")?;
        f.write_char('☃')?;
        f.write_str("bb")
    }
}

macro_rules! t {
    ($a:expr, $b:expr) => { assert_eq!($a, $b) }
}

pub fn main() {
    // Various edge cases without formats
    t!(format!(""), "");
    t!(format!("hello"), "hello");
    t!(format!("hello {{"), "hello {");

    // default formatters should work
    t!(format!("{}", 1.0f32), "1");
    t!(format!("{}", 1.0f64), "1");
    t!(format!("{}", "a"), "a");
    t!(format!("{}", "a".to_string()), "a");
    t!(format!("{}", false), "false");
    t!(format!("{}", 'a'), "a");

    // At least exercise all the formats
    t!(format!("{}", true), "true");
    t!(format!("{}", '☃'), "☃");
    t!(format!("{}", 10), "10");
    t!(format!("{}", 10_usize), "10");
    t!(format!("{:?}", '☃'), "'\\u{2603}'");
    t!(format!("{:?}", 10), "10");
    t!(format!("{:?}", 10_usize), "10");
    t!(format!("{:?}", "true"), "\"true\"");
    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
    t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
       r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
    t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"),
       r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#);
    t!(format!("{:o}", 10_usize), "12");
    t!(format!("{:x}", 10_usize), "a");
    t!(format!("{:X}", 10_usize), "A");
    t!(format!("{}", "foo"), "foo");
    t!(format!("{}", "foo".to_string()), "foo");
    if cfg!(target_pointer_width = "32") {
        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
    } else {
        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
    }
    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
    t!(format!("{:x}", A), "aloha");
    t!(format!("{:X}", B), "adios");
    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
    t!(format!("{1} {0}", 0, 1), "1 0");
    t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
    t!(format!("{} {0}", "a"), "a a");
    t!(format!("{foo_bar}", foo_bar=1), "1");
    t!(format!("{}", 5 + 5), "10");
    t!(format!("{:#4}", C), "☃123");
    t!(format!("{:b}", D), "aa☃bb");

    let a: &fmt::Debug = &1;
    t!(format!("{:?}", a), "1");

    // Formatting strings and their arguments
    t!(format!("{}", "a"), "a");
    t!(format!("{:4}", "a"), "a   ");
    t!(format!("{:4}", "☃"), "☃   ");
    t!(format!("{:>4}", "a"), "   a");
    t!(format!("{:<4}", "a"), "a   ");
    t!(format!("{:^5}", "a"),  "  a  ");
    t!(format!("{:^5}", "aa"), " aa  ");
    t!(format!("{:^4}", "a"),  " a  ");
    t!(format!("{:^4}", "aa"), " aa ");
    t!(format!("{:.4}", "a"), "a");
    t!(format!("{:4.4}", "a"), "a   ");
    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:2.4}", "aaaaa"), "aaaa");
    t!(format!("{:2.4}", "aaaa"), "aaaa");
    t!(format!("{:2.4}", "aaa"), "aaa");
    t!(format!("{:2.4}", "aa"), "aa");
    t!(format!("{:2.4}", "a"), "a ");
    t!(format!("{:0>2}", "a"), "0a");
    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa");
    t!(format!("{:1$}", "a", 4), "a   ");
    t!(format!("{1:0$}", 4, "a"), "a   ");
    t!(format!("{:a$}", "a", a=4), "a   ");
    t!(format!("{:-#}", "a"), "a");
    t!(format!("{:+#}", "a"), "a");

    // Some float stuff
    t!(format!("{:}", 1.0f32), "1");
    t!(format!("{:}", 1.0f64), "1");
    t!(format!("{:.3}", 1.0f64), "1.000");
    t!(format!("{:10.3}", 1.0f64),   "     1.000");
    t!(format!("{:+10.3}", 1.0f64),  "    +1.000");
    t!(format!("{:+10.3}", -1.0f64), "    -1.000");

    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
    t!(format!("{:10.3e}", 1.2345e6f64),   "   1.234e6");
    t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");

    // Float edge cases
    t!(format!("{}", -0.0), "0");
    t!(format!("{:?}", -0.0), "-0");
    t!(format!("{:?}", 0.0), "0");

    // Test that pointers don't get truncated.
    {
        let val = usize::MAX;
        let exp = format!("{:#x}", val);
        t!(format!("{:p}", val as *const isize), exp);
    }

    // Escaping
    t!(format!("{{"), "{");
    t!(format!("}}"), "}");

    test_write();
    test_print();
    test_order();

    // make sure that format! doesn't move out of local variables
    let a: Box<_> = box 3;
    format!("{}", a);
    format!("{}", a);

    // make sure that format! doesn't cause spurious unused-unsafe warnings when
    // it's inside of an outer unsafe block
    unsafe {
        let a: isize = ::std::mem::transmute(3_usize);
        format!("{}", a);
    }

    test_format_args();

    // test that trailing commas are acceptable
    format!("{}", "test",);
    format!("{foo}", foo="test",);
}

// Basic test to make sure that we can invoke the `write!` macro with an
// fmt::Write instance.
fn test_write() {
    use std::fmt::Write;
    let mut buf = String::new();
    write!(&mut buf, "{}", 3);
    {
        let w = &mut buf;
        write!(w, "{foo}", foo=4);
        write!(w, "{}", "hello");
        writeln!(w, "{}", "line");
        writeln!(w, "{foo}", foo="bar");
        w.write_char('☃');
        w.write_str("str");
    }

    t!(buf, "34helloline\nbar\n☃str");
}

// Just make sure that the macros are defined, there's not really a lot that we
// can do with them just yet (to test the output)
fn test_print() {
    print!("hi");
    print!("{:?}", vec!(0u8));
    println!("hello");
    println!("this is a {}", "test");
    println!("{foo}", foo="bar");
}

// Just make sure that the macros are defined, there's not really a lot that we
// can do with them just yet (to test the output)
fn test_format_args() {
    use std::fmt::Write;
    let mut buf = String::new();
    {
        let w = &mut buf;
        write!(w, "{}", format_args!("{}", 1));
        write!(w, "{}", format_args!("test"));
        write!(w, "{}", format_args!("{test}", test=3));
    }
    let s = buf;
    t!(s, "1test3");

    let s = fmt::format(format_args!("hello {}", "world"));
    t!(s, "hello world");
    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
    t!(s, "args were: hello world");
}

fn test_order() {
    // Make sure format!() arguments are always evaluated in a left-to-right
    // ordering
    fn foo() -> isize {
        static mut FOO: isize = 0;
        unsafe {
            FOO += 1;
            FOO
        }
    }
    assert_eq!(format!("{} {} {a} {b} {} {c}",
                       foo(), foo(), foo(), a=foo(), b=foo(), c=foo()),
               "1 2 4 5 3 6".to_string());
}
<commit_msg>format: add tests for ergonomic format_args!<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.

// no-pretty-expanded unnecessary unsafe block generated

#![deny(warnings)]
#![allow(unused_must_use)]
#![allow(unused_features)]
#![feature(box_syntax)]
#![feature(question_mark)]

use std::fmt::{self, Write};
use std::usize;

struct A;
struct B;
struct C;
struct D;

impl fmt::LowerHex for A {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("aloha")
    }
}
impl fmt::UpperHex for B {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("adios")
    }
}
impl fmt::Display for C {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad_integral(true, "☃", "123")
    }
}
impl fmt::Binary for D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("aa")?;
        f.write_char('☃')?;
        f.write_str("bb")
    }
}

macro_rules! t {
    ($a:expr, $b:expr) => { assert_eq!($a, $b) }
}

pub fn main() {
    // Various edge cases without formats
    t!(format!(""), "");
    t!(format!("hello"), "hello");
    t!(format!("hello {{"), "hello {");

    // default formatters should work
    t!(format!("{}", 1.0f32), "1");
    t!(format!("{}", 1.0f64), "1");
    t!(format!("{}", "a"), "a");
    t!(format!("{}", "a".to_string()), "a");
    t!(format!("{}", false), "false");
    t!(format!("{}", 'a'), "a");

    // At least exercise all the formats
    t!(format!("{}", true), "true");
    t!(format!("{}", '☃'), "☃");
    t!(format!("{}", 10), "10");
    t!(format!("{}", 10_usize), "10");
    t!(format!("{:?}", '☃'), "'\\u{2603}'");
    t!(format!("{:?}", 10), "10");
    t!(format!("{:?}", 10_usize), "10");
    t!(format!("{:?}", "true"), "\"true\"");
    t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
    t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
       r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
    t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"),
       r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#);
    t!(format!("{:o}", 10_usize), "12");
    t!(format!("{:x}", 10_usize), "a");
    t!(format!("{:X}", 10_usize), "A");
    t!(format!("{}", "foo"), "foo");
    t!(format!("{}", "foo".to_string()), "foo");
    if cfg!(target_pointer_width = "32") {
        t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234");
        t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234");
    } else {
        t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234");
        t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234");
    }
    t!(format!("{:p}", 0x1234 as *const isize), "0x1234");
    t!(format!("{:p}", 0x1234 as *mut isize), "0x1234");
    t!(format!("{:x}", A), "aloha");
    t!(format!("{:X}", B), "adios");
    t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃");
    t!(format!("{1} {0}", 0, 1), "1 0");
    t!(format!("{foo} {bar}", foo=0, bar=1), "0 1");
    t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0");
    t!(format!("{} {0}", "a"), "a a");
    t!(format!("{foo_bar}", foo_bar=1), "1");
    t!(format!("{}", 5 + 5), "10");
    t!(format!("{:#4}", C), "☃123");
    t!(format!("{:b}", D), "aa☃bb");

    let a: &fmt::Debug = &1;
    t!(format!("{:?}", a), "1");

    // Formatting strings and their arguments
    t!(format!("{}", "a"), "a");
    t!(format!("{:4}", "a"), "a   ");
    t!(format!("{:4}", "☃"), "☃   ");
    t!(format!("{:>4}", "a"), "   a");
    t!(format!("{:<4}", "a"), "a   ");
    t!(format!("{:^5}", "a"),  "  a  ");
    t!(format!("{:^5}", "aa"), " aa  ");
    t!(format!("{:^4}", "a"),  " a  ");
    t!(format!("{:^4}", "aa"), " aa ");
    t!(format!("{:.4}", "a"), "a");
    t!(format!("{:4.4}", "a"), "a   ");
    t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:2.4}", "aaaaa"), "aaaa");
    t!(format!("{:2.4}", "aaaa"), "aaaa");
    t!(format!("{:2.4}", "aaa"), "aaa");
    t!(format!("{:2.4}", "aa"), "aa");
    t!(format!("{:2.4}", "a"), "a ");
    t!(format!("{:0>2}", "a"), "0a");
    t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa");
    t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa");
    t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa");
    t!(format!("{:1$}", "a", 4), "a   ");
    t!(format!("{1:0$}", 4, "a"), "a   ");
    t!(format!("{:a$}", "a", a=4), "a   ");
    t!(format!("{:-#}", "a"), "a");
    t!(format!("{:+#}", "a"), "a");

    // Some float stuff
    t!(format!("{:}", 1.0f32), "1");
    t!(format!("{:}", 1.0f64), "1");
    t!(format!("{:.3}", 1.0f64), "1.000");
    t!(format!("{:10.3}", 1.0f64),   "     1.000");
    t!(format!("{:+10.3}", 1.0f64),  "    +1.000");
    t!(format!("{:+10.3}", -1.0f64), "    -1.000");

    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
    t!(format!("{:10.3e}", 1.2345e6f64),   "   1.234e6");
    t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");

    // Float edge cases
    t!(format!("{}", -0.0), "0");
    t!(format!("{:?}", -0.0), "-0");
    t!(format!("{:?}", 0.0), "0");

    // Ergonomic format_args!
    t!(format!("{0:x} {0:X}", 15), "f F");
    t!(format!("{0:x} {0:X} {}", 15), "f F 15");
    // NOTE: For now the longer test cases must not be followed immediately by
    // >1 empty lines, or the pretty printer will break. Since no one wants to
    // touch the current pretty printer (#751), we have no choice but to work
    // around it. Some of the following test cases are also affected.
    t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a=15), "dDfEeF");
    t!(format!("{a:x} {a:X}", a=15), "f F");

    // And its edge cases
    t!(format!("{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}",
               4, a="abcdefg", b="hijklmn", c=3),
               "abcd hijk 4\nabc hij 3");
    t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a="abcdef"), "abcd 4 efg");
    t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a=2), "aa 2 0x2");

    // Test that pointers don't get truncated.
    {
        let val = usize::MAX;
        let exp = format!("{:#x}", val);
        t!(format!("{:p}", val as *const isize), exp);
    }

    // Escaping
    t!(format!("{{"), "{");
    t!(format!("}}"), "}");

    test_write();
    test_print();
    test_order();
    test_once();

    // make sure that format! doesn't move out of local variables
    let a: Box<_> = box 3;
    format!("{}", a);
    format!("{}", a);

    // make sure that format! doesn't cause spurious unused-unsafe warnings when
    // it's inside of an outer unsafe block
    unsafe {
        let a: isize = ::std::mem::transmute(3_usize);
        format!("{}", a);
    }

    test_format_args();

    // test that trailing commas are acceptable
    format!("{}", "test",);
    format!("{foo}", foo="test",);
}

// Basic test to make sure that we can invoke the `write!` macro with an
// fmt::Write instance.
fn test_write() {
    use std::fmt::Write;
    let mut buf = String::new();
    write!(&mut buf, "{}", 3);
    {
        let w = &mut buf;
        write!(w, "{foo}", foo=4);
        write!(w, "{}", "hello");
        writeln!(w, "{}", "line");
        writeln!(w, "{foo}", foo="bar");
        w.write_char('☃');
        w.write_str("str");
    }

    t!(buf, "34helloline\nbar\n☃str");
}

// Just make sure that the macros are defined, there's not really a lot that we
// can do with them just yet (to test the output)
fn test_print() {
    print!("hi");
    print!("{:?}", vec!(0u8));
    println!("hello");
    println!("this is a {}", "test");
    println!("{foo}", foo="bar");
}

// Just make sure that the macros are defined, there's not really a lot that we
// can do with them just yet (to test the output)
fn test_format_args() {
    use std::fmt::Write;
    let mut buf = String::new();
    {
        let w = &mut buf;
        write!(w, "{}", format_args!("{}", 1));
        write!(w, "{}", format_args!("test"));
        write!(w, "{}", format_args!("{test}", test=3));
    }
    let s = buf;
    t!(s, "1test3");

    let s = fmt::format(format_args!("hello {}", "world"));
    t!(s, "hello world");
    let s = format!("{}: {}", "args were", format_args!("hello {}", "world"));
    t!(s, "args were: hello world");
}

fn test_order() {
    // Make sure format!() arguments are always evaluated in a left-to-right
    // ordering
    fn foo() -> isize {
        static mut FOO: isize = 0;
        unsafe {
            FOO += 1;
            FOO
        }
    }
    assert_eq!(format!("{} {} {a} {b} {} {c}",
                       foo(), foo(), foo(), a=foo(), b=foo(), c=foo()),
               "1 2 4 5 3 6".to_string());
}

fn test_once() {
    // Make sure each argument are evaluted only once even though it may be
    // formatted multiple times
    fn foo() -> isize {
        static mut FOO: isize = 0;
        unsafe {
            FOO += 1;
            FOO
        }
    }
    assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a=foo()),
               "1 1 1 2 2 2".to_string());
}
<|endoftext|>


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

//! Library used by tidy and other tools
//!
//! This library contains the tidy lints and exposes it
//! to be used by tools.

#![deny(warnings)]

use std::fs;

use std::path::Path;

macro_rules! t {
    ($e:expr, $p:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
    });

    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        *$bad = true;
        eprint!("tidy error: ");
        eprintln!($fmt, $($arg)*);
    });
}

pub mod bins;
pub mod style;
pub mod errors;
pub mod features;
pub mod cargo;
pub mod pal;
pub mod deps;
pub mod unstable_book;

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "src/binaryen",
        "src/dlmalloc",
        "src/jemalloc",
        "src/llvm",
        "src/libbacktrace",
        "src/libcompiler_builtins",
        "src/librustc_data_structures/owning_ref",
        "src/compiler-rt",
        "src/liblibc",
        "src/vendor",
        "src/rt/hoedown",
        "src/tools/cargo",
        "src/tools/rls",
        "src/tools/clippy",
        "src/tools/rust-installer",
        "src/tools/rustfmt",
        "src/tools/miri",
        "src/librustc/mir/interpret",
        "src/librustc_mir/interpret",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for entry in t!(fs::read_dir(path), path) {
        let entry = t!(entry);
        let kind = t!(entry.file_type());
        let path = entry.path();
        if kind.is_dir() {
            if !skip(&path) {
                walk(&path, skip, f);
            }
        } else {
            f(&path);
        }
    }
}
<commit_msg>add target/ to ignored tidy dirs<commit_after>// Copyright 2017 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.

//! Library used by tidy and other tools
//!
//! This library contains the tidy lints and exposes it
//! to be used by tools.

#![deny(warnings)]

use std::fs;

use std::path::Path;

macro_rules! t {
    ($e:expr, $p:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
    });

    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        *$bad = true;
        eprint!("tidy error: ");
        eprintln!($fmt, $($arg)*);
    });
}

pub mod bins;
pub mod style;
pub mod errors;
pub mod features;
pub mod cargo;
pub mod pal;
pub mod deps;
pub mod unstable_book;

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "src/binaryen",
        "src/dlmalloc",
        "src/jemalloc",
        "src/llvm",
        "src/libbacktrace",
        "src/libcompiler_builtins",
        "src/librustc_data_structures/owning_ref",
        "src/compiler-rt",
        "src/liblibc",
        "src/vendor",
        "src/rt/hoedown",
        "src/tools/cargo",
        "src/tools/rls",
        "src/tools/clippy",
        "src/tools/rust-installer",
        "src/tools/rustfmt",
        "src/tools/miri",
        "src/librustc/mir/interpret",
        "src/librustc_mir/interpret",
        "src/target",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for entry in t!(fs::read_dir(path), path) {
        let entry = t!(entry);
        let kind = t!(entry.file_type());
        let path = entry.path();
        if kind.is_dir() {
            if !skip(&path) {
                walk(&path, skip, f);
            }
        } else {
            f(&path);
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>vnc is connecting properly<commit_after><|endoftext|>


<commit_before><commit_msg>Add regression test for SimplifyBranchSame miscompilation<commit_after>// Regression test for SimplifyBranchSame miscompilation.
// run-pass

macro_rules! m {
    ($a:expr, $b:expr, $c:block) => {
        match $a {
            Lto::Fat | Lto::Thin => { $b; (); $c }
            Lto::No => { $b; () }
        }
    }
}

pub enum Lto { No, Thin, Fat }

fn f(mut cookie: u32, lto: Lto) -> u32 {
    let mut _a = false;
    m!(lto, _a = true, {cookie = 0});
    cookie
}

fn main() { assert_eq!(f(42, Lto::Thin), 0) }
<|endoftext|>


<commit_before><commit_msg>Finished basic implementation<commit_after><|endoftext|>


<commit_before><commit_msg>Add library with bisect function<commit_after>use std::ops::Range;

pub trait RangeExt {
    fn is_empty(&self) -> bool;
    fn is_singleton(&self) -> bool;
}

impl RangeExt for Range<i32> {
    #[inline]
    fn is_empty(&self) -> bool {
        self.start >= self.end
    }
    #[inline]
    fn is_singleton(&self) -> bool {
        self.start + 1 == self.end
    }
}

/// Finds least item in `r` for which the `predicate` holds.
pub fn bisect<P>(mut r: Range<i32>, mut predicate: P) -> Option<i32> where
       P: FnMut(i32) -> bool
{
    if r.is_empty() {
        return None;
    }

    loop {
       if r.is_empty() {
           return match predicate(r.end) {
               true => Some(r.end),
               false => None,
           }
       }
       if r.is_singleton() {
           return if predicate(r.start) {
               Some(r.start)
           } else {
               None
           }
       }
       let mid = r.start + (r.end - r.start) / 2;
       if predicate(mid) {
           r = Range { start: r.start, end: mid };
       } else {
           r = Range { start: mid + 1, end: r.end };
       }
   }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_bisect() {
        assert_eq!(None, bisect(0..0, |x| x >= 0));
        assert_eq!(Some(50), bisect(0..100, |x| x >= 50 ));
        assert_eq!(None, bisect(0..100, |x| x >= 1000));
    }
}
<|endoftext|>


<commit_before><commit_msg>Add `core` feature<commit_after><|endoftext|>


<commit_before><commit_msg>Add test::to_code_reserved test.<commit_after><|endoftext|>


<commit_before>#![feature(macro_rules)]

pub struct Slide<T: Iterator, A> {
  iter: T,
  n: uint,
  window: Vec
}

macro_rules! return_if(
  ($cond:expr, $value:expr) => (
    if $cond {
      return $value;
    }
  );
)

impl<A: Clone, T: Iterator> Slide<T, A> {
  fn push_window(&mut self) -> bool {
    let iter_next = self.iter.next();

    if iter_next.is_some() {
      self.window.push(iter_next.unwrap());
      true
    } else {
      false
    }
  }

  fn new(iter: T, n: uint) -> Slide<T, A> {
    Slide{
      iter: iter,
      n: n,
      window: Vec::with_capacity(n + 1)
    }
  }
}

impl<A: Clone, T: Iterator> Iterator<Vec> for Slide<T, A> {
  fn next(&mut self) -> Option<Vec> {
    return_if!(self.n == 0, None);
    return_if!(!self.push_window(), None);

    loop {
      let window_status = self.window.len().cmp(&self.n);

      match window_status {
        Greater => { self.window.remove(0); }
        Equal => { return Some(self.window.clone()); }
        Less => { return_if!(!self.push_window(), None); }
      }
    }
  }
}

pub trait SlideIterator<T: Iterator, A> {
  fn slide(self, n: uint) -> Slide<T, A>;
}

impl<A: Clone, T: Iterator> SlideIterator<T, A> for T {
  fn slide(self, n: uint) -> Slide<T, A> {
    Slide::new(self, n)
  }
}

#[test]
fn test_slide() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(3);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3])
  assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4])
  assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_equal_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(5);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_zero_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(0);
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_overlong_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(7);
  assert!(slide_iter.next().is_none())
}
<commit_msg>Simplify `push_window`<commit_after>#![feature(macro_rules)]

pub struct Slide<T: Iterator, A> {
  iter: T,
  n: uint,
  window: Vec
}

macro_rules! return_if(
  ($cond:expr, $value:expr) => (
    if $cond {
      return $value;
    }
  );
)

impl<A: Clone, T: Iterator> Slide<T, A> {
  fn push_window(&mut self) -> bool {
    let iter_next = self.iter.next();
    let is_some = iter_next.is_some();

    if is_some {
      self.window.push(iter_next.unwrap());
    }

    is_some
  }

  fn new(iter: T, n: uint) -> Slide<T, A> {
    Slide{
      iter: iter,
      n: n,
      window: Vec::with_capacity(n + 1)
    }
  }
}

impl<A: Clone, T: Iterator> Iterator<Vec> for Slide<T, A> {
  fn next(&mut self) -> Option<Vec> {
    return_if!(self.n == 0, None);
    return_if!(!self.push_window(), None);

    loop {
      let window_status = self.window.len().cmp(&self.n);

      match window_status {
        Greater => { self.window.remove(0); }
        Equal => { return Some(self.window.clone()); }
        Less => { return_if!(!self.push_window(), None); }
      }
    }
  }
}

pub trait SlideIterator<T: Iterator, A> {
  fn slide(self, n: uint) -> Slide<T, A>;
}

impl<A: Clone, T: Iterator> SlideIterator<T, A> for T {
  fn slide(self, n: uint) -> Slide<T, A> {
    Slide::new(self, n)
  }
}

#[test]
fn test_slide() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(3);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3])
  assert_eq!(slide_iter.next().unwrap(), vec![2, 3, 4])
  assert_eq!(slide_iter.next().unwrap(), vec![3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_equal_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(5);
  assert_eq!(slide_iter.next().unwrap(), vec![1, 2, 3, 4, 5])
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_zero_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(0);
  assert!(slide_iter.next().is_none())
}

#[test]
fn test_slide_overlong_window() {
  let mut slide_iter = vec![1i, 2, 3, 4, 5].into_iter().slide(7);
  assert!(slide_iter.next().is_none())
}
<|endoftext|>


<commit_before><commit_msg>Remove useless comparison<commit_after><|endoftext|>


<commit_before><commit_msg>Adding example code.<commit_after><|endoftext|>


<commit_before><commit_msg>Make cargo-expand able to be vendored by cargo-vendor<commit_after>// empty
<|endoftext|>


<commit_before><commit_msg>Add some examples of reading the content of a Response, and a paragraph about `Read`<commit_after><|endoftext|>


<commit_before><commit_msg>Add regression test for issue #17780<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.

#![feature(unboxed_closures, overloaded_calls)]

fn set(x: &mut uint) { *x = 5; }

fn main() {
    // By-ref captures
    {
        let mut x = 0u;
        let _f = |&:| x = 42;
        //~^ ERROR cannot assign to data in a free
        // variable from an immutable unboxed closure

        let mut y = 0u;
        let _g = |&:| set(&mut y);
        //~^ ERROR cannot borrow data mutably in a free
        // variable from an immutable unboxed closure

        let mut z = 0u;
        let _h = |&mut:| { set(&mut z); |&:| z = 42; };
        //~^ ERROR cannot assign to data in a
        // free variable from an immutable unboxed closure
    }
    // By-value captures
    {
        let mut x = 0u;
        let _f = move |&:| x = 42;
        //~^ ERROR cannot assign to data in a free
        // variable from an immutable unboxed closure

        let mut y = 0u;
        let _g = move |&:| set(&mut y);
        //~^ ERROR cannot borrow data mutably in a free
        // variable from an immutable unboxed closure

        let mut z = 0u;
        let _h = move |&mut:| { set(&mut z); move |&:| z = 42; };
        //~^ ERROR cannot assign to data in a free
        // variable from an immutable unboxed closure
    }
}
<|endoftext|>


<commit_before><commit_msg>Count missing tests as failed<commit_after><|endoftext|>


<commit_before><commit_msg>Add compile-fail test for when the inferred and actual result types differ.<commit_after>extern crate uom;

use uom::si::f32::*;

fn main() {
    let _: Velocity = Length::new(1.0, uom::si::length::meter) *
                      Time::new(1.0, uom::si::time::second);
    //~^^ ERROR mismatched types [E0308]
}
<|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.

use rustc::hir;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::*;
use rustc::mir::transform::{MirSuite, MirPassIndex, MirSource};
use rustc::ty::TyCtxt;
use rustc::ty::item_path;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_num: Option<(MirSuite, MirPassIndex)>,
                          pass_name: &str,
                          disambiguator: &Display,
                          source: MirSource,
                          mir: &Mir<'tcx>) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }

    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
    });
    dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
                          disambiguator, source, mir);
    for (index, promoted_mir) in mir.promoted.iter_enumerated() {
        let promoted_source = MirSource::Promoted(source.item_id(), index);
        dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
                              promoted_source, promoted_mir);
    }
}

pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              pass_name: &str,
                              source: MirSource)
                              -> bool {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return false,
        Some(ref filters) => filters,
    };
    let node_id = source.item_id();
    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(node_id))
    });
    filters.split("&")
           .any(|filter| {
               filter == "all" ||
                   pass_name.contains(filter) ||
                   node_path.contains(filter)
           })
}

// #41697 -- we use `with_forced_impl_filename_line()` because
// `item_path_str()` would otherwise trigger `type_of`, and this can
// run while we are already attempting to evaluate `type_of`.

fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   pass_num: Option<(MirSuite, MirPassIndex)>,
                                   pass_name: &str,
                                   node_path: &str,
                                   disambiguator: &Display,
                                   source: MirSource,
                                   mir: &Mir<'tcx>) {
    let promotion_id = match source {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        MirSource::GeneratorDrop(_) => format!("-drop"),
        _ => String::new()
    };

    let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
        format!("")
    } else {
        match pass_num {
            None => format!(".-------"),
            Some((suite, pass_num)) => format!(".{:03}-{:03}", suite.0, pass_num.0),
        }
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let _ = fs::create_dir_all(&file_path);
    let file_name = format!("rustc.node{}{}{}.{}.{}.mir",
                            source.item_id(), promotion_id, pass_num, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "// disambiguator = {}", disambiguator)?;
        if let Some(ref layout) = mir.generator_layout {
            writeln!(file, "// generator_layout = {:?}", layout)?;
        }
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file)?;
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  single: Option<DefId>,
                                  w: &mut Write)
                                  -> io::Result<()>
{
    writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
    writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;

    let mut first = true;
    for def_id in dump_mir_def_ids(tcx, single) {
        let mir = &tcx.optimized_mir(def_id);

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.hir.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
        }
    }
    Ok(())
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
pub fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

/// Prints user-defined variables in a scope tree.
///
/// Returns the total number of variables printed.
fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for local in mir.vars_iter() {
            let var = &mir.local_decls[local];
            let (name, source_info) = if var.source_info.scope == child {
                (var.name.unwrap(), var.source_info)
            } else {
                // Not a variable or not declared in this scope.
                continue;
            };

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       local,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     name,
                     comment(tcx, source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
pub fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    // Print return pointer
    let indented_retptr = format!("{}let mut {:?}: {};",
                                  INDENT,
                                  RETURN_POINTER,
                                  mir.return_ty);
    writeln!(w, "{0:1$} // return pointer",
             indented_retptr,
             ALIGN)?;

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_temp_decls(mir, w)?;

    // Add an empty line before the first block is printed.
    writeln!(w, "")?;

    Ok(())
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?,
        MirSource::GeneratorDrop(_) => write!(w, "drop_glue")?,
    }

    item_path::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere
        write!(w, " {}", tcx.node_path_str(src.item_id()))
    })?;

    match src {
        MirSource::Fn(_) | MirSource::GeneratorDrop(_) => {
            write!(w, "(")?;

            // fn argument types.
            for (i, arg) in mir.args_iter().enumerate() {
                if i != 0 {
                    write!(w, ", ")?;
                }
                write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
            }

            write!(w, ") -> {}", mir.return_ty)
        }
        MirSource::Const(..) |
        MirSource::Static(..) |
        MirSource::Promoted(..) => {
            assert_eq!(mir.arg_count, 0);
            write!(w, ": {} =", mir.return_ty)
        }
    }
}

fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for temp in mir.temps_iter() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
    }

    Ok(())
}

pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
    if let Some(i) = single {
        vec![i]
    } else {
        tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect()
    }
}
<commit_msg>Mir pretty print: Add cleanup comment<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.

use rustc::hir;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::mir::*;
use rustc::mir::transform::{MirSuite, MirPassIndex, MirSource};
use rustc::ty::TyCtxt;
use rustc::ty::item_path;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_num>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_num: Option<(MirSuite, MirPassIndex)>,
                          pass_name: &str,
                          disambiguator: &Display,
                          source: MirSource,
                          mir: &Mir<'tcx>) {
    if !dump_enabled(tcx, pass_name, source) {
        return;
    }

    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(source.item_id()))
    });
    dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
                          disambiguator, source, mir);
    for (index, promoted_mir) in mir.promoted.iter_enumerated() {
        let promoted_source = MirSource::Promoted(source.item_id(), index);
        dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
                              promoted_source, promoted_mir);
    }
}

pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              pass_name: &str,
                              source: MirSource)
                              -> bool {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return false,
        Some(ref filters) => filters,
    };
    let node_id = source.item_id();
    let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below
        tcx.item_path_str(tcx.hir.local_def_id(node_id))
    });
    filters.split("&")
           .any(|filter| {
               filter == "all" ||
                   pass_name.contains(filter) ||
                   node_path.contains(filter)
           })
}

// #41697 -- we use `with_forced_impl_filename_line()` because
// `item_path_str()` would otherwise trigger `type_of`, and this can
// run while we are already attempting to evaluate `type_of`.

fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   pass_num: Option<(MirSuite, MirPassIndex)>,
                                   pass_name: &str,
                                   node_path: &str,
                                   disambiguator: &Display,
                                   source: MirSource,
                                   mir: &Mir<'tcx>) {
    let promotion_id = match source {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        MirSource::GeneratorDrop(_) => format!("-drop"),
        _ => String::new()
    };

    let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
        format!("")
    } else {
        match pass_num {
            None => format!(".-------"),
            Some((suite, pass_num)) => format!(".{:03}-{:03}", suite.0, pass_num.0),
        }
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let _ = fs::create_dir_all(&file_path);
    let file_name = format!("rustc.node{}{}{}.{}.{}.mir",
                            source.item_id(), promotion_id, pass_num, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR for `{}`", node_path)?;
        writeln!(file, "// source = {:?}", source)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "// disambiguator = {}", disambiguator)?;
        if let Some(ref layout) = mir.generator_layout {
            writeln!(file, "// generator_layout = {:?}", layout)?;
        }
        writeln!(file, "")?;
        write_mir_fn(tcx, source, mir, &mut file)?;
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  single: Option<DefId>,
                                  w: &mut Write)
                                  -> io::Result<()>
{
    writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
    writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;

    let mut first = true;
    for def_id in dump_mir_def_ids(tcx, single) {
        let mir = &tcx.optimized_mir(def_id);

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.hir.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
        }
    }
    Ok(())
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
pub fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    let cleanup_text = if data.is_cleanup { " // cleanup" } else { "" };
    let lbl = format!("{}{:?}: {{", INDENT, block);
    writeln!(w, "{0:1$}{2}", lbl, ALIGN, cleanup_text)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

/// Prints user-defined variables in a scope tree.
///
/// Returns the total number of variables printed.
fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for local in mir.vars_iter() {
            let var = &mir.local_decls[local];
            let (name, source_info) = if var.source_info.scope == child {
                (var.name.unwrap(), var.source_info)
            } else {
                // Not a variable or not declared in this scope.
                continue;
            };

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       local,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     name,
                     comment(tcx, source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
pub fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    // Print return pointer
    let indented_retptr = format!("{}let mut {:?}: {};",
                                  INDENT,
                                  RETURN_POINTER,
                                  mir.return_ty);
    writeln!(w, "{0:1$} // return pointer",
             indented_retptr,
             ALIGN)?;

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_temp_decls(mir, w)?;

    // Add an empty line before the first block is printed.
    writeln!(w, "")?;

    Ok(())
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?,
        MirSource::GeneratorDrop(_) => write!(w, "drop_glue")?,
    }

    item_path::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere
        write!(w, " {}", tcx.node_path_str(src.item_id()))
    })?;

    match src {
        MirSource::Fn(_) | MirSource::GeneratorDrop(_) => {
            write!(w, "(")?;

            // fn argument types.
            for (i, arg) in mir.args_iter().enumerate() {
                if i != 0 {
                    write!(w, ", ")?;
                }
                write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
            }

            write!(w, ") -> {}", mir.return_ty)
        }
        MirSource::Const(..) |
        MirSource::Static(..) |
        MirSource::Promoted(..) => {
            assert_eq!(mir.arg_count, 0);
            write!(w, ": {} =", mir.return_ty)
        }
    }
}

fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for temp in mir.temps_iter() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
    }

    Ok(())
}

pub fn dump_mir_def_ids(tcx: TyCtxt, single: Option<DefId>) -> Vec<DefId> {
    if let Some(i) = single {
        vec![i]
    } else {
        tcx.mir_keys(LOCAL_CRATE).iter().cloned().collect()
    }
}
<|endoftext|>


<commit_before><commit_msg>Added notes on comments<commit_after>// A compilation of notes and lessons from https://doc.rust-lang.org/book/comments.html

// Yes, comments requires its own file - it's a bit more complex than just //
// Not much more complex but still :)

// Regular comments are like the ones I've been doing. Duh.

// Another type of comment is a doc comment, which is differentiated via /// instead of //
// These types of comments support Markdown within them and are commonly used to provide documentation
// and usage instructions for methods

// Another type of doc comment is //!, which is used commonly in module or crate root files (lib.rs and mod.rs)
// Using //! vs /// seems to just be a style/convention thing

// Interestingly - you can use the rustdoc tool (https://doc.rust-lang.org/book/documentation.html) to create HTML
// documents from doc comments and run code examples (from within the comments) as tests
<|endoftext|>


<commit_before><commit_msg>Added some end-user "sanity" tests<commit_after>/// Tests which exercise the overall application, in particular the `MDBook`
/// initialization and build/rendering process.
///
/// This will create an entire book in a temporary directory using some
/// dummy content.

extern crate mdbook;
extern crate tempdir;
extern crate env_logger;

use std::path::Path;
use std::fs::{self, File};
use std::io::{Read, Write};

use tempdir::TempDir;
use mdbook::MDBook;

const SUMMARY_MD: &'static str = "# Summary

[Introduction](intro.md)

- [First Chapter](./first/index.md)
    - [Nested Chapter](./first/nested.md)
- [Second Chapter](./second.md)

[Conclusion](./conclusion.md)
";

const INTRO: &'static str = "# Introduction

Here's some interesting text...";

const FIRST: &'static str = "# First Chapter

more text.";

const NESTED: &'static str = r#"# Nested Chapter

This file has some testable code.

```rust
assert!($TEST_STATUS);
```"#;

const SECOND: &'static str = "# Second Chapter";

const CONCLUSION: &'static str = "# Conclusion";

#[test]
fn build_the_dummy_book() {
    let temp = create_book(true);
    let mut md = MDBook::new(temp.path());

    md.build().unwrap();
}

#[test]
fn mdbook_can_correctly_test_a_passing_book() {
    let temp = create_book(true);
    let mut md = MDBook::new(temp.path());

    assert!(md.test().is_ok());
}

#[test]
fn mdbook_detects_book_with_failing_tests() {
    let temp = create_book(false);
    let mut md = MDBook::new(temp.path());

    assert!(md.test().is_err());
}

#[test]
fn by_default_mdbook_generates_rendered_content_in_the_book_directory() {
    let temp = create_book(false);
    let mut md = MDBook::new(temp.path());

    assert!(!temp.path().join("book").exists());
    md.build().unwrap();

    assert!(temp.path().join("book").exists());
    assert!(temp.path().join("book").join("index.html").exists());
}

#[test]
fn make_sure_bottom_level_files_contain_links_to_chapters() {
    let temp = create_book(false);
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let dest = temp.path().join("book");
    let links = vec![
        "intro.html",
        "first/index.html",
        "first/nested.html",
        "second.html",
        "conclusion.html",
    ];

    let files_in_bottom_dir = vec!["index.html", "intro.html", "second.html", "conclusion.html"];

    for filename in files_in_bottom_dir {
        assert_contains_strings(dest.join(filename), &links);
    }
}

#[test]
fn check_correct_cross_links_in_nested_dir() {
    let temp = create_book(false);
    let mut md = MDBook::new(temp.path());
    md.build().unwrap();

    let first = temp.path().join("book").join("first");
    let links = vec![
        r#"<base href="../">"#,
        "intro.html",
        "first/index.html",
        "first/nested.html",
        "second.html",
        "conclusion.html",
    ];

    let files_in_nested_dir = vec!["index.html", "nested.html"];

    for filename in files_in_nested_dir {
        assert_contains_strings(first.join(filename), &links);
    }
}

/// Create a dummy book in a temporary directory, using the contents of
/// `SUMMARY_MD` as a guide.
///
/// The "Nested Chapter" file contains a code block with a single
/// `assert!($TEST_STATUS)`. If you want to check MDBook's testing
/// functionality, `$TEST_STATUS` can be substitute for either `true` or
/// `false`. This is done using the `passing_test` parameter.
fn create_book(passing_test: bool) -> TempDir {
    let temp = TempDir::new("dummy_book").unwrap();

    let src = temp.path().join("src");
    fs::create_dir_all(&src).unwrap();

    File::create(src.join("SUMMARY.md"))
        .unwrap()
        .write_all(SUMMARY_MD.as_bytes())
        .unwrap();
    File::create(src.join("intro.md"))
        .unwrap()
        .write_all(INTRO.as_bytes())
        .unwrap();

    let first = src.join("first");
    fs::create_dir_all(&first).unwrap();
    File::create(first.join("index.md"))
        .unwrap()
        .write_all(FIRST.as_bytes())
        .unwrap();

    let to_substitute = if passing_test { "true" } else { "false" };
    let nested_text = NESTED.replace("$TEST_STATUS", to_substitute);
    File::create(first.join("nested.md"))
        .unwrap()
        .write_all(nested_text.as_bytes())
        .unwrap();

    File::create(src.join("second.md"))
        .unwrap()
        .write_all(SECOND.as_bytes())
        .unwrap();
    File::create(src.join("conclusion.md"))
        .unwrap()
        .write_all(CONCLUSION.as_bytes())
        .unwrap();

    temp
}

fn assert_contains_strings<P: AsRef<Path>>(filename: P, strings: &[&str]) {
    println!("Checking {}", filename.as_ref().display());
    println!();

    let mut content = String::new();
    File::open(filename)
        .expect("Couldn't open the provided file")
        .read_to_string(&mut content)
        .unwrap();

    println!("{}", content);
    println!();
    println!();

    for s in strings {
        println!("Checking for {:?}", s);
        assert!(content.contains(s));
    }
}<|endoftext|>


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

// This test case tests the incremental compilation hash (ICH) implementation
// for struct constructor expressions.

// The general pattern followed here is: Change one thing between rev1 and rev2
// and make sure that the hash has changed, then change nothing between rev2 and
// rev3 and make sure that the hash has not changed.

// must-compile-successfully
// revisions: cfail1 cfail2 cfail3
// compile-flags: -Z query-dep-graph

#![allow(warnings)]
#![feature(rustc_attrs)]
#![crate_type="rlib"]

struct RegularStruct {
    x: i32,
    y: i64,
    z: i16,
}

// Change field value (regular struct) -----------------------------------------
#[cfg(cfail1)]
fn change_field_value_regular_struct() -> RegularStruct {
    RegularStruct {
        x: 0,
        y: 1,
        z: 2,
    }
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_field_value_regular_struct() -> RegularStruct {
    RegularStruct {
        x: 0,
        y: 2,
        z: 2,
    }
}

// Change field order (regular struct) -----------------------------------------
#[cfg(cfail1)]
fn change_field_order_regular_struct() -> RegularStruct {
    RegularStruct {
        x: 3,
        y: 4,
        z: 5,
    }
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_field_order_regular_struct() -> RegularStruct {
    RegularStruct {
        y: 4,
        x: 3,
        z: 5,
    }
}

// Add field (regular struct) --------------------------------------------------
#[cfg(cfail1)]
fn add_field_regular_struct() -> RegularStruct {
    let struct1 = RegularStruct {
        x: 3,
        y: 4,
        z: 5,
    };

    RegularStruct {
        x: 7,
        .. struct1
    }
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn add_field_regular_struct() -> RegularStruct {
    let struct1 = RegularStruct {
        x: 3,
        y: 4,
        z: 5,
    };

    RegularStruct {
        x: 7,
        y: 8,
        .. struct1
    }
}

// Change field label (regular struct) -----------------------------------------
#[cfg(cfail1)]
fn change_field_label_regular_struct() -> RegularStruct {
    let struct1 = RegularStruct {
        x: 3,
        y: 4,
        z: 5,
    };

    RegularStruct {
        x: 7,
        y: 9,
        .. struct1
    }
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_field_label_regular_struct() -> RegularStruct {
    let struct1 = RegularStruct {
        x: 3,
        y: 4,
        z: 5,
    };

    RegularStruct {
        x: 7,
        z: 9,
        .. struct1
    }
}

struct RegularStruct2 {
    x: i8,
    y: i8,
    z: i8,
}

// Change constructor path (regular struct) ------------------------------------
#[cfg(cfail1)]
fn change_constructor_path_regular_struct() {
    let _ = RegularStruct {
        x: 0,
        y: 1,
        z: 2,
    };
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_constructor_path_regular_struct() {
    let _ = RegularStruct2 {
        x: 0,
        y: 1,
        z: 2,
    };
}

// Change constructor path indirectly (regular struct) -------------------------
mod change_constructor_path_indirectly_regular_struct {
    #[cfg(cfail1)]
    use super::RegularStruct as Struct;
    #[cfg(not(cfail1))]
    use super::RegularStruct2 as Struct;

    fn function() -> Struct {
        Struct {
            x: 0,
            y: 1,
            z: 2,
        }
    }
}

struct TupleStruct(i32, i64, i16);

// Change field value (tuple struct) -------------------------------------------
#[cfg(cfail1)]
fn change_field_value_tuple_struct() -> TupleStruct {
    TupleStruct(0, 1, 2)
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_field_value_tuple_struct() -> TupleStruct {
    TupleStruct(0, 1, 3)
}

struct TupleStruct2(u16, u16, u16);

// Change constructor path (tuple struct) --------------------------------------
#[cfg(cfail1)]
fn change_constructor_path_tuple_struct() {
    let _ = TupleStruct(0, 1, 2);
}

#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
fn change_constructor_path_tuple_struct() {
    let _ = TupleStruct2(0, 1, 2);
}

// Change constructor path indirectly (tuple struct) ---------------------------
mod change_constructor_path_indirectly_tuple_struct {
    #[cfg(cfail1)]
    use super::TupleStruct as Struct;
    #[cfg(not(cfail1))]
    use super::TupleStruct2 as Struct;

    fn function() -> Struct {
        Struct(0, 1, 2)
    }
}
<|endoftext|>


<commit_before>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::ioivec;
import std::ioivec::stdout;
import std::vec;
import std::ivec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::walk;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

fn read_whole_file(filename: &str) -> str {
    str::unsafe_from_bytes_ivec(ioivec::file_reader(filename).read_whole_stream())
}

fn write_file(filename: &str, content: &str) {
    ioivec::file_writer(filename,
                        ~[ioivec::create,
                          ioivec::truncate]).write_str(content);
    // Work around https://github.com/graydon/rust/issues/726
    std::run::run_program("chmod", ["644", filename]);
}

fn file_contains(filename: &str, needle: &str) -> bool {
    let contents = read_whole_file(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(haystack: &str, needle: &str) -> bool {
    str::find(haystack, needle) != -1
}

fn find_rust_files(files: &mutable str[], path: str) {
    if str::ends_with(path, ".rs") {
        if file_contains(path, "xfail-stage1") {
            //log_err "Skipping " + path + " because it is marked as xfail-stage1";
        } else { files += ~[path]; }
    } else if (fs::file_is_dir(path) && str::find(path, "compile-fail") == -1)
     {
        for p in fs::list_dir(path) { find_rust_files(files, p); }
    }
}

fn safe_to_steal(e: ast::expr_) -> bool {
    alt e {

      // pretty-printer precedence issues -- https://github.com/graydon/rust/issues/670
      ast::expr_unary(_, _) {
        false
      }
      ast::expr_lit(lit) {
        alt lit.node {
          ast::lit_str(_, _) { true }
          ast::lit_char(_) { true }
          ast::lit_int(_) { false }
          ast::lit_uint(_) { false }
          ast::lit_mach_int(_, _) { false }
          ast::lit_float(_) { false }
          ast::lit_mach_float(_, _) { false }
          ast::lit_nil. { true }
          ast::lit_bool(_) { true }
        }
      }
      ast::expr_cast(_, _) { false }
      ast::expr_send(_, _) { false }
      ast::expr_recv(_, _) { false }
      ast::expr_assert(_) { false }
      ast::expr_binary(_, _, _) { false }
      ast::expr_assign(_, _) { false }
      ast::expr_assign_op(_, _, _) { false }
      ast::expr_fail(option::none.) { false /* https://github.com/graydon/rust/issues/764 */ }
      ast::expr_ret(option::none.) { false }
      ast::expr_put(option::none.) { false }

      _ {
        true
      }
    }
}

fn steal_exprs(crate: &ast::crate) -> ast::expr[] {
    let exprs: @mutable ast::expr[] = @mutable ~[];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(es: @mutable ast::expr[], e: &@ast::expr) {
        if safe_to_steal(e.node) {
            *es += ~[*e];
        } else {/* now my indices are wrong :( */ }
    }
    let v =
        {visit_expr_pre: bind stash_expr(exprs, _)
            with walk::default_visitor()};
    walk::walk_crate(v, crate);
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(e: ast::expr_) -> bool {
    alt e {
      ast::expr_if(_, _, _) { false }
      ast::expr_block(_) { false }
      _ { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(crate: &ast::crate, i: uint, newexpr: ast::expr_) ->
   ast::crate {
    let j: @mutable uint = @mutable 0u;
    fn fold_expr_rep(j_: @mutable uint, i_: uint, newexpr_: &ast::expr_,
                     original: &ast::expr_, fld: fold::ast_fold) ->
       ast::expr_ {
        *j_ += 1u;
        if i_ + 1u == *j_ && safe_to_replace(original) {
            newexpr_
        } else { fold::noop_fold_expr(original, fld) }
    }
    let afp =
        {fold_expr: bind fold_expr_rep(j, i, newexpr, _, _)
            with *fold::default_ast_fold()};
    let af = fold::make_fold(afp);
    let crate2: @ast::crate = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    *crate2
}

iter under(n: uint) -> uint {
    let i: uint = 0u;
    while i < n { put i; i += 1u; }
}

fn devnull() -> ioivec::writer { std::ioivec::string_writer().get_writer() }

fn as_str(f: fn(ioivec::writer) ) -> str {
    let w = std::ioivec::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

fn pp_variants(crate: &ast::crate, codemap: &codemap::codemap, filename: &str) {
    let exprs = steal_exprs(crate);
    let exprsL = ivec::len(exprs);
    if (exprsL < 100u) {
        for each i: uint in under(uint::min(exprsL, 20u)) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs.(i));
            for each j: uint in under(uint::min(exprsL, 5u)) {
                log_err "With... " + pprust::expr_to_str(@exprs.(j));
                let crate2 = @replace_expr_in_crate(crate, i, exprs.(j).node);
                // It would be best to test the *crate* for stability, but testing the
                // string for stability is easier and ok for now.
                let str3 = as_str(bind pprust::print_crate(codemap, crate2, filename,
                                  ioivec::string_reader(""), _,
                                  pprust::no_ann()));
                // 1u would be sane here, but the pretty-printer currently has lots of whitespace and paren issues,
                // and https://github.com/graydon/rust/issues/766 is hilarious.
                check_roundtrip_convergence(str3, 7u);
            }
        }
    }
}

fn parse_and_print(code: &str) -> str {
    let filename = "tmp.rs";
    let codemap = codemap::new_codemap();
    //write_file(filename, code);
    let crate =
        parser::parse_crate_from_source_str(filename, code, ~[], codemap);
    ret as_str(bind pprust::print_crate(codemap, crate, filename,
                                        ioivec::string_reader(code), _,
                                        pprust::no_ann()));
}

fn content_is_dangerous_to_modify(code: &str) -> bool {
    let dangerous_patterns = [
         "obj", // not safe to steal; https://github.com/graydon/rust/issues/761
         "#macro", // not safe to steal things inside of it, because they have a special syntax
         " be " // don't want to replace its child with a non-call: "Non-call expression in tail call"
    ];

    for p: str in dangerous_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn content_is_confusing(code: &str) -> bool {
    let  // https://github.com/graydon/rust/issues/671
         // https://github.com/graydon/rust/issues/669
         // https://github.com/graydon/rust/issues/669
         // https://github.com/graydon/rust/issues/669
         // crazy rules enforced by parser rather than typechecker?
         // more precedence issues
         // more precedence issues?
        confusing_patterns =
        ["#macro", "][]", "][mutable]", "][mutable ]", "self", "spawn",
         "bind",
         "\n\n\n\n\n", // https://github.com/graydon/rust/issues/759
         " : ", // https://github.com/graydon/rust/issues/760
         "if ret",
         "alt ret",
         "if fail",
         "alt fail"
         ];

    for p: str in confusing_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn file_is_confusing(filename: &str) -> bool {
    let

         // https://github.com/graydon/rust/issues/674

         // something to do with () as a lone pattern

         // an issue where -2147483648 gains an
         // extra negative sign each time through,
         // which i can't reproduce using "rustc
         // --pretty normal"???
         confusing_files =
        ["block-expr-precedence.rs", "nil-pattern.rs",
         "syntax-extension-fmt.rs",
         "newtype.rs" // modifying it hits something like https://github.com/graydon/rust/issues/670
         ];

    for f in confusing_files { if contains(filename, f) { ret true; } }

    ret false;
}

fn check_roundtrip_convergence(code: &str, maxIters: uint) {

    let i = 0u;
    let new = code;
    let old = code;

    while i < maxIters {
        old = new;
        if content_is_confusing(old) { ret; }
        new = parse_and_print(old);
        if old == new { break; }
        i += 1u;
    }

    if old == new {
        log_err #fmt("Converged after %u iterations", i);
    } else {
        log_err #fmt("Did not converge after %u iterations!", i);
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("diff", ["-w", "-u", "round-trip-a.rs", "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn check_convergence(files: &str[]) {
    log_err #fmt("pp convergence tests: %u files", ivec::len(files));
    for file in files {
        if !file_is_confusing(file) {
            let s = read_whole_file(file);
            if !content_is_confusing(s) {
                log_err #fmt("pp converge: %s", file);
                // Change from 7u to 2u when https://github.com/graydon/rust/issues/759 is fixed
                check_roundtrip_convergence(s, 7u);
            }
        }
    }
}

fn check_convergence_of_variants(files: &str[]) {
    for file in files {
        if !file_is_confusing(file) {
            let s = read_whole_file(file);
            if content_is_dangerous_to_modify(s) || content_is_confusing(s) { cont; }
            log_err "check_convergence_of_variants: " + file;
            let codemap = codemap::new_codemap();
            let crate = parser::parse_crate_from_source_str(file, s, ~[], codemap);
            log_err as_str(bind pprust::print_crate(codemap, crate, file,
                                        ioivec::string_reader(s), _,
                                        pprust::no_ann()));
            pp_variants(*crate, codemap, file);
        }
    }
}

fn main(args: vec[str]) {
    if vec::len(args) != 2u {
        log_err #fmt("usage: %s <testdir>", args.(0));
        ret;
    }
    let files = ~[];
    let root = args.(1);

    find_rust_files(files, root);
    check_convergence(files);
    check_convergence_of_variants(files);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Make the fuzzer check for obvious errors in the 'rest of the compiler', not just the parser. (Disabled by default because it's slow and messy.)<commit_after>use std;
use rustc;

import std::fs;
import std::getopts;
import std::getopts::optopt;
import std::getopts::opt_present;
import std::getopts::opt_str;
import std::ioivec;
import std::ioivec::stdout;
import std::vec;
import std::ivec;
import std::str;
import std::uint;
import std::option;

import rustc::syntax::ast;
import rustc::syntax::fold;
import rustc::syntax::walk;
import rustc::syntax::codemap;
import rustc::syntax::parse::parser;
import rustc::syntax::print::pprust;

fn read_whole_file(filename: &str) -> str {
    str::unsafe_from_bytes_ivec(ioivec::file_reader(filename).read_whole_stream())
}

fn write_file(filename: &str, content: &str) {
    ioivec::file_writer(filename,
                        ~[ioivec::create,
                          ioivec::truncate]).write_str(content);
    // Work around https://github.com/graydon/rust/issues/726
    std::run::run_program("chmod", ["644", filename]);
}

fn file_contains(filename: &str, needle: &str) -> bool {
    let contents = read_whole_file(filename);
    ret str::find(contents, needle) != -1;
}

fn contains(haystack: &str, needle: &str) -> bool {
    str::find(haystack, needle) != -1
}

fn find_rust_files(files: &mutable str[], path: str) {
    if str::ends_with(path, ".rs") {
        if file_contains(path, "xfail-stage1") {
            //log_err "Skipping " + path + " because it is marked as xfail-stage1";
        } else { files += ~[path]; }
    } else if (fs::file_is_dir(path) && str::find(path, "compile-fail") == -1)
     {
        for p in fs::list_dir(path) { find_rust_files(files, p); }
    }
}

fn safe_to_steal(e: ast::expr_) -> bool {
    alt e {

      // pretty-printer precedence issues -- https://github.com/graydon/rust/issues/670
      ast::expr_unary(_, _) {
        false
      }
      ast::expr_lit(lit) {
        alt lit.node {
          ast::lit_str(_, _) { true }
          ast::lit_char(_) { true }
          ast::lit_int(_) { false }
          ast::lit_uint(_) { false }
          ast::lit_mach_int(_, _) { false }
          ast::lit_float(_) { false }
          ast::lit_mach_float(_, _) { false }
          ast::lit_nil. { true }
          ast::lit_bool(_) { true }
        }
      }
      ast::expr_cast(_, _) { false }
      ast::expr_send(_, _) { false }
      ast::expr_recv(_, _) { false }
      ast::expr_assert(_) { false }
      ast::expr_binary(_, _, _) { false }
      ast::expr_assign(_, _) { false }
      ast::expr_assign_op(_, _, _) { false }
      ast::expr_fail(option::none.) { false /* https://github.com/graydon/rust/issues/764 */ }
      ast::expr_ret(option::none.) { false }
      ast::expr_put(option::none.) { false }

      ast::expr_ret(_) { false /* lots of code generation issues, such as https://github.com/graydon/rust/issues/770 */ }
      ast::expr_fail(_) { false }

      _ {
        true
      }
    }
}

fn steal_exprs(crate: &ast::crate) -> ast::expr[] {
    let exprs: @mutable ast::expr[] = @mutable ~[];
    // "Stash" is not type-parameterized because of the need for safe_to_steal
    fn stash_expr(es: @mutable ast::expr[], e: &@ast::expr) {
        if safe_to_steal(e.node) {
            *es += ~[*e];
        } else {/* now my indices are wrong :( */ }
    }
    let v =
        {visit_expr_pre: bind stash_expr(exprs, _)
            with walk::default_visitor()};
    walk::walk_crate(v, crate);
    *exprs
}

// https://github.com/graydon/rust/issues/652
fn safe_to_replace(e: ast::expr_) -> bool {
    alt e {
      ast::expr_if(_, _, _) { false }
      ast::expr_block(_) { false }
      _ { true }
    }
}

// Replace the |i|th expr (in fold order) of |crate| with |newexpr|.
fn replace_expr_in_crate(crate: &ast::crate, i: uint, newexpr: ast::expr_) ->
   ast::crate {
    let j: @mutable uint = @mutable 0u;
    fn fold_expr_rep(j_: @mutable uint, i_: uint, newexpr_: &ast::expr_,
                     original: &ast::expr_, fld: fold::ast_fold) ->
       ast::expr_ {
        *j_ += 1u;
        if i_ + 1u == *j_ && safe_to_replace(original) {
            newexpr_
        } else { fold::noop_fold_expr(original, fld) }
    }
    let afp =
        {fold_expr: bind fold_expr_rep(j, i, newexpr, _, _)
            with *fold::default_ast_fold()};
    let af = fold::make_fold(afp);
    let crate2: @ast::crate = @af.fold_crate(crate);
    fold::dummy_out(af); // work around a leak (https://github.com/graydon/rust/issues/651)
    *crate2
}

iter under(n: uint) -> uint {
    let i: uint = 0u;
    while i < n { put i; i += 1u; }
}

fn devnull() -> ioivec::writer { std::ioivec::string_writer().get_writer() }

fn as_str(f: fn(ioivec::writer) ) -> str {
    let w = std::ioivec::string_writer();
    f(w.get_writer());
    ret w.get_str();
}

fn check_variants_of_ast(crate: &ast::crate, codemap: &codemap::codemap, filename: &str) {
    let exprs = steal_exprs(crate);
    let exprsL = ivec::len(exprs);
    if (exprsL < 100u) {
        for each i: uint in under(uint::min(exprsL, 20u)) {
            log_err "Replacing... " + pprust::expr_to_str(@exprs.(i));
            for each j: uint in under(uint::min(exprsL, 5u)) {
                log_err "With... " + pprust::expr_to_str(@exprs.(j));
                let crate2 = @replace_expr_in_crate(crate, i, exprs.(j).node);
                // It would be best to test the *crate* for stability, but testing the
                // string for stability is easier and ok for now.
                let str3 = as_str(bind pprust::print_crate(codemap, crate2, filename,
                                  ioivec::string_reader(""), _,
                                  pprust::no_ann()));
                // 1u would be sane here, but the pretty-printer currently has lots of whitespace and paren issues,
                // and https://github.com/graydon/rust/issues/766 is hilarious.
                check_roundtrip_convergence(str3, 7u);
                //check_whole_compiler(str3);
            }
        }
    }
}

// We'd find more bugs if we could take an AST here, but
// - that would find many "false positives" or unimportant bugs
// - that would be tricky, requiring use of tasks or serialization or randomness.
// This seems to find plenty of bugs as it is :)
fn check_whole_compiler(code: &str) {
    let filename = "test.rs";
    write_file(filename, code);
    let p = std::run::program_output("/Users/jruderman/code/rust/build/stage1/rustc", ["-c", filename]);
    //log_err #fmt("Status: %d", p.status);
    //log_err "Output: " + p.out;
    if p.err != "" {
        if contains(p.err, "argument of incompatible type") {
            log_err "https://github.com/graydon/rust/issues/769";
        } else if contains(p.err, "Cannot create binary operator with two operands of differing type") {
            log_err "https://github.com/graydon/rust/issues/770";
        } else if contains(p.err, "May only branch on boolean predicates!") {
            log_err "https://github.com/graydon/rust/issues/770 or https://github.com/graydon/rust/issues/776";
        } else if contains(p.err, "Invalid constantexpr cast!") && contains(code, "!") {
            log_err "https://github.com/graydon/rust/issues/777";
        } else if contains(p.err, "Both operands to ICmp instruction are not of the same type!") && contains(code, "!") {
            log_err "https://github.com/graydon/rust/issues/777 #issuecomment-1678487";
        } else if contains(p.err, "Ptr must be a pointer to Val type!") && contains(code, "!") {
            log_err "https://github.com/graydon/rust/issues/779";
        } else if contains(p.err, "Calling a function with bad signature!") && (contains(code, "iter") || contains(code, "range")) {
            log_err "https://github.com/graydon/rust/issues/771 - calling an iter fails";
        } else if contains(p.err, "Calling a function with a bad signature!") && contains(code, "empty") {
            log_err "https://github.com/graydon/rust/issues/775 - possibly a modification of run-pass/import-glob-crate.rs";
        } else if contains(p.err, "Invalid type for pointer element!") && contains(code, "put") {
            log_err "https://github.com/graydon/rust/issues/773 - put put ()";
        } else if contains(p.err, "pointer being freed was not allocated") && contains(p.out, "Out of stack space, sorry") {
            log_err "https://github.com/graydon/rust/issues/768 + https://github.com/graydon/rust/issues/778"
        } else {
            log_err "Stderr: " + p.err;
            fail "Unfamiliar error message";
        }
    } else if contains(p.out, "non-exhaustive match failure") && contains(p.out, "alias.rs") {
        log_err "https://github.com/graydon/rust/issues/772";
    } else if contains(p.out, "non-exhaustive match failure") && contains(p.out, "trans.rs") && contains(code, "put") {
        log_err "https://github.com/graydon/rust/issues/774";
    } else if contains(p.out, "Out of stack space, sorry") {
        log_err "Possibly a variant of https://github.com/graydon/rust/issues/768";
    } else if p.status == 256 {
        if !contains(p.out, "error:") {
            fail "Exited with status 256 without a span-error";
        }
    } else if p.status == 11 {
        log_err "What is this I don't even";
    } else if p.status != 0 {
        fail "Unfamiliar status code";
    }
}

fn parse_and_print(code: &str) -> str {
    let filename = "tmp.rs";
    let codemap = codemap::new_codemap();
    //write_file(filename, code);
    let crate =
        parser::parse_crate_from_source_str(filename, code, ~[], codemap);
    ret as_str(bind pprust::print_crate(codemap, crate, filename,
                                        ioivec::string_reader(code), _,
                                        pprust::no_ann()));
}

fn content_is_dangerous_to_modify(code: &str) -> bool {
    let dangerous_patterns = [
         "obj", // not safe to steal; https://github.com/graydon/rust/issues/761
         "#macro", // not safe to steal things inside of it, because they have a special syntax
         "#", // strange representation of the arguments to #fmt, for example
         " be ", // don't want to replace its child with a non-call: "Non-call expression in tail call"
         "@" // hangs when compiling: https://github.com/graydon/rust/issues/768
    ];

    for p: str in dangerous_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn content_is_confusing(code: &str) -> bool {
    let  // https://github.com/graydon/rust/issues/671
         // https://github.com/graydon/rust/issues/669
         // https://github.com/graydon/rust/issues/669
         // https://github.com/graydon/rust/issues/669
         // crazy rules enforced by parser rather than typechecker?
         // more precedence issues
         // more precedence issues?
        confusing_patterns =
        ["#macro", "][]", "][mutable]", "][mutable ]", "self", "spawn",
         "bind",
         "\n\n\n\n\n", // https://github.com/graydon/rust/issues/759
         " : ", // https://github.com/graydon/rust/issues/760
         "if ret",
         "alt ret",
         "if fail",
         "alt fail"
         ];

    for p: str in confusing_patterns { if contains(code, p) { ret true; } }
    ret false;
}

fn file_is_confusing(filename: &str) -> bool {
    let

         // https://github.com/graydon/rust/issues/674

         // something to do with () as a lone pattern

         // an issue where -2147483648 gains an
         // extra negative sign each time through,
         // which i can't reproduce using "rustc
         // --pretty normal"???
         confusing_files =
        ["block-expr-precedence.rs", "nil-pattern.rs",
         "syntax-extension-fmt.rs",
         "newtype.rs" // modifying it hits something like https://github.com/graydon/rust/issues/670
         ];

    for f in confusing_files { if contains(filename, f) { ret true; } }

    ret false;
}

fn check_roundtrip_convergence(code: &str, maxIters: uint) {

    let i = 0u;
    let new = code;
    let old = code;

    while i < maxIters {
        old = new;
        if content_is_confusing(old) { ret; }
        new = parse_and_print(old);
        if old == new { break; }
        i += 1u;
    }

    if old == new {
        log_err #fmt("Converged after %u iterations", i);
    } else {
        log_err #fmt("Did not converge after %u iterations!", i);
        write_file("round-trip-a.rs", old);
        write_file("round-trip-b.rs", new);
        std::run::run_program("diff", ["-w", "-u", "round-trip-a.rs", "round-trip-b.rs"]);
        fail "Mismatch";
    }
}

fn check_convergence(files: &str[]) {
    log_err #fmt("pp convergence tests: %u files", ivec::len(files));
    for file in files {
        if !file_is_confusing(file) {
            let s = read_whole_file(file);
            if !content_is_confusing(s) {
                log_err #fmt("pp converge: %s", file);
                // Change from 7u to 2u when https://github.com/graydon/rust/issues/759 is fixed
                check_roundtrip_convergence(s, 7u);
            }
        }
    }
}

fn check_variants(files: &str[]) {
    for file in files {
        if !file_is_confusing(file) {
            let s = read_whole_file(file);
            if content_is_dangerous_to_modify(s) || content_is_confusing(s) { cont; }
            log_err "check_variants: " + file;
            let codemap = codemap::new_codemap();
            let crate = parser::parse_crate_from_source_str(file, s, ~[], codemap);
            log_err as_str(bind pprust::print_crate(codemap, crate, file,
                                        ioivec::string_reader(s), _,
                                        pprust::no_ann()));
            check_variants_of_ast(*crate, codemap, file);
        }
    }
}

fn main(args: vec[str]) {
    if vec::len(args) != 2u {
        log_err #fmt("usage: %s <testdir>", args.(0));
        ret;
    }
    let files = ~[];
    let root = args.(1);

    find_rust_files(files, root);
    check_convergence(files);
    check_variants(files);
    log_err "Fuzzer done";
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>