tracing_attributes/lib.rs
1//! A procedural macro attribute for instrumenting functions with [`tracing`].
2//!
3//! [`tracing`] is a framework for instrumenting Rust programs to collect
4//! structured, event-based diagnostic information. This crate provides the
5//! [`#[instrument]`][instrument] procedural macro attribute.
6//!
7//! Note that this macro is also re-exported by the main `tracing` crate.
8//!
9//! *Compiler support: [requires `rustc` 1.65+][msrv]*
10//!
11//! [msrv]: #supported-rust-versions
12//!
13//! ## Usage
14//!
15//! In the `Cargo.toml`:
16//!
17//! ```toml
18//! [dependencies]
19//! tracing-attributes = "0.1.24"
20//! ```
21//!
22//! The [`#[instrument]`][instrument] attribute can now be added to a function
23//! to automatically create and enter `tracing` [span] when that function is
24//! called. For example:
25//!
26//! ```
27//! use tracing::instrument;
28//!
29//! #[instrument]
30//! pub fn my_function(my_arg: usize) {
31//! // ...
32//! }
33//!
34//! # fn main() {}
35//! ```
36//!
37//! [`tracing`]: https://crates.io/crates/tracing
38//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39//! [instrument]: macro@self::instrument
40//!
41//! ## Supported Rust Versions
42//!
43//! Tracing is built against the latest stable release. The minimum supported
44//! version is 1.65. The current Tracing version is not guaranteed to build on
45//! Rust versions earlier than the minimum supported version.
46//!
47//! Tracing follows the same compiler support policies as the rest of the Tokio
48//! project. The current stable Rust compiler and the three most recent minor
49//! versions before it will always be supported. For example, if the current
50//! stable compiler version is 1.69, the minimum supported version will not be
51//! increased past 1.66, three minor versions prior. Increasing the minimum
52//! supported compiler version is not considered a semver breaking change as
53//! long as doing so complies with this policy.
54//!
55#![doc(
56 html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/logo-type.png",
57 html_favicon_url = "https://raw.githubusercontent.com/tokio-rs/tracing/main/assets/favicon.ico",
58 issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
59)]
60#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
61#![warn(
62 missing_debug_implementations,
63 missing_docs,
64 rust_2018_idioms,
65 unreachable_pub,
66 bad_style,
67 dead_code,
68 improper_ctypes,
69 non_shorthand_field_patterns,
70 no_mangle_generic_items,
71 overflowing_literals,
72 path_statements,
73 patterns_in_fns_without_body,
74 private_interfaces,
75 private_bounds,
76 unconditional_recursion,
77 unused_allocation,
78 unused_comparisons,
79 unused_parens,
80 while_true
81)]
82
83use proc_macro2::TokenStream;
84use quote::TokenStreamExt;
85use quote::{quote, ToTokens};
86use syn::parse::{Parse, ParseStream};
87use syn::token::Brace;
88use syn::{Attribute, ItemFn, Signature, Visibility};
89
90mod attr;
91mod expand;
92/// Instruments a function to create and enter a `tracing` [span] every time
93/// the function is called.
94///
95/// Unless overridden, a span with the [`INFO`] [level] will be generated.
96/// The generated span's name will be the name of the function.
97/// By default, all arguments to the function are included as fields on the
98/// span. Arguments that are `tracing` [primitive types] implementing the
99/// [`Value` trait] will be recorded as fields of that type. Types which do
100/// not implement `Value` will be recorded using [`fmt::Debug`].
101///
102/// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
103/// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html
104///
105/// # Overriding Span Attributes
106///
107/// To change the [name] of the generated span, add a `name` argument to the
108/// `#[instrument]` macro, followed by an equals sign and a string literal. For
109/// example:
110///
111/// ```
112/// # use tracing_attributes::instrument;
113///
114/// // The generated span's name will be "my_span" rather than "my_function".
115/// #[instrument(name = "my_span")]
116/// pub fn my_function() {
117/// // ... do something incredibly interesting and important ...
118/// }
119/// ```
120///
121/// To override the [target] of the generated span, add a `target` argument to
122/// the `#[instrument]` macro, followed by an equals sign and a string literal
123/// for the new target. The [module path] is still recorded separately. For
124/// example:
125///
126/// ```
127/// pub mod my_module {
128/// # use tracing_attributes::instrument;
129/// // The generated span's target will be "my_crate::some_special_target",
130/// // rather than "my_crate::my_module".
131/// #[instrument(target = "my_crate::some_special_target")]
132/// pub fn my_function() {
133/// // ... all kinds of neat code in here ...
134/// }
135/// }
136/// ```
137///
138/// Finally, to override the [level] of the generated span, add a `level`
139/// argument, followed by an equals sign and a string literal with the name of
140/// the desired level. Level names are not case sensitive. For example:
141///
142/// ```
143/// # use tracing_attributes::instrument;
144/// // The span's level will be TRACE rather than INFO.
145/// #[instrument(level = "trace")]
146/// pub fn my_function() {
147/// // ... I have written a truly marvelous implementation of this function,
148/// // which this example is too narrow to contain ...
149/// }
150/// ```
151///
152/// # Skipping Fields
153///
154/// To skip recording one or more arguments to a function or method, pass
155/// the argument's name inside the `skip()` argument on the `#[instrument]`
156/// macro. This can be used when an argument to an instrumented function does
157/// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
158/// costly `Debug` implementation. Note that:
159///
160/// - multiple argument names can be passed to `skip`.
161/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
162///
163/// You can also use `skip_all` to skip all arguments.
164///
165/// ## Examples
166///
167/// ```
168/// # use tracing_attributes::instrument;
169/// # use std::collections::HashMap;
170/// // This type doesn't implement `fmt::Debug`!
171/// struct NonDebug;
172///
173/// // `arg` will be recorded, while `non_debug` will not.
174/// #[instrument(skip(non_debug))]
175/// fn my_function(arg: usize, non_debug: NonDebug) {
176/// // ...
177/// }
178///
179/// // These arguments are huge
180/// #[instrument(skip_all)]
181/// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
182/// // ...
183/// }
184/// ```
185///
186/// Skipping the `self` parameter:
187///
188/// ```
189/// # use tracing_attributes::instrument;
190/// #[derive(Debug)]
191/// struct MyType {
192/// data: Vec<u8>, // Suppose this buffer is often quite long...
193/// }
194///
195/// impl MyType {
196/// // Suppose we don't want to print an entire kilobyte of `data`
197/// // every time this is called...
198/// #[instrument(skip(self))]
199/// pub fn my_method(&mut self, an_interesting_argument: usize) {
200/// // ... do something (hopefully, using all that `data`!)
201/// }
202/// }
203/// ```
204///
205/// # Adding Fields
206///
207/// Additional fields (key-value pairs with arbitrary data) can be passed
208/// to the generated span through the `fields` argument on the
209/// `#[instrument]` macro. Arbitrary expressions are accepted as value
210/// for each field. The name of the field must be a single valid Rust
211/// identifier, or a constant expression that evaluates to one, enclosed in curly
212/// braces. Note that nested (dotted) field names are also supported. Any
213/// Rust expression can be used as a field value in this manner. These
214/// expressions will be evaluated at the beginning of the function's body, so
215/// arguments to the function may be used in these expressions. Field names may
216/// also be specified *without* values. Doing so will result in an [empty field]
217/// whose value may be recorded later within the function body.
218///
219/// Note that defining a field with the same name as a (non-skipped)
220/// argument will implicitly skip the argument, unless the field is provided
221/// via a constant expression (e.g. {EXPR} or {const_fn()}) as deduplicating
222/// would incur a runtime cost. In this case, the
223/// field must be explicitly skipped.
224///
225/// ## Examples
226///
227/// Adding a new field based on the value of an argument:
228///
229/// ```
230/// # use tracing_attributes::instrument;
231///
232/// // This will record a field named "i" with the value of `i` *and* a field
233/// // named "next" with the value of `i` + 1.
234/// #[instrument(fields(next = i + 1))]
235/// pub fn my_function(i: usize) {
236/// // ...
237/// }
238/// ```
239///
240/// Recording specific properties of a struct as their own fields:
241///
242/// ```
243/// # mod http {
244/// # pub struct Error;
245/// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
246/// # pub struct Request<B> { _b: B }
247/// # impl<B> std::fmt::Debug for Request<B> {
248/// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249/// # f.pad("request")
250/// # }
251/// # }
252/// # impl<B> Request<B> {
253/// # pub fn uri(&self) -> &str { "fake" }
254/// # pub fn method(&self) -> &str { "GET" }
255/// # }
256/// # }
257/// # use tracing_attributes::instrument;
258///
259/// // This will record the request's URI and HTTP method as their own separate
260/// // fields.
261/// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
262/// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
263/// // ... handle the request ...
264/// # http::Response { _b: std::marker::PhantomData }
265/// }
266/// ```
267///
268/// This can be used in conjunction with `skip` or `skip_all` to record only
269/// some fields of a struct:
270/// ```
271/// # use tracing_attributes::instrument;
272/// // Remember the struct with the very large `data` field from the earlier
273/// // example? Now it also has a `name`, which we might want to include in
274/// // our span.
275/// #[derive(Debug)]
276/// struct MyType {
277/// name: &'static str,
278/// data: Vec<u8>,
279/// }
280///
281/// impl MyType {
282/// // This will skip the `data` field, but will include `self.name`,
283/// // formatted using `fmt::Display`.
284/// #[instrument(skip(self), fields(self.name = %self.name))]
285/// pub fn my_method(&mut self, an_interesting_argument: usize) {
286/// // ... do something (hopefully, using all that `data`!)
287/// }
288/// }
289/// ```
290///
291/// Adding an empty field to be recorded later:
292///
293/// ```
294/// # use tracing_attributes::instrument;
295///
296/// // This function does a very interesting and important mathematical calculation.
297/// // Suppose we want to record both the inputs to the calculation *and* its result...
298/// #[instrument(fields(result))]
299/// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
300/// // Rerform the calculation.
301/// let result = input_1 + input_2;
302///
303/// // Record the result as part of the current span.
304/// tracing::Span::current().record("result", &result);
305///
306/// // Now, the result will also be included on this event!
307/// tracing::info!("calculation complete!");
308///
309/// // ... etc ...
310/// # 0
311/// }
312/// ```
313///
314/// # Examples
315///
316/// Instrumenting a function:
317///
318/// ```
319/// # use tracing_attributes::instrument;
320/// #[instrument]
321/// pub fn my_function(my_arg: usize) {
322/// // This event will be recorded inside a span named `my_function` with the
323/// // field `my_arg`.
324/// tracing::info!("inside my_function!");
325/// // ...
326/// }
327/// ```
328/// Setting the level for the generated span:
329/// ```
330/// # use tracing_attributes::instrument;
331/// # use tracing::Level;
332/// #[instrument(level = Level::DEBUG)]
333/// pub fn my_function() {
334/// // ...
335/// }
336/// ```
337/// Levels can be specified either with [`Level`] constants, literal strings
338/// (e.g., `"debug"`, `"info"`) or numerically (1—5, corresponding to [`Level::TRACE`]—[`Level::ERROR`]).
339///
340/// Overriding the generated span's name:
341/// ```
342/// # use tracing_attributes::instrument;
343/// #[instrument(name = "my_name")]
344/// pub fn my_function() {
345/// // ...
346/// }
347/// ```
348/// Overriding the generated span's target:
349/// ```
350/// # use tracing_attributes::instrument;
351/// #[instrument(target = "my_target")]
352/// pub fn my_function() {
353/// // ...
354/// }
355/// ```
356/// Overriding the generated span's parent:
357/// ```
358/// # use tracing_attributes::instrument;
359/// #[instrument(parent = None)]
360/// pub fn my_function() {
361/// // ...
362/// }
363/// ```
364/// ```
365/// # use tracing_attributes::instrument;
366/// // A struct which owns a span handle.
367/// struct MyStruct
368/// {
369/// span: tracing::Span
370/// }
371///
372/// impl MyStruct
373/// {
374/// // Use the struct's `span` field as the parent span
375/// #[instrument(parent = &self.span, skip(self))]
376/// fn my_method(&self) {}
377/// }
378/// ```
379/// Specifying [`follows_from`] relationships:
380/// ```
381/// # use tracing_attributes::instrument;
382/// #[instrument(follows_from = causes)]
383/// pub fn my_function(causes: &[tracing::Id]) {
384/// // ...
385/// }
386/// ```
387/// Any expression of type `impl IntoIterator<Item = impl Into<Option<Id>>>`
388/// may be provided to `follows_from`; e.g.:
389/// ```
390/// # use tracing_attributes::instrument;
391/// #[instrument(follows_from = [cause])]
392/// pub fn my_function(cause: &tracing::span::EnteredSpan) {
393/// // ...
394/// }
395/// ```
396///
397///
398/// To skip recording an argument, pass the argument's name to the `skip`:
399///
400/// ```
401/// # use tracing_attributes::instrument;
402/// struct NonDebug;
403///
404/// #[instrument(skip(non_debug))]
405/// fn my_function(arg: usize, non_debug: NonDebug) {
406/// // ...
407/// }
408/// ```
409///
410/// To add additional context to the span, pass key-value pairs to `fields`:
411///
412/// ```
413/// # use tracing_attributes::instrument;
414/// #[derive(Debug)]
415/// struct Argument;
416/// impl Argument {
417/// fn bar(&self) -> &'static str {
418/// "bar"
419/// }
420/// }
421/// const FOOBAR: &'static str = "foo.bar";
422/// #[instrument(fields(foo="bar", id=1, show=true, {FOOBAR}=%arg.bar()))]
423/// fn my_function(arg: Argument) {
424/// // ...
425/// }
426/// ```
427///
428/// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
429/// return value when the function returns:
430///
431/// ```
432/// # use tracing_attributes::instrument;
433/// #[instrument(ret)]
434/// fn my_function() -> i32 {
435/// 42
436/// }
437/// ```
438/// The return value event will have the same level as the span generated by `#[instrument]`.
439/// By default, this will be [`INFO`], but if the level is overridden, the event will be at the same
440/// level.
441///
442/// It's also possible to override the level for the `ret` event independently:
443///
444/// ```
445/// # use tracing_attributes::instrument;
446/// # use tracing::Level;
447/// #[instrument(ret(level = Level::WARN))]
448/// fn my_function() -> i32 {
449/// 42
450/// }
451/// ```
452///
453/// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
454/// only if the function returns [`Result::Ok`].
455///
456/// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
457/// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
458/// implementation instead, by writing `ret(Display)`:
459///
460/// ```
461/// # use tracing_attributes::instrument;
462/// #[instrument(ret(Display))]
463/// fn my_function() -> i32 {
464/// 42
465/// }
466/// ```
467///
468/// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, adding
469/// `err` or `err(Display)` will emit error events when the function returns `Err`:
470///
471/// ```
472/// # use tracing_attributes::instrument;
473/// #[instrument(err)]
474/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
475/// Ok(())
476/// }
477/// ```
478///
479/// The level of the error value event defaults to `ERROR`.
480///
481/// Similarly, overriding the level of the `err` event :
482///
483/// ```
484/// # use tracing_attributes::instrument;
485/// # use tracing::Level;
486/// #[instrument(err(level = Level::INFO))]
487/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
488/// Ok(())
489/// }
490/// ```
491///
492/// By default, error values will be recorded using their `std::fmt::Display` implementations.
493/// If an error implements `std::fmt::Debug`, it can be recorded using its `Debug` implementation
494/// instead by writing `err(Debug)`:
495///
496/// ```
497/// # use tracing_attributes::instrument;
498/// #[instrument(err(Debug))]
499/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
500/// Ok(())
501/// }
502/// ```
503///
504/// If a `target` is specified, both the `ret` and `err` arguments will emit outputs to
505/// the declared target (or the default channel if `target` is not specified).
506///
507/// The `ret` and `err` arguments can be combined in order to record an event if a
508/// function returns [`Result::Ok`] or [`Result::Err`]:
509///
510/// ```
511/// # use tracing_attributes::instrument;
512/// #[instrument(err, ret)]
513/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
514/// Ok(())
515/// }
516/// ```
517///
518/// `async fn`s may also be instrumented:
519///
520/// ```
521/// # use tracing_attributes::instrument;
522/// #[instrument]
523/// pub async fn my_function() -> Result<(), ()> {
524/// // ...
525/// # Ok(())
526/// }
527/// ```
528///
529/// It also works with [async-trait](https://crates.io/crates/async-trait)
530/// (a crate that allows defining async functions in traits,
531/// something not currently possible in Rust),
532/// and hopefully most libraries that exhibit similar behaviors:
533///
534/// ```
535/// # use tracing::instrument;
536/// use async_trait::async_trait;
537///
538/// #[async_trait]
539/// pub trait Foo {
540/// async fn foo(&self, arg: usize);
541/// }
542///
543/// #[derive(Debug)]
544/// struct FooImpl(usize);
545///
546/// #[async_trait]
547/// impl Foo for FooImpl {
548/// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
549/// async fn foo(&self, arg: usize) {}
550/// }
551/// ```
552///
553/// `const fn` cannot be instrumented, and will result in a compilation failure:
554///
555/// ```compile_fail
556/// # use tracing_attributes::instrument;
557/// #[instrument]
558/// const fn my_const_function() {}
559/// ```
560///
561/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
562/// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
563/// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
564/// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
565/// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
566/// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
567/// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
568/// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
569/// [`follows_from`]: https://docs.rs/tracing/latest/tracing/struct.Span.html#method.follows_from
570/// [`tracing`]: https://github.com/tokio-rs/tracing
571/// [`fmt::Debug`]: std::fmt::Debug
572/// [`Level`]: https://docs.rs/tracing/latest/tracing/struct.Level.html
573/// [`Level::TRACE`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.TRACE
574/// [`Level::ERROR`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.ERROR
575#[proc_macro_attribute]
576pub fn instrument(
577 args: proc_macro::TokenStream,
578 item: proc_macro::TokenStream,
579) -> proc_macro::TokenStream {
580 let args = syn::parse_macro_input!(args as attr::InstrumentArgs);
581 // Cloning a `TokenStream` is cheap since it's reference counted internally.
582 instrument_precise(args.clone(), item.clone())
583 .unwrap_or_else(|_err| instrument_speculative(args, item))
584}
585
586/// Instrument the function, without parsing the function body (instead using the raw tokens).
587fn instrument_speculative(
588 args: attr::InstrumentArgs,
589 item: proc_macro::TokenStream,
590) -> proc_macro::TokenStream {
591 let input = syn::parse_macro_input!(item as MaybeItemFn);
592 let instrumented_function_name = input.sig.ident.to_string();
593 expand::gen_function(
594 input.as_ref(),
595 args,
596 instrumented_function_name.as_str(),
597 None,
598 )
599 .into()
600}
601
602/// Instrument the function, by fully parsing the function body,
603/// which allows us to rewrite some statements related to async-like patterns.
604fn instrument_precise(
605 args: attr::InstrumentArgs,
606 item: proc_macro::TokenStream,
607) -> Result<proc_macro::TokenStream, syn::Error> {
608 let input = syn::parse::<ItemFn>(item)?;
609 let instrumented_function_name = input.sig.ident.to_string();
610
611 if input.sig.constness.is_some() {
612 return Ok(quote! {
613 compile_error!("the `#[instrument]` attribute may not be used with `const fn`s")
614 }
615 .into());
616 }
617
618 // check for async_trait-like patterns in the block, and instrument
619 // the future instead of the wrapper
620 if let Some(async_like) = expand::AsyncInfo::from_fn(&input) {
621 return async_like.gen_async(args, instrumented_function_name.as_str());
622 }
623
624 let input = MaybeItemFn::from(input);
625
626 Ok(expand::gen_function(
627 input.as_ref(),
628 args,
629 instrumented_function_name.as_str(),
630 None,
631 )
632 .into())
633}
634
635/// This is a more flexible/imprecise `ItemFn` type,
636/// which's block is just a `TokenStream` (it may contain invalid code).
637#[derive(Debug, Clone)]
638struct MaybeItemFn {
639 outer_attrs: Vec<Attribute>,
640 inner_attrs: Vec<Attribute>,
641 vis: Visibility,
642 sig: Signature,
643 brace_token: Brace,
644 block: TokenStream,
645}
646
647impl MaybeItemFn {
648 fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> {
649 MaybeItemFnRef {
650 outer_attrs: &self.outer_attrs,
651 inner_attrs: &self.inner_attrs,
652 vis: &self.vis,
653 sig: &self.sig,
654 brace_token: &self.brace_token,
655 block: &self.block,
656 }
657 }
658}
659
660/// This parses a `TokenStream` into a `MaybeItemFn`
661/// (just like `ItemFn`, but skips parsing the body).
662impl Parse for MaybeItemFn {
663 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
664 let outer_attrs = input.call(Attribute::parse_outer)?;
665 let vis: Visibility = input.parse()?;
666 let sig: Signature = input.parse()?;
667 let inner_attrs = input.call(Attribute::parse_inner)?;
668 let block;
669 let brace_token = syn::braced!(block in input);
670 let block: TokenStream = block.call(|buffer| buffer.parse())?;
671 Ok(Self {
672 outer_attrs,
673 inner_attrs,
674 vis,
675 sig,
676 brace_token,
677 block,
678 })
679 }
680}
681
682impl From<ItemFn> for MaybeItemFn {
683 fn from(
684 ItemFn {
685 attrs,
686 vis,
687 sig,
688 block,
689 }: ItemFn,
690 ) -> Self {
691 let (outer_attrs, inner_attrs) = attrs
692 .into_iter()
693 .partition(|attr| attr.style == syn::AttrStyle::Outer);
694 let mut block_tokens = TokenStream::new();
695 block_tokens.append_all(block.stmts);
696 Self {
697 outer_attrs,
698 inner_attrs,
699 vis,
700 sig,
701 brace_token: block.brace_token,
702 block: block_tokens,
703 }
704 }
705}
706
707/// A generic reference type for `MaybeItemFn`,
708/// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
709#[derive(Debug, Clone)]
710struct MaybeItemFnRef<'a, B: ToTokens> {
711 outer_attrs: &'a Vec<Attribute>,
712 inner_attrs: &'a Vec<Attribute>,
713 vis: &'a Visibility,
714 sig: &'a Signature,
715 brace_token: &'a Brace,
716 block: &'a B,
717}