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

Reply via email to