Repository navigation
Fix #15126 FP syntaxError (function try block with override in struct) - #8955
chrchr-github wants to merge 5 commits into
Conversation
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
The fix works for the common forms, void f() [const|noexcept|noexcept(true)] override|final try {...} catch(...) {...}, and I found no regressions. It only handles a single override or final directly after ) or after a keyword, though. Two forms with override still give the same syntaxError:
- a ref-qualifier:
void i() & override try,void i() && override try,void i() const & override try - a trailing return type:
auto k() -> void override try
The base version fails on these forms without override as well (void i() & try, auto k() -> void try), so they are a gap that already existed rather than a regression. It is still a gap in the same ticket area. When final or override is used as a variable name before a try inside a function body, the PR gives no new false positive.
Testing
I built cppcheck and testrunner in pr/. ./testrunner TestTokenizer TestGarbage TestSymbolDatabase TestSimplifyTokens TestClass passed with 0 failures.
Handled correctly, no errors:
const overridenoexcept overridenoexcept(true) overrideoverride finalint final = 0; try {...}inside a function bodyint override[2]; ... try {...}inside a function body
Still syntaxError, ./cppcheck -q x.cpp in each case:
struct E : B {
void i() & override try {} catch (...) {}
};error: syntax error: keyword 'try' is not allowed in class/struct/union/enum scope [syntaxError]
These forms give the same error:
void i() && override try {} catch (...) {}void i() const & override try {} catch (...) {}auto k() -> void override try {} catch (...) {}
Without override, the base version also rejects void i() & try {} catch (...) {} and auto k() -> void try {} catch (...) {}, so this limitation existed before the PR.
Automated review of aa91b3a by Claude. The pull request was built and tested locally.
| continue; | ||
| const Token* par = tok->previous(); | ||
| while (par && par->isKeyword()) | ||
| while (par && (par->isKeyword() || Token::Match(par, "final|override"))) |
There was a problem hiding this comment.
AI review
This loop still misses override or final after a ref-qualifier or a trailing return type. These still produce syntaxError:
struct E : B { void i() & override try {} catch (...) {} };
struct F : B { auto k() -> void override try {} catch (...) {} };&/&& and -> type before try already fail in base without override, so this is a gap that existed before, not a regression. It may still be worth covering here, or noting in the ticket.
|
Test results for commit aa91b3a (tools/test-my-pr.py, main compared to this PR): Test: http://ec2-16-170-140-253.eu-north-1.compute.amazonaws.com/pr-8955/ Posted automatically by the cppcheck PR test runner. +N: warnings only with this PR, -N: warnings only with main. The AI review is written by Claude and can be wrong. |
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
The fix now covers ref-qualifiers and trailing return types, but the trailing return type part only works when the return type is made of plain names and ::. The backward walk in simplifyFunctionTryCatch stops at any other token, so these still give syntaxError:
- a pointer return type:
auto k() -> int* override try {} catch (...) {} - a template return type:
auto k() -> std::vector<int> override try {} catch (...) {}
Forms that do work now include -> std::size_t final, -> const int& override, -> decltype(1) override and -> int (*)() override, so whether this case works depends on the spelling of the return type. Apart from this, I found no new problems: I saw no regressions in function bodies or in constructor try blocks. The earlier review already covered -> T try without override, which still fails in both base and the PR.
Testing
I built cppcheck and testrunner in pr/, and cppcheck in base/. ./testrunner TestTokenizer TestGarbage TestSymbolDatabase TestSimplifyTokens TestClass TestFunctions TestVarID passed: 1627 tests, 0 failures.
Still syntaxError. I put each member below in struct B{virtual ~B();}; struct D : B { <member> }; and ran ./cppcheck -q t.cpp:
auto k() -> int* override try {} catch (...) {}
auto k() -> std::vector<int> override try {} catch (...) {}Output:
t1.cpp:3:28: error: syntax error: keyword 'try' is not allowed in class/struct/union/enum scope [syntaxError]
t2.cpp:3:40: error: syntax error: keyword 'try' is not allowed in class/struct/union/enum scope [syntaxError]
Fixed by the PR (base gives syntaxError, the PR gives none):
-> const int& override-> decltype(1) override-> int (*)() override-> std::size_t finalconst & noexcept overridenoexcept(false) overridethrow() overridevoid f() &override final
Some of these give missingReturn, which is correct for those bodies.
Function bodies. I compared the --debug-normal output of base and the PR on try blocks after if (x) MACRO, while (x), x = x && p; and for (;;), and on a constructor try block with an initializer list. The output is identical.
Automated review of bb851af by Claude. The pull request was built and tested locally.
| continue; | ||
| const Token* par = tok->previous(); | ||
| while (par && par->isKeyword()) | ||
| while (par && (par->isKeyword() || Token::Match(par, "%name%|&|&&|->|::"))) |
There was a problem hiding this comment.
AI review
This walk only steps over %name%|&|&&|->|::, so a trailing return type with any other token stops it early. isFunctionHead() then gets a token that is not ), and these forms still give syntaxError:
struct D : B {
auto k() -> int* override try {} catch (...) {}
auto l() -> std::vector<int> override try {} catch (...) {}
};Meanwhile -> int (*)() override try and -> decltype(1) override try work, because the walk happens to stop at a ). One option is to jump to the ( before the -> and let isFunctionHead() parse the trailing return type, since it already handles </(/[ links. Another is to skip * and linked > here as well.
No description provided.