llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Hirotaka Monya (catlover-bot) <details> <summary>Changes</summary> Fixes #<!-- -->213973 This change updates `#line` filename handling so that doubled backslashes (`\\`) are treated as a single backslash. Importantly, it does not revert to the old string-literal parsing behavior. Only doubled backslashes are collapsed; single backslashes are preserved as written. This means filenames such as `C:\moo\zar\haz.h` remain unchanged, as do sequences such as `\x12`. Regression coverage includes both forms of line directives: * `#line ...` * GNU line markers such as `# 40 "..."` The tests cover the relevant doubled- and single-backslash cases for both forms. Validation performed locally: * Original reproducer after the fix: `exit code = 0` * `clang/test/Preprocessor`: `380 passed / 12 unsupported / 0 failed` * Related regression tests: `3/3 PASS` AI tool usage: I do not use AI tools. --- Full diff: https://github.com/llvm/llvm-project/pull/215992.diff 4 Files Affected: - (modified) clang/include/clang/Lex/Preprocessor.h (+4-1) - (modified) clang/lib/Frontend/FrontendAction.cpp (+3-1) - (modified) clang/lib/Lex/PPDirectives.cpp (+24-4) - (added) clang/test/Preprocessor/line-directive-backslash.c (+17) ``````````diff diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index e752010dd2062..61ad3e252087c 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2556,7 +2556,10 @@ class Preprocessor { /// the spelling of the filename, but is also expected to handle the case /// when this method decides to use a different buffer. /// - void GetLineDirectiveFilenameSpelling(SourceLocation Loc, StringRef &Buffer); + /// \p UnescapedBuffer provides storage when the filename needs unescaping. + /// + void GetLineDirectiveFilenameSpelling(SourceLocation Loc, StringRef &Buffer, + SmallVectorImpl<char> &UnescapedBuffer); /// Given a "foo" or \<foo> reference, look up the indicated file. /// diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index c18c702d46cc7..d00ce06b99112 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -529,7 +529,9 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI, Preprocessor &PP = CI.getPreprocessor(); SmallString<128> HeaderNameBuffer; StringRef HeaderName = PP.getSpelling(T, HeaderNameBuffer); - PP.GetLineDirectiveFilenameSpelling(T.getLocation(), HeaderName); + SmallString<128> UnescapedHeaderNameBuffer; + PP.GetLineDirectiveFilenameSpelling(T.getLocation(), HeaderName, + UnescapedHeaderNameBuffer); RawLexer->LexFromRawLexer(T); if (T.isNot(tok::eof) && !T.isAtStartOfLine()) diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index ec387a4d582fc..e2a4c3d9db6b9 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1645,7 +1645,9 @@ void Preprocessor::HandleLineDirective() { } else { SmallString<128> FilenameBuffer; StringRef Filename = getSpelling(StrTok, FilenameBuffer); - GetLineDirectiveFilenameSpelling(StrTok.getLocation(), Filename); + SmallString<128> UnescapedFilenameBuffer; + GetLineDirectiveFilenameSpelling(StrTok.getLocation(), Filename, + UnescapedFilenameBuffer); FilenameID = SourceMgr.getLineTableFilenameID(Filename); // Verify that there is nothing after the string, other than EOD. Because @@ -1783,7 +1785,9 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { } else { SmallString<128> FilenameBuffer; StringRef Filename = getSpelling(StrTok, FilenameBuffer); - GetLineDirectiveFilenameSpelling(StrTok.getLocation(), Filename); + SmallString<128> UnescapedFilenameBuffer; + GetLineDirectiveFilenameSpelling(StrTok.getLocation(), Filename, + UnescapedFilenameBuffer); // If a filename was present, read any flags that are present. if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this)) return; @@ -1983,8 +1987,9 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, return isAngled; } -void Preprocessor::GetLineDirectiveFilenameSpelling(SourceLocation Loc, - StringRef &Buffer) { +void Preprocessor::GetLineDirectiveFilenameSpelling( + SourceLocation Loc, StringRef &Buffer, + SmallVectorImpl<char> &UnescapedBuffer) { // Get the text form of the filename. assert(!Buffer.empty() && "Can't have tokens with empty spellings!"); if (Buffer.size() < 2 || Buffer.front() != '"' || Buffer.back() != '"') { @@ -1993,6 +1998,21 @@ void Preprocessor::GetLineDirectiveFilenameSpelling(SourceLocation Loc, return; } Buffer = Buffer.substr(1, Buffer.size() - 2); + + // A line directive filename is lexed as a header-name so that backslashes + // in paths are not interpreted as escape sequences. However, a doubled + // backslash represents a single backslash in the resulting filename. + if (!Buffer.contains("\\\\")) + return; + + UnescapedBuffer.clear(); + UnescapedBuffer.reserve(Buffer.size()); + for (size_t I = 0; I < Buffer.size(); ++I) { + if (Buffer[I] == '\\' && I + 1 < Buffer.size() && Buffer[I + 1] == '\\') + ++I; + UnescapedBuffer.push_back(Buffer[I]); + } + Buffer = StringRef(UnescapedBuffer.data(), UnescapedBuffer.size()); } /// Push a token onto the token stream containing an annotation. diff --git a/clang/test/Preprocessor/line-directive-backslash.c b/clang/test/Preprocessor/line-directive-backslash.c new file mode 100644 index 0000000000000..801c249eebcc7 --- /dev/null +++ b/clang/test/Preprocessor/line-directive-backslash.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -E -P %s | FileCheck %s + +#line 10 "not_a_\\tab" +const char *escaped_backslash = __FILE__; +// CHECK: const char *escaped_backslash = "not_a_\\tab"; + +#line 20 "c:\moo\zar\haz.h" +const char *windows_path = __FILE__; +// CHECK: const char *windows_path = "c:\\moo\\zar\\haz.h"; + +#line 30 "original\x12source.c" +const char *non_escape = __FILE__; +// CHECK: const char *non_escape = "original\\x12source.c"; + +# 40 "gnu_\\path" +const char *gnu_line_marker = __FILE__; +// CHECK: const char *gnu_line_marker = "gnu_\\path"; `````````` </details> https://github.com/llvm/llvm-project/pull/215992 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
