//! Tests macro_metavars_in_unsafe with default configuration #![feature(decl_macro, lint_reasons)] #![warn(clippy::macro_metavars_in_unsafe)] #![allow(clippy::no_effect)] #[macro_export] macro_rules! allow_works { ($v:expr) => { #[expect(clippy::macro_metavars_in_unsafe)] unsafe { $v; }; }; } #[macro_export] macro_rules! simple { ($v:expr) => { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block dbg!($v); } }; } #[macro_export] #[rustfmt::skip] // for some reason rustfmt rewrites $r#unsafe to r#u$nsafe, bug? macro_rules! raw_symbol { ($r#mod:expr, $r#unsafe:expr) => { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $r#mod; } $r#unsafe; }; } #[macro_export] macro_rules! multilevel_unsafe { ($v:expr) => { unsafe { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $v; } } }; } #[macro_export] macro_rules! in_function { ($v:expr) => { unsafe { fn f() { // function introduces a new body, so don't lint. $v; } } }; } #[macro_export] macro_rules! in_function_with_unsafe { ($v:expr) => { unsafe { fn f() { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $v; } } } }; } #[macro_export] macro_rules! const_static { ($c:expr, $s:expr) => { unsafe { // const and static introduces new body, don't lint const _X: i32 = $c; static _Y: i32 = $s; } }; } #[macro_export] macro_rules! const_generic_in_struct { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { struct Ty< const L: i32 = 1, const M: i32 = { 1; unsafe { $inside_unsafe } //~^ ERROR: this macro expands metavariables in an unsafe block }, const N: i32 = { $outside_unsafe }, >; } }; } #[macro_export] macro_rules! fn_with_const_generic { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { fn f() { $outside_unsafe; unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $inside_unsafe; } } } }; } #[macro_export] macro_rules! variables { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $inside_unsafe; let inside_unsafe = 1; inside_unsafe; } $outside_unsafe; let outside_unsafe = 1; outside_unsafe; }; } #[macro_export] macro_rules! multiple_matchers { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $inside_unsafe; } $outside_unsafe; }; ($($v:expr, $x:expr),+) => { $( $v; unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $x; } );+ }; } #[macro_export] macro_rules! multiple_unsafe_blocks { ($w:expr, $x:expr, $y:expr) => { $w; unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $x; } unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $x; $y; } }; } pub macro macro2_0($v:expr) { unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $v; } } // don't lint private macros with the default configuration macro_rules! private_mac { ($v:expr) => { unsafe { $v; } }; } // don't lint exported macros that are doc(hidden) because they also aren't part of the public API #[macro_export] #[doc(hidden)] macro_rules! exported_but_hidden { ($v:expr) => { unsafe { $v; } }; } // don't lint if the same metavariable is expanded in an unsafe block and then outside of one: // unsafe {} is still needed at callsite so not problematic #[macro_export] macro_rules! does_require_unsafe { ($v:expr) => { unsafe { $v; } $v; }; } #[macro_export] macro_rules! unsafe_from_root_ctxt { ($v:expr) => { // Expands to unsafe { 1 }, but the unsafe block is from the root ctxt and not this macro, // so no warning. $v; }; } // invoked from another macro, should still generate a warning #[macro_export] macro_rules! nested_macro_helper { ($v:expr) => {{ unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block $v; } }}; } #[macro_export] macro_rules! nested_macros { ($v:expr, $v2:expr) => {{ unsafe { //~^ ERROR: this macro expands metavariables in an unsafe block nested_macro_helper!($v); $v; } }}; } fn main() { allow_works!(1); simple!(1); raw_symbol!(1, 1); multilevel_unsafe!(1); in_function!(1); in_function_with_unsafe!(1); const_static!(1, 1); const_generic_in_struct!(1, 1); fn_with_const_generic!(1, 1); variables!(1, 1); multiple_matchers!(1, 1); multiple_matchers!(1, 1, 1, 1); macro2_0!(1); private_mac!(1); exported_but_hidden!(1); does_require_unsafe!(1); multiple_unsafe_blocks!(1, 1, 1); unsafe_from_root_ctxt!(unsafe { 1 }); nested_macros!(1, 1); }