fix(lint): constexpr-constant asks clang's evaluator, not the initialiser tokens
The first cut scanned the initialiser's tokens and required every one to be a literal or an operator. That is exactly the kind of approximation this work has been removing, and it was wrong in both directions: const int A = sizeof(Big); missed — `sizeof` is a keyword const int B = Base + 1; missed — `Base` is an identifier const auto C = 5_notConstexpr; would have been reported, wrongly clang_Cursor_Evaluate answers the question directly. Evaluating a variable declaration evaluates its initialiser, so anything that folds is recognised and a call result still is not. Costs nothing measurable — lint stays at ~15s. Found one real case the token version could not see: an EShMessages fold over three glslang enum constants in Crafter.Build-Shader.cpp. Promoting it to constexpr then made `naming` ask for constant naming, since a constexpr variable is a compile-time constant — so it is `Messages` now. Two rules agreeing on the same declaration is the intended behaviour. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
651720e494
commit
649d64ae12
5 changed files with 52 additions and 31 deletions
|
|
@ -478,20 +478,29 @@ int main() {
|
|||
Check(!HasFinding(r.summary, "'each'"), "const-local: a range-for binding is not reported");
|
||||
}
|
||||
|
||||
// constexpr-constant only promotes a constant whose initialiser is made of
|
||||
// literals and operators, so a call result is left alone.
|
||||
// constexpr-constant asks clang's constant evaluator, not the tokens of the
|
||||
// initialiser. sizeof and a fold over other constants are constant
|
||||
// expressions that no token scan can recognise; a call result is not.
|
||||
{
|
||||
RuleRun r = RunRule("int Compute();\n"
|
||||
"constexpr int Base = 4;\n"
|
||||
"struct Big { int a, b; };\n"
|
||||
"void F() {\n"
|
||||
" const int literal = 4;\n"
|
||||
" const int folded = 1 << 4;\n"
|
||||
" const int fromSizeof = sizeof(Big);\n"
|
||||
" const int fromOtherConstant = Base + 1;\n"
|
||||
" const int fromCall = Compute();\n"
|
||||
" constexpr int already = 8;\n"
|
||||
" (void)literal; (void)folded; (void)fromCall; (void)already;\n"
|
||||
" (void)literal; (void)folded; (void)fromSizeof;\n"
|
||||
" (void)fromOtherConstant; (void)fromCall; (void)already;\n"
|
||||
"}\n",
|
||||
"constexpr-constant", LintMode::Report);
|
||||
Check(HasFinding(r.summary, "'literal'"), "constexpr: a literal constant is reported");
|
||||
Check(HasFinding(r.summary, "'folded'"), "constexpr: an operator fold over literals is reported");
|
||||
// Neither of these is reachable from a token scan of the initialiser.
|
||||
Check(HasFinding(r.summary, "'fromSizeof'"), "constexpr: sizeof folds");
|
||||
Check(HasFinding(r.summary, "'fromOtherConstant'"), "constexpr: a fold over another constant folds");
|
||||
Check(!HasFinding(r.summary, "'fromCall'"), "constexpr: a call result is not a constant expression");
|
||||
Check(!HasFinding(r.summary, "'already'"), "constexpr: an existing constexpr is not re-reported");
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue