Skip to content

Commit afd20aa

Browse files
authored
[clang-scan-deps] Fix "unterminated conditional directive" bug (#146645)
`clang-scan-deps` threw "unterminated conditional directive" error falsely on the following example: ``` #ifndef __TEST #define __TEST #if defined(__TEST_DUMMY) #if defined(__TEST_DUMMY2) #pragma GCC warning \ "Hello!" #else #pragma GCC error \ "World!" #endif // defined(__TEST_DUMMY2) #endif // defined(__TEST_DUMMY) #endif // #ifndef __TEST ``` The issue comes from PR #143950, where the flag `LastNonWhitespace` does not correctly represent the state for the example above. The PR aimed to support that a line-continuation can be followed by whitespaces. This commit fixes the issue by moving the `LastNonWhitespace` variable to the inner loop so that it will be correctly reset. rdar://153742186
1 parent 85aaaf6 commit afd20aa

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

clang/lib/Lex/DependencyDirectivesScanner.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,6 @@ static bool isQuoteCppDigitSeparator(const char *const Start,
419419
}
420420

421421
void Scanner::skipLine(const char *&First, const char *const End) {
422-
char LastNonWhitespace = ' ';
423422
for (;;) {
424423
assert(First <= End);
425424
if (First == End)
@@ -430,6 +429,9 @@ void Scanner::skipLine(const char *&First, const char *const End) {
430429
return;
431430
}
432431
const char *Start = First;
432+
// Use `LastNonWhitespace`to track if a line-continuation has ever been seen
433+
// before a new-line character:
434+
char LastNonWhitespace = ' ';
433435
while (First != End && !isVerticalWhitespace(*First)) {
434436
// Iterate over strings correctly to avoid comments and newlines.
435437
if (*First == '"' ||

clang/unittests/Lex/DependencyDirectivesScannerTest.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,37 @@ TEST(MinimizeSourceToDependencyDirectivesTest,
880880
EXPECT_EQ(pp_eof, Directives[22].Kind);
881881
}
882882

883+
TEST(MinimizeSourceToDependencyDirectivesTest,
884+
TestFixedBugThatReportUnterminatedDirectiveFalsely) {
885+
SmallVector<char, 512> Out;
886+
SmallVector<dependency_directives_scan::Token, 16> Tokens;
887+
SmallVector<Directive, 16> Directives;
888+
889+
StringRef Input = "#ifndef __TEST \n"
890+
"#define __TEST \n"
891+
"#if defined(__TEST_DUMMY) \n"
892+
"#if defined(__TEST_DUMMY2) \n"
893+
"#pragma GCC warning \\ \n"
894+
"\"hello!\"\n"
895+
"#else\n"
896+
"#pragma GCC error \\ \n"
897+
"\"world!\" \n"
898+
"#endif // defined(__TEST_DUMMY2) \n"
899+
"#endif // defined(__TEST_DUMMY) \n"
900+
"#endif // #ifndef __TEST \n";
901+
ASSERT_FALSE( // False on no error:
902+
minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives));
903+
ASSERT_TRUE(Directives.size() == 8);
904+
EXPECT_EQ(pp_ifndef, Directives[0].Kind);
905+
EXPECT_EQ(pp_define, Directives[1].Kind);
906+
EXPECT_EQ(pp_if, Directives[2].Kind);
907+
EXPECT_EQ(pp_if, Directives[3].Kind);
908+
EXPECT_EQ(pp_endif, Directives[4].Kind);
909+
EXPECT_EQ(pp_endif, Directives[5].Kind);
910+
EXPECT_EQ(pp_endif, Directives[6].Kind);
911+
EXPECT_EQ(pp_eof, Directives[7].Kind);
912+
}
913+
883914
TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) {
884915
SmallVector<char, 128> Out;
885916

0 commit comments

Comments
 (0)