Skip to content

Unsafe Function Without Unsafe Block

Description

This rule detects functions marked with the unsafe keyword that do not contain any unsafe blocks in their body.

When a function is marked unsafe, it indicates that the function contains operations that the compiler cannot verify as safe. However, if the function body doesn't contain any unsafe blocks, it may be unnecessarily marked as unsafe. This could be a sign that:

  1. The function should not be marked unsafe if it doesn't perform any unsafe operations
  2. Or if there are unsafe operations, they should be explicitly wrapped in unsafe blocks for clarity

This rule helps identify such cases so developers can review whether the unsafe marker is truly necessary or if the code needs to be refactored.

YAML

yaml
id: redundant-unsafe-function
language: rust
severity: error
message: Unsafe function without unsafe block inside
note: |
  Consider whether this function needs to be marked unsafe 
  or if unsafe operations should be wrapped in an unsafe block
rule:
  all:
    - kind: function_item
    - has:
        kind: function_modifiers
        regex: "^unsafe"
    - not:
        has:
          kind: unsafe_block
          stopBy: end

Example

rs
// Should match - unsafe function without unsafe block (no return type)
unsafe fn redundant_unsafe() {
    println!("No unsafe operations here");
}

// Should match - unsafe function with return type, no unsafe block
unsafe fn redundant_with_return() -> i32 {
    let x = 5;
    x + 10
}

// Should match - unsafe function with complex return type
unsafe fn redundant_complex_return() -> Result<String, std::io::Error> {
    Ok(String::from("safe operation"))
}

// Should NOT match - unsafe function with unsafe block
unsafe fn proper_unsafe() -> *const i32 {
    unsafe {
        let ptr = 0x1234 as *const i32;
        ptr
    }
}

// Should match - unsafe async function without unsafe block
unsafe async fn async_redundant() -> i32 {
    42
}

// Should match - unsafe const function
unsafe const fn const_redundant() -> i32 {
    100
}

// Should NOT match - regular function
fn regular_function() -> i32 {
    42
}

Contributed by

Inspired by @hd_nvim's Tweet

Made with ❤️ with Rust