llvm / llvm-project

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

[clang][analyzer] suppress `optin.core.EnumCastOutOfRange` for bit-wise operator of scoped enum #76208

Open zufuliu opened 6 months ago

zufuliu commented 6 months ago

related to issue #48725.

enum class Flag {
    None = 0,
    A = 1, 
    B = 2,
};

constexpr Flag operator|(Flag a, Flag b) noexcept {
    return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b));
}

Flag getFlag() {
    return Flag::A | Flag::B;
}

https://godbolt.org/z/bhqcoPEPj

<source>:8:12: warning: The value '3' provided to the cast expression is not in the valid range of values for 'Flag' [clang-analyzer-optin.core.EnumCastOutOfRange]
    8 |     return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b));
      |            ^
<source>:1:12: note: enum declared here
    1 | enum class Flag {
      | ~~~~~~~~~~~^~~~~~
    2 |     None = 0,
      |     ~~~~~~~~~
    3 |     A = 1, 
      |     ~~~~~~
    4 |     B = 2,
      |     ~~~~~~
    5 | };
      | ~
<source>:12:12: note: Calling 'operator|'
   12 |     return Flag::A | Flag::B;
      |            ^~~~~~~~~~~~~~~~~
<source>:8:12: note: The value '3' provided to the cast expression is not in the valid range of values for 'Flag'
    8 |     return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b));
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
llvmbot commented 6 months ago

@llvm/issue-subscribers-clang-static-analyzer

Author: Zufu Liu (zufuliu)

related to issue #48725. ```c++ enum class Flag { None = 0, A = 1, B = 2, }; constexpr Flag operator|(Flag a, Flag b) noexcept { return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b)); } Flag getFlag() { return Flag::A | Flag::B; } ``` https://godbolt.org/z/bhqcoPEPj ``` <source>:8:12: warning: The value '3' provided to the cast expression is not in the valid range of values for 'Flag' [clang-analyzer-optin.core.EnumCastOutOfRange] 8 | return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b)); | ^ <source>:1:12: note: enum declared here 1 | enum class Flag { | ~~~~~~~~~~~^~~~~~ 2 | None = 0, | ~~~~~~~~~ 3 | A = 1, | ~~~~~~ 4 | B = 2, | ~~~~~~ 5 | }; | ~ <source>:12:12: note: Calling 'operator|' 12 | return Flag::A | Flag::B; | ^~~~~~~~~~~~~~~~~ <source>:8:12: note: The value '3' provided to the cast expression is not in the valid range of values for 'Flag' 8 | return static_cast<Flag>(static_cast<int>(a) | static_cast<int>(b)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1 warning generated. ```
whisperity commented 6 months ago

This is, unfortunately, indeed not supported right now, but, as far as I know, this is a planned improvement. (An issue, however, would be that if the CSA checker is taking a configuration flag, as far as I know, there is no way to pass checker configurations of CSA checkers from Clang-Tidy's interface.)

NagyDonat commented 6 months ago

(Also note that this limitation of this "optin" checker is clearly documented: https://clang.llvm.org/docs/analyzer/checkers.html#optin-core-enumcastoutofrange-c-c . There are some plans to make this checker more general in the future, but until then it should not be enabled on projects that want to store flag combinations in enum variables.)

zufuliu commented 6 months ago

this limitation of this "optin" checker is clearly documented

Thanks for the link, however clang-analyzer-* does not enable the check in clang-tidy 17.

NagyDonat commented 6 months ago

This checker was improved by recent commits (authored by @gamesh411 and me), so in Clang 17 you can only find an earlier variant that's named alpha.cplusplus.EnumCastOutOfRange. (Note: this checker is not especially connected to C++, the "cplusplus" in the old name is just misleading. Also note that the old documentation was highly incomplete.)

This checker wasn't enabled by clang-analyzer-* in clang-tidy 17 because then it was an alpha checker (= has general quality issues, use at your own risk), while now it's an optin checker (= stable, but enforces a guideline or stylistic choice that is useful for some projects, but unwanted in others).

I'd say that the main issue is that the generic clang-analyzer-* flag, which should provide a "sane default", turns on the optin checkers.

NagyDonat commented 6 months ago

Unfortunately it seems that clang-analyzer-* is just a "dump" wildcard expression, not a reference to a "smart", curated list of generally useful checkers.

The alpha checkers are disabled by a hardcoded setting, which can be disabled by a hidden undocumented command-line flag for those users who like to see lots of false positives. This solution is appropriate for the alpha checkers but we cannot "borrow" it for the optin checkers, because there we hope that many users will opt in to some of them (which are compatible with their goals).

I don't know what would be the good UI that (1) makes the optin checkers easy to access (2) ensures that the rough "turn on everything" setting produces sane behavior.