Skip to main content

no_panic/
lib.rs

1//! [![github]](https://github.com/dtolnay/no-panic) [![crates-io]](https://crates.io/crates/no-panic) [![docs-rs]](https://docs.rs/no-panic)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6//!
7//! <br>
8//!
9//! A Rust attribute macro to require that the compiler prove a function can't
10//! ever panic.
11//!
12//! ```toml
13//! [dependencies]
14//! no-panic = "0.1"
15//! ```
16//!
17//! ```
18//! use no_panic::no_panic;
19//!
20//! #[no_panic]
21//! fn demo(s: &str) -> &str {
22//!     &s[1..]
23//! }
24//!
25//! fn main() {
26//!     # fn demo(s: &str) -> &str {
27//!     #     &s[1..]
28//!     # }
29//!     #
30//!     println!("{}", demo("input string"));
31//! }
32//! ```
33//!
34//! If the function does panic (or the compiler fails to prove that the function
35//! cannot panic), the program fails to compile with a linker error that
36//! identifies the function name. Let's trigger that by passing a string that
37//! cannot be sliced at the first byte:
38//!
39//! ```should_panic
40//! # fn demo(s: &str) -> &str {
41//! #     &s[1..]
42//! # }
43//! #
44//! fn main() {
45//!     println!("{}", demo("\u{1f980}input string"));
46//! }
47//! ```
48//!
49//! ```console
50//!    Compiling no-panic-demo v0.0.1
51//! error: linking with `cc` failed: exit code: 1
52//!   |
53//!   = note: /no-panic-demo/target/release/deps/no_panic_demo-7170785b672ae322.no_p
54//! anic_demo1-cba7f4b666ccdbcbbf02b7348e5df1b2.rs.rcgu.o: In function `_$LT$no_pani
55//! c_demo..demo..__NoPanic$u20$as$u20$core..ops..drop..Drop$GT$::drop::h72f8f423002
56//! b8d9f':
57//!           no_panic_demo1-cba7f4b666ccdbcbbf02b7348e5df1b2.rs:(.text._ZN72_$LT$no
58//! _panic_demo..demo..__NoPanic$u20$as$u20$core..ops..drop..Drop$GT$4drop17h72f8f42
59//! 3002b8d9fE+0x2): undefined reference to `
60//!
61//!           ERROR[no-panic]: detected panic in function `demo`
62//!           '
63//!           collect2: error: ld returned 1 exit status
64//! ```
65//!
66//! The error is not stellar but notice the ERROR\[no-panic\] part at the end
67//! that provides the name of the offending function.
68//!
69//! <br>
70//!
71//! ## Caveats
72//!
73//! - Functions that require some amount of optimization to prove that they do
74//!   not panic may no longer compile in debug mode after being marked
75//!   `#[no_panic]`.
76//!
77//! - Panic detection happens at link time across the entire dependency graph,
78//!   so any Cargo commands that do not invoke a linker will not trigger panic
79//!   detection. This includes `cargo build` of library crates and `cargo check`
80//!   of binary and library crates.
81//!
82//! - The attribute is useless in code built with `panic = "abort"`. Code must
83//!   be built with `panic = "unwind"` (the default) in order for any panics to
84//!   be detected. After confirming absence of panics, you can of course still
85//!   ship your software as a `panic = "abort"` build.
86//!
87//! - Const functions are not supported. The attribute will fail to compile if
88//!   placed on a `const fn`.
89//!
90//! If you find that code requires optimization to pass `#[no_panic]`, either
91//! make no-panic an optional dependency that you only enable in release builds,
92//! or add a section like the following to your Cargo.toml or .cargo/config.toml
93//! to enable very basic optimization in debug builds.
94//!
95//! ```toml
96//! [profile.dev]
97//! opt-level = 1
98//! ```
99//!
100//! If the code that you need to prove isn't panicking makes function calls to
101//! non-generic non-inline functions from a different crate, you may need thin
102//! LTO enabled for the linker to deduce those do not panic.
103//!
104//! ```toml
105//! [profile.release]
106//! lto = "thin"
107//! ```
108//!
109//! If thin LTO isn't cutting it, the next thing to try would be fat LTO with a
110//! single codegen unit:
111//!
112//! ```toml
113//! [profile.release]
114//! lto = "fat"
115//! codegen-units = 1
116//! ```
117//!
118//! If you want no_panic to just assume that some function you call doesn't
119//! panic, and get Undefined Behavior if it does at runtime, see
120//! [dtolnay/no-panic#16]; try wrapping that call in an `unsafe extern "C"`
121//! wrapper.
122//!
123//! [dtolnay/no-panic#16]: https://github.com/dtolnay/no-panic/issues/16
124//!
125//! <br>
126//!
127//! ## Acknowledgments
128//!
129//! The linker error technique is based on [Kixunil]'s crate [`dont_panic`].
130//! Check out that crate for other convenient ways to require absence of panics.
131//!
132//! [Kixunil]: https://github.com/Kixunil
133//! [`dont_panic`]: https://github.com/Kixunil/dont_panic
134
135#![doc(html_root_url = "https://docs.rs/no-panic/0.1.37")]
136#![allow(
137    clippy::doc_markdown,
138    clippy::match_same_arms,
139    clippy::missing_panics_doc,
140    clippy::uninlined_format_args
141)]
142#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))]
143
144extern crate proc_macro;
145
146use proc_macro::TokenStream;
147use proc_macro2::{Span, TokenStream as TokenStream2};
148use quote::quote;
149use std::mem;
150use syn::parse::{Error, Nothing, Result};
151use syn::{
152    parse_quote, FnArg, GenericArgument, Ident, ItemFn, Pat, PatType, Path, PathArguments,
153    ReturnType, Token, Type, TypeInfer, TypeParamBound,
154};
155
156#[proc_macro_attribute]
157pub fn no_panic(args: TokenStream, input: TokenStream) -> TokenStream {
158    let args = TokenStream2::from(args);
159    let input = TokenStream2::from(input);
160    TokenStream::from(match parse(args, input.clone()) {
161        Ok(function) => {
162            let expanded = expand_no_panic(function);
163            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "cfg");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "not");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "doc");
                            _s
                        });
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&expanded, &mut _s);
    ::quote::__private::push_pound(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Bracket,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "cfg");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "doc");
                    _s
                });
            _s
        });
    ::quote::ToTokens::to_tokens(&input, &mut _s);
    _s
}quote! {
164                #[cfg(not(doc))]
165                #expanded
166                // Keep generated parameter names out of doc builds.
167                #[cfg(doc)]
168                #input
169            }
170        }
171        Err(parse_error) => {
172            let compile_error = parse_error.to_compile_error();
173            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&compile_error, &mut _s);
    ::quote::ToTokens::to_tokens(&input, &mut _s);
    _s
}quote! {
174                #compile_error
175                #input
176            }
177        }
178    })
179}
180
181fn parse(args: TokenStream2, input: TokenStream2) -> Result<ItemFn> {
182    let function: ItemFn = syn::parse2(input)?;
183    let _: Nothing = syn::parse2::<Nothing>(args)?;
184    if function.sig.constness.is_some() {
185        return Err(Error::new(
186            Span::call_site(),
187            "no_panic attribute on const fn is not supported",
188        ));
189    }
190    if function.sig.asyncness.is_some() {
191        return Err(Error::new(
192            Span::call_site(),
193            "no_panic attribute on async fn is not supported",
194        ));
195    }
196    Ok(function)
197}
198
199// Convert `Path<impl Trait>` to `Path<_>`
200fn make_impl_trait_wild(ret: &mut Type) {
201    match ret {
202        #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
203        Type::ImplTrait(impl_trait) => {
204            *ret = Type::Infer(TypeInfer {
205                attrs: Vec::new(),
206                underscore_token: ::syn::token::UnderscoreToken![_](impl_trait.impl_token.span),
207            });
208        }
209        Type::Array(ret) => make_impl_trait_wild(&mut ret.elem),
210        Type::Group(ret) => make_impl_trait_wild(&mut ret.elem),
211        Type::Paren(ret) => make_impl_trait_wild(&mut ret.elem),
212        Type::Path(ret) => make_impl_trait_wild_in_path(&mut ret.path),
213        Type::Ptr(ret) => make_impl_trait_wild(&mut ret.elem),
214        Type::Reference(ret) => make_impl_trait_wild(&mut ret.elem),
215        Type::Slice(ret) => make_impl_trait_wild(&mut ret.elem),
216        Type::TraitObject(ret) => {
217            for bound in &mut ret.bounds {
218                if let TypeParamBound::Trait(bound) = bound {
219                    make_impl_trait_wild_in_path(&mut bound.path);
220                }
221            }
222        }
223        Type::Tuple(ret) => ret.elems.iter_mut().for_each(make_impl_trait_wild),
224        Type::FnPtr(_) | Type::Infer(_) | Type::Macro(_) | Type::Never(_) | Type::Verbatim(_) => {}
225        _ => {}
226    }
227}
228
229fn make_impl_trait_wild_in_path(path: &mut Path) {
230    for segment in &mut path.segments {
231        if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
232            for arg in &mut bracketed.args {
233                if let GenericArgument::Type(arg) = arg {
234                    make_impl_trait_wild(arg);
235                }
236            }
237        }
238    }
239}
240
241fn expand_no_panic(mut function: ItemFn) -> TokenStream2 {
242    let mut move_self = None;
243    let mut arg_attrs = Vec::new();
244    let mut arg_pat = Vec::new();
245    let mut arg_val = Vec::new();
246    for (i, input) in function.sig.inputs.iter_mut().enumerate() {
247        match input {
248            FnArg::Typed(PatType { attrs, pat, .. })
249                if match pat.as_ref() {
250                    Pat::Ident(pat) => pat.ident != "self",
251                    _ => true,
252                } =>
253            {
254                let arg_name = if let Pat::Ident(original_name) = &**pat {
255                    original_name.ident.clone()
256                } else {
257                    Ident::new(&::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("__arg{0}", i))
    })format!("__arg{}", i), Span::call_site())
258                };
259                arg_attrs.push(attrs);
260                arg_pat.push(mem::replace(&mut *pat, ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_ident(&mut _s, "mut");
        ::quote::ToTokens::to_tokens(&arg_name, &mut _s);
        _s
    })parse_quote!(mut #arg_name)));
261                arg_val.push(arg_name);
262            }
263            FnArg::Typed(_) | FnArg::Receiver(_) => {
264                move_self = Some({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "if");
    ::quote::__private::push_ident(&mut _s, "false");
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "loop");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                ::quote::__private::TokenStream::new());
            ::quote::__private::push_pound(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Bracket,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "allow");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "unreachable_code");
                            _s
                        });
                    _s
                });
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "__self");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_semi(&mut _s);
                    _s
                });
            _s
        });
    _s
}quote! {
265                    if false {
266                        loop {}
267                        #[allow(unreachable_code)]
268                        {
269                            let __self = self;
270                        }
271                    }
272                });
273            }
274        }
275    }
276
277    let has_inline = function
278        .attrs
279        .iter()
280        .any(|attr| attr.path().is_ident("inline"));
281    if !has_inline {
282        function.attrs.push(::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_pound(&mut _s);
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Bracket,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "inline");
                _s
            });
        _s
    })parse_quote!(#[inline]));
283    }
284
285    let ret = match &function.sig.output {
286        ReturnType::Default => {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_rarrow(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Parenthesis,
        ::quote::__private::TokenStream::new());
    _s
}quote!(-> ()),
287        ReturnType::Type(arrow, output) => {
288            let mut output = output.clone();
289            make_impl_trait_wild(&mut output);
290            {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&arrow, &mut _s);
    ::quote::ToTokens::to_tokens(&output, &mut _s);
    _s
}quote!(#arrow #output)
291        }
292    };
293    let stmts = function.block.stmts;
294    let message = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("\n\nERROR[no-panic]: detected panic in function `{0}`\n",
                function.sig.ident))
    })format!(
295        "\n\nERROR[no-panic]: detected panic in function `{}`\n",
296        function.sig.ident,
297    );
298    let unsafe_extern = if falsecfg!(no_unsafe_extern_blocks) {
299        None
300    } else {
301        Some(::syn::token::UnsafeToken![unsafe](Span::call_site()))
302    };
303    *function.block = ::syn::__private::parse_quote({
        let mut _s = ::quote::__private::TokenStream::new();
        ::quote::__private::push_group(&mut _s,
            ::quote::__private::Delimiter::Brace,
            {
                let mut _s = ::quote::__private::TokenStream::new();
                ::quote::__private::push_ident(&mut _s, "struct");
                ::quote::__private::push_ident(&mut _s, "__NoPanic");
                ::quote::__private::push_semi(&mut _s);
                ::quote::ToTokens::to_tokens(&unsafe_extern, &mut _s);
                ::quote::__private::push_ident(&mut _s, "extern");
                ::quote::__private::parse(&mut _s, "\"C\"");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Brace,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_pound(&mut _s);
                        ::quote::__private::push_group(&mut _s,
                            ::quote::__private::Delimiter::Bracket,
                            {
                                let mut _s = ::quote::__private::TokenStream::new();
                                ::quote::__private::push_ident(&mut _s, "link_name");
                                ::quote::__private::push_eq(&mut _s);
                                ::quote::ToTokens::to_tokens(&message, &mut _s);
                                _s
                            });
                        ::quote::__private::push_ident(&mut _s, "fn");
                        ::quote::__private::push_ident(&mut _s, "trigger");
                        ::quote::__private::push_group(&mut _s,
                            ::quote::__private::Delimiter::Parenthesis,
                            ::quote::__private::TokenStream::new());
                        ::quote::__private::push_rarrow(&mut _s);
                        ::quote::__private::push_bang(&mut _s);
                        ::quote::__private::push_semi(&mut _s);
                        _s
                    });
                ::quote::__private::push_ident(&mut _s, "impl");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "core");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "ops");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "Drop");
                ::quote::__private::push_ident(&mut _s, "for");
                ::quote::__private::push_ident(&mut _s, "__NoPanic");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Brace,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "fn");
                        ::quote::__private::push_ident(&mut _s, "drop");
                        ::quote::__private::push_group(&mut _s,
                            ::quote::__private::Delimiter::Parenthesis,
                            {
                                let mut _s = ::quote::__private::TokenStream::new();
                                ::quote::__private::push_and(&mut _s);
                                ::quote::__private::push_ident(&mut _s, "mut");
                                ::quote::__private::push_ident(&mut _s, "self");
                                _s
                            });
                        ::quote::__private::push_group(&mut _s,
                            ::quote::__private::Delimiter::Brace,
                            {
                                let mut _s = ::quote::__private::TokenStream::new();
                                ::quote::__private::push_ident(&mut _s, "unsafe");
                                ::quote::__private::push_group(&mut _s,
                                    ::quote::__private::Delimiter::Brace,
                                    {
                                        let mut _s = ::quote::__private::TokenStream::new();
                                        ::quote::__private::push_ident(&mut _s, "trigger");
                                        ::quote::__private::push_group(&mut _s,
                                            ::quote::__private::Delimiter::Parenthesis,
                                            ::quote::__private::TokenStream::new());
                                        ::quote::__private::push_semi(&mut _s);
                                        _s
                                    });
                                _s
                            });
                        _s
                    });
                ::quote::__private::push_ident(&mut _s, "let");
                ::quote::__private::push_ident(&mut _s, "__guard");
                ::quote::__private::push_eq(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__NoPanic");
                ::quote::__private::push_semi(&mut _s);
                ::quote::__private::push_ident(&mut _s, "let");
                ::quote::__private::push_ident(&mut _s, "__result");
                ::quote::__private::push_eq(&mut _s);
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "move");
                        ::quote::__private::push_or_or(&mut _s);
                        ::quote::ToTokens::to_tokens(&ret, &mut _s);
                        ::quote::__private::push_group(&mut _s,
                            ::quote::__private::Delimiter::Brace,
                            {
                                let mut _s = ::quote::__private::TokenStream::new();
                                ::quote::ToTokens::to_tokens(&move_self, &mut _s);
                                {
                                    use ::quote::__private::ext::*;
                                    let has_iter = ::quote::__private::HasIterator::<false>;
                                    #[allow(unused_mut)]
                                    let (mut arg_attrs, i) = arg_attrs.quote_into_iter();
                                    let has_iter = has_iter | i;
                                    #[allow(unused_mut)]
                                    let (mut arg_pat, i) = arg_pat.quote_into_iter();
                                    let has_iter = has_iter | i;
                                    #[allow(unused_mut)]
                                    let (mut arg_val, i) = arg_val.quote_into_iter();
                                    let has_iter = has_iter | i;
                                    <_ as
                                            ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                    while true {
                                        let arg_attrs =
                                            match arg_attrs.next() {
                                                Some(_x) => ::quote::__private::RepInterp(_x),
                                                None => break,
                                            };
                                        let arg_pat =
                                            match arg_pat.next() {
                                                Some(_x) => ::quote::__private::RepInterp(_x),
                                                None => break,
                                            };
                                        let arg_val =
                                            match arg_val.next() {
                                                Some(_x) => ::quote::__private::RepInterp(_x),
                                                None => break,
                                            };
                                        {
                                            use ::quote::__private::ext::*;
                                            let has_iter = ::quote::__private::HasIterator::<false>;
                                            #[allow(unused_mut)]
                                            let (mut arg_attrs, i) = arg_attrs.quote_into_iter();
                                            let has_iter = has_iter | i;
                                            <_ as
                                                    ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                            while true {
                                                let arg_attrs =
                                                    match arg_attrs.next() {
                                                        Some(_x) => ::quote::__private::RepInterp(_x),
                                                        None => break,
                                                    };
                                                ::quote::ToTokens::to_tokens(&arg_attrs, &mut _s);
                                            }
                                        }
                                        ::quote::__private::push_ident(&mut _s, "let");
                                        ::quote::ToTokens::to_tokens(&arg_pat, &mut _s);
                                        ::quote::__private::push_eq(&mut _s);
                                        ::quote::ToTokens::to_tokens(&arg_val, &mut _s);
                                        ::quote::__private::push_semi(&mut _s);
                                    }
                                }
                                {
                                    use ::quote::__private::ext::*;
                                    let has_iter = ::quote::__private::HasIterator::<false>;
                                    #[allow(unused_mut)]
                                    let (mut stmts, i) = stmts.quote_into_iter();
                                    let has_iter = has_iter | i;
                                    <_ as
                                            ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                    while true {
                                        let stmts =
                                            match stmts.next() {
                                                Some(_x) => ::quote::__private::RepInterp(_x),
                                                None => break,
                                            };
                                        ::quote::ToTokens::to_tokens(&stmts, &mut _s);
                                    }
                                }
                                _s
                            });
                        _s
                    });
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    ::quote::__private::TokenStream::new());
                ::quote::__private::push_semi(&mut _s);
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "core");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "mem");
                ::quote::__private::push_colon2(&mut _s);
                ::quote::__private::push_ident(&mut _s, "forget");
                ::quote::__private::push_group(&mut _s,
                    ::quote::__private::Delimiter::Parenthesis,
                    {
                        let mut _s = ::quote::__private::TokenStream::new();
                        ::quote::__private::push_ident(&mut _s, "__guard");
                        _s
                    });
                ::quote::__private::push_semi(&mut _s);
                ::quote::__private::push_ident(&mut _s, "__result");
                _s
            });
        _s
    })parse_quote!({
304        struct __NoPanic;
305        #unsafe_extern extern "C" {
306            #[link_name = #message]
307            fn trigger() -> !;
308        }
309        impl ::core::ops::Drop for __NoPanic {
310            fn drop(&mut self) {
311                unsafe {
312                    trigger();
313                }
314            }
315        }
316        let __guard = __NoPanic;
317        let __result = (move || #ret {
318            #move_self
319            #(
320                #(#arg_attrs)*
321                let #arg_pat = #arg_val;
322            )*
323            #(#stmts)*
324        })();
325        ::core::mem::forget(__guard);
326        __result
327    });
328
329    {
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&function, &mut _s);
    _s
}quote!(#function)
330}