Rollup merge of #131351 - jieyouxu:yeet-the-valgrind, r=Kobzol
Remove valgrind test suite and support from compiletest, bootstrap and opt-dist
The `run-pass-valgrind` test suite is not exercised in CI, and as far as I'm aware nobody runs it (asked in https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Are.20the.20valgrind.20tests.20even.20used.20by.20anyone.3F). What's remaining of valgrind support in compiletest isn't even properly hooked up with bootstrap.
The existing valgrind logic in compiletest is also straight up questionable, i.e.
1b3b8e7b02/src/tools/compiletest/src/runtest/valgrind.rs (L7-L12)
It just runs valgrind tests as `rpass` if no valgrind path is provided to compiletest from bootstrap -- but bootstrap doesn't even pass a valgrind path to compiletest in the first place, so this always ran as `rpass` tests. So what is this even testing?
So if it's not testing anything, let's delete it.
Closes #44816 by deleting the test suite :3
<img src="https://github.com/user-attachments/assets/99525bf7-e85b-40ba-9281-e4e1e275c4e8" width=300 />
This commit is contained in:
commit
f88bfa34e1
@ -1394,12 +1394,6 @@ fn run(self, builder: &Builder<'_>) {
|
||||
|
||||
default_test!(Crashes { path: "tests/crashes", mode: "crashes", suite: "crashes" });
|
||||
|
||||
default_test!(RunPassValgrind {
|
||||
path: "tests/run-pass-valgrind",
|
||||
mode: "run-pass-valgrind",
|
||||
suite: "run-pass-valgrind"
|
||||
});
|
||||
|
||||
default_test!(Codegen { path: "tests/codegen", mode: "codegen", suite: "codegen" });
|
||||
|
||||
default_test!(CodegenUnits {
|
||||
|
@ -327,7 +327,6 @@ pub fn assert_single_path(&self) -> &TaskPath {
|
||||
"tests/mir-opt",
|
||||
"tests/pretty",
|
||||
"tests/run-make",
|
||||
"tests/run-pass-valgrind",
|
||||
"tests/rustdoc",
|
||||
"tests/rustdoc-gui",
|
||||
"tests/rustdoc-js",
|
||||
@ -852,7 +851,6 @@ macro_rules! describe {
|
||||
test::Tidy,
|
||||
test::Ui,
|
||||
test::Crashes,
|
||||
test::RunPassValgrind,
|
||||
test::Coverage,
|
||||
test::CoverageMap,
|
||||
test::CoverageRun,
|
||||
|
@ -53,7 +53,6 @@ fn from_str(s: &str) -> Result<Self, ()> {
|
||||
string_enum! {
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum Mode {
|
||||
RunPassValgrind => "run-pass-valgrind",
|
||||
Pretty => "pretty",
|
||||
DebugInfo => "debuginfo",
|
||||
Codegen => "codegen",
|
||||
@ -207,13 +206,6 @@ pub struct Config {
|
||||
/// Path to LLVM's bin directory.
|
||||
pub llvm_bin_dir: Option<PathBuf>,
|
||||
|
||||
/// The valgrind path.
|
||||
pub valgrind_path: Option<String>,
|
||||
|
||||
/// Whether to fail if we can't run run-pass-valgrind tests under valgrind
|
||||
/// (or, alternatively, to silently run them like regular run-pass tests).
|
||||
pub force_valgrind: bool,
|
||||
|
||||
/// The path to the Clang executable to run Clang-based tests with. If
|
||||
/// `None` then these tests will be ignored.
|
||||
pub run_clang_based_tests_with: Option<String>,
|
||||
|
@ -53,8 +53,6 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
.reqopt("", "python", "path to python to use for doc tests", "PATH")
|
||||
.optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH")
|
||||
.optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH")
|
||||
.optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM")
|
||||
.optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind")
|
||||
.optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH")
|
||||
.optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR")
|
||||
.reqopt("", "src-base", "directory to scan for test files", "PATH")
|
||||
@ -65,7 +63,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
||||
"",
|
||||
"mode",
|
||||
"which sort of compile tests to run",
|
||||
"run-pass-valgrind | pretty | debug-info | codegen | rustdoc \
|
||||
"pretty | debug-info | codegen | rustdoc \
|
||||
| rustdoc-json | codegen-units | incremental | run-make | ui \
|
||||
| js-doc-test | mir-opt | assembly | crashes",
|
||||
)
|
||||
@ -269,8 +267,6 @@ fn make_absolute(path: PathBuf) -> PathBuf {
|
||||
python: matches.opt_str("python").unwrap(),
|
||||
jsondocck_path: matches.opt_str("jsondocck-path"),
|
||||
jsondoclint_path: matches.opt_str("jsondoclint-path"),
|
||||
valgrind_path: matches.opt_str("valgrind-path"),
|
||||
force_valgrind: matches.opt_present("force-valgrind"),
|
||||
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
|
||||
llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
|
||||
llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
|
||||
|
@ -18,10 +18,6 @@ fn main() {
|
||||
|
||||
let config = Arc::new(parse_config(env::args().collect()));
|
||||
|
||||
if config.valgrind_path.is_none() && config.force_valgrind {
|
||||
panic!("Can't find Valgrind to run Valgrind tests");
|
||||
}
|
||||
|
||||
if !config.has_tidy && config.mode == Mode::Rustdoc {
|
||||
eprintln!("warning: `tidy` is not installed; diffs will not be generated");
|
||||
}
|
||||
|
@ -20,9 +20,9 @@
|
||||
use crate::common::{
|
||||
Assembly, Codegen, CodegenUnits, CompareMode, Config, CoverageMap, CoverageRun, Crashes,
|
||||
DebugInfo, Debugger, FailMode, Incremental, JsDocTest, MirOpt, PassMode, Pretty, RunMake,
|
||||
RunPassValgrind, Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR,
|
||||
UI_RUN_STDOUT, UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path,
|
||||
incremental_dir, output_base_dir, output_base_name, output_testname_unique,
|
||||
Rustdoc, RustdocJson, TestPaths, UI_EXTENSIONS, UI_FIXED, UI_RUN_STDERR, UI_RUN_STDOUT,
|
||||
UI_STDERR, UI_STDOUT, UI_SVG, UI_WINDOWS_SVG, Ui, expected_output_path, incremental_dir,
|
||||
output_base_dir, output_base_name, output_testname_unique,
|
||||
};
|
||||
use crate::compute_diff::{write_diff, write_filtered_diff};
|
||||
use crate::errors::{self, Error, ErrorKind};
|
||||
@ -49,7 +49,6 @@
|
||||
mod rustdoc;
|
||||
mod rustdoc_json;
|
||||
mod ui;
|
||||
mod valgrind;
|
||||
// tidy-alphabet-end
|
||||
|
||||
#[cfg(test)]
|
||||
@ -253,7 +252,6 @@ fn run_revision(&self) {
|
||||
self.fatal("cannot use should-ice in a test that is not cfail");
|
||||
}
|
||||
match self.config.mode {
|
||||
RunPassValgrind => self.run_valgrind_test(),
|
||||
Pretty => self.run_pretty_test(),
|
||||
DebugInfo => self.run_debuginfo_test(),
|
||||
Codegen => self.run_codegen_test(),
|
||||
@ -1500,8 +1498,7 @@ fn make_compile_args(
|
||||
Crashes => {
|
||||
set_mir_dump_dir(&mut rustc);
|
||||
}
|
||||
RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
|
||||
| CodegenUnits | JsDocTest => {
|
||||
Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake | CodegenUnits | JsDocTest => {
|
||||
// do not use JSON output
|
||||
}
|
||||
}
|
||||
@ -2655,33 +2652,6 @@ fn init_incremental_test(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jieyouxu): `run_rpass_test` is hoisted out here and not in incremental because
|
||||
// apparently valgrind test falls back to `run_rpass_test` if valgrind isn't available, which
|
||||
// seems highly questionable to me.
|
||||
fn run_rpass_test(&self) {
|
||||
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, emit_metadata);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
// FIXME(#41968): Move this check to tidy?
|
||||
if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
|
||||
self.fatal("run-pass tests with expected warnings should be moved to ui/");
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
|
||||
fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> {
|
||||
for e in path.read_dir()? {
|
||||
let entry = e?;
|
||||
|
@ -1,10 +1,6 @@
|
||||
use super::{TestCx, WillExecute};
|
||||
use crate::errors;
|
||||
|
||||
// FIXME(jieyouxu): `run_rpass_test` got hoisted out of this because apparently valgrind falls back
|
||||
// to `run_rpass_test` if valgrind isn't available, which is questionable, but keeping it for
|
||||
// refactoring changes to preserve current behavior.
|
||||
|
||||
impl TestCx<'_> {
|
||||
pub(super) fn run_incremental_test(&self) {
|
||||
// Basic plan for a test incremental/foo/bar.rs:
|
||||
@ -73,6 +69,30 @@ fn run_cpass_test(&self) {
|
||||
}
|
||||
}
|
||||
|
||||
fn run_rpass_test(&self) {
|
||||
let emit_metadata = self.should_emit_metadata(self.pass_mode());
|
||||
let should_run = self.run_if_enabled();
|
||||
let proc_res = self.compile_test(should_run, emit_metadata);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
// FIXME(#41968): Move this check to tidy?
|
||||
if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() {
|
||||
self.fatal("run-pass tests with expected warnings should be moved to ui/");
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_cfail_test(&self) {
|
||||
let pm = self.pass_mode();
|
||||
let proc_res = self.compile_test(WillExecute::No, self.should_emit_metadata(pm));
|
||||
@ -115,12 +135,6 @@ fn run_rfail_test(&self) {
|
||||
|
||||
let proc_res = self.exec_compiled_test();
|
||||
|
||||
// The value our Makefile configures valgrind to return on failure
|
||||
const VALGRIND_ERR: i32 = 100;
|
||||
if proc_res.status.code() == Some(VALGRIND_ERR) {
|
||||
self.fatal_proc_rec("run-fail test isn't valgrind-clean!", &proc_res);
|
||||
}
|
||||
|
||||
let output_to_check = self.get_output(&proc_res);
|
||||
self.check_correct_failure_status(&proc_res);
|
||||
self.check_all_error_patterns(&output_to_check, &proc_res, pm);
|
||||
|
@ -1,34 +0,0 @@
|
||||
use super::{Emit, TestCx, WillExecute};
|
||||
|
||||
impl TestCx<'_> {
|
||||
pub(super) fn run_valgrind_test(&self) {
|
||||
assert!(self.revision.is_none(), "revisions not relevant here");
|
||||
|
||||
// FIXME(jieyouxu): does this really make any sense? If a valgrind test isn't testing
|
||||
// valgrind, what is it even testing?
|
||||
if self.config.valgrind_path.is_none() {
|
||||
assert!(!self.config.force_valgrind);
|
||||
return self.run_rpass_test();
|
||||
}
|
||||
|
||||
let should_run = self.run_if_enabled();
|
||||
let mut proc_res = self.compile_test(should_run, Emit::None);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("compilation failed!", &proc_res);
|
||||
}
|
||||
|
||||
if let WillExecute::Disabled = should_run {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut new_config = self.config.clone();
|
||||
new_config.runner = new_config.valgrind_path.clone();
|
||||
let new_cx = TestCx { config: &new_config, ..*self };
|
||||
proc_res = new_cx.exec_compiled_test();
|
||||
|
||||
if !proc_res.status.success() {
|
||||
self.fatal_proc_rec("test run failed!", &proc_res);
|
||||
}
|
||||
}
|
||||
}
|
@ -96,7 +96,6 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
|
||||
"tests/incremental",
|
||||
"tests/mir-opt",
|
||||
"tests/pretty",
|
||||
"tests/run-pass-valgrind",
|
||||
"tests/ui",
|
||||
"tests/crashes",
|
||||
];
|
||||
|
@ -1,34 +0,0 @@
|
||||
#![allow(dead_code, cenum_impl_drop_cast)]
|
||||
|
||||
// check dtor calling order when casting enums.
|
||||
|
||||
use std::mem;
|
||||
use std::sync::atomic;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
enum E {
|
||||
A = 0,
|
||||
B = 1,
|
||||
C = 2,
|
||||
}
|
||||
|
||||
static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
|
||||
|
||||
impl Drop for E {
|
||||
fn drop(&mut self) {
|
||||
// avoid dtor loop
|
||||
unsafe { mem::forget(mem::replace(self, E::B)) };
|
||||
|
||||
FLAG.store(FLAG.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 0);
|
||||
{
|
||||
let e = E::C;
|
||||
assert_eq!(e as u32, 2);
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
|
||||
}
|
||||
assert_eq!(FLAG.load(Ordering::SeqCst), 1);
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// This would previously leak the Box<Trait> because we wouldn't
|
||||
// schedule cleanups when auto borrowing trait objects.
|
||||
// This program should be valgrind clean.
|
||||
|
||||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: &Trait = &*(Box::new(Foo) as Box<Trait>);
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
fn main() {
|
||||
let _ = std::io::stdin();
|
||||
let _ = std::io::stdout();
|
||||
let _ = std::io::stderr();
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
// Check that coercions are propagated through match and if expressions.
|
||||
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
use std::boxed::Box;
|
||||
|
||||
pub fn main() {
|
||||
let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) };
|
||||
|
||||
let _: Box<[isize]> = match true {
|
||||
true => Box::new([1, 2, 3]),
|
||||
false => Box::new([1]),
|
||||
};
|
||||
|
||||
// Check we don't get over-keen at propagating coercions in the case of casts.
|
||||
let x = if true { 42 } else { 42u8 } as u16;
|
||||
let x = match true {
|
||||
true => 42,
|
||||
false => 42u8,
|
||||
} as u16;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
// Check that coercions are propagated through match and if expressions.
|
||||
|
||||
//@ pretty-expanded FIXME #23616
|
||||
|
||||
pub fn main() {
|
||||
let _: Box<[isize]> = if true {
|
||||
let b: Box<_> = Box::new([1, 2, 3]);
|
||||
b
|
||||
} else {
|
||||
let b: Box<_> = Box::new([1]);
|
||||
b
|
||||
};
|
||||
|
||||
let _: Box<[isize]> = match true {
|
||||
true => {
|
||||
let b: Box<_> = Box::new([1, 2, 3]);
|
||||
b
|
||||
}
|
||||
false => {
|
||||
let b: Box<_> = Box::new([1]);
|
||||
b
|
||||
}
|
||||
};
|
||||
|
||||
// Check we don't get over-keen at propagating coercions in the case of casts.
|
||||
let x = if true { 42 } else { 42u8 } as u16;
|
||||
let x = match true {
|
||||
true => 42,
|
||||
false => 42u8,
|
||||
} as u16;
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
//@ ignore-emscripten
|
||||
|
||||
thread_local!(static FOO: Foo = Foo);
|
||||
thread_local!(static BAR: Bar = Bar(1));
|
||||
thread_local!(static BAZ: Baz = Baz);
|
||||
|
||||
static mut HIT: bool = false;
|
||||
|
||||
struct Foo;
|
||||
struct Bar(i32);
|
||||
struct Baz;
|
||||
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
BAR.with(|_| {});
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Bar {
|
||||
fn drop(&mut self) {
|
||||
assert_eq!(self.0, 1);
|
||||
self.0 = 2;
|
||||
BAZ.with(|_| {});
|
||||
assert_eq!(self.0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Baz {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HIT = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
std::thread::spawn(|| {
|
||||
FOO.with(|_| {});
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
assert!(unsafe { HIT });
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
struct Fat<T: ?Sized> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<Fat<Trait>> = Box::<Fat<Foo>>::new(Fat { f: Foo });
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
static mut DROP_RAN: isize = 0;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Fat<T: ?Sized> {
|
||||
f: T,
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<Fat<[Foo]>> = Box::<Fat<[Foo; 3]>>::new(Fat { f: [Foo, Foo, Foo] });
|
||||
}
|
||||
unsafe {
|
||||
assert_eq!(DROP_RAN, 3);
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
|
||||
static mut DROP_RAN: bool = false;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait Trait {
|
||||
fn dummy(&self) {}
|
||||
}
|
||||
impl Trait for Foo {}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo));
|
||||
}
|
||||
unsafe {
|
||||
assert!(DROP_RAN);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
#![feature(unsized_tuple_coercion)]
|
||||
|
||||
static mut DROP_RAN: isize = 0;
|
||||
|
||||
struct Foo;
|
||||
impl Drop for Foo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
DROP_RAN += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
{
|
||||
let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo]));
|
||||
}
|
||||
unsafe {
|
||||
assert_eq!(DROP_RAN, 3);
|
||||
}
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
//@ ignore-wasm32 no subprocess support
|
||||
//@ ignore-sgx no processes
|
||||
//@ ignore-apple this needs valgrind 3.11 or higher; see
|
||||
// https://github.com/rust-lang/rust/pull/30365#issuecomment-165763679
|
||||
|
||||
use std::env;
|
||||
use std::process::{Command, exit};
|
||||
|
||||
fn main() {
|
||||
if env::args().len() > 1 {
|
||||
print!("hello!");
|
||||
exit(0);
|
||||
} else {
|
||||
let out = Command::new(env::args().next().unwrap()).arg("foo").output().unwrap();
|
||||
assert!(out.status.success());
|
||||
assert_eq!(String::from_utf8(out.stdout).unwrap(), "hello!");
|
||||
assert_eq!(String::from_utf8(out.stderr).unwrap(), "");
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
use std::alloc::System;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: System = System;
|
||||
|
||||
fn main() {
|
||||
let mut deque = VecDeque::with_capacity(32);
|
||||
deque.push_front(0);
|
||||
deque.reserve(31);
|
||||
deque.push_back(0);
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(tuple_trait)]
|
||||
|
||||
pub trait FnOnce<Args: std::marker::Tuple> {
|
||||
type Output;
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl FnOnce<()> for A {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl FnOnce<()> for B {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl FnOnce<()> for C {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl FnOnce<()> for D {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("hello"));
|
||||
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("42"));
|
||||
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("jumping fox"));
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn FnOnce<(), Output = String>>);
|
||||
assert_eq!(x.call_once(()), format!("lazy dog"));
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
#![feature(unsized_locals)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(tuple_trait)]
|
||||
|
||||
pub trait FnOnce<Args: std::marker::Tuple> {
|
||||
type Output;
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for A {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for B {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for C {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl FnOnce<(String, Box<str>)> for D {
|
||||
type Output = String;
|
||||
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
|
||||
assert_eq!(&s1 as &str, "s1");
|
||||
assert_eq!(&s2 as &str, "s2");
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("hello"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("42"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(C(format!("jumping fox")))
|
||||
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("jumping fox"));
|
||||
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog"))))
|
||||
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
|
||||
assert_eq!(x.call_once((s1, s2)), format!("lazy dog"));
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
#![feature(unsized_locals)]
|
||||
|
||||
pub trait Foo {
|
||||
fn foo(self) -> String;
|
||||
}
|
||||
|
||||
struct A;
|
||||
|
||||
impl Foo for A {
|
||||
fn foo(self) -> String {
|
||||
format!("hello")
|
||||
}
|
||||
}
|
||||
|
||||
struct B(i32);
|
||||
|
||||
impl Foo for B {
|
||||
fn foo(self) -> String {
|
||||
format!("{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct C(String);
|
||||
|
||||
impl Foo for C {
|
||||
fn foo(self) -> String {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct D(Box<String>);
|
||||
|
||||
impl Foo for D {
|
||||
fn foo(self) -> String {
|
||||
*self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = *(Box::new(A) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("hello"));
|
||||
let x = *(Box::new(B(42)) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("42"));
|
||||
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("jumping fox"));
|
||||
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn Foo>);
|
||||
assert_eq!(x.foo(), format!("lazy dog"));
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unsized_locals, unsized_fn_params)]
|
||||
|
||||
use std::fmt;
|
||||
|
||||
fn gen_foo() -> Box<fmt::Display> {
|
||||
Box::new(Box::new("foo"))
|
||||
}
|
||||
|
||||
fn foo(x: fmt::Display) {
|
||||
assert_eq!(x.to_string(), "foo");
|
||||
}
|
||||
|
||||
fn foo_indirect(x: fmt::Display) {
|
||||
foo(x);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo(*gen_foo());
|
||||
foo_indirect(*gen_foo());
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
foo(x);
|
||||
}
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
let y: fmt::Display = *gen_foo();
|
||||
foo(x);
|
||||
foo(y);
|
||||
}
|
||||
|
||||
{
|
||||
let mut cnt: usize = 3;
|
||||
let x = loop {
|
||||
let x: fmt::Display = *gen_foo();
|
||||
if cnt == 0 {
|
||||
break x;
|
||||
} else {
|
||||
cnt -= 1;
|
||||
}
|
||||
};
|
||||
foo(x);
|
||||
}
|
||||
|
||||
{
|
||||
let x: fmt::Display = *gen_foo();
|
||||
let x = if true { x } else { *gen_foo() };
|
||||
foo(x);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user