mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 03:23:25 +00:00
Auto merge of #102586 - Dylan-DPC:rollup-g107h6z, r=Dylan-DPC
Rollup of 5 pull requests Successful merges: - #100451 (Do not panic when a test function returns Result::Err.) - #102098 (Use fetch_update in sync::Weak::upgrade) - #102538 (Give `def_span` the same SyntaxContext as `span_with_body`.) - #102556 (Make `feature(const_btree_len)` implied by `feature(const_btree_new)`) - #102566 (Add a known-bug test for #102498) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
39323a5877
@ -941,9 +941,19 @@ impl<'hir> Map<'hir> {
|
||||
|
||||
let span = match self.find(hir_id)? {
|
||||
// Function-like.
|
||||
Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. })
|
||||
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. })
|
||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span,
|
||||
Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. })
|
||||
| Node::TraitItem(TraitItem {
|
||||
kind: TraitItemKind::Fn(sig, ..),
|
||||
span: outer_span,
|
||||
..
|
||||
})
|
||||
| Node::ImplItem(ImplItem {
|
||||
kind: ImplItemKind::Fn(sig, ..), span: outer_span, ..
|
||||
}) => {
|
||||
// Ensure that the returned span has the item's SyntaxContext, and not the
|
||||
// SyntaxContext of the visibility.
|
||||
sig.span.find_ancestor_in_same_ctxt(*outer_span).unwrap_or(*outer_span)
|
||||
}
|
||||
// Constants and Statics.
|
||||
Node::Item(Item {
|
||||
kind:
|
||||
@ -985,7 +995,11 @@ impl<'hir> Map<'hir> {
|
||||
}
|
||||
// Other cases.
|
||||
Node::Item(item) => match &item.kind {
|
||||
ItemKind::Use(path, _) => path.span,
|
||||
ItemKind::Use(path, _) => {
|
||||
// Ensure that the returned span has the item's SyntaxContext, and not the
|
||||
// SyntaxContext of the path.
|
||||
path.span.find_ancestor_in_same_ctxt(item.span).unwrap_or(item.span)
|
||||
}
|
||||
_ => named_span(item.span, item.ident, item.kind.generics()),
|
||||
},
|
||||
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
|
||||
@ -995,11 +1009,17 @@ impl<'hir> Map<'hir> {
|
||||
_ => named_span(item.span, item.ident, None),
|
||||
},
|
||||
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
|
||||
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
|
||||
*fn_decl_span
|
||||
Node::Expr(Expr {
|
||||
kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
|
||||
span,
|
||||
..
|
||||
}) => {
|
||||
// Ensure that the returned span has the item's SyntaxContext.
|
||||
fn_decl_span.find_ancestor_in_same_ctxt(*span).unwrap_or(*span)
|
||||
}
|
||||
_ => self.span_with_body(hir_id),
|
||||
};
|
||||
debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt());
|
||||
Some(span)
|
||||
}
|
||||
|
||||
|
@ -2392,7 +2392,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
|
||||
#[rustc_const_unstable(
|
||||
feature = "const_btree_len",
|
||||
issue = "71835",
|
||||
implied_by = "const_btree_new"
|
||||
)]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
@ -2413,7 +2417,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
|
||||
#[rustc_const_unstable(
|
||||
feature = "const_btree_len",
|
||||
issue = "71835",
|
||||
implied_by = "const_btree_new"
|
||||
)]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
@ -1174,7 +1174,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
|
||||
#[rustc_const_unstable(
|
||||
feature = "const_btree_len",
|
||||
issue = "71835",
|
||||
implied_by = "const_btree_new"
|
||||
)]
|
||||
pub const fn len(&self) -> usize {
|
||||
self.map.len()
|
||||
}
|
||||
@ -1193,7 +1197,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_unstable(feature = "const_btree_len", issue = "71835")]
|
||||
#[rustc_const_unstable(
|
||||
feature = "const_btree_len",
|
||||
issue = "71835",
|
||||
implied_by = "const_btree_new"
|
||||
)]
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
@ -1980,33 +1980,26 @@ impl<T: ?Sized> Weak<T> {
|
||||
// We use a CAS loop to increment the strong count instead of a
|
||||
// fetch_add as this function should never take the reference count
|
||||
// from zero to one.
|
||||
let inner = self.inner()?;
|
||||
|
||||
// Relaxed load because any write of 0 that we can observe
|
||||
// leaves the field in a permanently zero state (so a
|
||||
// "stale" read of 0 is fine), and any other value is
|
||||
// confirmed via the CAS below.
|
||||
let mut n = inner.strong.load(Relaxed);
|
||||
|
||||
loop {
|
||||
if n == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// See comments in `Arc::clone` for why we do this (for `mem::forget`).
|
||||
if n > MAX_REFCOUNT {
|
||||
abort();
|
||||
}
|
||||
|
||||
self.inner()?
|
||||
.strong
|
||||
// Relaxed is fine for the failure case because we don't have any expectations about the new state.
|
||||
// Acquire is necessary for the success case to synchronise with `Arc::new_cyclic`, when the inner
|
||||
// value can be initialized after `Weak` references have already been created. In that case, we
|
||||
// expect to observe the fully initialized value.
|
||||
match inner.strong.compare_exchange_weak(n, n + 1, Acquire, Relaxed) {
|
||||
Ok(_) => return Some(unsafe { Arc::from_inner(self.ptr) }), // null checked above
|
||||
Err(old) => n = old,
|
||||
}
|
||||
}
|
||||
.fetch_update(Acquire, Relaxed, |n| {
|
||||
// Any write of 0 we can observe leaves the field in permanently zero state.
|
||||
if n == 0 {
|
||||
return None;
|
||||
}
|
||||
// See comments in `Arc::clone` for why we do this (for `mem::forget`).
|
||||
if n > MAX_REFCOUNT {
|
||||
abort();
|
||||
}
|
||||
Some(n + 1)
|
||||
})
|
||||
.ok()
|
||||
// null checked above
|
||||
.map(|_| unsafe { Arc::from_inner(self.ptr) })
|
||||
}
|
||||
|
||||
/// Gets the number of strong (`Arc`) pointers pointing to this allocation.
|
||||
|
@ -49,12 +49,12 @@ impl Bencher {
|
||||
self.summary = Some(iter(&mut inner));
|
||||
}
|
||||
|
||||
pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary>
|
||||
pub fn bench<F>(&mut self, mut f: F) -> Result<Option<stats::Summary>, String>
|
||||
where
|
||||
F: FnMut(&mut Bencher),
|
||||
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||
{
|
||||
f(self);
|
||||
self.summary
|
||||
let result = f(self);
|
||||
result.map(|_| self.summary)
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ pub fn benchmark<F>(
|
||||
nocapture: bool,
|
||||
f: F,
|
||||
) where
|
||||
F: FnMut(&mut Bencher),
|
||||
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||
{
|
||||
let mut bs = Bencher { mode: BenchMode::Auto, summary: None, bytes: 0 };
|
||||
|
||||
@ -211,14 +211,14 @@ pub fn benchmark<F>(
|
||||
|
||||
let test_result = match result {
|
||||
//bs.bench(f) {
|
||||
Ok(Some(ns_iter_summ)) => {
|
||||
Ok(Ok(Some(ns_iter_summ))) => {
|
||||
let ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
|
||||
let mb_s = bs.bytes * 1000 / ns_iter;
|
||||
|
||||
let bs = BenchSamples { ns_iter_summ, mb_s: mb_s as usize };
|
||||
TestResult::TrBench(bs)
|
||||
}
|
||||
Ok(None) => {
|
||||
Ok(Ok(None)) => {
|
||||
// iter not called, so no data.
|
||||
// FIXME: error in this case?
|
||||
let samples: &mut [f64] = &mut [0.0_f64; 1];
|
||||
@ -226,6 +226,7 @@ pub fn benchmark<F>(
|
||||
TestResult::TrBench(bs)
|
||||
}
|
||||
Err(_) => TestResult::TrFailed,
|
||||
Ok(Err(_)) => TestResult::TrFailed,
|
||||
};
|
||||
|
||||
let stdout = data.lock().unwrap().to_vec();
|
||||
@ -233,10 +234,10 @@ pub fn benchmark<F>(
|
||||
monitor_ch.send(message).unwrap();
|
||||
}
|
||||
|
||||
pub fn run_once<F>(f: F)
|
||||
pub fn run_once<F>(f: F) -> Result<(), String>
|
||||
where
|
||||
F: FnMut(&mut Bencher),
|
||||
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||
{
|
||||
let mut bs = Bencher { mode: BenchMode::Single, summary: None, bytes: 0 };
|
||||
bs.bench(f);
|
||||
bs.bench(f).map(|_| ())
|
||||
}
|
||||
|
@ -6,7 +6,8 @@
|
||||
//! benchmarks themselves) should be done via the `#[test]` and
|
||||
//! `#[bench]` attributes.
|
||||
//!
|
||||
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details.
|
||||
//! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more
|
||||
//! details.
|
||||
|
||||
// Currently, not much of this is meant for users. It is intended to
|
||||
// support the simplest interface possible for representing and
|
||||
@ -76,6 +77,7 @@ mod types;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use core::any::Any;
|
||||
use event::{CompletedTest, TestEvent};
|
||||
use helpers::concurrency::get_concurrency;
|
||||
use helpers::exit_code::get_exit_code;
|
||||
@ -175,17 +177,20 @@ fn make_owned_test(test: &&TestDescAndFn) -> TestDescAndFn {
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoked when unit tests terminate. Should panic if the unit
|
||||
/// Tests is considered a failure. By default, invokes `report()`
|
||||
/// and checks for a `0` result.
|
||||
pub fn assert_test_result<T: Termination>(result: T) {
|
||||
/// Invoked when unit tests terminate. Returns `Result::Err` if the test is
|
||||
/// considered a failure. By default, invokes `report() and checks for a `0`
|
||||
/// result.
|
||||
pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
|
||||
let code = result.report().to_i32();
|
||||
assert_eq!(
|
||||
code, 0,
|
||||
"the test returned a termination value with a non-zero status code ({}) \
|
||||
which indicates a failure",
|
||||
code
|
||||
);
|
||||
if code == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!(
|
||||
"the test returned a termination value with a non-zero status code \
|
||||
({}) which indicates a failure",
|
||||
code
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_tests<F>(
|
||||
@ -478,7 +483,7 @@ pub fn run_test(
|
||||
id: TestId,
|
||||
desc: TestDesc,
|
||||
monitor_ch: Sender<CompletedTest>,
|
||||
testfn: Box<dyn FnOnce() + Send>,
|
||||
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
|
||||
opts: TestRunOpts,
|
||||
) -> Option<thread::JoinHandle<()>> {
|
||||
let concurrency = opts.concurrency;
|
||||
@ -567,11 +572,11 @@ pub fn run_test(
|
||||
|
||||
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
|
||||
#[inline(never)]
|
||||
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
|
||||
f();
|
||||
fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
|
||||
let result = f();
|
||||
|
||||
// prevent this frame from being tail-call optimised away
|
||||
black_box(());
|
||||
black_box(result)
|
||||
}
|
||||
|
||||
fn run_test_in_process(
|
||||
@ -579,7 +584,7 @@ fn run_test_in_process(
|
||||
desc: TestDesc,
|
||||
nocapture: bool,
|
||||
report_time: bool,
|
||||
testfn: Box<dyn FnOnce() + Send>,
|
||||
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
|
||||
monitor_ch: Sender<CompletedTest>,
|
||||
time_opts: Option<time::TestTimeOptions>,
|
||||
) {
|
||||
@ -591,7 +596,7 @@ fn run_test_in_process(
|
||||
}
|
||||
|
||||
let start = report_time.then(Instant::now);
|
||||
let result = catch_unwind(AssertUnwindSafe(testfn));
|
||||
let result = fold_err(catch_unwind(AssertUnwindSafe(testfn)));
|
||||
let exec_time = start.map(|start| {
|
||||
let duration = start.elapsed();
|
||||
TestExecTime(duration)
|
||||
@ -608,6 +613,19 @@ fn run_test_in_process(
|
||||
monitor_ch.send(message).unwrap();
|
||||
}
|
||||
|
||||
fn fold_err<T, E>(
|
||||
result: Result<Result<T, E>, Box<dyn Any + Send>>,
|
||||
) -> Result<T, Box<dyn Any + Send>>
|
||||
where
|
||||
E: Send + 'static,
|
||||
{
|
||||
match result {
|
||||
Ok(Err(e)) => Err(Box::new(e)),
|
||||
Ok(Ok(v)) => Ok(v),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
fn spawn_test_subprocess(
|
||||
id: TestId,
|
||||
desc: TestDesc,
|
||||
@ -663,7 +681,10 @@ fn spawn_test_subprocess(
|
||||
monitor_ch.send(message).unwrap();
|
||||
}
|
||||
|
||||
fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Send>) -> ! {
|
||||
fn run_test_in_spawned_subprocess(
|
||||
desc: TestDesc,
|
||||
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
|
||||
) -> ! {
|
||||
let builtin_panic_hook = panic::take_hook();
|
||||
let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| {
|
||||
let test_result = match panic_info {
|
||||
@ -689,7 +710,9 @@ fn run_test_in_spawned_subprocess(desc: TestDesc, testfn: Box<dyn FnOnce() + Sen
|
||||
});
|
||||
let record_result2 = record_result.clone();
|
||||
panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
|
||||
testfn();
|
||||
if let Err(message) = testfn() {
|
||||
panic!("{}", message);
|
||||
}
|
||||
record_result(None);
|
||||
unreachable!("panic=abort callback should have exited the process")
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
||||
no_run: false,
|
||||
test_type: TestType::Unknown,
|
||||
},
|
||||
testfn: DynTestFn(Box::new(move || {})),
|
||||
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||
},
|
||||
TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
@ -79,14 +79,14 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
||||
no_run: false,
|
||||
test_type: TestType::Unknown,
|
||||
},
|
||||
testfn: DynTestFn(Box::new(move || {})),
|
||||
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn do_not_run_ignored_tests() {
|
||||
fn f() {
|
||||
fn f() -> Result<(), String> {
|
||||
panic!();
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
@ -109,7 +109,9 @@ pub fn do_not_run_ignored_tests() {
|
||||
|
||||
#[test]
|
||||
pub fn ignored_tests_result_in_ignored() {
|
||||
fn f() {}
|
||||
fn f() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
name: StaticTestName("whatever"),
|
||||
@ -132,7 +134,7 @@ pub fn ignored_tests_result_in_ignored() {
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn test_should_panic() {
|
||||
fn f() {
|
||||
fn f() -> Result<(), String> {
|
||||
panic!();
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
@ -157,7 +159,7 @@ fn test_should_panic() {
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn test_should_panic_good_message() {
|
||||
fn f() {
|
||||
fn f() -> Result<(), String> {
|
||||
panic!("an error message");
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
@ -183,7 +185,7 @@ fn test_should_panic_good_message() {
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn test_should_panic_bad_message() {
|
||||
use crate::tests::TrFailedMsg;
|
||||
fn f() {
|
||||
fn f() -> Result<(), String> {
|
||||
panic!("an error message");
|
||||
}
|
||||
let expected = "foobar";
|
||||
@ -214,7 +216,7 @@ fn test_should_panic_bad_message() {
|
||||
fn test_should_panic_non_string_message_type() {
|
||||
use crate::tests::TrFailedMsg;
|
||||
use std::any::TypeId;
|
||||
fn f() {
|
||||
fn f() -> Result<(), String> {
|
||||
std::panic::panic_any(1i32);
|
||||
}
|
||||
let expected = "foobar";
|
||||
@ -249,7 +251,9 @@ fn test_should_panic_but_succeeds() {
|
||||
let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
|
||||
|
||||
for &should_panic in should_panic_variants.iter() {
|
||||
fn f() {}
|
||||
fn f() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
name: StaticTestName("whatever"),
|
||||
@ -283,7 +287,9 @@ fn test_should_panic_but_succeeds() {
|
||||
}
|
||||
|
||||
fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
|
||||
fn f() {}
|
||||
fn f() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
name: StaticTestName("whatever"),
|
||||
@ -318,7 +324,9 @@ fn test_should_report_time() {
|
||||
}
|
||||
|
||||
fn time_test_failure_template(test_type: TestType) -> TestResult {
|
||||
fn f() {}
|
||||
fn f() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
name: StaticTestName("whatever"),
|
||||
@ -480,7 +488,7 @@ pub fn exclude_should_panic_option() {
|
||||
no_run: false,
|
||||
test_type: TestType::Unknown,
|
||||
},
|
||||
testfn: DynTestFn(Box::new(move || {})),
|
||||
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||
});
|
||||
|
||||
let filtered = filter_tests(&opts, tests);
|
||||
@ -504,7 +512,7 @@ pub fn exact_filter_match() {
|
||||
no_run: false,
|
||||
test_type: TestType::Unknown,
|
||||
},
|
||||
testfn: DynTestFn(Box::new(move || {})),
|
||||
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -580,7 +588,9 @@ fn sample_tests() -> Vec<TestDescAndFn> {
|
||||
"test::run_include_ignored_option".to_string(),
|
||||
"test::sort_tests".to_string(),
|
||||
];
|
||||
fn testfn() {}
|
||||
fn testfn() -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
let mut tests = Vec::new();
|
||||
for name in &names {
|
||||
let test = TestDescAndFn {
|
||||
@ -717,21 +727,26 @@ pub fn test_metricmap_compare() {
|
||||
|
||||
#[test]
|
||||
pub fn test_bench_once_no_iter() {
|
||||
fn f(_: &mut Bencher) {}
|
||||
bench::run_once(f);
|
||||
fn f(_: &mut Bencher) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
bench::run_once(f).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bench_once_iter() {
|
||||
fn f(b: &mut Bencher) {
|
||||
b.iter(|| {})
|
||||
fn f(b: &mut Bencher) -> Result<(), String> {
|
||||
b.iter(|| {});
|
||||
Ok(())
|
||||
}
|
||||
bench::run_once(f);
|
||||
bench::run_once(f).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_bench_no_iter() {
|
||||
fn f(_: &mut Bencher) {}
|
||||
fn f(_: &mut Bencher) -> Result<(), String> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
|
||||
@ -751,8 +766,9 @@ pub fn test_bench_no_iter() {
|
||||
|
||||
#[test]
|
||||
pub fn test_bench_iter() {
|
||||
fn f(b: &mut Bencher) {
|
||||
b.iter(|| {})
|
||||
fn f(b: &mut Bencher) -> Result<(), String> {
|
||||
b.iter(|| {});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let (tx, rx) = channel();
|
||||
@ -821,3 +837,33 @@ fn should_sort_failures_before_printing_them() {
|
||||
let bpos = s.find("b").unwrap();
|
||||
assert!(apos < bpos);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_os = "emscripten"))]
|
||||
fn test_dyn_bench_returning_err_fails_when_run_as_test() {
|
||||
fn f(_: &mut Bencher) -> Result<(), String> {
|
||||
Result::Err("An error".into())
|
||||
}
|
||||
let desc = TestDescAndFn {
|
||||
desc: TestDesc {
|
||||
name: StaticTestName("whatever"),
|
||||
ignore: false,
|
||||
ignore_message: None,
|
||||
should_panic: ShouldPanic::No,
|
||||
compile_fail: false,
|
||||
no_run: false,
|
||||
test_type: TestType::Unknown,
|
||||
},
|
||||
testfn: DynBenchFn(Box::new(f)),
|
||||
};
|
||||
let (tx, rx) = channel();
|
||||
let notify = move |event: TestEvent| {
|
||||
if let TestEvent::TeResult(result) = event {
|
||||
tx.send(result).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
run_tests(&TestOpts { run_tests: true, ..TestOpts::new() }, vec![desc], notify).unwrap();
|
||||
let result = rx.recv().unwrap().result;
|
||||
assert_eq!(result, TrFailed);
|
||||
}
|
||||
|
@ -75,14 +75,15 @@ impl fmt::Display for TestName {
|
||||
}
|
||||
|
||||
// A function that runs a test. If the function returns successfully,
|
||||
// the test succeeds; if the function panics then the test fails. We
|
||||
// may need to come up with a more clever definition of test in order
|
||||
// to support isolation of tests into threads.
|
||||
// the test succeeds; if the function panics or returns Result::Err
|
||||
// then the test fails. We may need to come up with a more clever
|
||||
// definition of test in order to support isolation of tests into
|
||||
// threads.
|
||||
pub enum TestFn {
|
||||
StaticTestFn(fn()),
|
||||
StaticBenchFn(fn(&mut Bencher)),
|
||||
DynTestFn(Box<dyn FnOnce() + Send>),
|
||||
DynBenchFn(Box<dyn Fn(&mut Bencher) + Send>),
|
||||
StaticTestFn(fn() -> Result<(), String>),
|
||||
StaticBenchFn(fn(&mut Bencher) -> Result<(), String>),
|
||||
DynTestFn(Box<dyn FnOnce() -> Result<(), String> + Send>),
|
||||
DynBenchFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
|
||||
}
|
||||
|
||||
impl TestFn {
|
||||
|
@ -1134,6 +1134,7 @@ impl Tester for Collector {
|
||||
|
||||
panic::resume_unwind(Box::new(()));
|
||||
}
|
||||
Ok(())
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
21
src/test/ui/consts/constifconst-call-in-const-position.rs
Normal file
21
src/test/ui/consts/constifconst-call-in-const-position.rs
Normal file
@ -0,0 +1,21 @@
|
||||
// known-bug: #102498
|
||||
|
||||
#![feature(const_trait_impl, generic_const_exprs)]
|
||||
|
||||
pub trait Tr {
|
||||
fn a() -> usize;
|
||||
}
|
||||
|
||||
impl Tr for () {
|
||||
fn a() -> usize {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
const fn foo<T: ~const Tr>() -> [u8; T::a()] {
|
||||
[0; T::a()]
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo::<()>();
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/constifconst-call-in-const-position.rs:3:30
|
||||
|
|
||||
LL | #![feature(const_trait_impl, generic_const_exprs)]
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0080]: evaluation of `foo::<()>::{constant#0}` failed
|
||||
--> $DIR/constifconst-call-in-const-position.rs:15:38
|
||||
|
|
||||
LL | const fn foo<T: ~const Tr>() -> [u8; T::a()] {
|
||||
| ^^^^^^ calling non-const function `<() as Tr>::a`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
@ -13,7 +13,7 @@ LL | | }
|
||||
note: required by a bound in `assert_test_result`
|
||||
--> $SRC_DIR/test/src/lib.rs:LL:COL
|
||||
|
|
||||
LL | pub fn assert_test_result<T: Termination>(result: T) {
|
||||
LL | pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
|
||||
| ^^^^^^^^^^^ required by this bound in `assert_test_result`
|
||||
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
|
@ -797,7 +797,10 @@ fn make_test_closure(
|
||||
let config = config.clone();
|
||||
let testpaths = testpaths.clone();
|
||||
let revision = revision.cloned();
|
||||
test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref())))
|
||||
test::DynTestFn(Box::new(move || {
|
||||
runtest::run(config, &testpaths, revision.as_deref());
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
/// Returns `true` if the given target is an Android target for the
|
||||
|
@ -538,7 +538,9 @@ fn map_lib_features(
|
||||
becoming_feature = None;
|
||||
if line.contains("rustc_const_unstable(") {
|
||||
// `const fn` features are handled specially.
|
||||
let feature_name = match find_attr_val(line, "feature") {
|
||||
let feature_name = match find_attr_val(line, "feature").or_else(|| {
|
||||
iter_lines.peek().and_then(|next| find_attr_val(next.1, "feature"))
|
||||
}) {
|
||||
Some(name) => name,
|
||||
None => err!("malformed stability attribute: missing `feature` key"),
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user