<commit_before>use self::Decode::{V, C};

static VS: [char; 5] = ['a', 'e', 'i', 'o', 'u'];
static CS: [char; 14] = ['b', 'd', 'f', 'g', 'j', 'k', 'm', 'n',
    'p', 'r', 's', 't', 'v', 'z'];

#[derive(Copy)]
enum Decode {
    V(u16),
    C(u16),
}

static LUT: [Option<Decode>; 26] = [
    Some(V(0)),  // a (ASCII 97)
    Some(C(0)),  // b
    None,        // c
    Some(C(1)),  // d
    Some(V(1)),  // e
    Some(C(2)),  // f
    Some(C(3)),  // g
    None,        // h
    Some(V(2)),  // i
    Some(C(4)),  // j
    Some(C(5)),  // k
    None,        // l
    Some(C(6)),  // m
    Some(C(7)),  // n
    Some(V(3)),  // o
    Some(C(8)),  // p
    None,        // q
    Some(C(9)),  // r
    Some(C(10)), // s
    Some(C(11)), // t
    Some(V(4)),  // u
    Some(C(12)), // v
    None,        // w
    None,        // x
    None,        // y
    Some(C(13)), // z
];

fn vorud_chunk(data: u16) -> String {
    let (data, c5) = (data / CS.len() as u16, data % CS.len() as u16);
    let (data, v4) = (data / VS.len() as u16, data % VS.len() as u16);
    let (data, c3) = (data / CS.len() as u16, data % CS.len() as u16);
    let (data, v2) = (data / VS.len() as u16, data % VS.len() as u16);
    let (_, c1) =    (data / CS.len() as u16, data % CS.len() as u16);
    [CS[c1 as usize],
     VS[v2 as usize],
     CS[c3 as usize],
     VS[v4 as usize],
     CS[c5 as usize],
    ].iter().map(|&x| x).collect()
}

fn decode(c: char) -> Option<Decode> {
    let idx = c as isize - 97;
    if idx < 0 || idx >= LUT.len() as isize { return None; }
    LUT[idx as usize]
}

fn v(c: char) -> Result<u16, ()> {
    match decode(c) {
        Some(V(i)) => Ok(i),
        _ => Err(())
    }
}

fn c(c: char) -> Result<u16, ()> {
    match decode(c) {
        Some(C(i)) => Ok(i),
        _ => Err(())
    }
}

fn durov_chunk(s: &str) -> Result<u16, ()> {
    if s.len() != 5 { return Err(()); }
    let s: Vec<char> = s.chars().collect();
    let (mut ret, mut n) = (0u16, 1u16);
    ret += try!(c(s[4])) * n; n *= CS.len() as u16;
    ret += try!(v(s[3])) * n; n *= VS.len() as u16;
    ret += try!(c(s[2])) * n; n *= CS.len() as u16;
    ret += try!(v(s[1])) * n; n *= VS.len() as u16;
    ret += try!(c(s[0])) * n;

    Ok(ret)
}

#[derive(PartialEq, Eq, Debug)]
pub struct Vorud(String);

impl Vorud {
    pub fn new(s: String) -> Result<Vorud, ()> {
        if s.len() == 0 { return Ok(Vorud("".to_string())); }
        let ch = &s[..].chars().collect::<Vec<char>>();
        let mut i = 0;
        loop {
            if i > ch.len() - 5 { return Err(()); }
            try!(c(ch[i]));
            try!(v(ch[i + 1]));
            try!(c(ch[i + 2]));
            try!(v(ch[i + 3]));
            try!(c(ch[i + 4]));
            if i == ch.len() - 5 { return Ok(Vorud(s)); }
            if ch[i + 5] != '-' { return Err(()); }
            i += 6;
        }
    }
}

pub trait FromVorud<E> {
    fn from_vorud(v: &Vorud) -> Result<Self, E>;
}

pub trait ToVorud {
    fn to_vorud(&self) -> Vorud;
}

impl<'a> ToVorud for &'a [u8] {
    fn to_vorud(&self) -> Vorud {
        let mut ret = String::new();
        for i in 0..(self.len() / 2) {
            if ret.len() > 0 { ret.push_str("-"); }
            let b0 = self[i * 2] as u16;
            let b1 = if self.len() == i * 2 + 1 { 0 } else { self[i * 2 + 1] as u16 };
            ret.push_str(&vorud_chunk(b1 + (b0 << 8))[..]);
        }
        Vorud(ret)
    }
}

impl FromVorud<()> for Vec<u8> {
    fn from_vorud(&Vorud(ref s): &Vorud) -> Result<Vec<u8>, ()> {
        let mut ret = Vec::new();
        for chunk in (&s[..]).split('-') {
            let x = try!(durov_chunk(chunk));
            ret.push((x / 0xff) as u8);
            ret.push((x % 0xff) as u8);
        }
        Ok(ret)
    }
}

impl ToVorud for u32 {
    fn to_vorud(&self) -> Vorud {
        let mut vec = Vec::new();
        vec.push(((*self >> 24) % 0xff) as u8);
        vec.push(((*self >> 16) % 0xff) as u8);
        vec.push(((*self >> 8) % 0xff) as u8);
        vec.push((*self % 0xff) as u8);
        (&vec[..]).to_vorud()
    }
}

impl FromVorud<()> for u32 {
    fn from_vorud(v: &Vorud) -> Result<u32, ()> {
        let v: Vec<u8> = try!(FromVorud::from_vorud(v));
        if v.len() != 4 { return Err(()); }
        Ok(v[3] as u32 +
            ((v[2] as u32) << 8) +
            ((v[1] as u32) << 16) +
            ((v[0] as u32) << 24))
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_vorud() {
        use super::ToVorud;

        assert_eq!("babab", &super::vorud_chunk(0)[]);
        assert_eq!("babad", &super::vorud_chunk(1)[]);
        assert_eq!(Ok(0u16), super::durov_chunk("babab"));
        assert_eq!(Ok(1234u16), super::durov_chunk(&super::vorud_chunk(1234)[]));
        assert_eq!("togas", &super::vorud_chunk(super::durov_chunk("togas").unwrap())[]);
        assert_eq!(super::Vorud("babab-babab".to_string()), 0u32.to_vorud());
        assert_eq!(super::Vorud("babab-babad".to_string()), 1u32.to_vorud());
        assert_eq!(Ok(1u32), super::FromVorud::from_vorud(&super::Vorud("babab-babad".to_string())));
    }
}
<commit_msg>Update unit test syntax<commit_after>use self::Decode::{V, C};

static VS: [char; 5] = ['a', 'e', 'i', 'o', 'u'];
static CS: [char; 14] = ['b', 'd', 'f', 'g', 'j', 'k', 'm', 'n',
    'p', 'r', 's', 't', 'v', 'z'];

#[derive(Copy)]
enum Decode {
    V(u16),
    C(u16),
}

static LUT: [Option<Decode>; 26] = [
    Some(V(0)),  // a (ASCII 97)
    Some(C(0)),  // b
    None,        // c
    Some(C(1)),  // d
    Some(V(1)),  // e
    Some(C(2)),  // f
    Some(C(3)),  // g
    None,        // h
    Some(V(2)),  // i
    Some(C(4)),  // j
    Some(C(5)),  // k
    None,        // l
    Some(C(6)),  // m
    Some(C(7)),  // n
    Some(V(3)),  // o
    Some(C(8)),  // p
    None,        // q
    Some(C(9)),  // r
    Some(C(10)), // s
    Some(C(11)), // t
    Some(V(4)),  // u
    Some(C(12)), // v
    None,        // w
    None,        // x
    None,        // y
    Some(C(13)), // z
];

fn vorud_chunk(data: u16) -> String {
    let (data, c5) = (data / CS.len() as u16, data % CS.len() as u16);
    let (data, v4) = (data / VS.len() as u16, data % VS.len() as u16);
    let (data, c3) = (data / CS.len() as u16, data % CS.len() as u16);
    let (data, v2) = (data / VS.len() as u16, data % VS.len() as u16);
    let (_, c1) =    (data / CS.len() as u16, data % CS.len() as u16);
    [CS[c1 as usize],
     VS[v2 as usize],
     CS[c3 as usize],
     VS[v4 as usize],
     CS[c5 as usize],
    ].iter().map(|&x| x).collect()
}

fn decode(c: char) -> Option<Decode> {
    let idx = c as isize - 97;
    if idx < 0 || idx >= LUT.len() as isize { return None; }
    LUT[idx as usize]
}

fn v(c: char) -> Result<u16, ()> {
    match decode(c) {
        Some(V(i)) => Ok(i),
        _ => Err(())
    }
}

fn c(c: char) -> Result<u16, ()> {
    match decode(c) {
        Some(C(i)) => Ok(i),
        _ => Err(())
    }
}

fn durov_chunk(s: &str) -> Result<u16, ()> {
    if s.len() != 5 { return Err(()); }
    let s: Vec<char> = s.chars().collect();
    let (mut ret, mut n) = (0u16, 1u16);
    ret += try!(c(s[4])) * n; n *= CS.len() as u16;
    ret += try!(v(s[3])) * n; n *= VS.len() as u16;
    ret += try!(c(s[2])) * n; n *= CS.len() as u16;
    ret += try!(v(s[1])) * n; n *= VS.len() as u16;
    ret += try!(c(s[0])) * n;

    Ok(ret)
}

#[derive(PartialEq, Eq, Debug)]
pub struct Vorud(String);

impl Vorud {
    pub fn new(s: String) -> Result<Vorud, ()> {
        if s.len() == 0 { return Ok(Vorud("".to_string())); }
        let ch = &s[..].chars().collect::<Vec<char>>();
        let mut i = 0;
        loop {
            if i > ch.len() - 5 { return Err(()); }
            try!(c(ch[i]));
            try!(v(ch[i + 1]));
            try!(c(ch[i + 2]));
            try!(v(ch[i + 3]));
            try!(c(ch[i + 4]));
            if i == ch.len() - 5 { return Ok(Vorud(s)); }
            if ch[i + 5] != '-' { return Err(()); }
            i += 6;
        }
    }
}

pub trait FromVorud<E> {
    fn from_vorud(v: &Vorud) -> Result<Self, E>;
}

pub trait ToVorud {
    fn to_vorud(&self) -> Vorud;
}

impl<'a> ToVorud for &'a [u8] {
    fn to_vorud(&self) -> Vorud {
        let mut ret = String::new();
        for i in 0..(self.len() / 2) {
            if ret.len() > 0 { ret.push_str("-"); }
            let b0 = self[i * 2] as u16;
            let b1 = if self.len() == i * 2 + 1 { 0 } else { self[i * 2 + 1] as u16 };
            ret.push_str(&vorud_chunk(b1 + (b0 << 8))[..]);
        }
        Vorud(ret)
    }
}

impl FromVorud<()> for Vec<u8> {
    fn from_vorud(&Vorud(ref s): &Vorud) -> Result<Vec<u8>, ()> {
        let mut ret = Vec::new();
        for chunk in (&s[..]).split('-') {
            let x = try!(durov_chunk(chunk));
            ret.push((x / 0xff) as u8);
            ret.push((x % 0xff) as u8);
        }
        Ok(ret)
    }
}

impl ToVorud for u32 {
    fn to_vorud(&self) -> Vorud {
        let mut vec = Vec::new();
        vec.push(((*self >> 24) % 0xff) as u8);
        vec.push(((*self >> 16) % 0xff) as u8);
        vec.push(((*self >> 8) % 0xff) as u8);
        vec.push((*self % 0xff) as u8);
        (&vec[..]).to_vorud()
    }
}

impl FromVorud<()> for u32 {
    fn from_vorud(v: &Vorud) -> Result<u32, ()> {
        let v: Vec<u8> = try!(FromVorud::from_vorud(v));
        if v.len() != 4 { return Err(()); }
        Ok(v[3] as u32 +
            ((v[2] as u32) << 8) +
            ((v[1] as u32) << 16) +
            ((v[0] as u32) << 24))
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn test_vorud() {
        use super::ToVorud;

        assert_eq!("babab", &super::vorud_chunk(0)[..]);
        assert_eq!("babad", &super::vorud_chunk(1)[..]);
        assert_eq!(Ok(0u16), super::durov_chunk("babab"));
        assert_eq!(Ok(1234u16), super::durov_chunk(&super::vorud_chunk(1234)[..]));
        assert_eq!("togas", &super::vorud_chunk(super::durov_chunk("togas").unwrap())[..]);
        assert_eq!(super::Vorud("babab-babab".to_string()), 0u32.to_vorud());
        assert_eq!(super::Vorud("babab-babad".to_string()), 1u32.to_vorud());
        assert_eq!(Ok(1u32), super::FromVorud::from_vorud(&super::Vorud("babab-babad".to_string())));
    }
}
<|endoftext|>


<commit_before>#![feature(async_await)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    async { x + y }.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

fn run_fut(mut fut: impl Future<Output=u32>, output: u32) {
    fn raw_waker_clone(_this: *const ()) -> RawWaker {
        panic!("unimplemented");
    }
    fn raw_waker_wake(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_wake_by_ref(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_drop(_this: *const ()) {}

    static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
        raw_waker_clone,
        raw_waker_wake,
        raw_waker_wake_by_ref,
        raw_waker_drop,
    );

    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output));
}

fn main() {
    let x = 5;
    run_fut(foo(&x, 7), 31);

    run_fut(build_aggregate(1, 2, 3, 4), 10);

    run_fut(includes_never(false, 4), 16);
}
<commit_msg>add async fn with partial initialization<commit_after>#![feature(async_await, never_type)]

use std::{future::Future, pin::Pin, task::Poll, ptr};
use std::task::{Waker, RawWaker, RawWakerVTable, Context};

// See if we can run a basic `async fn`
pub async fn foo(x: &u32, y: u32) -> u32 {
    let y = &y;
    let z = 9;
    let z = &z;
    let y = async { *y + *z }.await;
    let a = 10;
    let a = &a;
    *x + y + *a
}

async fn add(x: u32, y: u32) -> u32 {
    async { x + y }.await
}

async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
    let x = (add(a, b).await, add(c, d).await);
    x.0 + x.1
}

enum Never {}
fn never() -> Never {
    panic!()
}

async fn includes_never(crash: bool, x: u32) -> u32 {
    let mut result = async { x * x }.await;
    if !crash {
        return result;
    }
    #[allow(unused)]
    let bad = never();
    result *= async { x + x }.await;
    drop(bad);
    result
}

async fn partial_init(x: u32) -> u32 {
    #[allow(unreachable_code)]
    let _x: (String, !) = (String::new(), return async { x + x }.await);
}

fn run_fut(mut fut: impl Future<Output=u32>, output: u32) {
    fn raw_waker_clone(_this: *const ()) -> RawWaker {
        panic!("unimplemented");
    }
    fn raw_waker_wake(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_wake_by_ref(_this: *const ()) {
        panic!("unimplemented");
    }
    fn raw_waker_drop(_this: *const ()) {}

    static RAW_WAKER: RawWakerVTable = RawWakerVTable::new(
        raw_waker_clone,
        raw_waker_wake,
        raw_waker_wake_by_ref,
        raw_waker_drop,
    );

    let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) };
    let mut context = Context::from_waker(&waker);
    assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output));
}

fn main() {
    let x = 5;
    run_fut(foo(&x, 7), 31);

    run_fut(build_aggregate(1, 2, 3, 4), 10);

    run_fut(includes_never(false, 4), 16);

    run_fut(partial_init(4), 8);
}
<|endoftext|>


<commit_before>use std::cmp::Eq;
use std::fmt::Display;
use std::iter::FromIterator;

trait Parser<T: Display + Eq, E>: Sized {
    fn preview(&self) -> Option<&T>;
    fn consume(&mut self) -> Option<T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;

    fn export(&self) -> Self;
    fn import(&mut self, backup: Self);

    fn next(&mut self) -> Result<T, E> {
        self.consume().ok_or(self.error("unexpected eof"))
    }

    fn predicate<F>(&mut self, pred: F) -> Result<T, E>
        where F: Fn(&T) -> bool
    {
        let x = try!(self.next());
        if pred(&x) {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}", x)))
        }
    }

    fn atom(&mut self, expected: T) -> Result<T, E> {
        let x = try!(self.next());
        if x == expected {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}, expected {}", x, expected)))
        }
    }

    fn string<S, O>(&mut self, s: S) -> Result<O, E>
        where S: IntoIterator<Item = T>,
              O: FromIterator<T>
    {
        let mut res: Vec<T> = Vec::new();
        for c in s {
            match self.atom(c) {
                Ok(x) => res.push(x),
                Err(err) => return Err(err),
            }
        }
        Ok(O::from_iter(res))
    }

    fn try<O, F>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<O, E>
    {
        let backup = self.export();
        parser(self).map_err(|x| {
                                 self.import(backup);
                                 x
                             })
    }

    fn choose<O>(&mut self, parsers: &[&Fn(&mut Self) -> Result<O, E>]) -> Result<O, E> {
        for parser in parsers {
            match self.try(parser) {
                Ok(x) => return Ok(x),
                Err(_) => continue,
            }
        }

        Err(self.error(match self.preview() {
                           Some(x) => format!("unexpected token {}", x),
                           None => String::from("unexpected eof"),
                       }))
    }

    fn many<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn many1<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        res.push(try!(parser(self)));
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::vec_deque::VecDeque;

    struct TP {
        input: VecDeque<i32>,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP { input: VecDeque::from(input.to_vec()) }
        }
    }

    impl Parser<i32, String> for TP {
        fn consume(&mut self) -> Option<i32> {
            self.input.pop_front()
        }

        fn preview(&self) -> Option<&i32> {
            self.input.front()
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }

        fn export(&self) -> Self {
            TP { input: self.input.clone() }
        }

        fn import(&mut self, backup: Self) {
            self.input = backup.input;
        }
    }

    type TPR = Result<Vec<i32>, String>;

    fn err<T>(m: &str) -> Result<T, String> {
        Err(String::from(m))
    }

    #[test]
    fn next_success() {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(p.next(), Ok(1));
        assert_eq!(p.next(), Ok(2));
        assert_eq!(p.next(), Ok(3));
    }

    #[test]
    fn next_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.next(), err("unexpected eof"));
    }

    #[test]
    fn predicate_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(2));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(4));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(6));
    }

    #[test]
    fn predicate_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected eof"));
    }

    #[test]
    fn predicate_fail_not_satisfy() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected token 3"));
    }

    #[test]
    fn atom_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.atom(2), Ok(2));
        assert_eq!(p.atom(4), Ok(4));
        assert_eq!(p.atom(6), Ok(6));
    }

    #[test]
    fn atom_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.atom(2), err("unexpected eof"));
    }

    #[test]
    fn atom_fail_not_expected() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.atom(3), Ok(3));
        assert_eq!(p.atom(4), err("unexpected token 5, expected 4"));
    }

    #[test]
    fn string_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.string(vec![2, 4, 6]), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn string_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR, err("unexpected eof"));
    }

    #[test]
    fn string_fail_not_expected() {
        let mut p = TP::new(&[2, 5, 6]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR,
                   err("unexpected token 5, expected 4"));
    }

    #[test]
    fn try_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn try_fail_recover() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 7])) as TPR,
                   err("unexpected token 6, expected 7"));
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn choose_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 7]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![1, 2, 3]));
    }

    #[test]
    fn choose_success_with_recover() {
        let mut p = TP::new(&[4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![4, 5, 6]));
    }

    #[test]
    fn choose_fail_no_match() {
        let mut p = TP::new(&[5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn choose_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected eof"));
    }

    #[test]
    fn many_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many(&lt5), Ok(vec![4]));
        assert_eq!(TP::new(&[5, 6, 7, 8]).many(&lt5), Ok(vec![]));
    }

    #[test]
    fn many1_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many1(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many1(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many1(&lt5), Ok(vec![4]));
    }

    #[test]
    fn many1_fail() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[5, 6, 7, 8]).many1(&lt5) as TPR,
                   err("unexpected token 5"));
    }
}
<commit_msg>Add unimplemented optional combinator and its tests<commit_after>use std::cmp::Eq;
use std::fmt::Display;
use std::iter::FromIterator;

trait Parser<T: Display + Eq, E>: Sized {
    fn preview(&self) -> Option<&T>;
    fn consume(&mut self) -> Option<T>;
    fn current_pos(&self) -> (i32, i32);
    fn error<S: Into<String>>(&self, message: S) -> E;

    fn export(&self) -> Self;
    fn import(&mut self, backup: Self);

    fn next(&mut self) -> Result<T, E> {
        self.consume().ok_or(self.error("unexpected eof"))
    }

    fn predicate<F>(&mut self, pred: F) -> Result<T, E>
        where F: Fn(&T) -> bool
    {
        let x = try!(self.next());
        if pred(&x) {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}", x)))
        }
    }

    fn atom(&mut self, expected: T) -> Result<T, E> {
        let x = try!(self.next());
        if x == expected {
            Ok(x)
        } else {
            Err(self.error(format!("unexpected token {}, expected {}", x, expected)))
        }
    }

    fn string<S, O>(&mut self, s: S) -> Result<O, E>
        where S: IntoIterator<Item = T>,
              O: FromIterator<T>
    {
        let mut res: Vec<T> = Vec::new();
        for c in s {
            match self.atom(c) {
                Ok(x) => res.push(x),
                Err(err) => return Err(err),
            }
        }
        Ok(O::from_iter(res))
    }

    fn try<O, F>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<O, E>
    {
        let backup = self.export();
        parser(self).map_err(|x| {
                                 self.import(backup);
                                 x
                             })
    }

    fn choose<O>(&mut self, parsers: &[&Fn(&mut Self) -> Result<O, E>]) -> Result<O, E> {
        for parser in parsers {
            match self.try(parser) {
                Ok(x) => return Ok(x),
                Err(_) => continue,
            }
        }

        Err(self.error(match self.preview() {
                           Some(x) => format!("unexpected token {}", x),
                           None => String::from("unexpected eof"),
                       }))
    }

    fn many<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn many1<X, F, O>(&mut self, parser: F) -> Result<O, E>
        where F: Fn(&mut Self) -> Result<X, E>,
              O: FromIterator<X>
    {
        let mut res: Vec<X> = Vec::new();
        res.push(try!(parser(self)));
        loop {
            match self.try(&parser) {
                Ok(x) => res.push(x),
                Err(_) => break,
            }
        }
        Ok(O::from_iter(res))
    }

    fn optional<X, F>(&mut self, parser: F)
        where F: Fn(&mut Self) -> Result<X, E>
    {
        unimplemented!()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::vec_deque::VecDeque;

    struct TP {
        input: VecDeque<i32>,
    }

    impl TP {
        fn new(input: &[i32]) -> TP {
            TP { input: VecDeque::from(input.to_vec()) }
        }
    }

    impl Parser<i32, String> for TP {
        fn consume(&mut self) -> Option<i32> {
            self.input.pop_front()
        }

        fn preview(&self) -> Option<&i32> {
            self.input.front()
        }

        fn current_pos(&self) -> (i32, i32) {
            (0, 0)
        }

        fn error<S: Into<String>>(&self, message: S) -> String {
            message.into()
        }

        fn export(&self) -> Self {
            TP { input: self.input.clone() }
        }

        fn import(&mut self, backup: Self) {
            self.input = backup.input;
        }
    }

    type TPR = Result<Vec<i32>, String>;

    fn err<T>(m: &str) -> Result<T, String> {
        Err(String::from(m))
    }

    #[test]
    fn next_success() {
        let mut p = TP::new(&[1, 2, 3]);
        assert_eq!(p.next(), Ok(1));
        assert_eq!(p.next(), Ok(2));
        assert_eq!(p.next(), Ok(3));
    }

    #[test]
    fn next_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.next(), err("unexpected eof"));
    }

    #[test]
    fn predicate_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(2));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(4));
        assert_eq!(p.predicate(|x| x % 2 == 0), Ok(6));
    }

    #[test]
    fn predicate_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected eof"));
    }

    #[test]
    fn predicate_fail_not_satisfy() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.predicate(|x| x % 2 == 0), err("unexpected token 3"));
    }

    #[test]
    fn atom_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.atom(2), Ok(2));
        assert_eq!(p.atom(4), Ok(4));
        assert_eq!(p.atom(6), Ok(6));
    }

    #[test]
    fn atom_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.atom(2), err("unexpected eof"));
    }

    #[test]
    fn atom_fail_not_expected() {
        let mut p = TP::new(&[3, 5, 7]);
        assert_eq!(p.atom(3), Ok(3));
        assert_eq!(p.atom(4), err("unexpected token 5, expected 4"));
    }

    #[test]
    fn string_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.string(vec![2, 4, 6]), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn string_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR, err("unexpected eof"));
    }

    #[test]
    fn string_fail_not_expected() {
        let mut p = TP::new(&[2, 5, 6]);
        assert_eq!(p.string(vec![2, 4, 6]) as TPR,
                   err("unexpected token 5, expected 4"));
    }

    #[test]
    fn try_success() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn try_fail_recover() {
        let mut p = TP::new(&[2, 4, 6]);
        assert_eq!(p.try(|p| p.string(vec![2, 4, 7])) as TPR,
                   err("unexpected token 6, expected 7"));
        assert_eq!(p.try(|p| p.string(vec![2, 4, 6])), Ok(vec![2, 4, 6]));
    }

    #[test]
    fn choose_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 7]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![1, 2, 3]));
    }

    #[test]
    fn choose_success_with_recover() {
        let mut p = TP::new(&[4, 5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]),
                   Ok(vec![4, 5, 6]));
    }

    #[test]
    fn choose_fail_no_match() {
        let mut p = TP::new(&[5, 6, 7, 8, 9, 10]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn choose_fail_empty() {
        let mut p = TP::new(&[]);
        assert_eq!(p.choose(&[&|p| p.string(vec![1, 2, 3]),
                              &|p| p.string(vec![4, 5, 6, 8]),
                              &|p| p.string(vec![4, 5, 6])]) as TPR,
                   err("unexpected eof"));
    }

    #[test]
    fn many_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many(&lt5), Ok(vec![4]));
        assert_eq!(TP::new(&[5, 6, 7, 8]).many(&lt5), Ok(vec![]));
    }

    #[test]
    fn many1_success() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[1, 2, 3, 4]).many1(&lt5), Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[1, 2, 3, 4, 5, 6, 7, 8]).many1(&lt5),
                   Ok(vec![1, 2, 3, 4]));
        assert_eq!(TP::new(&[4, 5, 6, 7, 8]).many1(&lt5), Ok(vec![4]));
    }

    #[test]
    fn many1_fail() {
        let lt5 = |p: &mut TP| -> Result<i32, String> { p.predicate(|x| *x < 5) };

        assert_eq!(TP::new(&[5, 6, 7, 8]).many1(&lt5) as TPR,
                   err("unexpected token 5"));
    }

    #[test]
    fn optional_success() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(1));
        assert_eq!(p.string(vec![2, 3, 4]), Ok(vec![2, 3, 4]));
    }

    #[test]
    fn optional_success_without_matching() {
        let mut p = TP::new(&[1, 2, 3, 4, 5]);
        p.optional(|p| p.atom(2));
        assert_eq!(p.string(vec![1, 2, 3]), Ok(vec![1, 2, 3]));
    }
}
<|endoftext|>


<commit_before>use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_hir as hir;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_parse_format::{ParseMode, Parser, Piece};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::edition::Edition;
use rustc_span::{hygiene, sym, symbol::kw, symbol::SymbolStr, InnerSpan, Span, Symbol};

declare_lint! {
    /// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
    /// argument is not a formatting string.
    ///
    /// ### Example
    ///
    /// ```rust,no_run
    /// panic!("{}");
    /// panic!(123);
    /// ```
    ///
    /// {{produces}}
    ///
    /// ### Explanation
    ///
    /// In Rust 2018 and earlier, `panic!(x)` directly uses `x` as the message.
    /// That means that `panic!("{}")` panics with the message `"{}"` instead
    /// of using it as a formatting string, and `panic!(123)` will panic with
    /// an `i32` as message.
    ///
    /// Rust 2021 always interprets the first argument as format string.
    NON_FMT_PANICS,
    Warn,
    "detect single-argument panic!() invocations in which the argument is not a format string",
    @future_incompatible = FutureIncompatibleInfo {
        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
        explain_reason: false,
    };
    report_in_external_macro
}

declare_lint_pass!(NonPanicFmt => [NON_FMT_PANICS]);

impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
        if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
            if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
                if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
                    || Some(def_id) == cx.tcx.lang_items().panic_fn()
                    || Some(def_id) == cx.tcx.lang_items().panic_str()
                {
                    if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
                        if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
                            || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
                        {
                            check_panic(cx, f, arg);
                        }
                    }
                }
            }
        }
    }
}

fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
    if let hir::ExprKind::Lit(lit) = &arg.kind {
        if let ast::LitKind::Str(sym, _) = lit.node {
            // The argument is a string literal.
            check_panic_str(cx, f, arg, &sym.as_str());
            return;
        }
    }

    // The argument is *not* a string literal.

    let (span, panic, symbol_str) = panic_call(cx, f);

    if in_external_macro(cx.sess(), span) {
        // Nothing that can be done about it in the current crate.
        return;
    }

    // Find the span of the argument to `panic!()`, before expansion in the
    // case of `panic!(some_macro!())`.
    // We don't use source_callsite(), because this `panic!(..)` might itself
    // be expanded from another macro, in which case we want to stop at that
    // expansion.
    let mut arg_span = arg.span;
    let mut arg_macro = None;
    while !span.contains(arg_span) {
        let expn = arg_span.ctxt().outer_expn_data();
        if expn.is_root() {
            break;
        }
        arg_macro = expn.macro_def_id;
        arg_span = expn.call_site;
    }

    cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
        let mut l = lint.build("panic message is not a string literal");
        l.note("this usage of panic!() is deprecated; it will be a hard error in Rust 2021");
        l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
        if !span.contains(arg_span) {
            // No clue where this argument is coming from.
            l.emit();
            return;
        }
        if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
            // A case of `panic!(format!(..))`.
            l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol_str).as_str());
            if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                l.multipart_suggestion(
                    "remove the `format!(..)` macro call",
                    vec![
                        (arg_span.until(open.shrink_to_hi()), "".into()),
                        (close.until(arg_span.shrink_to_hi()), "".into()),
                    ],
                    Applicability::MachineApplicable,
                );
            }
        } else {
            let ty = cx.typeck_results().expr_ty(arg);
            // If this is a &str or String, we can confidently give the `"{}", ` suggestion.
            let is_str = matches!(
                ty.kind(),
                ty::Ref(_, r, _) if *r.kind() == ty::Str
            ) || matches!(
                (ty.ty_adt_def(), cx.tcx.get_diagnostic_item(sym::string_type)),
                (Some(ty_def), Some(string_type)) if ty_def.did == string_type
            );
            l.span_suggestion_verbose(
                arg_span.shrink_to_lo(),
                "add a \"{}\" format string to Display the message",
                "\"{}\", ".into(),
                if is_str {
                    Applicability::MachineApplicable
                } else {
                    Applicability::MaybeIncorrect
                },
            );
            if !is_str && panic == sym::std_panic_macro {
                if let Some((open, close, del)) = find_delimiters(cx, span) {
                    l.multipart_suggestion(
                        "or use std::panic::panic_any instead",
                        if del == '(' {
                            vec![(span.until(open), "std::panic::panic_any".into())]
                        } else {
                            vec![
                                (span.until(open.shrink_to_hi()), "std::panic::panic_any(".into()),
                                (close, ")".into()),
                            ]
                        },
                        Applicability::MachineApplicable,
                    );
                }
            }
        }
        l.emit();
    });
}

fn check_panic_str<'tcx>(
    cx: &LateContext<'tcx>,
    f: &'tcx hir::Expr<'tcx>,
    arg: &'tcx hir::Expr<'tcx>,
    fmt: &str,
) {
    if !fmt.contains(&['{', '}'][..]) {
        // No brace, no problem.
        return;
    }

    let (span, _, _) = panic_call(cx, f);

    if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
        // Nothing that can be done about it in the current crate.
        return;
    }

    let fmt_span = arg.span.source_callsite();

    let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
        Ok(snippet) => {
            // Count the number of `#`s between the `r` and `"`.
            let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
            (Some(snippet), style)
        }
        Err(_) => (None, None),
    };

    let mut fmt_parser =
        Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
    let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();

    if n_arguments > 0 && fmt_parser.errors.is_empty() {
        let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
            [] => vec![fmt_span],
            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
        };
        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
            let mut l = lint.build(match n_arguments {
                1 => "panic message contains an unused formatting placeholder",
                _ => "panic message contains unused formatting placeholders",
            });
            l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
            if span.contains(arg.span) {
                l.span_suggestion(
                    arg.span.shrink_to_hi(),
                    &format!("add the missing argument{}", pluralize!(n_arguments)),
                    ", ...".into(),
                    Applicability::HasPlaceholders,
                );
                l.span_suggestion(
                    arg.span.shrink_to_lo(),
                    "or add a \"{}\" format string to use the message literally",
                    "\"{}\", ".into(),
                    Applicability::MachineApplicable,
                );
            }
            l.emit();
        });
    } else {
        let brace_spans: Option<Vec<_>> =
            snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
                s.char_indices()
                    .filter(|&(_, c)| c == '{' || c == '}')
                    .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
                    .collect()
            });
        let msg = match &brace_spans {
            Some(v) if v.len() == 1 => "panic message contains a brace",
            _ => "panic message contains braces",
        };
        cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
            let mut l = lint.build(msg);
            l.note("this message is not used as a format string, but will be in Rust 2021");
            if span.contains(arg.span) {
                l.span_suggestion(
                    arg.span.shrink_to_lo(),
                    "add a \"{}\" format string to use the message literally",
                    "\"{}\", ".into(),
                    Applicability::MachineApplicable,
                );
            }
            l.emit();
        });
    }
}

/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
/// and the type of (opening) delimiter used.
fn find_delimiters<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<(Span, Span, char)> {
    let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?;
    let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
    let close = snippet.rfind(|c| ")]}".contains(c))?;
    Some((
        span.from_inner(InnerSpan { start: open, end: open + 1 }),
        span.from_inner(InnerSpan { start: close, end: close + 1 }),
        open_ch,
    ))
}

fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol, SymbolStr) {
    let mut expn = f.span.ctxt().outer_expn_data();

    let mut panic_macro = kw::Empty;

    // Unwrap more levels of macro expansion, as panic_2015!()
    // was likely expanded from panic!() and possibly from
    // [debug_]assert!().
    for &i in
        &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
    {
        let parent = expn.call_site.ctxt().outer_expn_data();
        if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
            expn = parent;
            panic_macro = i;
        }
    }

    let macro_symbol =
        if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind { symbol } else { sym::panic };
    (expn.call_site, panic_macro, macro_symbol.as_str())
}
<commit_msg>Use is_diagnostic_item instead of get_diagnostic_item.<commit_after>use crate::{LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::{pluralize, Applicability};
use rustc_hir as hir;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_parse_format::{ParseMode, Parser, Piece};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_span::edition::Edition;
use rustc_span::{hygiene, sym, symbol::kw, symbol::SymbolStr, InnerSpan, Span, Symbol};

declare_lint! {
    /// The `non_fmt_panics` lint detects `panic!(..)` invocations where the first
    /// argument is not a formatting string.
    ///
    /// ### Example
    ///
    /// ```rust,no_run
    /// panic!("{}");
    /// panic!(123);
    /// ```
    ///
    /// {{produces}}
    ///
    /// ### Explanation
    ///
    /// In Rust 2018 and earlier, `panic!(x)` directly uses `x` as the message.
    /// That means that `panic!("{}")` panics with the message `"{}"` instead
    /// of using it as a formatting string, and `panic!(123)` will panic with
    /// an `i32` as message.
    ///
    /// Rust 2021 always interprets the first argument as format string.
    NON_FMT_PANICS,
    Warn,
    "detect single-argument panic!() invocations in which the argument is not a format string",
    @future_incompatible = FutureIncompatibleInfo {
        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
        explain_reason: false,
    };
    report_in_external_macro
}

declare_lint_pass!(NonPanicFmt => [NON_FMT_PANICS]);

impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
        if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
            if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
                if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
                    || Some(def_id) == cx.tcx.lang_items().panic_fn()
                    || Some(def_id) == cx.tcx.lang_items().panic_str()
                {
                    if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
                        if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id)
                            || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id)
                        {
                            check_panic(cx, f, arg);
                        }
                    }
                }
            }
        }
    }
}

fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tcx hir::Expr<'tcx>) {
    if let hir::ExprKind::Lit(lit) = &arg.kind {
        if let ast::LitKind::Str(sym, _) = lit.node {
            // The argument is a string literal.
            check_panic_str(cx, f, arg, &sym.as_str());
            return;
        }
    }

    // The argument is *not* a string literal.

    let (span, panic, symbol_str) = panic_call(cx, f);

    if in_external_macro(cx.sess(), span) {
        // Nothing that can be done about it in the current crate.
        return;
    }

    // Find the span of the argument to `panic!()`, before expansion in the
    // case of `panic!(some_macro!())`.
    // We don't use source_callsite(), because this `panic!(..)` might itself
    // be expanded from another macro, in which case we want to stop at that
    // expansion.
    let mut arg_span = arg.span;
    let mut arg_macro = None;
    while !span.contains(arg_span) {
        let expn = arg_span.ctxt().outer_expn_data();
        if expn.is_root() {
            break;
        }
        arg_macro = expn.macro_def_id;
        arg_span = expn.call_site;
    }

    cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
        let mut l = lint.build("panic message is not a string literal");
        l.note("this usage of panic!() is deprecated; it will be a hard error in Rust 2021");
        l.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>");
        if !span.contains(arg_span) {
            // No clue where this argument is coming from.
            l.emit();
            return;
        }
        if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
            // A case of `panic!(format!(..))`.
            l.note(format!("the {}!() macro supports formatting, so there's no need for the format!() macro here", symbol_str).as_str());
            if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
                l.multipart_suggestion(
                    "remove the `format!(..)` macro call",
                    vec![
                        (arg_span.until(open.shrink_to_hi()), "".into()),
                        (close.until(arg_span.shrink_to_hi()), "".into()),
                    ],
                    Applicability::MachineApplicable,
                );
            }
        } else {
            let ty = cx.typeck_results().expr_ty(arg);
            // If this is a &str or String, we can confidently give the `"{}", ` suggestion.
            let is_str = matches!(
                ty.kind(),
                ty::Ref(_, r, _) if *r.kind() == ty::Str,
            ) || matches!(
                ty.ty_adt_def(),
                Some(ty_def) if cx.tcx.is_diagnostic_item(sym::string_type, ty_def.did),
            );
            l.span_suggestion_verbose(
                arg_span.shrink_to_lo(),
                "add a \"{}\" format string to Display the message",
                "\"{}\", ".into(),
                if is_str {
                    Applicability::MachineApplicable
                } else {
                    Applicability::MaybeIncorrect
                },
            );
            if !is_str && panic == sym::std_panic_macro {
                if let Some((open, close, del)) = find_delimiters(cx, span) {
                    l.multipart_suggestion(
                        "or use std::panic::panic_any instead",
                        if del == '(' {
                            vec![(span.until(open), "std::panic::panic_any".into())]
                        } else {
                            vec![
                                (span.until(open.shrink_to_hi()), "std::panic::panic_any(".into()),
                                (close, ")".into()),
                            ]
                        },
                        Applicability::MachineApplicable,
                    );
                }
            }
        }
        l.emit();
    });
}

fn check_panic_str<'tcx>(
    cx: &LateContext<'tcx>,
    f: &'tcx hir::Expr<'tcx>,
    arg: &'tcx hir::Expr<'tcx>,
    fmt: &str,
) {
    if !fmt.contains(&['{', '}'][..]) {
        // No brace, no problem.
        return;
    }

    let (span, _, _) = panic_call(cx, f);

    if in_external_macro(cx.sess(), span) && in_external_macro(cx.sess(), arg.span) {
        // Nothing that can be done about it in the current crate.
        return;
    }

    let fmt_span = arg.span.source_callsite();

    let (snippet, style) = match cx.sess().parse_sess.source_map().span_to_snippet(fmt_span) {
        Ok(snippet) => {
            // Count the number of `#`s between the `r` and `"`.
            let style = snippet.strip_prefix('r').and_then(|s| s.find('"'));
            (Some(snippet), style)
        }
        Err(_) => (None, None),
    };

    let mut fmt_parser =
        Parser::new(fmt.as_ref(), style, snippet.clone(), false, ParseMode::Format);
    let n_arguments = (&mut fmt_parser).filter(|a| matches!(a, Piece::NextArgument(_))).count();

    if n_arguments > 0 && fmt_parser.errors.is_empty() {
        let arg_spans: Vec<_> = match &fmt_parser.arg_places[..] {
            [] => vec![fmt_span],
            v => v.iter().map(|span| fmt_span.from_inner(*span)).collect(),
        };
        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
            let mut l = lint.build(match n_arguments {
                1 => "panic message contains an unused formatting placeholder",
                _ => "panic message contains unused formatting placeholders",
            });
            l.note("this message is not used as a format string when given without arguments, but will be in Rust 2021");
            if span.contains(arg.span) {
                l.span_suggestion(
                    arg.span.shrink_to_hi(),
                    &format!("add the missing argument{}", pluralize!(n_arguments)),
                    ", ...".into(),
                    Applicability::HasPlaceholders,
                );
                l.span_suggestion(
                    arg.span.shrink_to_lo(),
                    "or add a \"{}\" format string to use the message literally",
                    "\"{}\", ".into(),
                    Applicability::MachineApplicable,
                );
            }
            l.emit();
        });
    } else {
        let brace_spans: Option<Vec<_>> =
            snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
                s.char_indices()
                    .filter(|&(_, c)| c == '{' || c == '}')
                    .map(|(i, _)| fmt_span.from_inner(InnerSpan { start: i, end: i + 1 }))
                    .collect()
            });
        let msg = match &brace_spans {
            Some(v) if v.len() == 1 => "panic message contains a brace",
            _ => "panic message contains braces",
        };
        cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
            let mut l = lint.build(msg);
            l.note("this message is not used as a format string, but will be in Rust 2021");
            if span.contains(arg.span) {
                l.span_suggestion(
                    arg.span.shrink_to_lo(),
                    "add a \"{}\" format string to use the message literally",
                    "\"{}\", ".into(),
                    Applicability::MachineApplicable,
                );
            }
            l.emit();
        });
    }
}

/// Given the span of `some_macro!(args);`, gives the span of `(` and `)`,
/// and the type of (opening) delimiter used.
fn find_delimiters<'tcx>(cx: &LateContext<'tcx>, span: Span) -> Option<(Span, Span, char)> {
    let snippet = cx.sess().parse_sess.source_map().span_to_snippet(span).ok()?;
    let (open, open_ch) = snippet.char_indices().find(|&(_, c)| "([{".contains(c))?;
    let close = snippet.rfind(|c| ")]}".contains(c))?;
    Some((
        span.from_inner(InnerSpan { start: open, end: open + 1 }),
        span.from_inner(InnerSpan { start: close, end: close + 1 }),
        open_ch,
    ))
}

fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span, Symbol, SymbolStr) {
    let mut expn = f.span.ctxt().outer_expn_data();

    let mut panic_macro = kw::Empty;

    // Unwrap more levels of macro expansion, as panic_2015!()
    // was likely expanded from panic!() and possibly from
    // [debug_]assert!().
    for &i in
        &[sym::std_panic_macro, sym::core_panic_macro, sym::assert_macro, sym::debug_assert_macro]
    {
        let parent = expn.call_site.ctxt().outer_expn_data();
        if parent.macro_def_id.map_or(false, |id| cx.tcx.is_diagnostic_item(i, id)) {
            expn = parent;
            panic_macro = i;
        }
    }

    let macro_symbol =
        if let hygiene::ExpnKind::Macro(_, symbol) = expn.kind { symbol } else { sym::panic };
    (expn.call_site, panic_macro, macro_symbol.as_str())
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc;
use profile::time;
use profile_traits::time::ProfilerMsg;

#[test]
fn time_profiler_smoke_test() {
    let chan = time::Profiler::create(&None, None);
    assert!(true, "Can create the profiler thread");

    let (ipcchan, _ipcport) = ipc::channel().unwrap();
    chan.send(ProfilerMsg::Exit(ipcchan));
    assert!(true, "Can tell the profiler thread to exit");
}

#[test]
fn time_profiler_stats_test() {
    let even_data = vec![1.234, 3.24567, 3.54578, 5.0, 5.324, 7.345,
                         9.2345, 10.2342345, 13.2599, 15.0];
    let (even_mean, even_median, even_min, even_max) = time::Profiler::get_statistics(&even_data);

    assert_eq!(7.34230845, even_mean);
    assert_eq!(7.345, even_median);
    assert_eq!(1.234, even_min);
    assert_eq!(15.0, even_max);

    let odd_data = vec![1.234, 3.24567, 3.54578, 5.0, 5.324, 7.345,
                        9.2345, 10.2342345, 13.2599];
    let (odd_mean, odd_median, odd_min, odd_max) = time::Profiler::get_statistics(&odd_data);

    assert_eq!(6.491453833333334, odd_mean);
    assert_eq!(5.324, odd_median);
    assert_eq!(1.234, odd_min);
    assert_eq!(13.2599, odd_max);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn time_profiler_unsorted_stats_test() {
    let unsorted_data = vec![5.0, 7.5, 1.0, 8.9];
    time::Profiler::get_statistics(&unsorted_data);
}
<commit_msg>Add test to assert that servo panics when the length of a given data is zero.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use ipc_channel::ipc;
use profile::time;
use profile_traits::time::ProfilerMsg;

#[test]
fn time_profiler_smoke_test() {
    let chan = time::Profiler::create(&None, None);
    assert!(true, "Can create the profiler thread");

    let (ipcchan, _ipcport) = ipc::channel().unwrap();
    chan.send(ProfilerMsg::Exit(ipcchan));
    assert!(true, "Can tell the profiler thread to exit");
}

#[test]
fn time_profiler_stats_test() {
    let even_data = vec![1.234, 3.24567, 3.54578, 5.0, 5.324, 7.345,
                         9.2345, 10.2342345, 13.2599, 15.0];
    let (even_mean, even_median, even_min, even_max) = time::Profiler::get_statistics(&even_data);

    assert_eq!(7.34230845, even_mean);
    assert_eq!(7.345, even_median);
    assert_eq!(1.234, even_min);
    assert_eq!(15.0, even_max);

    let odd_data = vec![1.234, 3.24567, 3.54578, 5.0, 5.324, 7.345,
                        9.2345, 10.2342345, 13.2599];
    let (odd_mean, odd_median, odd_min, odd_max) = time::Profiler::get_statistics(&odd_data);

    assert_eq!(6.491453833333334, odd_mean);
    assert_eq!(5.324, odd_median);
    assert_eq!(1.234, odd_min);
    assert_eq!(13.2599, odd_max);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn time_profiler_unsorted_stats_test() {
    let unsorted_data = vec![5.0, 7.5, 1.0, 8.9];
    time::Profiler::get_statistics(&unsorted_data);
}

#[cfg(debug_assertions)]
#[test]
#[should_panic]
fn time_profiler_data_len_zero() {
    let zero_data = vec![];
    time::Profiler::get_statistics(&zero_data);
}
<|endoftext|>


<commit_before>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;

use bindgen::{BindgenOptions, Bindings, ClangVersion, LinkType, clang_version};
use std::default::Default;
use std::env;
use std::fs;
use std::io;
use std::path;
use std::process;

const USAGE: &'static str = "
Usage:
    bindgen [options] \
        [--link=<lib>...] \
        [--static-link=<lib>...] \
        [--framework-link=<framework>...] \
        [--raw-line=<raw>...] \
        [--opaque-type=<type>...] \
        [--blacklist-type=<type>...] \
        [--whitelist-type=<type>...] \
        [--whitelist-function=<name>...] \
        [--whitelist-var=<name>...] \
        <input-header> \
        [-- <clang-args>...]

    bindgen (-h | --help)

Options:
    -h, --help                    Display this help message.

    -l=<lib>, --link=<lib>        Link to a dynamic library, can be provided
                                  multiple times.

    --static-link=<lib>           Link to a static library, can be provided
                                  multiple times.

    --framework-link=<framework>  Link to a framework.

    -o=<output-rust-file>         Write bindings to <output-rust-file>
                                  (defaults to stdout)

    --builtins                    Output bindings for builtin definitions (for
                                  example __builtin_va_list)

    --ignore-functions            Don't generate bindings for functions and
                                  methods. This is useful when you only care
                                  about struct layouts.

    --ignore-methods              Avoid generating all kind of methods.

    --enable-cxx-namespaces       Enable support for C++ namespaces.

    --emit-clang-ast              Output the ast (for debugging purposes)

    --use-msvc-mangling           Handle MSVC C++ ABI mangling; requires that
                                  target be set to (i686|x86_64)-pc-win32

    --raw-line=<raw>              Add a raw line at the beginning of the output.

    --no-unstable-rust            Avoid generating unstable rust.

    --use-core                    Use built-in types from core instead of std.

    --ctypes-prefix=<prefix>      Use the given prefix before the raw types
                                  instead of ::std::os::raw::.

    --opaque-type=<type>          Mark a type as opaque.

    --blacklist-type=<type>       Mark a type as hidden.

    --whitelist-type=<type>       Whitelist the type. If this set or any other
                                  of the whitelisting sets is not empty, then
                                  all the non-whitelisted types (or dependant)
                                  won't be generated.

    --whitelist-function=<regex>  Whitelist all the free-standing functions
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    --whitelist-var=<regex>       Whitelist all the free-standing variables
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    --dummy-uses=<path>           For testing purposes, generate a C/C++ file
                                  containing dummy uses of all types defined in
                                  the input header.

    <clang-args>                  Options other than stated above are passed
                                  directly through to clang.
";

// FIXME(emilio): Replace this with docopt if/when they fix their exponential
// algorithm for argument parsing.
//
// FIXME(fitzgen): Switch from `BindgenOptions` to the non-deprecated `Builder`.
#[allow(deprecated)]
fn parse_args_or_exit(args: Vec<String>) -> (BindgenOptions, Box<io::Write>) {
    let mut options = BindgenOptions::default();
    let mut dest_file = None;
    let mut source_file = None;

    let mut iter = args.into_iter().skip(1);
    loop {
        let next = match iter.next() {
            Some(arg) => arg,
            _ => break,
        };

        match &*next {
            "-h" | "--help" => {
                println!("{}", USAGE);
                process::exit(0);
            }
            "-l" | "--link" => {
                let lib = iter.next().expect("--link needs an argument");
                options.links.push((lib, LinkType::Default));
            }
            "--static-link" => {
                let lib = iter.next().expect("--static-link needs an argument");
                options.links.push((lib, LinkType::Static));
            }
            "--framework-link" => {
                let lib = iter.next()
                    .expect("--framework-link needs an argument");
                options.links.push((lib, LinkType::Framework));
            }
            "--raw-line" => {
                let line = iter.next().expect("--raw-line needs an argument");
                options.raw_lines.push(line);
            }
            "--opaque-type" => {
                let ty_canonical_name = iter.next()
                    .expect("--opaque-type expects a type");
                options.opaque_types.insert(ty_canonical_name);
            }
            "--blacklist-type" => {
                let ty_canonical_name = iter.next()
                    .expect("--blacklist-type expects a type");
                options.hidden_types.insert(ty_canonical_name);
            }
            "--whitelist-type" => {
                let ty_pat = iter.next()
                    .expect("--whitelist-type expects a type pattern");
                options.whitelisted_types.insert(&ty_pat);
            }
            "--whitelist-function" => {
                let function_pat = iter.next()
                    .expect("--whitelist-function expects a pattern");
                options.whitelisted_functions.insert(&function_pat);
            }
            "--whitelist-var" => {
                let var_pat = iter.next()
                    .expect("--whitelist-var expects a pattern");
                options.whitelisted_vars.insert(&var_pat);
            }
            "--" => {
                while let Some(clang_arg) = iter.next() {
                    options.clang_args.push(clang_arg);
                }
            }
            "--output" | "-o" => {
                let out_name = iter.next().expect("-o expects a file name");
                dest_file = Some(out_name);
            }
            "--builtins" => {
                options.builtins = true;
            }
            "--ignore-functions" => {
                options.ignore_functions = true;
            }
            "--ignore-methods" => {
                options.ignore_methods = true;
            }
            "--enable-cxx-namespaces" => {
                options.enable_cxx_namespaces = true;
            }
            "--no-unstable-rust" => {
                options.unstable_rust = false;
            }
            "--use-core" => {
                options.use_core = true;
            }
            "--ctypes-prefix" => {
                let prefix = iter.next()
                    .expect("--ctypes-prefix expects a prefix after it");
                options.ctypes_prefix = Some(prefix);
            }
            "--emit-clang-ast" => {
                options.emit_ast = true;
            }
            "--use-msvc-mangling" => {
                options.msvc_mangling = true;
            }
            "--dummy-uses" => {
                let dummy_path = iter.next()
                    .expect("--dummy-uses expects a file path");
                options.dummy_uses = Some(dummy_path);
            }
            other if source_file.is_none() => {
                source_file = Some(other.into());
            }
            other => {
                panic!("Unknown option: \"{}\"", other);
            }
        }
    }

    if let Some(source_file) = source_file.take() {
        options.clang_args.push(source_file);
        options.input_header = options.clang_args.last().cloned();
    } else {
        options.input_header = options.clang_args
            .iter()
            .find(|arg| arg.ends_with(".h") || arg.ends_with(".hpp"))
            .cloned();
    }

    let out = if let Some(ref path_name) = dest_file {
        let path = path::Path::new(path_name);
        let file = fs::File::create(path).expect("Opening out file failed");
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    (options, out)
}

pub fn main() {
    log::set_logger(|max_log_level| {
            use env_logger::Logger;
            let env_logger = Logger::new();
            max_log_level.set(env_logger.filter());
            Box::new(env_logger)
        })
        .expect("Failed to set logger.");

    let mut bind_args: Vec<_> = env::args().collect();

    let version = clang_version();
    let expected_version = if cfg!(feature = "llvm_stable") {
        (3, 8)
    } else {
        (3, 9)
    };

    info!("Clang Version: {}", version.full);

    match version.parsed {
        None => warn!("Couldn't parse libclang version"),
        Some(version) if version != expected_version => {
            error!("Using clang {:?}, expected {:?}",
                   version,
                   expected_version);
        }
        _ => {}
    }

    if let Some(clang) = clang_sys::support::Clang::find(None) {
        let has_clang_args =
            bind_args.iter().rposition(|arg| *arg == "--").is_some();
        if !has_clang_args {
            bind_args.push("--".to_owned());
        }

        // If --target is specified, assume caller knows what they're doing and
        // don't mess with
        // include paths for them
        let has_target_arg = bind_args.iter()
            .rposition(|arg| arg.starts_with("--target"))
            .is_some();
        if !has_target_arg {
            // TODO: distinguish C and C++ paths? C++'s should be enough, I
            // guess.
            for path in clang.cpp_search_paths.into_iter() {
                if let Ok(path) = path.into_os_string().into_string() {
                    bind_args.push("-isystem".to_owned());
                    bind_args.push(path);
                }
            }
        }
    }

    let (options, out) = parse_args_or_exit(bind_args);

    let mut bindings = Bindings::generate(options, None)
        .expect("Unable to generate bindings");

    bindings.write_dummy_uses()
        .expect("Unable to write dummy uses to file.");

    bindings.write(out)
        .expect("Unable to write bindings to file.");
}
<commit_msg>bin: Remove unused import.<commit_after>#![crate_name = "bindgen"]
#![crate_type = "bin"]

extern crate bindgen;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;

use bindgen::{BindgenOptions, Bindings, LinkType, clang_version};
use std::default::Default;
use std::env;
use std::fs;
use std::io;
use std::path;
use std::process;

const USAGE: &'static str = "
Usage:
    bindgen [options] \
        [--link=<lib>...] \
        [--static-link=<lib>...] \
        [--framework-link=<framework>...] \
        [--raw-line=<raw>...] \
        [--opaque-type=<type>...] \
        [--blacklist-type=<type>...] \
        [--whitelist-type=<type>...] \
        [--whitelist-function=<name>...] \
        [--whitelist-var=<name>...] \
        <input-header> \
        [-- <clang-args>...]

    bindgen (-h | --help)

Options:
    -h, --help                    Display this help message.

    -l=<lib>, --link=<lib>        Link to a dynamic library, can be provided
                                  multiple times.

    --static-link=<lib>           Link to a static library, can be provided
                                  multiple times.

    --framework-link=<framework>  Link to a framework.

    -o=<output-rust-file>         Write bindings to <output-rust-file>
                                  (defaults to stdout)

    --builtins                    Output bindings for builtin definitions (for
                                  example __builtin_va_list)

    --ignore-functions            Don't generate bindings for functions and
                                  methods. This is useful when you only care
                                  about struct layouts.

    --ignore-methods              Avoid generating all kind of methods.

    --enable-cxx-namespaces       Enable support for C++ namespaces.

    --emit-clang-ast              Output the ast (for debugging purposes)

    --use-msvc-mangling           Handle MSVC C++ ABI mangling; requires that
                                  target be set to (i686|x86_64)-pc-win32

    --raw-line=<raw>              Add a raw line at the beginning of the output.

    --no-unstable-rust            Avoid generating unstable rust.

    --use-core                    Use built-in types from core instead of std.

    --ctypes-prefix=<prefix>      Use the given prefix before the raw types
                                  instead of ::std::os::raw::.

    --opaque-type=<type>          Mark a type as opaque.

    --blacklist-type=<type>       Mark a type as hidden.

    --whitelist-type=<type>       Whitelist the type. If this set or any other
                                  of the whitelisting sets is not empty, then
                                  all the non-whitelisted types (or dependant)
                                  won't be generated.

    --whitelist-function=<regex>  Whitelist all the free-standing functions
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    --whitelist-var=<regex>       Whitelist all the free-standing variables
                                  matching <regex>.  Same behavior on emptyness
                                  than the type whitelisting.

    --dummy-uses=<path>           For testing purposes, generate a C/C++ file
                                  containing dummy uses of all types defined in
                                  the input header.

    <clang-args>                  Options other than stated above are passed
                                  directly through to clang.
";

// FIXME(emilio): Replace this with docopt if/when they fix their exponential
// algorithm for argument parsing.
//
// FIXME(fitzgen): Switch from `BindgenOptions` to the non-deprecated `Builder`.
#[allow(deprecated)]
fn parse_args_or_exit(args: Vec<String>) -> (BindgenOptions, Box<io::Write>) {
    let mut options = BindgenOptions::default();
    let mut dest_file = None;
    let mut source_file = None;

    let mut iter = args.into_iter().skip(1);
    loop {
        let next = match iter.next() {
            Some(arg) => arg,
            _ => break,
        };

        match &*next {
            "-h" | "--help" => {
                println!("{}", USAGE);
                process::exit(0);
            }
            "-l" | "--link" => {
                let lib = iter.next().expect("--link needs an argument");
                options.links.push((lib, LinkType::Default));
            }
            "--static-link" => {
                let lib = iter.next().expect("--static-link needs an argument");
                options.links.push((lib, LinkType::Static));
            }
            "--framework-link" => {
                let lib = iter.next()
                    .expect("--framework-link needs an argument");
                options.links.push((lib, LinkType::Framework));
            }
            "--raw-line" => {
                let line = iter.next().expect("--raw-line needs an argument");
                options.raw_lines.push(line);
            }
            "--opaque-type" => {
                let ty_canonical_name = iter.next()
                    .expect("--opaque-type expects a type");
                options.opaque_types.insert(ty_canonical_name);
            }
            "--blacklist-type" => {
                let ty_canonical_name = iter.next()
                    .expect("--blacklist-type expects a type");
                options.hidden_types.insert(ty_canonical_name);
            }
            "--whitelist-type" => {
                let ty_pat = iter.next()
                    .expect("--whitelist-type expects a type pattern");
                options.whitelisted_types.insert(&ty_pat);
            }
            "--whitelist-function" => {
                let function_pat = iter.next()
                    .expect("--whitelist-function expects a pattern");
                options.whitelisted_functions.insert(&function_pat);
            }
            "--whitelist-var" => {
                let var_pat = iter.next()
                    .expect("--whitelist-var expects a pattern");
                options.whitelisted_vars.insert(&var_pat);
            }
            "--" => {
                while let Some(clang_arg) = iter.next() {
                    options.clang_args.push(clang_arg);
                }
            }
            "--output" | "-o" => {
                let out_name = iter.next().expect("-o expects a file name");
                dest_file = Some(out_name);
            }
            "--builtins" => {
                options.builtins = true;
            }
            "--ignore-functions" => {
                options.ignore_functions = true;
            }
            "--ignore-methods" => {
                options.ignore_methods = true;
            }
            "--enable-cxx-namespaces" => {
                options.enable_cxx_namespaces = true;
            }
            "--no-unstable-rust" => {
                options.unstable_rust = false;
            }
            "--use-core" => {
                options.use_core = true;
            }
            "--ctypes-prefix" => {
                let prefix = iter.next()
                    .expect("--ctypes-prefix expects a prefix after it");
                options.ctypes_prefix = Some(prefix);
            }
            "--emit-clang-ast" => {
                options.emit_ast = true;
            }
            "--use-msvc-mangling" => {
                options.msvc_mangling = true;
            }
            "--dummy-uses" => {
                let dummy_path = iter.next()
                    .expect("--dummy-uses expects a file path");
                options.dummy_uses = Some(dummy_path);
            }
            other if source_file.is_none() => {
                source_file = Some(other.into());
            }
            other => {
                panic!("Unknown option: \"{}\"", other);
            }
        }
    }

    if let Some(source_file) = source_file.take() {
        options.clang_args.push(source_file);
        options.input_header = options.clang_args.last().cloned();
    } else {
        options.input_header = options.clang_args
            .iter()
            .find(|arg| arg.ends_with(".h") || arg.ends_with(".hpp"))
            .cloned();
    }

    let out = if let Some(ref path_name) = dest_file {
        let path = path::Path::new(path_name);
        let file = fs::File::create(path).expect("Opening out file failed");
        Box::new(io::BufWriter::new(file)) as Box<io::Write>
    } else {
        Box::new(io::BufWriter::new(io::stdout())) as Box<io::Write>
    };

    (options, out)
}

pub fn main() {
    log::set_logger(|max_log_level| {
            use env_logger::Logger;
            let env_logger = Logger::new();
            max_log_level.set(env_logger.filter());
            Box::new(env_logger)
        })
        .expect("Failed to set logger.");

    let mut bind_args: Vec<_> = env::args().collect();

    let version = clang_version();
    let expected_version = if cfg!(feature = "llvm_stable") {
        (3, 8)
    } else {
        (3, 9)
    };

    info!("Clang Version: {}", version.full);

    match version.parsed {
        None => warn!("Couldn't parse libclang version"),
        Some(version) if version != expected_version => {
            error!("Using clang {:?}, expected {:?}",
                   version,
                   expected_version);
        }
        _ => {}
    }

    if let Some(clang) = clang_sys::support::Clang::find(None) {
        let has_clang_args =
            bind_args.iter().rposition(|arg| *arg == "--").is_some();
        if !has_clang_args {
            bind_args.push("--".to_owned());
        }

        // If --target is specified, assume caller knows what they're doing and
        // don't mess with
        // include paths for them
        let has_target_arg = bind_args.iter()
            .rposition(|arg| arg.starts_with("--target"))
            .is_some();
        if !has_target_arg {
            // TODO: distinguish C and C++ paths? C++'s should be enough, I
            // guess.
            for path in clang.cpp_search_paths.into_iter() {
                if let Ok(path) = path.into_os_string().into_string() {
                    bind_args.push("-isystem".to_owned());
                    bind_args.push(path);
                }
            }
        }
    }

    let (options, out) = parse_args_or_exit(bind_args);

    let mut bindings = Bindings::generate(options, None)
        .expect("Unable to generate bindings");

    bindings.write_dummy_uses()
        .expect("Unable to write dummy uses to file.");

    bindings.write(out)
        .expect("Unable to write bindings to file.");
}
<|endoftext|>


<commit_before>#![feature(rustc_private)]

extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_target;

use rustc_data_structures::profiling::print_time_passes_entry;
use rustc_interface::interface;
use rustc_session::config::ErrorOutputType;
use rustc_session::early_error;
use rustc_target::spec::PanicStrategy;

#[derive(Default)]
pub struct CraneliftPassesCallbacks {
    time_passes: bool,
}

impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        // If a --prints=... option has been given, we don't print the "total"
        // time because it will mess up the --prints output. See #64339.
        self.time_passes = config.opts.prints.is_empty()
            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);

        config.opts.cg.panic = Some(PanicStrategy::Abort);
        config.opts.debugging_opts.panic_abort_tests = true;
        config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| {
            std::env::current_exe()
                .unwrap()
                .parent()
                .unwrap()
                .parent()
                .unwrap()
                .to_owned()
        }));
    }
}

fn main() {
    let start = std::time::Instant::now();
    rustc_driver::init_rustc_env_logger();
    let mut callbacks = CraneliftPassesCallbacks::default();
    rustc_driver::install_ice_hook();
    let exit_code = rustc_driver::catch_with_exit_code(|| {
        let args = std::env::args_os()
            .enumerate()
            .map(|(i, arg)| {
                arg.into_string().unwrap_or_else(|arg| {
                    early_error(
                        ErrorOutputType::default(),
                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
                    )
                })
            })
            .collect::<Vec<_>>();
        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
        run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
        })));
        run_compiler.run()
    });
    // The extra `\t` is necessary to align this label with the others.
    print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
    std::process::exit(exit_code)
}
<commit_msg>Sync from rust d60b29d1ae8147538b8d542f7ffcc03b48e2cbda<commit_after>#![feature(rustc_private)]

extern crate rustc_data_structures;
extern crate rustc_driver;
extern crate rustc_interface;
extern crate rustc_session;
extern crate rustc_target;

use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_interface::interface;
use rustc_session::config::ErrorOutputType;
use rustc_session::early_error;
use rustc_target::spec::PanicStrategy;

#[derive(Default)]
pub struct CraneliftPassesCallbacks {
    time_passes: bool,
}

impl rustc_driver::Callbacks for CraneliftPassesCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        // If a --prints=... option has been given, we don't print the "total"
        // time because it will mess up the --prints output. See #64339.
        self.time_passes = config.opts.prints.is_empty()
            && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time);

        config.opts.cg.panic = Some(PanicStrategy::Abort);
        config.opts.debugging_opts.panic_abort_tests = true;
        config.opts.maybe_sysroot = Some(config.opts.maybe_sysroot.clone().unwrap_or_else(|| {
            std::env::current_exe()
                .unwrap()
                .parent()
                .unwrap()
                .parent()
                .unwrap()
                .to_owned()
        }));
    }
}

fn main() {
    let start_time = std::time::Instant::now();
    let start_rss = get_resident_set_size();
    rustc_driver::init_rustc_env_logger();
    let mut callbacks = CraneliftPassesCallbacks::default();
    rustc_driver::install_ice_hook();
    let exit_code = rustc_driver::catch_with_exit_code(|| {
        let args = std::env::args_os()
            .enumerate()
            .map(|(i, arg)| {
                arg.into_string().unwrap_or_else(|arg| {
                    early_error(
                        ErrorOutputType::default(),
                        &format!("Argument {} is not valid Unicode: {:?}", i, arg),
                    )
                })
            })
            .collect::<Vec<_>>();
        let mut run_compiler = rustc_driver::RunCompiler::new(&args, &mut callbacks);
        run_compiler.set_make_codegen_backend(Some(Box::new(move |_| {
            Box::new(rustc_codegen_cranelift::CraneliftCodegenBackend { config: None })
        })));
        run_compiler.run()
    });

    if callbacks.time_passes {
        let end_rss = get_resident_set_size();
        print_time_passes_entry("total", start_time.elapsed(), start_rss, end_rss);
    }

    std::process::exit(exit_code)
}
<|endoftext|>