[clang] Convert user-defined literals to fexec-charset (PR #222037)

Abhina Sree via cfe-commits cfe-commits at lists.llvm.org
Tue Sep 8 08:49:56 PDT 2026


https://github.com/abhina-sree updated https://github.com/llvm/llvm-project/pull/222037

>From 07c5a3b2f887d7beaab1986b32d909cb1da6c2a8 Mon Sep 17 00:00:00 2001
From: Abhina Sreeskantharajan <Abhina.Sreeskantharajan at ibm.com>
Date: Tue, 8 Sep 2026 11:46:25 -0400
Subject: [PATCH] Convert user-defined literals to fexec-charset

---
 clang/lib/Sema/SemaExpr.cpp                   | 25 ++++++++++++++++---
 .../CodeGenCXX/cxx11-user-defined-literal.cpp | 18 ++++++++-----
 2 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index d06079a43e23a..e158a656748b8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3939,10 +3939,27 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
       QualType StrTy = Context.getConstantArrayType(
           Context.adjustStringLiteralBaseType(Context.CharTy.withConst()),
           llvm::APInt(32, Length + 1), nullptr, ArraySizeModifier::Normal, 0);
-      Expr *Lit =
-          StringLiteral::Create(Context, StringRef(TokSpelling.data(), Length),
-                                StringLiteralKind::Ordinary,
-                                /*Pascal*/ false, StrTy, TokLoc);
+      // Wrap the raw spelling in quotes and run it through StringLiteralParser
+      // so that the exec-charset conversion (e.g. -fexec-charset=IBM-1047)
+      // is applied before building the StringLiteral node.
+      SmallString<256> SpellString;
+      SpellString += "\"";
+      SpellString += StringRef(TokSpelling.data(), Length);
+      SpellString += "\"";
+      Token RawStringTok;
+      RawStringTok.startToken();
+      RawStringTok.setKind(tok::string_literal);
+      RawStringTok.setLocation(TokLoc);
+      RawStringTok.setLiteralData(SpellString.data());
+      RawStringTok.setLength(SpellString.size());
+      StringLiteralParser TempLiteral(RawStringTok, PP,
+                                      StringLiteralEvalMethod::Evaluated,
+                                      CA_ToLiteralEncoding);
+      if (TempLiteral.hadError)
+        return ExprError();
+      Expr *Lit = StringLiteral::Create(Context, TempLiteral.GetString(),
+                                        StringLiteralKind::Ordinary,
+                                        /*Pascal*/ false, StrTy, TokLoc);
       return BuildLiteralOperatorCall(R, OpNameInfo, Lit, TokLoc);
     }
 
diff --git a/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp
index 3b18a9ad811c3..2528d82ae573c 100644
--- a/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp
+++ b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-ASCII -check-prefix=CHECK %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -fexec-charset IBM-1047 -emit-llvm %s -o - | FileCheck -check-prefix=CHECK-EBCDIC -check-prefix=CHECK %s
 
 struct S { S(); ~S(); S(const S &); void operator()(int); };
 using size_t = decltype(sizeof(int));
@@ -9,11 +10,16 @@ S operator"" _f(long double);
 S operator"" _r(const char *);
 template<char...Cs> S operator"" _t() { return S(); }
 
-// CHECK: @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"foo\00"
-// CHECK: @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"bar\00"
-// CHECK: @[[s_123:.*]] = {{.*}} constant [4 x i8] c"123\00"
-// CHECK: @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"4.9\00"
-// CHECK: @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"0xffffeeee\00"
+// CHECK-ASCII:  @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"foo\00"
+// CHECK-EBCDIC: @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"\86\96\96\00"
+// CHECK-ASCII:  @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"bar\00"
+// CHECK-EBCDIC: @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"\82\81\99\00"
+// CHECK-ASCII:  @[[s_123:.*]] = {{.*}} constant [4 x i8] c"123\00"
+// CHECK-EBCDIC: @[[s_123:.*]] = {{.*}} constant [4 x i8] c"\F1\F2\F3\00"
+// CHECK-ASCII:  @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"4.9\00"
+// CHECK-EBCDIC: @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"\F4K\F9\00"
+// CHECK-ASCII:  @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"0xffffeeee\00"
+// CHECK-EBCDIC: @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"\F0\A7\86\86\86\86\85\85\85\85\00"
 
 void f() {
   // CHECK: call void @_Zli2_xPKcm({{.*}}, ptr noundef @[[s_foo]], i64 noundef 3)



More information about the cfe-commits mailing list