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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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
 }
 

>From 7eb4aec053c9efe538641995ec3bdaeda7c91f34 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <[email protected]>
Date: Mon, 2 Nov 2026 13:57:43 -0500
Subject: [PATCH 15/15] address latest comments

---
 clang/docs/LanguageExtensions.md              | 18 +++----
 clang/include/clang/AST/APValue.h             |  4 ++
 .../include/clang/Basic/DiagnosticLexKinds.td |  3 +-
 clang/include/clang/Lex/LiteralSupport.h      |  9 ++--
 clang/include/clang/Sema/Sema.h               |  2 +-
 clang/lib/AST/APValue.cpp                     | 11 ++++
 clang/lib/Lex/LiteralSupport.cpp              | 51 +++++++++----------
 clang/lib/Parse/Parser.cpp                    |  6 +--
 clang/lib/Sema/SemaStmtAsm.cpp                | 13 ++---
 clang/test/CodeGen/systemz-charset-diag.cpp   |  2 +-
 clang/test/Sema/systemz-charset-asm.cpp       |  2 +-
 11 files changed, 64 insertions(+), 57 deletions(-)

diff --git a/clang/docs/LanguageExtensions.md b/clang/docs/LanguageExtensions.md
index 9e19cc8c34d3e4..673cf45e130682 100644
--- a/clang/docs/LanguageExtensions.md
+++ b/clang/docs/LanguageExtensions.md
@@ -2265,10 +2265,9 @@ 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):
+On z/OS, where the system default encoding is IBM-1047 rather than UTF-8:
 
-* **String literals**: A string literal used as the template string in an
+* 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
@@ -2276,14 +2275,11 @@ UTF-8 (such as z/OS, where the system default encoding 
is IBM-1047):
   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.
+  points. This does **not** apply to parenthesized
+  constant expressions (see
+  [Constexpr strings in GNU ASM 
statements](#constexpr-strings-in-gnu-asm-statements)),
+  in which string literals are encoded according to the literal encoding
+  specified by `-fexec-charset=`.
 
 For example, on z/OS compiled with `-fexec-charset=UTF-8`:
 
diff --git a/clang/include/clang/AST/APValue.h 
b/clang/include/clang/AST/APValue.h
index 7a69a98702a8cc..42e03c51533e89 100644
--- a/clang/include/clang/AST/APValue.h
+++ b/clang/include/clang/AST/APValue.h
@@ -570,6 +570,10 @@ class LLVM_ATTRIBUTE_WARN_UNUSED APValue {
 
   std::string getAsString(const ASTContext &Ctx, QualType Ty) const;
 
+  /// Returns the contents of an array of integers (e.g. an evaluated character
+  /// array) as a string, with each element truncated to a char.
+  std::string getCharArrayAsString() const;
+
   APSInt &getInt() {
     assert(isInt() && "Invalid accessor");
     return *(APSInt *)(char *)&Data;
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td 
b/clang/include/clang/Basic/DiagnosticLexKinds.td
index d6d94005e57df3..a75c7ddd66cb87 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -301,7 +301,8 @@ 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<"encoding conversion failed: '%0'">;
+    : Error<"conversion %select{to literal encoding|to asm string encoding|"
+            "from literal encoding to UTF-8}1 failed: '%0'">;
 def warn_c99_compat_unicode_literal : Warning<
   "unicode literals are incompatible with C99">,
   InGroup<C99Compat>, DefaultIgnore;
diff --git a/clang/include/clang/Lex/LiteralSupport.h 
b/clang/include/clang/Lex/LiteralSupport.h
index 9270190e024805..ac52c76db00564 100644
--- a/clang/include/clang/Lex/LiteralSupport.h
+++ b/clang/include/clang/Lex/LiteralSupport.h
@@ -247,6 +247,7 @@ class StringLiteralParser {
   unsigned UDSuffixToken;
   unsigned UDSuffixOffset;
   StringLiteralEvalMethod EvalMethod;
+  ConversionAction Action;
 
 public:
   StringLiteralParser(
@@ -259,9 +260,9 @@ class StringLiteralParser {
       : SM(sm), Features(features), Target(target), Diags(diags), TE(nullptr),
         MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown),
         ResultPtr(ResultBuf.data()),
-        EvalMethod(StringLiteralEvalMethod::Evaluated), hadError(false),
-        Pascal(false) {
-    init(StringToks, CA_NoConversion);
+        EvalMethod(StringLiteralEvalMethod::Evaluated), 
Action(CA_NoConversion),
+        hadError(false), Pascal(false) {
+    init(StringToks);
   }
 
   bool hadError;
@@ -309,7 +310,7 @@ class StringLiteralParser {
   static bool isValidUDSuffix(const LangOptions &LangOpts, StringRef Suffix);
 
 private:
-  void init(ArrayRef<Token> StringToks, ConversionAction Action);
+  void init(ArrayRef<Token> StringToks);
   bool CopyStringFragment(const Token &Tok, const char *TokBegin,
                           StringRef Fragment,
                           llvm::TextEncodingConverter *Converter);
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 778478f4723234..a78e8bb94a1b91 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11490,7 +11490,7 @@ class Sema final : public SemaBase {
 
 public:
   ExprResult ActOnGCCAsmStmtString(Expr *Stm, bool ForAsmLabel,
-                                   bool IsConstExpr = false);
+                                   bool IsConstexpr = false);
   StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
                              bool IsVolatile, unsigned NumOutputs,
                              unsigned NumInputs, IdentifierInfo **Names,
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 97023be49c715b..51233d0a8fc416 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -1103,6 +1103,17 @@ std::string APValue::getAsString(const ASTContext &Ctx, 
QualType Ty) const {
   return Result;
 }
 
+std::string APValue::getCharArrayAsString() const {
+  assert(isArray() && "Invalid accessor");
+  unsigned Size = getArraySize();
+  std::string Result;
+  Result.reserve(Size);
+  for (unsigned I = 0; I < Size; ++I)
+    Result.push_back(
+        static_cast<char>(getArrayInitializedElt(I).getInt().getExtValue()));
+  return Result;
+}
+
 bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
                                  const ASTContext &Ctx) const {
   if (isInt()) {
diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp
index efb1138b466150..ca4c3574bd9972 100644
--- a/clang/lib/Lex/LiteralSupport.cpp
+++ b/clang/lib/Lex/LiteralSupport.cpp
@@ -139,14 +139,12 @@ convertCharacter(StringRef Char, const 
llvm::TextEncodingConverter &Converter) {
 
 /// ProcessCharEscape - Parse a standard C escape sequence, which can occur in
 /// either a character or a string literal.
-static unsigned ProcessCharEscape(const char *ThisTokBegin,
-                                  const char *&ThisTokBuf,
-                                  const char *ThisTokEnd, bool &HadError,
-                                  FullSourceLoc Loc, unsigned CharWidth,
-                                  DiagnosticsEngine *Diags,
-                                  const LangOptions &Features,
-                                  StringLiteralEvalMethod EvalMethod,
-                                  llvm::TextEncodingConverter *Converter) {
+static unsigned ProcessCharEscape(
+    const char *ThisTokBegin, const char *&ThisTokBuf, const char *ThisTokEnd,
+    bool &HadError, FullSourceLoc Loc, unsigned CharWidth,
+    DiagnosticsEngine *Diags, const LangOptions &Features,
+    StringLiteralEvalMethod EvalMethod, llvm::TextEncodingConverter *Converter,
+    ConversionAction Action) {
   const char *EscapeBegin = ThisTokBuf;
   bool Delimited = false;
   bool EndDelimiterFound = false;
@@ -397,7 +395,8 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin,
     else {
       Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf,
            diag::err_exec_charset_conversion_failed)
-          << ErrorOrChar.getError().message();
+          << ErrorOrChar.getError().message()
+          << (Action == CA_ToLiteralEncodingForAsm ? 1 : 0);
       HadError = true;
     }
   }
@@ -807,7 +806,8 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const 
char *&ThisTokBuf,
                             bool &HadError, FullSourceLoc Loc,
                             unsigned CharByteWidth, DiagnosticsEngine *Diags,
                             const LangOptions &Features,
-                            llvm::TextEncodingConverter *Converter) {
+                            llvm::TextEncodingConverter *Converter,
+                            ConversionAction Action) {
   typedef uint32_t UTF32;
   UTF32 UcnVal = 0;
   unsigned short UcnLen = 0;
@@ -904,7 +904,7 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const 
char *&ThisTokBuf,
       ResultBuf = Cp + CpConv.size();
     } else {
       Diags->Report(Loc, diag::err_exec_charset_conversion_failed)
-          << EC.message();
+          << EC.message() << (Action == CA_ToLiteralEncodingForAsm ? 1 : 0);
       HadError = true;
     }
   }
@@ -1943,7 +1943,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, 
const char *end,
           } else {
             HadError = true;
             PP.Diag(Loc, diag::err_exec_charset_conversion_failed)
-                << ErrorOrChar.message();
+                << ErrorOrChar.message() << 0;
           }
         }
       }
@@ -1968,7 +1968,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, 
const char *end,
         EncodeUCNEscape(TokBegin, begin, end, ResultPtr, HadError,
                         FullSourceLoc(Loc, PP.getSourceManager()),
                         /*CharByteWidth=*/1u, &PP.getDiagnostics(),
-                        PP.getLangOpts(), Converter);
+                        PP.getLangOpts(), Converter, CA_ToLiteralEncoding);
         if (!HadError)
           *buffer_begin = *Cp;
       }
@@ -1976,11 +1976,11 @@ CharLiteralParser::CharLiteralParser(const char *begin, 
const char *end,
       continue;
     }
     unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo());
-    uint64_t result =
-        ProcessCharEscape(TokBegin, begin, end, HadError,
-                          FullSourceLoc(Loc, PP.getSourceManager()), CharWidth,
-                          &PP.getDiagnostics(), PP.getLangOpts(),
-                          StringLiteralEvalMethod::Evaluated, nullptr);
+    uint64_t result = ProcessCharEscape(
+        TokBegin, begin, end, HadError,
+        FullSourceLoc(Loc, PP.getSourceManager()), CharWidth,
+        &PP.getDiagnostics(), PP.getLangOpts(),
+        StringLiteralEvalMethod::Evaluated, nullptr, CA_NoConversion);
     *buffer_begin++ = result;
   }
 
@@ -2096,12 +2096,11 @@ 
StringLiteralParser::StringLiteralParser(ArrayRef<Token> StringToks,
       Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()),
       TE(&PP.getTextEncoding()), MaxTokenLength(0), SizeBound(0),
       CharByteWidth(0), Kind(tok::unknown), ResultPtr(ResultBuf.data()),
-      EvalMethod(EvalMethod), hadError(false), Pascal(false) {
-  init(StringToks, Action);
+      EvalMethod(EvalMethod), Action(Action), hadError(false), Pascal(false) {
+  init(StringToks);
 }
 
-void StringLiteralParser::init(ArrayRef<Token> StringToks,
-                               ConversionAction Action) {
+void StringLiteralParser::init(ArrayRef<Token> StringToks) {
   // The literal token may have come from an invalid source location (e.g. due
   // to a PCH error), in which case the token length will be 0.
   if (StringToks.empty() || StringToks[0].getLength() < 2)
@@ -2358,14 +2357,14 @@ void StringLiteralParser::init(ArrayRef<Token> 
StringToks,
           EncodeUCNEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, ResultPtr,
                           hadError,
                           FullSourceLoc(StringToks[i].getLocation(), SM),
-                          CharByteWidth, Diags, Features, Converter);
+                          CharByteWidth, Diags, Features, Converter, Action);
           continue;
         }
         // Otherwise, this is a non-UCN escape character.  Process it.
         unsigned ResultChar = ProcessCharEscape(
             ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError,
             FullSourceLoc(StringToks[i].getLocation(), SM), CharByteWidth * 8,
-            Diags, Features, EvalMethod, Converter);
+            Diags, Features, EvalMethod, Converter, Action);
 
         if (CharByteWidth == 4) {
           // FIXME: Make the type of the result buffer correct instead of
@@ -2459,7 +2458,7 @@ bool StringLiteralParser::CopyStringFragment(
         if (Diags)
           Diags->Report(Tok.getLocation(),
                         diag::err_exec_charset_conversion_failed)
-              << EC.message();
+              << EC.message() << (Action == CA_ToLiteralEncodingForAsm ? 1 : 
0);
         return true;
       }
     }
@@ -2582,7 +2581,7 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const 
Token &Tok,
       ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError,
                         FullSourceLoc(Tok.getLocation(), SM), CharByteWidth * 
8,
                         Diags, Features, StringLiteralEvalMethod::Evaluated,
-                        /*TextEncoding=*/nullptr);
+                        /*TextEncoding=*/nullptr, CA_NoConversion);
       --ByteNo;
     }
     assert(!HadError && "This method isn't valid on erroneous strings");
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 3f6776d72d5372..230363d98c985e 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -1566,7 +1566,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
 ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) {
 
   ExprResult AsmString;
-  bool IsConstExpr = false;
+  bool IsConstexpr = false;
   if (isTokenStringLiteral()) {
     AsmString = ParseStringLiteralExpression(/*AllowUserDefinedLiteral=*/false,
                                              /*Unevaluated=*/false,
@@ -1582,7 +1582,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool 
ForAsmLabel) {
     }
   } else if (!ForAsmLabel && getLangOpts().CPlusPlus11 &&
              Tok.is(tok::l_paren)) {
-    IsConstExpr = true;
+    IsConstexpr = true;
     ParenParseOption ExprType = ParenParseOption::SimpleExpr;
     SourceLocation RParenLoc;
     ParsedType CastTy;
@@ -1603,7 +1603,7 @@ ExprResult Parser::ParseAsmStringLiteral(bool 
ForAsmLabel) {
   }
 
   return Actions.ActOnGCCAsmStmtString(AsmString.get(), ForAsmLabel,
-                                       IsConstExpr);
+                                       IsConstexpr);
 }
 
 ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) {
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index b2d95a739c1c36..0f9b3e2fe1d079 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -239,7 +239,7 @@ getClobberConflictLocation(MultiExprArg Exprs, Expr 
**Constraints,
 }
 
 ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool ForAsmLabel,
-                                       bool IsConstExpr) {
+                                       bool IsConstexpr) {
   if (!Expr)
     return ExprError();
 
@@ -250,7 +250,7 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool 
ForAsmLabel,
           << SL->getSourceRange();
     }
 
-    if (!IsConstExpr &&
+    if (!IsConstexpr &&
         PP.getTextEncoding().getFromIBM1047Converter() != nullptr) {
       SmallString<16> ConvertedAsm;
       PP.getTextEncoding().getFromIBM1047Converter()->convert(SL->getString(),
@@ -280,16 +280,11 @@ ExprResult Sema::ActOnGCCAsmStmtString(Expr *Expr, bool 
ForAsmLabel,
   // 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()));
+    std::string Raw = V.getCharArrayAsString();
     SmallString<16> Converted;
     if (std::error_code EC = FromLiteral->convert(Raw, Converted)) {
       Diag(Expr->getBeginLoc(), diag::err_exec_charset_conversion_failed)
-          << EC.message();
+          << EC.message() << /*from literal encoding to UTF-8*/ 2;
       return ExprError();
     }
     llvm::APSInt Proto(Context.getTypeSize(Context.CharTy),
diff --git a/clang/test/CodeGen/systemz-charset-diag.cpp 
b/clang/test/CodeGen/systemz-charset-diag.cpp
index a59a5ef4f0604c..4ed94810150a3a 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 {{encoding conversion 
failed: {{.*}}}}
+const char* Computer = "🖥️"; // expected-error-re {{conversion to literal 
encoding failed: {{.*}}}}
diff --git a/clang/test/Sema/systemz-charset-asm.cpp 
b/clang/test/Sema/systemz-charset-asm.cpp
index b3c27cc53638e6..3b7067bde2bf90 100644
--- a/clang/test/Sema/systemz-charset-asm.cpp
+++ b/clang/test/Sema/systemz-charset-asm.cpp
@@ -4,7 +4,7 @@
 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: {{.*}}}}
+  asm("\tLGR %0, %[\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}]\n" // 
expected-error-re {{conversion to asm string encoding failed: {{.*}}}}
       : "=r"(a)
       : [\N{LATIN CAPITAL LETTER I WITH DOT ABOVE}] "r"(b));
   return a;

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

Reply via email to