summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tracing-attributes/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/tracing-attributes/tests
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tracing-attributes/tests')
-rw-r--r--third_party/rust/tracing-attributes/tests/async_fn.rs488
-rw-r--r--third_party/rust/tracing-attributes/tests/destructuring.rs213
-rw-r--r--third_party/rust/tracing-attributes/tests/err.rs306
-rw-r--r--third_party/rust/tracing-attributes/tests/fields.rs160
-rw-r--r--third_party/rust/tracing-attributes/tests/follows_from.rs101
-rw-r--r--third_party/rust/tracing-attributes/tests/instrument.rs252
-rw-r--r--third_party/rust/tracing-attributes/tests/levels.rs142
-rw-r--r--third_party/rust/tracing-attributes/tests/names.rs63
-rw-r--r--third_party/rust/tracing-attributes/tests/parents.rs102
-rw-r--r--third_party/rust/tracing-attributes/tests/ret.rs307
-rw-r--r--third_party/rust/tracing-attributes/tests/targets.rs97
-rw-r--r--third_party/rust/tracing-attributes/tests/ui.rs14
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/async_instrument.rs46
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr98
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/const_instrument.rs8
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/const_instrument.stderr15
16 files changed, 2412 insertions, 0 deletions
diff --git a/third_party/rust/tracing-attributes/tests/async_fn.rs b/third_party/rust/tracing-attributes/tests/async_fn.rs
new file mode 100644
index 0000000000..d6d874ffd7
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/async_fn.rs
@@ -0,0 +1,488 @@
+use tracing_mock::*;
+
+use std::convert::Infallible;
+use std::{future::Future, pin::Pin, sync::Arc};
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+
+#[instrument]
+async fn test_async_fn(polls: usize) -> Result<(), ()> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await
+}
+
+// Reproduces a compile error when returning an `impl Trait` from an
+// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument]
+async fn test_ret_impl_trait(n: i32) -> Result<impl Iterator<Item = i32>, ()> {
+ let n = n;
+ Ok((0..10).filter(move |x| *x < n))
+}
+
+// Reproduces a compile error when returning an `impl Trait` from an
+// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument(err)]
+async fn test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'static str> {
+ Ok((0..10).filter(move |x| *x < n))
+}
+
+#[instrument]
+async fn test_async_fn_empty() {}
+
+// Reproduces a compile error when an instrumented function body contains inner
+// attributes (https://github.com/tokio-rs/tracing/issues/2294).
+#[deny(unused_variables)]
+#[instrument]
+async fn repro_async_2294() {
+ #![allow(unused_variables)]
+ let i = 42;
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1613
+#[instrument]
+// LOAD-BEARING `#[rustfmt::skip]`! This is necessary to reproduce the bug;
+// with the rustfmt-generated formatting, the lint will not be triggered!
+#[rustfmt::skip]
+#[deny(clippy::suspicious_else_formatting)]
+async fn repro_1613(var: bool) {
+ println!(
+ "{}",
+ if var { "true" } else { "false" }
+ );
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1613
+// and https://github.com/rust-lang/rust-clippy/issues/7760
+#[instrument]
+#[deny(clippy::suspicious_else_formatting)]
+async fn repro_1613_2() {
+ // hello world
+ // else
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1831
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument]
+#[deny(unused_braces)]
+fn repro_1831() -> Pin<Box<dyn Future<Output = ()>>> {
+ Box::pin(async move {})
+}
+
+// This replicates the pattern used to implement async trait methods on nightly using the
+// `type_alias_impl_trait` feature
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument(ret, err)]
+#[deny(unused_braces)]
+#[allow(clippy::manual_async_fn)]
+fn repro_1831_2() -> impl Future<Output = Result<(), Infallible>> {
+ async { Ok(()) }
+}
+
+#[test]
+fn async_fn_only_enters_for_polls() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("test_async_fn"))
+ .enter(span::mock().named("test_async_fn"))
+ .event(event::mock().with_fields(field::mock("awaiting").with_value(&true)))
+ .exit(span::mock().named("test_async_fn"))
+ .enter(span::mock().named("test_async_fn"))
+ .exit(span::mock().named("test_async_fn"))
+ .enter(span::mock().named("test_async_fn"))
+ .exit(span::mock().named("test_async_fn"))
+ .drop_span(span::mock().named("test_async_fn"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { test_async_fn(2).await }).unwrap();
+ });
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_nested() {
+ #[instrument]
+ async fn test_async_fns_nested() {
+ test_async_fns_nested_other().await
+ }
+
+ #[instrument]
+ async fn test_async_fns_nested_other() {
+ tracing::trace!(nested = true);
+ }
+
+ let span = span::mock().named("test_async_fns_nested");
+ let span2 = span::mock().named("test_async_fns_nested_other");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .new_span(span2.clone())
+ .enter(span2.clone())
+ .event(event::mock().with_fields(field::mock("nested").with_value(&true)))
+ .exit(span2.clone())
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async { test_async_fns_nested().await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait() {
+ use async_trait::async_trait;
+
+ // test the correctness of the metadata obtained by #[instrument]
+ // (function name, functions parameters) when async-trait is used
+ #[async_trait]
+ pub trait TestA {
+ async fn foo(&mut self, v: usize);
+ }
+
+ // test nesting of async fns with aync-trait
+ #[async_trait]
+ pub trait TestB {
+ async fn bar(&self);
+ }
+
+ // test skip(self) with async-await
+ #[async_trait]
+ pub trait TestC {
+ async fn baz(&self);
+ }
+
+ #[derive(Debug)]
+ struct TestImpl(usize);
+
+ #[async_trait]
+ impl TestA for TestImpl {
+ #[instrument]
+ async fn foo(&mut self, v: usize) {
+ self.baz().await;
+ self.0 = v;
+ self.bar().await
+ }
+ }
+
+ #[async_trait]
+ impl TestB for TestImpl {
+ #[instrument]
+ async fn bar(&self) {
+ tracing::trace!(val = self.0);
+ }
+ }
+
+ #[async_trait]
+ impl TestC for TestImpl {
+ #[instrument(skip(self))]
+ async fn baz(&self) {
+ tracing::trace!(val = self.0);
+ }
+ }
+
+ let span = span::mock().named("foo");
+ let span2 = span::mock().named("bar");
+ let span3 = span::mock().named("baz");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("self"))
+ .with_field(field::mock("v")),
+ )
+ .enter(span.clone())
+ .new_span(span3.clone())
+ .enter(span3.clone())
+ .event(event::mock().with_fields(field::mock("val").with_value(&2u64)))
+ .exit(span3.clone())
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .drop_span(span3)
+ .new_span(span2.clone().with_field(field::mock("self")))
+ .enter(span2.clone())
+ .event(event::mock().with_fields(field::mock("val").with_value(&5u64)))
+ .exit(span2.clone())
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let mut test = TestImpl(2);
+ block_on_future(async { test.foo(5).await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait_and_fields_expressions() {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Test {
+ async fn call(&mut self, v: usize);
+ }
+
+ #[derive(Clone, Debug)]
+ struct TestImpl;
+
+ impl TestImpl {
+ fn foo(&self) -> usize {
+ 42
+ }
+ }
+
+ #[async_trait]
+ impl Test for TestImpl {
+ // check that self is correctly handled, even when using async_trait
+ #[instrument(fields(val=self.foo(), val2=Self::clone(self).foo(), test=%_v+5))]
+ async fn call(&mut self, _v: usize) {}
+ }
+
+ let span = span::mock().named("call");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("_v")
+ .with_value(&5usize)
+ .and(field::mock("test").with_value(&tracing::field::debug(10)))
+ .and(field::mock("val").with_value(&42u64))
+ .and(field::mock("val2").with_value(&42u64)),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async { TestImpl.call(5).await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Test {
+ async fn call();
+ async fn call_with_self(&self);
+ async fn call_with_mut_self(&mut self);
+ }
+
+ #[derive(Clone, Debug)]
+ struct TestImpl;
+
+ // we also test sync functions that return futures, as they should be handled just like
+ // async-trait (>= 0.1.44) functions
+ impl TestImpl {
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ fn sync_fun(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
+ let val = self.clone();
+ Box::pin(async move {
+ let _ = val;
+ })
+ }
+ }
+
+ #[async_trait]
+ impl Test for TestImpl {
+ // instrumenting this is currently not possible, see https://github.com/tokio-rs/tracing/issues/864#issuecomment-667508801
+ //#[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call() {}
+
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call_with_self(&self) {
+ self.sync_fun().await;
+ }
+
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call_with_mut_self(&mut self) {}
+ }
+
+ //let span = span::mock().named("call");
+ let span2 = span::mock().named("call_with_self");
+ let span3 = span::mock().named("call_with_mut_self");
+ let span4 = span::mock().named("sync_fun");
+ let (subscriber, handle) = subscriber::mock()
+ /*.new_span(span.clone()
+ .with_field(
+ field::mock("Self").with_value(&"TestImpler")))
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)*/
+ .new_span(
+ span2
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span2.clone())
+ .new_span(
+ span4
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span4.clone())
+ .exit(span4.clone())
+ .enter(span4.clone())
+ .exit(span4)
+ .exit(span2.clone())
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .new_span(
+ span3
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .drop_span(span3)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ TestImpl::call().await;
+ TestImpl.call_with_self().await;
+ TestImpl.call_with_mut_self().await
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn out_of_scope_fields() {
+ // Reproduces tokio-rs/tracing#1296
+
+ struct Thing {
+ metrics: Arc<()>,
+ }
+
+ impl Thing {
+ #[instrument(skip(self, _req), fields(app_id))]
+ fn call(&mut self, _req: ()) -> Pin<Box<dyn Future<Output = Arc<()>> + Send + Sync>> {
+ // ...
+ let metrics = self.metrics.clone();
+ // ...
+ Box::pin(async move {
+ // ...
+ metrics // cannot find value `metrics` in this scope
+ })
+ }
+ }
+
+ let span = span::mock().named("call");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ let mut my_thing = Thing {
+ metrics: Arc::new(()),
+ };
+ my_thing.call(()).await;
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn manual_impl_future() {
+ #[allow(clippy::manual_async_fn)]
+ #[instrument]
+ fn manual_impl_future() -> impl Future<Output = ()> {
+ async {
+ tracing::trace!(poll = true);
+ }
+ }
+
+ let span = span::mock().named("manual_impl_future");
+ let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true));
+
+ let (subscriber, handle) = subscriber::mock()
+ // await manual_impl_future
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(poll_event())
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ manual_impl_future().await;
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn manual_box_pin() {
+ #[instrument]
+ fn manual_box_pin() -> Pin<Box<dyn Future<Output = ()>>> {
+ Box::pin(async {
+ tracing::trace!(poll = true);
+ })
+ }
+
+ let span = span::mock().named("manual_box_pin");
+ let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true));
+
+ let (subscriber, handle) = subscriber::mock()
+ // await manual_box_pin
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(poll_event())
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ manual_box_pin().await;
+ });
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/destructuring.rs b/third_party/rust/tracing-attributes/tests/destructuring.rs
new file mode 100644
index 0000000000..09cf1ad534
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/destructuring.rs
@@ -0,0 +1,213 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[test]
+fn destructure_tuples() {
+ #[instrument]
+ fn my_fn((arg1, arg2): (usize, usize)) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn((1, 2));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_nested_tuples() {
+ #[instrument]
+ fn my_fn(((arg1, arg2), (arg3, arg4)): ((usize, usize), (usize, usize))) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .and(field::mock("arg3").with_value(&format_args!("3")))
+ .and(field::mock("arg4").with_value(&format_args!("4")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(((1, 2), (3, 4)));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_refs() {
+ #[instrument]
+ fn my_fn(&arg1: &usize) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("arg1").with_value(&1usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(&1);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_tuple_structs() {
+ struct Foo(usize, usize);
+
+ #[instrument]
+ fn my_fn(Foo(arg1, arg2): Foo) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo(1, 2));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_structs() {
+ struct Foo {
+ bar: usize,
+ baz: usize,
+ }
+
+ #[instrument]
+ fn my_fn(
+ Foo {
+ bar: arg1,
+ baz: arg2,
+ }: Foo,
+ ) {
+ let _ = (arg1, arg2);
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo { bar: 1, baz: 2 });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_everything() {
+ struct Foo {
+ bar: Bar,
+ baz: (usize, usize),
+ qux: NoDebug,
+ }
+ struct Bar((usize, usize));
+ struct NoDebug;
+
+ #[instrument]
+ fn my_fn(
+ &Foo {
+ bar: Bar((arg1, arg2)),
+ baz: (arg3, arg4),
+ ..
+ }: &Foo,
+ ) {
+ let _ = (arg1, arg2, arg3, arg4);
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .and(field::mock("arg3").with_value(&format_args!("3")))
+ .and(field::mock("arg4").with_value(&format_args!("4")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = Foo {
+ bar: Bar((1, 2)),
+ baz: (3, 4),
+ qux: NoDebug,
+ };
+ let _ = foo.qux; // to eliminate unused field warning
+ my_fn(&foo);
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/err.rs b/third_party/rust/tracing-attributes/tests/err.rs
new file mode 100644
index 0000000000..485dd11961
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/err.rs
@@ -0,0 +1,306 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+use tracing_subscriber::filter::EnvFilter;
+use tracing_subscriber::layer::SubscriberExt;
+
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
+
+#[instrument(err)]
+fn err() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[instrument(err)]
+fn err_suspicious_else() -> Result<u8, TryFromIntError> {
+ {}
+ u8::try_from(1234)
+}
+
+#[test]
+fn test() {
+ let span = span::mock().named("err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err().ok());
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+async fn err_async(polls: usize) -> Result<u8, TryFromIntError> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await.ok();
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_async() {
+ let span = span::mock().named("err_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("awaiting").with_value(&true))
+ .at_level(Level::TRACE),
+ )
+ .exit(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { err_async(2).await }).ok();
+ });
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+fn err_mut(out: &mut u8) -> Result<(), TryFromIntError> {
+ *out = u8::try_from(1234)?;
+ Ok(())
+}
+
+#[test]
+fn test_mut() {
+ let span = span::mock().named("err_mut");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_mut(&mut 0).ok());
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+async fn err_mut_async(polls: usize, out: &mut u8) -> Result<(), TryFromIntError> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await.ok();
+ *out = u8::try_from(1234)?;
+ Ok(())
+}
+
+#[test]
+fn test_mut_async() {
+ let span = span::mock().named("err_mut_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("awaiting").with_value(&true))
+ .at_level(Level::TRACE),
+ )
+ .exit(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { err_mut_async(2, &mut 0).await }).ok();
+ });
+ handle.assert_finished();
+}
+
+#[test]
+fn impl_trait_return_type() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/1227
+
+ #[instrument(err)]
+ fn returns_impl_trait(x: usize) -> Result<impl Iterator<Item = usize>, String> {
+ Ok(0..x)
+ }
+
+ let span = span::mock().named("returns_impl_trait");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("x").with_value(&10usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ for _ in returns_impl_trait(10).unwrap() {
+ // nop
+ }
+ });
+
+ handle.assert_finished();
+}
+
+#[instrument(err(Debug))]
+fn err_dbg() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_err_dbg() {
+ let span = span::mock().named("err_dbg");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock().at_level(Level::ERROR).with_fields(
+ field::mock("error")
+ // use the actual error value that will be emitted, so
+ // that this test doesn't break if the standard library
+ // changes the `fmt::Debug` output from the error type
+ // in the future.
+ .with_value(&tracing::field::debug(u8::try_from(1234).unwrap_err())),
+ ),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_dbg().ok());
+ handle.assert_finished();
+}
+
+#[test]
+fn test_err_display_default() {
+ let span = span::mock().named("err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock().at_level(Level::ERROR).with_fields(
+ field::mock("error")
+ // by default, errors will be emitted with their display values
+ .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err())),
+ ),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err().ok());
+ handle.assert_finished();
+}
+
+#[test]
+fn test_err_custom_target() {
+ let filter: EnvFilter = "my_target=error".parse().expect("filter should parse");
+ let span = span::mock().named("error_span").with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .at_level(Level::ERROR)
+ .with_target("my_target"),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ let subscriber = subscriber.with(filter);
+
+ with_default(subscriber, || {
+ let error_span = tracing::error_span!(target: "my_target", "error_span");
+
+ {
+ let _enter = error_span.enter();
+ tracing::error!(target: "my_target", "This should display")
+ }
+ });
+ handle.assert_finished();
+}
+
+#[instrument(err(level = "info"))]
+fn err_info() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_err_info() {
+ let span = span::mock().named("err_info");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::INFO))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_info().ok());
+ handle.assert_finished();
+}
+
+#[instrument(err(Debug, level = "info"))]
+fn err_dbg_info() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_err_dbg_info() {
+ let span = span::mock().named("err_dbg_info");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock().at_level(Level::INFO).with_fields(
+ field::mock("error")
+ // use the actual error value that will be emitted, so
+ // that this test doesn't break if the standard library
+ // changes the `fmt::Debug` output from the error type
+ // in the future.
+ .with_value(&tracing::field::debug(u8::try_from(1234).unwrap_err())),
+ ),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_dbg_info().ok());
+ handle.assert_finished();
+}
+
+#[instrument(level = "warn", err(level = "info"))]
+fn err_warn_info() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_err_warn_info() {
+ let span = span::mock().named("err_warn_info").at_level(Level::WARN);
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::INFO))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_warn_info().ok());
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/fields.rs b/third_party/rust/tracing-attributes/tests/fields.rs
new file mode 100644
index 0000000000..c178fbb3d3
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/fields.rs
@@ -0,0 +1,160 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::field::mock;
+use tracing_mock::span::NewSpan;
+use tracing_mock::*;
+
+#[instrument(fields(foo = "bar", dsa = true, num = 1))]
+fn fn_no_param() {}
+
+#[instrument(fields(foo = "bar"))]
+fn fn_param(param: u32) {}
+
+#[instrument(fields(foo = "bar", empty))]
+fn fn_empty_field() {}
+
+#[instrument(fields(len = s.len()))]
+fn fn_expr_field(s: &str) {}
+
+#[instrument(fields(s.len = s.len(), s.is_empty = s.is_empty()))]
+fn fn_two_expr_fields(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(%s, s.len = s.len()))]
+fn fn_clashy_expr_field(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(s = "s"))]
+fn fn_clashy_expr_field2(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(s = &s))]
+fn fn_string(s: String) {
+ let _ = s;
+}
+
+#[derive(Debug)]
+struct HasField {
+ my_field: &'static str,
+}
+
+impl HasField {
+ #[instrument(fields(my_field = self.my_field), skip(self))]
+ fn self_expr_field(&self) {}
+}
+
+#[test]
+fn fields() {
+ let span = span::mock().with_field(
+ mock("foo")
+ .with_value(&"bar")
+ .and(mock("dsa").with_value(&true))
+ .and(mock("num").with_value(&1))
+ .only(),
+ );
+ run_test(span, || {
+ fn_no_param();
+ });
+}
+
+#[test]
+fn expr_field() {
+ let span = span::mock().with_field(
+ mock("s")
+ .with_value(&"hello world")
+ .and(mock("len").with_value(&"hello world".len()))
+ .only(),
+ );
+ run_test(span, || {
+ fn_expr_field("hello world");
+ });
+}
+
+#[test]
+fn two_expr_fields() {
+ let span = span::mock().with_field(
+ mock("s")
+ .with_value(&"hello world")
+ .and(mock("s.len").with_value(&"hello world".len()))
+ .and(mock("s.is_empty").with_value(&false))
+ .only(),
+ );
+ run_test(span, || {
+ fn_two_expr_fields("hello world");
+ });
+}
+
+#[test]
+fn clashy_expr_field() {
+ let span = span::mock().with_field(
+ // Overriding the `s` field should record `s` as a `Display` value,
+ // rather than as a `Debug` value.
+ mock("s")
+ .with_value(&tracing::field::display("hello world"))
+ .and(mock("s.len").with_value(&"hello world".len()))
+ .only(),
+ );
+ run_test(span, || {
+ fn_clashy_expr_field("hello world");
+ });
+
+ let span = span::mock().with_field(mock("s").with_value(&"s").only());
+ run_test(span, || {
+ fn_clashy_expr_field2("hello world");
+ });
+}
+
+#[test]
+fn self_expr_field() {
+ let span = span::mock().with_field(mock("my_field").with_value(&"hello world").only());
+ run_test(span, || {
+ let has_field = HasField {
+ my_field: "hello world",
+ };
+ has_field.self_expr_field();
+ });
+}
+
+#[test]
+fn parameters_with_fields() {
+ let span = span::mock().with_field(
+ mock("foo")
+ .with_value(&"bar")
+ .and(mock("param").with_value(&1u32))
+ .only(),
+ );
+ run_test(span, || {
+ fn_param(1);
+ });
+}
+
+#[test]
+fn empty_field() {
+ let span = span::mock().with_field(mock("foo").with_value(&"bar").only());
+ run_test(span, || {
+ fn_empty_field();
+ });
+}
+
+#[test]
+fn string_field() {
+ let span = span::mock().with_field(mock("s").with_value(&"hello world").only());
+ run_test(span, || {
+ fn_string(String::from("hello world"));
+ });
+}
+
+fn run_test<F: FnOnce() -> T, T>(span: NewSpan, fun: F) {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span)
+ .enter(span::mock())
+ .exit(span::mock())
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, fun);
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/follows_from.rs b/third_party/rust/tracing-attributes/tests/follows_from.rs
new file mode 100644
index 0000000000..a589409ded
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/follows_from.rs
@@ -0,0 +1,101 @@
+use tracing::{subscriber::with_default, Id, Level, Span};
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument(follows_from = causes, skip(causes))]
+fn with_follows_from_sync(causes: impl IntoIterator<Item = impl Into<Option<Id>>>) {}
+
+#[instrument(follows_from = causes, skip(causes))]
+async fn with_follows_from_async(causes: impl IntoIterator<Item = impl Into<Option<Id>>>) {}
+
+#[instrument(follows_from = [&Span::current()])]
+fn follows_from_current() {}
+
+#[test]
+fn follows_from_sync_test() {
+ let cause_a = span::mock().named("cause_a");
+ let cause_b = span::mock().named("cause_b");
+ let cause_c = span::mock().named("cause_c");
+ let consequence = span::mock().named("with_follows_from_sync");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause_a.clone())
+ .new_span(cause_b.clone())
+ .new_span(cause_c.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause_a)
+ .follows_from(consequence.clone(), cause_b)
+ .follows_from(consequence.clone(), cause_c)
+ .enter(consequence.clone())
+ .exit(consequence)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let cause_a = tracing::span!(Level::TRACE, "cause_a");
+ let cause_b = tracing::span!(Level::TRACE, "cause_b");
+ let cause_c = tracing::span!(Level::TRACE, "cause_c");
+
+ with_follows_from_sync(&[cause_a, cause_b, cause_c])
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn follows_from_async_test() {
+ let cause_a = span::mock().named("cause_a");
+ let cause_b = span::mock().named("cause_b");
+ let cause_c = span::mock().named("cause_c");
+ let consequence = span::mock().named("with_follows_from_async");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause_a.clone())
+ .new_span(cause_b.clone())
+ .new_span(cause_c.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause_a)
+ .follows_from(consequence.clone(), cause_b)
+ .follows_from(consequence.clone(), cause_c)
+ .enter(consequence.clone())
+ .exit(consequence.clone())
+ .enter(consequence.clone())
+ .exit(consequence)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ let cause_a = tracing::span!(Level::TRACE, "cause_a");
+ let cause_b = tracing::span!(Level::TRACE, "cause_b");
+ let cause_c = tracing::span!(Level::TRACE, "cause_c");
+
+ with_follows_from_async(&[cause_a, cause_b, cause_c]).await
+ })
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn follows_from_current_test() {
+ let cause = span::mock().named("cause");
+ let consequence = span::mock().named("follows_from_current");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause.clone())
+ .enter(cause.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause.clone())
+ .enter(consequence.clone())
+ .exit(consequence)
+ .exit(cause)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "cause").in_scope(follows_from_current)
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/instrument.rs b/third_party/rust/tracing-attributes/tests/instrument.rs
new file mode 100644
index 0000000000..b215b8455d
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/instrument.rs
@@ -0,0 +1,252 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+// Reproduces a compile error when an instrumented function body contains inner
+// attributes (https://github.com/tokio-rs/tracing/issues/2294).
+#[deny(unused_variables)]
+#[instrument]
+fn repro_2294() {
+ #![allow(unused_variables)]
+ let i = 42;
+}
+
+#[test]
+fn override_everything() {
+ #[instrument(target = "my_target", level = "debug")]
+ fn my_fn() {}
+
+ #[instrument(level = Level::DEBUG, target = "my_target")]
+ fn my_other_fn() {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let span2 = span::mock()
+ .named("my_other_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(span2.clone())
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn();
+ my_other_fn();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn fields() {
+ #[instrument(target = "my_target", level = "debug")]
+ fn my_fn(arg1: usize, arg2: bool) {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span2 = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&2usize)
+ .and(field::mock("arg2").with_value(&false))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(
+ span2.clone().with_field(
+ field::mock("arg1")
+ .with_value(&3usize)
+ .and(field::mock("arg2").with_value(&true))
+ .only(),
+ ),
+ )
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(2, false);
+ my_fn(3, true);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn skip() {
+ struct UnDebug(pub u32);
+
+ #[instrument(target = "my_target", level = "debug", skip(_arg2, _arg3))]
+ fn my_fn(arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
+
+ #[instrument(target = "my_target", level = "debug", skip_all)]
+ fn my_fn2(_arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span2 = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span3 = span::mock()
+ .named("my_fn2")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("arg1").with_value(&2usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(
+ span2
+ .clone()
+ .with_field(field::mock("arg1").with_value(&3usize).only()),
+ )
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .new_span(span3.clone())
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .drop_span(span3)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(2, UnDebug(0), UnDebug(1));
+ my_fn(3, UnDebug(0), UnDebug(1));
+ my_fn2(2, UnDebug(0), UnDebug(1));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn generics() {
+ #[derive(Debug)]
+ struct Foo;
+
+ #[instrument]
+ fn my_fn<S, T: std::fmt::Debug>(arg1: S, arg2: T)
+ where
+ S: std::fmt::Debug,
+ {
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("Foo"))
+ .and(field::mock("arg2").with_value(&format_args!("false"))),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo, false);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn methods() {
+ #[derive(Debug)]
+ struct Foo;
+
+ impl Foo {
+ #[instrument]
+ fn my_fn(&self, arg1: usize) {}
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("self")
+ .with_value(&format_args!("Foo"))
+ .and(field::mock("arg1").with_value(&42usize)),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = Foo;
+ foo.my_fn(42);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn impl_trait_return_type() {
+ #[instrument]
+ fn returns_impl_trait(x: usize) -> impl Iterator<Item = usize> {
+ 0..x
+ }
+
+ let span = span::mock().named("returns_impl_trait");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("x").with_value(&10usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ for _ in returns_impl_trait(10) {
+ // nop
+ }
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/levels.rs b/third_party/rust/tracing-attributes/tests/levels.rs
new file mode 100644
index 0000000000..94fc7e85a2
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/levels.rs
@@ -0,0 +1,142 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[test]
+fn named_levels() {
+ #[instrument(level = "trace")]
+ fn trace() {}
+
+ #[instrument(level = "Debug")]
+ fn debug() {}
+
+ #[instrument(level = "INFO")]
+ fn info() {}
+
+ #[instrument(level = "WARn")]
+ fn warn() {}
+
+ #[instrument(level = "eRrOr")]
+ fn error() {}
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("trace").at_level(Level::TRACE))
+ .enter(span::mock().named("trace").at_level(Level::TRACE))
+ .exit(span::mock().named("trace").at_level(Level::TRACE))
+ .new_span(span::mock().named("debug").at_level(Level::DEBUG))
+ .enter(span::mock().named("debug").at_level(Level::DEBUG))
+ .exit(span::mock().named("debug").at_level(Level::DEBUG))
+ .new_span(span::mock().named("info").at_level(Level::INFO))
+ .enter(span::mock().named("info").at_level(Level::INFO))
+ .exit(span::mock().named("info").at_level(Level::INFO))
+ .new_span(span::mock().named("warn").at_level(Level::WARN))
+ .enter(span::mock().named("warn").at_level(Level::WARN))
+ .exit(span::mock().named("warn").at_level(Level::WARN))
+ .new_span(span::mock().named("error").at_level(Level::ERROR))
+ .enter(span::mock().named("error").at_level(Level::ERROR))
+ .exit(span::mock().named("error").at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ trace();
+ debug();
+ info();
+ warn();
+ error();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn numeric_levels() {
+ #[instrument(level = 1)]
+ fn trace() {}
+
+ #[instrument(level = 2)]
+ fn debug() {}
+
+ #[instrument(level = 3)]
+ fn info() {}
+
+ #[instrument(level = 4)]
+ fn warn() {}
+
+ #[instrument(level = 5)]
+ fn error() {}
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("trace").at_level(Level::TRACE))
+ .enter(span::mock().named("trace").at_level(Level::TRACE))
+ .exit(span::mock().named("trace").at_level(Level::TRACE))
+ .new_span(span::mock().named("debug").at_level(Level::DEBUG))
+ .enter(span::mock().named("debug").at_level(Level::DEBUG))
+ .exit(span::mock().named("debug").at_level(Level::DEBUG))
+ .new_span(span::mock().named("info").at_level(Level::INFO))
+ .enter(span::mock().named("info").at_level(Level::INFO))
+ .exit(span::mock().named("info").at_level(Level::INFO))
+ .new_span(span::mock().named("warn").at_level(Level::WARN))
+ .enter(span::mock().named("warn").at_level(Level::WARN))
+ .exit(span::mock().named("warn").at_level(Level::WARN))
+ .new_span(span::mock().named("error").at_level(Level::ERROR))
+ .enter(span::mock().named("error").at_level(Level::ERROR))
+ .exit(span::mock().named("error").at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ trace();
+ debug();
+ info();
+ warn();
+ error();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn enum_levels() {
+ #[instrument(level = Level::TRACE)]
+ fn trace() {}
+
+ #[instrument(level = Level::DEBUG)]
+ fn debug() {}
+
+ #[instrument(level = tracing::Level::INFO)]
+ fn info() {}
+
+ #[instrument(level = Level::WARN)]
+ fn warn() {}
+
+ #[instrument(level = Level::ERROR)]
+ fn error() {}
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("trace").at_level(Level::TRACE))
+ .enter(span::mock().named("trace").at_level(Level::TRACE))
+ .exit(span::mock().named("trace").at_level(Level::TRACE))
+ .new_span(span::mock().named("debug").at_level(Level::DEBUG))
+ .enter(span::mock().named("debug").at_level(Level::DEBUG))
+ .exit(span::mock().named("debug").at_level(Level::DEBUG))
+ .new_span(span::mock().named("info").at_level(Level::INFO))
+ .enter(span::mock().named("info").at_level(Level::INFO))
+ .exit(span::mock().named("info").at_level(Level::INFO))
+ .new_span(span::mock().named("warn").at_level(Level::WARN))
+ .enter(span::mock().named("warn").at_level(Level::WARN))
+ .exit(span::mock().named("warn").at_level(Level::WARN))
+ .new_span(span::mock().named("error").at_level(Level::ERROR))
+ .enter(span::mock().named("error").at_level(Level::ERROR))
+ .exit(span::mock().named("error").at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ trace();
+ debug();
+ info();
+ warn();
+ error();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/names.rs b/third_party/rust/tracing-attributes/tests/names.rs
new file mode 100644
index 0000000000..d97dece9a1
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/names.rs
@@ -0,0 +1,63 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn default_name() {}
+
+#[instrument(name = "my_name")]
+fn custom_name() {}
+
+// XXX: it's weird that we support both of these forms, but apparently we
+// managed to release a version that accepts both syntax, so now we have to
+// support it! yay!
+#[instrument("my_other_name")]
+fn custom_name_no_equals() {}
+
+#[test]
+fn default_name_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("default_name"))
+ .enter(span::mock().named("default_name"))
+ .exit(span::mock().named("default_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ default_name();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_name_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("my_name"))
+ .enter(span::mock().named("my_name"))
+ .exit(span::mock().named("my_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_name();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_name_no_equals_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("my_other_name"))
+ .enter(span::mock().named("my_other_name"))
+ .exit(span::mock().named("my_other_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_name_no_equals();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/parents.rs b/third_party/rust/tracing-attributes/tests/parents.rs
new file mode 100644
index 0000000000..7069b98ea5
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/parents.rs
@@ -0,0 +1,102 @@
+use tracing::{subscriber::with_default, Id, Level};
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn with_default_parent() {}
+
+#[instrument(parent = parent_span, skip(parent_span))]
+fn with_explicit_parent<P>(parent_span: P)
+where
+ P: Into<Option<Id>>,
+{
+}
+
+#[test]
+fn default_parent_test() {
+ let contextual_parent = span::mock().named("contextual_parent");
+ let child = span::mock().named("with_default_parent");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ contextual_parent
+ .clone()
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(None),
+ )
+ .enter(child.clone())
+ .exit(child.clone())
+ .enter(contextual_parent.clone())
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(None),
+ )
+ .enter(child.clone())
+ .exit(child)
+ .exit(contextual_parent)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let contextual_parent = tracing::span!(Level::TRACE, "contextual_parent");
+
+ with_default_parent();
+
+ contextual_parent.in_scope(|| {
+ with_default_parent();
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn explicit_parent_test() {
+ let contextual_parent = span::mock().named("contextual_parent");
+ let explicit_parent = span::mock().named("explicit_parent");
+ let child = span::mock().named("with_explicit_parent");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ contextual_parent
+ .clone()
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .new_span(
+ explicit_parent
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .enter(contextual_parent.clone())
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(Some("explicit_parent")),
+ )
+ .enter(child.clone())
+ .exit(child)
+ .exit(contextual_parent)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let contextual_parent = tracing::span!(Level::INFO, "contextual_parent");
+ let explicit_parent = tracing::span!(Level::INFO, "explicit_parent");
+
+ contextual_parent.in_scope(|| {
+ with_explicit_parent(&explicit_parent);
+ });
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/ret.rs b/third_party/rust/tracing-attributes/tests/ret.rs
new file mode 100644
index 0000000000..f56c80baaf
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ret.rs
@@ -0,0 +1,307 @@
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
+use tracing_mock::*;
+
+use tracing::{subscriber::with_default, Level};
+use tracing_attributes::instrument;
+use tracing_subscriber::layer::SubscriberExt;
+use tracing_subscriber::EnvFilter;
+
+#[instrument(ret)]
+fn ret() -> i32 {
+ 42
+}
+
+#[instrument(target = "my_target", ret)]
+fn ret_with_target() -> i32 {
+ 42
+}
+
+#[test]
+fn test() {
+ let span = span::mock().named("ret");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret);
+ handle.assert_finished();
+}
+
+#[test]
+fn test_custom_target() {
+ let filter: EnvFilter = "my_target=info".parse().expect("filter should parse");
+ let span = span::mock()
+ .named("ret_with_target")
+ .with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO)
+ .with_target("my_target"),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ let subscriber = subscriber.with(filter);
+
+ with_default(subscriber, ret_with_target);
+ handle.assert_finished();
+}
+
+#[instrument(level = "warn", ret)]
+fn ret_warn() -> i32 {
+ 42
+}
+
+#[test]
+fn test_warn() {
+ let span = span::mock().named("ret_warn");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::WARN),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_warn);
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+fn ret_mut(a: &mut i32) -> i32 {
+ *a *= 2;
+ tracing::info!(?a);
+ *a
+}
+
+#[test]
+fn test_mut() {
+ let span = span::mock().named("ret_mut");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("a").with_value(&tracing::field::display(2)))
+ .at_level(Level::INFO),
+ )
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(2)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_mut(&mut 1));
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+async fn ret_async() -> i32 {
+ 42
+}
+
+#[test]
+fn test_async() {
+ let span = span::mock().named("ret_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || block_on_future(async { ret_async().await }));
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+fn ret_impl_type() -> impl Copy {
+ 42
+}
+
+#[test]
+fn test_impl_type() {
+ let span = span::mock().named("ret_impl_type");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_impl_type);
+ handle.assert_finished();
+}
+
+#[instrument(ret(Display))]
+fn ret_display() -> i32 {
+ 42
+}
+
+#[test]
+fn test_dbg() {
+ let span = span::mock().named("ret_display");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::display(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_display);
+ handle.assert_finished();
+}
+
+#[instrument(err, ret)]
+fn ret_and_err() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_ret_and_err() {
+ let span = span::mock().named("ret_and_err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(
+ field::mock("error")
+ .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err()))
+ .only(),
+ )
+ .at_level(Level::ERROR),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_and_err().ok());
+ handle.assert_finished();
+}
+
+#[instrument(err, ret)]
+fn ret_and_ok() -> Result<u8, TryFromIntError> {
+ u8::try_from(123)
+}
+
+#[test]
+fn test_ret_and_ok() {
+ let span = span::mock().named("ret_and_ok");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(
+ field::mock("return")
+ .with_value(&tracing::field::debug(u8::try_from(123).unwrap()))
+ .only(),
+ )
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_and_ok().ok());
+ handle.assert_finished();
+}
+
+#[instrument(level = "warn", ret(level = "info"))]
+fn ret_warn_info() -> i32 {
+ 42
+}
+
+#[test]
+fn test_warn_info() {
+ let span = span::mock().named("ret_warn_info").at_level(Level::WARN);
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_warn_info);
+ handle.assert_finished();
+}
+
+#[instrument(ret(level = "warn", Debug))]
+fn ret_dbg_warn() -> i32 {
+ 42
+}
+
+#[test]
+fn test_dbg_warn() {
+ let span = span::mock().named("ret_dbg_warn").at_level(Level::INFO);
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::WARN),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_dbg_warn);
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/targets.rs b/third_party/rust/tracing-attributes/tests/targets.rs
new file mode 100644
index 0000000000..363f628f31
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/targets.rs
@@ -0,0 +1,97 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn default_target() {}
+
+#[instrument(target = "my_target")]
+fn custom_target() {}
+
+mod my_mod {
+ use tracing_attributes::instrument;
+
+ pub const MODULE_PATH: &str = module_path!();
+
+ #[instrument]
+ pub fn default_target() {}
+
+ #[instrument(target = "my_other_target")]
+ pub fn custom_target() {}
+}
+
+#[test]
+fn default_targets() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .enter(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .exit(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .new_span(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .enter(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .exit(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ default_target();
+ my_mod::default_target();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_targets() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("custom_target").with_target("my_target"))
+ .enter(span::mock().named("custom_target").with_target("my_target"))
+ .exit(span::mock().named("custom_target").with_target("my_target"))
+ .new_span(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .enter(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .exit(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_target();
+ my_mod::custom_target();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/ui.rs b/third_party/rust/tracing-attributes/tests/ui.rs
new file mode 100644
index 0000000000..73d7fdcef8
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui.rs
@@ -0,0 +1,14 @@
+// Only test on nightly, since UI tests are bound to change over time
+#[rustversion::stable]
+#[test]
+fn async_instrument() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/async_instrument.rs");
+}
+
+#[rustversion::stable]
+#[test]
+fn const_instrument() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/const_instrument.rs");
+}
diff --git a/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs b/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs
new file mode 100644
index 0000000000..5b245746a6
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs
@@ -0,0 +1,46 @@
+#![allow(unreachable_code)]
+
+#[tracing::instrument]
+async fn unit() {
+ ""
+}
+
+#[tracing::instrument]
+async fn simple_mismatch() -> String {
+ ""
+}
+
+// FIXME: this span is still pretty poor
+#[tracing::instrument]
+async fn opaque_unsatisfied() -> impl std::fmt::Display {
+ ("",)
+}
+
+struct Wrapper<T>(T);
+
+#[tracing::instrument]
+async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
+ ""
+}
+
+#[tracing::instrument]
+async fn early_return_unit() {
+ if true {
+ return "";
+ }
+}
+
+#[tracing::instrument]
+async fn early_return() -> String {
+ if true {
+ return "";
+ }
+ String::new()
+}
+
+#[tracing::instrument]
+async fn extra_semicolon() -> i32 {
+ 1;
+}
+
+fn main() {}
diff --git a/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr b/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr
new file mode 100644
index 0000000000..2c64b0c15e
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr
@@ -0,0 +1,98 @@
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:5:5
+ |
+5 | ""
+ | ^^ expected `()`, found `&str`
+ |
+note: return type inferred to be `()` here
+ --> tests/ui/async_instrument.rs:4:10
+ |
+4 | async fn unit() {
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:10:5
+ |
+10 | ""
+ | ^^- help: try using a conversion method: `.to_string()`
+ | |
+ | expected `String`, found `&str`
+ |
+note: return type inferred to be `String` here
+ --> tests/ui/async_instrument.rs:9:31
+ |
+9 | async fn simple_mismatch() -> String {
+ | ^^^^^^
+
+error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
+ --> tests/ui/async_instrument.rs:14:1
+ |
+14 | #[tracing::instrument]
+ | ^^^^^^^^^^^^^^^^^^^^^^ `(&str,)` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `(&str,)`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
+ --> tests/ui/async_instrument.rs:15:34
+ |
+15 | async fn opaque_unsatisfied() -> impl std::fmt::Display {
+ | ^^^^^^^^^^^^^^^^^^^^^^ `(&str,)` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `(&str,)`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:23:5
+ |
+23 | ""
+ | ^^ expected `Wrapper<_>`, found `&str`
+ |
+ = note: expected struct `Wrapper<_>`
+ found reference `&'static str`
+note: return type inferred to be `Wrapper<_>` here
+ --> tests/ui/async_instrument.rs:22:36
+ |
+22 | async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
+ | ^^^^^^^
+help: try wrapping the expression in `Wrapper`
+ |
+23 | Wrapper("")
+ | ++++++++ +
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:29:16
+ |
+29 | return "";
+ | ^^ expected `()`, found `&str`
+ |
+note: return type inferred to be `()` here
+ --> tests/ui/async_instrument.rs:27:10
+ |
+27 | async fn early_return_unit() {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:36:16
+ |
+36 | return "";
+ | ^^- help: try using a conversion method: `.to_string()`
+ | |
+ | expected `String`, found `&str`
+ |
+note: return type inferred to be `String` here
+ --> tests/ui/async_instrument.rs:34:28
+ |
+34 | async fn early_return() -> String {
+ | ^^^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:42:35
+ |
+42 | async fn extra_semicolon() -> i32 {
+ | ___________________________________^
+43 | | 1;
+ | | - help: remove this semicolon to return this value
+44 | | }
+ | |_^ expected `i32`, found `()`
diff --git a/third_party/rust/tracing-attributes/tests/ui/const_instrument.rs b/third_party/rust/tracing-attributes/tests/ui/const_instrument.rs
new file mode 100644
index 0000000000..a251e8f66b
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/const_instrument.rs
@@ -0,0 +1,8 @@
+#![allow(unreachable_code)]
+
+#[tracing::instrument]
+const fn unit() {
+ ""
+}
+
+fn main() {}
diff --git a/third_party/rust/tracing-attributes/tests/ui/const_instrument.stderr b/third_party/rust/tracing-attributes/tests/ui/const_instrument.stderr
new file mode 100644
index 0000000000..e76d4acad9
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/const_instrument.stderr
@@ -0,0 +1,15 @@
+error: macros that expand to items must be delimited with braces or followed by a semicolon
+ --> tests/ui/const_instrument.rs:3:1
+ |
+3 | #[tracing::instrument]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `#[instrument]` attribute may not be used with `const fn`s
+ --> tests/ui/const_instrument.rs:3:1
+ |
+3 | #[tracing::instrument]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)