compiler: Build string data through checked storage

508ce34e05a6b7feaf9f06e7e9767134a787398f71cc6966f1e9fb0804e629fa
Alexis Sellier committed ago 1 parent 54994768
lib/std/lang/lower.rad +7 -15
1895 1895
    dataPrefix: *[u8]
1896 1896
) -> *[u8] throws (LowerError) where 'arena: 'phase {
1897 1897
    if let existing = findStringData(self, s) {
1898 1898
        return existing;
1899 1899
    }
1900 -
    let values = try! alloc::allocSlice(
1901 -
        self.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue), 1
1902 -
    ) as *mut [il::DataValue];
1903 -
1904 -
    set values[0] = il::DataValue {
1905 -
        item: il::DataItem::Str(s),
1906 -
        count: 1
1907 -
    };
1908 -
    return try pushDeclData(self, s.len, 1, true, &values[..1], dataPrefix);
1900 +
    let mut builder = dataBuilder(alloc::arenaAllocator(self.arena));
1901 +
    dataBuilderPush(&mut builder, il::DataValue { item: il::DataItem::Str(s), count: 1 });
1902 +
    let result = dataBuilderFinish(builder);
1903 +
    return try pushDeclData(self, s.len, 1, true, result.values, dataPrefix);
1909 1904
}
1910 1905
1911 1906
/// Compare two data items for structural equality.
1912 1907
/// Unlike raw byte comparison, this correctly ignores padding bytes in unions.
1913 1908
fn dataItemEq(a: il::DataItem, b: il::DataItem) -> bool {
6403 6398
    // Get the slice type from the node.
6404 6399
    let sliceTy = try typeOf(self, node);
6405 6400
    let case resolver::Type::Slice { item, mutable, .. } = sliceTy
6406 6401
        else throw LowerError::ExpectedSliceOrArray;
6407 6402
    // Build the string data value.
6408 -
    let ptr = try! alloc::alloc(
6409 -
        self.low.arena, @sizeOf(il::DataValue), @alignOf(il::DataValue)
6410 -
    ) as *mut il::DataValue;
6411 -
6412 -
    set *ptr = il::DataValue { item: il::DataItem::Str(s), count: 1 };
6413 -
    let result = ConstDataResult { values: @sliceOf(ptr, 1), zeroInit: false };
6403 +
    let mut builder = dataBuilder(alloc::arenaAllocator(self.low.arena));
6404 +
    dataBuilderPush(&mut builder, il::DataValue { item: il::DataItem::Str(s), count: 1 });
6405 +
    let result = dataBuilderFinish(builder);
6414 6406
6415 6407
    return try lowerConstDataAsSlice(
6416 6408
        self, &result, 1, true, item, mutable, s.len
6417 6409
    );
6418 6410
}
test/tests/const.backing.names.rad +16 -0
4 4
constant WORDS: [*[u8]; 12] = ["a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhh", "iiiiiiiii", "jjjjjjjjjj", "kkkkkkkkkkk", "llllllllllll"];
5 5
6 6
/// A separate declaration with some identical string contents.
7 7
constant OTHER: [*[u8]; 3] = ["ccc", "a", "bb"];
8 8
9 +
/// Backing strings include zero-length and embedded-zero payloads.
10 +
constant SPECIAL: [*[u8]; 3] = ["", "a\0b", "\0"];
11 +
9 12
/// Check that generated names retain the correct backing bytes.
10 13
@default fn main() -> u32 {
11 14
    for index in 0..WORDS.len {
12 15
        let word = WORDS[index];
13 16
        assert word.len == index + 1;
16 19
        }
17 20
    }
18 21
    assert OTHER[0] == WORDS[2];
19 22
    assert OTHER[1] == WORDS[0];
20 23
    assert OTHER[2] == WORDS[1];
24 +
    let empty = "";
25 +
    let embedded = "a\0b";
26 +
    let zero = "\0";
27 +
    assert empty.len == 0;
28 +
    assert SPECIAL[0].len == 0;
29 +
    assert embedded.len == 3;
30 +
    assert embedded[0] == 'a';
31 +
    assert embedded[1] == 0;
32 +
    assert embedded[2] == 'b';
33 +
    assert zero.len == 1;
34 +
    assert zero[0] == 0;
35 +
    assert SPECIAL[1] == embedded;
36 +
    assert SPECIAL[2] == zero;
21 37
    return 0;
22 38
}