diff --git a/benchmark/benchmark.bzl b/benchmark/benchmark.bzl index c85df7858..38ab7c3f3 100644 --- a/benchmark/benchmark.bzl +++ b/benchmark/benchmark.bzl @@ -30,7 +30,8 @@ def reduction_golden_test( statistics_file = None, progress_dump_file = None, golden_progress_file = None, - enable_query_caching = None): + enable_query_caching = None, + enable_edit_caching = None): if "/" in source_file: fail("The source file should be in the current folder.") if "/" in test_script: @@ -49,6 +50,7 @@ def reduction_golden_test( statistics_file = statistics_file, progress_dump_file = progress_dump_file, enable_query_caching = enable_query_caching, + enable_edit_caching = enable_edit_caching, code_format = "COMPACT_ORIG_FORMAT", ) diff --git a/benchmark/rust-44800/.gitignore b/benchmark/rust-44800/.gitignore new file mode 100644 index 000000000..283c8a008 --- /dev/null +++ b/benchmark/rust-44800/.gitignore @@ -0,0 +1,6 @@ +/* +!r.sh +!mutant.rs +!info.properties +!.gitignore + diff --git a/benchmark/rust-44800/mutant.rs b/benchmark/rust-44800/mutant.rs new file mode 100644 index 000000000..dfd3e6d1f --- /dev/null +++ b/benchmark/rust-44800/mutant.rs @@ -0,0 +1,152 @@ +use std::collections::VecDeque; +use std::fmt; + +pub struct Packet +{ + pub payload: VecDeque, +} + +pub struct Header +{ + pub data: Vec, +} + +impl Packet +{ + pub fn new() -> Self + { + let payload = VecDeque::with_capacity(32); + Packet{payload} + } + + pub fn len(&self) -> usize + { + self.payload.len() + } + + pub fn push_header(&mut self, header: &Header) + { + self.payload.reserve(header.data.len()); + for b in header.data.iter().rev() { + self.payload.push_front(*b); + } + } + + pub fn push_back_bytes(&mut self, data: &[u8]) + { + self.payload.extend(data.iter()); + } +} + +impl fmt::Debug for Packet +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + let mut bytes = String::with_capacity(3*self.len()); + for i in 0..self.payload.len() { + bytes.push_str(&format!(" {:02X}", self.payload[i])); + } + + write!(f, "{}", bytes) + } +} + +impl Header +{ + pub fn new() -> Self + { + let data = Vec::with_capacity(20); + Header{data} + } + + pub fn with_capacity(capacity: usize) -> Self + { + let data = Vec::with_capacity(capacity); + Header{data} + } + + pub fn push8(&mut self, data: u8) + { + self.data.push(data); + } + + pub fn push16(&mut self, data: u16) + { + self.data.push((data >> 8) as u8); + self.data.push((data & 0xFF) as u8); + } + + pub fn push32(&mut self, data: u32) + { + self.data.push((data >> 24) as u8); + self.data.push(((data >> 16) & 0xFF) as u8); + self.data.push(((data >> 8) & 0xFF) as u8); + self.data.push((data & 0xFF) as u8); + } + + pub fn push_bytes(&mut self, data: &[u8]) + { + self.data.extend(data); + } +} + +fn push_ipv4(packet: &mut Packet) +{ + let payload_len = packet.len(); + let mut header = Header::with_capacity(20); + + let b = 0x45; // version + IHL (we don't support options so length is fixed) + header.push8(b); + + header.push8(20); + + let hw = 20 + payload_len; // total length + header.push16(hw as u16); + + header.push16(21); // identification + header.push16(23); + + packet.push_header(&header); +} + +fn push_mac(packet: &mut Packet) +{ + let mut header = Header::with_capacity(30); + + let hw = 0b1000_10_00; // frame control, see 9.2.4.1 + header.push16(hw); + + let addr = [1, 2, 3, 4, 5, 6]; + for &b in addr.iter() { // address 1, see 9.3.2.1 + header.push8(b); + } + + for &b in addr.iter() { // address 2 + header.push8(b); + } + + for &b in addr.iter() {// address 3 + header.push8(b); + } + + header.push16(55); + + let hw = 0b111_0_00_0_000; // QoS control, see 9.2.4.5.1 + header.push16(hw); + + packet.push_header(&header); + + let fcs = [0xD9, 0x58, 0xFB, 0xA8]; + println!("old packet = {:?}", packet); + println!("pushing {:X} {:X} {:X} {:X} ", fcs[0], fcs[1], fcs[2], fcs[3]); + packet.push_back_bytes(&fcs); + + println!("new packet = {:?}", packet); +} + +fn main() +{ + let mut packet = Packet::new(); + push_ipv4(&mut packet); + push_mac(&mut packet); +} diff --git a/benchmark/rust-44800/r.sh b/benchmark/rust-44800/r.sh new file mode 100755 index 000000000..d66bfe171 --- /dev/null +++ b/benchmark/rust-44800/r.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -o nounset + +readonly FILE="mutant.rs" + +readonly BUGGY_RUSTC_VERSION="1.20.0" +readonly CORRECT_RUSTC_VERSION="1.47.0" +readonly CORRECT_RUSTC_VERSION_2="1.47.0" +rustup toolchain install "${BUGGY_RUSTC_VERSION}" --force +rustup toolchain install "${CORRECT_RUSTC_VERSION}" --force +rustup toolchain install "${CORRECT_RUSTC_VERSION_2}" --force + +if ! command -v valgrind > /dev/null ; then + echo "valgrind is not installed" + exit 100 +fi + +readonly EXE_WRONG="./wrong.out" +if ! timeout -s 9 60 rustup run "${BUGGY_RUSTC_VERSION}" rustc -o "${EXE_WRONG}" "${FILE}"; then + exit 1 +fi + +readonly EXE_CORRECT="./correct.out" +if ! timeout -s 9 60 rustup run "${CORRECT_RUSTC_VERSION}" rustc -o "${EXE_CORRECT}" "${FILE}" ; then + exit 1 +fi + +readonly EXE_CORRECT_2="./correct_2.out" +if ! timeout -s 9 60 rustup run "${CORRECT_RUSTC_VERSION_2}" rustc -o "${EXE_CORRECT_2}" "${FILE}" ; then + exit 1 +fi + +readonly OUTPUT_WRONG="wrong_output.txt" + +if (timeout -s 9 30 valgrind "${EXE_WRONG}") &> "${OUTPUT_WRONG}" ; then + exit 1 +fi + +readonly OUTPUT_CORRECT_1="correct_output.txt" +readonly OUTPUT_CORRECT_2="correct_output_2.txt" +if ! timeout -s 9 30 valgrind "${EXE_CORRECT}"; then + exit 1 +fi + +timeout -s 9 30 "${EXE_CORRECT}" &> "${OUTPUT_CORRECT_1}" + +if ! timeout -s 9 30 valgrind "${EXE_CORRECT_2}" ; then + exit 1 +fi +timeout -s 9 30 "${EXE_CORRECT_2}" &> "${OUTPUT_CORRECT_2}" + +if ! diff "${OUTPUT_CORRECT_1}" "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +exit 0 + diff --git a/benchmark/rust-63791/.gitignore b/benchmark/rust-63791/.gitignore new file mode 100644 index 000000000..283c8a008 --- /dev/null +++ b/benchmark/rust-63791/.gitignore @@ -0,0 +1,6 @@ +/* +!r.sh +!mutant.rs +!info.properties +!.gitignore + diff --git a/benchmark/rust-63791/info.properties b/benchmark/rust-63791/info.properties new file mode 100644 index 000000000..61eb6bd9c --- /dev/null +++ b/benchmark/rust-63791/info.properties @@ -0,0 +1,4 @@ +buggy_compiler_version_file=compiler_version.txt +script_file=r.sh +reduced_file=reduced_mutant.rs +source_file=mutant.rs diff --git a/benchmark/rust-63791/mutant.rs b/benchmark/rust-63791/mutant.rs new file mode 100644 index 000000000..848fbdf03 --- /dev/null +++ b/benchmark/rust-63791/mutant.rs @@ -0,0 +1,903 @@ +pub fn main() { + let plain = [127, 0, 0, 1, 174, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let key = [0; 16]; + let encrypted = [ + 222, 157, 168, 71, 195, 237, 77, 237, 182, 194, 17, 235, 182, 214, 204, 80, + ]; + + let output = encrypt(plain, key); + if output != encrypted { + std::process::abort(); + } + // assert_eq!(output, encrypted); + + // println!("success"); +} + +fn encrypt(input: [u8; 16], key: [u8; 16]) -> [u8; 16] { + let mut block = input; + let cipher = Aes128::new(&key); + cipher.encrypt_block(&mut block); + block +} + +use std::ops::{BitAnd, BitOr, BitXor, Not}; +use std::ptr::copy_nonoverlapping; + +macro_rules! read_slice { + ($src:expr, $dst:expr, $size:expr, $which:ident) => {{ + assert_eq!($src.len(), $size * $dst.len()); + + unsafe { + copy_nonoverlapping($src.as_ptr(), $dst.as_mut_ptr() as *mut u8, $src.len()); + } + for v in $dst.iter_mut() { + *v = v.$which(); + } + }}; +} +macro_rules! write_num_bytes { + ($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => {{ + assert!($size <= $dst.len()); + unsafe { + let bytes = *(&$n.$which() as *const _ as *const [u8; $size]); + copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size); + } + }}; +} + +const U32X4_0: u32x4 = u32x4(0, 0, 0, 0); +const U32X4_1: u32x4 = u32x4(0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff); +trait AesOps { + fn sub_bytes(self) -> Self; + fn inv_sub_bytes(self) -> Self; + fn shift_rows(self) -> Self; + fn inv_shift_rows(self) -> Self; + fn mix_columns(self) -> Self; + fn inv_mix_columns(self) -> Self; + fn add_round_key(self, rk: &Self) -> Self; +} + +fn encrypt_core(state: &S, sk: &[S]) -> S { + let mut tmp = state.add_round_key(&sk[0]); + for i in 1..sk.len() - 1 { + tmp = tmp.sub_bytes(); + tmp = tmp.shift_rows(); + tmp = tmp.mix_columns(); + tmp = tmp.add_round_key(&sk[i]); + } + tmp = tmp.sub_bytes(); + tmp = tmp.shift_rows(); + tmp = tmp.add_round_key(&sk[sk.len() - 1]); + + tmp +} + +#[derive(Clone, Copy)] +struct Bs8State(T, T, T, T, T, T, T, T); + +impl Bs8State { + fn split(self) -> (Bs4State, Bs4State) { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self; + (Bs4State(x0, x1, x2, x3), Bs4State(x4, x5, x6, x7)) + } +} + +impl + Copy> Bs8State { + fn xor(self, rhs: Bs8State) -> Bs8State { + let Bs8State(a0, a1, a2, a3, a4, a5, a6, a7) = self; + let Bs8State(b0, b1, b2, b3, b4, b5, b6, b7) = rhs; + Bs8State( + a0 ^ b0, + a1 ^ b1, + a2 ^ b2, + a3 ^ b3, + a4 ^ b4, + a5 ^ b5, + a6 ^ b6, + a7 ^ b7, + ) + } + + fn change_basis_a2x(&self) -> Bs8State { + let t06 = self.6 ^ self.0; + let t056 = self.5 ^ t06; + let t0156 = t056 ^ self.1; + let t13 = self.1 ^ self.3; + + let x0 = self.2 ^ t06 ^ t13; + let x1 = t056; + let x2 = self.0; + let x3 = self.0 ^ self.4 ^ self.7 ^ t13; + let x4 = self.7 ^ t056; + let x5 = t0156; + let x6 = self.4 ^ t056; + let x7 = self.2 ^ self.7 ^ t0156; + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) + } + + fn change_basis_x2s(&self) -> Bs8State { + let t46 = self.4 ^ self.6; + let t35 = self.3 ^ self.5; + let t06 = self.0 ^ self.6; + let t357 = t35 ^ self.7; + + let x0 = self.1 ^ t46; + let x1 = self.1 ^ self.4 ^ self.5; + let x2 = self.2 ^ t35 ^ t06; + let x3 = t46 ^ t357; + let x4 = t357; + let x5 = t06; + let x6 = self.3 ^ self.7; + let x7 = t35; + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) + } + + fn change_basis_x2a(&self) -> Bs8State { + let t15 = self.1 ^ self.5; + let t36 = self.3 ^ self.6; + let t1356 = t15 ^ t36; + let t07 = self.0 ^ self.7; + + let x0 = self.2; + let x1 = t15; + let x2 = self.4 ^ self.7 ^ t15; + let x3 = self.2 ^ self.4 ^ t1356; + let x4 = self.1 ^ self.6; + let x5 = self.2 ^ self.5 ^ t36 ^ t07; + let x6 = t1356 ^ t07; + let x7 = self.1 ^ self.4; + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) + } + + fn change_basis_s2x(&self) -> Bs8State { + let t46 = self.4 ^ self.6; + let t01 = self.0 ^ self.1; + let t0146 = t01 ^ t46; + + let x0 = self.5 ^ t0146; + let x1 = self.0 ^ self.3 ^ self.4; + let x2 = self.2 ^ self.5 ^ self.7; + let x3 = self.7 ^ t46; + let x4 = self.3 ^ self.6 ^ t01; + let x5 = t46; + let x6 = t0146; + let x7 = self.4 ^ self.7; + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) + } +} + +impl + Copy> Bs8State { + fn xor_x63(self) -> Bs8State { + Bs8State( + !self.0, !self.1, self.2, self.3, self.4, !self.5, !self.6, self.7, + ) + } +} + +#[derive(Clone, Copy)] +struct Bs4State(T, T, T, T); + +impl Bs4State { + fn split(self) -> (Bs2State, Bs2State) { + let Bs4State(x0, x1, x2, x3) = self; + (Bs2State(x0, x1), Bs2State(x2, x3)) + } + + fn join(self, rhs: Bs4State) -> Bs8State { + let Bs4State(a0, a1, a2, a3) = self; + let Bs4State(b0, b1, b2, b3) = rhs; + Bs8State(a0, a1, a2, a3, b0, b1, b2, b3) + } +} + +impl + Copy> Bs4State { + fn xor(self, rhs: Bs4State) -> Bs4State { + let Bs4State(a0, a1, a2, a3) = self; + let Bs4State(b0, b1, b2, b3) = rhs; + Bs4State(a0 ^ b0, a1 ^ b1, a2 ^ b2, a3 ^ b3) + } +} + +#[derive(Clone, Copy)] +struct Bs2State(T, T); + +impl Bs2State { + fn split(self) -> (T, T) { + let Bs2State(x0, x1) = self; + (x0, x1) + } + + fn join(self, rhs: Bs2State) -> Bs4State { + let Bs2State(a0, a1) = self; + let Bs2State(b0, b1) = rhs; + Bs4State(a0, a1, b0, b1) + } +} + +impl + Copy> Bs2State { + fn xor(self, rhs: Bs2State) -> Bs2State { + let Bs2State(a0, a1) = self; + let Bs2State(b0, b1) = rhs; + Bs2State(a0 ^ b0, a1 ^ b1) + } +} +#[inline(always)] +fn bit_slice_4x4_with_u16(a: u32, b: u32, c: u32, d: u32) -> Bs8State { + fn pb(x: u32, bit: u32, shift: u32) -> u16 { + (((x >> bit) & 1) as u16) << shift + } + + fn construct(a: u32, b: u32, c: u32, d: u32, bit: u32) -> u16 { + pb(a, bit, 0) + | pb(b, bit, 1) + | pb(c, bit, 2) + | pb(d, bit, 3) + | pb(a, bit + 8, 4) + | pb(b, bit + 8, 5) + | pb(c, bit + 8, 6) + | pb(d, bit + 8, 7) + | pb(a, bit + 16, 8) + | pb(b, bit + 16, 9) + | pb(c, bit + 16, 10) + | pb(d, bit + 16, 11) + | pb(a, bit + 24, 12) + | pb(b, bit + 24, 13) + | pb(c, bit + 24, 14) + | pb(d, bit + 24, 15) + } + + let x0 = construct(a, b, c, d, 0); + let x1 = construct(a, b, c, d, 1); + let x2 = construct(a, b, c, d, 2); + let x3 = construct(a, b, c, d, 3); + let x4 = construct(a, b, c, d, 4); + let x5 = construct(a, b, c, d, 5); + let x6 = construct(a, b, c, d, 6); + let x7 = construct(a, b, c, d, 7); + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) +} +fn bit_slice_4x1_with_u16(a: u32) -> Bs8State { + bit_slice_4x4_with_u16(a, 0, 0, 0) +} +fn bit_slice_1x16_with_u16(data: &[u8]) -> Bs8State { + let mut n = [0u32; 4]; + // LE::read_u32_into(data, &mut n); + read_slice!(data, &mut n, 4, to_le); + + let a = n[0]; + let b = n[1]; + let c = n[2]; + let d = n[3]; + + bit_slice_4x4_with_u16(a, b, c, d) +} +fn un_bit_slice_4x4_with_u16(bs: &Bs8State) -> (u32, u32, u32, u32) { + fn pb(x: u16, bit: u32, shift: u32) -> u32 { + u32::from((x >> bit) & 1) << shift + } + + fn deconstruct(bs: &Bs8State, bit: u32) -> u32 { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = *bs; + + pb(x0, bit, 0) + | pb(x1, bit, 1) + | pb(x2, bit, 2) + | pb(x3, bit, 3) + | pb(x4, bit, 4) + | pb(x5, bit, 5) + | pb(x6, bit, 6) + | pb(x7, bit, 7) + | pb(x0, bit + 4, 8) + | pb(x1, bit + 4, 9) + | pb(x2, bit + 4, 10) + | pb(x3, bit + 4, 11) + | pb(x4, bit + 4, 12) + | pb(x5, bit + 4, 13) + | pb(x6, bit + 4, 14) + | pb(x7, bit + 4, 15) + | pb(x0, bit + 8, 16) + | pb(x1, bit + 8, 17) + | pb(x2, bit + 8, 18) + | pb(x3, bit + 8, 19) + | pb(x4, bit + 8, 20) + | pb(x5, bit + 8, 21) + | pb(x6, bit + 8, 22) + | pb(x7, bit + 8, 23) + | pb(x0, bit + 12, 24) + | pb(x1, bit + 12, 25) + | pb(x2, bit + 12, 26) + | pb(x3, bit + 12, 27) + | pb(x4, bit + 12, 28) + | pb(x5, bit + 12, 29) + | pb(x6, bit + 12, 30) + | pb(x7, bit + 12, 31) + } + + let a = deconstruct(bs, 0); + let b = deconstruct(bs, 1); + let c = deconstruct(bs, 2); + let d = deconstruct(bs, 3); + + (a, b, c, d) +} +fn un_bit_slice_4x1_with_u16(bs: &Bs8State) -> u32 { + let (a, _, _, _) = un_bit_slice_4x4_with_u16(bs); + a +} +fn un_bit_slice_1x16_with_u16(bs: &Bs8State, output: &mut [u8]) { + let (a, b, c, d) = un_bit_slice_4x4_with_u16(bs); + + write_num_bytes!(u32, 4, a, &mut output[0..4], to_le); + write_num_bytes!(u32, 4, b, &mut output[4..8], to_le); + write_num_bytes!(u32, 4, c, &mut output[8..12], to_le); + write_num_bytes!(u32, 4, d, &mut output[12..16], to_le); +} +fn bit_slice_1x128_with_u32x4(data: &[u8]) -> Bs8State { + let bit0 = u32x4(0x01010101, 0x01010101, 0x01010101, 0x01010101); + let bit1 = u32x4(0x02020202, 0x02020202, 0x02020202, 0x02020202); + let bit2 = u32x4(0x04040404, 0x04040404, 0x04040404, 0x04040404); + let bit3 = u32x4(0x08080808, 0x08080808, 0x08080808, 0x08080808); + let bit4 = u32x4(0x10101010, 0x10101010, 0x10101010, 0x10101010); + let bit5 = u32x4(0x20202020, 0x20202020, 0x20202020, 0x20202020); + let bit6 = u32x4(0x40404040, 0x40404040, 0x40404040, 0x40404040); + let bit7 = u32x4(0x80808080, 0x80808080, 0x80808080, 0x80808080); + + fn read_row_major(data: &[u8]) -> u32x4 { + u32x4( + u32::from(data[0]) + | (u32::from(data[4]) << 8) + | (u32::from(data[8]) << 16) + | (u32::from(data[12]) << 24), + u32::from(data[1]) + | (u32::from(data[5]) << 8) + | (u32::from(data[9]) << 16) + | (u32::from(data[13]) << 24), + u32::from(data[2]) + | (u32::from(data[6]) << 8) + | (u32::from(data[10]) << 16) + | (u32::from(data[14]) << 24), + u32::from(data[3]) + | (u32::from(data[7]) << 8) + | (u32::from(data[11]) << 16) + | (u32::from(data[15]) << 24), + ) + } + + let t0 = read_row_major(&data[0..16]); + let t1 = read_row_major(&data[16..32]); + let t2 = read_row_major(&data[32..48]); + let t3 = read_row_major(&data[48..64]); + let t4 = read_row_major(&data[64..80]); + let t5 = read_row_major(&data[80..96]); + let t6 = read_row_major(&data[96..112]); + let t7 = read_row_major(&data[112..128]); + + let x0 = (t0 & bit0) + | (t1.lsh(1) & bit1) + | (t2.lsh(2) & bit2) + | (t3.lsh(3) & bit3) + | (t4.lsh(4) & bit4) + | (t5.lsh(5) & bit5) + | (t6.lsh(6) & bit6) + | (t7.lsh(7) & bit7); + let x1 = (t0.rsh(1) & bit0) + | (t1 & bit1) + | (t2.lsh(1) & bit2) + | (t3.lsh(2) & bit3) + | (t4.lsh(3) & bit4) + | (t5.lsh(4) & bit5) + | (t6.lsh(5) & bit6) + | (t7.lsh(6) & bit7); + let x2 = (t0.rsh(2) & bit0) + | (t1.rsh(1) & bit1) + | (t2 & bit2) + | (t3.lsh(1) & bit3) + | (t4.lsh(2) & bit4) + | (t5.lsh(3) & bit5) + | (t6.lsh(4) & bit6) + | (t7.lsh(5) & bit7); + let x3 = (t0.rsh(3) & bit0) + | (t1.rsh(2) & bit1) + | (t2.rsh(1) & bit2) + | (t3 & bit3) + | (t4.lsh(1) & bit4) + | (t5.lsh(2) & bit5) + | (t6.lsh(3) & bit6) + | (t7.lsh(4) & bit7); + let x4 = (t0.rsh(4) & bit0) + | (t1.rsh(3) & bit1) + | (t2.rsh(2) & bit2) + | (t3.rsh(1) & bit3) + | (t4 & bit4) + | (t5.lsh(1) & bit5) + | (t6.lsh(2) & bit6) + | (t7.lsh(3) & bit7); + let x5 = (t0.rsh(5) & bit0) + | (t1.rsh(4) & bit1) + | (t2.rsh(3) & bit2) + | (t3.rsh(2) & bit3) + | (t4.rsh(1) & bit4) + | (t5 & bit5) + | (t6.lsh(1) & bit6) + | (t7.lsh(2) & bit7); + let x6 = (t0.rsh(6) & bit0) + | (t1.rsh(5) & bit1) + | (t2.rsh(4) & bit2) + | (t3.rsh(3) & bit3) + | (t4.rsh(2) & bit4) + | (t5.rsh(1) & bit5) + | (t6 & bit6) + | (t7.lsh(1) & bit7); + let x7 = (t0.rsh(7) & bit0) + | (t1.rsh(6) & bit1) + | (t2.rsh(5) & bit2) + | (t3.rsh(4) & bit3) + | (t4.rsh(3) & bit4) + | (t5.rsh(2) & bit5) + | (t6.rsh(1) & bit6) + | (t7 & bit7); + + Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) +} + +fn bit_slice_fill_4x4_with_u32x4(a: u32, b: u32, c: u32, d: u32) -> Bs8State { + let mut tmp = [0u8; 128]; + for i in 0..8 { + write_num_bytes!(u32, 4, a, &mut tmp[i * 16..i * 16 + 4], to_le); + write_num_bytes!(u32, 4, b, &mut tmp[i * 16 + 4..i * 16 + 8], to_le); + write_num_bytes!(u32, 4, c, &mut tmp[i * 16 + 8..i * 16 + 12], to_le); + write_num_bytes!(u32, 4, d, &mut tmp[i * 16 + 12..i * 16 + 16], to_le); + } + bit_slice_1x128_with_u32x4(&tmp) +} + +impl + BitAnd + Copy> Bs2State { + fn mul(self, y: Bs2State) -> Bs2State { + let (b, a) = self.split(); + let (d, c) = y.split(); + let e = (a ^ b) & (c ^ d); + let p = (a & c) ^ e; + let q = (b & d) ^ e; + Bs2State(q, p) + } + + fn scl_n(self) -> Bs2State { + let (b, a) = self.split(); + let q = a ^ b; + Bs2State(q, b) + } + + fn scl_n2(self) -> Bs2State { + let (b, a) = self.split(); + let p = a ^ b; + let q = a; + Bs2State(q, p) + } + + fn sq(self) -> Bs2State { + let (b, a) = self.split(); + Bs2State(a, b) + } + + fn inv(self) -> Bs2State { + self.sq() + } +} + +impl + BitAnd + Copy> Bs4State { + fn mul(self, y: Bs4State) -> Bs4State { + let (b, a) = self.split(); + let (d, c) = y.split(); + let f = c.xor(d); + let e = a.xor(b).mul(f).scl_n(); + let p = a.mul(c).xor(e); + let q = b.mul(d).xor(e); + q.join(p) + } + + fn sq_scl(self) -> Bs4State { + let (b, a) = self.split(); + let p = a.xor(b).sq(); + let q = b.sq().scl_n2(); + q.join(p) + } + + fn inv(self) -> Bs4State { + let (b, a) = self.split(); + let c = a.xor(b).sq().scl_n(); + let d = a.mul(b); + let e = c.xor(d).inv(); + let p = e.mul(b); + let q = e.mul(a); + q.join(p) + } +} + +impl + BitAnd + Copy + Default> Bs8State { + fn inv(&self) -> Bs8State { + let (b, a) = self.split(); + let c = a.xor(b).sq_scl(); + let d = a.mul(b); + let e = c.xor(d).inv(); + let p = e.mul(b); + let q = e.mul(a); + q.join(p) + } +} + +impl AesOps for Bs8State { + fn sub_bytes(self) -> Bs8State { + let nb: Bs8State = self.change_basis_a2x(); + let inv = nb.inv(); + let nb2: Bs8State = inv.change_basis_x2s(); + nb2.xor_x63() + } + + fn inv_sub_bytes(self) -> Bs8State { + let t = self.xor_x63(); + let nb: Bs8State = t.change_basis_s2x(); + let inv = nb.inv(); + inv.change_basis_x2a() + } + + fn shift_rows(self) -> Bs8State { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self; + Bs8State( + x0.shift_row(), + x1.shift_row(), + x2.shift_row(), + x3.shift_row(), + x4.shift_row(), + x5.shift_row(), + x6.shift_row(), + x7.shift_row(), + ) + } + + fn inv_shift_rows(self) -> Bs8State { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self; + Bs8State( + x0.inv_shift_row(), + x1.inv_shift_row(), + x2.inv_shift_row(), + x3.inv_shift_row(), + x4.inv_shift_row(), + x5.inv_shift_row(), + x6.inv_shift_row(), + x7.inv_shift_row(), + ) + } + fn mix_columns(self) -> Bs8State { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self; + + let x0out = x7 ^ x7.ror1() ^ x0.ror1() ^ (x0 ^ x0.ror1()).ror2(); + let x1out = x0 ^ x0.ror1() ^ x7 ^ x7.ror1() ^ x1.ror1() ^ (x1 ^ x1.ror1()).ror2(); + let x2out = x1 ^ x1.ror1() ^ x2.ror1() ^ (x2 ^ x2.ror1()).ror2(); + let x3out = x2 ^ x2.ror1() ^ x7 ^ x7.ror1() ^ x3.ror1() ^ (x3 ^ x3.ror1()).ror2(); + let x4out = x3 ^ x3.ror1() ^ x7 ^ x7.ror1() ^ x4.ror1() ^ (x4 ^ x4.ror1()).ror2(); + let x5out = x4 ^ x4.ror1() ^ x5.ror1() ^ (x5 ^ x5.ror1()).ror2(); + let x6out = x5 ^ x5.ror1() ^ x6.ror1() ^ (x6 ^ x6.ror1()).ror2(); + let x7out = x6 ^ x6.ror1() ^ x7.ror1() ^ (x7 ^ x7.ror1()).ror2(); + + Bs8State(x0out, x1out, x2out, x3out, x4out, x5out, x6out, x7out) + } + fn inv_mix_columns(self) -> Bs8State { + let Bs8State(x0, x1, x2, x3, x4, x5, x6, x7) = self; + + let x0out = x5 ^ x6 ^ x7 ^ (x5 ^ x7 ^ x0).ror1() ^ (x0 ^ x5 ^ x6).ror2() ^ (x5 ^ x0).ror3(); + let x1out = x5 + ^ x0 + ^ (x6 ^ x5 ^ x0 ^ x7 ^ x1).ror1() + ^ (x1 ^ x7 ^ x5).ror2() + ^ (x6 ^ x5 ^ x1).ror3(); + let x2out = x6 + ^ x0 + ^ x1 + ^ (x7 ^ x6 ^ x1 ^ x2).ror1() + ^ (x0 ^ x2 ^ x6).ror2() + ^ (x7 ^ x6 ^ x2).ror3(); + let x3out = x0 + ^ x5 + ^ x1 + ^ x6 + ^ x2 + ^ (x0 ^ x5 ^ x2 ^ x3).ror1() + ^ (x0 ^ x1 ^ x3 ^ x5 ^ x6 ^ x7).ror2() + ^ (x0 ^ x5 ^ x7 ^ x3).ror3(); + let x4out = x1 + ^ x5 + ^ x2 + ^ x3 + ^ (x1 ^ x6 ^ x5 ^ x3 ^ x7 ^ x4).ror1() + ^ (x1 ^ x2 ^ x4 ^ x5 ^ x7).ror2() + ^ (x1 ^ x5 ^ x6 ^ x4).ror3(); + let x5out = x2 + ^ x6 + ^ x3 + ^ x4 + ^ (x2 ^ x7 ^ x6 ^ x4 ^ x5).ror1() + ^ (x2 ^ x3 ^ x5 ^ x6).ror2() + ^ (x2 ^ x6 ^ x7 ^ x5).ror3(); + let x6out = x3 + ^ x7 + ^ x4 + ^ x5 + ^ (x3 ^ x7 ^ x5 ^ x6).ror1() + ^ (x3 ^ x4 ^ x6 ^ x7).ror2() + ^ (x3 ^ x7 ^ x6).ror3(); + let x7out = x4 ^ x5 ^ x6 ^ (x4 ^ x6 ^ x7).ror1() ^ (x4 ^ x5 ^ x7).ror2() ^ (x4 ^ x7).ror3(); + + Bs8State(x0out, x1out, x2out, x3out, x4out, x5out, x6out, x7out) + } + + fn add_round_key(self, rk: &Bs8State) -> Bs8State { + self.xor(*rk) + } +} + +trait AesBitValueOps: + BitXor + BitAnd + Not + Default + Sized +{ + fn shift_row(self) -> Self; + fn inv_shift_row(self) -> Self; + fn ror1(self) -> Self; + fn ror2(self) -> Self; + fn ror3(self) -> Self; +} + +impl AesBitValueOps for u16 { + fn shift_row(self) -> u16 { + (self & 0x000f) + | ((self & 0x00e0) >> 1) + | ((self & 0x0010) << 3) + | ((self & 0x0c00) >> 2) + | ((self & 0x0300) << 2) + | ((self & 0x8000) >> 3) + | ((self & 0x7000) << 1) + } + + fn inv_shift_row(self) -> u16 { + (self & 0x000f) + | ((self & 0x0080) >> 3) + | ((self & 0x0070) << 1) + | ((self & 0x0c00) >> 2) + | ((self & 0x0300) << 2) + | ((self & 0xe000) >> 1) + | ((self & 0x1000) << 3) + } + + fn ror1(self) -> u16 { + self >> 4 | self << 12 + } + + fn ror2(self) -> u16 { + self >> 8 | self << 8 + } + + fn ror3(self) -> u16 { + self >> 12 | self << 4 + } +} + +impl u32x4 { + fn lsh(self, s: u32) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4( + a0 << s, + (a1 << s) | (a0 >> (32 - s)), + (a2 << s) | (a1 >> (32 - s)), + (a3 << s) | (a2 >> (32 - s)), + ) + } + + fn rsh(self, s: u32) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4( + (a0 >> s) | (a1 << (32 - s)), + (a1 >> s) | (a2 << (32 - s)), + (a2 >> s) | (a3 << (32 - s)), + a3 >> s, + ) + } +} + +impl Not for u32x4 { + type Output = u32x4; + + fn not(self) -> u32x4 { + self ^ U32X4_1 + } +} + +impl Default for u32x4 { + fn default() -> u32x4 { + u32x4(0, 0, 0, 0) + } +} + +impl AesBitValueOps for u32x4 { + fn shift_row(self) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4( + a0, + a1 >> 8 | a1 << 24, + a2 >> 16 | a2 << 16, + a3 >> 24 | a3 << 8, + ) + } + + fn inv_shift_row(self) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4( + a0, + a1 >> 24 | a1 << 8, + a2 >> 16 | a2 << 16, + a3 >> 8 | a3 << 24, + ) + } + + fn ror1(self) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4(a1, a2, a3, a0) + } + + fn ror2(self) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4(a2, a3, a0, a1) + } + + fn ror3(self) -> u32x4 { + let u32x4(a0, a1, a2, a3) = self; + u32x4(a3, a0, a1, a2) + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +#[allow(non_camel_case_types)] +struct u32x4(u32, u32, u32, u32); + +impl BitXor for u32x4 { + type Output = u32x4; + + #[inline(always)] + fn bitxor(self, rhs: u32x4) -> u32x4 { + u32x4( + self.0 ^ rhs.0, + self.1 ^ rhs.1, + self.2 ^ rhs.2, + self.3 ^ rhs.3, + ) + } +} + +impl BitAnd for u32x4 { + type Output = u32x4; + + #[inline(always)] + fn bitand(self, rhs: u32x4) -> u32x4 { + u32x4( + self.0 & rhs.0, + self.1 & rhs.1, + self.2 & rhs.2, + self.3 & rhs.3, + ) + } +} + +impl BitOr for u32x4 { + type Output = u32x4; + + #[inline(always)] + fn bitor(self, rhs: u32x4) -> u32x4 { + u32x4( + self.0 | rhs.0, + self.1 | rhs.1, + self.2 | rhs.2, + self.3 | rhs.3, + ) + } +} + +#[derive(Clone)] +struct Aes128 { + enc_keys: [Bs8State; 11], + dec_keys: [Bs8State; 11], + enc_keys8: [Bs8State; 11], + dec_keys8: [Bs8State; 11], +} + +impl Aes128 { + #[inline] + fn new(key: &[u8; 16]) -> Self { + let (ek, dk) = expand_key(key); + let k8 = Bs8State( + U32X4_0, U32X4_0, U32X4_0, U32X4_0, U32X4_0, U32X4_0, U32X4_0, U32X4_0, + ); + let mut c = Self { + enc_keys: [Bs8State(0, 0, 0, 0, 0, 0, 0, 0); 11], + dec_keys: [Bs8State(0, 0, 0, 0, 0, 0, 0, 0); 11], + enc_keys8: [k8; 11], + dec_keys8: [k8; 11], + }; + for i in 0..11 { + c.enc_keys[i] = bit_slice_4x4_with_u16(ek[i][0], ek[i][1], ek[i][2], ek[i][3]); + c.dec_keys[i] = bit_slice_4x4_with_u16(dk[i][0], dk[i][1], dk[i][2], dk[i][3]); + c.enc_keys8[i] = bit_slice_fill_4x4_with_u32x4(ek[i][0], ek[i][1], ek[i][2], ek[i][3]); + c.dec_keys8[i] = bit_slice_fill_4x4_with_u32x4(dk[i][0], dk[i][1], dk[i][2], dk[i][3]); + } + c + } + + #[inline] + fn encrypt_block(&self, block: &mut [u8; 16]) { + let mut bs = bit_slice_1x16_with_u16(block); + bs = encrypt_core(&bs, &self.enc_keys); + un_bit_slice_1x16_with_u16(&bs, block); + } +} +static RCON: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36]; + +fn ffmulx(x: u32) -> u32 { + let m1: u32 = 0x80808080; + let m2: u32 = 0x7f7f7f7f; + let m3: u32 = 0x0000001b; + ((x & m2) << 1) ^ (((x & m1) >> 7) * m3) +} + +fn inv_mcol(x: u32) -> u32 { + let f2 = ffmulx(x); + let f4 = ffmulx(f2); + let f8 = ffmulx(f4); + let f9 = x ^ f8; + + f2 ^ f4 ^ f8 ^ (f2 ^ f9).rotate_right(8) ^ (f4 ^ f9).rotate_right(16) ^ f9.rotate_right(24) +} + +fn sub_word(x: u32) -> u32 { + let bs = bit_slice_4x1_with_u16(x).sub_bytes(); + un_bit_slice_4x1_with_u16(&bs) +} +fn expand_key(key: &[u8; 16]) -> ([[u32; 4]; 11], [[u32; 4]; 11]) { + let rounds = 11; + let key_len = 16; + let key_words = match key_len { + 16 => 4, + 24 => 6, + 32 => 8, + _ => panic!("Invalid AES key size."), + }; + let mut ek = <[[u32; 4]; 11]>::default(); + let mut j = 0; + for i in 0..key_len / 4 { + ek[j / 4][j % 4] = u32::from(key[4 * i]) + | (u32::from(key[4 * i + 1]) << 8) + | (u32::from(key[4 * i + 2]) << 16) + | (u32::from(key[4 * i + 3]) << 24); + j += 1; + } + for i in key_words..rounds * 4 { + let mut tmp = ek[(i - 1) / 4][(i - 1) % 4]; + if (i % key_words) == 0 { + tmp = sub_word(tmp.rotate_right(8)) ^ RCON[(i / key_words) - 1]; + } else if (key_words == 8) && ((i % key_words) == 4) { + tmp = sub_word(tmp); + } + ek[i / 4][i % 4] = ek[(i - key_words) / 4][(i - key_words) % 4] ^ tmp; + } + let mut dk = <[[u32; 4]; 11]>::default(); + dk[0] = ek[0]; + for j in 1..rounds - 1 { + for i in 0..4 { + dk[j][i] = inv_mcol(ek[j][i]); + } + } + dk[rounds - 1] = ek[rounds - 1]; + + (ek, dk) +} diff --git a/benchmark/rust-63791/r.sh b/benchmark/rust-63791/r.sh new file mode 100755 index 000000000..86766b227 --- /dev/null +++ b/benchmark/rust-63791/r.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -o nounset +set -o pipefail + +readonly FILE="mutant.rs" + +readonly RUSTC_VERSION="1.34.0" +readonly CORRECT_RUSTC_VERSION="1.33.0" +rustup toolchain install "${RUSTC_VERSION}" +rustup toolchain install "${CORRECT_RUSTC_VERSION}" + +readonly EXTRA_FLAGS="-C opt-level=3" + +readonly EXE_WRONG="./wrong.out" +if ! timeout -s 9 60 rustup run "${RUSTC_VERSION}" rustc -C target-cpu=haswell ${EXTRA_FLAGS} -o "${EXE_WRONG}" "${FILE}"; then + exit 1 +fi + +readonly EXE_CORRECT="./correct.out" +if ! timeout -s 9 60 rustup run "${RUSTC_VERSION}" rustc -C target-cpu=ivybridge ${EXTRA_FLAGS} -o "${EXE_CORRECT}" "${FILE}" ; then + exit 1 +fi + +readonly EXE_CORRECT_2="./correct_2.out" +if ! timeout -s 9 60 rustup run "${CORRECT_RUSTC_VERSION}" rustc -C target-cpu=haswell ${EXTRA_FLAGS} -o "${EXE_CORRECT_2}" "${FILE}" ; then + exit 1 +fi + +readonly OUTPUT_WRONG="wrong_output.txt" +readonly OUTPUT_CORRECT_1="correct_output.txt" +readonly OUTPUT_CORRECT_2="correct_output_2.txt" + +if (timeout -s 9 30 "${EXE_WRONG}") &> "${OUTPUT_WRONG}" ; then + exit 1 +fi + +if ! timeout -s 9 30 "${EXE_CORRECT}" &> "${OUTPUT_CORRECT_1}" ; then + exit 1 +fi + +if ! timeout -s 9 30 "${EXE_CORRECT_2}" &> "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +if ! diff -q "${OUTPUT_CORRECT_1}" "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +if diff -q "${OUTPUT_WRONG}" "${OUTPUT_CORRECT_1}" ; then + exit 1 +fi + +exit 0 + diff --git a/benchmark/rust-69039/.gitignore b/benchmark/rust-69039/.gitignore new file mode 100644 index 000000000..283c8a008 --- /dev/null +++ b/benchmark/rust-69039/.gitignore @@ -0,0 +1,6 @@ +/* +!r.sh +!mutant.rs +!info.properties +!.gitignore + diff --git a/benchmark/rust-69039/info.properties b/benchmark/rust-69039/info.properties new file mode 100644 index 000000000..61eb6bd9c --- /dev/null +++ b/benchmark/rust-69039/info.properties @@ -0,0 +1,4 @@ +buggy_compiler_version_file=compiler_version.txt +script_file=r.sh +reduced_file=reduced_mutant.rs +source_file=mutant.rs diff --git a/benchmark/rust-69039/mutant.rs b/benchmark/rust-69039/mutant.rs new file mode 100644 index 000000000..888c8cd36 --- /dev/null +++ b/benchmark/rust-69039/mutant.rs @@ -0,0 +1,36 @@ +#![feature(generators, generator_trait)] + +use std::{ + io, + ops::{Generator, GeneratorState}, +}; + +fn my_scenario() -> impl Generator { + |_arg: String| { + let my_name = yield "What is your name?"; + let my_mood = yield "How are you feeling?"; + format!("{} is {}", my_name.trim(), my_mood.trim()) + } +} + +fn main() { + let mut my_session = Box::pin(my_scenario()); + + loop { + let mut line = String::new(); + + match my_session.as_mut().resume(line) { + GeneratorState::Yielded(prompt) => { + println!("{}", prompt); + } + GeneratorState::Complete(v) => { + println!("{}", v); + break; + } + } + + line = String::new(); + io::stdin().read_line(&mut line).unwrap(); + } +} + diff --git a/benchmark/rust-69039/r.sh b/benchmark/rust-69039/r.sh new file mode 100755 index 000000000..17babad79 --- /dev/null +++ b/benchmark/rust-69039/r.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -o nounset + +readonly FILE="mutant.rs" + +readonly BUGGY_RUSTC_VERSION="nightly-2020-02-10" +readonly CORRECT_RUSTC_VERSION="nightly-2020-11-05" +rustup toolchain install "${BUGGY_RUSTC_VERSION}" --force +rustup toolchain install "${CORRECT_RUSTC_VERSION}" --force + +readonly EXE_WRONG="./wrong.out" +if ! timeout -s 9 60 rustup run "${BUGGY_RUSTC_VERSION}" rustc -o "${EXE_WRONG}" "${FILE}"; then + exit 1 +fi + +readonly EXE_CORRECT="./correct.out" +if ! timeout -s 9 60 rustup run "${CORRECT_RUSTC_VERSION}" rustc -o "${EXE_CORRECT}" "${FILE}" ; then + exit 1 +fi + +readonly EXE_CORRECT_2="./correct_2.out" +if ! timeout -s 9 60 rustup run "${CORRECT_RUSTC_VERSION}" rustc -Z mir-opt-level=2 -o "${EXE_CORRECT_2}" "${FILE}" ; then + exit 1 +fi + +readonly OUTPUT_WRONG="wrong_output.txt" + +if (echo -e "a\nb" | timeout -s 9 30 "${EXE_WRONG}") &> "${OUTPUT_WRONG}" ; then + exit 1 +fi + +if ! grep "Segmentation fault" "${OUTPUT_WRONG}" ; then + exit 1 +fi + +readonly OUTPUT_CORRECT_1="correct_output.txt" +readonly OUTPUT_CORRECT_2="correct_output_2.txt" +if ! timeout -s 9 30 echo -e "a\nb" | "${EXE_CORRECT}" &> "${OUTPUT_CORRECT_1}" ; then + exit 1 +fi + +if ! timeout -s 9 30 echo -e "a\nb" | "${EXE_CORRECT_2}" &> "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +if ! diff "${OUTPUT_CORRECT_1}" "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +exit 0 + diff --git a/benchmark/rust-70746/info.properties b/benchmark/rust-70746/info.properties new file mode 100644 index 000000000..08095c75d --- /dev/null +++ b/benchmark/rust-70746/info.properties @@ -0,0 +1,4 @@ +#Thu Oct 22 21:34:51 UTC 2020 +buggy_compiler_version_file=compiler_version.txt +script_file=r.sh +source_file=mutant.rs diff --git a/benchmark/rust-70746/mutant.rs b/benchmark/rust-70746/mutant.rs new file mode 100644 index 000000000..d27f5e685 --- /dev/null +++ b/benchmark/rust-70746/mutant.rs @@ -0,0 +1,26 @@ +pub trait Trait1 { + type C; +} + +struct T1; +impl Trait1 for T1 { + type C = usize; +} +pub trait Callback: FnMut(::C) {} +impl::C)> Callback for F { } + + +pub struct State { + callback: Option>>, +} +impl State { + fn new() -> Self { Self { callback: None } } + fn test_cb(&mut self, d: ::C) { + (self.callback.as_mut().unwrap())(d) + } +} + +fn main() { + let mut s = State::::new(); + s.test_cb(1); +} \ No newline at end of file diff --git a/benchmark/rust-70746/r.sh b/benchmark/rust-70746/r.sh new file mode 100755 index 000000000..5173d0922 --- /dev/null +++ b/benchmark/rust-70746/r.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -o nounset +set -o pipefail + +readonly RUSTC_VERSION="1.42.0" + +readonly OUTPUT="temp_compilation_output.tmp.txt" + +if ! timeout -s 9 30 rustc -Z parse-only mutant.rs &> /dev/null ; then + # make sure the source file is syntactically correct. + exit 1 +fi + +if timeout -s 9 30 rustup run "${RUSTC_VERSION}" rustc mutant.rs &> "${OUTPUT}" ; then + exit 1 +fi + +if ! grep --quiet --fixed-strings "error: internal compiler error: src/librustc/traits/codegen/mod.rs" "${OUTPUT}" ; then + exit 1 +fi + +if ! grep --quiet --fixed-strings "[FulfillmentError(Obligation(predicate=Binder(TraitPredicate( as std::ops::FnMut<(usize,)>>))" "${OUTPUT}" ; then + exit 1 +fi + +exit 0 diff --git a/benchmark/rust-77002/.gitignore b/benchmark/rust-77002/.gitignore new file mode 100644 index 000000000..283c8a008 --- /dev/null +++ b/benchmark/rust-77002/.gitignore @@ -0,0 +1,6 @@ +/* +!r.sh +!mutant.rs +!info.properties +!.gitignore + diff --git a/benchmark/rust-77002/info.properties b/benchmark/rust-77002/info.properties new file mode 100644 index 000000000..61eb6bd9c --- /dev/null +++ b/benchmark/rust-77002/info.properties @@ -0,0 +1,4 @@ +buggy_compiler_version_file=compiler_version.txt +script_file=r.sh +reduced_file=reduced_mutant.rs +source_file=mutant.rs diff --git a/benchmark/rust-77002/mutant.rs b/benchmark/rust-77002/mutant.rs new file mode 100644 index 000000000..890c01a4c --- /dev/null +++ b/benchmark/rust-77002/mutant.rs @@ -0,0 +1,37 @@ +fn main() { + const MOD: i64 = 100_000_000; + const N: u64 = 1_000_000_000_000; + + const SIZE: usize = 4; + const SIZE64: u64 = SIZE as _; + type Mat = [[i64; SIZE]; SIZE]; + + fn matrix_prod(a: &Mat, b: &Mat, n: usize, m: usize, p: usize) -> Mat { + let mut res: Mat = Mat::default(); + for i in 0 .. n { + for j in 0 .. p { + for k in 0 .. m { + res[i][j] = (res[i][j] + a[i][k] * b[k][j] % MOD) % MOD; + } + } + } + res + } + + fn matrix_pow(mut a: Mat, s: usize, mut n: u64) -> Mat { + let mut res: Mat = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]; + + while n != 0 { + if (n & 1) != 0 { + res = matrix_prod(&a, &res, s, s, s); + } + n >>= 1; + a = matrix_prod(&a, &a, s, s, s); + } + res + } + + const G1: Mat = [[0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [1, -2, 2, 2]]; + let g2 = matrix_pow(G1, SIZE, N - SIZE64); + println!("{:?}", g2); +} diff --git a/benchmark/rust-77002/r.sh b/benchmark/rust-77002/r.sh new file mode 100755 index 000000000..4cedc1e5b --- /dev/null +++ b/benchmark/rust-77002/r.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +set -o nounset +set -o pipefail + +readonly FILE="mutant.rs" + +readonly RUSTC_VERSION="nightly-2020-09-22" +rustup toolchain install "${RUSTC_VERSION}" + +readonly EXE_WRONG="./wrong.out" +if ! timeout -s 9 60 rustup run "${RUSTC_VERSION}" rustc -Z mir-opt-level=2 -o "${EXE_WRONG}" "${FILE}"; then + exit 1 +fi + +readonly EXE_CORRECT="./correct.out" +if ! timeout -s 9 60 rustup run "${RUSTC_VERSION}" rustc -Z mir-opt-level=1 -o "${EXE_CORRECT}" "${FILE}" ; then + exit 1 +fi + +readonly EXE_CORRECT_2="./correct_2.out" +if ! timeout -s 9 60 rustup run "${RUSTC_VERSION}" rustc -Z mir-opt-level=0 -o "${EXE_CORRECT_2}" "${FILE}" ; then + exit 1 +fi + +readonly OUTPUT_WRONG="wrong_output.txt" +readonly OUTPUT_CORRECT_1="correct_output.txt" +readonly OUTPUT_CORRECT_2="correct_output_2.txt" + +if ! timeout -s 9 30 "${EXE_WRONG}" &> "${OUTPUT_WRONG}" ; then + exit 1 +fi + +if ! timeout -s 9 30 "${EXE_CORRECT}" &> "${OUTPUT_CORRECT_1}" ; then + exit 1 +fi + +if ! timeout -s 9 30 "${EXE_CORRECT_2}" &> "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +if [[ ! -s "${OUTPUT_WRONG}" ]] ; then + # empty file, return 1. + exit 1 +fi +if ! diff -q "${OUTPUT_CORRECT_1}" "${OUTPUT_CORRECT_2}" ; then + exit 1 +fi + +if diff -q "${OUTPUT_WRONG}" "${OUTPUT_CORRECT_1}" ; then + exit 1 +fi + +exit 0 + diff --git a/benchmark/rust-78622/compiler_version.txt b/benchmark/rust-78622/compiler_version.txt new file mode 100644 index 000000000..6ada4ab95 --- /dev/null +++ b/benchmark/rust-78622/compiler_version.txt @@ -0,0 +1,14 @@ +rustc 1.49.0-nightly (ffa2e7ae8 2020-10-24) + +binary: rustc + +commit-hash: ffa2e7ae8fbf9badc035740db949b9dae271c29f + +commit-date: 2020-10-24 + +host: x86_64-unknown-linux-gnu + +release: 1.49.0-nightly + +LLVM version: 11.0 + diff --git a/benchmark/rust-78622/crash_signature.txt b/benchmark/rust-78622/crash_signature.txt new file mode 100644 index 000000000..b7151fe71 --- /dev/null +++ b/benchmark/rust-78622/crash_signature.txt @@ -0,0 +1,3 @@ +error: internal compiler error: compiler/rustc_typeck/src/collect/type_of.rs +thread 'rustc' panicked at 'Box' +note: the compiler unexpectedly panicked. this is a bug. \ No newline at end of file diff --git a/benchmark/rust-78622/info.properties b/benchmark/rust-78622/info.properties new file mode 100644 index 000000000..660c59698 --- /dev/null +++ b/benchmark/rust-78622/info.properties @@ -0,0 +1,5 @@ +#Sat Oct 31 16:46:04 UTC 2020 +buggy_compiler_version_file=compiler_version.txt +script_file=r.sh +reduced_file=reduced_mutant.rs +source_file=mutant.rs diff --git a/benchmark/rust-78622/mutant.rs b/benchmark/rust-78622/mutant.rs new file mode 100644 index 000000000..b0ba75a6b --- /dev/null +++ b/benchmark/rust-78622/mutant.rs @@ -0,0 +1,28 @@ +struct S ; +trait Tr { +type A ; +} +impl Tr for S { +type A = S ; +} +fn f < T : Tr > ( ) { +let s = T :: A { } ; +let z = T :: A :: < u8 > { } ; +match S { +T :: A { } => { } +} +} +fn g < T : Tr < A = S > > ( ) { +let s = T :: A { } ; +let z = T :: A :: < u8 > { } ; +match S { +T :: A { } => { } +} +} +fn main ( ) { +let s = S :: A { } ; +let z = S :: A :: < f > { } ; +match S { +S :: A { } => { } +} +} diff --git a/benchmark/rust-78622/r.sh b/benchmark/rust-78622/r.sh new file mode 100755 index 000000000..2aa58c96c --- /dev/null +++ b/benchmark/rust-78622/r.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -o nounset +set -o pipefail + +readonly OUTPUT="temp_compilation_output.tmp.txt" + +if ! timeout -s 9 30 rustc -Z parse-only mutant.rs ; then + exit 1 +fi + +if timeout -s 9 30 rustc --crate-type=staticlib -C debuginfo=2 -C opt-level=z -C target-cpu=skylake mutant.rs &> "${OUTPUT}" ; then + exit 1 +fi + +if ! grep --quiet --fixed-strings "error: internal compiler error: compiler/rustc_typeck/src/collect/type_of.rs" "${OUTPUT}" ; then + exit 1 +fi + +if ! grep --quiet --fixed-strings "thread 'rustc' panicked at 'Box'" "${OUTPUT}" ; then + exit 1 +fi + +if ! grep --quiet --fixed-strings "note: the compiler unexpectedly panicked. this is a bug." "${OUTPUT}" ; then + exit 1 +fi +exit 0 diff --git a/scripts/perses-trunk b/scripts/perses-trunk index d655e857b..a0f0a1592 100755 --- a/scripts/perses-trunk +++ b/scripts/perses-trunk @@ -31,4 +31,3 @@ cp -f "bazel-bin/src/org/perses/perses_deploy.jar" "${FOLDER_BIN}" cd "${REDUCTION_DIR}" readonly FILE_JAR="${FOLDER_BIN}/perses_deploy.jar" java -jar "${FILE_JAR}" "$@" - diff --git a/scripts/run_ktlint.sh b/scripts/run_ktlint.sh index 47a192ed5..4d57e9eca 100755 --- a/scripts/run_ktlint.sh +++ b/scripts/run_ktlint.sh @@ -9,7 +9,11 @@ if [[ ! -e "WORKSPACE" ]] ; then exit 1 fi -bazel run "//:ktlint" -- --format \ +bazel build "//:ktlint_deploy.jar" + +# DON'T use 'bazel run //:ktlint_deploy.jar' due to its working directory +# is not the root of the workspace. +java -jar bazel-bin/ktlint_deploy.jar --format \ "src/**/*.kt" \ "test/**/*.kt" \ "antlropt/**/*.kt" \ diff --git a/src/org/perses/BUILD b/src/org/perses/BUILD index 22596e2f8..3a6d37730 100644 --- a/src/org/perses/BUILD +++ b/src/org/perses/BUILD @@ -9,6 +9,7 @@ kt_jvm_library( srcs = ["CommandOptions.kt"], deps = [ "//src/org/perses/program:enum_format_control", + "//src/org/perses/reduction:enum_query_caching_control", "//src/org/perses/util:command_line_flags", "//src/org/perses/util:percentage", "//src/org/perses/util:shell", diff --git a/src/org/perses/CommandOptions.kt b/src/org/perses/CommandOptions.kt index 7f0a0b7d9..06f9b628b 100644 --- a/src/org/perses/CommandOptions.kt +++ b/src/org/perses/CommandOptions.kt @@ -16,17 +16,19 @@ */ package org.perses +import com.beust.jcommander.IStringConverter import com.beust.jcommander.Parameter +import com.beust.jcommander.ParameterException import org.perses.program.EnumFormatControl +import org.perses.reduction.EnumQueryCachingControl import org.perses.util.AbstractCommandOptions import org.perses.util.Fraction -import org.perses.util.Fraction.Companion.parse import org.perses.util.ICommandLineFlags import org.perses.util.ShellCommandOnPath.Companion.normalizeAndCheckExecutability import java.io.File /** Parser for command line arguments. */ -class CommandOptions(private val defaultReductionAlgorithm: String) : AbstractCommandOptions() { +class CommandOptions(defaultReductionAlgorithm: String) : AbstractCommandOptions() { @JvmField val compulsoryFlags = registerFlags(CompulsoryFlags()) @@ -38,7 +40,9 @@ class CommandOptions(private val defaultReductionAlgorithm: String) : AbstractCo val outputRefiningFlags = registerFlags(OutputRefiningFlags()) @JvmField - val algorithmControlFlags = registerFlags(ReductionAlgorithmControlFlags()) + val algorithmControlFlags = registerFlags( + ReductionAlgorithmControlFlags(defaultReductionAlgorithm) + ) val cacheControlFlags = registerFlags(CacheControlFlags()) val profilingFlags = registerFlags(ProfilingFlags()) @@ -226,7 +230,8 @@ class CommandOptions(private val defaultReductionAlgorithm: String) : AbstractCo } } - inner class ReductionAlgorithmControlFlags : ICommandLineFlags { + class ReductionAlgorithmControlFlags(val defaultReductionAlgorithm: String) : + ICommandLineFlags { @JvmField @Parameter( names = ["--alg"], @@ -295,14 +300,24 @@ class CommandOptions(private val defaultReductionAlgorithm: String) : AbstractCo override fun validate() = Unit } - inner class CacheControlFlags : ICommandLineFlags { + class QueryCachingControlConverter : IStringConverter { + override fun convert(flagValue: String?): EnumQueryCachingControl { + return EnumQueryCachingControl.convert(flagValue!!) + ?: throw ParameterException( + "Cannot convert '$flagValue' to an instanceof ${EnumQueryCachingControl::class}" + ) + } + } + + class CacheControlFlags : ICommandLineFlags { @Parameter( names = ["--query-caching"], description = "Enable query caching for test script executions.", arity = 1, + converter = QueryCachingControlConverter::class, order = FlagOrder.CACHE_CONTROL + 0 ) - var queryCaching = false + var queryCaching = EnumQueryCachingControl.AUTO @Parameter( names = ["--edit-caching"], @@ -323,7 +338,7 @@ class CommandOptions(private val defaultReductionAlgorithm: String) : AbstractCo "e.g. 0 represents 0%, 85 represents 85%.", order = FlagOrder.CACHE_CONTROL + 2 ) - var queryCacheRefreshThreshold = 100 // Represent 100/100 = 100% + var queryCacheRefreshThreshold = 0 // Represent 0/100 = 0% fun getQueryCacheRefreshThreshold(): Fraction { return Fraction(queryCacheRefreshThreshold, 100) diff --git a/src/org/perses/grammar/c/LanguageC.kt b/src/org/perses/grammar/c/LanguageC.kt index 32842eb36..6f0e93a71 100644 --- a/src/org/perses/grammar/c/LanguageC.kt +++ b/src/org/perses/grammar/c/LanguageC.kt @@ -20,23 +20,21 @@ import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet import org.perses.program.EnumFormatControl import org.perses.program.LanguageKind +import org.perses.util.ShellCommandOnPath -object LanguageC : LanguageKind() { - - override val name = "c" - - override val extensions = ImmutableSet.of("c") - - override val defaultCodeFormatControl = EnumFormatControl.SINGLE_TOKEN_PER_LINE - - override val defaultFormmaterCommand = - tryObtainingDefaultFormatter( +object LanguageC : LanguageKind( + name = "c", + extensions = ImmutableSet.of("c"), + defaultCodeFormatControl = EnumFormatControl.SINGLE_TOKEN_PER_LINE, + defaultFormaterCommand = createPotentialCodeFormatterList( + ShellCommandOnPath.tryCreating( "clang-format", - ImmutableList.of(/*in-place formatting*/"-i")) - - override val allowedCodeFormatControl = ImmutableSet.of( + ImmutableList.of(/*in-place formatting*/"-i") + ) + ), + allowedCodeFormatControl = ImmutableSet.of( EnumFormatControl.SINGLE_TOKEN_PER_LINE, EnumFormatControl.COMPACT_ORIG_FORMAT, EnumFormatControl.ORIG_FORMAT ) -} +) diff --git a/src/org/perses/grammar/go/LanguageGo.kt b/src/org/perses/grammar/go/LanguageGo.kt index 92c3ecde1..2a8072556 100644 --- a/src/org/perses/grammar/go/LanguageGo.kt +++ b/src/org/perses/grammar/go/LanguageGo.kt @@ -20,18 +20,12 @@ import com.google.common.collect.ImmutableSet import org.perses.program.EnumFormatControl import org.perses.program.LanguageKind -object LanguageGo : LanguageKind() { - - override val name = "go" - - override val extensions = ImmutableSet.of("go") - - override val defaultCodeFormatControl = EnumFormatControl.COMPACT_ORIG_FORMAT - - override val defaultFormmaterCommand = null - - override val allowedCodeFormatControl = ImmutableSet.of( +object LanguageGo : LanguageKind( + name = "go", + extensions = ImmutableSet.of("go"), + defaultCodeFormatControl = EnumFormatControl.COMPACT_ORIG_FORMAT, + allowedCodeFormatControl = ImmutableSet.of( EnumFormatControl.COMPACT_ORIG_FORMAT, EnumFormatControl.ORIG_FORMAT ) -} +) diff --git a/src/org/perses/grammar/java/LanguageJava.kt b/src/org/perses/grammar/java/LanguageJava.kt index 59c026104..ce41980e3 100644 --- a/src/org/perses/grammar/java/LanguageJava.kt +++ b/src/org/perses/grammar/java/LanguageJava.kt @@ -20,19 +20,13 @@ import com.google.common.collect.ImmutableSet import org.perses.program.EnumFormatControl import org.perses.program.LanguageKind -object LanguageJava : LanguageKind() { - - override val name = "java" - - override val extensions = ImmutableSet.of("java") - - override val defaultCodeFormatControl = EnumFormatControl.SINGLE_TOKEN_PER_LINE - - override val defaultFormmaterCommand = null - - override val allowedCodeFormatControl = ImmutableSet.of( +object LanguageJava : LanguageKind( + name = "java", + extensions = ImmutableSet.of("java"), + defaultCodeFormatControl = EnumFormatControl.SINGLE_TOKEN_PER_LINE, + allowedCodeFormatControl = ImmutableSet.of( EnumFormatControl.SINGLE_TOKEN_PER_LINE, EnumFormatControl.COMPACT_ORIG_FORMAT, EnumFormatControl.ORIG_FORMAT ) -} +) diff --git a/src/org/perses/grammar/rust/LanguageRust.kt b/src/org/perses/grammar/rust/LanguageRust.kt index 3759a7104..708966ef7 100644 --- a/src/org/perses/grammar/rust/LanguageRust.kt +++ b/src/org/perses/grammar/rust/LanguageRust.kt @@ -16,22 +16,47 @@ */ package org.perses.grammar.rust +import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet import org.perses.program.EnumFormatControl import org.perses.program.LanguageKind +import org.perses.util.ShellCommandOnPath -object LanguageRust : LanguageKind() { - - override val name = "rust" - - override val extensions = ImmutableSet.of("rs") - - override val defaultCodeFormatControl = EnumFormatControl.COMPACT_ORIG_FORMAT - - override val defaultFormmaterCommand = tryObtainingDefaultFormatter("rustfmt") - - override val allowedCodeFormatControl = ImmutableSet.of( +object LanguageRust : LanguageKind( + name = "rust", + extensions = ImmutableSet.of("rs"), + defaultCodeFormatControl = EnumFormatControl.SINGLE_TOKEN_PER_LINE, + allowedCodeFormatControl = ImmutableSet.of( + EnumFormatControl.SINGLE_TOKEN_PER_LINE, EnumFormatControl.COMPACT_ORIG_FORMAT, EnumFormatControl.ORIG_FORMAT + ), + defaultFormaterCommand = createPotentialCodeFormatterList( + ShellCommandOnPath.tryCreating("rustfmt"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.47.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.46.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.45.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.44.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.43.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.42.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.41.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.40.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.39.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.38.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.37.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.36.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.35.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.34.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.33.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.32.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.31.0"), + ShellCommandOnPath.tryCreating("rustfmt", "+1.30.0") ) +) { + + override fun getDefaultWorkingFormatter(): ShellCommandOnPath? { + return defaultFormaterCommand.asSequence().firstOrNull { + it.runWith(ImmutableList.of("--help")).exitCode == 0 + } + } } diff --git a/src/org/perses/grammar/rust/Rust.g4 b/src/org/perses/grammar/rust/Rust.g4 index 604e4ace1..5fd4781b7 100644 --- a/src/org/perses/grammar/rust/Rust.g4 +++ b/src/org/perses/grammar/rust/Rust.g4 @@ -881,7 +881,7 @@ visibility: visibility_restriction: '(' 'crate' ')' | '(' 'super' ')' - | '(' 'in' ident ')'; + | '(' 'in' simple_path ')'; item: attr* visibility? pub_item @@ -976,8 +976,7 @@ associated_static_decl: 'static' 'mut'? ident ':' ty_sum';'; const_decl: - 'const' (ident|'_') ':' ty_sum '=' expr ';'; -// | 'const' (ident|'_') ':' ty_sum '=' '(' ')' ';'; + 'default'? 'const' (ident|'_') ':' ty_sum '=' expr ';'; associated_const_decl: 'const' ident (':' ty_sum)? ';'; //experimental: const ident syntactic but not semantically @@ -998,7 +997,7 @@ foreign_fn_decl: //macro declaration here is not documented, macro_decl: - macro_head ( '(' param_list? ')' )? fn_rtype? where_clause? tt; + macro_head ( '(' tt* ')' )? fn_rtype? where_clause? tt; // tt* should be replaced onced offical grammar is released macro_head: 'macro' ident type_parameter?; @@ -1042,11 +1041,11 @@ method_param_list: // Instead, the `pat` is restricted to a few short, simple cases. trait_method_param: '...' - | attr* restricted_pat ':' attr* ty_sum + | attr* ( ('(' (restricted_pat ',')* restricted_pat')' ) | restricted_pat) ':' attr* ty_sum | attr* ty_sum; restricted_pat: - ('&' | '&&' | 'mut')? ('_' | ident); + 'ref'? ('&' | '&&' | 'mut')? ('_' | ident); trait_method_param_list: attr* (trait_method_param | self_param) (',' trait_method_param)* ','?; @@ -1095,7 +1094,7 @@ enum_decl: 'enum' ident type_parameters? where_clause? '{' enum_variant_list? '}'; enum_variant: - attr* visibility? enum_variant_main; + attr* visibility? enum_variant_main ('=' lit)?; enum_variant_list: enum_variant (',' enum_variant)* ','?; @@ -1255,6 +1254,7 @@ simple_path: simple_path_segment: ident + | 'super' | 'Self' | 'crate' | '$crate'; @@ -1296,7 +1296,8 @@ type_path_segment: | 'super'; ty_path_segment_no_super: - (ident | 'Self') type_arguments?; + '(' (ident | 'Self')? ')' type_arguments? + | (ident | 'Self'| '&raw') type_arguments?; // === Type bounds @@ -1309,7 +1310,7 @@ where_bound_list: where_bound: lifetime ':' lifetime_bound - | for_lifetimes? type empty_ok_colon_bound; + | for_lifetimes? type empty_ok_colon_bound ?; empty_ok_colon_bound: ':' bound?; @@ -1425,6 +1426,8 @@ type_argument: ident '=' ty_sum | ty_sum | BareIntLit + | 'true' + | 'false' ; // TODO(cnsun): get rid of this. @@ -1436,7 +1439,7 @@ ty_sum_list: type_parameters: '<' lifetime_param_list '>' - | '<' (lifetime_param ',')* type_parameter_list '>'; + | '<' (lifetime_param ',')* type_parameter_list? '>'; lifetime_param: attr* 'const'? lifetime (':' lifetime_bound)?; @@ -1445,7 +1448,8 @@ lifetime_param_list: lifetime_param (',' lifetime_param)* ','?; type_parameter: - attr* 'const'? ident colon_bound? ty_default?; + attr* 'const'? ident colon_bound? ty_default? + | ty_sum; type_parameter_list: type_parameter (',' type_parameter)* ','?; @@ -1525,8 +1529,8 @@ pat_fields: | pat_field (',' pat_field)* (',' '..' | ','?); pat_field: - 'box'? 'ref'? 'mut'? ident - | ident ':' pattern; + attr* 'box'? 'ref'? 'mut'? ident + | attr* ident ':' pattern; // === Expressions @@ -1642,7 +1646,7 @@ prim_expr_no_struct | 'static'? 'move'? closure_params closure_tail | 'async' 'move' (blocky_expr | closure_params closure_tail) | blocky_expr - | 'break' lifetime_or_expr? + | 'break' lifetime_or_expr? lit? item? expr? //experimental: label/loop break value | 'continue' lifetime? | 'return' expr? // this is IMO a rustc bug, should be expr_no_struct | 'yield' expr? @@ -1662,6 +1666,7 @@ lit: closure_params : '|' '|' | '||' + | '|_|' | '|' closure_param_list? '|'; closure_param: @@ -1712,6 +1717,7 @@ pre_expr: | expr_attrs pre_expr | '-' pre_expr | '!' pre_expr + | '&raw' | '&' 'mut'? pre_expr | '&&' 'mut'? pre_expr // meaning `& & expr` | '*' pre_expr @@ -1860,6 +1866,8 @@ ident: | 'default' | 'union' | 'try' + | 'crate' + | 'macro_rules' | RawIdentifier ; @@ -2057,7 +2065,7 @@ BareIntLit: DEC_DIGITS; fragment INT_SUFFIX: - [ui] ('8'|'16'|'32'|'64'|'size'); + [ui] ('8'|'16'|'32'|'64'|'128'|'size'); FullIntLit: DEC_DIGITS INT_SUFFIX? @@ -2066,7 +2074,7 @@ FullIntLit: | '0b' '_'* [01] [01_]* INT_SUFFIX?; fragment EXPONENT: - [Ee] [+-]? '_'* [0-9] [0-9_]*; + [Ee] [+-]? 'd_'* [0-9] [0-9_]*; fragment FLOAT_SUFFIX: 'f32' diff --git a/src/org/perses/grammar/scala/LanguageScala.kt b/src/org/perses/grammar/scala/LanguageScala.kt index 55cad36f2..760fe752f 100644 --- a/src/org/perses/grammar/scala/LanguageScala.kt +++ b/src/org/perses/grammar/scala/LanguageScala.kt @@ -20,18 +20,12 @@ import com.google.common.collect.ImmutableSet import org.perses.program.EnumFormatControl import org.perses.program.LanguageKind -object LanguageScala : LanguageKind() { - - override val name = "scala" - - override val extensions = ImmutableSet.of("scala", "sc") - - override val defaultCodeFormatControl = EnumFormatControl.COMPACT_ORIG_FORMAT - - override val defaultFormmaterCommand = null - - override val allowedCodeFormatControl = ImmutableSet.of( +object LanguageScala : LanguageKind( + name = "scala", + extensions = ImmutableSet.of("scala", "sc"), + defaultCodeFormatControl = EnumFormatControl.COMPACT_ORIG_FORMAT, + allowedCodeFormatControl = ImmutableSet.of( EnumFormatControl.COMPACT_ORIG_FORMAT, EnumFormatControl.ORIG_FORMAT ) -} +) diff --git a/src/org/perses/program/AbstractSourceFile.kt b/src/org/perses/program/AbstractSourceFile.kt index 578fe79cb..9cdf4cd8d 100644 --- a/src/org/perses/program/AbstractSourceFile.kt +++ b/src/org/perses/program/AbstractSourceFile.kt @@ -16,9 +16,7 @@ */ package org.perses.program -import com.google.common.io.MoreFiles import java.io.File -import java.nio.charset.StandardCharsets abstract class AbstractSourceFile(val file: File) { val fileContent: String @@ -29,13 +27,12 @@ abstract class AbstractSourceFile(val file: File) { val parentFile: File get() = file.parentFile - fun writeTo(path: File) = - MoreFiles.asCharSink(path.toPath(), StandardCharsets.UTF_8).write(fileContent) + fun writeTo(path: File) = path.writeText(fileContent) init { require(file.isFile) { "The file should be a regular file $file" } - fileContent = MoreFiles.asCharSource(file.toPath(), StandardCharsets.UTF_8).read() + fileContent = file.readText() } } diff --git a/src/org/perses/program/LanguageKind.kt b/src/org/perses/program/LanguageKind.kt index e1805081c..12e64ca2d 100644 --- a/src/org/perses/program/LanguageKind.kt +++ b/src/org/perses/program/LanguageKind.kt @@ -20,27 +20,50 @@ import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableSet import org.perses.util.ShellCommandOnPath -abstract class LanguageKind { +abstract class LanguageKind( + val name: String, + val extensions: ImmutableSet, + val defaultCodeFormatControl: EnumFormatControl, + val allowedCodeFormatControl: ImmutableSet, + protected val defaultFormaterCommand: ImmutableList = ImmutableList.of() +) { - abstract val name: String - - abstract val extensions: ImmutableSet - - abstract val defaultCodeFormatControl: EnumFormatControl + init { + check(defaultCodeFormatControl in allowedCodeFormatControl) { + "The default code format $defaultFormaterCommand is not in $allowedCodeFormatControl" + } + } - abstract val allowedCodeFormatControl: ImmutableSet + open fun getDefaultWorkingFormatter(): ShellCommandOnPath? { + return if (defaultFormaterCommand.isEmpty()) { + null + } else { + defaultFormaterCommand[0] + } + } - abstract val defaultFormmaterCommand: ShellCommandOnPath? + fun getAllDefaultFormatterCommandStrings() = defaultFormaterCommand + .fold( + StringBuilder(), + { builder, shellCmd -> + builder.append("'$shellCmd'").append(", ") + } + ).toString() fun isCodeFormatAllowed(codeFormat: EnumFormatControl) = allowedCodeFormatControl.contains(codeFormat) - protected fun tryObtainingDefaultFormatter( - formamtterCmd: String, - defaultFlags: ImmutableList = ImmutableList.of() - ) = try { - ShellCommandOnPath(formamtterCmd, defaultFlags) - } catch (e: Exception) { - null + companion object { + + @JvmStatic + fun createPotentialCodeFormatterList(vararg formatters: ShellCommandOnPath?) = + formatters + .asSequence() + .filter { it != null } + .fold( + ImmutableList.builder(), + { builder, formatter -> builder.add(formatter!!) } + ) + .build()!! } } diff --git a/src/org/perses/reduction.bzl b/src/org/perses/reduction.bzl index 66fb90f3f..6fa92209d 100644 --- a/src/org/perses/reduction.bzl +++ b/src/org/perses/reduction.bzl @@ -23,10 +23,6 @@ def reduce( result_file = result_file or "reduced_%s_result_%s" % (name, source_file) statistics_file = statistics_file or "%s_statistics.txt" % name progress_dump_file = progress_dump_file or "%s_progress.txt" % name - if enable_query_caching == None: - enable_query_caching = True - if enable_edit_caching == None: - enable_edit_caching = True if enable_token_slicer == None: enable_token_slicer = False if enable_tree_slicer == None: @@ -45,11 +41,14 @@ def reduce( "--output-file $(location %s)" % result_file, "--stat-dump-file $(location %s)" % statistics_file, "--progress-dump-file $(location %s)" % progress_dump_file, - "--query-caching %s" % ("true" if enable_query_caching else "false"), - "--edit-caching %s" % ("true" if enable_edit_caching else "false"), "--enable-token-slicer %s" % ("true" if enable_token_slicer else "false"), "--enable-tree-slicer %s" % ("true" if enable_tree_slicer else "false"), ] + + if enable_query_caching != None: + args.append("--query-caching %s" % ("true" if enable_query_caching else "false")) + if enable_edit_caching != None: + args.append("--edit-caching %s" % ("true" if enable_edit_caching else "false")) if call_formatter != None: args.append("--call-formatter %s" % ("true" if call_formatter else "false")) args.append("&>") diff --git a/src/org/perses/reduction/BUILD b/src/org/perses/reduction/BUILD index fe7852724..a1b2dbcf4 100644 --- a/src/org/perses/reduction/BUILD +++ b/src/org/perses/reduction/BUILD @@ -5,6 +5,11 @@ package(default_visibility = [ load("@io_bazel_rules_kotlin//kotlin:kotlin.bzl", "kt_jvm_library") +kt_jvm_library( + name = "enum_query_caching_control", + srcs = ["EnumQueryCachingControl.kt"], +) + java_library( name = "test_script_execution_cache", srcs = [ @@ -155,6 +160,7 @@ kt_jvm_library( deps = [ ":abstract_reducer", ":actionset_profiler", + ":enum_query_caching_control", ":reducer_factory", ":reduction_configuration", ":test_script_execution_cache", diff --git a/src/org/perses/reduction/EnumQueryCachingControl.kt b/src/org/perses/reduction/EnumQueryCachingControl.kt new file mode 100644 index 000000000..cfdc11eff --- /dev/null +++ b/src/org/perses/reduction/EnumQueryCachingControl.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018-2020 University of Waterloo. + * + * This file is part of Perses. + * + * Perses is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * Perses is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Perses; see the file LICENSE. If not see . + */ +package org.perses.reduction + +enum class EnumQueryCachingControl { + TRUE, + FALSE, + AUTO; + + companion object { + fun convert(string: String): EnumQueryCachingControl? { + return when (string.toLowerCase()) { + "true" -> TRUE + "false" -> FALSE + "auto" -> AUTO + else -> null + } + } + } +} diff --git a/src/org/perses/reduction/ReductionDriver.kt b/src/org/perses/reduction/ReductionDriver.kt index 401745954..64d719732 100644 --- a/src/org/perses/reduction/ReductionDriver.kt +++ b/src/org/perses/reduction/ReductionDriver.kt @@ -21,7 +21,6 @@ import com.google.common.base.Strings import com.google.common.collect.ImmutableList import com.google.common.flogger.FluentLogger import com.google.common.io.Files -import com.google.common.io.MoreFiles import org.antlr.v4.runtime.tree.ParseTree import org.perses.CommandOptions import org.perses.grammar.AbstractParserFacade @@ -31,6 +30,7 @@ import org.perses.listener.ProgressMonitorForNodeReducer import org.perses.listener.ReductionProfileListener import org.perses.listener.StatisticsListener import org.perses.listener.TestScriptExecutionListener +import org.perses.program.EnumFormatControl import org.perses.program.ScriptFile import org.perses.program.SourceFile import org.perses.program.TokenizedProgramFactory @@ -51,7 +51,6 @@ import org.perses.util.TimeUtil import java.io.Closeable import java.io.File import java.io.IOException -import java.nio.charset.StandardCharsets /** * This is the main entry to invoke Perses reducer. It does not have a main, but is the main entry @@ -59,7 +58,7 @@ import java.nio.charset.StandardCharsets */ class ReductionDriver( private val cmd: CommandOptions, - private val parserFacadeFactory: ParserFacadeFactory, + parserFacadeFactory: ParserFacadeFactory, vararg extraListeners: AbstractReductionListener ) : Closeable { @@ -103,6 +102,11 @@ class ReductionDriver( "The reduction process started at %s", TimeUtil.formatDateForDisplay(System.currentTimeMillis()) ) + logger.atInfo().log( + "Cache setting: query-caching=%s, edit-caching=%s", + booleanToEnabledOrDisabled(configuration.enableTestScriptExecutionCaching), + booleanToEnabledOrDisabled(cmd.cacheControlFlags.nodeActionSetCaching) + ) backupFile(configuration) val worker = createMainReducer() val sparTreeEditListeners = createSparTreeEditListeners(configuration) @@ -118,8 +122,7 @@ class ReductionDriver( val fileToReduce = configuration.fileToReduce val bestFile = configuration.bestResultFile if (fileToReduce.file.canonicalPath != bestFile.canonicalPath) { - MoreFiles.asCharSink(bestFile.toPath(), StandardCharsets.UTF_8) - .write(fileToReduce.fileContent) + bestFile.writeText(fileToReduce.fileContent) } } listenerManager.onReductionStart(tree, tree.originalTokenCount) @@ -157,7 +160,7 @@ class ReductionDriver( "The tokenized program factory should be unchanged during a reduction process." } check( - tree.tokenizedProgramFactory.tokenFactory== + tree.tokenizedProgramFactory.tokenFactory == originalTokenizedProgramFactory.tokenFactory ) { "The perses token factory should be unchanged during a reduction process." @@ -201,7 +204,7 @@ class ReductionDriver( captureOutput = false, environment = Shell.CURRENT_ENV ) - if (cmdOutput.exitCode!=0) { + if (cmdOutput.exitCode != 0) { val tempDir = copyFilesToTempDir(reductionFolder.folder) logger.atSevere().log( "C-Reduce failed to reduce the file. All files are copied to %s", @@ -226,19 +229,17 @@ class ReductionDriver( private fun constructFullCreduceCommand( creduceCmd: String, reductionFolder: ReductionFolder - ): String { - return StringBuilder() - .append(creduceCmd) - .append(' ') - .append(reductionFolder.testScript.scriptFile.name) - .append(' ') - .append(reductionFolder.sourceFilePath.name) - .toString() - } + ) = StringBuilder() + .append(creduceCmd) + .append(' ') + .append(reductionFolder.testScript.scriptFile.name) + .append(' ') + .append(reductionFolder.sourceFilePath.name) + .toString() private fun shouldExitFixpointIteration(initialTokenCount: Int): Boolean { check(initialTokenCount >= tree.tokenCount) - return !configuration.fixpointReduction || initialTokenCount==tree.tokenCount + return !configuration.fixpointReduction || initialTokenCount == tree.tokenCount } private fun runTreeSlicerIfEnabled(initialTokenCount: Int) { @@ -293,7 +294,7 @@ class ReductionDriver( currentFixpointIteration, preSize, mainReducer.redcucerAnnotation ) val reductionState = ReductionState(tree) - assert(reductionState.sparTree==tree) + assert(reductionState.sparTree == tree) mainReducer.reduce(reductionState) val scriptExecutionNumberAfter = executorService.statistics.getScriptExecutionNumber() val countOfTestScriptExecutionsInThisIteration = @@ -329,13 +330,16 @@ class ReductionDriver( if (!future.get().isPass) { logger.atFine().log("The initial sanity check failed. Folder: %s", future.workingDirectory) val tempDir = copyFilesToTempDir(future.workingDirectory) - logger.atSevere().log("***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** *****") - logger.atSevere().log("*") - logger.atSevere().log("* The initial sanity check failed.") - logger.atSevere().log("* The files have been saved, and you can check them at:") - logger.atSevere().log("* $tempDir") - logger.atSevere().log("*") - logger.atSevere().log("***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** *****") + logger.atSevere().apply { + log("***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** *****") + log("*") + log("* The initial sanity check failed.") + log("* The files have been saved, and you can check them at:") + log("* $tempDir") + log("*") + log("***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** *****") + } + throw IllegalStateException() } check(future.get().isPass) { @@ -358,7 +362,14 @@ class ReductionDriver( if (!cmd.outputRefiningFlags.callFormatter) { return } - val formatCmd = configuration.parserFacade.language.defaultFormmaterCommand ?: return + val formatCmd = configuration.parserFacade.language.getDefaultWorkingFormatter() + if (formatCmd == null) { + logger.atSevere().log( + "The default formatter is not working. cmd=%s", + configuration.parserFacade.language.getAllDefaultFormatterCommandStrings() + ) + return + } val formatFolderName = "formatter_at_the_end_" + TimeUtil.formatDateForFileName(System.currentTimeMillis()) @@ -373,14 +384,14 @@ class ReductionDriver( ImmutableList.of(formatFolder.sourceFilePath.name), workingDirectory = formatFolder.folder ) - if (cmdOutput.exitCode!=0) { + if (cmdOutput.exitCode != 0) { logger.atSevere().log( "Failed to call formatter %s on the final result %s.", formatCmd.command, formatFolder.sourceFilePath ) - logger.atSevere().log("stdout: %s", cmdOutput.stderr.combineLines()) - logger.atSevere().log("stderr: %s", cmdOutput.stdout.combineLines()) + logger.atSevere().log("stdout: %s", cmdOutput.stderr.combinedLines) + logger.atSevere().log("stderr: %s", cmdOutput.stdout.combinedLines) return } val scriptTestResult = formatFolder.testScript.test() @@ -512,7 +523,7 @@ class ReductionDriver( configuration.workingFolder, baseName + "." + TimeUtil.formatDateForFileName(System.currentTimeMillis()) + ".orig" ) - MoreFiles.asCharSink(backupFile.toPath(), StandardCharsets.UTF_8).write(fileContent) + backupFile.writeText(fileContent) } companion object { @@ -530,7 +541,7 @@ class ReductionDriver( ) val testScript = ScriptFile(cmd.compulsoryFlags.getTestScript().absoluteFile) - require(sourceFile.parentFile.absolutePath==testScript.parentFile.absolutePath) { + require(sourceFile.parentFile.absolutePath == testScript.parentFile.absolutePath) { "The source file and the test script should reside in the same folder. " + "sourceFile:$sourceFile, testScript:$testScript" } @@ -544,7 +555,7 @@ class ReductionDriver( else File(cmd.profilingFlags.progressDumpFile) val programFormatControl = cmd.reductionControlFlags.codeFormat.let { codeFormat -> - if (codeFormat!=null) { + if (codeFormat != null) { check(sourceFile.languageKind.isCodeFormatAllowed(codeFormat)) { "$codeFormat is not allowed for language ${sourceFile.languageKind}" } @@ -563,13 +574,28 @@ class ReductionDriver( progressDumpFile = progressDumpFile, programFormatControl = programFormatControl, fixpointReduction = cmd.reductionControlFlags.fixpoint, - enableTestScriptExecutionCaching = cmd.cacheControlFlags.queryCaching, + enableTestScriptExecutionCaching = computeWhetherToEnableQueryCaching( + cmd.cacheControlFlags.queryCaching, + programFormatControl + ), useRealDeltaDebugger = cmd.algorithmControlFlags.useRealDeltaDebugger, numOfReductionThreads = cmd.reductionControlFlags.getNumOfThreads(), parserFacadeFactory = parserFacadeFactory ) } + fun booleanToEnabledOrDisabled(value: Boolean) = if (value) "enabled" else "disabled" + + private fun computeWhetherToEnableQueryCaching( + userSpecified: EnumQueryCachingControl, + programFormatControl: EnumFormatControl + ) = when (userSpecified) { + EnumQueryCachingControl.TRUE -> true + EnumQueryCachingControl.FALSE -> false + EnumQueryCachingControl.AUTO -> + programFormatControl == EnumFormatControl.SINGLE_TOKEN_PER_LINE + } + private fun createTokenizedProgramFactory(originalTree: ParseTree): TokenizedProgramFactory { val tokens = AbstractParserFacade.getTokens(originalTree) return TokenizedProgramFactory.createFactory(tokens) diff --git a/src/org/perses/util/Shell.kt b/src/org/perses/util/Shell.kt index 89fe677e2..612fd298b 100644 --- a/src/org/perses/util/Shell.kt +++ b/src/org/perses/util/Shell.kt @@ -110,7 +110,6 @@ object Shell { } } - class CmdOutput constructor( val exitCode: Int, val stdout: ShellOutputLines, @@ -120,15 +119,14 @@ object Shell { override fun toString(): String { return MoreObjects.toStringHelper(this) .add("exitCode", exitCode) - .add("stdout", stdout.combineLines()) - .add("stderr", stderr.combineLines()) + .add("stdout", stdout.combinedLines) + .add("stderr", stderr.combinedLines) .toString() } } private val logger = FluentLogger.forEnclosingClass() - private val EMPTY_OUTPUT_STREAM: OutputStream = object : OutputStream() { override fun write(b: Int) { // Discard all the input. diff --git a/src/org/perses/util/ShellCommandOnPath.kt b/src/org/perses/util/ShellCommandOnPath.kt index 859694e11..6f6110aa6 100644 --- a/src/org/perses/util/ShellCommandOnPath.kt +++ b/src/org/perses/util/ShellCommandOnPath.kt @@ -29,7 +29,8 @@ import java.util.Arrays */ class ShellCommandOnPath( command: String, - val defaultFlags: ImmutableList = ImmutableList.of()) { + val defaultFlags: ImmutableList = ImmutableList.of() +) { private val path = Paths.get(command) @@ -60,6 +61,23 @@ class ShellCommandOnPath( private val logger = FluentLogger.forEnclosingClass() + @JvmStatic + fun tryCreating( + command: String, + defaultFlags: ImmutableList = ImmutableList.of() + ) = + try { + ShellCommandOnPath(command, defaultFlags) + } catch (e: Exception) { + null + } + + @JvmStatic + fun tryCreating( + command: String, + vararg defaultFlags: String + ) = tryCreating(command, ImmutableList.copyOf(defaultFlags)) + @JvmStatic fun normalizeAndCheckExecutability(cmdName: String): String { val cmdPath = Paths.get(cmdName) @@ -91,6 +109,5 @@ class ShellCommandOnPath( } return cmdPath.toAbsolutePath().toString() } - } } diff --git a/src/org/perses/util/ShellOutputLines.kt b/src/org/perses/util/ShellOutputLines.kt index 2ff9ed615..48af27272 100644 --- a/src/org/perses/util/ShellOutputLines.kt +++ b/src/org/perses/util/ShellOutputLines.kt @@ -26,16 +26,16 @@ data class ShellOutputLines(val lines: ImmutableList) { /** * Returns true if there is a line contains the string. */ - fun anyLineContains(needle: String) = lines.asSequence().any { + fun anyLineContains(needle: String) = lines.any { it.contains(needle) } fun hasLines() = !lines.isEmpty() - fun combineLines(): String { - val builder = StringBuilder() - lines.forEach { builder.append(it).append('\n') } - return builder.toString() + val combinedLines by lazy { + StringBuilder(lines.map { it.length + 1 }.sum()).apply { + lines.forEach { line -> append(line).append('\n') } + }.toString() } fun writeToFile(file: File) { diff --git a/test/org/perses/benchmark_toys/delta_1/BUILD b/test/org/perses/benchmark_toys/delta_1/BUILD index a50ff9d95..82e055930 100644 --- a/test/org/perses/benchmark_toys/delta_1/BUILD +++ b/test/org/perses/benchmark_toys/delta_1/BUILD @@ -10,6 +10,8 @@ sanity_test( reduction_golden_test( name = "reduction_golden_test", + enable_edit_caching = True, + enable_query_caching = True, golden_progress_file = "golden_reduction_progress.txt", golden_reduced_file = "golden_reduced_t.c", progress_dump_file = "reduction_progress.txt", diff --git a/test/org/perses/benchmark_toys/delta_1/golden_reduction_progress.txt b/test/org/perses/benchmark_toys/delta_1/golden_reduction_progress.txt index a992eb040..3d55f1342 100644 --- a/test/org/perses/benchmark_toys/delta_1/golden_reduction_progress.txt +++ b/test/org/perses/benchmark_toys/delta_1/golden_reduction_progress.txt @@ -342,7 +342,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -1 entries are removed: 8 --> 7. +2 entries are removed: 8 --> 6. ------------------------------------------------------------ @@ -391,7 +391,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -2 entries are removed: 9 --> 7. +2 entries are removed: 8 --> 6. ------------------------------------------------------------ @@ -413,7 +413,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -4 entries are removed: 8 --> 4. +5 entries are removed: 7 --> 2. ------------------------------------------------------------ @@ -646,7 +646,7 @@ It took less than 1 second to cancel the task. ===========TestScriptExecutionCacheEntryEviction============ -4 entries are removed: 10 --> 6. +6 entries are removed: 8 --> 2. ------------------------------------------------------------ diff --git a/test/org/perses/benchmark_toys/go_print/BUILD b/test/org/perses/benchmark_toys/go_print/BUILD index f6c4af02d..7a0f51e08 100644 --- a/test/org/perses/benchmark_toys/go_print/BUILD +++ b/test/org/perses/benchmark_toys/go_print/BUILD @@ -32,6 +32,8 @@ reduce( reduction_golden_test( name = "reduction_golden_test", + enable_edit_caching = True, + enable_query_caching = True, golden_progress_file = "golden_reduction_progress.txt", golden_reduced_file = "golden_reduced_small.go", progress_dump_file = "reduction_progress.txt", diff --git a/test/org/perses/benchmark_toys/parentheses/BUILD b/test/org/perses/benchmark_toys/parentheses/BUILD index b038f8b73..6f204c895 100644 --- a/test/org/perses/benchmark_toys/parentheses/BUILD +++ b/test/org/perses/benchmark_toys/parentheses/BUILD @@ -8,6 +8,8 @@ sanity_test( reduction_golden_test( name = "reduction_golden_test", + enable_edit_caching = True, + enable_query_caching = True, golden_progress_file = "golden_reduction_progress.txt", golden_reduced_file = "golden_reduced_t.c", progress_dump_file = "reduction_progress.txt", diff --git a/test/org/perses/benchmark_toys/parentheses/golden_reduction_progress.txt b/test/org/perses/benchmark_toys/parentheses/golden_reduction_progress.txt index 73c1f0b00..b48acef08 100644 --- a/test/org/perses/benchmark_toys/parentheses/golden_reduction_progress.txt +++ b/test/org/perses/benchmark_toys/parentheses/golden_reduction_progress.txt @@ -319,7 +319,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -1 entries are removed: 8 --> 7. +2 entries are removed: 8 --> 6. ------------------------------------------------------------ @@ -595,7 +595,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -1 entries are removed: 15 --> 14. +6 entries are removed: 14 --> 8. ------------------------------------------------------------ @@ -724,7 +724,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -1 entries are removed: 17 --> 16. +3 entries are removed: 11 --> 8. ------------------------------------------------------------ @@ -861,7 +861,7 @@ It took less than 1 second to cancel the task. ===========TestScriptExecutionCacheEntryEviction============ -11 entries are removed: 19 --> 8. +9 entries are removed: 11 --> 2. ------------------------------------------------------------ @@ -1126,7 +1126,7 @@ It took less than 1 second to cancel the task. ===========TestScriptExecutionCacheEntryEviction============ -6 entries are removed: 16 --> 10. +9 entries are removed: 10 --> 1. ------------------------------------------------------------ @@ -1199,7 +1199,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -5 entries are removed: 12 --> 7. +3 entries are removed: 3 --> 0. ------------------------------------------------------------ @@ -1366,7 +1366,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -3 entries are removed: 11 --> 8. +4 entries are removed: 4 --> 0. ------------------------------------------------------------ diff --git a/test/org/perses/benchmark_toys/rs_print/BUILD b/test/org/perses/benchmark_toys/rs_print/BUILD index 8fcae15b8..4c6a9c1fe 100644 --- a/test/org/perses/benchmark_toys/rs_print/BUILD +++ b/test/org/perses/benchmark_toys/rs_print/BUILD @@ -34,7 +34,8 @@ genrule( name = "format_rs_from_reduced_rs_print", srcs = ["hello_reduced.rs"], outs = ["golden_file_format_rs_from_reduced_rs_print.rs"], - cmd = "cat $(location hello_reduced.rs) | rustfmt > $@", + cmd = "$(location rustfmt_wrapper.sh) $(location hello_reduced.rs) $@", + tools = ["rustfmt_wrapper.sh"], ) reduce( @@ -56,6 +57,8 @@ golden_test( reduction_golden_test( name = "reduction_golden_test", + enable_edit_caching = True, + enable_query_caching = True, golden_progress_file = "golden_reduction_progress.txt", golden_reduced_file = "golden_reduced_hello.rs", progress_dump_file = "reduction_progress.txt", diff --git a/test/org/perses/benchmark_toys/rs_print/golden_reduction_progress.txt b/test/org/perses/benchmark_toys/rs_print/golden_reduction_progress.txt index 5fa8f9c36..657a5eba1 100644 --- a/test/org/perses/benchmark_toys/rs_print/golden_reduction_progress.txt +++ b/test/org/perses/benchmark_toys/rs_print/golden_reduction_progress.txt @@ -165,7 +165,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -1 entries are removed: 6 --> 5. +2 entries are removed: 6 --> 4. ------------------------------------------------------------ @@ -202,7 +202,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -2 entries are removed: 7 --> 5. +3 entries are removed: 6 --> 3. ------------------------------------------------------------ diff --git a/test/org/perses/benchmark_toys/rs_print/rustfmt_wrapper.sh b/test/org/perses/benchmark_toys/rs_print/rustfmt_wrapper.sh new file mode 100755 index 000000000..86337ba85 --- /dev/null +++ b/test/org/perses/benchmark_toys/rs_print/rustfmt_wrapper.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -o pipefail +set -o nounset + +if [[ "$#" != 2 ]] ; then + echo "USAGE: $0 " + exit 1 +fi + +ALTS=("rustfmt" + "rustfmt +1.47.0" + "rustfmt +1.46.0" + "rustfmt +1.45.0" + "rustfmt +1.44.0" + "rustfmt +1.43.0" + "rustfmt +1.42.0" + "rustfmt +1.41.0" + "rustfmt +1.40.0" + "rustfmt +1.39.0" + "rustfmt +1.38.0" + "rustfmt +1.37.0" + "rustfmt +1.36.0" + "rustfmt +1.35.0" + "rustfmt +1.34.0" + "rustfmt +1.33.0" + "rustfmt +1.32.0" + "rustfmt +1.31.0" + "rustfmt +1.30.0" + "rustfmt +1.29.0" + "rustfmt +1.28.0" + "rustfmt +1.27.0" +) + +readonly TMP=$(mktemp) +trap "rm ${TMP}" TRAP +cp "${1}" "${TMP}" +for alt in "${ALTS[@]}" ; do + if ${alt} "${TMP}" ; then + cp "${TMP}" "${2}" + exit 0 + fi +done +exit 1 \ No newline at end of file diff --git a/test/org/perses/golden_perses_cmd_usage.txt b/test/org/perses/golden_perses_cmd_usage.txt index 37c232fea..ca0296977 100644 --- a/test/org/perses/golden_perses_cmd_usage.txt +++ b/test/org/perses/golden_perses_cmd_usage.txt @@ -53,7 +53,8 @@ Usage: org.perses.Main [options] Default: false --query-caching Enable query caching for test script executions. - Default: false + Default: AUTO + Possible Values: [TRUE, FALSE, AUTO] --edit-caching Enable caching for edits performed between two successful reductions. Default: true @@ -63,7 +64,7 @@ Usage: org.perses.Main [options] tokens of the best program at last refresh. t'' - tokens of the current best program. Refresh threshold requires an integer input ranging [0, 100]. e.g. 0 represents 0%, 85 represents 85%. - Default: 100 + Default: 0 --progress-dump-file The file to record the reduction process. The dump file can be large.. --stat-dump-file diff --git a/test/org/perses/grammar/c/PnfCParserFacadeTest.kt b/test/org/perses/grammar/c/PnfCParserFacadeTest.kt index e81aeef00..94aff98bc 100644 --- a/test/org/perses/grammar/c/PnfCParserFacadeTest.kt +++ b/test/org/perses/grammar/c/PnfCParserFacadeTest.kt @@ -52,8 +52,9 @@ class PnfCParserFacadeTest { |return 0;} """.trimMargin() tempFile.writeText(orig) - facade.language.defaultFormmaterCommand!!.runWith(ImmutableList.of(tempFile.toString())) + facade.language.getDefaultWorkingFormatter()!! + .runWith(ImmutableList.of(tempFile.toString())) val formatted = tempFile.readText() assertThat(orig).isNotEqualTo(formatted) } -} \ No newline at end of file +} diff --git a/test/org/perses/grammar/rust/BUILD b/test/org/perses/grammar/rust/BUILD index 695654348..5d4be0da8 100644 --- a/test/org/perses/grammar/rust/BUILD +++ b/test/org/perses/grammar/rust/BUILD @@ -18,7 +18,10 @@ kt_jvm_test( name = "PnfRustParserFacadeTest", size = "enormous", # This is a slow test. srcs = ["PnfRustParserFacadeTest.kt"], - data = ["golden_fail_list.txt"], + data = [ + "golden_fail_list.txt", + "//test_data/rust_programs:whole_rust_repo", + ], shard_count = 7, test_class = "org.perses.grammar.rust.PnfRustParserFacadeTest", deps = [ diff --git a/test/org/perses/grammar/rust/PnfRustParserFacadeTest.kt b/test/org/perses/grammar/rust/PnfRustParserFacadeTest.kt index 37dd9cc86..a04683d35 100644 --- a/test/org/perses/grammar/rust/PnfRustParserFacadeTest.kt +++ b/test/org/perses/grammar/rust/PnfRustParserFacadeTest.kt @@ -41,7 +41,7 @@ class PnfRustParserFacadeTest { @Test fun testDefaultFormatterCmd() { - assertThat(facade.language.defaultFormmaterCommand).isNotNull() + assertThat(facade.language.getDefaultWorkingFormatter()).isNotNull() val tempFile = File(workingDir, "to-be-formatted.rs") val unformatted = """ |fn main() { @@ -49,14 +49,14 @@ class PnfRustParserFacadeTest { """ tempFile.writeText(unformatted.trimMargin()) - facade.language.defaultFormmaterCommand!!.runWith(ImmutableList.of(tempFile.toString())) + facade.language.getDefaultWorkingFormatter()!!.runWith(ImmutableList.of(tempFile.toString())) val formatted = tempFile.readText() assertThat(formatted).isNotEqualTo(unformatted) - facade.language.defaultFormmaterCommand!!.runWith(ImmutableList.of(tempFile.toString())) + facade.language.getDefaultWorkingFormatter()!!.runWith(ImmutableList.of(tempFile.toString())) assertThat(formatted).isEqualTo(tempFile.readText()) } - fun testString(file: File) { + fun compareOrigAndPnfParsers(file: File) { val parseTreeFromOrigParser = facade.parseWithOrigRustParser(file) val tokensByOrigParser = TestUtility.extractTokens(parseTreeFromOrigParser.tree) @@ -68,8 +68,10 @@ class PnfRustParserFacadeTest { fun testSingleFile(file: File) { try { - testString(file) - Truth.assertWithMessage("Remove $file").that(failedTests).containsNoneIn(arrayOf(file.toString())) + compareOrigAndPnfParsers(file) + Truth.assertWithMessage("Remove $file") + .that(failedTests) + .containsNoneIn(arrayOf(file.toString())) } catch (e: Throwable) { e.printStackTrace() assertThat(failedTests).contains(file.toString()) @@ -134,7 +136,57 @@ class PnfRustParserFacadeTest { val file = File(workingDir, "test.rs") file.writeText(program) - testString(file) + compareOrigAndPnfParsers(file) + } + + @Test + fun test_compiler_rustc_ast_src_mut_visit() { + val compilerFolder = "test_data/rust_programs/rust/compiler" + val libraryFolder = "test_data/rust_programs/rust/library" + compareOrigAndPnfParsers(File("$compilerFolder/rustc_ast/src/mut_visit.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_ast/src/token.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_ast/src/tokenstream.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_ast/src/attr/mod.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_builtin_macros/src/deriving/mod.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_data_structures/src/sip128/tests.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_data_structures/src/tagged_ptr/copy.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_index/src/bit_set.rs")) + compareOrigAndPnfParsers( + File("$compilerFolder/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs") + ) + compareOrigAndPnfParsers( + File("$compilerFolder/rustc_mir/src/borrow_check/diagnostics/region_errors.rs") + ) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_mir/src/borrow_check/nll.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_mir/src/borrow_check/nll.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_mir/src/borrow_check/region_infer/mod.rs")) + compareOrigAndPnfParsers( + File("$compilerFolder/rustc_mir/src/borrow_check/region_infer/opaque_types.rs") + ) + compareOrigAndPnfParsers( + File("$compilerFolder/rustc_mir/src/borrow_check/type_check/free_region_relations.rs") + ) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_mir/src/borrow_check/type_check/mod.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_mir_build/src/build/into.rs")) + compareOrigAndPnfParsers( + File("$compilerFolder/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs") + ) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/android/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/dragonfly/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/emscripten/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/freebsd/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/haiku/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/illumos/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/ios/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/linux/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/macos/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/netbsd/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/openbsd/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/redox/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/os/solaris/fs.rs")) + compareOrigAndPnfParsers(File("$libraryFolder/std/src/sys/sgx/abi/usercalls/alloc.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_data_structures/src/tagged_ptr.rs")) + compareOrigAndPnfParsers(File("$compilerFolder/rustc_middle/src/mir/interpret/pointer.rs")) } // Collection for keeping track of the shards of tests we need to run @@ -164,7 +216,5 @@ class PnfRustParserFacadeTest { .filter { it.isNotBlank() } .fold(ImmutableSet.builder(), { builder, f -> builder.add(f) }) .build() - } - } diff --git a/test/org/perses/grammar/rust/golden_fail_list.txt b/test/org/perses/grammar/rust/golden_fail_list.txt index d80b3c9b0..f2162c8f3 100755 --- a/test/org/perses/grammar/rust/golden_fail_list.txt +++ b/test/org/perses/grammar/rust/golden_fail_list.txt @@ -9,34 +9,20 @@ test_data/rust_programs/rust_testsuite/ui/associated-type-bounds/fn-dyn-apit.rs test_data/rust_programs/rust_testsuite/ui/associated-type-bounds/fn-wrap-apit.rs test_data/rust_programs/rust_testsuite/ui/associated-type-bounds/lcsit.rs test_data/rust_programs/rust_testsuite/ui/associated-type-bounds/trait-alias-impl-trait.rs -test_data/rust_programs/rust_testsuite/ui/attrs-resolution.rs -test_data/rust_programs/rust_testsuite/ui/const-generics/condition-in-trait-const-arg.rs -test_data/rust_programs/rust_testsuite/ui/const-generics/const-param-in-trait.rs test_data/rust_programs/rust_testsuite/ui/const-generics/fn-const-param-call.rs test_data/rust_programs/rust_testsuite/ui/const-generics/fn-const-param-infer.rs test_data/rust_programs/rust_testsuite/ui/const-generics/issues/issue-61747.rs test_data/rust_programs/rust_testsuite/ui/const-generics/raw-ptr-const-param-deref.rs test_data/rust_programs/rust_testsuite/ui/const-generics/raw-ptr-const-param.rs test_data/rust_programs/rust_testsuite/ui/const-generics/slice-const-param.rs -test_data/rust_programs/rust_testsuite/ui/consts/const-endianess.rs -test_data/rust_programs/rust_testsuite/ui/consts/trait_specialization.rs -test_data/rust_programs/rust_testsuite/ui/cross-crate/issue-64872/auxiliary/a_def_obj.rs -test_data/rust_programs/rust_testsuite/ui/cross-crate/issue-64872/auxiliary/c_another_vtable_for_obj.rs test_data/rust_programs/rust_testsuite/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs -test_data/rust_programs/rust_testsuite/ui/empty-type-parameter-list.rs -test_data/rust_programs/rust_testsuite/ui/enum-discriminant/arbitrary_enum_discriminant.rs -test_data/rust_programs/rust_testsuite/ui/enum-discriminant/discriminant_value.rs test_data/rust_programs/rust_testsuite/ui/error-codes/e0119/auxiliary/complex_impl_support.rs -test_data/rust_programs/rust_testsuite/ui/for-loop-while/label_break_value.rs -test_data/rust_programs/rust_testsuite/ui/for-loop-while/loop-break-value.rs -test_data/rust_programs/rust_testsuite/ui/functions-closures/closure-returning-closure.rs test_data/rust_programs/rust_testsuite/ui/generic/generic-param-attrs.rs test_data/rust_programs/rust_testsuite/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs test_data/rust_programs/rust_testsuite/ui/half-open-range-patterns/pat-tuple-4.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-15043.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-20616.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-36116.rs -test_data/rust_programs/rust_testsuite/ui/issues/issue-38987.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-43692.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-50571.rs test_data/rust_programs/rust_testsuite/ui/issues/issue-55376.rs @@ -44,6 +30,5 @@ test_data/rust_programs/rust_testsuite/ui/json-bom-plus-crlf-multifile.rs test_data/rust_programs/rust_testsuite/ui/parser-unicode-whitespace.rs test_data/rust_programs/rust_testsuite/ui/parser/trait-plusequal-splitting.rs test_data/rust_programs/rust_testsuite/ui/parser/underscore-suffix-for-string.rs -test_data/rust_programs/rust_testsuite/ui/resolve/auxiliary/privacy-struct-ctor.rs test_data/rust_programs/rust_testsuite/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/syntax.rs test_data/rust_programs/rust_testsuite/ui/weird-exprs.rs diff --git a/test/org/perses/grammar/rust/golden_pnf_rust.g4 b/test/org/perses/grammar/rust/golden_pnf_rust.g4 index 3e49d43b3..8fda64eb6 100644 --- a/test/org/perses/grammar/rust/golden_pnf_rust.g4 +++ b/test/org/perses/grammar/rust/golden_pnf_rust.g4 @@ -71,16 +71,23 @@ visibility_restriction alternative__visibility_restriction_2 : 'super' | 'crate' - | 'in' ident + | 'in' simple_path ; -ident - : Ident - | 'auto' - | 'default' - | 'union' - | 'try' - | RawIdentifier +simple_path + : optional__simple_path_1 simple_path_segment kleene_star__simple_path_3 + ; + +optional__simple_path_1 + : '::'? + ; + +simple_path_2 + : '::' simple_path_segment + ; + +kleene_star__simple_path_3 + : simple_path_2* ; attr @@ -175,7 +182,7 @@ optional__static_decl_1 ; const_decl - : 'const' (ident | '_') ':' ty_sum '=' expr ';' + : optional__impl_block_1 'const' (ident | '_') ':' ty_sum '=' expr ';' ; associated_const_decl @@ -276,23 +283,30 @@ macro_decl ; macro_decl_2 - : '(' optional__fn_decl_1 ')' + : '(' kleene_star__inner_attr_1 ')' ; optional__macro_decl_3 : macro_decl_2? ; +ident + : Ident + | 'auto' + | 'default' + | 'union' + | 'try' + | 'crate' + | 'macro_rules' + | RawIdentifier + ; + rename : 'as' (ident | '_') ; use_path - : optional__use_path_1 alternative__use_path_7 - ; - -optional__use_path_1 - : '::'? + : optional__simple_path_1 alternative__use_path_7 ; optional__use_path_2 @@ -439,7 +453,7 @@ optional__expr_2 ; type_parameters - : '<' alternative__type_parameters_3 '>' + : '<' alternative__type_parameters_4 '>' ; type_parameters_1 @@ -450,9 +464,13 @@ kleene_star__type_parameters_2 : type_parameters_1* ; -alternative__type_parameters_3 +optional__type_parameters_3 + : type_parameter_list? + ; + +alternative__type_parameters_4 : lifetime_param_list - | kleene_star__type_parameters_2 type_parameter_list + | kleene_star__type_parameters_2 optional__type_parameters_3 ; colon_bound @@ -607,7 +625,8 @@ tt ; type_parameter - : kleene_star__item_1 optional__impl_block_5 ident optional__type_decl_4 optional__type_parameter_4 + : ty_sum + | kleene_star__item_1 optional__impl_block_5 ident optional__type_decl_4 optional__type_parameter_4 ; optional__type_parameter_4 @@ -684,19 +703,27 @@ variadic_param_list_names_optional trait_method_param : '...' - | alternative__trait_method_param_4 ty_sum + | alternative__trait_method_param_6 ty_sum + ; + +trait_method_param_2 + : restricted_pat ',' ; -alternative__trait_method_param_4 - : kleene_star__item_1 optional__trait_method_param_6 +kleene_star__trait_method_param_3 + : trait_method_param_2* ; -trait_method_param_5 - : restricted_pat ':' kleene_star__item_1 +alternative__trait_method_param_6 + : kleene_star__item_1 optional__trait_method_param_8 ; -optional__trait_method_param_6 - : trait_method_param_5? +trait_method_param_7 + : ('(' kleene_star__trait_method_param_3 restricted_pat ')' | restricted_pat) ':' kleene_star__item_1 + ; + +optional__trait_method_param_8 + : trait_method_param_7? ; self_param @@ -705,17 +732,21 @@ self_param ; restricted_pat - : optional__restricted_pat_2 ('_' | ident) + : optional__restricted_pat_1 optional__restricted_pat_3 ('_' | ident) ; -restricted_pat_1 +optional__restricted_pat_1 + : 'ref'? + ; + +restricted_pat_2 : '&' | '&&' | 'mut' ; -optional__restricted_pat_2 - : restricted_pat_1? +optional__restricted_pat_3 + : restricted_pat_2? ; struct_tail @@ -788,7 +819,15 @@ kleene_star__enum_variant_list_2 ; enum_variant - : kleene_star__item_1 optional__item_2 enum_variant_main + : kleene_star__item_1 optional__item_2 enum_variant_main optional__enum_variant_4 + ; + +enum_variant_3 + : '=' lit + ; + +optional__enum_variant_4 + : enum_variant_3? ; enum_variant_main @@ -813,6 +852,18 @@ alternative__enum_variant_main_6 | '{' optional__struct_tail_5 '}' ; +lit + : 'true' + | 'false' + | BareIntLit + | FullIntLit + | ByteLit + | ByteStringLit + | FloatLit + | CharLit + | StringLit + ; + enum_tuple_field_list : enum_tuple_field kleene_star__enum_tuple_field_list_2 optional__use_item_list_3 ; @@ -981,13 +1032,9 @@ alternative__impl_item_tail_13 ; tt_delimited - : tt_parens - | tt_brackets + : tt_brackets | tt_block - ; - -tt_parens - : '(' kleene_star__inner_attr_1 ')' + | macro_decl_2 ; tt_brackets @@ -1049,7 +1096,7 @@ path_parent_3 path_parent_4 : 'self' | '<' ty_sum optional__path_parent_1 '>' - | optional__use_path_1 path_segment + | optional__simple_path_1 path_segment ; as_trait @@ -1063,23 +1110,12 @@ path_segment simple_path_segment : ident + | 'super' | 'Self' | 'crate' | '$crate' ; -simple_path - : optional__use_path_1 simple_path_segment kleene_star__simple_path_3 - ; - -simple_path_2 - : '::' simple_path_segment - ; - -kleene_star__simple_path_3 - : simple_path_2* - ; - for_lifetimes : 'for' '<' optional__for_lifetimes_1 '>' ; @@ -1163,7 +1199,7 @@ ty_path_parent_3 ty_path_parent_4 : 'self' - | optional__use_path_1 type_path_segment + | optional__simple_path_1 type_path_segment | '<' ty_sum optional__path_parent_1 '>' ; @@ -1180,13 +1216,29 @@ kleene_star__ty_sum_list_2 ; ty_path_segment_no_super - : (ident | 'Self') optional__ty_path_segment_no_super_1 + : alternative__ty_path_segment_no_super_5 optional__ty_path_segment_no_super_3 ; -optional__ty_path_segment_no_super_1 +ty_path_segment_no_super_1 + : ident + | 'Self' + ; + +optional__ty_path_segment_no_super_2 + : ty_path_segment_no_super_1? + ; + +optional__ty_path_segment_no_super_3 : type_arguments? ; +alternative__ty_path_segment_no_super_5 + : '(' optional__ty_path_segment_no_super_2 ')' + | ident + | 'Self' + | '&raw' + ; + type_path_segment : ty_path_segment_no_super | 'super' @@ -1206,13 +1258,17 @@ kleene_star__where_bound_list_2 where_bound : lifetime ':' lifetime_bound - | optional__where_bound_1 type empty_ok_colon_bound + | optional__where_bound_1 type optional__where_bound_2 ; optional__where_bound_1 : for_lifetimes? ; +optional__where_bound_2 + : empty_ok_colon_bound? + ; + empty_ok_colon_bound : ':' optional__empty_ok_colon_bound_1 ; @@ -1352,6 +1408,8 @@ type_param_bound type_argument : BareIntLit + | 'true' + | 'false' | optional__type_argument_2 ty_sum ; @@ -1399,10 +1457,6 @@ kleene_star__pattern_without_mut_5 : pattern_without_mut_4* ; -optional__pattern_without_mut_8 - : 'ref'? - ; - optional__pattern_without_mut_12 : pat_list_with_dots? ; @@ -1488,7 +1542,7 @@ alternative__pattern_without_mut_33 alternative__pattern_without_mut_34 : kleene_star__pattern_without_mut_5 pat_ident - | optional__pattern_without_mut_8 optional__static_decl_1 ident + | optional__restricted_pat_1 optional__static_decl_1 ident ; pat_ident @@ -1565,18 +1619,6 @@ alternative__pat_fields_6 | pat_fields_left ':' pat_fields_left ; -lit - : 'true' - | 'false' - | BareIntLit - | FullIntLit - | ByteLit - | ByteStringLit - | FloatLit - | CharLit - | StringLit - ; - pat_list_dots_tail : '..' optional__pat_list_dots_tail_2 ; @@ -1596,14 +1638,18 @@ pat_fields_left ; pat_field - : ident ':' pattern - | optional__pat_field_1 optional__pattern_without_mut_8 optional__static_decl_1 ident + : kleene_star__item_1 alternative__pat_field_6 ; -optional__pat_field_1 +optional__pat_field_2 : 'box'? ; +alternative__pat_field_6 + : ident ':' pattern + | optional__pat_field_2 optional__restricted_pat_1 optional__static_decl_1 ident + ; + assign_expr : range_expr optional__assign_expr_2 ; @@ -1801,11 +1847,10 @@ prim_expr_no_struct | 'async' 'move' (blocky_expr | closure_params closure_tail) | path optional__prim_expr_no_struct_1 | optional__prim_expr_no_struct_9 optional__prim_expr_no_struct_10 closure_params closure_tail - | 'break' optional__prim_expr_no_struct_11 - | '(' alternative__prim_expr_no_struct_16 ')' - | '[' alternative__prim_expr_no_struct_17 ']' + | '(' alternative__prim_expr_no_struct_19 ')' + | '[' alternative__prim_expr_no_struct_20 ']' | 'continue' optional__type_1 - | alternative__prim_expr_no_struct_19 optional__block_with_inner_attrs_3 + | alternative__prim_expr_no_struct_23 optional__block_with_inner_attrs_3 ; optional__prim_expr_no_struct_1 @@ -1828,25 +1873,34 @@ optional__prim_expr_no_struct_11 : lifetime_or_expr? ; -alternative__prim_expr_no_struct_16 - : optional__prim_expr_1 alternative__prim_expr_no_struct_20 +optional__prim_expr_no_struct_12 + : lit? ; -alternative__prim_expr_no_struct_17 - : optional__prim_expr_1 alternative__prim_expr_no_struct_21 +optional__prim_expr_no_struct_13 + : item? ; alternative__prim_expr_no_struct_19 - : 'return' - | 'yield' + : optional__prim_expr_1 alternative__prim_expr_no_struct_24 ; alternative__prim_expr_no_struct_20 + : optional__prim_expr_1 alternative__prim_expr_no_struct_25 + ; + +alternative__prim_expr_no_struct_23 + : 'yield' + | 'break' optional__prim_expr_no_struct_11 optional__prim_expr_no_struct_12 optional__prim_expr_no_struct_13 + | 'return' + ; + +alternative__prim_expr_no_struct_24 : expr ',' optional__prim_expr_no_struct_5 | optional__block_with_inner_attrs_3 ; -alternative__prim_expr_no_struct_21 +alternative__prim_expr_no_struct_25 : expr ';' expr | optional__prim_expr_no_struct_5 ; @@ -1866,6 +1920,7 @@ kleene_star__fields_2 closure_params : '||' + | '|_|' | '|' optional__closure_params_2 '|' ; @@ -1951,6 +2006,7 @@ alternative__post_expr_tail_7 pre_expr : post_expr + | '&raw' | 'in' expr_no_struct block | alternative__pre_expr_8 pre_expr ; @@ -3337,7 +3393,7 @@ BareIntLit fragment INT_SUFFIX - : [ui] ('8' | '16' | '32' | '64' | 'size') + : [ui] ('8' | '16' | '32' | '64' | '128' | 'size') ; FullIntLit @@ -3349,7 +3405,7 @@ FullIntLit fragment EXPONENT - : [Ee] [+-]? '_'* [0-9] [0-9_]* + : [Ee] [+-]? 'd_'* [0-9] [0-9_]* ; fragment diff --git a/test/org/perses/reduction/BUILD b/test/org/perses/reduction/BUILD index 45dda5ecc..1391a312c 100644 --- a/test/org/perses/reduction/BUILD +++ b/test/org/perses/reduction/BUILD @@ -93,19 +93,20 @@ java_test( ], ) -java_test( +kt_jvm_test( name = "ReductionDriverTest", - srcs = ["ReductionDriverTest.java"], + srcs = ["ReductionDriverTest.kt"], data = [ "//test_data/delta_1", ], - test_class = "org.perses.reduction.ReductionDriverTest", deps = [ "//src/org/perses:command_options", "//src/org/perses/grammar:facade_factory", "//src/org/perses/grammar:grammar_facade", "//src/org/perses/program", + "//src/org/perses/program:enum_format_control", "//src/org/perses/program:language_kind", + "//src/org/perses/reduction:enum_query_caching_control", "//src/org/perses/reduction:reducer_factory", "//src/org/perses/reduction:reduction_configuration", "//src/org/perses/reduction:reduction_driver", diff --git a/test/org/perses/reduction/ReductionDriverTest.java b/test/org/perses/reduction/ReductionDriverTest.java deleted file mode 100644 index 181f3d7e3..000000000 --- a/test/org/perses/reduction/ReductionDriverTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2018-2020 University of Waterloo. - * - * This file is part of Perses. - * - * Perses is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation; either version 3, or (at your option) any later version. - * - * Perses is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with - * Perses; see the file LICENSE. If not see . - */ -package org.perses.reduction; - -import com.google.common.truth.Truth; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.perses.CommandOptions; -import org.perses.grammar.ParserFacadeFactory; - -@RunWith(JUnit4.class) -public class ReductionDriverTest { - - @Test - public void testCreateConfiguration() { - CommandOptions cmd = new CommandOptions(ReducerFactory.getDefaultReductionAlgName()); - cmd.compulsoryFlags.inputFile = "t.c"; - cmd.compulsoryFlags.testScript = "r.sh"; - try { - ReductionDriver.createConfiguration(cmd, ParserFacadeFactory.builderWithBuiltinLanguages().build()); - } catch (RuntimeException e) { - // Keep this. This is just capture a bug when only "t.c" and "r.sh" were given without parent - // folders. - Truth.assertThat(e.getMessage()).contains("The file should be a regular file"); - } - } -} diff --git a/test/org/perses/reduction/ReductionDriverTest.kt b/test/org/perses/reduction/ReductionDriverTest.kt new file mode 100644 index 000000000..8acc02e7f --- /dev/null +++ b/test/org/perses/reduction/ReductionDriverTest.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2018-2020 University of Waterloo. + * + * This file is part of Perses. + * + * Perses is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3, or (at your option) any later version. + * + * Perses is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * Perses; see the file LICENSE. If not see . + */ +package org.perses.reduction + +import com.google.common.io.Files +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.perses.CommandOptions +import org.perses.grammar.ParserFacadeFactory.Companion.builderWithBuiltinLanguages +import org.perses.program.EnumFormatControl +import org.perses.reduction.ReducerFactory.defaultReductionAlgName +import org.perses.reduction.ReductionDriver.Companion.booleanToEnabledOrDisabled +import org.perses.reduction.ReductionDriver.Companion.createConfiguration +import java.io.File + +@RunWith(JUnit4::class) +class ReductionDriverTest { + + private val workDir = Files.createTempDir() + + @After + fun teardown() { + workDir.deleteRecursively() + } + + @Test + fun testBooleanToEnabledOrDisabled() { + assertThat(booleanToEnabledOrDisabled(true)).isEqualTo("enabled") + assertThat(booleanToEnabledOrDisabled(false)).isEqualTo("disabled") + } + + @Test + fun test() { + val sourceFile = File(workDir, "t.c").apply { check(createNewFile()) } + val scriptFile = File(workDir, "r.sh").apply { + check(createNewFile()) + check(setExecutable(true)) + writeText("#!/usr/bin/env bash") + } + + for (format in EnumFormatControl.values()) { + val cmd = CommandOptions(defaultReductionAlgName).apply { + compulsoryFlags.inputFile = sourceFile.absolutePath + compulsoryFlags.testScript = scriptFile.absolutePath + reductionControlFlags.codeFormat = format + cacheControlFlags.nodeActionSetCaching = true + cacheControlFlags.queryCaching = EnumQueryCachingControl.TRUE + } + val config = createConfiguration(cmd, builderWithBuiltinLanguages().build()) + assertThat(config.enableTestScriptExecutionCaching).isTrue() + } + + for (format in EnumFormatControl.values()) { + val cmd = CommandOptions(defaultReductionAlgName).apply { + compulsoryFlags.inputFile = sourceFile.absolutePath + compulsoryFlags.testScript = scriptFile.absolutePath + reductionControlFlags.codeFormat = format + cacheControlFlags.nodeActionSetCaching = true + cacheControlFlags.queryCaching = EnumQueryCachingControl.FALSE + } + val config = createConfiguration(cmd, builderWithBuiltinLanguages().build()) + assertThat(config.enableTestScriptExecutionCaching).isFalse() + } + + CommandOptions(defaultReductionAlgName).apply { + compulsoryFlags.inputFile = sourceFile.absolutePath + compulsoryFlags.testScript = scriptFile.absolutePath + reductionControlFlags.codeFormat = EnumFormatControl.SINGLE_TOKEN_PER_LINE + cacheControlFlags.nodeActionSetCaching = true + cacheControlFlags.queryCaching = EnumQueryCachingControl.AUTO + }.let { + val config = createConfiguration(it, builderWithBuiltinLanguages().build()) + assertThat(config.enableTestScriptExecutionCaching).isTrue() + } + + CommandOptions(defaultReductionAlgName).apply { + compulsoryFlags.inputFile = sourceFile.absolutePath + compulsoryFlags.testScript = scriptFile.absolutePath + reductionControlFlags.codeFormat = EnumFormatControl.COMPACT_ORIG_FORMAT + cacheControlFlags.nodeActionSetCaching = true + cacheControlFlags.queryCaching = EnumQueryCachingControl.AUTO + }.let { + val config = createConfiguration(it, builderWithBuiltinLanguages().build()) + assertThat(config.enableTestScriptExecutionCaching).isFalse() + } + } + + @Test + fun testCreateConfigurationForNonExistingFiles() { + val cmd = CommandOptions(defaultReductionAlgName) + cmd.compulsoryFlags.inputFile = "t.c" + cmd.compulsoryFlags.testScript = "r.sh" + try { + createConfiguration( + cmd, builderWithBuiltinLanguages().build() + ) + } catch (e: RuntimeException) { + // Keep this. This is just capture a bug when only "t.c" and "r.sh" were given without parent + // folders. + assertThat(e.message).contains("The file should be a regular file") + } + } +} diff --git a/test/org/perses/reduction/reducer/golden_reduction_log_of_delta_1_with_cache.txt b/test/org/perses/reduction/reducer/golden_reduction_log_of_delta_1_with_cache.txt index 8293fae37..4469432c9 100644 --- a/test/org/perses/reduction/reducer/golden_reduction_log_of_delta_1_with_cache.txt +++ b/test/org/perses/reduction/reducer/golden_reduction_log_of_delta_1_with_cache.txt @@ -843,7 +843,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -2 entries are removed: 13 --> 11. +7 entries are removed: 13 --> 6. ------------------------------------------------------------ @@ -892,7 +892,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -4 entries are removed: 13 --> 9. +2 entries are removed: 8 --> 6. ------------------------------------------------------------ @@ -914,7 +914,7 @@ The current best program is the following ===========TestScriptExecutionCacheEntryEviction============ -6 entries are removed: 10 --> 4. +5 entries are removed: 7 --> 2. ------------------------------------------------------------ @@ -1019,7 +1019,7 @@ It took less than 1 second to cancel the task. ===========TestScriptExecutionCacheEntryEviction============ -3 entries are removed: 6 --> 3. +3 entries are removed: 4 --> 1. ------------------------------------------------------------ @@ -1129,7 +1129,7 @@ It took less than 1 second to cancel the task. ===========TestScriptExecutionCacheEntryEviction============ -3 entries are removed: 5 --> 2. +3 entries are removed: 3 --> 0. ------------------------------------------------------------ diff --git a/test/org/perses/util/ShellOutputLinesTest.kt b/test/org/perses/util/ShellOutputLinesTest.kt index 99ae9e3fc..ca9e615ae 100644 --- a/test/org/perses/util/ShellOutputLinesTest.kt +++ b/test/org/perses/util/ShellOutputLinesTest.kt @@ -56,6 +56,6 @@ class ShellOutputLinesTest { val file = File.createTempFile("test_shell_output_lines_test", ".txt") list.writeToFile(file) val readText = file.readText(StandardCharsets.UTF_8) - Truth.assertThat(readText.trim()).isEqualTo(list.combineLines().trim()) + Truth.assertThat(readText.trim()).isEqualTo(list.combinedLines.trim()) } } diff --git a/test/org/perses/util/ShellTest.kt b/test/org/perses/util/ShellTest.kt index 6620e0c42..708298093 100644 --- a/test/org/perses/util/ShellTest.kt +++ b/test/org/perses/util/ShellTest.kt @@ -90,6 +90,6 @@ class ShellTest { captureOutput = true, environment = Shell.createNewEnvironmentVar("TEST_ENV_VALUE", "hello world") ) - assertThat(cmdOutput.stdout.combineLines().trim()).isEqualTo("hello world") + assertThat(cmdOutput.stdout.combinedLines.trim()).isEqualTo("hello world") } } diff --git a/test_data/rust_programs/BUILD b/test_data/rust_programs/BUILD index 6e23fe9c4..cb36f8644 100644 --- a/test_data/rust_programs/BUILD +++ b/test_data/rust_programs/BUILD @@ -3,6 +3,16 @@ # Run './generate_BUILD.sh' to update this BUILD file. package(default_visibility = ["//test/org/perses:__subpackages__"]) +filegroup( + name = "whole_rust_repo", + srcs = glob( + ["rust/**/*.rs"], + exclude = [ + "rust/src/test/**", + ], + ), +) + filegroup( name = "rust_testsuite", srcs = glob( diff --git a/test_data/rust_programs/generate_BUILD.sh b/test_data/rust_programs/generate_BUILD.sh index b03d77229..4158bbd3a 100755 --- a/test_data/rust_programs/generate_BUILD.sh +++ b/test_data/rust_programs/generate_BUILD.sh @@ -56,6 +56,16 @@ cat > "${BUILD_FILE}" <<-EOF # Run '$0' to update this BUILD file. package(default_visibility = ["//test/org/perses:__subpackages__"]) +filegroup( + name = "whole_rust_repo", + srcs = glob( + ["rust/**/*.rs"], + exclude = [ + "rust/src/test/**", + ], + ), +) + filegroup( name = "rust_testsuite", srcs = glob( diff --git a/version/org/perses/version/VersionClassGenerator.kt b/version/org/perses/version/VersionClassGenerator.kt index 9fc3adc71..1206c34ce 100644 --- a/version/org/perses/version/VersionClassGenerator.kt +++ b/version/org/perses/version/VersionClassGenerator.kt @@ -26,7 +26,7 @@ import java.time.format.DateTimeFormatter object VersionClassGenerator { private const val MAJOR_VERSION = "1" - private const val MINOR_VERSION = "1" + private const val MINOR_VERSION = "4" @JvmStatic fun generate(args: Array) {