https://github.com/cor3ntin created 
https://github.com/llvm/llvm-project/pull/211512

We treated line directives as being unevaluated string literal. However
  - The standard has no such restriction - or rather the standard has 
different, unclear restriction (wg21.link/P2693)
  - Because of Windows paths, it's common for "C:\foo\bar" to be used, and 
these should not form escape sequences.

To remain consistent with other implementations, we do not allow `#line 1 <>` 
at this time. We do however support `#line 1 ""` to avoid a breaking change.

Fixes a regression introduced by #201413

>From 5498ac5dac4b6753a224cff8df46896cd391c38b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <[email protected]>
Date: Thu, 23 Jul 2026 11:51:19 +0200
Subject: [PATCH] [Clang] Treat line directives as header names.

We treated line directives as being unevaluated string literal.
However
  - The standard has no such restriction - or rather the standard has
    different, unclear restriction (wg21.link/P2693)
  - Because of Windows paths, it's common for "C:\foo\bar" to be used,
    and these should not form escape sequences.

To remain consistent with other implementations, we do not allow `#line 1 <>`
at this time. We do however support `#line 1 ""` to avoid a breaking change.

Fix a regression introduced by #201413
---
 clang/lib/Lex/PPDirectives.cpp                | 70 ++++++++-----------
 .../test/Frontend/linemarker-invalid-escape.c |  5 --
 .../Parser/cxx11-user-defined-literals.cpp    |  4 +-
 .../test/Preprocessor/line-directive-output.c | 14 +++-
 clang/test/Preprocessor/line-directive.c      |  4 +-
 5 files changed, 45 insertions(+), 52 deletions(-)
 delete mode 100644 clang/test/Frontend/linemarker-invalid-escape.c

diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index c161f6a03593e..46649eae044b2 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1599,6 +1599,21 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val,
   return false;
 }
 
+// Unlike header-names, line directive only support filenames in double quotes
+// but does support empty filenames.
+static void GetFilenameSpellingForLineDirective(const Preprocessor &PP,
+                                                SourceLocation Loc,
+                                                StringRef &Buffer) {
+  // 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() != '"') {
+    PP.Diag(Loc, diag::err_pp_line_invalid_filename);
+    Buffer = StringRef();
+    return;
+  }
+  Buffer = Buffer.substr(1, Buffer.size() - 2);
+}
+
 /// Handle a \#line directive: C99 6.10.4.
 ///
 /// The two acceptable forms are:
@@ -1632,35 +1647,21 @@ void Preprocessor::HandleLineDirective() {
 
   int FilenameID = -1;
   Token StrTok;
-  Lex(StrTok);
+  LexHeaderName(StrTok);
 
   // If the StrTok is "eod", then it wasn't present.  Otherwise, it must be a
   // string followed by eod.
   if (StrTok.is(tok::eod))
     ; // ok
-  else if (StrTok.isNot(tok::string_literal)) {
+  else if (StrTok.isNot(tok::header_name)) {
     Diag(StrTok, diag::err_pp_line_invalid_filename);
     DiscardUntilEndOfDirective();
     return;
-  } else if (StrTok.hasUDSuffix()) {
-    Diag(StrTok, diag::err_invalid_string_udl);
-    DiscardUntilEndOfDirective();
-    return;
   } else {
-    // Parse and validate the string, converting it into a unique ID.
-    StringLiteralParser Literal(StrTok, *this,
-                                StringLiteralEvalMethod::Unevaluated);
-    assert(Literal.isOrdinary() && "Didn't allow wide strings in");
-    if (Literal.hadError) {
-      DiscardUntilEndOfDirective();
-      return;
-    }
-    if (Literal.Pascal) {
-      Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
-      DiscardUntilEndOfDirective();
-      return;
-    }
-    FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
+    SmallString<128> FilenameBuffer;
+    StringRef Filename = getSpelling(StrTok, FilenameBuffer);
+    GetFilenameSpellingForLineDirective(*this, StrTok.getLocation(), Filename);
+    FilenameID = SourceMgr.getLineTableFilenameID(Filename);
 
     // Verify that there is nothing after the string, other than EOD.  Because
     // of C99 6.10.4p5, macros that expand to empty tokens are ok.
@@ -1778,7 +1779,7 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
     return;
 
   Token StrTok;
-  Lex(StrTok);
+  LexHeaderName(StrTok);
 
   bool IsFileEntry = false, IsFileExit = false;
   int FilenameID = -1;
@@ -1790,29 +1791,14 @@ void Preprocessor::HandleDigitDirective(Token 
&DigitTok) {
     Diag(StrTok, diag::ext_pp_gnu_line_directive);
     // Treat this like "#line NN", which doesn't change file characteristics.
     FileKind = SourceMgr.getFileCharacteristic(DigitTok.getLocation());
-  } else if (StrTok.isNot(tok::string_literal)) {
+  } else if (StrTok.isNot(tok::header_name)) {
     Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
     DiscardUntilEndOfDirective();
     return;
-  } else if (StrTok.hasUDSuffix()) {
-    Diag(StrTok, diag::err_invalid_string_udl);
-    DiscardUntilEndOfDirective();
-    return;
   } else {
-    // Parse and validate the string, converting it into a unique ID.
-    StringLiteralParser Literal(StrTok, *this,
-                                StringLiteralEvalMethod::Unevaluated);
-    assert(Literal.isOrdinary() && "Didn't allow wide strings in");
-    if (Literal.hadError) {
-      DiscardUntilEndOfDirective();
-      return;
-    }
-    if (Literal.Pascal) {
-      Diag(StrTok, diag::err_pp_linemarker_invalid_filename);
-      DiscardUntilEndOfDirective();
-      return;
-    }
-
+    SmallString<128> FilenameBuffer;
+    StringRef Filename = getSpelling(StrTok, FilenameBuffer);
+    GetFilenameSpellingForLineDirective(*this, StrTok.getLocation(), Filename);
     // If a filename was present, read any flags that are present.
     if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this))
       return;
@@ -1821,8 +1807,8 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
 
     // Exiting to an empty string means pop to the including file, so leave
     // FilenameID as -1 in that case.
-    if (!(IsFileExit && Literal.GetString().empty()))
-      FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString());
+    if (!(IsFileExit && Filename.empty()))
+      FilenameID = SourceMgr.getLineTableFilenameID(Filename);
   }
 
   // Create a line note with this information.
diff --git a/clang/test/Frontend/linemarker-invalid-escape.c 
b/clang/test/Frontend/linemarker-invalid-escape.c
deleted file mode 100644
index a8239f81f152d..0000000000000
--- a/clang/test/Frontend/linemarker-invalid-escape.c
+++ /dev/null
@@ -1,5 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -o - -verify %s
-
-# 1 "original\x12source.c" // expected-error {{invalid escape sequence '\x12' 
in an unevaluated string literal}}
-
-int x = 0;
diff --git a/clang/test/Parser/cxx11-user-defined-literals.cpp 
b/clang/test/Parser/cxx11-user-defined-literals.cpp
index 968868509de19..6c15b8133b86f 100644
--- a/clang/test/Parser/cxx11-user-defined-literals.cpp
+++ b/clang/test/Parser/cxx11-user-defined-literals.cpp
@@ -3,8 +3,8 @@
 // A ud-suffix cannot be used on string literals in a whole bunch of contexts:
 
 #include "foo"_bar // expected-error {{expected "FILENAME" or <FILENAME>}}
-#line 1 "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
-# 1 "foo"_bar 1 // expected-error {{user-defined suffix cannot be used here}}
+#line 1 "foo"_bar // expected-error {{invalid filename for #line directive}}
+# 1 "foo"_bar 1 // expected-error {{invalid filename for #line directive}}
 #ident "foo"_bar // expected-error {{user-defined suffix cannot be used here}}
 _Pragma("foo"_bar) // expected-error {{user-defined suffix cannot be used 
here}}
 #pragma comment(lib, "foo"_bar) // expected-error {{user-defined suffix cannot 
be used here}}
diff --git a/clang/test/Preprocessor/line-directive-output.c 
b/clang/test/Preprocessor/line-directive-output.c
index 0e66487bd20c9..7774cc7c9cb31 100644
--- a/clang/test/Preprocessor/line-directive-output.c
+++ b/clang/test/Preprocessor/line-directive-output.c
@@ -75,9 +75,21 @@ extern int z;
 # 44 "A.c"
 # 49 "A.c"
 
-// CHECK: # 50 "a\n.c"
+// CHECK: # 50 "a\\n.c"
 # 50 "a\n.c"
 
+// CHECK: # 1 "c:\\moo\\zar\\haz.h"
+#line 1 "c:\moo\zar\haz.h"
+
+// CHECK # 1 "original\x12source.c"
+# 1 "original\x12source.c"
+
+// CHECK # 1 "original\u1234"
+# 1 "original\u1234"
+
+// CHECK # 1 "original\u{1234}"
+# 1 "original\u{1234}"
+
 # 1 "system.h" 3
 # 2
 void sys_foo(void);
diff --git a/clang/test/Preprocessor/line-directive.c 
b/clang/test/Preprocessor/line-directive.c
index 4fb05a4ea2f6e..530ddd686fdc8 100644
--- a/clang/test/Preprocessor/line-directive.c
+++ b/clang/test/Preprocessor/line-directive.c
@@ -127,6 +127,6 @@ undefined t; // expected-error {{unknown type name 
'undefined'}}
 // expected-error@-1{{MAIN2}}
 
 #line 129 L"wide" // expected-error {{invalid filename for #line directive}}
-#line 130 "\x12" // expected-error {{invalid escape sequence '\x12' in an 
unevaluated string literal}}
+#line 130 "\x12"
 # 131 U"hello" // expected-error {{invalid filename for line marker directive}}
-# 132 "\x13" // expected-error {{invalid escape sequence '\x13' in an 
unevaluated string literal}}
+# 132 "\x13" // expected-warning {{this style of line directive is a GNU 
extension}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to