https://github.com/catlover-bot updated https://github.com/llvm/llvm-project/pull/215992
>From b3987a24186f90dedb6c4aa9def2ed53c92d1fd0 Mon Sep 17 00:00:00 2001 From: Hirotaka Monya <[email protected]> Date: Mon, 17 Aug 2026 00:45:17 +0900 Subject: [PATCH] [Clang] Unescape doubled backslashes in #line filenames Assisted-by: GPT-5.6 Sol --- clang/include/clang/Lex/Preprocessor.h | 5 +++- clang/lib/Frontend/FrontendAction.cpp | 4 ++- clang/lib/Lex/PPDirectives.cpp | 28 ++++++++++++++++--- .../Preprocessor/line-directive-backslash.c | 17 +++++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) create mode 100644 clang/test/Preprocessor/line-directive-backslash.c 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"; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
