Parser; C++20 for loop with initialization expression

This commit is contained in:
Daniel Marjamäki 2021-04-24 11:47:51 +02:00
parent bd7551411a
commit c9dc92c266
3 changed files with 41 additions and 20 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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