Author: Abhina Sree
Date: 2026-06-29T08:17:07-04:00
New Revision: 2fbe136ff25870ce61af0331704409e8c69a3ce9

URL: 
https://github.com/llvm/llvm-project/commit/2fbe136ff25870ce61af0331704409e8c69a3ce9
DIFF: 
https://github.com/llvm/llvm-project/commit/2fbe136ff25870ce61af0331704409e8c69a3ce9.diff

LOG: Line and digit directives, OriginalFileName, ModuleName should be 
unevaluated strings (#201413)

Based on
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2361r6.pdf,
line and digit directives should be unevaluated strings. This patch
changes the HandleLineDirective and HandleDigitDirective to parse
strings as unevaluated string literals and fixes the testcase to not
have escape sequences.

Added: 
    clang/test/Frontend/linemarker-invalid-escape.c

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Frontend/FrontendAction.cpp
    clang/lib/Lex/PPDirectives.cpp
    clang/lib/Lex/Pragma.cpp
    clang/test/Preprocessor/line-directive-output.c
    clang/test/Preprocessor/line-directive.c
    clang/test/Preprocessor/pragma_module.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 837e86d357129..5390abe7cb90a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -71,6 +71,17 @@ C/C++ Language Potentially Breaking Changes
   Clang would previously ``break`` out of the ``while`` loop, whereas GCC 
(since version 9) would
   ``break`` out of the ``for`` loop here. Now, Clang and GCC both break out of 
the ``for`` loop.
 
+- Clang now parses line and digit directives, module names, and original 
filenames as unevaluated
+  strings. This means that code containing strings with escape sequences such 
as
+
+  .. code-block:: c++
+
+    # 1 "original\x12source.c"
+    #pragma clang module import "\x41"
+    # 50 "a\012.c"
+
+  are now ill-formed.
+
 C++ Specific Potentially Breaking Changes
 -----------------------------------------
 

diff  --git a/clang/lib/Frontend/FrontendAction.cpp 
b/clang/lib/Frontend/FrontendAction.cpp
index 7754861fabaf0..55e3877384622 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -525,7 +525,8 @@ static SourceLocation ReadOriginalFileName(CompilerInstance 
&CI,
   if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
     return SourceLocation();
 
-  StringLiteralParser Literal(T, CI.getPreprocessor());
+  StringLiteralParser Literal(T, CI.getPreprocessor(),
+                              StringLiteralEvalMethod::Unevaluated);
   if (Literal.hadError)
     return SourceLocation();
   RawLexer->LexFromRawLexer(T);

diff  --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index eb21a510dcf83..20f2575254e7b 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1646,7 +1646,8 @@ void Preprocessor::HandleLineDirective() {
     return;
   } else {
     // Parse and validate the string, converting it into a unique ID.
-    StringLiteralParser Literal(StrTok, *this);
+    StringLiteralParser Literal(StrTok, *this,
+                                StringLiteralEvalMethod::Unevaluated);
     assert(Literal.isOrdinary() && "Didn't allow wide strings in");
     if (Literal.hadError) {
       DiscardUntilEndOfDirective();
@@ -1797,7 +1798,8 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) {
     return;
   } else {
     // Parse and validate the string, converting it into a unique ID.
-    StringLiteralParser Literal(StrTok, *this);
+    StringLiteralParser Literal(StrTok, *this,
+                                StringLiteralEvalMethod::Unevaluated);
     assert(Literal.isOrdinary() && "Didn't allow wide strings in");
     if (Literal.hadError) {
       DiscardUntilEndOfDirective();

diff  --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index 60577ef77dba7..9b48a45ade668 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -779,7 +779,7 @@ static bool LexModuleNameComponent(Preprocessor &PP, Token 
&Tok,
                                    bool First) {
   PP.LexUnexpandedToken(Tok);
   if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) {
-    StringLiteralParser Literal(Tok, PP);
+    StringLiteralParser Literal(Tok, PP, StringLiteralEvalMethod::Unevaluated);
     if (Literal.hadError)
       return true;
     ModuleNameComponent = IdentifierLoc(

diff  --git a/clang/test/Frontend/linemarker-invalid-escape.c 
b/clang/test/Frontend/linemarker-invalid-escape.c
new file mode 100644
index 0000000000000..a8239f81f152d
--- /dev/null
+++ b/clang/test/Frontend/linemarker-invalid-escape.c
@@ -0,0 +1,5 @@
+// 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/Preprocessor/line-directive-output.c 
b/clang/test/Preprocessor/line-directive-output.c
index 5e3dec155cad4..0e66487bd20c9 100644
--- a/clang/test/Preprocessor/line-directive-output.c
+++ b/clang/test/Preprocessor/line-directive-output.c
@@ -76,7 +76,7 @@ extern int z;
 # 49 "A.c"
 
 // CHECK: # 50 "a\n.c"
-# 50 "a\012.c"
+# 50 "a\n.c"
 
 # 1 "system.h" 3
 # 2

diff  --git a/clang/test/Preprocessor/line-directive.c 
b/clang/test/Preprocessor/line-directive.c
index 676e07a5571ab..4fb05a4ea2f6e 100644
--- a/clang/test/Preprocessor/line-directive.c
+++ b/clang/test/Preprocessor/line-directive.c
@@ -125,3 +125,8 @@ undefined t; // expected-error {{unknown type name 
'undefined'}}
 # 121 "" 2 // pop to "main": expected-warning {{this style of line directive 
is a GNU extension}}
 #error MAIN2
 // 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}}
+# 131 U"hello" // expected-error {{invalid filename for line marker directive}}
+# 132 "\x13" // expected-error {{invalid escape sequence '\x13' in an 
unevaluated string literal}}

diff  --git a/clang/test/Preprocessor/pragma_module.c 
b/clang/test/Preprocessor/pragma_module.c
index 2d86b989411fd..b3b2e5f3bbcc1 100644
--- a/clang/test/Preprocessor/pragma_module.c
+++ b/clang/test/Preprocessor/pragma_module.c
@@ -12,6 +12,8 @@
 #pragma clang module import foo ? bar // expected-warning {{extra tokens at 
end of #pragma}}
 #pragma clang module import foo. // expected-error {{expected identifier after 
'.' in module name}}
 #pragma clang module import foo.bar.baz.quux // expected-error {{no submodule 
named 'bar' in module 'foo'}}
+#pragma clang module import "\x41" // expected-error {{invalid escape sequence 
'\x41' in an unevaluated string literal}}
+#pragma clang module import "foo"."\x41" // expected-error {{invalid escape 
sequence '\x41' in an unevaluated string literal}}
 
 #pragma clang module begin ! // expected-error {{expected module name}}
 


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

Reply via email to