https://github.com/abhina-sree updated https://github.com/llvm/llvm-project/pull/169803
>From 428436d0c27c5108d4a9245c6a4f7ead1e676cd7 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Fri, 8 May 2026 12:17:22 -0400 Subject: [PATCH 01/14] add ParserConversionAction, do not translate unevaluated strings --- clang/include/clang/Parse/Parser.h | 1 + clang/include/clang/Sema/Sema.h | 4 +++- clang/lib/Parse/ParseDecl.cpp | 9 +++++++++ clang/lib/Parse/ParseExpr.cpp | 6 +++--- clang/lib/Parse/Parser.cpp | 4 ++++ clang/lib/Sema/SemaExpr.cpp | 8 ++++---- clang/test/CodeGen/systemz-charset-diag.cpp | 8 ++++++++ clang/test/CodeGen/systemz-charset.c | 5 +++++ 8 files changed, 37 insertions(+), 8 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5237d767affdd0..24b012b0503523 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -5762,6 +5762,7 @@ class Parser : public CodeCompletionHandler { bool Finished; }; ObjCImplParsingDataRAII *CurParsedObjCImpl; + ConversionAction ParserConversionAction; /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them /// for later parsing. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 0d207679d1f4d8..a15811c40f2237 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -54,6 +54,7 @@ #include "clang/Basic/StackExhaustionHandler.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TokenKinds.h" +#include "clang/Lex/TextEncoding.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/Attr.h" #include "clang/Sema/CleanupInfo.h" @@ -7439,7 +7440,8 @@ class Sema final : public SemaBase { /// from multiple tokens. However, the common case is that StringToks points /// to one string. ExprResult ActOnStringLiteral(ArrayRef<Token> StringToks, - Scope *UDLScope = nullptr); + Scope *UDLScope = nullptr, + ConversionAction Action = CA_ToLiteralEncoding); ExprResult ActOnUnevaluatedStringLiteral(ArrayRef<Token> StringToks); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index ada54c85695c34..e5fee9f956d211 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -586,6 +586,9 @@ unsigned Parser::ParseAttributeArgsCommon( nullptr, Sema::ExpressionEvaluationContextRecord::EK_AttrArgument); + SaveAndRestore<ConversionAction> SavedTranslationState( + ParserConversionAction, CA_NoConversion); + ExprResult ArgExpr = ParseAssignmentExpression(); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); @@ -666,6 +669,9 @@ void Parser::ParseGNUAttributeArgs( ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax()); + SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, + CA_NoConversion); + if (AttrKind == ParsedAttr::AT_Availability) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Form); @@ -745,6 +751,9 @@ unsigned Parser::ParseClangAttributeArgs( ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax()); + SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, + CA_NoConversion); + switch (AttrKind) { default: return ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index d42ffc2ccf0a65..68af97fad5c4ae 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3044,9 +3044,9 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral, } // Pass the set of string tokens, ready for concatenation, to the actions. - return Actions.ActOnStringLiteral(StringToks, - AllowUserDefinedLiteral ? getCurScope() - : nullptr); + return Actions.ActOnStringLiteral( + StringToks, AllowUserDefinedLiteral ? getCurScope() : nullptr, + ParserConversionAction); } ExprResult Parser::ParseGenericSelectionExpression() { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index f0f4c7195381e5..c334cd62ee256e 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -82,6 +82,8 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) NumCachedScopes = 0; CurParsedObjCImpl = nullptr; + ParserConversionAction = CA_ToLiteralEncoding; + // Add #pragma handlers. These are removed and destroyed in the // destructor. initializePragmaHandlers(); @@ -1564,6 +1566,8 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { } ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { + SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, + CA_NoConversion); ExprResult AsmString; if (isTokenStringLiteral()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 00dd8acf1f68dd..cd1416a724e754 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2264,8 +2264,8 @@ Sema::ExpandFunctionLocalPredefinedMacros(ArrayRef<Token> Toks) { return ExpandedToks; } -ExprResult -Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { +ExprResult Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope, + ConversionAction Action) { assert(!StringToks.empty() && "Must have at least one string!"); // StringToks needs backing storage as it doesn't hold array elements itself @@ -2273,8 +2273,8 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { if (getLangOpts().MicrosoftExt) StringToks = ExpandedToks = ExpandFunctionLocalPredefinedMacros(StringToks); - StringLiteralParser Literal( - StringToks, PP, StringLiteralEvalMethod::Evaluated, CA_ToLiteralEncoding); + StringLiteralParser Literal(StringToks, PP, + StringLiteralEvalMethod::Evaluated, Action); if (Literal.hadError) return ExprError(); diff --git a/clang/test/CodeGen/systemz-charset-diag.cpp b/clang/test/CodeGen/systemz-charset-diag.cpp index 4ed94810150a3a..ad08e1f3912149 100644 --- a/clang/test/CodeGen/systemz-charset-diag.cpp +++ b/clang/test/CodeGen/systemz-charset-diag.cpp @@ -1,3 +1,11 @@ // RUN: %clang_cc1 -triple s390x-none-zos -fexec-charset IBM-1047 %s -std=c++17 -emit-llvm -o - -verify const char* Computer = "🖥️"; // expected-error-re {{conversion to literal encoding failed: {{.*}}}} + +static_assert(false, "Error string"); // expected-error {{static assertion failed: Error string}} + +[[deprecated("message")]] void test_deprecated() {return;} // expected-note {{'test_deprecated' has been explicitly marked deprecated here}} + +int main() { + test_deprecated(); // expected-warning {{'test_deprecated' is deprecated: message}} +} diff --git a/clang/test/CodeGen/systemz-charset.c b/clang/test/CodeGen/systemz-charset.c index e1dc1ec2dc23a9..fd81110f5f6c70 100644 --- a/clang/test/CodeGen/systemz-charset.c +++ b/clang/test/CodeGen/systemz-charset.c @@ -66,3 +66,8 @@ const char* hello_macro = HELLO; const char* preprocessor_concatenation = HELLO_WORLD; //CHECK: c"\C8\85\93\93\96@\E6\96\99\93\84Z\00" //CHECK-UTF8: c"Hello World!\00" + +void asm_labeled_fn(void) __asm__("asm_sym"); +void asm_labeled_fn(void) {} +//CHECK: define{{.*}} void @asm_sym( +//CHECK-UTF8: define{{.*}} void @asm_sym( >From 275e5eb1aac06849962a6d43b73a5b7b0b86f4ff Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Fri, 3 Jul 2026 14:52:22 -0400 Subject: [PATCH 02/14] remove unnecessary changes --- clang/lib/Parse/ParseDecl.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e5fee9f956d211..ada54c85695c34 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -586,9 +586,6 @@ unsigned Parser::ParseAttributeArgsCommon( nullptr, Sema::ExpressionEvaluationContextRecord::EK_AttrArgument); - SaveAndRestore<ConversionAction> SavedTranslationState( - ParserConversionAction, CA_NoConversion); - ExprResult ArgExpr = ParseAssignmentExpression(); if (ArgExpr.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); @@ -669,9 +666,6 @@ void Parser::ParseGNUAttributeArgs( ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax()); - SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, - CA_NoConversion); - if (AttrKind == ParsedAttr::AT_Availability) { ParseAvailabilityAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Form); @@ -751,9 +745,6 @@ unsigned Parser::ParseClangAttributeArgs( ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax()); - SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, - CA_NoConversion); - switch (AttrKind) { default: return ParseAttributeArgsCommon(AttrName, AttrNameLoc, Attrs, EndLoc, >From e2bc4da52621b79a237622f95f26aa319715a389 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Thu, 9 Jul 2026 13:25:39 -0400 Subject: [PATCH 03/14] remove ParserConversionAction, add paramter to ParseStringLiteralExpression instead, add conversion to SystemCharset then back to UTF8 to handle escape sequences in system encoding --- clang/include/clang/Basic/TargetInfo.h | 3 ++ clang/include/clang/Lex/TextEncoding.h | 11 ++++++-- clang/include/clang/Parse/Parser.h | 6 ++-- clang/lib/Basic/TargetInfo.cpp | 2 ++ clang/lib/Frontend/CompilerInstance.cpp | 4 +-- clang/lib/Lex/TextEncoding.cpp | 37 +++++++++++++++++++++---- clang/lib/Parse/ParseExpr.cpp | 6 ++-- clang/lib/Parse/Parser.cpp | 8 ++---- clang/lib/Sema/SemaStmtAsm.cpp | 8 ++++++ clang/test/CodeGen/systemz-charset.c | 6 ++-- 10 files changed, 67 insertions(+), 24 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index a6523e8eaaa437..f073d98408b211 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -37,6 +37,7 @@ #include "llvm/Frontend/OpenMP/OMPGridValues.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" +#include "llvm/Support/TextEncoding.h" #include "llvm/Support/VersionTuple.h" #include "llvm/TargetParser/Triple.h" #include <cassert> @@ -330,6 +331,8 @@ class TargetInfo : public TransferrableTargetInfo, virtual ~TargetInfo(); + std::unique_ptr<llvm::TextEncodingConverter> TargetStrConverter; + /// Retrieve the target options. TargetOptions &getTargetOpts() const { assert(TargetOpts && "Missing target options"); diff --git a/clang/include/clang/Lex/TextEncoding.h b/clang/include/clang/Lex/TextEncoding.h index 55663cdc072daa..02cb16cef9f1ba 100644 --- a/clang/include/clang/Lex/TextEncoding.h +++ b/clang/include/clang/Lex/TextEncoding.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_LEX_TEXTENCODING_H #include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringRef.h" namespace llvm { @@ -17,16 +18,22 @@ class TextEncodingConverter; } // namespace llvm namespace clang { -enum ConversionAction { CA_NoConversion, CA_ToLiteralEncoding }; +enum ConversionAction { + CA_NoConversion, + CA_ToSystemEncoding, + CA_ToLiteralEncoding +}; class TextEncoding { llvm::StringRef LiteralEncoding; std::unique_ptr<llvm::TextEncodingConverter> ToLiteralEncodingConverter; + std::unique_ptr<llvm::TextEncodingConverter> ToSystemEncodingConverter; public: llvm::TextEncodingConverter *getConverter(ConversionAction Action) const; static std::error_code - setConvertersFromOptions(TextEncoding &TE, const clang::LangOptions &Opts); + setConvertersFromOptions(TextEncoding &TE, const clang::LangOptions &Opts, + clang::TargetInfo &TInfo); llvm::StringRef getLiteralEncoding() { return LiteralEncoding; } }; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 24b012b0503523..5268a7eeb911ea 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3893,8 +3893,9 @@ class Parser : public CodeCompletionHandler { /// associated with the class's definition. void PopParsingClass(Sema::ParsingClassState); - ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral, - bool Unevaluated); + ExprResult + ParseStringLiteralExpression(bool AllowUserDefinedLiteral, bool Unevaluated, + ConversionAction CA = CA_ToLiteralEncoding); /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This @@ -5762,7 +5763,6 @@ class Parser : public CodeCompletionHandler { bool Finished; }; ObjCImplParsingDataRAII *CurParsedObjCImpl; - ConversionAction ParserConversionAction; /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them /// for later parsing. diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 6e390226d2e4b8..488c3c5c28a74f 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -201,6 +201,8 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { MaxOpenCLWorkGroupSize = 1024; MaxBitIntWidth.reset(); + + TargetStrConverter = nullptr; } // Out of line virtual dtor for TargetInfo. diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index f122208d6b4c8b..8c255c317f0a1e 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -568,8 +568,8 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { if (GetDependencyDirectives) PP->setDependencyDirectivesGetter(*GetDependencyDirectives); - if (auto EC = TextEncoding::setConvertersFromOptions(PP->getTextEncoding(), - getLangOpts())) + if (auto EC = TextEncoding::setConvertersFromOptions( + PP->getTextEncoding(), getLangOpts(), getTarget())) PP->getDiagnostics().Report(clang::diag::err_fe_text_encoding_config) << PP->getTextEncoding().getLiteralEncoding(); } diff --git a/clang/lib/Lex/TextEncoding.cpp b/clang/lib/Lex/TextEncoding.cpp index eb4fde8928a688..effd05185faf7f 100644 --- a/clang/lib/Lex/TextEncoding.cpp +++ b/clang/lib/Lex/TextEncoding.cpp @@ -17,6 +17,8 @@ TextEncoding::getConverter(ConversionAction Action) const { switch (Action) { case CA_ToLiteralEncoding: return ToLiteralEncodingConverter.get(); + case CA_ToSystemEncoding: + return ToSystemEncodingConverter.get(); default: return nullptr; } @@ -24,23 +26,46 @@ TextEncoding::getConverter(ConversionAction Action) const { std::error_code TextEncoding::setConvertersFromOptions(TextEncoding &TE, - const clang::LangOptions &Opts) { + const clang::LangOptions &Opts, + clang::TargetInfo &TInfo) { using namespace llvm; const char *UTF8 = "UTF-8"; TE.LiteralEncoding = Opts.LiteralEncoding.empty() ? UTF8 : Opts.LiteralEncoding.c_str(); - // Create converter between internal and literal encoding specified - // in fexec-charset option. - if (TE.LiteralEncoding == UTF8) + if (TE.LiteralEncoding != UTF8) { + ErrorOr<TextEncodingConverter> ErrorOrLiteralConverter = + llvm::TextEncodingConverter::create(UTF8, TE.LiteralEncoding); + if (ErrorOrLiteralConverter) + TE.ToLiteralEncodingConverter = std::make_unique<TextEncodingConverter>( + std::move(*ErrorOrLiteralConverter)); + else + return ErrorOrLiteralConverter.getError(); + } + + if (TInfo.getDefaultOrdinaryLiteralEncoding() == UTF8) return std::error_code(); + + // Create converter between internal and default ordinary encoding for the + // target ErrorOr<TextEncodingConverter> ErrorOrConverter = - llvm::TextEncodingConverter::create(UTF8, TE.LiteralEncoding); + llvm::TextEncodingConverter::create( + UTF8, TInfo.getDefaultOrdinaryLiteralEncoding()); + if (ErrorOrConverter) + TE.ToSystemEncodingConverter = + std::make_unique<TextEncodingConverter>(std::move(*ErrorOrConverter)); + else + return ErrorOrConverter.getError(); + + ErrorOrConverter = llvm::TextEncodingConverter::create( + TInfo.getDefaultOrdinaryLiteralEncoding(), UTF8); + if (ErrorOrConverter) - TE.ToLiteralEncodingConverter = + TInfo.TargetStrConverter = std::make_unique<TextEncodingConverter>(std::move(*ErrorOrConverter)); else return ErrorOrConverter.getError(); + return std::error_code(); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 68af97fad5c4ae..45c4988f671dfd 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -3024,7 +3024,8 @@ ExprResult Parser::ParseUnevaluatedStringLiteralExpression() { } ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral, - bool Unevaluated) { + bool Unevaluated, + ConversionAction CA) { assert(tokenIsLikeStringLiteral(Tok, getLangOpts()) && "Not a string-literal-like token!"); @@ -3045,8 +3046,7 @@ ExprResult Parser::ParseStringLiteralExpression(bool AllowUserDefinedLiteral, // Pass the set of string tokens, ready for concatenation, to the actions. return Actions.ActOnStringLiteral( - StringToks, AllowUserDefinedLiteral ? getCurScope() : nullptr, - ParserConversionAction); + StringToks, AllowUserDefinedLiteral ? getCurScope() : nullptr, CA); } ExprResult Parser::ParseGenericSelectionExpression() { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index c334cd62ee256e..0eb02a45d89066 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -82,8 +82,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) NumCachedScopes = 0; CurParsedObjCImpl = nullptr; - ParserConversionAction = CA_ToLiteralEncoding; - // Add #pragma handlers. These are removed and destroyed in the // destructor. initializePragmaHandlers(); @@ -1566,12 +1564,12 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { } ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { - SaveAndRestore<ConversionAction> SavedTranslationState(ParserConversionAction, - CA_NoConversion); ExprResult AsmString; if (isTokenStringLiteral()) { - AsmString = ParseStringLiteralExpression(); + AsmString = ParseStringLiteralExpression(/*AllowUserDefinedLiteral=*/false, + /*Unevaluated=*/false, + CA_ToSystemEncoding); if (AsmString.isInvalid()) return AsmString; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index bf460ebe75ef10..bf11f9f5151097 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -245,6 +245,14 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) { Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string) << SL->getSourceRange(); } + if (Context.getTargetInfo().TargetStrConverter) { + SmallString<16> ConvertedAsm; + Context.getTargetInfo().TargetStrConverter->convert(SL->getString(), + ConvertedAsm); + return StringLiteral::Create(Context, ConvertedAsm, + StringLiteralKind::Ordinary, + /*Pascal*/ false, {}, SL->getBeginLoc()); + } return SL; } if (DiagnoseUnexpandedParameterPack(Expr)) diff --git a/clang/test/CodeGen/systemz-charset.c b/clang/test/CodeGen/systemz-charset.c index fd81110f5f6c70..eaa2747d9ce5f0 100644 --- a/clang/test/CodeGen/systemz-charset.c +++ b/clang/test/CodeGen/systemz-charset.c @@ -67,7 +67,7 @@ const char* preprocessor_concatenation = HELLO_WORLD; //CHECK: c"\C8\85\93\93\96@\E6\96\99\93\84Z\00" //CHECK-UTF8: c"Hello World!\00" -void asm_labeled_fn(void) __asm__("asm_sym"); +void asm_labeled_fn(void) __asm__("\174asm_sym"); void asm_labeled_fn(void) {} -//CHECK: define{{.*}} void @asm_sym( -//CHECK-UTF8: define{{.*}} void @asm_sym( +//CHECK: define{{.*}}void @"@asm_sym"( +//CHECK-UTF8: define{{.*}}void @"@asm_sym"( >From d664432d978c226dabbc470ebae76d7614139992 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Fri, 10 Jul 2026 15:07:07 -0400 Subject: [PATCH 04/14] address comments, attempt to fix CI --- clang/include/clang/Basic/TargetInfo.h | 2 +- clang/lib/Basic/TargetInfo.cpp | 2 +- clang/lib/Lex/TextEncoding.cpp | 2 +- clang/lib/Sema/SemaStmtAsm.cpp | 10 ++++++---- clang/test/CodeGen/systemz-charset.c | 4 ++++ 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index f073d98408b211..3c906d870e576e 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -331,7 +331,7 @@ class TargetInfo : public TransferrableTargetInfo, virtual ~TargetInfo(); - std::unique_ptr<llvm::TextEncodingConverter> TargetStrConverter; + std::unique_ptr<llvm::TextEncodingConverter> FromSystemEncodingConverter; /// Retrieve the target options. TargetOptions &getTargetOpts() const { diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 488c3c5c28a74f..09365d4f01b892 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -202,7 +202,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { MaxBitIntWidth.reset(); - TargetStrConverter = nullptr; + FromSystemEncodingConverter = nullptr; } // Out of line virtual dtor for TargetInfo. diff --git a/clang/lib/Lex/TextEncoding.cpp b/clang/lib/Lex/TextEncoding.cpp index effd05185faf7f..fd59f3df59bdfb 100644 --- a/clang/lib/Lex/TextEncoding.cpp +++ b/clang/lib/Lex/TextEncoding.cpp @@ -62,7 +62,7 @@ TextEncoding::setConvertersFromOptions(TextEncoding &TE, TInfo.getDefaultOrdinaryLiteralEncoding(), UTF8); if (ErrorOrConverter) - TInfo.TargetStrConverter = + TInfo.FromSystemEncodingConverter = std::make_unique<TextEncodingConverter>(std::move(*ErrorOrConverter)); else return ErrorOrConverter.getError(); diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index bf11f9f5151097..1399191418fcd5 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -245,13 +245,15 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) { Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string) << SL->getSourceRange(); } - if (Context.getTargetInfo().TargetStrConverter) { + if (Context.getTargetInfo().FromSystemEncodingConverter) { SmallString<16> ConvertedAsm; - Context.getTargetInfo().TargetStrConverter->convert(SL->getString(), - ConvertedAsm); + Context.getTargetInfo().FromSystemEncodingConverter->convert( + SL->getString(), ConvertedAsm); + QualType StrTy = Context.getStringLiteralArrayType(Context.CharTy, + ConvertedAsm.size()); return StringLiteral::Create(Context, ConvertedAsm, StringLiteralKind::Ordinary, - /*Pascal*/ false, {}, SL->getBeginLoc()); + /*Pascal*/ false, StrTy, SL->getBeginLoc()); } return SL; } diff --git a/clang/test/CodeGen/systemz-charset.c b/clang/test/CodeGen/systemz-charset.c index eaa2747d9ce5f0..db5a99b5eb3b72 100644 --- a/clang/test/CodeGen/systemz-charset.c +++ b/clang/test/CodeGen/systemz-charset.c @@ -71,3 +71,7 @@ void asm_labeled_fn(void) __asm__("\174asm_sym"); void asm_labeled_fn(void) {} //CHECK: define{{.*}}void @"@asm_sym"( //CHECK-UTF8: define{{.*}}void @"@asm_sym"( + +void asm_stmt_fn(void) { __asm__("\225\226\227nop"); } +//CHECK: call void asm{{.*}}"nopnop" +//CHECK-UTF8: call void asm{{.*}}"nopnop" >From f03fd41cb059a525e846cec2f7dc7938daf5ec2f Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Fri, 17 Jul 2026 14:31:50 -0400 Subject: [PATCH 05/14] check for UTF-8 to avoid conversion codepath if no conversion is needed --- clang/lib/Sema/SemaStmtAsm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 1399191418fcd5..3ec75dab8d84e4 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -245,7 +245,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) { Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string) << SL->getSourceRange(); } - if (Context.getTargetInfo().FromSystemEncodingConverter) { + if (Context.getTargetInfo().FromSystemEncodingConverter != nullptr) { SmallString<16> ConvertedAsm; Context.getTargetInfo().FromSystemEncodingConverter->convert( SL->getString(), ConvertedAsm); >From 96837dfd7036f28fdf40eee09b3920f4567f272c Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Tue, 11 Aug 2026 09:02:17 -0400 Subject: [PATCH 06/14] Remove unrelated testcases --- clang/test/CodeGen/systemz-charset-diag.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/clang/test/CodeGen/systemz-charset-diag.cpp b/clang/test/CodeGen/systemz-charset-diag.cpp index ad08e1f3912149..4ed94810150a3a 100644 --- a/clang/test/CodeGen/systemz-charset-diag.cpp +++ b/clang/test/CodeGen/systemz-charset-diag.cpp @@ -1,11 +1,3 @@ // RUN: %clang_cc1 -triple s390x-none-zos -fexec-charset IBM-1047 %s -std=c++17 -emit-llvm -o - -verify const char* Computer = "🖥️"; // expected-error-re {{conversion to literal encoding failed: {{.*}}}} - -static_assert(false, "Error string"); // expected-error {{static assertion failed: Error string}} - -[[deprecated("message")]] void test_deprecated() {return;} // expected-note {{'test_deprecated' has been explicitly marked deprecated here}} - -int main() { - test_deprecated(); // expected-warning {{'test_deprecated' is deprecated: message}} -} >From 84b75379950aa969912714ee27e653c2e5dc8c04 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Thu, 13 Aug 2026 14:18:12 -0400 Subject: [PATCH 07/14] constexpr in asm strings will be in fexec-charset, do not do backwards conversion for those strings --- clang/include/clang/Sema/Sema.h | 3 ++- clang/lib/Parse/Parser.cpp | 5 ++++- clang/lib/Sema/SemaStmtAsm.cpp | 6 ++++-- clang/test/CodeGen/systemz-charset.cpp | 24 ++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a15811c40f2237..778478f4723234 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11489,7 +11489,8 @@ class Sema final : public SemaBase { ///@{ public: - ExprResult ActOnGCCAsmStmtString(Expr *Stm, bool ForAsmLabel); + ExprResult ActOnGCCAsmStmtString(Expr *Stm, bool ForAsmLabel, + bool IsConstExpr = false); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 0eb02a45d89066..7fd9fe9dee0c76 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1566,6 +1566,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { ExprResult AsmString; + bool IsConstExpr = false; if (isTokenStringLiteral()) { AsmString = ParseStringLiteralExpression(/*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/false, @@ -1581,6 +1582,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { } } else if (!ForAsmLabel && getLangOpts().CPlusPlus11 && Tok.is(tok::l_paren)) { + IsConstExpr = true; ParenParseOption ExprType = ParenParseOption::SimpleExpr; SourceLocation RParenLoc; ParsedType CastTy; @@ -1600,7 +1602,8 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { (getLangOpts().CPlusPlus11 && !ForAsmLabel) ? 0 : 1); } - return Actions.ActOnGCCAsmStmtString(AsmString.get(), ForAsmLabel); + return Actions.ActOnGCCAsmStmtString(AsmString.get(), ForAsmLabel, + IsConstExpr); } ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) { diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 3ec75dab8d84e4..5a376a21e84733 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -235,7 +235,8 @@ getClobberConflictLocation(MultiExprArg Exprs, Expr **Constraints, return SourceLocation(); } -ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) { +ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel, + bool IsConstExpr) { if (!Expr) return ExprError(); @@ -245,7 +246,8 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel) { Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string) << SL->getSourceRange(); } - if (Context.getTargetInfo().FromSystemEncodingConverter != nullptr) { + if (!IsConstExpr && + Context.getTargetInfo().FromSystemEncodingConverter != nullptr) { SmallString<16> ConvertedAsm; Context.getTargetInfo().FromSystemEncodingConverter->convert( SL->getString(), ConvertedAsm); diff --git a/clang/test/CodeGen/systemz-charset.cpp b/clang/test/CodeGen/systemz-charset.cpp index 41674e9c11a640..6348fb72dac9a0 100644 --- a/clang/test/CodeGen/systemz-charset.cpp +++ b/clang/test/CodeGen/systemz-charset.cpp @@ -72,3 +72,27 @@ const char16_t *UnicodeUCNString16 = u"\u00E2\u00AC\U000000DF"; const char32_t *UnicodeUCNString32 = U"\u00E2\u00AC\U000000DF"; //CHECK: [4 x i32] [i32 226, i32 172, i32 223, i32 0] //CHECK-UTF8: [4 x i32] [i32 226, i32 172, i32 223, i32 0] + + +struct string_view { + int S; + const char* D; + constexpr string_view() : S(0), D(0){} + constexpr string_view(const char* Str) : S(__builtin_strlen(Str)), D(Str) {} + constexpr string_view(int Size, const char* Str) : S(Size), D(Str) {} + constexpr int size() const { + return S; + } + constexpr const char* data() const { + return D; + } +}; + +constexpr string_view getfoo() { return "\174foo"; } + +void function() +{ + asm((getfoo())); +} +// CHECK: asm{{.*}}|\86\96\96 +// CHECK-UTF8: asm{{.*}}|foo >From 897d1978004be27dc60cb932fd2efa812a05717c Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Wed, 30 Sep 2026 11:52:59 -0400 Subject: [PATCH 08/14] rename FromSystemEncodingConverter and move out of TargetInfo --- clang/include/clang/Basic/TargetInfo.h | 3 --- clang/include/clang/Lex/TextEncoding.h | 14 +++++++++++++- clang/lib/Basic/TargetInfo.cpp | 2 -- clang/lib/Lex/TextEncoding.cpp | 19 +++++++++++++------ clang/lib/Sema/SemaStmtAsm.cpp | 8 +++++--- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 3c906d870e576e..a6523e8eaaa437 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -37,7 +37,6 @@ #include "llvm/Frontend/OpenMP/OMPGridValues.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Error.h" -#include "llvm/Support/TextEncoding.h" #include "llvm/Support/VersionTuple.h" #include "llvm/TargetParser/Triple.h" #include <cassert> @@ -331,8 +330,6 @@ class TargetInfo : public TransferrableTargetInfo, virtual ~TargetInfo(); - std::unique_ptr<llvm::TextEncodingConverter> FromSystemEncodingConverter; - /// Retrieve the target options. TargetOptions &getTargetOpts() const { assert(TargetOpts && "Missing target options"); diff --git a/clang/include/clang/Lex/TextEncoding.h b/clang/include/clang/Lex/TextEncoding.h index 02cb16cef9f1ba..ec826ec6615922 100644 --- a/clang/include/clang/Lex/TextEncoding.h +++ b/clang/include/clang/Lex/TextEncoding.h @@ -27,10 +27,22 @@ enum ConversionAction { class TextEncoding { llvm::StringRef LiteralEncoding; std::unique_ptr<llvm::TextEncodingConverter> ToLiteralEncodingConverter; - std::unique_ptr<llvm::TextEncodingConverter> ToSystemEncodingConverter; + + // Only non-null on z/OS, where the system default encoding is IBM-1047. + // This converts UTF-8 to IBM-1047 for asm string literals so that + // octal/hex escape sequences are interpreted as IBM-1047 code points, + // regardless of -fexec-charset. + std::unique_ptr<llvm::TextEncodingConverter> ToIBM1047Converter; + std::unique_ptr<llvm::TextEncodingConverter> FromIBM1047Converter; public: llvm::TextEncodingConverter *getConverter(ConversionAction Action) const; + + /// Returns the converter from IBM-1047 to UTF-8, or nullptr if not on z/OS. + llvm::TextEncodingConverter *getFromIBM1047Converter() const { + return FromIBM1047Converter.get(); + } + static std::error_code setConvertersFromOptions(TextEncoding &TE, const clang::LangOptions &Opts, clang::TargetInfo &TInfo); diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 09365d4f01b892..6e390226d2e4b8 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -201,8 +201,6 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { MaxOpenCLWorkGroupSize = 1024; MaxBitIntWidth.reset(); - - FromSystemEncodingConverter = nullptr; } // Out of line virtual dtor for TargetInfo. diff --git a/clang/lib/Lex/TextEncoding.cpp b/clang/lib/Lex/TextEncoding.cpp index fd59f3df59bdfb..6ee6f8a0ef2666 100644 --- a/clang/lib/Lex/TextEncoding.cpp +++ b/clang/lib/Lex/TextEncoding.cpp @@ -18,7 +18,8 @@ TextEncoding::getConverter(ConversionAction Action) const { case CA_ToLiteralEncoding: return ToLiteralEncodingConverter.get(); case CA_ToSystemEncoding: - return ToSystemEncodingConverter.get(); + // return null for non-z/OS targets + return ToIBM1047Converter.get(); default: return nullptr; } @@ -34,6 +35,8 @@ TextEncoding::setConvertersFromOptions(TextEncoding &TE, TE.LiteralEncoding = Opts.LiteralEncoding.empty() ? UTF8 : Opts.LiteralEncoding.c_str(); + // Create converter between internal and literal encoding specified + // in fexec-charset option. if (TE.LiteralEncoding != UTF8) { ErrorOr<TextEncodingConverter> ErrorOrLiteralConverter = llvm::TextEncodingConverter::create(UTF8, TE.LiteralEncoding); @@ -47,22 +50,26 @@ TextEncoding::setConvertersFromOptions(TextEncoding &TE, if (TInfo.getDefaultOrdinaryLiteralEncoding() == UTF8) return std::error_code(); - // Create converter between internal and default ordinary encoding for the - // target + // The IBM-1047 converters are only needed on z/OS, where the system + // (assembler/linker) default encoding is IBM-1047 rather than UTF-8. + assert((TInfo.getTriple().getOS() == llvm::Triple::ZOS) && + "Non-UTF-8 system encoding is only expected on z/OS"); + + // Create a converter from UTF-8 to IBM-1047 for use when parsing asm string + // literals on z/OS, where escape sequences are IBM-1047 code points. ErrorOr<TextEncodingConverter> ErrorOrConverter = llvm::TextEncodingConverter::create( UTF8, TInfo.getDefaultOrdinaryLiteralEncoding()); if (ErrorOrConverter) - TE.ToSystemEncodingConverter = + TE.ToIBM1047Converter = std::make_unique<TextEncodingConverter>(std::move(*ErrorOrConverter)); else return ErrorOrConverter.getError(); ErrorOrConverter = llvm::TextEncodingConverter::create( TInfo.getDefaultOrdinaryLiteralEncoding(), UTF8); - if (ErrorOrConverter) - TInfo.FromSystemEncodingConverter = + TE.FromIBM1047Converter = std::make_unique<TextEncodingConverter>(std::move(*ErrorOrConverter)); else return ErrorOrConverter.getError(); diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 5a376a21e84733..1746604f61378c 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -15,6 +15,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/TextEncoding.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" @@ -24,6 +25,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/Support/TextEncoding.h" #include <optional> using namespace clang; using namespace sema; @@ -247,10 +249,10 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel, << SL->getSourceRange(); } if (!IsConstExpr && - Context.getTargetInfo().FromSystemEncodingConverter != nullptr) { + PP.getTextEncoding().getFromIBM1047Converter() != nullptr) { SmallString<16> ConvertedAsm; - Context.getTargetInfo().FromSystemEncodingConverter->convert( - SL->getString(), ConvertedAsm); + PP.getTextEncoding().getFromIBM1047Converter()->convert(SL->getString(), + ConvertedAsm); QualType StrTy = Context.getStringLiteralArrayType(Context.CharTy, ConvertedAsm.size()); return StringLiteral::Create(Context, ConvertedAsm, >From 16870c5a2529f0b39667bbda6cfb8a34f58e02c9 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Mon, 5 Oct 2026 10:13:37 -0400 Subject: [PATCH 09/14] rename CA_ToSystemEncoding to CA_ToLiteralEncodingForAsm --- clang/include/clang/Lex/TextEncoding.h | 2 +- clang/lib/Lex/TextEncoding.cpp | 2 +- clang/lib/Parse/Parser.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Lex/TextEncoding.h b/clang/include/clang/Lex/TextEncoding.h index ec826ec6615922..46903a53610591 100644 --- a/clang/include/clang/Lex/TextEncoding.h +++ b/clang/include/clang/Lex/TextEncoding.h @@ -20,7 +20,7 @@ class TextEncodingConverter; namespace clang { enum ConversionAction { CA_NoConversion, - CA_ToSystemEncoding, + CA_ToLiteralEncodingForAsm, // IBM-1047 on z/OS, UTF-8 on other platforms CA_ToLiteralEncoding }; diff --git a/clang/lib/Lex/TextEncoding.cpp b/clang/lib/Lex/TextEncoding.cpp index 6ee6f8a0ef2666..afb5130ece88e4 100644 --- a/clang/lib/Lex/TextEncoding.cpp +++ b/clang/lib/Lex/TextEncoding.cpp @@ -17,7 +17,7 @@ TextEncoding::getConverter(ConversionAction Action) const { switch (Action) { case CA_ToLiteralEncoding: return ToLiteralEncodingConverter.get(); - case CA_ToSystemEncoding: + case CA_ToLiteralEncodingForAsm: // return null for non-z/OS targets return ToIBM1047Converter.get(); default: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 7fd9fe9dee0c76..3f6776d72d5372 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1570,7 +1570,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { if (isTokenStringLiteral()) { AsmString = ParseStringLiteralExpression(/*AllowUserDefinedLiteral=*/false, /*Unevaluated=*/false, - CA_ToSystemEncoding); + CA_ToLiteralEncodingForAsm); if (AsmString.isInvalid()) return AsmString; >From c6201b8bddf321d6d603dff89ad6372c56eb49b6 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Wed, 7 Oct 2026 10:56:26 -0400 Subject: [PATCH 10/14] add more testcases, make diagnostic message generic --- clang/include/clang/Basic/DiagnosticLexKinds.td | 2 +- clang/test/CodeGen/systemz-charset-diag.cpp | 2 +- clang/test/CodeGen/systemz-charset.cpp | 8 ++++++-- clang/test/Sema/systemz-charset-asm.cpp | 11 +++++++++++ 4 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 clang/test/Sema/systemz-charset-asm.cpp diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ee3fb0e74d2209..d6d94005e57df3 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -301,7 +301,7 @@ def ext_string_too_long : Extension<"string literal of length %0 exceeds " def err_character_too_large : Error< "character too large for enclosing character literal type">; def err_exec_charset_conversion_failed - : Error<"conversion to literal encoding failed: '%0'">; + : Error<"encoding conversion failed: '%0'">; def warn_c99_compat_unicode_literal : Warning< "unicode literals are incompatible with C99">, InGroup<C99Compat>, DefaultIgnore; diff --git a/clang/test/CodeGen/systemz-charset-diag.cpp b/clang/test/CodeGen/systemz-charset-diag.cpp index 4ed94810150a3a..a59a5ef4f0604c 100644 --- a/clang/test/CodeGen/systemz-charset-diag.cpp +++ b/clang/test/CodeGen/systemz-charset-diag.cpp @@ -1,3 +1,3 @@ // RUN: %clang_cc1 -triple s390x-none-zos -fexec-charset IBM-1047 %s -std=c++17 -emit-llvm -o - -verify -const char* Computer = "🖥️"; // expected-error-re {{conversion to literal encoding failed: {{.*}}}} +const char* Computer = "🖥️"; // expected-error-re {{encoding conversion failed: {{.*}}}} diff --git a/clang/test/CodeGen/systemz-charset.cpp b/clang/test/CodeGen/systemz-charset.cpp index 6348fb72dac9a0..b6b79842468c15 100644 --- a/clang/test/CodeGen/systemz-charset.cpp +++ b/clang/test/CodeGen/systemz-charset.cpp @@ -92,7 +92,11 @@ constexpr string_view getfoo() { return "\174foo"; } void function() { + asm("\174foo"); + // CHECK: asm{{.*}}@foo + // CHECK-UTF8: asm{{.*}}@foo asm((getfoo())); + // CHECK: asm{{.*}}|\86\96\96 + // CHECK-UTF8: asm{{.*}}|foo } -// CHECK: asm{{.*}}|\86\96\96 -// CHECK-UTF8: asm{{.*}}|foo + diff --git a/clang/test/Sema/systemz-charset-asm.cpp b/clang/test/Sema/systemz-charset-asm.cpp new file mode 100644 index 00000000000000..b3c27cc53638e6 --- /dev/null +++ b/clang/test/Sema/systemz-charset-asm.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple s390x-none-zos -fexec-charset IBM-1047 %s -std=c++23 -fsyntax-only -verify +// RUN: %clang_cc1 -triple s390x-none-zos -fexec-charset UTF-8 %s -std=c++23 -fsyntax-only -verify + +long inline_asm_ucn_named_operand(long a, long b) { + // The \N{...} escape encodes to U+0130. IBM-1047 has no code point for + // U+0130, so the conversion reports an error. + asm("\tLGR %0, %[\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}]\n" // expected-error-re {{encoding conversion failed: {{.*}}}} + : "=r"(a) + : [\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}] "r"(b)); + return a; +} >From 29f61ad886c78e05f4c4f11dff11603c60a3f0c0 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Fri, 9 Oct 2026 13:29:51 -0400 Subject: [PATCH 11/14] Add some documentation --- clang/docs/LanguageExtensions.md | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md index 3db8d083c40756..4b0a39a37159ed 100644 --- a/clang/docs/LanguageExtensions.md +++ b/clang/docs/LanguageExtensions.md @@ -2263,6 +2263,45 @@ int foo() { } ``` +### String literal encoding in ASM statements + +On targets where the platform's default ordinary literal encoding differs from +UTF-8 (such as z/OS, where the system default encoding is IBM-1047): + +* **Direct ASM string literals**: Direct string literals used in `asm` statements + or `asm` labels (such as `asm("...")` or `__asm__("...")`) are parsed and + interpreted using the target system's default encoding (such as IBM-1047 on + z/OS) rather than the literal encoding specified by `-fexec-charset`. This + ensures that escape sequences (such as octal or hexadecimal byte escapes) + are interpreted as system/assembler code points. + +* **Constexpr string expressions in ASM statements**: When a parenthesized + constant expression is provided in place of an `asm` string, string literals + within that constant expression are encoded according to the execution + character set specified by `-fexec-charset` (the literal encoding), as + constant expression evaluation expects `char` sequences to operate in the + literal encoding. The system encoding conversion applied to direct `asm` + string literals is restricted to the direct string literal case and does not + extend to string literals within constant expressions. + +For example, on z/OS compiled with `-fexec-charset UTF-8`: + +```c++ +constexpr std::string_view takeStringAndReturnEmptyStringView(const char *str) { + return std::string_view(); +} + +int main(void) { + // Direct string literals in asm statements are interpreted in the system encoding (IBM-1047). + asm("nop"); + + // String literals within the constexpr expression are encoded in the execution charset (UTF-8). + // Characters not representable in IBM-1047 (such as "\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}") + // are valid here because constant evaluation evaluates the string literal in UTF-8. + asm((takeStringAndReturnEmptyStringView("\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}"))); +} +``` + ## Objective-C Features ### Related result types @@ -5650,6 +5689,14 @@ The builtins return 0 if the values are equal, or 1 if they are unequal. Generates a 16-byte compare-and-swap using the CDSG instruction. +#### ASM string literal encoding + +On z/OS, the system default encoding is IBM-1047. Direct string literals in +`asm` statements and `asm` labels are interpreted using IBM-1047 regardless of +`-fexec-charset`. When using parenthesized constant expressions in `asm` +statements, string literals within the constant expression are instead encoded +using the execution character set specified by `-fexec-charset`. + ## Extensions for Static Analysis Clang supports additional attributes that are useful for documenting program >From 864d56b11b9c0e2be9e156077e321e51ec25c936 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Tue, 13 Oct 2026 15:26:03 -0400 Subject: [PATCH 12/14] address comments on document --- clang/docs/LanguageExtensions.md | 41 ++++++++++++++++---------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md index 4b0a39a37159ed..3c4fd93bdc45dd 100644 --- a/clang/docs/LanguageExtensions.md +++ b/clang/docs/LanguageExtensions.md @@ -2268,23 +2268,21 @@ int foo() { On targets where the platform's default ordinary literal encoding differs from UTF-8 (such as z/OS, where the system default encoding is IBM-1047): -* **Direct ASM string literals**: Direct string literals used in `asm` statements - or `asm` labels (such as `asm("...")` or `__asm__("...")`) are parsed and +* **ASM template strings**: Asm template strings used in `asm` statements or + `asm` labels (such as `asm("...")` or `__asm__("...")`) are parsed and interpreted using the target system's default encoding (such as IBM-1047 on - z/OS) rather than the literal encoding specified by `-fexec-charset`. This - ensures that escape sequences (such as octal or hexadecimal byte escapes) - are interpreted as system/assembler code points. + z/OS) rather than the literal encoding specified by `-fexec-charset=`. This + ensures that escape sequences (such as octal or hexadecimal byte escapes) are + interpreted as system/assembler code points. * **Constexpr string expressions in ASM statements**: When a parenthesized constant expression is provided in place of an `asm` string, string literals within that constant expression are encoded according to the execution - character set specified by `-fexec-charset` (the literal encoding), as + character set specified by `-fexec-charset=` (the literal encoding), as constant expression evaluation expects `char` sequences to operate in the - literal encoding. The system encoding conversion applied to direct `asm` - string literals is restricted to the direct string literal case and does not - extend to string literals within constant expressions. + literal encoding. -For example, on z/OS compiled with `-fexec-charset UTF-8`: +For example, on z/OS compiled with `-fexec-charset=UTF-8`: ```c++ constexpr std::string_view takeStringAndReturnEmptyStringView(const char *str) { @@ -2292,12 +2290,15 @@ constexpr std::string_view takeStringAndReturnEmptyStringView(const char *str) { } int main(void) { - // Direct string literals in asm statements are interpreted in the system encoding (IBM-1047). - asm("nop"); - - // String literals within the constexpr expression are encoded in the execution charset (UTF-8). - // Characters not representable in IBM-1047 (such as "\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}") - // are valid here because constant evaluation evaluates the string literal in UTF-8. + // Template strings in asm statements are interpreted in the system encoding + // (IBM-1047). + asm("\t\x95\x96\x97"); + + // String literals within the constexpr expression are encoded in the + // execution character set specified by -fexec-charset=. + // With -fexec-charset=IBM-1047, the string below is diagnosed as invalid + // because U+0130 cannot be represented in IBM-1047. + // With -fexec-charset=UTF-8, the string below is valid. asm((takeStringAndReturnEmptyStringView("\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}"))); } ``` @@ -5691,11 +5692,11 @@ The builtins return 0 if the values are equal, or 1 if they are unequal. #### ASM string literal encoding -On z/OS, the system default encoding is IBM-1047. Direct string literals in -`asm` statements and `asm` labels are interpreted using IBM-1047 regardless of -`-fexec-charset`. When using parenthesized constant expressions in `asm` +On z/OS, the system default encoding is IBM-1047. Template strings in `asm` +statements and `asm` labels are interpreted using IBM-1047 regardless of +`-fexec-charset=`. When using parenthesized constant expressions in `asm` statements, string literals within the constant expression are instead encoded -using the execution character set specified by `-fexec-charset`. +using the execution character set specified by `-fexec-charset=`. ## Extensions for Static Analysis >From 44385fbf7c329442d62eaca043680d3d3edac152 Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Wed, 14 Oct 2026 09:04:23 -0400 Subject: [PATCH 13/14] address comments in LanguageExtensions.md --- clang/docs/LanguageExtensions.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md index 3c4fd93bdc45dd..9e19cc8c34d3e4 100644 --- a/clang/docs/LanguageExtensions.md +++ b/clang/docs/LanguageExtensions.md @@ -2268,12 +2268,15 @@ int foo() { On targets where the platform's default ordinary literal encoding differs from UTF-8 (such as z/OS, where the system default encoding is IBM-1047): -* **ASM template strings**: Asm template strings used in `asm` statements or - `asm` labels (such as `asm("...")` or `__asm__("...")`) are parsed and - interpreted using the target system's default encoding (such as IBM-1047 on - z/OS) rather than the literal encoding specified by `-fexec-charset=`. This - ensures that escape sequences (such as octal or hexadecimal byte escapes) are - interpreted as system/assembler code points. +* **String literals**: A string literal used as the template string in an + extended asm statement, as the instruction string in a basic asm statement, + or as the string specifying the assembler name or register in an asm label or + a global/local register variable declaration (such as `asm("...")` or + `__asm__("...")`) is parsed and interpreted using the target system's default + encoding (such as IBM-1047 on z/OS) rather than the literal encoding + specified by `-fexec-charset=`. This ensures that escape sequences (such as + octal or hexadecimal byte escapes) are interpreted as system/assembler code + points. * **Constexpr string expressions in ASM statements**: When a parenthesized constant expression is provided in place of an `asm` string, string literals @@ -2291,8 +2294,8 @@ constexpr std::string_view takeStringAndReturnEmptyStringView(const char *str) { int main(void) { // Template strings in asm statements are interpreted in the system encoding - // (IBM-1047). - asm("\t\x95\x96\x97"); + // (IBM-1047 on z/OS). + asm("\t\x95\x96\x97"); // This generates a "nop" in IBM-1047 // String literals within the constexpr expression are encoded in the // execution character set specified by -fexec-charset=. @@ -5692,11 +5695,11 @@ The builtins return 0 if the values are equal, or 1 if they are unequal. #### ASM string literal encoding -On z/OS, the system default encoding is IBM-1047. Template strings in `asm` -statements and `asm` labels are interpreted using IBM-1047 regardless of -`-fexec-charset=`. When using parenthesized constant expressions in `asm` -statements, string literals within the constant expression are instead encoded -using the execution character set specified by `-fexec-charset=`. +On z/OS, the system default encoding is IBM-1047, which has implications for +ASM strings. See +[String literal encoding in ASM statements](#string-literal-encoding-in-asm-statements) +for details. + ## Extensions for Static Analysis >From 569d5680bb14511afa810854ebdb4b22a71da54b Mon Sep 17 00:00:00 2001 From: Abhina Sreeskantharajan <[email protected]> Date: Mon, 19 Oct 2026 15:06:11 -0400 Subject: [PATCH 14/14] reverse conversion from literal encoding for assembler template string --- clang/include/clang/Lex/TextEncoding.h | 7 +++++++ clang/lib/Lex/TextEncoding.cpp | 8 ++++++++ clang/lib/Sema/SemaStmtAsm.cpp | 27 ++++++++++++++++++++++++++ clang/test/CodeGen/systemz-charset.cpp | 6 +++++- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Lex/TextEncoding.h b/clang/include/clang/Lex/TextEncoding.h index 46903a53610591..ebfd537488a1cd 100644 --- a/clang/include/clang/Lex/TextEncoding.h +++ b/clang/include/clang/Lex/TextEncoding.h @@ -27,6 +27,7 @@ enum ConversionAction { class TextEncoding { llvm::StringRef LiteralEncoding; std::unique_ptr<llvm::TextEncodingConverter> ToLiteralEncodingConverter; + std::unique_ptr<llvm::TextEncodingConverter> FromLiteralEncodingConverter; // Only non-null on z/OS, where the system default encoding is IBM-1047. // This converts UTF-8 to IBM-1047 for asm string literals so that @@ -38,6 +39,12 @@ class TextEncoding { public: llvm::TextEncodingConverter *getConverter(ConversionAction Action) const; + /// Returns the converter from the literal encoding (-fexec-charset) to UTF-8, + /// or nullptr if the literal encoding is UTF-8. + llvm::TextEncodingConverter *getFromLiteralEncodingConverter() const { + return FromLiteralEncodingConverter.get(); + } + /// Returns the converter from IBM-1047 to UTF-8, or nullptr if not on z/OS. llvm::TextEncodingConverter *getFromIBM1047Converter() const { return FromIBM1047Converter.get(); diff --git a/clang/lib/Lex/TextEncoding.cpp b/clang/lib/Lex/TextEncoding.cpp index afb5130ece88e4..32613199187100 100644 --- a/clang/lib/Lex/TextEncoding.cpp +++ b/clang/lib/Lex/TextEncoding.cpp @@ -45,6 +45,14 @@ TextEncoding::setConvertersFromOptions(TextEncoding &TE, std::move(*ErrorOrLiteralConverter)); else return ErrorOrLiteralConverter.getError(); + + ErrorOrLiteralConverter = + llvm::TextEncodingConverter::create(TE.LiteralEncoding, UTF8); + if (ErrorOrLiteralConverter) + TE.FromLiteralEncodingConverter = std::make_unique<TextEncodingConverter>( + std::move(*ErrorOrLiteralConverter)); + else + return ErrorOrLiteralConverter.getError(); } if (TInfo.getDefaultOrdinaryLiteralEncoding() == UTF8) diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 1746604f61378c..b2d95a739c1c36 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/DiagnosticLex.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/TextEncoding.h" @@ -248,6 +249,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel, Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string) << SL->getSourceRange(); } + if (!IsConstExpr && PP.getTextEncoding().getFromIBM1047Converter() != nullptr) { SmallString<16> ConvertedAsm; @@ -274,6 +276,31 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel, Diag(Expr->getBeginLoc(), diag::err_asm_operand_empty_string); } + // The evaluated string is in the literal encoding (-fexec-charset). + // Convert it back to UTF-8 + if (llvm::TextEncodingConverter *FromLiteral = + PP.getTextEncoding().getFromLiteralEncodingConverter()) { + unsigned Size = V.getArraySize(); + std::string Raw; + Raw.reserve(Size); + for (unsigned I = 0; I < Size; ++I) + Raw.push_back(static_cast<char>( + V.getArrayInitializedElt(I).getInt().getExtValue())); + SmallString<16> Converted; + if (std::error_code EC = FromLiteral->convert(Raw, Converted)) { + Diag(Expr->getBeginLoc(), diag::err_exec_charset_conversion_failed) + << EC.message(); + return ExprError(); + } + llvm::APSInt Proto(Context.getTypeSize(Context.CharTy), + Context.CharTy->isUnsignedIntegerType()); + V = APValue(APValue::UninitArray{}, Converted.size(), Converted.size()); + for (unsigned I = 0; I < Converted.size(); ++I) { + Proto = static_cast<unsigned char>(Converted[I]); + V.getArrayInitializedElt(I) = APValue(Proto); + } + } + return ConstantExpr::Create(getASTContext(), Expr, V); } diff --git a/clang/test/CodeGen/systemz-charset.cpp b/clang/test/CodeGen/systemz-charset.cpp index b6b79842468c15..b1c58b3336bb39 100644 --- a/clang/test/CodeGen/systemz-charset.cpp +++ b/clang/test/CodeGen/systemz-charset.cpp @@ -96,7 +96,11 @@ void function() // CHECK: asm{{.*}}@foo // CHECK-UTF8: asm{{.*}}@foo asm((getfoo())); - // CHECK: asm{{.*}}|\86\96\96 + // CHECK: asm{{.*}}@foo // CHECK-UTF8: asm{{.*}}|foo + + asm((string_view("\tnop\n"))); + // CHECK: asm{{.*}}\09nop\0A + // CHECK-UTF8: asm{{.*}}\09nop\0A } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
