From 18e28387722e3740b8786d964caaac375a0282bd Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 6 Dec 2025 18:24:15 +0100 Subject: [PATCH] - Hex escapes like `"\x80"` would be incorrectly lowered. #2623 --- releasenotes.md | 1 + src/compiler/lexer.c | 5 ++--- test/test_suite/clang/2002-03.c3t | 4 +++- test/test_suite/literals/x_escape.c3t | 12 ++++++++++++ 4 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 test/test_suite/literals/x_escape.c3t diff --git a/releasenotes.md b/releasenotes.md index 02758786d..b52f27ceb 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -10,6 +10,7 @@ - Casting bitstruct to wider base type should be single step #2616. - Optional does not play well with bit ops #2618. - `Bytebuffer.grow` was broken #2622. +- Hex escapes like `"\x80"` would be incorrectly lowered. #2623 ### Stdlib changes diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 2d3960a8c..c9afc1af9 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -858,9 +858,8 @@ static int append_esc_string_token(char *restrict dest, const char *restrict src if (h < 0) return -1; int l = char_hex_to_nibble(src[2]); if (l < 0) return -1; - unicode_char = ((unsigned) h << 4U) + (unsigned)l; - scanned = 3; - break; + dest[(*pos)++] = (char)(((unsigned) h << 4U) + (unsigned)l); + return 3; } case 'u': { diff --git a/test/test_suite/clang/2002-03.c3t b/test/test_suite/clang/2002-03.c3t index ab572335a..29da84267 100644 --- a/test/test_suite/clang/2002-03.c3t +++ b/test/test_suite/clang/2002-03.c3t @@ -60,7 +60,7 @@ fn char* foo() { @test.array = local_unnamed_addr global { %Test, %Test, [8 x %Test] } { %Test { i32 2, double 1.200000e+01 }, %Test { i32 3, double 2.400000e+01 }, [8 x %Test] zeroinitializer }, align 16 @test.b = local_unnamed_addr global { [4 x i32], [4 x i32], { i32, i32, [2 x i32] }, [4 x i32] } { [4 x i32] [i32 1, i32 2, i32 3, i32 4], [4 x i32] [i32 5, i32 6, i32 7, i32 0], { i32, i32, [2 x i32] } { i32 8, i32 9, [2 x i32] zeroinitializer }, [4 x i32] zeroinitializer }, align 16 @test.link = local_unnamed_addr global [3 x %Connection] [%Connection { i64 1, [10 x i8] c"link1\00\00\00\00\00", i64 10 }, %Connection { i64 2, [10 x i8] c"link2\00\00\00\00\00", i64 20 }, %Connection { i64 3, [10 x i8] c"link3\00\00\00\00\00", i64 30 }], align 16 -@.str = private unnamed_addr constant [4 x i8] c"\1F\C2\8B\00", align 1 +@.str = private unnamed_addr constant [3 x i8] c"\1F\8B\00", align 1 @.str.7 = private unnamed_addr constant [32 x i8] c"*** Word \22%s\22 on line %d is not\00", align 1 declare i32 @strcmp(ptr, ptr) #0 @@ -81,12 +81,14 @@ entry: store i32 0, ptr %lLS, align 4 %i2b = icmp ne i32 %1, 0 br i1 %i2b, label %if.then, label %if.exit + if.then: ; preds = %entry %2 = load i32, ptr %lLS, align 4 %3 = load i32, ptr %asa, align 4 %add = add i32 %2, %3 store i32 %add, ptr %asa, align 4 br label %if.exit + if.exit: ; preds = %if.then, %entry %4 = load i32, ptr %asa, align 4 %5 = load double, ptr %val, align 8 diff --git a/test/test_suite/literals/x_escape.c3t b/test/test_suite/literals/x_escape.c3t new file mode 100644 index 000000000..8e995b0ac --- /dev/null +++ b/test/test_suite/literals/x_escape.c3t @@ -0,0 +1,12 @@ +// #target: macos-x64 +module test; +import std; + +fn void main() +{ + char[] test = "\x80\x80\x79"; + io::printfn("%s", test); +} +/* #expect: test.ll + +@.str = private unnamed_addr constant [4 x i8] c"\80\80y\00", align 1