Fix repeated string slice constant data
8c31c850d6cd809988aec7d72e16582aca5b9770fb984c8a165777997e6f2f25
Constant array-repeat lowering treated every resolver constant as an inline scalar. Repeated strings were emitted as raw bytes even though each element required a slice header, leaving missing relocations and length fields that caused runtime traps. Route repeated string values through generic per-element constant lowering so each element receives a complete relocated slice header backed by deduplicated string data.
1 parent
60335cc1
lib/std/lang/lower.rad
+12 -4
| 1544 | 1544 | dataBuilderPush(b, il::DataValue { |
|
| 1545 | 1545 | item: il::DataItem::Undef, |
|
| 1546 | 1546 | count: elemLayout.size * length |
|
| 1547 | 1547 | }); |
|
| 1548 | 1548 | } else if let val = resolver::constValueEntry(self.resolver, repeat.item) { |
|
| 1549 | - | dataBuilderPush(b, il::DataValue { |
|
| 1550 | - | item: constValueToDataItem(self, val, elemTy), |
|
| 1551 | - | count: length |
|
| 1552 | - | }); |
|
| 1549 | + | if let case resolver::ConstValue::String(_) = val { |
|
| 1550 | + | // A string used as a slice is represented by a three-word slice |
|
| 1551 | + | // header, not by the bytes of the string itself. |
|
| 1552 | + | for _ in 0..length { |
|
| 1553 | + | try lowerConstDataInto(self, repeat.item, elemTy, elemLayout.size, dataPrefix, b); |
|
| 1554 | + | } |
|
| 1555 | + | } else { |
|
| 1556 | + | dataBuilderPush(b, il::DataValue { |
|
| 1557 | + | item: constValueToDataItem(self, val, elemTy), |
|
| 1558 | + | count: length |
|
| 1559 | + | }); |
|
| 1560 | + | } |
|
| 1553 | 1561 | } else { |
|
| 1554 | 1562 | for _ in 0..length { |
|
| 1555 | 1563 | try lowerConstDataInto(self, repeat.item, elemTy, elemLayout.size, dataPrefix, b); |
|
| 1556 | 1564 | } |
|
| 1557 | 1565 | } |
test/tests/const.array.repeat.string.slice.rad
added
+11 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | /// Repeated string slices in constant arrays must emit complete slice headers. |
|
| 3 | + | constant WORDS: [*[u8]; 2] = ["abc"; 2]; |
|
| 4 | + | ||
| 5 | + | @default fn main() -> i32 { |
|
| 6 | + | assert WORDS[0].len == 3; |
|
| 7 | + | assert WORDS[1].len == 3; |
|
| 8 | + | assert WORDS[0][0] == 'a'; |
|
| 9 | + | assert WORDS[1][2] == 'c'; |
|
| 10 | + | return 0; |
|
| 11 | + | } |
test/tests/const.array.repeat.string.slice.ril
added
+60 -0
| 1 | + | data $WORDS$literal$0 align 1 { |
|
| 2 | + | str "abc"; |
|
| 3 | + | } |
|
| 4 | + | ||
| 5 | + | data $WORDS align 8 { |
|
| 6 | + | sym $WORDS$literal$0; |
|
| 7 | + | w32 3; |
|
| 8 | + | w32 3; |
|
| 9 | + | sym $WORDS$literal$0; |
|
| 10 | + | w32 3; |
|
| 11 | + | w32 3; |
|
| 12 | + | } |
|
| 13 | + | ||
| 14 | + | fn w32 $main() { |
|
| 15 | + | @entry0 |
|
| 16 | + | copy %0 $WORDS; |
|
| 17 | + | load w32 %1 %0 8; |
|
| 18 | + | br.eq w32 %1 3 @assert.ok2 @assert.fail1; |
|
| 19 | + | @assert.fail1 |
|
| 20 | + | unreachable; |
|
| 21 | + | @assert.ok2 |
|
| 22 | + | copy %2 $WORDS; |
|
| 23 | + | mul w64 %3 1 16; |
|
| 24 | + | add w64 %4 %2 %3; |
|
| 25 | + | load w32 %5 %4 8; |
|
| 26 | + | br.eq w32 %5 3 @assert.ok4 @assert.fail3; |
|
| 27 | + | @assert.fail3 |
|
| 28 | + | unreachable; |
|
| 29 | + | @assert.ok4 |
|
| 30 | + | copy %6 $WORDS; |
|
| 31 | + | load w32 %7 %6 8; |
|
| 32 | + | br.ult w32 0 %7 @guard#pass7 @guard#trap8; |
|
| 33 | + | @assert.fail5 |
|
| 34 | + | unreachable; |
|
| 35 | + | @assert.ok6 |
|
| 36 | + | copy %10 $WORDS; |
|
| 37 | + | mul w64 %11 1 16; |
|
| 38 | + | add w64 %12 %10 %11; |
|
| 39 | + | load w32 %13 %12 8; |
|
| 40 | + | br.ult w32 2 %13 @guard#pass11 @guard#trap12; |
|
| 41 | + | @guard#pass7 |
|
| 42 | + | load w64 %8 %6 0; |
|
| 43 | + | load w8 %9 %8 0; |
|
| 44 | + | br.eq w8 %9 97 @assert.ok6 @assert.fail5; |
|
| 45 | + | @guard#trap8 |
|
| 46 | + | ebreak; |
|
| 47 | + | unreachable; |
|
| 48 | + | @assert.fail9 |
|
| 49 | + | unreachable; |
|
| 50 | + | @assert.ok10 |
|
| 51 | + | ret 0; |
|
| 52 | + | @guard#pass11 |
|
| 53 | + | load w64 %14 %12 0; |
|
| 54 | + | add w64 %15 %14 2; |
|
| 55 | + | load w8 %16 %15 0; |
|
| 56 | + | br.eq w8 %16 99 @assert.ok10 @assert.fail9; |
|
| 57 | + | @guard#trap12 |
|
| 58 | + | ebreak; |
|
| 59 | + | unreachable; |
|
| 60 | + | } |