Skip to content

Commit 103fb2d

Browse files
authored
fix #13561: Syntax error reported when a _Generic is used in if condition (danmar#7282)
1 parent 83c9a57 commit 103fb2d

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

lib/tokenlist.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,7 @@ namespace {
451451
bool cpp;
452452
int assign{};
453453
bool inCase{}; // true from case to :
454+
bool inGeneric{};
454455
bool stopAtColon{}; // help to properly parse ternary operators
455456
const Token* functionCallEndPar{};
456457
explicit AST_state(bool cpp) : cpp(cpp) {}
@@ -706,11 +707,31 @@ static void compileUnaryOp(Token *&tok, AST_state& state, void (*f)(Token *&tok,
706707
state.op.push(unaryop);
707708
}
708709

710+
static void skipGenericType(Token *&tok)
711+
{
712+
Token *skip = tok;
713+
while (Token::Match(skip, "%name%|*|:|(")) {
714+
if (skip->link()) {
715+
skip = skip->link()->next();
716+
continue;
717+
}
718+
if (Token::simpleMatch(skip, ":")) {
719+
tok = skip->next();
720+
return;
721+
}
722+
skip = skip->next();
723+
}
724+
}
725+
709726
static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, AST_state& state))
710727
{
711728
Token *binop = tok;
712729
if (f) {
713730
tok = tok->next();
731+
if (Token::simpleMatch(binop, ",") && state.inGeneric)
732+
skipGenericType(tok);
733+
const bool inGenericSaved = state.inGeneric;
734+
state.inGeneric = false;
714735
if (Token::Match(binop, "::|. ~"))
715736
tok = tok->next();
716737
state.depth++;
@@ -719,6 +740,7 @@ static void compileBinOp(Token *&tok, AST_state& state, void (*f)(Token *&tok, A
719740
if (state.depth > AST_MAX_DEPTH)
720741
throw InternalError(tok, "maximum AST depth exceeded", InternalError::AST);
721742
state.depth--;
743+
state.inGeneric = inGenericSaved;
722744
}
723745

724746
// TODO: Should we check if op is empty.
@@ -1048,6 +1070,9 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10481070
continue;
10491071
} else if (tok->str() == "(" &&
10501072
(!iscast(tok, state.cpp) || Token::Match(tok->previous(), "if|while|for|switch|catch"))) {
1073+
const bool inGenericSaved = state.inGeneric;
1074+
if (Token::simpleMatch(tok->previous(), "_Generic"))
1075+
state.inGeneric = true;
10511076
Token* tok2 = tok;
10521077
tok = tok->next();
10531078
const bool opPrevTopSquare = !state.op.empty() && state.op.top() && state.op.top()->str() == "[";
@@ -1066,6 +1091,7 @@ static void compilePrecedence2(Token *&tok, AST_state& state)
10661091
else
10671092
compileUnaryOp(tok, state, nullptr);
10681093
}
1094+
state.inGeneric = inGenericSaved;
10691095
tok = tok->link()->next();
10701096
if (Token::simpleMatch(tok, "::"))
10711097
compileBinOp(tok, state, compileTerm);

test/testtokenize.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@ class TestTokenizer : public TestFixture {
464464
TEST_CASE(funcnameInParenthesis1); // #13554
465465
TEST_CASE(funcnameInParenthesis2); // #13578
466466
TEST_CASE(funcnameInParenthesis3); // #13585
467+
468+
TEST_CASE(genericInIf); // #13561
467469
}
468470

469471
#define tokenizeAndStringify(...) tokenizeAndStringify_(__FILE__, __LINE__, __VA_ARGS__)
@@ -8389,6 +8391,12 @@ class TestTokenizer : public TestFixture {
83898391
ASSERT_EQUALS(par->astOperand1(), f->astParent() /* :: */);
83908392
ASSERT(Token::simpleMatch(par->astOperand2(), ","));
83918393
}
8394+
8395+
void genericInIf() { // #13561
8396+
const char code[] = " if (_Generic(s, char * : 1, const float * : (a ? b, c : d), volatile int * : 3, default : 0)) {}";
8397+
const char ast[] = "(( if (( _Generic (, (, (, (, s 1) (? a (: (, b c) d))) 3) 0)))";
8398+
ASSERT_EQUALS(ast, testAst(code, AstStyle::Z3));
8399+
}
83928400
};
83938401

83948402
REGISTER_TEST(TestTokenizer)

0 commit comments

Comments
 (0)