llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.24k stars 11.66k forks source link

`bugprone-exception-escape` reported for generic (unused) code with `libc++` #109587

Open firewave opened 1 week ago

firewave commented 1 week ago
#include <functional>

struct OnExit {
    std::function<void()> f;

    ~OnExit() {
        f();
    }
};
<source>:6:5: warning: an exception may be thrown in function '~OnExit' which should not throw exceptions [bugprone-exception-escape]
    6 |     ~OnExit() {
      |     ^

https://godbolt.org/z/PG8M7jeE9

This is reported for any file which includes it (even when unused) when using libc++. There is no warning with libstdc++.

First I think this should only be reported when it is used. And second as you cannot annotate the function with noexcept it should only be reported when the provided function does not throw an exception.

llvmbot commented 1 week ago

@llvm/issue-subscribers-clang-tidy

Author: Oliver Stöneberg (firewave)

```cpp #include <functional> struct OnExit { std::function<void()> f; ~OnExit() { f(); } }; ``` ``` <source>:6:5: warning: an exception may be thrown in function '~OnExit' which should not throw exceptions [bugprone-exception-escape] 6 | ~OnExit() { | ^ ``` https://godbolt.org/z/PG8M7jeE9 This is reported for any file which includes it (even when unused) when using `libc++`. There is no warning with `libstdc++`. First I think this should only be reported when it is used. And second as you cannot annotate the function with `noexcept` it should only be reported when the provided function does not throw an exception.
chrchr-github commented 1 week ago

Some experiments (independent from libc++:

struct S {
    bool b{};
    void operator()() {
        if (b)
            throw 1;
    }
};

void f(bool b) {
    if (b)
        throw 1;
}

struct OnExit1 {
    S s;
    ~OnExit1() {
        s(); // warning
    }
};

struct OnExit2 {
    ~OnExit2() {
        f(false); // warning
    }
};

struct OnExit3 {
    ~OnExit3() {
        int* p = new int[1000]; // no warning
    }
};

https://godbolt.org/z/rGbv848na

ldionne commented 6 days ago

I suspect the libc++/libstdc++ difference has to do with the number of abstraction layers we use to implement std::function in libc++, but I don't think that's a libc++ bug per se. Untagging.