diff --git a/simplecpp.cpp b/simplecpp.cpp index 438288e5..9fa548a3 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3839,9 +3839,12 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL return; } + const bool isElif = (rawtok->str() == ELIF || rawtok->str() == ELIFDEF || rawtok->str() == ELIFNDEF); + bool conditionIsTrue; - if (ifstates.top() == AlwaysFalse || (ifstates.top() == ElseIsTrue && rawtok->str() != ELIF && - rawtok->str() != ELIFDEF && rawtok->str() != ELIFNDEF)) { + // An #if is only evaluated in an active group. An #elif is only evaluated + // if no previous group was taken; otherwise it is skipped (C 6.10.1p6). + if (isElif ? (ifstates.top() != ElseIsTrue) : (ifstates.top() != True)) { conditionIsTrue = false; } else if (rawtok->str() == IFDEF || rawtok->str() == ELIFDEF) { diff --git a/test.cpp b/test.cpp index 4ef9bdd2..3574563a 100644 --- a/test.cpp +++ b/test.cpp @@ -2490,6 +2490,16 @@ static void elif() "3\n" "#endif"; ASSERT_EQUALS("\n\n\n\n\n3", preprocess(code3)); + + // #elif after a taken group must not be evaluated + const char code4[] = "#if 1\n" + "1\n" + "#elif 1/0\n" + "2\n" + "#elif garbage(\n" + "3\n" + "#endif"; + ASSERT_EQUALS("\n1", preprocess(code4)); } static void elifdef()