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
