From c9dc92c26609b98f4b33cf1584266e9e81cfc35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 24 Apr 2021 11:47:51 +0200 Subject: [PATCH] Parser; C++20 for loop with initialization expression --- lib/tokenize.cpp | 8 ++++++-- lib/tokenlist.cpp | 38 ++++++++++++++++++++++---------------- test/testtokenize.cpp | 15 +++++++++++++-- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 91934ee16..f7a823900 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -10182,9 +10182,10 @@ void Tokenizer::findGarbageCode() const } } // if we have an invalid number of semicolons inside for( ), assume syntax error - if ((semicolons == 1) || (semicolons > 2)) { + if (semicolons > 2) + syntaxError(tok); + if (semicolons == 1 && !(isCPP() && mSettings->standards.cpp >= Standards::CPP20)) syntaxError(tok); - } } // Operators without operands.. @@ -11281,6 +11282,9 @@ void Tokenizer::simplifyBitfields() } Token *last = nullptr; + if (Token::simpleMatch(tok, "for (")) + tok = tok->linkAt(1); + if (!Token::Match(tok, ";|{|}|public:|protected:|private:")) continue; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 00033f0c1..d9f94b8e8 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -1495,26 +1495,32 @@ static Token * createAstAtToken(Token *tok, bool cpp) Token * const semicolon2 = tok2; if (!semicolon2) return nullptr; // invalid code #7235 - tok2 = tok2->next(); - AST_state state3(cpp); - if (Token::simpleMatch(tok2, "( {")) { - state3.op.push(tok2->next()); - tok2 = tok2->link()->next(); + + if (semicolon2->str() == ";") { + tok2 = tok2->next(); + AST_state state3(cpp); + if (Token::simpleMatch(tok2, "( {")) { + state3.op.push(tok2->next()); + tok2 = tok2->link()->next(); + } + compileExpression(tok2, state3); + + tok2 = findAstTop(semicolon1->next(), semicolon2); + if (tok2) + semicolon2->astOperand1(tok2); + tok2 = findAstTop(semicolon2->next(), endPar); + if (tok2) + semicolon2->astOperand2(tok2); + else if (!state3.op.empty()) + semicolon2->astOperand2(state3.op.top()); + semicolon1->astOperand2(semicolon2); + } else { + tok2 = findAstTop(semicolon1->next(), semicolon2); + semicolon1->astOperand2(tok2 ? tok2 : state2.op.top()); } - compileExpression(tok2, state3); if (init != semicolon1) semicolon1->astOperand1(init->astTop()); - tok2 = findAstTop(semicolon1->next(), semicolon2); - if (tok2) - semicolon2->astOperand1(tok2); - tok2 = findAstTop(semicolon2->next(), endPar); - if (tok2) - semicolon2->astOperand2(tok2); - else if (!state3.op.empty()) - semicolon2->astOperand2(state3.op.top()); - - semicolon1->astOperand2(semicolon2); tok->next()->astOperand1(tok); tok->next()->astOperand2(semicolon1); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 50fea13e9..fb9ca24d4 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -281,6 +281,7 @@ private: TEST_CASE(bitfields14); // ticket #4561 (segfault for 'class a { signals: };') TEST_CASE(bitfields15); // ticket #7747 (enum Foo {A,B}:4;) TEST_CASE(bitfields16); // Save bitfield bit count + TEST_CASE(bitfields17); // for (A; b:c); TEST_CASE(simplifyNamespaceStd); @@ -3952,6 +3953,13 @@ private: ASSERT_EQUALS(1, x->bits()); } + void bitfields17() { + Settings settings; + settings.standards.cpp = Standards::CPP20; + const char code[] = "void f() { for (a;b:c) {} }"; + ASSERT_EQUALS("void f ( ) { for ( a ; b : c ) { } }", tokenizeAndStringify(code, settings)); + } + void simplifyNamespaceStd() { const char *code, *expected; @@ -5366,6 +5374,7 @@ private: ASSERT_EQUALS("12*34*5*+", testAst("1*2+3*4*5")); ASSERT_EQUALS("0(r.&", testAst("(&((typeof(x))0).r);")); ASSERT_EQUALS("0(r.&", testAst("&((typeof(x))0).r;")); + ASSERT_EQUALS("0f1(||", testAst("; 0 || f(1);")); // Various tests of precedence ASSERT_EQUALS("ab::c+", testAst("a::b+c")); @@ -5449,6 +5458,10 @@ private: ASSERT_EQUALS("fora*++;;(", testAst("for (++(*a);;);")); ASSERT_EQUALS("foryz:(", testAst("for (decltype(x) *y : z);")); ASSERT_EQUALS("for(tmpNULL!=tmptmpnext.=;;( tmpa=", testAst("for ( ({ tmp = a; }) ; tmp != NULL; tmp = tmp->next ) {}")); + ASSERT_EQUALS("forx0=x;;(", testAst("for (int x=0; x;);")); + + // for with initializer (c++20) + ASSERT_EQUALS("forab=ca:;(", testAst("for(a=b;int c:a)")); // problems with multiple expressions ASSERT_EQUALS("ax( whilex(", testAst("a(x) while (x)")); @@ -5474,9 +5487,7 @@ private: // C++17: if (expr1; expr2) ASSERT_EQUALS("ifx3=y;(", testAst("if (int x=3; y)")); - ASSERT_EQUALS("forx0=x;;(", testAst("for (int x=0; x;);")); - ASSERT_EQUALS("0f1(||", testAst("; 0 || f(1);")); } void astexpr2() { // limit for large expressions