TemplateSimplifier; Better handling of c++17 fold expressions and c++20 concepts.
c++17 fold expressions are simplified to a __cppcheck_uninstantiated_fold__ if they are not instantiated. c++20 concepts are skipped/removed by Cppcheck and these will be enforced by the compiler.
This commit is contained in:
parent
f371a92501
commit
04e9c13bc6
|
@ -32,6 +32,32 @@
|
|||
#include <stack>
|
||||
#include <utility>
|
||||
|
||||
static Token *skipRequires(Token *tok)
|
||||
{
|
||||
if (!Token::simpleMatch(tok, "requires"))
|
||||
return tok;
|
||||
|
||||
while (Token::Match(tok, "%oror%|&&|requires %name%|(")) {
|
||||
Token *after = tok->next();
|
||||
if (after->str() == "(") {
|
||||
tok = after->link()->next();
|
||||
continue;
|
||||
}
|
||||
if (Token::Match(after, "requires (") && Token::simpleMatch(after->linkAt(1), ") {")) {
|
||||
tok = after->linkAt(1)->linkAt(1)->next();
|
||||
continue;
|
||||
}
|
||||
while (Token::Match(after, "%name% :: %name%"))
|
||||
after = after->tokAt(2);
|
||||
if (Token::Match(after, "%name% <")) {
|
||||
after = after->next()->findClosingBracket();
|
||||
tok = after ? after->next() : nullptr;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class FindToken {
|
||||
public:
|
||||
|
@ -616,13 +642,8 @@ bool TemplateSimplifier::getTemplateDeclarations()
|
|||
break;
|
||||
tok1 = closing->next();
|
||||
}
|
||||
if (!tok1)
|
||||
if (!Token::Match(tok, "%any% %any%"))
|
||||
syntaxError(tok);
|
||||
if (!tok1->next())
|
||||
syntaxError(tok);
|
||||
// Some syntax checks, see #6865
|
||||
if (!tok->tokAt(2))
|
||||
syntaxError(tok->next());
|
||||
if (tok->strAt(2)=="typename" &&
|
||||
!Token::Match(tok->tokAt(3), "%name%|...|,|=|>"))
|
||||
syntaxError(tok->next());
|
||||
|
@ -3662,6 +3683,18 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
}
|
||||
}
|
||||
|
||||
if (mSettings->standards.cpp >= Standards::CPP20) {
|
||||
// Remove concepts/requires
|
||||
// TODO concepts are not removed yet
|
||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||
if (!Token::Match(tok, ")|>|>> requires %name%|("))
|
||||
continue;
|
||||
Token *end = skipRequires(tok->next());
|
||||
if (end)
|
||||
Token::eraseTokens(tok, end);
|
||||
}
|
||||
}
|
||||
|
||||
mTokenizer->calculateScopes();
|
||||
|
||||
unsigned int passCount = 0;
|
||||
|
@ -3820,6 +3853,26 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
mErrorLogger->reportErr(errmsg);
|
||||
}
|
||||
}
|
||||
|
||||
// Tweak uninstantiated C++17 fold expressions (... && args)
|
||||
if (mSettings->standards.cpp >= Standards::CPP17) {
|
||||
bool simplify = false;
|
||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "template")
|
||||
simplify = false;
|
||||
if (tok->str() == "{")
|
||||
simplify = true;
|
||||
if (!simplify || tok->str() != "(")
|
||||
continue;
|
||||
if (Token::Match(tok, "( ... %op%") ||
|
||||
Token::Match(tok, "( %name% %op% ...") ||
|
||||
Token::Match(tok->link()->tokAt(-3), "%op% ... )") ||
|
||||
Token::Match(tok->link()->tokAt(-3), "... %op% %name% )")) {
|
||||
Token::eraseTokens(tok, tok->link());
|
||||
tok->insertToken("__cppcheck_uninstantiated_fold__");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::syntaxError(const Token *tok)
|
||||
|
|
|
@ -6216,8 +6216,8 @@ static void valueFlowIteratorInfer(TokenList *tokenlist, const Settings *setting
|
|||
}
|
||||
|
||||
static std::vector<ValueFlow::Value> getInitListSize(const Token* tok,
|
||||
const Library::Container* container,
|
||||
bool known = true)
|
||||
const Library::Container* container,
|
||||
bool known = true)
|
||||
{
|
||||
std::vector<const Token*> args = getArguments(tok);
|
||||
if ((args.size() == 1 && astIsContainer(args[0]) && args[0]->valueType()->container == container) ||
|
||||
|
|
|
@ -282,6 +282,18 @@ private:
|
|||
TEST_CASE(simplifyDecltype);
|
||||
|
||||
TEST_CASE(castInExpansion);
|
||||
|
||||
TEST_CASE(fold_expression_1);
|
||||
TEST_CASE(fold_expression_2);
|
||||
TEST_CASE(fold_expression_3);
|
||||
TEST_CASE(fold_expression_4);
|
||||
|
||||
TEST_CASE(concepts1);
|
||||
TEST_CASE(requires1);
|
||||
TEST_CASE(requires2);
|
||||
TEST_CASE(requires3);
|
||||
TEST_CASE(requires4);
|
||||
TEST_CASE(requires5);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
|
||||
|
@ -6051,6 +6063,78 @@ private:
|
|||
"class Base<C<static_cast<int>-1>> { } ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void fold_expression_1() {
|
||||
const char code[] = "template<typename... Args> bool all(Args... args) { return (... && args); }\n"
|
||||
"x=all(true,false,true,true);";
|
||||
const char expected[] = "template < typename ... Args > bool all ( Args ... args ) { return ( __cppcheck_uninstantiated_fold__ ) ; } x = all ( true , false , true , true ) ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void fold_expression_2() {
|
||||
const char code[] = "template<typename... Args> bool all(Args... args) { return (args && ...); }\n"
|
||||
"x=all(true,false,true,true);";
|
||||
const char expected[] = "template < typename ... Args > bool all ( Args ... args ) { return ( __cppcheck_uninstantiated_fold__ ) ; } x = all ( true , false , true , true ) ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void fold_expression_3() {
|
||||
const char code[] = "template<typename... Args> int foo(Args... args) { return (12 * ... * args); }\n"
|
||||
"x=foo(1,2);";
|
||||
const char expected[] = "template < typename ... Args > int foo ( Args ... args ) { return ( __cppcheck_uninstantiated_fold__ ) ; } x = foo ( 1 , 2 ) ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void fold_expression_4() {
|
||||
const char code[] = "template<typename... Args> int foo(Args... args) { return (args * ... * 123); }\n"
|
||||
"x=foo(1,2);";
|
||||
const char expected[] = "template < typename ... Args > int foo ( Args ... args ) { return ( __cppcheck_uninstantiated_fold__ ) ; } x = foo ( 1 , 2 ) ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void concepts1() {
|
||||
const char code[] = "template <my_concept T> void f(T v) {}\n"
|
||||
"f<int>(123);";
|
||||
const char expected[] = "void f<int> ( int v ) ; f<int> ( 123 ) ; void f<int> ( int v ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void requires1() {
|
||||
const char code[] = "template <class T> requires my_concept<T> void f(T v) {}\n"
|
||||
"f<int>(123);";
|
||||
const char expected[] = "void f<int> ( int v ) ; f<int> ( 123 ) ; void f<int> ( int v ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void requires2() {
|
||||
const char code[] = "template<class T> requires (sizeof(T) > 1 && get_value<T>()) void f(T v){}\n"
|
||||
"f<int>(123);";
|
||||
const char expected[] = "void f<int> ( int v ) ; f<int> ( 123 ) ; void f<int> ( int v ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void requires3() {
|
||||
const char code[] = "template<class T> requires c1<T> && c2<T> void f(T v){}\n"
|
||||
"f<int>(123);";
|
||||
const char expected[] = "void f<int> ( int v ) ; f<int> ( 123 ) ; void f<int> ( int v ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void requires4() {
|
||||
const char code[] = "template <class T> void f(T v) requires my_concept<T> {}\n"
|
||||
"f<int>(123);";
|
||||
const char expected[] = "void f<int> ( int v ) ; f<int> ( 123 ) ; void f<int> ( int v ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
|
||||
void requires5() {
|
||||
const char code[] = "template <class T>\n"
|
||||
" requires requires (T x) { x + x; }\n"
|
||||
" T add(T a, T b) { return a + b; }\n"
|
||||
"add<int>(123,456);";
|
||||
const char expected[] = "int add<int> ( int a , int b ) ; add<int> ( 123 , 456 ) ; int add<int> ( int a , int b ) { return a + b ; }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyTemplate)
|
||||
|
|
Loading…
Reference in New Issue