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
14 changed files with 239 additions and 94 deletions
|
@ -941,9 +941,19 @@ impl<'hir> Map<'hir> {
|
||||||
|
|
||||||
let span = match self.find(hir_id)? {
|
let span = match self.find(hir_id)? {
|
||||||
// Function-like.
|
// Function-like.
|
||||||
Node::Item(Item { kind: ItemKind::Fn(sig, ..), .. })
|
Node::Item(Item { kind: ItemKind::Fn(sig, ..), span: outer_span, .. })
|
||||||
| Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(sig, ..), .. })
|
| Node::TraitItem(TraitItem {
|
||||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(sig, ..), .. }) => sig.span,
|
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.
|
// Constants and Statics.
|
||||||
Node::Item(Item {
|
Node::Item(Item {
|
||||||
kind:
|
kind:
|
||||||
|
@ -985,7 +995,11 @@ impl<'hir> Map<'hir> {
|
||||||
}
|
}
|
||||||
// Other cases.
|
// Other cases.
|
||||||
Node::Item(item) => match &item.kind {
|
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()),
|
_ => named_span(item.span, item.ident, item.kind.generics()),
|
||||||
},
|
},
|
||||||
Node::Variant(variant) => named_span(variant.span, variant.ident, None),
|
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),
|
_ => named_span(item.span, item.ident, None),
|
||||||
},
|
},
|
||||||
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
|
Node::Ctor(_) => return self.opt_span(self.get_parent_node(hir_id)),
|
||||||
Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl_span, .. }), .. }) => {
|
Node::Expr(Expr {
|
||||||
*fn_decl_span
|
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),
|
_ => self.span_with_body(hir_id),
|
||||||
};
|
};
|
||||||
|
debug_assert_eq!(span.ctxt(), self.span_with_body(hir_id).ctxt());
|
||||||
Some(span)
|
Some(span)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2392,7 +2392,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub const fn len(&self) -> usize {
|
||||||
self.length
|
self.length
|
||||||
}
|
}
|
||||||
|
@ -2413,7 +2417,11 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub const fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
|
|
@ -1174,7 +1174,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub const fn len(&self) -> usize {
|
||||||
self.map.len()
|
self.map.len()
|
||||||
}
|
}
|
||||||
|
@ -1193,7 +1197,11 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> {
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub const fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
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
|
// We use a CAS loop to increment the strong count instead of a
|
||||||
// fetch_add as this function should never take the reference count
|
// fetch_add as this function should never take the reference count
|
||||||
// from zero to one.
|
// from zero to one.
|
||||||
let inner = self.inner()?;
|
self.inner()?
|
||||||
|
.strong
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Relaxed is fine for the failure case because we don't have any expectations about the new state.
|
// 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
|
// 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
|
// value can be initialized after `Weak` references have already been created. In that case, we
|
||||||
// expect to observe the fully initialized value.
|
// expect to observe the fully initialized value.
|
||||||
match inner.strong.compare_exchange_weak(n, n + 1, Acquire, Relaxed) {
|
.fetch_update(Acquire, Relaxed, |n| {
|
||||||
Ok(_) => return Some(unsafe { Arc::from_inner(self.ptr) }), // null checked above
|
// Any write of 0 we can observe leaves the field in permanently zero state.
|
||||||
Err(old) => n = old,
|
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.
|
/// Gets the number of strong (`Arc`) pointers pointing to this allocation.
|
||||||
|
|
|
@ -49,12 +49,12 @@ impl Bencher {
|
||||||
self.summary = Some(iter(&mut inner));
|
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
|
where
|
||||||
F: FnMut(&mut Bencher),
|
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||||
{
|
{
|
||||||
f(self);
|
let result = f(self);
|
||||||
self.summary
|
result.map(|_| self.summary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ pub fn benchmark<F>(
|
||||||
nocapture: bool,
|
nocapture: bool,
|
||||||
f: F,
|
f: F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(&mut Bencher),
|
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||||
{
|
{
|
||||||
let mut bs = Bencher { mode: BenchMode::Auto, summary: None, bytes: 0 };
|
let mut bs = Bencher { mode: BenchMode::Auto, summary: None, bytes: 0 };
|
||||||
|
|
||||||
|
@ -211,14 +211,14 @@ pub fn benchmark<F>(
|
||||||
|
|
||||||
let test_result = match result {
|
let test_result = match result {
|
||||||
//bs.bench(f) {
|
//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 ns_iter = cmp::max(ns_iter_summ.median as u64, 1);
|
||||||
let mb_s = bs.bytes * 1000 / ns_iter;
|
let mb_s = bs.bytes * 1000 / ns_iter;
|
||||||
|
|
||||||
let bs = BenchSamples { ns_iter_summ, mb_s: mb_s as usize };
|
let bs = BenchSamples { ns_iter_summ, mb_s: mb_s as usize };
|
||||||
TestResult::TrBench(bs)
|
TestResult::TrBench(bs)
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(Ok(None)) => {
|
||||||
// iter not called, so no data.
|
// iter not called, so no data.
|
||||||
// FIXME: error in this case?
|
// FIXME: error in this case?
|
||||||
let samples: &mut [f64] = &mut [0.0_f64; 1];
|
let samples: &mut [f64] = &mut [0.0_f64; 1];
|
||||||
|
@ -226,6 +226,7 @@ pub fn benchmark<F>(
|
||||||
TestResult::TrBench(bs)
|
TestResult::TrBench(bs)
|
||||||
}
|
}
|
||||||
Err(_) => TestResult::TrFailed,
|
Err(_) => TestResult::TrFailed,
|
||||||
|
Ok(Err(_)) => TestResult::TrFailed,
|
||||||
};
|
};
|
||||||
|
|
||||||
let stdout = data.lock().unwrap().to_vec();
|
let stdout = data.lock().unwrap().to_vec();
|
||||||
|
@ -233,10 +234,10 @@ pub fn benchmark<F>(
|
||||||
monitor_ch.send(message).unwrap();
|
monitor_ch.send(message).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_once<F>(f: F)
|
pub fn run_once<F>(f: F) -> Result<(), String>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut Bencher),
|
F: FnMut(&mut Bencher) -> Result<(), String>,
|
||||||
{
|
{
|
||||||
let mut bs = Bencher { mode: BenchMode::Single, summary: None, bytes: 0 };
|
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
|
//! benchmarks themselves) should be done via the `#[test]` and
|
||||||
//! `#[bench]` attributes.
|
//! `#[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
|
// Currently, not much of this is meant for users. It is intended to
|
||||||
// support the simplest interface possible for representing and
|
// support the simplest interface possible for representing and
|
||||||
|
@ -76,6 +77,7 @@ mod types;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
|
use core::any::Any;
|
||||||
use event::{CompletedTest, TestEvent};
|
use event::{CompletedTest, TestEvent};
|
||||||
use helpers::concurrency::get_concurrency;
|
use helpers::concurrency::get_concurrency;
|
||||||
use helpers::exit_code::get_exit_code;
|
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
|
/// Invoked when unit tests terminate. Returns `Result::Err` if the test is
|
||||||
/// Tests is considered a failure. By default, invokes `report()`
|
/// considered a failure. By default, invokes `report() and checks for a `0`
|
||||||
/// and checks for a `0` result.
|
/// result.
|
||||||
pub fn assert_test_result<T: Termination>(result: T) {
|
pub fn assert_test_result<T: Termination>(result: T) -> Result<(), String> {
|
||||||
let code = result.report().to_i32();
|
let code = result.report().to_i32();
|
||||||
assert_eq!(
|
if code == 0 {
|
||||||
code, 0,
|
Ok(())
|
||||||
"the test returned a termination value with a non-zero status code ({}) \
|
} else {
|
||||||
which indicates a failure",
|
Err(format!(
|
||||||
code
|
"the test returned a termination value with a non-zero status code \
|
||||||
);
|
({}) which indicates a failure",
|
||||||
|
code
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tests<F>(
|
pub fn run_tests<F>(
|
||||||
|
@ -478,7 +483,7 @@ pub fn run_test(
|
||||||
id: TestId,
|
id: TestId,
|
||||||
desc: TestDesc,
|
desc: TestDesc,
|
||||||
monitor_ch: Sender<CompletedTest>,
|
monitor_ch: Sender<CompletedTest>,
|
||||||
testfn: Box<dyn FnOnce() + Send>,
|
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
|
||||||
opts: TestRunOpts,
|
opts: TestRunOpts,
|
||||||
) -> Option<thread::JoinHandle<()>> {
|
) -> Option<thread::JoinHandle<()>> {
|
||||||
let concurrency = opts.concurrency;
|
let concurrency = opts.concurrency;
|
||||||
|
@ -567,11 +572,11 @@ pub fn run_test(
|
||||||
|
|
||||||
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
|
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
|
fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
|
||||||
f();
|
let result = f();
|
||||||
|
|
||||||
// prevent this frame from being tail-call optimised away
|
// prevent this frame from being tail-call optimised away
|
||||||
black_box(());
|
black_box(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_test_in_process(
|
fn run_test_in_process(
|
||||||
|
@ -579,7 +584,7 @@ fn run_test_in_process(
|
||||||
desc: TestDesc,
|
desc: TestDesc,
|
||||||
nocapture: bool,
|
nocapture: bool,
|
||||||
report_time: bool,
|
report_time: bool,
|
||||||
testfn: Box<dyn FnOnce() + Send>,
|
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
|
||||||
monitor_ch: Sender<CompletedTest>,
|
monitor_ch: Sender<CompletedTest>,
|
||||||
time_opts: Option<time::TestTimeOptions>,
|
time_opts: Option<time::TestTimeOptions>,
|
||||||
) {
|
) {
|
||||||
|
@ -591,7 +596,7 @@ fn run_test_in_process(
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = report_time.then(Instant::now);
|
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 exec_time = start.map(|start| {
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
TestExecTime(duration)
|
TestExecTime(duration)
|
||||||
|
@ -608,6 +613,19 @@ fn run_test_in_process(
|
||||||
monitor_ch.send(message).unwrap();
|
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(
|
fn spawn_test_subprocess(
|
||||||
id: TestId,
|
id: TestId,
|
||||||
desc: TestDesc,
|
desc: TestDesc,
|
||||||
|
@ -663,7 +681,10 @@ fn spawn_test_subprocess(
|
||||||
monitor_ch.send(message).unwrap();
|
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 builtin_panic_hook = panic::take_hook();
|
||||||
let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| {
|
let record_result = Arc::new(move |panic_info: Option<&'_ PanicInfo<'_>>| {
|
||||||
let test_result = match panic_info {
|
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();
|
let record_result2 = record_result.clone();
|
||||||
panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
|
panic::set_hook(Box::new(move |info| record_result2(Some(&info))));
|
||||||
testfn();
|
if let Err(message) = testfn() {
|
||||||
|
panic!("{}", message);
|
||||||
|
}
|
||||||
record_result(None);
|
record_result(None);
|
||||||
unreachable!("panic=abort callback should have exited the process")
|
unreachable!("panic=abort callback should have exited the process")
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
||||||
no_run: false,
|
no_run: false,
|
||||||
test_type: TestType::Unknown,
|
test_type: TestType::Unknown,
|
||||||
},
|
},
|
||||||
testfn: DynTestFn(Box::new(move || {})),
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||||
},
|
},
|
||||||
TestDescAndFn {
|
TestDescAndFn {
|
||||||
desc: TestDesc {
|
desc: TestDesc {
|
||||||
|
@ -79,14 +79,14 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
|
||||||
no_run: false,
|
no_run: false,
|
||||||
test_type: TestType::Unknown,
|
test_type: TestType::Unknown,
|
||||||
},
|
},
|
||||||
testfn: DynTestFn(Box::new(move || {})),
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn do_not_run_ignored_tests() {
|
pub fn do_not_run_ignored_tests() {
|
||||||
fn f() {
|
fn f() -> Result<(), String> {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
|
@ -109,7 +109,9 @@ pub fn do_not_run_ignored_tests() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn ignored_tests_result_in_ignored() {
|
pub fn ignored_tests_result_in_ignored() {
|
||||||
fn f() {}
|
fn f() -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
desc: TestDesc {
|
desc: TestDesc {
|
||||||
name: StaticTestName("whatever"),
|
name: StaticTestName("whatever"),
|
||||||
|
@ -132,7 +134,7 @@ pub fn ignored_tests_result_in_ignored() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
fn test_should_panic() {
|
fn test_should_panic() {
|
||||||
fn f() {
|
fn f() -> Result<(), String> {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
|
@ -157,7 +159,7 @@ fn test_should_panic() {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
fn test_should_panic_good_message() {
|
fn test_should_panic_good_message() {
|
||||||
fn f() {
|
fn f() -> Result<(), String> {
|
||||||
panic!("an error message");
|
panic!("an error message");
|
||||||
}
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
|
@ -183,7 +185,7 @@ fn test_should_panic_good_message() {
|
||||||
#[cfg(not(target_os = "emscripten"))]
|
#[cfg(not(target_os = "emscripten"))]
|
||||||
fn test_should_panic_bad_message() {
|
fn test_should_panic_bad_message() {
|
||||||
use crate::tests::TrFailedMsg;
|
use crate::tests::TrFailedMsg;
|
||||||
fn f() {
|
fn f() -> Result<(), String> {
|
||||||
panic!("an error message");
|
panic!("an error message");
|
||||||
}
|
}
|
||||||
let expected = "foobar";
|
let expected = "foobar";
|
||||||
|
@ -214,7 +216,7 @@ fn test_should_panic_bad_message() {
|
||||||
fn test_should_panic_non_string_message_type() {
|
fn test_should_panic_non_string_message_type() {
|
||||||
use crate::tests::TrFailedMsg;
|
use crate::tests::TrFailedMsg;
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
fn f() {
|
fn f() -> Result<(), String> {
|
||||||
std::panic::panic_any(1i32);
|
std::panic::panic_any(1i32);
|
||||||
}
|
}
|
||||||
let expected = "foobar";
|
let expected = "foobar";
|
||||||
|
@ -249,7 +251,9 @@ fn test_should_panic_but_succeeds() {
|
||||||
let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
|
let should_panic_variants = [ShouldPanic::Yes, ShouldPanic::YesWithMessage("error message")];
|
||||||
|
|
||||||
for &should_panic in should_panic_variants.iter() {
|
for &should_panic in should_panic_variants.iter() {
|
||||||
fn f() {}
|
fn f() -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
desc: TestDesc {
|
desc: TestDesc {
|
||||||
name: StaticTestName("whatever"),
|
name: StaticTestName("whatever"),
|
||||||
|
@ -283,7 +287,9 @@ fn test_should_panic_but_succeeds() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
|
fn report_time_test_template(report_time: bool) -> Option<TestExecTime> {
|
||||||
fn f() {}
|
fn f() -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
desc: TestDesc {
|
desc: TestDesc {
|
||||||
name: StaticTestName("whatever"),
|
name: StaticTestName("whatever"),
|
||||||
|
@ -318,7 +324,9 @@ fn test_should_report_time() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn time_test_failure_template(test_type: TestType) -> TestResult {
|
fn time_test_failure_template(test_type: TestType) -> TestResult {
|
||||||
fn f() {}
|
fn f() -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
let desc = TestDescAndFn {
|
let desc = TestDescAndFn {
|
||||||
desc: TestDesc {
|
desc: TestDesc {
|
||||||
name: StaticTestName("whatever"),
|
name: StaticTestName("whatever"),
|
||||||
|
@ -480,7 +488,7 @@ pub fn exclude_should_panic_option() {
|
||||||
no_run: false,
|
no_run: false,
|
||||||
test_type: TestType::Unknown,
|
test_type: TestType::Unknown,
|
||||||
},
|
},
|
||||||
testfn: DynTestFn(Box::new(move || {})),
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||||
});
|
});
|
||||||
|
|
||||||
let filtered = filter_tests(&opts, tests);
|
let filtered = filter_tests(&opts, tests);
|
||||||
|
@ -504,7 +512,7 @@ pub fn exact_filter_match() {
|
||||||
no_run: false,
|
no_run: false,
|
||||||
test_type: TestType::Unknown,
|
test_type: TestType::Unknown,
|
||||||
},
|
},
|
||||||
testfn: DynTestFn(Box::new(move || {})),
|
testfn: DynTestFn(Box::new(move || Ok(()))),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -580,7 +588,9 @@ fn sample_tests() -> Vec<TestDescAndFn> {
|
||||||
"test::run_include_ignored_option".to_string(),
|
"test::run_include_ignored_option".to_string(),
|
||||||
"test::sort_tests".to_string(),
|
"test::sort_tests".to_string(),
|
||||||
];
|
];
|
||||||
fn testfn() {}
|
fn testfn() -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
let mut tests = Vec::new();
|
let mut tests = Vec::new();
|
||||||
for name in &names {
|
for name in &names {
|
||||||
let test = TestDescAndFn {
|
let test = TestDescAndFn {
|
||||||
|
@ -717,21 +727,26 @@ pub fn test_metricmap_compare() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_bench_once_no_iter() {
|
pub fn test_bench_once_no_iter() {
|
||||||
fn f(_: &mut Bencher) {}
|
fn f(_: &mut Bencher) -> Result<(), String> {
|
||||||
bench::run_once(f);
|
Ok(())
|
||||||
|
}
|
||||||
|
bench::run_once(f).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_bench_once_iter() {
|
pub fn test_bench_once_iter() {
|
||||||
fn f(b: &mut Bencher) {
|
fn f(b: &mut Bencher) -> Result<(), String> {
|
||||||
b.iter(|| {})
|
b.iter(|| {});
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
bench::run_once(f);
|
bench::run_once(f).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_bench_no_iter() {
|
pub fn test_bench_no_iter() {
|
||||||
fn f(_: &mut Bencher) {}
|
fn f(_: &mut Bencher) -> Result<(), String> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
|
||||||
|
@ -751,8 +766,9 @@ pub fn test_bench_no_iter() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_bench_iter() {
|
pub fn test_bench_iter() {
|
||||||
fn f(b: &mut Bencher) {
|
fn f(b: &mut Bencher) -> Result<(), String> {
|
||||||
b.iter(|| {})
|
b.iter(|| {});
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
|
@ -821,3 +837,33 @@ fn should_sort_failures_before_printing_them() {
|
||||||
let bpos = s.find("b").unwrap();
|
let bpos = s.find("b").unwrap();
|
||||||
assert!(apos < bpos);
|
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,
|
// A function that runs a test. If the function returns successfully,
|
||||||
// the test succeeds; if the function panics then the test fails. We
|
// the test succeeds; if the function panics or returns Result::Err
|
||||||
// may need to come up with a more clever definition of test in order
|
// then the test fails. We may need to come up with a more clever
|
||||||
// to support isolation of tests into threads.
|
// definition of test in order to support isolation of tests into
|
||||||
|
// threads.
|
||||||
pub enum TestFn {
|
pub enum TestFn {
|
||||||
StaticTestFn(fn()),
|
StaticTestFn(fn() -> Result<(), String>),
|
||||||
StaticBenchFn(fn(&mut Bencher)),
|
StaticBenchFn(fn(&mut Bencher) -> Result<(), String>),
|
||||||
DynTestFn(Box<dyn FnOnce() + Send>),
|
DynTestFn(Box<dyn FnOnce() -> Result<(), String> + Send>),
|
||||||
DynBenchFn(Box<dyn Fn(&mut Bencher) + Send>),
|
DynBenchFn(Box<dyn Fn(&mut Bencher) -> Result<(), String> + Send>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestFn {
|
impl TestFn {
|
||||||
|
|
|
@ -1134,6 +1134,7 @@ impl Tester for Collector {
|
||||||
|
|
||||||
panic::resume_unwind(Box::new(()));
|
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`
|
note: required by a bound in `assert_test_result`
|
||||||
--> $SRC_DIR/test/src/lib.rs:LL:COL
|
--> $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`
|
| ^^^^^^^^^^^ 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)
|
= 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 config = config.clone();
|
||||||
let testpaths = testpaths.clone();
|
let testpaths = testpaths.clone();
|
||||||
let revision = revision.cloned();
|
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
|
/// Returns `true` if the given target is an Android target for the
|
||||||
|
|
|
@ -538,7 +538,9 @@ fn map_lib_features(
|
||||||
becoming_feature = None;
|
becoming_feature = None;
|
||||||
if line.contains("rustc_const_unstable(") {
|
if line.contains("rustc_const_unstable(") {
|
||||||
// `const fn` features are handled specially.
|
// `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,
|
Some(name) => name,
|
||||||
None => err!("malformed stability attribute: missing `feature` key"),
|
None => err!("malformed stability attribute: missing `feature` key"),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue