1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
#![forbid(unsafe_code)] //! Helping you make your programs less safe. //! //! ## Usage //! Add `plutonium` to your `Cargo.toml`: //! ```toml //! [dependencies] //! plutonium = "*" //! ``` //! //! and start calling your "safe" functions: //! ``` //! use plutonium::*; //! //! fn main() { //! let x = super_safe(1.0); //! println!("{:?}", x); //! deref_null(); //! } //! //! #[safe] //! fn super_safe(x: f32) -> i32 { //! std::mem::transmute::<f32, i32>(x) //! } //! //! #[safe] //! unsafe fn deref_null() { //! let p = &mut 0 as *mut i32; //! println!("{}", *p); //! } //! ``` //! //! ## Roadmap: //! 1. Disable `#![forbid(unsafe_code)]` //! 2. Add `#![forbid(safe_code)]` proc-macro lint extern crate proc_macro; use proc_macro::TokenStream; use quote::quote; use syn::{ fold::Fold, parse_macro_input, parse_quote, Block, Expr, ExprUnsafe, ItemFn, Stmt, Token, }; /// Turn unsafe code into "safe" code. /// ``` /// use plutonium::safe; /// /// #[safe] /// fn a_very_safe_function() { /// let num = 5; /// let r1 = &num as *const i32; /// println!("r1 is: {}", *r1); /// } /// /// #[safe] /// unsafe fn an_even_more_safe_function() -> i32 { /// 1 /// } /// /// fn main() { /// a_very_safe_function(); /// println!("{}", an_even_more_safe_function()); /// } /// ``` #[proc_macro_attribute] pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream { let input_fn = parse_macro_input!(item as ItemFn); let mut safe_fn = input_fn.clone(); if input_fn.sig.unsafety.is_some() { safe_fn.sig.unsafety = None; } safe_fn.block = Box::new(MakeFnBodyUnsafe.fold_block(*input_fn.block)); let safe_fn = quote! { #safe_fn }; safe_fn.into() } struct MakeFnBodyUnsafe; impl Fold for MakeFnBodyUnsafe { fn fold_block(&mut self, block: Block) -> Block { Block { brace_token: block.brace_token, stmts: vec![Stmt::Expr(Expr::Unsafe(ExprUnsafe { attrs: vec![parse_quote! { #[allow(unused_unsafe)] }], unsafe_token: Token!(unsafe)(block.brace_token.span), block, }))], } } } // #[proc_macro_attribute] // pub fn forbid(args: TokenStream, input: TokenStream) -> TokenStream { // input // } // blocked on https://github.com/rust-lang/rust/issues/55467 // #[proc_macro_attribute] // pub fn forbìd(args: TokenStream, input: TokenStream) -> TokenStream { // input // }