Author: Ziqing Luo Date: 2025-07-04T12:53:23+08:00 New Revision: afd20aaca5fd89dd14992c3fe2f735c5e16ad986
URL: https://github.com/llvm/llvm-project/commit/afd20aaca5fd89dd14992c3fe2f735c5e16ad986 DIFF: https://github.com/llvm/llvm-project/commit/afd20aaca5fd89dd14992c3fe2f735c5e16ad986.diff LOG: [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 Added: Modified: clang/lib/Lex/DependencyDirectivesScanner.cpp clang/unittests/Lex/DependencyDirectivesScannerTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Lex/DependencyDirectivesScanner.cpp b/clang/lib/Lex/DependencyDirectivesScanner.cpp index a862abcc44b38..d894c265a07a2 100644 --- a/clang/lib/Lex/DependencyDirectivesScanner.cpp +++ b/clang/lib/Lex/DependencyDirectivesScanner.cpp @@ -419,7 +419,6 @@ static bool isQuoteCppDigitSeparator(const char *const Start, } void Scanner::skipLine(const char *&First, const char *const End) { - char LastNonWhitespace = ' '; for (;;) { assert(First <= End); if (First == End) @@ -430,6 +429,9 @@ void Scanner::skipLine(const char *&First, const char *const End) { return; } const char *Start = First; + // Use `LastNonWhitespace`to track if a line-continuation has ever been seen + // before a new-line character: + char LastNonWhitespace = ' '; while (First != End && !isVerticalWhitespace(*First)) { // Iterate over strings correctly to avoid comments and newlines. if (*First == '"' || diff --git a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp index 61f74929c1e98..d2ef27155df94 100644 --- a/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp +++ b/clang/unittests/Lex/DependencyDirectivesScannerTest.cpp @@ -880,6 +880,37 @@ TEST(MinimizeSourceToDependencyDirectivesTest, EXPECT_EQ(pp_eof, Directives[22].Kind); } +TEST(MinimizeSourceToDependencyDirectivesTest, + TestFixedBugThatReportUnterminatedDirectiveFalsely) { + SmallVector<char, 512> Out; + SmallVector<dependency_directives_scan::Token, 16> Tokens; + SmallVector<Directive, 16> Directives; + + StringRef Input = "#ifndef __TEST \n" + "#define __TEST \n" + "#if defined(__TEST_DUMMY) \n" + "#if defined(__TEST_DUMMY2) \n" + "#pragma GCC warning \\ \n" + "\"hello!\"\n" + "#else\n" + "#pragma GCC error \\ \n" + "\"world!\" \n" + "#endif // defined(__TEST_DUMMY2) \n" + "#endif // defined(__TEST_DUMMY) \n" + "#endif // #ifndef __TEST \n"; + ASSERT_FALSE( // False on no error: + minimizeSourceToDependencyDirectives(Input, Out, Tokens, Directives)); + ASSERT_TRUE(Directives.size() == 8); + EXPECT_EQ(pp_ifndef, Directives[0].Kind); + EXPECT_EQ(pp_define, Directives[1].Kind); + EXPECT_EQ(pp_if, Directives[2].Kind); + EXPECT_EQ(pp_if, Directives[3].Kind); + EXPECT_EQ(pp_endif, Directives[4].Kind); + EXPECT_EQ(pp_endif, Directives[5].Kind); + EXPECT_EQ(pp_endif, Directives[6].Kind); + EXPECT_EQ(pp_eof, Directives[7].Kind); +} + TEST(MinimizeSourceToDependencyDirectivesTest, PoundWarningAndError) { SmallVector<char, 128> Out; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits