Require unsafe context for undefined values
5ef2ba405899069b703e595116a505f66deafdfe46fe578292be834469dbaf87
1 parent
3c86541c
compiler/radiance.rad
+19 -19
| 44 | 44 | /// Main arena size (96 MB) - lives throughout compilation. |
|
| 45 | 45 | /// Used for: resolver data, types, symbols, global IL data, and codegen output. |
|
| 46 | 46 | constant MAIN_ARENA_SIZE: u32 = 100663296; |
|
| 47 | 47 | ||
| 48 | 48 | /// AST storage arena. |
|
| 49 | - | static TEMP_ARENA: [u8; TEMP_ARENA_SIZE] = undefined; |
|
| 49 | + | static TEMP_ARENA: [u8; TEMP_ARENA_SIZE] = [0; TEMP_ARENA_SIZE]; |
|
| 50 | 50 | /// Scratch storage reclaimed after each generated function. |
|
| 51 | - | static FN_ARENA: [u8; FN_ARENA_SIZE] = undefined; |
|
| 51 | + | static FN_ARENA: [u8; FN_ARENA_SIZE] = [0; FN_ARENA_SIZE]; |
|
| 52 | 52 | /// Main storage arena - persists throughout compilation. |
|
| 53 | - | static MAIN_ARENA: [u8; MAIN_ARENA_SIZE] = undefined; |
|
| 53 | + | static MAIN_ARENA: [u8; MAIN_ARENA_SIZE] = [0; MAIN_ARENA_SIZE]; |
|
| 54 | 54 | ||
| 55 | 55 | /// Module source code. |
|
| 56 | - | static MODULE_SOURCES: [u8; MAX_SOURCES_SIZE] = undefined; |
|
| 56 | + | static MODULE_SOURCES: [u8; MAX_SOURCES_SIZE] = [0; MAX_SOURCES_SIZE]; |
|
| 57 | 57 | /// Module entries for all packages. |
|
| 58 | - | static MODULE_ENTRIES: [module::ModuleEntry; MAX_TOTAL_MODULES] = undefined; |
|
| 58 | + | unsafe static MODULE_ENTRIES: [module::ModuleEntry; MAX_TOTAL_MODULES] = undefined; |
|
| 59 | 59 | /// String pool. |
|
| 60 | - | static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 60 | + | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 61 | 61 | ||
| 62 | 62 | /// Package scope. |
|
| 63 | - | static RESOLVER_PKG_SCOPE: resolver::Scope = undefined; |
|
| 63 | + | unsafe static RESOLVER_PKG_SCOPE: resolver::Scope = undefined; |
|
| 64 | 64 | /// Errors emitted by resolver. |
|
| 65 | - | static RESOLVER_ERRORS: [resolver::Error; resolver::MAX_ERRORS] = undefined; |
|
| 65 | + | unsafe static RESOLVER_ERRORS: [resolver::Error; resolver::MAX_ERRORS] = undefined; |
|
| 66 | 66 | ||
| 67 | 67 | /// Code generation storage. |
|
| 68 | - | static CODEGEN_DATA_SYMS: [data::DataSym; data::MAX_DATA_SYMS] = undefined; |
|
| 68 | + | unsafe static CODEGEN_DATA_SYMS: [data::DataSym; data::MAX_DATA_SYMS] = undefined; |
|
| 69 | 69 | /// Hash table entries for data symbol lookup. |
|
| 70 | - | static CODEGEN_DATA_SYM_ENTRIES: [dict::Entry; data::DATA_SYM_TABLE_SIZE] = undefined; |
|
| 70 | + | unsafe static CODEGEN_DATA_SYM_ENTRIES: [dict::Entry; data::DATA_SYM_TABLE_SIZE] = undefined; |
|
| 71 | 71 | ||
| 72 | 72 | /// Debug info file extension. |
|
| 73 | 73 | constant DEBUG_EXT: *[u8] = ".debug"; |
|
| 74 | 74 | ||
| 75 | 75 | /// Maximum rodata size (4MB). |
| 77 | 77 | /// Maximum rwdata size (4MB). |
|
| 78 | 78 | constant MAX_RW_DATA_SIZE: u32 = 4194304; |
|
| 79 | 79 | /// Maximum path length. |
|
| 80 | 80 | constant MAX_PATH_LEN: u32 = 256; |
|
| 81 | 81 | /// Read-only data buffer. |
|
| 82 | - | static RO_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = undefined; |
|
| 82 | + | static RO_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = [0; MAX_RO_DATA_SIZE]; |
|
| 83 | 83 | /// Read-write data buffer. |
|
| 84 | - | static RW_DATA_BUF: [u8; MAX_RW_DATA_SIZE] = undefined; |
|
| 84 | + | static RW_DATA_BUF: [u8; MAX_RW_DATA_SIZE] = [0; MAX_RW_DATA_SIZE]; |
|
| 85 | 85 | /// Assembly module source buffer. |
|
| 86 | - | static ASM_SOURCE_BUF: [u8; MAX_SOURCES_SIZE] = undefined; |
|
| 86 | + | static ASM_SOURCE_BUF: [u8; MAX_SOURCES_SIZE] = [0; MAX_SOURCES_SIZE]; |
|
| 87 | 87 | /// Temporary assembly text buffer. |
|
| 88 | - | static ASM_TEXT_BUF: [u32; 262144] = undefined; |
|
| 88 | + | static ASM_TEXT_BUF: [u32; 262144] = [0; 262144]; |
|
| 89 | 89 | /// Temporary assembly data buffer. |
|
| 90 | - | static ASM_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = undefined; |
|
| 90 | + | static ASM_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = [0; MAX_RO_DATA_SIZE]; |
|
| 91 | 91 | /// Accumulated assembly read-only data. |
|
| 92 | - | static ASM_RO_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = undefined; |
|
| 92 | + | static ASM_RO_DATA_BUF: [u8; MAX_RO_DATA_SIZE] = [0; MAX_RO_DATA_SIZE]; |
|
| 93 | 93 | ||
| 94 | 94 | /// Assembly source file extension. |
|
| 95 | 95 | constant ASM_SOURCE_EXT: *[u8] = ".ras"; |
|
| 96 | 96 | /// Symbol name exported for startup code to call the semantic entry function. |
|
| 97 | 97 | export constant DEFAULT_ENTRY_SYMBOL: *[u8] = "::default"; |
| 230 | 230 | /// Create an empty source input set for one package. |
|
| 231 | 231 | fn packageInput(name: *[u8]) -> PackageInput { |
|
| 232 | 232 | return PackageInput { |
|
| 233 | 233 | name, |
|
| 234 | 234 | startupPath: nil, |
|
| 235 | - | radPaths: undefined, |
|
| 235 | + | radPaths: [""; MAX_LOADED_MODULES], |
|
| 236 | 236 | radPathCount: 0, |
|
| 237 | - | asmPaths: undefined, |
|
| 237 | + | asmPaths: [""; MAX_ASM_MODULES], |
|
| 238 | 238 | asmPathCount: 0, |
|
| 239 | 239 | }; |
|
| 240 | 240 | } |
|
| 241 | 241 | ||
| 242 | 242 | /// Register, load, and parse `path` within `pkg`. |
| 799 | 799 | fn writeDataWithExt( |
|
| 800 | 800 | data: *[u8], |
|
| 801 | 801 | basePath: *[u8], |
|
| 802 | 802 | ext: *[u8] |
|
| 803 | 803 | ) throws (Error) { |
|
| 804 | - | let mut path: [u8; MAX_PATH_LEN] = undefined; |
|
| 804 | + | let mut path: [u8; MAX_PATH_LEN] = [0; MAX_PATH_LEN]; |
|
| 805 | 805 | let mut pos: u32 = 0; |
|
| 806 | 806 | ||
| 807 | 807 | set pos += try! mem::copy(&mut path[pos..], basePath); |
|
| 808 | 808 | set pos += try! mem::copy(&mut path[pos..], ext); |
|
| 809 | 809 | set path[pos] = 0; // Null-terminate for syscall. |
lib/std/arch/rv64/asm/scanner/tests.rad
+4 -2
| 1 | 1 | use std::mem; |
|
| 2 | 2 | use std::testing; |
|
| 3 | 3 | use std::lang::strings; |
|
| 4 | 4 | ||
| 5 | 5 | /// String pool used by assembler scanner tests. |
|
| 6 | - | static TEST_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 6 | + | unsafe static TEST_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 7 | 7 | ||
| 8 | 8 | /// Create a scanner for test input. |
|
| 9 | 9 | fn testScanner(source: *[u8]) -> super::Scanner { |
|
| 10 | - | return super::scanner(super::SourceKind::String, source, &mut TEST_STRING_POOL); |
|
| 10 | + | unsafe { |
|
| 11 | + | return super::scanner(super::SourceKind::String, source, &mut TEST_STRING_POOL); |
|
| 12 | + | } |
|
| 11 | 13 | } |
|
| 12 | 14 | ||
| 13 | 15 | /// Scanner recognizes assembler-specific sigils and scoped names. |
|
| 14 | 16 | @test fn testScanRegisterDirectiveAndLabelTokens() throws (testing::TestError) { |
|
| 15 | 17 | let mut s = testScanner( |
lib/std/arch/rv64/asm/tests.rad
+6 -6
| 9 | 9 | use std::arch::rv64::encode; |
|
| 10 | 10 | use std::arch::rv64::printer; |
|
| 11 | 11 | ||
| 12 | 12 | use super::scanner; |
|
| 13 | 13 | ||
| 14 | - | static ASM_ARENA_STORAGE: [u8; 65536] = undefined; |
|
| 15 | - | static ASM_TEXT_STORAGE: [u32; 256] = undefined; |
|
| 16 | - | static ASM_DATA_STORAGE: [u8; 1024] = undefined; |
|
| 17 | - | static ASM_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 18 | - | static PRINT_ARENA_STORAGE: [u8; 1024] = undefined; |
|
| 19 | - | static PRINT_BUFFER: [u8; 128] = undefined; |
|
| 14 | + | static ASM_ARENA_STORAGE: [u8; 65536] = [0; 65536]; |
|
| 15 | + | static ASM_TEXT_STORAGE: [u32; 256] = [0; 256]; |
|
| 16 | + | static ASM_DATA_STORAGE: [u8; 1024] = [0; 1024]; |
|
| 17 | + | unsafe static ASM_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 18 | + | static PRINT_ARENA_STORAGE: [u8; 1024] = [0; 1024]; |
|
| 19 | + | static PRINT_BUFFER: [u8; 128] = [0; 128]; |
|
| 20 | 20 | ||
| 21 | 21 | unsafe fn assembleSource(source: *[u8]) -> super::Program throws (testing::TestError) { |
|
| 22 | 22 | let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]); |
|
| 23 | 23 | return try super::assemble( |
|
| 24 | 24 | scanner::SourceKind::String, |
lib/std/arch/rv64/emit.rad
+1 -1
| 143 | 143 | ||
| 144 | 144 | /// Compute frame layout from local size and used callee-saved registers. |
|
| 145 | 145 | export fn computeFrame(localSize: i32, usedCalleeSaved: u32, epilogueBlock: u32, isLeaf: bool, isDynamic: bool) -> Frame { |
|
| 146 | 146 | let mut frame = Frame { |
|
| 147 | 147 | totalSize: 0, |
|
| 148 | - | savedRegs: undefined, |
|
| 148 | + | savedRegs: [SavedReg { reg: super::ZERO, offset: 0 }; super::NUM_SAVED_REGISTERS], |
|
| 149 | 149 | savedRegsLen: 0, |
|
| 150 | 150 | epilogueBlock, |
|
| 151 | 151 | isLeaf, |
|
| 152 | 152 | isDynamic, |
|
| 153 | 153 | }; |
lib/std/arch/rv64/tests.rad
+2 -2
| 8 | 8 | use std::collections::dict; |
|
| 9 | 9 | ||
| 10 | 10 | use super::encode; |
|
| 11 | 11 | use super::asm; |
|
| 12 | 12 | ||
| 13 | - | static ASSEMBLY_ARENA_STORAGE: [u8; 16777216] = undefined; |
|
| 14 | - | static ASSEMBLY_TEXT_STORAGE: [u32; 2] = undefined; |
|
| 13 | + | static ASSEMBLY_ARENA_STORAGE: [u8; 16777216] = [0; 16777216]; |
|
| 14 | + | static ASSEMBLY_TEXT_STORAGE: [u32; 2] = [0; 2]; |
|
| 15 | 15 | ||
| 16 | 16 | /// Helper to check encoding equals expected value. |
|
| 17 | 17 | fn expectEncoding(actual: u32, expected: u32) throws (testing::TestError) { |
|
| 18 | 18 | try testing::expect(actual == expected); |
|
| 19 | 19 | } |
lib/std/lang/alloc/tests.rad
+8 -8
| 2 | 2 | ||
| 3 | 3 | use std::testing; |
|
| 4 | 4 | ||
| 5 | 5 | /// Test basic allocation. |
|
| 6 | 6 | @test fn testAllocBasic() throws (testing::TestError) { |
|
| 7 | - | static STORAGE: [u8; 64] = undefined; |
|
| 7 | + | static STORAGE: [u8; 64] = [0; 64]; |
|
| 8 | 8 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 9 | 9 | ||
| 10 | 10 | let ptr = try! super::alloc(&mut arena, 4, 4); |
|
| 11 | 11 | try testing::expect(super::used(&arena) == 4); |
|
| 12 | 12 | try testing::expect(super::remaining(&arena) == 60); |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | 15 | /// Test that allocations are properly aligned. |
|
| 16 | 16 | @test fn testAllocAlignment() throws (testing::TestError) { |
|
| 17 | - | static STORAGE: [u8; 64] = undefined; |
|
| 17 | + | static STORAGE: [u8; 64] = [0; 64]; |
|
| 18 | 18 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 19 | 19 | ||
| 20 | 20 | // Allocate 1 byte with 1-byte alignment. |
|
| 21 | 21 | let p1 = try! super::alloc(&mut arena, 1, 1); |
|
| 22 | 22 | try testing::expect(super::used(&arena) == 1); |
| 26 | 26 | try testing::expect(super::used(&arena) == 8); // 1 + 3 padding + 4 |
|
| 27 | 27 | } |
|
| 28 | 28 | ||
| 29 | 29 | /// Test multiple allocations. |
|
| 30 | 30 | @test fn testAllocMultiple() throws (testing::TestError) { |
|
| 31 | - | static STORAGE: [u8; 128] = undefined; |
|
| 31 | + | static STORAGE: [u8; 128] = [0; 128]; |
|
| 32 | 32 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 33 | 33 | ||
| 34 | 34 | let p1 = try! super::alloc(&mut arena, 8, 4); |
|
| 35 | 35 | let p2 = try! super::alloc(&mut arena, 16, 4); |
|
| 36 | 36 | let p3 = try! super::alloc(&mut arena, 4, 4); |
| 38 | 38 | try testing::expect(super::used(&arena) == 28); // 8 + 16 + 4 |
|
| 39 | 39 | } |
|
| 40 | 40 | ||
| 41 | 41 | /// Test that arena throws when exhausted. |
|
| 42 | 42 | @test fn testAllocExhausted() throws (testing::TestError) { |
|
| 43 | - | static STORAGE: [u8; 16] = undefined; |
|
| 43 | + | static STORAGE: [u8; 16] = [0; 16]; |
|
| 44 | 44 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 45 | 45 | ||
| 46 | 46 | // This should succeed. |
|
| 47 | 47 | let p1 = try! super::alloc(&mut arena, 8, 4); |
|
| 48 | 48 |
| 57 | 57 | try testing::expect(failed); |
|
| 58 | 58 | } |
|
| 59 | 59 | ||
| 60 | 60 | /// Test that reset allows reuse of memory. |
|
| 61 | 61 | @test fn testAllocReset() throws (testing::TestError) { |
|
| 62 | - | static STORAGE: [u8; 32] = undefined; |
|
| 62 | + | static STORAGE: [u8; 32] = [0; 32]; |
|
| 63 | 63 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 64 | 64 | ||
| 65 | 65 | let p1 = try! super::alloc(&mut arena, 16, 4); |
|
| 66 | 66 | try testing::expect(super::used(&arena) == 16); |
|
| 67 | 67 |
| 73 | 73 | let p2 = try! super::alloc(&mut arena, 32, 4); |
|
| 74 | 74 | } |
|
| 75 | 75 | ||
| 76 | 76 | /// Test alignment when offset is already aligned. |
|
| 77 | 77 | @test fn testAllocAlreadyAligned() throws (testing::TestError) { |
|
| 78 | - | static STORAGE: [u8; 64] = undefined; |
|
| 78 | + | static STORAGE: [u8; 64] = [0; 64]; |
|
| 79 | 79 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 80 | 80 | ||
| 81 | 81 | // Allocate 4 bytes - offset becomes 4, already aligned for next 4-byte alloc. |
|
| 82 | 82 | let p1 = try! super::alloc(&mut arena, 4, 4); |
|
| 83 | 83 | try testing::expect(super::used(&arena) == 4); |
| 87 | 87 | try testing::expect(super::used(&arena) == 8); |
|
| 88 | 88 | } |
|
| 89 | 89 | ||
| 90 | 90 | /// Test allocation that would overflow with alignment padding. |
|
| 91 | 91 | @test fn testAllocOverflowWithPadding() throws (testing::TestError) { |
|
| 92 | - | static STORAGE: [u8; 16] = undefined; |
|
| 92 | + | static STORAGE: [u8; 16] = [0; 16]; |
|
| 93 | 93 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 94 | 94 | ||
| 95 | 95 | // Allocate 1 byte, offset is now 1. |
|
| 96 | 96 | let p1 = try! super::alloc(&mut arena, 1, 1); |
|
| 97 | 97 |
| 104 | 104 | try testing::expect(failed); |
|
| 105 | 105 | } |
|
| 106 | 106 | ||
| 107 | 107 | /// Test the Allocator interface backed by an arena. |
|
| 108 | 108 | @test unsafe fn testAllocator() throws (testing::TestError) { |
|
| 109 | - | static STORAGE: [u8; 256] = undefined; |
|
| 109 | + | static STORAGE: [u8; 256] = [0; 256]; |
|
| 110 | 110 | let mut arena = super::new(&mut STORAGE[..]); |
|
| 111 | 111 | let a = super::arenaAllocator(&mut arena); |
|
| 112 | 112 | ||
| 113 | 113 | // Allocate through the Allocator indirection. |
|
| 114 | 114 | let p1 = a.func(a.ctx, 16, 4); |
lib/std/lang/lower.rad
+4 -6
| 845 | 845 | } |
|
| 846 | 846 | } |
|
| 847 | 847 | ||
| 848 | 848 | /// Finalize lowering and return the unified IL program. |
|
| 849 | 849 | export fn finalize(low: &Lowerer) -> il::Program { |
|
| 850 | - | let mut fns: *mut [*il::Fn] = undefined; |
|
| 851 | 850 | match low.output { |
|
| 852 | 851 | case FnOutput::Accumulate(accumulated) => { |
|
| 853 | - | set fns = accumulated; |
|
| 852 | + | return il::Program { |
|
| 853 | + | data: &low.data[..], |
|
| 854 | + | fns: &accumulated[..], |
|
| 855 | + | }; |
|
| 854 | 856 | } |
|
| 855 | 857 | case FnOutput::Stream(_) => { |
|
| 856 | 858 | panic "finalize: cannot finalize streaming lowerer"; |
|
| 857 | 859 | } |
|
| 858 | 860 | } |
|
| 859 | - | return il::Program { |
|
| 860 | - | data: &low.data[..], |
|
| 861 | - | fns: &fns[..], |
|
| 862 | - | }; |
|
| 863 | 861 | } |
|
| 864 | 862 | ||
| 865 | 863 | ///////////////////////////////// |
|
| 866 | 864 | // Qualified Name Construction // |
|
| 867 | 865 | ///////////////////////////////// |
lib/std/lang/module.rad
+3 -3
| 285 | 285 | let pathSuffix = mem::stripPrefix(baseDir, filePath) else { |
|
| 286 | 286 | throw ModuleError::InvalidPath; |
|
| 287 | 287 | }; |
|
| 288 | 288 | ||
| 289 | 289 | // Parse the stripped path into components. |
|
| 290 | - | let mut parts: [*[u8]; MAX_MODULE_PATH_DEPTH] = undefined; |
|
| 290 | + | let mut parts: [*[u8]; MAX_MODULE_PATH_DEPTH] = [""; MAX_MODULE_PATH_DEPTH]; |
|
| 291 | 291 | let partsLen = parsePath(pathSuffix, &mut parts[..]) else { |
|
| 292 | 292 | throw ModuleError::InvalidPath; |
|
| 293 | 293 | }; |
|
| 294 | 294 | if partsLen == 0 { |
|
| 295 | 295 | throw ModuleError::InvalidPath; |
| 331 | 331 | packageId, |
|
| 332 | 332 | parent: nil, |
|
| 333 | 333 | filePath, |
|
| 334 | 334 | dirLen: 0, |
|
| 335 | 335 | name: strings::intern(graph.pool, name), |
|
| 336 | - | path: undefined, |
|
| 336 | + | path: [""; MAX_MODULE_PATH_DEPTH], |
|
| 337 | 337 | pathDepth: 0, |
|
| 338 | 338 | state: ModuleState::Vacant, |
|
| 339 | - | children: undefined, |
|
| 339 | + | children: [0; MAX_MODULES], |
|
| 340 | 340 | childrenLen: 0, |
|
| 341 | 341 | ast: nil, |
|
| 342 | 342 | source: nil, |
|
| 343 | 343 | }; |
|
| 344 | 344 | set m.dirLen = dirLength(m.filePath); |
lib/std/lang/module/tests.rad
+5 -5
| 4 | 4 | use std::testing; |
|
| 5 | 5 | use std::lang::ast; |
|
| 6 | 6 | use std::lang::strings; |
|
| 7 | 7 | ||
| 8 | 8 | /// Test arena backing storage. |
|
| 9 | - | static TEST_ARENA: [u8; 4096] = undefined; |
|
| 9 | + | static TEST_ARENA: [u8; 4096] = [0; 4096]; |
|
| 10 | 10 | /// Interned string pool. |
|
| 11 | - | static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 11 | + | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 12 | 12 | ||
| 13 | 13 | fn expectSliceEq(actual: *[u8], expected: *[u8]) |
|
| 14 | 14 | throws (testing::TestError) |
|
| 15 | 15 | { |
|
| 16 | 16 | if not mem::eq(actual, expected) { |
| 114 | 114 | try testing::expect(result == nil); |
|
| 115 | 115 | } |
|
| 116 | 116 | ||
| 117 | 117 | @test fn testParsePathSingleComponent() throws (testing::TestError) { |
|
| 118 | 118 | let path = "std.rad"; |
|
| 119 | - | let mut components: [*[u8]; 8] = undefined; |
|
| 119 | + | let mut components: [*[u8]; 8] = [""; 8]; |
|
| 120 | 120 | let count = super::parsePath(path, &mut components[..]) else { |
|
| 121 | 121 | throw testing::TestError::Failed; |
|
| 122 | 122 | }; |
|
| 123 | 123 | try testing::expect(count == 1); |
|
| 124 | 124 | try expectSliceEq(components[0], "std"); |
|
| 125 | 125 | } |
|
| 126 | 126 | ||
| 127 | 127 | @test fn testParsePathMultipleComponents() throws (testing::TestError) { |
|
| 128 | 128 | let path = "std/lang/parser.rad"; |
|
| 129 | - | let mut components: [*[u8]; 8] = undefined; |
|
| 129 | + | let mut components: [*[u8]; 8] = [""; 8]; |
|
| 130 | 130 | let count = super::parsePath(path, &mut components[..]) else { |
|
| 131 | 131 | throw testing::TestError::Failed; |
|
| 132 | 132 | }; |
|
| 133 | 133 | try testing::expect(count == 3); |
|
| 134 | 134 | try expectSliceEq(components[0], "std"); |
| 136 | 136 | try expectSliceEq(components[2], "parser"); |
|
| 137 | 137 | } |
|
| 138 | 138 | ||
| 139 | 139 | @test fn testParsePathWithoutExtension() throws (testing::TestError) { |
|
| 140 | 140 | let path = "std/lang/parser"; |
|
| 141 | - | let mut components: [*[u8]; 8] = undefined; |
|
| 141 | + | let mut components: [*[u8]; 8] = [""; 8]; |
|
| 142 | 142 | let result = super::parsePath(path, &mut components[..]); |
|
| 143 | 143 | try testing::expect(result == nil); |
|
| 144 | 144 | } |
|
| 145 | 145 | ||
| 146 | 146 | @test unsafe fn testRegisterFromPathHierarchy() throws (testing::TestError) { |
lib/std/lang/parser/tests.rad
+2 -2
| 12 | 12 | use std::lang::strings; |
|
| 13 | 13 | ||
| 14 | 14 | /// Unified arena size. |
|
| 15 | 15 | constant ARENA_SIZE: u32 = 2097152; |
|
| 16 | 16 | /// Unified arena storage for all AST allocations. |
|
| 17 | - | static ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 17 | + | static ARENA_STORAGE: [u8; ARENA_SIZE] = [0; ARENA_SIZE]; |
|
| 18 | 18 | /// String pool. |
|
| 19 | - | static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 19 | + | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 20 | 20 | ||
| 21 | 21 | /// Assert that a node is an identifier with the given name. |
|
| 22 | 22 | fn expectIdent(node: *ast::Node, name: *[u8]) |
|
| 23 | 23 | throws (testing::TestError) |
|
| 24 | 24 | { |
lib/std/lang/resolver.rad
+1 -0
| 2955 | 2955 | return setNodeType(self, node, hint); |
|
| 2956 | 2956 | } |
|
| 2957 | 2957 | return setNodeType(self, node, Type::Nil); |
|
| 2958 | 2958 | }, |
|
| 2959 | 2959 | case ast::NodeValue::Undef => { |
|
| 2960 | + | try requireUnsafe(self, node); |
|
| 2960 | 2961 | return setNodeType(self, node, Type::Undefined); |
|
| 2961 | 2962 | }, |
|
| 2962 | 2963 | case ast::NodeValue::Bool(value) => { |
|
| 2963 | 2964 | setNodeConstValue(self, node, ConstValue::Bool(value)); |
|
| 2964 | 2965 | return setNodeType(self, node, Type::Bool); |
lib/std/lang/resolver/tests.rad
+65 -25
| 12 | 12 | ||
| 13 | 13 | /// Synthetic file path used for resolver tests. |
|
| 14 | 14 | constant MODULE_PATH: *[u8] = "/dev/test.rad"; |
|
| 15 | 15 | ||
| 16 | 16 | /// AST arena storage used by resolver tests. |
|
| 17 | - | static AST_ARENA: [u8; 2097152] = undefined; |
|
| 17 | + | static AST_ARENA: [u8; 2097152] = [0; 2097152]; |
|
| 18 | 18 | ||
| 19 | 19 | /// Resolver arena storage used by resolver tests. |
|
| 20 | - | static ARENA_STORAGE: [u8; 2097152] = undefined; |
|
| 20 | + | static ARENA_STORAGE: [u8; 2097152] = [0; 2097152]; |
|
| 21 | 21 | ||
| 22 | 22 | /// Node metadata storage used by resolver tests. |
|
| 23 | - | static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined; |
|
| 23 | + | unsafe static NODE_DATA_STORAGE: [super::NodeData; 256] = undefined; |
|
| 24 | 24 | ||
| 25 | 25 | /// Diagnostic storage used by resolver tests. |
|
| 26 | - | static ERROR_STORAGE: [super::Error; 16] = undefined; |
|
| 26 | + | unsafe static ERROR_STORAGE: [super::Error; 16] = undefined; |
|
| 27 | 27 | ||
| 28 | 28 | /// Package scope used by resolver tests. |
|
| 29 | - | static PKG_SCOPE: super::Scope = undefined; |
|
| 29 | + | unsafe static PKG_SCOPE: super::Scope = undefined; |
|
| 30 | 30 | ||
| 31 | 31 | /// Module entries used by resolver tests. |
|
| 32 | - | static MODULE_ENTRIES: [module::ModuleEntry; 8] = undefined; |
|
| 32 | + | unsafe static MODULE_ENTRIES: [module::ModuleEntry; 8] = undefined; |
|
| 33 | 33 | ||
| 34 | 34 | /// Module graph used by resolver tests. |
|
| 35 | - | static MODULE_GRAPH: module::ModuleGraph = undefined; |
|
| 35 | + | unsafe static MODULE_GRAPH: module::ModuleGraph = undefined; |
|
| 36 | 36 | ||
| 37 | 37 | /// Module AST arena storage used by resolver tests. |
|
| 38 | - | static MODULE_ARENA_STORAGE: [u8; 4096] = undefined; |
|
| 38 | + | static MODULE_ARENA_STORAGE: [u8; 4096] = [0; 4096]; |
|
| 39 | 39 | ||
| 40 | 40 | /// Module AST arena used by resolver tests. |
|
| 41 | - | static MODULE_ARENA: ast::NodeArena = undefined; |
|
| 41 | + | unsafe static MODULE_ARENA: ast::NodeArena = undefined; |
|
| 42 | 42 | ||
| 43 | 43 | /// Interned string pool used by resolver tests. |
|
| 44 | - | static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 44 | + | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 45 | 45 | ||
| 46 | 46 | /// String literals used in tests. |
|
| 47 | 47 | constant LITERALS: [*[u8]; 15] = [ |
|
| 48 | 48 | "Ok", "Error", "R", "S", |
|
| 49 | 49 | "f", "Status", "Pending", |
| 57 | 57 | diagnostics: super::Diagnostics, |
|
| 58 | 58 | root: *ast::Node, |
|
| 59 | 59 | } |
|
| 60 | 60 | ||
| 61 | 61 | /// Create isolated storage for tests to avoid conflicts with global resolver storage. |
|
| 62 | - | fn testStorage() -> super::ResolverStorage { |
|
| 62 | + | unsafe fn testStorage() -> super::ResolverStorage { |
|
| 63 | 63 | return super::ResolverStorage { |
|
| 64 | 64 | arena: alloc::new(&mut ARENA_STORAGE[..]), |
|
| 65 | 65 | nodeData: &mut NODE_DATA_STORAGE[..], |
|
| 66 | 66 | pkgScope: &mut PKG_SCOPE, |
|
| 67 | 67 | errors: &mut ERROR_STORAGE[..], |
| 2154 | 2154 | } |
|
| 2155 | 2155 | ||
| 2156 | 2156 | @test unsafe fn testUndefinedCoercions() throws (testing::TestError) { |
|
| 2157 | 2157 | { |
|
| 2158 | 2158 | let mut a = testResolver(); |
|
| 2159 | - | let result = try resolveBlockStr(&mut a, "let count: i32 = undefined;"); |
|
| 2159 | + | let result = try resolveBlockStr(&mut a, "unsafe { let count: i32 = undefined; }"); |
|
| 2160 | 2160 | try expectNoErrors(&result); |
|
| 2161 | 2161 | } { |
|
| 2162 | 2162 | let mut a = testResolver(); |
|
| 2163 | - | let program = "let mut value: i32 = 0; set value = undefined;"; |
|
| 2163 | + | let program = "unsafe { let mut value: i32 = 0; set value = undefined; }"; |
|
| 2164 | 2164 | let result = try resolveProgramStr(&mut a, program); |
|
| 2165 | 2165 | try expectNoErrors(&result); |
|
| 2166 | 2166 | } { |
|
| 2167 | 2167 | let mut a = testResolver(); |
|
| 2168 | - | let program = "fn f(x: i32) {} fn g() { f(undefined); }"; |
|
| 2168 | + | let program = "fn f(x: i32) {} unsafe fn g() { f(undefined); }"; |
|
| 2169 | 2169 | let result = try resolveProgramStr(&mut a, program); |
|
| 2170 | 2170 | try expectNoErrors(&result); |
|
| 2171 | 2171 | } { |
|
| 2172 | 2172 | let mut a = testResolver(); |
|
| 2173 | - | let program = "fn fetch() -> i32 { return undefined; }"; |
|
| 2173 | + | let program = "unsafe fn fetch() -> i32 { return undefined; }"; |
|
| 2174 | 2174 | let result = try resolveProgramStr(&mut a, program); |
|
| 2175 | 2175 | try expectNoErrors(&result); |
|
| 2176 | 2176 | } |
|
| 2177 | 2177 | } |
|
| 2178 | 2178 |
| 3672 | 3672 | let result = try resolveProgramStr(&mut a, "fn f(x: opaque) {}"); |
|
| 3673 | 3673 | let err = try expectError(&result); |
|
| 3674 | 3674 | try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed); |
|
| 3675 | 3675 | } { |
|
| 3676 | 3676 | let mut a = testResolver(); |
|
| 3677 | - | let result = try resolveProgramStr(&mut a, "fn f() { let x: opaque = undefined; }"); |
|
| 3677 | + | let result = try resolveProgramStr(&mut a, "unsafe fn f() { let x: opaque = undefined; }"); |
|
| 3678 | 3678 | let err = try expectError(&result); |
|
| 3679 | 3679 | try expectErrorKind(&result, super::ErrorKind::OpaqueTypeNotAllowed); |
|
| 3680 | 3680 | } { |
|
| 3681 | 3681 | let mut a = testResolver(); |
|
| 3682 | 3682 | let result = try resolveProgramStr(&mut a, "record R { x: opaque }"); |
| 3832 | 3832 | let mut a = testResolver(); |
|
| 3833 | 3833 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 3834 | 3834 | ||
| 3835 | 3835 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena); |
|
| 3836 | 3836 | let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant SIZE: u32 = 8;", &mut arena); |
|
| 3837 | - | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = undefined;", &mut arena); |
|
| 3837 | + | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; static BUFFER: [u8; consts::SIZE] = [0; consts::SIZE];", &mut arena); |
|
| 3838 | 3838 | ||
| 3839 | 3839 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 3840 | 3840 | try expectNoErrors(&result); |
|
| 3841 | 3841 | } |
|
| 3842 | 3842 |
| 4500 | 4500 | let mut a = testResolver(); |
|
| 4501 | 4501 | let result = try resolveBlockStr(&mut a, "static x: i32 = 0; let p = &x; p as u32;"); |
|
| 4502 | 4502 | try expectNoErrors(&result); |
|
| 4503 | 4503 | } { // Function pointer to numeric. |
|
| 4504 | 4504 | let mut a = testResolver(); |
|
| 4505 | - | let result = try resolveBlockStr(&mut a, "let f: fn() = undefined; f as u32;"); |
|
| 4505 | + | let result = try resolveProgramStr(&mut a, "fn run(f: fn()) { f as u32; }"); |
|
| 4506 | 4506 | try expectNoErrors(&result); |
|
| 4507 | 4507 | } { // *u8 to *i32 (u8 to i32 is valid). |
|
| 4508 | 4508 | let mut a = testResolver(); |
|
| 4509 | 4509 | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: *u8 = undefined; p as *i32; }"); |
|
| 4510 | 4510 | try expectNoErrors(&result); |
| 4514 | 4514 | try expectNoErrors(&result); |
|
| 4515 | 4515 | } |
|
| 4516 | 4516 | ||
| 4517 | 4517 | { // *[i32] to *[opaque]. |
|
| 4518 | 4518 | let mut a = testResolver(); |
|
| 4519 | - | let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *[opaque];"); |
|
| 4519 | + | let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *[opaque]; }"); |
|
| 4520 | 4520 | try expectNoErrors(&result); |
|
| 4521 | 4521 | } { // *[opaque] to *[i32]. |
|
| 4522 | 4522 | let mut a = testResolver(); |
|
| 4523 | 4523 | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[opaque] = undefined; s as *[i32]; }"); |
|
| 4524 | 4524 | try expectNoErrors(&result); |
| 4544 | 4544 | try expectNoErrors(&result); |
|
| 4545 | 4545 | } |
|
| 4546 | 4546 | ||
| 4547 | 4547 | { // Identity cast: *mut [i32] to *mut [i32]. |
|
| 4548 | 4548 | let mut a = testResolver(); |
|
| 4549 | - | let result = try resolveBlockStr(&mut a, "let s: *mut [i32] = undefined; s as *mut [i32];"); |
|
| 4549 | + | let result = try resolveProgramStr(&mut a, "fn run(s: *mut [i32]) { s as *mut [i32]; }"); |
|
| 4550 | 4550 | try expectNoErrors(&result); |
|
| 4551 | 4551 | } { // Identity cast: *i32 to *i32. |
|
| 4552 | 4552 | let mut a = testResolver(); |
|
| 4553 | - | let result = try resolveBlockStr(&mut a, "let p: *i32 = undefined; p as *i32;"); |
|
| 4553 | + | let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *i32; }"); |
|
| 4554 | 4554 | try expectNoErrors(&result); |
|
| 4555 | 4555 | } { // Identity cast: i32 to i32. |
|
| 4556 | 4556 | let mut a = testResolver(); |
|
| 4557 | 4557 | let result = try resolveBlockStr(&mut a, "let x: i32 = 0; x as i32;"); |
|
| 4558 | 4558 | try expectNoErrors(&result); |
| 4561 | 4561 | ||
| 4562 | 4562 | /// Tests for invalid `as` casts that should be rejected. |
|
| 4563 | 4563 | @test unsafe fn testResolveAsCastsInvalid() throws (testing::TestError) { |
|
| 4564 | 4564 | { // Pointer to slice is invalid. |
|
| 4565 | 4565 | let mut a = testResolver(); |
|
| 4566 | - | let result = try resolveBlockStr(&mut a, "let p: *i32 = undefined; p as *[i32];"); |
|
| 4566 | + | let result = try resolveProgramStr(&mut a, "fn run(p: *i32) { p as *[i32]; }"); |
|
| 4567 | 4567 | let err = try expectError(&result); |
|
| 4568 | 4568 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 4569 | 4569 | else throw testing::TestError::Failed; |
|
| 4570 | 4570 | } { // Slice to pointer is invalid. |
|
| 4571 | 4571 | let mut a = testResolver(); |
|
| 4572 | - | let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *i32;"); |
|
| 4572 | + | let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as *i32; }"); |
|
| 4573 | 4573 | let err = try expectError(&result); |
|
| 4574 | 4574 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 4575 | 4575 | else throw testing::TestError::Failed; |
|
| 4576 | 4576 | } { // *T to *i32 is invalid. |
|
| 4577 | 4577 | let mut a = testResolver(); |
| 4585 | 4585 | let err = try expectError(&result); |
|
| 4586 | 4586 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 4587 | 4587 | else throw testing::TestError::Failed; |
|
| 4588 | 4588 | } { // Slice to numeric is invalid. |
|
| 4589 | 4589 | let mut a = testResolver(); |
|
| 4590 | - | let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as u32;"); |
|
| 4590 | + | let result = try resolveProgramStr(&mut a, "fn run(s: *[i32]) { s as u32; }"); |
|
| 4591 | 4591 | let err = try expectError(&result); |
|
| 4592 | 4592 | let case super::ErrorKind::InvalidAsCast(_) = err.kind |
|
| 4593 | 4593 | else throw testing::TestError::Failed; |
|
| 4594 | 4594 | } { // *record to *u8 is invalid. |
|
| 4595 | 4595 | let mut a = testResolver(); |
| 5099 | 5099 | let mut a = testResolver(); |
|
| 5100 | 5100 | let mut arena = ast::nodeArena(&mut AST_ARENA[..]); |
|
| 5101 | 5101 | ||
| 5102 | 5102 | let rootId = try registerModule(&mut MODULE_GRAPH, nil, "root", "export mod consts; mod app;", &mut arena); |
|
| 5103 | 5103 | let constsId = try registerModule(&mut MODULE_GRAPH, rootId, "consts", "export constant WIDTH: u32 = 8; export constant HEIGHT: u32 = 4;", &mut arena); |
|
| 5104 | - | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = undefined;", &mut arena); |
|
| 5104 | + | let appId = try registerModule(&mut MODULE_GRAPH, rootId, "app", "use root::consts; constant TOTAL: u32 = consts::WIDTH * consts::HEIGHT; static BUF: [u8; TOTAL] = [0; TOTAL];", &mut arena); |
|
| 5105 | 5105 | ||
| 5106 | 5106 | let result = try resolveModuleTree(&mut a, rootId); |
|
| 5107 | 5107 | try expectNoErrors(&result); |
|
| 5108 | 5108 | } |
|
| 5109 | 5109 |
| 5680 | 5680 | let mut b = testResolver(); |
|
| 5681 | 5681 | let next = try resolveProgramStr(&mut b, "constant BYTES: *[u8] = \"x\"; unsafe static VALUE: u32 = 7; static DATA: *[u64] = BYTES as *[u64];"); |
|
| 5682 | 5682 | try expectErrorKind(&next, super::ErrorKind::UnsafeOperation); |
|
| 5683 | 5683 | } |
|
| 5684 | 5684 | ||
| 5685 | + | /// Uninitialized values require an explicit unsafe context in every value position. |
|
| 5686 | + | @test unsafe fn testUndefinedRequiresUnsafe() throws (testing::TestError) { |
|
| 5687 | + | let programs = &[ |
|
| 5688 | + | "fn run() -> u8 { let pointers: [*u8; 1] = undefined; return *pointers[0]; }", |
|
| 5689 | + | "fn run() { let n: u32 = undefined; }", |
|
| 5690 | + | "fn run() -> *u8 { return undefined; }", |
|
| 5691 | + | "fn take(p: *u8) {} fn run() { take(undefined); }", |
|
| 5692 | + | "fn run(p: *u8) { let mut q = p; set q = undefined; }", |
|
| 5693 | + | "fn run() { let pointers: [*u8; 1] = [undefined]; }", |
|
| 5694 | + | "fn run() { let pointers: [*u8; 2] = [undefined; 2]; }", |
|
| 5695 | + | "record R: Copy { p: *u8 } fn run() { let r = R { p: undefined }; }", |
|
| 5696 | + | "union U: Copy { Value { p: *u8 } } fn run() { let u = U::Value { p: undefined }; }", |
|
| 5697 | + | "static P: *u8 = undefined;", |
|
| 5698 | + | "constant P: *u8 = undefined;", |
|
| 5699 | + | "static DATA: [u8; 4] = undefined;", |
|
| 5700 | + | "record R: Copy { p: *u8 } static VALUE: R = R { p: undefined };", |
|
| 5701 | + | ]; |
|
| 5702 | + | for program in programs { |
|
| 5703 | + | let mut a = testResolver(); |
|
| 5704 | + | let result = try resolveProgramStr(&mut a, program); |
|
| 5705 | + | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5706 | + | } |
|
| 5707 | + | try expectAnalyzeOk("unsafe fn run() { let p: *u8 = undefined; }"); |
|
| 5708 | + | try expectAnalyzeOk("fn run() -> u32 { unsafe { let mut n: u32 = undefined; set n = 7; return n; } }"); |
|
| 5709 | + | try expectAnalyzeOk("unsafe static P: *u8 = undefined;"); |
|
| 5710 | + | try expectAnalyzeOk("record R: Copy { p: *u8 } unsafe static VALUE: R = R { p: undefined };"); |
|
| 5711 | + | try expectAnalyzeOk("fn run() { let data: [u8; 4] = [0; 4]; let pointer: ?*u8 = nil; }"); |
|
| 5712 | + | try expectAnalyzeOk("static DATA: [u8; 4] = [0; 4];"); |
|
| 5713 | + | } |
|
| 5714 | + | ||
| 5715 | + | /// Unsafe initialization does not grant permission to subsequent safe expressions. |
|
| 5716 | + | @test unsafe fn testUndefinedContextRestored() throws (testing::TestError) { |
|
| 5717 | + | let mut a = testResolver(); |
|
| 5718 | + | let result = try resolveProgramStr(&mut a, "fn run() { unsafe { let p: *u8 = undefined; } let q: *u8 = undefined; }"); |
|
| 5719 | + | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5720 | + | let mut b = testResolver(); |
|
| 5721 | + | let next = try resolveProgramStr(&mut b, "unsafe static P: *u8 = undefined; static Q: *u8 = undefined;"); |
|
| 5722 | + | try expectErrorKind(&next, super::ErrorKind::UnsafeOperation); |
|
| 5723 | + | } |
|
| 5724 | + | ||
| 5685 | 5725 | /// Unsafe declarations may compose unsafe operations and calls. |
|
| 5686 | 5726 | @test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) { |
|
| 5687 | 5727 | let program = "record Marker: Once {} unsafe fn load(pointer: *unsafe u32) -> u32 { return *pointer; } unsafe fn run(pointer: *unsafe u32) -> u32 { let next = pointer + 1; let same = pointer == next; return load(pointer); }"; |
|
| 5688 | 5728 | try expectAnalyzeOk(program); |
|
| 5689 | 5729 | } |
lib/std/lang/scanner/tests.rad
+6 -9
| 1 | 1 | use std::lang::strings; |
|
| 2 | 2 | use std::mem; |
|
| 3 | 3 | use std::testing; |
|
| 4 | 4 | ||
| 5 | 5 | /// String pool for testing. |
|
| 6 | - | static TEST_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 6 | + | unsafe static TEST_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 7 | 7 | ||
| 8 | + | /// Create a scanner backed by the test string pool. |
|
| 8 | 9 | fn testScanner(source: *[u8]) -> super::Scanner { |
|
| 9 | - | return super::scanner(super::SourceLoc::File("test.r"), source, &mut TEST_STRING_POOL); |
|
| 10 | + | unsafe { |
|
| 11 | + | return super::scanner(super::SourceLoc::File("test.r"), source, &mut TEST_STRING_POOL); |
|
| 12 | + | } |
|
| 10 | 13 | } |
|
| 11 | 14 | ||
| 12 | 15 | @test fn testScanTokens() throws (testing::TestError) { |
|
| 13 | 16 | let mut s = testScanner( |
|
| 14 | 17 | "'x' < fnord fnord: 0 => >> mod and nil" |
| 127 | 130 | try testing::expect(false); |
|
| 128 | 131 | } |
|
| 129 | 132 | } |
|
| 130 | 133 | ||
| 131 | 134 | @test fn testScanEmptyInput() throws (testing::TestError) { |
|
| 132 | - | let mut s = super::Scanner { |
|
| 133 | - | sourceLoc: super::SourceLoc::File("test.r"), |
|
| 134 | - | source: "", |
|
| 135 | - | token: 0, |
|
| 136 | - | cursor: 0, |
|
| 137 | - | pool: &mut TEST_STRING_POOL, |
|
| 138 | - | }; |
|
| 135 | + | let mut s = testScanner(""); |
|
| 139 | 136 | let tok: super::Token = super::next(&mut s); |
|
| 140 | 137 | ||
| 141 | 138 | try testing::expect(tok.kind == super::TokenKind::Eof); |
|
| 142 | 139 | try testing::expect(tok.source.len == 0); |
|
| 143 | 140 | try testing::expect(tok.offset == 0); |
lib/std/tests.rad
+1 -1
| 253 | 253 | try testing::expect(threw); |
|
| 254 | 254 | } |
|
| 255 | 255 | ||
| 256 | 256 | @test fn testWriteFileParts() throws (testing::TestError) { |
|
| 257 | 257 | let path = "/tmp/radiance-std-write-file-parts.test"; |
|
| 258 | - | let mut buffer: [u8; 16] = undefined; |
|
| 258 | + | let mut buffer: [u8; 16] = [0; 16]; |
|
| 259 | 259 | ||
| 260 | 260 | if not unix::writeFileParts(path, &["hello", " ", "world"]) { |
|
| 261 | 261 | throw testing::TestError::Failed; |
|
| 262 | 262 | } |
|
| 263 | 263 | let data = unix::readFile(path, &mut buffer[..]) else { |
test/runner.rad
+11 -11
| 33 | 33 | constant SOURCE_EXT: *[u8] = ".rad"; |
|
| 34 | 34 | /// IL snapshot file extension for binary tests. |
|
| 35 | 35 | constant SNAPSHOT_EXT: *[u8] = ".ril"; |
|
| 36 | 36 | ||
| 37 | 37 | /// String pool. |
|
| 38 | - | static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 38 | + | unsafe static STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 }; |
|
| 39 | 39 | ||
| 40 | 40 | /// Maximum number of AST nodes per test file. |
|
| 41 | 41 | constant MAX_NODE_DATA: u32 = 4096; |
|
| 42 | 42 | /// Maximum number of resolver errors per test file. |
|
| 43 | 43 | constant MAX_ERRORS: u32 = 16; |
| 46 | 46 | /// Maximum number of data bytes in a `.ras` test binary. |
|
| 47 | 47 | constant ASM_DATA_CAPACITY: u32 = 1024; |
|
| 48 | 48 | ||
| 49 | 49 | // Static storage for large buffers to avoid stack overflow. |
|
| 50 | 50 | // Tests run serially so sharing these is safe. |
|
| 51 | - | static SOURCE_BUF: [u8; SOURCE_BUF_SIZE] = undefined; |
|
| 52 | - | static EXPECTED_BUF: [u8; EXPECTED_BUF_SIZE] = undefined; |
|
| 53 | - | static OUTPUT_BUF: [u8; OUTPUT_BUF_SIZE] = undefined; |
|
| 54 | - | static AST_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 55 | - | static IL_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 56 | - | static RESOLVER_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 57 | - | static NODE_DATA_STORAGE: [resolver::NodeData; MAX_NODE_DATA] = undefined; |
|
| 58 | - | static ERROR_STORAGE: [resolver::Error; MAX_ERRORS] = undefined; |
|
| 59 | - | static ASM_TEXT_STORAGE: [u32; ASM_TEXT_CAPACITY] = undefined; |
|
| 60 | - | static ASM_DATA_STORAGE: [u8; ASM_DATA_CAPACITY] = undefined; |
|
| 51 | + | unsafe static SOURCE_BUF: [u8; SOURCE_BUF_SIZE] = undefined; |
|
| 52 | + | unsafe static EXPECTED_BUF: [u8; EXPECTED_BUF_SIZE] = undefined; |
|
| 53 | + | unsafe static OUTPUT_BUF: [u8; OUTPUT_BUF_SIZE] = undefined; |
|
| 54 | + | unsafe static AST_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 55 | + | unsafe static IL_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 56 | + | unsafe static RESOLVER_ARENA_STORAGE: [u8; ARENA_SIZE] = undefined; |
|
| 57 | + | unsafe static NODE_DATA_STORAGE: [resolver::NodeData; MAX_NODE_DATA] = undefined; |
|
| 58 | + | unsafe static ERROR_STORAGE: [resolver::Error; MAX_ERRORS] = undefined; |
|
| 59 | + | unsafe static ASM_TEXT_STORAGE: [u32; ASM_TEXT_CAPACITY] = undefined; |
|
| 60 | + | unsafe static ASM_DATA_STORAGE: [u8; ASM_DATA_CAPACITY] = undefined; |
|
| 61 | 61 | ||
| 62 | 62 | /// Strip a `//` comment from a line, preserving `//` inside quoted strings. |
|
| 63 | 63 | /// Returns the content before the comment, trimmed of trailing whitespace. |
|
| 64 | 64 | fn stripLine(line: *[u8]) -> *[u8] { |
|
| 65 | 65 | let mut end = line.len; |
test/tests/const-expr-array-size.rad
+2 -2
| 5 | 5 | ||
| 6 | 6 | constant ROWS: u32 = 3; |
|
| 7 | 7 | constant COLS: u32 = 4; |
|
| 8 | 8 | constant TOTAL: u32 = ROWS * COLS; |
|
| 9 | 9 | ||
| 10 | - | static DATA: [i32; TOTAL] = undefined; |
|
| 10 | + | unsafe static DATA: [i32; TOTAL] = undefined; |
|
| 11 | 11 | ||
| 12 | - | @default fn main() -> i32 { |
|
| 12 | + | @default unsafe fn main() -> i32 { |
|
| 13 | 13 | // Verify the array has the expected length. |
|
| 14 | 14 | if DATA.len <> 12 { return 1; } |
|
| 15 | 15 | return 0; |
|
| 16 | 16 | } |
test/tests/const-expr-cast.rad
+2 -2
| 10 | 10 | constant SHIFTED: u64 = 4 as u64; |
|
| 11 | 11 | ||
| 12 | 12 | // Chained casts. |
|
| 13 | 13 | constant LEN: u32 = 8; |
|
| 14 | 14 | constant LEN2: u32 = (LEN as u64) as u32; |
|
| 15 | - | static BUF: [u8; LEN2] = undefined; |
|
| 15 | + | unsafe static BUF: [u8; LEN2] = undefined; |
|
| 16 | 16 | ||
| 17 | 17 | // Cast of unsuffixed literal arithmetic. |
|
| 18 | 18 | constant E: u32 = (3 + 4) as u32; |
|
| 19 | 19 | // Nested casts of literal arithmetic. |
|
| 20 | 20 | constant F: u32 = ((3 + 4) as u64) as u32; |
| 30 | 30 | // Typed constant * typed constant through cast. |
|
| 31 | 31 | constant X: u8 = 3; |
|
| 32 | 32 | constant Y: u8 = 4; |
|
| 33 | 33 | constant Z: i32 = (X as i32) * (Y as i32); |
|
| 34 | 34 | ||
| 35 | - | @default fn main() -> i32 { |
|
| 35 | + | @default unsafe fn main() -> i32 { |
|
| 36 | 36 | assert BUF.len == 8; |
|
| 37 | 37 | assert WIDE == 255; |
|
| 38 | 38 | assert Z == 12; |
|
| 39 | 39 | assert E == 7; |
|
| 40 | 40 | assert F == 7; |
test/tests/const-expr-literal.rad
+3 -3
| 13 | 13 | constant E: u32 = 2 * 3 + 4; |
|
| 14 | 14 | // Unary negation with literal. |
|
| 15 | 15 | constant F: i32 = -5; |
|
| 16 | 16 | constant G: i32 = F * 2; |
|
| 17 | 17 | ||
| 18 | - | static BUF: [u8; A] = undefined; |
|
| 19 | - | static BUF2: [u8; C] = undefined; |
|
| 18 | + | unsafe static BUF: [u8; A] = undefined; |
|
| 19 | + | unsafe static BUF2: [u8; C] = undefined; |
|
| 20 | 20 | ||
| 21 | - | @default fn main() -> i32 { |
|
| 21 | + | @default unsafe fn main() -> i32 { |
|
| 22 | 22 | assert A == 16; |
|
| 23 | 23 | assert BUF.len == 16; |
|
| 24 | 24 | assert C == 20; |
|
| 25 | 25 | assert BUF2.len == 20; |
|
| 26 | 26 | assert D == 10; |
test/tests/edge.cases.6.rad
+5 -5
| 55 | 55 | q: 0x1234560C, |
|
| 56 | 56 | r: 0x1234560D, |
|
| 57 | 57 | s: 0x1234560E, |
|
| 58 | 58 | t: 0x1234560F, |
|
| 59 | 59 | }; |
|
| 60 | - | static ANALYZER: Analyzer = undefined; |
|
| 60 | + | unsafe static ANALYZER: Analyzer = undefined; |
|
| 61 | 61 | ||
| 62 | 62 | fn fillEntry(out: *mut Entry) { |
|
| 63 | 63 | set *out = DEFAULT_ENTRY; |
|
| 64 | 64 | } |
|
| 65 | 65 |
| 72 | 72 | return nil; |
|
| 73 | 73 | } |
|
| 74 | 74 | return mkEntry(); |
|
| 75 | 75 | } |
|
| 76 | 76 | ||
| 77 | - | fn init(entries: *mut [Entry]) { |
|
| 77 | + | unsafe fn init(entries: *mut [Entry]) { |
|
| 78 | 78 | set ANALYZER = Analyzer { |
|
| 79 | 79 | pad0: 0xDEADAAA0, |
|
| 80 | 80 | pad1: 0xDEADAAA1, |
|
| 81 | 81 | entries, |
|
| 82 | 82 | len: 0, |
|
| 83 | 83 | }; |
|
| 84 | 84 | } |
|
| 85 | 85 | ||
| 86 | - | fn add() { |
|
| 86 | + | unsafe fn add() { |
|
| 87 | 87 | let idx = ANALYZER.len; |
|
| 88 | 88 | let entry = mkOptEntry(true) else { |
|
| 89 | 89 | return; |
|
| 90 | 90 | }; |
|
| 91 | 91 | set ANALYZER.entries[idx] = entry; |
|
| 92 | 92 | set ANALYZER.len = idx + 1; |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | - | fn checkHeader(expected: *[Entry]) -> i32 { |
|
| 95 | + | unsafe fn checkHeader(expected: *[Entry]) -> i32 { |
|
| 96 | 96 | unsafe { |
|
| 97 | 97 | if ANALYZER.entries.ptr <> expected.ptr or ANALYZER.entries.len <> expected.len { |
|
| 98 | 98 | // Slice header got clobbered instead of the backing storage. |
|
| 99 | 99 | return 1; |
|
| 100 | 100 | } |
| 111 | 111 | return 3; |
|
| 112 | 112 | } |
|
| 113 | 113 | return 0; |
|
| 114 | 114 | } |
|
| 115 | 115 | ||
| 116 | - | @default fn main() -> i32 { |
|
| 116 | + | @default unsafe fn main() -> i32 { |
|
| 117 | 117 | let target = &mut STORAGE[..]; |
|
| 118 | 118 | init(target); |
|
| 119 | 119 | add(); |
|
| 120 | 120 | return checkHeader(target); |
|
| 121 | 121 | } |
test/tests/edge.cases.7.addr.bug.rad
+2 -2
| 3 | 3 | record PtrHolder: Copy { |
|
| 4 | 4 | ptr: *mut i32, |
|
| 5 | 5 | } |
|
| 6 | 6 | ||
| 7 | 7 | static target: i32 = 10; |
|
| 8 | - | static holder: PtrHolder = undefined; |
|
| 8 | + | unsafe static holder: PtrHolder = undefined; |
|
| 9 | 9 | ||
| 10 | - | @default fn main() -> i32 { |
|
| 10 | + | @default unsafe fn main() -> i32 { |
|
| 11 | 11 | set holder.ptr = &mut target; |
|
| 12 | 12 | set *holder.ptr = 42; |
|
| 13 | 13 | ||
| 14 | 14 | return target; |
|
| 15 | 15 | } |
test/tests/edge.cases.8.bug.rad
+2 -2
| 10 | 10 | record Outer: Copy { |
|
| 11 | 11 | padding: i32, |
|
| 12 | 12 | inner: Inner, |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | - | static global: Outer = undefined; |
|
| 15 | + | unsafe static global: Outer = undefined; |
|
| 16 | 16 | ||
| 17 | 17 | fn readInner(i: Inner) -> i32 { |
|
| 18 | 18 | return i.value; |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | - | @default fn main() -> i32 { |
|
| 21 | + | @default unsafe fn main() -> i32 { |
|
| 22 | 22 | set global = Outer { padding: 0, inner: Inner { value: 42 } }; |
|
| 23 | 23 | ||
| 24 | 24 | assert readInner(global.inner) == 42; |
|
| 25 | 25 | return 0; |
|
| 26 | 26 | } |
test/tests/for.else.continue.rad
+1 -1
| 23 | 23 | } |
|
| 24 | 24 | } |
|
| 25 | 25 | return nil; |
|
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | - | @default fn main() -> i32 { |
|
| 28 | + | @default unsafe fn main() -> i32 { |
|
| 29 | 29 | let mut fields: [Field; 4] = undefined; |
|
| 30 | 30 | set fields[0] = Field { name: nil, value: 10 }; |
|
| 31 | 31 | set fields[1] = Field { name: "foo", value: 20 }; |
|
| 32 | 32 | set fields[2] = Field { name: nil, value: 30 }; |
|
| 33 | 33 | set fields[3] = Field { name: "bar", value: 40 }; |
test/tests/frame.large.rad
+4 -4
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | //! Test large stack frames and addressing near top of frame. |
|
| 3 | - | fn bigFrame1() -> i32 { |
|
| 3 | + | unsafe fn bigFrame1() -> i32 { |
|
| 4 | 4 | let pad: [u8; 2024] = undefined; |
|
| 5 | 5 | let n: i32 = 491823; |
|
| 6 | 6 | ||
| 7 | 7 | return n + 1; |
|
| 8 | 8 | } |
|
| 9 | 9 | ||
| 10 | - | fn bigFrame2() -> i32 { |
|
| 10 | + | unsafe fn bigFrame2() -> i32 { |
|
| 11 | 11 | let pad: [u8; 2028] = undefined; |
|
| 12 | 12 | let arr: [i32; 4] = [1, 2, 3, 4]; |
|
| 13 | 13 | ||
| 14 | 14 | return arr[0] + arr[1] + arr[3]; |
|
| 15 | 15 | } |
|
| 16 | 16 | ||
| 17 | - | fn bigFrame3() -> i32 { |
|
| 17 | + | unsafe fn bigFrame3() -> i32 { |
|
| 18 | 18 | let mut ary: [u8; 4096] = undefined; |
|
| 19 | 19 | set ary[4091] = 192; |
|
| 20 | 20 | ||
| 21 | 21 | return ary[4091] as i32; |
|
| 22 | 22 | } |
|
| 23 | 23 | ||
| 24 | - | @default fn main() -> i32 { |
|
| 24 | + | @default unsafe fn main() -> i32 { |
|
| 25 | 25 | assert bigFrame1() == 491824; |
|
| 26 | 26 | assert bigFrame2() == 7; |
|
| 27 | 27 | assert bigFrame3() == 192; |
|
| 28 | 28 | return 0; |
|
| 29 | 29 | } |
test/tests/large.blit.store.rad
+4 -4
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | 21 | /// Store at offset 2200 (> MAX_IMM) into a record field. |
|
| 22 | 22 | /// Generates `store w32 <imm> %0 2200` in IL, which triggers the |
|
| 23 | 23 | /// SCRATCH1 aliasing bug when adjustOffset clobbers the value. |
|
| 24 | - | fn storeLargeOffset() -> i32 { |
|
| 24 | + | unsafe fn storeLargeOffset() -> i32 { |
|
| 25 | 25 | let mut b: Big = undefined; |
|
| 26 | 26 | set b.tag = 42; |
|
| 27 | 27 | assert b.tag == 42; |
|
| 28 | 28 | set b.tag = 99; |
|
| 29 | 29 | assert b.tag == 99; |
|
| 30 | 30 | return 0; |
|
| 31 | 31 | } |
|
| 32 | 32 | ||
| 33 | 33 | /// Copy a >2047 byte struct (triggers blit offset overflow). |
|
| 34 | - | fn copyBig() -> i32 { |
|
| 34 | + | unsafe fn copyBig() -> i32 { |
|
| 35 | 35 | let mut src: Big = undefined; |
|
| 36 | 36 | set src.a[0] = 10; |
|
| 37 | 37 | set src.a[1000] = 20; |
|
| 38 | 38 | set src.a[2199] = 30; |
|
| 39 | 39 | set src.tag = 77; |
| 46 | 46 | assert dst.tag == 77; |
|
| 47 | 47 | return 0; |
|
| 48 | 48 | } |
|
| 49 | 49 | ||
| 50 | 50 | /// Mutate a copy to ensure the blit produced an independent copy. |
|
| 51 | - | fn copyIndependence() -> i32 { |
|
| 51 | + | unsafe fn copyIndependence() -> i32 { |
|
| 52 | 52 | let mut a: Big = undefined; |
|
| 53 | 53 | set a.a[0] = 1; |
|
| 54 | 54 | set a.a[2199] = 2; |
|
| 55 | 55 | set a.tag = 100; |
|
| 56 | 56 |
| 64 | 64 | assert b.a[2199] == 2; |
|
| 65 | 65 | assert b.tag == 200; |
|
| 66 | 66 | return 0; |
|
| 67 | 67 | } |
|
| 68 | 68 | ||
| 69 | - | @default fn main() -> i32 { |
|
| 69 | + | @default unsafe fn main() -> i32 { |
|
| 70 | 70 | let r1 = storeLargeOffset(); |
|
| 71 | 71 | if r1 <> 0 { |
|
| 72 | 72 | return 10 + r1; |
|
| 73 | 73 | } |
|
| 74 | 74 |
test/tests/loc.addr.offset.bug.rad
+2 -2
| 9 | 9 | record Outer: Copy { |
|
| 10 | 10 | pad: i32, // offset 0, size 4 |
|
| 11 | 11 | inner: Inner, // offset 4, size 4 |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | - | static outer: Outer = undefined; |
|
| 14 | + | unsafe static outer: Outer = undefined; |
|
| 15 | 15 | ||
| 16 | - | @default fn main() -> i32 { |
|
| 16 | + | @default unsafe fn main() -> i32 { |
|
| 17 | 17 | set outer.inner.value = 42; |
|
| 18 | 18 | ||
| 19 | 19 | let ptr: *Inner = &outer.inner; |
|
| 20 | 20 | ||
| 21 | 21 | assert (*ptr).value == 42; |
test/tests/loc.addr.opt.to.opt.rad
+2 -2
| 5 | 5 | record Container: Copy { |
|
| 6 | 6 | pad: i32, // offset 0 |
|
| 7 | 7 | opt: ?i32, // offset 4 |
|
| 8 | 8 | } |
|
| 9 | 9 | ||
| 10 | - | static container: Container = undefined; |
|
| 10 | + | unsafe static container: Container = undefined; |
|
| 11 | 11 | ||
| 12 | - | @default fn main() -> i32 { |
|
| 12 | + | @default unsafe fn main() -> i32 { |
|
| 13 | 13 | let sourceOpt: ?i32 = 42; |
|
| 14 | 14 | ||
| 15 | 15 | set container.opt = sourceOpt; |
|
| 16 | 16 | ||
| 17 | 17 | if let val = container.opt { |
test/tests/loc.addr.optional.assign.rad
+2 -2
| 4 | 4 | record Container: Copy { |
|
| 5 | 5 | pad: i32, // offset 0, size 4 |
|
| 6 | 6 | opt: ?i32, // offset 4, size 8 (tag + value) |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | - | static container: Container = undefined; |
|
| 9 | + | unsafe static container: Container = undefined; |
|
| 10 | 10 | ||
| 11 | - | @default fn main() -> i32 { |
|
| 11 | + | @default unsafe fn main() -> i32 { |
|
| 12 | 12 | set container.opt = 42; |
|
| 13 | 13 | ||
| 14 | 14 | if let val = container.opt { |
|
| 15 | 15 | assert val == 42; |
|
| 16 | 16 | return 0; |
test/tests/loc.addr.record.assign.rad
+3 -3
| 9 | 9 | record Outer: Copy { |
|
| 10 | 10 | pad: i32, // offset 0, size 4 |
|
| 11 | 11 | inner: Inner, // offset 4, size 4 |
|
| 12 | 12 | } |
|
| 13 | 13 | ||
| 14 | - | static outer: Outer = undefined; |
|
| 15 | - | static source: Inner = undefined; |
|
| 14 | + | unsafe static outer: Outer = undefined; |
|
| 15 | + | unsafe static source: Inner = undefined; |
|
| 16 | 16 | ||
| 17 | - | @default fn main() -> i32 { |
|
| 17 | + | @default unsafe fn main() -> i32 { |
|
| 18 | 18 | set source.value = 42; |
|
| 19 | 19 | ||
| 20 | 20 | set outer.inner = source; |
|
| 21 | 21 | ||
| 22 | 22 | assert outer.inner.value == 42; |
test/tests/memzero.union.bug.rad
+1 -1
| 10 | 10 | guard1: u16, |
|
| 11 | 11 | val: Payload, |
|
| 12 | 12 | guard2: u32, |
|
| 13 | 13 | } |
|
| 14 | 14 | ||
| 15 | - | @default fn main() -> i32 { |
|
| 15 | + | @default unsafe fn main() -> i32 { |
|
| 16 | 16 | let mut f: Frame = Frame { guard1: 0xDEAD, val: undefined, guard2: 0xDEADBEEF }; |
|
| 17 | 17 | ||
| 18 | 18 | set f.val = Payload::Small(7); |
|
| 19 | 19 | set f.val = Payload::Big([1, 2, 3]); |
|
| 20 | 20 |
test/tests/pointer.slice.store.rad
+3 -3
| 16 | 16 | ||
| 17 | 17 | record PtrBox: Copy { |
|
| 18 | 18 | ptr: *mut *mut [Entry], |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | - | static STORAGE: [Entry; 2] = undefined; |
|
| 22 | - | static TABLE: Table = undefined; |
|
| 23 | - | static HOLDER: PtrBox = undefined; |
|
| 21 | + | unsafe static STORAGE: [Entry; 2] = undefined; |
|
| 22 | + | unsafe static TABLE: Table = undefined; |
|
| 23 | + | unsafe static HOLDER: PtrBox = undefined; |
|
| 24 | 24 | ||
| 25 | 25 | /// Exercise slice storage and inspect its pointer fields. |
|
| 26 | 26 | @default unsafe fn main() -> i32 { |
|
| 27 | 27 | set TABLE.entries = &mut STORAGE[..]; |
|
| 28 | 28 | set TABLE.len = 0; |
test/tests/record.copy.rad
+3 -3
| 69 | 69 | assert a[2].x == 561; |
|
| 70 | 70 | assert a[3].x == 12; |
|
| 71 | 71 | return 0; |
|
| 72 | 72 | } |
|
| 73 | 73 | ||
| 74 | - | fn func4(s: S) -> i32 { |
|
| 74 | + | unsafe fn func4(s: S) -> i32 { |
|
| 75 | 75 | let mut a: [S; 2] = undefined; |
|
| 76 | 76 | set a[0] = s; |
|
| 77 | 77 | ||
| 78 | 78 | assert a[0].x == 561; |
|
| 79 | 79 | assert a[0].y == 938; |
|
| 80 | 80 | assert a[0].z == 102; |
|
| 81 | 81 | return 0; |
|
| 82 | 82 | } |
|
| 83 | 83 | ||
| 84 | - | fn func5(s: S) -> i32 { |
|
| 84 | + | unsafe fn func5(s: S) -> i32 { |
|
| 85 | 85 | let mut a: [S; 2] = undefined; |
|
| 86 | 86 | let t: S = makeS(s.x, s.y, s.z); |
|
| 87 | 87 | set a[0] = t; |
|
| 88 | 88 | ||
| 89 | 89 | assert a[0].x == 561; |
|
| 90 | 90 | assert a[0].y == 938; |
|
| 91 | 91 | assert a[0].z == 102; |
|
| 92 | 92 | return 0; |
|
| 93 | 93 | } |
|
| 94 | 94 | ||
| 95 | - | @default fn main() -> i32 { |
|
| 95 | + | @default unsafe fn main() -> i32 { |
|
| 96 | 96 | let s: S = S { x: 561, y: 938, z: 102 }; |
|
| 97 | 97 | ||
| 98 | 98 | let r1: i32 = func1(s); |
|
| 99 | 99 | if r1 <> 0 { |
|
| 100 | 100 | return 10 + r1; |
test/tests/slice.append.rad
+1 -1
| 39 | 39 | func: arenaAllocFn, |
|
| 40 | 40 | ctx: arena as *mut opaque, |
|
| 41 | 41 | }; |
|
| 42 | 42 | } |
|
| 43 | 43 | ||
| 44 | - | static BUF: [u8; 4096] = undefined; |
|
| 44 | + | unsafe static BUF: [u8; 4096] = undefined; |
|
| 45 | 45 | ||
| 46 | 46 | @default unsafe fn main() -> i32 { |
|
| 47 | 47 | static arena: Arena = undefined; |
|
| 48 | 48 | set arena = newArena(&mut BUF[..]); |
|
| 49 | 49 | let a = arenaAllocator(&mut arena); |
test/tests/static.slice.index.assign.rad
+2 -2
| 7 | 7 | record Container: Copy { |
|
| 8 | 8 | pad: i32, |
|
| 9 | 9 | items: [Inner; 3], |
|
| 10 | 10 | } |
|
| 11 | 11 | ||
| 12 | - | static container: Container = undefined; |
|
| 12 | + | unsafe static container: Container = undefined; |
|
| 13 | 13 | ||
| 14 | - | @default fn main() -> i32 { |
|
| 14 | + | @default unsafe fn main() -> i32 { |
|
| 15 | 15 | set container.items[0].value = 10; |
|
| 16 | 16 | set container.items[1].value = 20; |
|
| 17 | 17 | set container.items[2].value = 30; |
|
| 18 | 18 | ||
| 19 | 19 | let slice: *mut [Inner] = &mut container.items[..]; |
test/tests/static.slice.offset.rad
+2 -2
| 15 | 15 | static SCRATCH: [Entry; 1] = [Entry { a: 0, b: 0 }]; |
|
| 16 | 16 | static STORAGE: [Entry; 2] = [ |
|
| 17 | 17 | Entry { a: 0, b: 0 }, |
|
| 18 | 18 | Entry { a: 0, b: 0 }, |
|
| 19 | 19 | ]; |
|
| 20 | - | static TBL: Table = undefined; |
|
| 20 | + | unsafe static TBL: Table = undefined; |
|
| 21 | 21 | ||
| 22 | - | @default fn main() -> i32 { |
|
| 22 | + | @default unsafe fn main() -> i32 { |
|
| 23 | 23 | set TBL.scratch = &mut SCRATCH[..]; |
|
| 24 | 24 | set TBL.entries = &mut STORAGE[..]; |
|
| 25 | 25 | set TBL.len = 0; |
|
| 26 | 26 | ||
| 27 | 27 | set TBL.entries[TBL.len] = Entry { a: 7, b: 9 }; |
test/tests/static.zero.bss.rad
+2 -2
| 16 | 16 | /// Field that forces padding after `tag`. |
|
| 17 | 17 | value: u32, |
|
| 18 | 18 | } |
|
| 19 | 19 | ||
| 20 | 20 | /// Partially initialized aggregate where all concrete bytes are zero. |
|
| 21 | - | static POOL: Pool = Pool { table: undefined, count: 0 }; |
|
| 21 | + | unsafe static POOL: Pool = Pool { table: undefined, count: 0 }; |
|
| 22 | 22 | ||
| 23 | 23 | /// Repeated scalar zeros. |
|
| 24 | 24 | static FLAGS: [bool; 4] = [false; 4]; |
|
| 25 | 25 | ||
| 26 | 26 | /// Explicit zero fields with undefined padding. |
|
| 27 | 27 | static PADDED: Padded = Padded { tag: 0, value: 0 }; |
|
| 28 | 28 | ||
| 29 | - | @default fn main() -> i32 { |
|
| 29 | + | @default unsafe fn main() -> i32 { |
|
| 30 | 30 | assert POOL.count == 0; |
|
| 31 | 31 | assert FLAGS[0] == false; |
|
| 32 | 32 | assert FLAGS[3] == false; |
|
| 33 | 33 | assert PADDED.tag == 0; |
|
| 34 | 34 | assert PADDED.value == 0; |
test/tests/undefined.aggregate.rad
+1 -1
| 1 | 1 | /// Test lowering of undefined for aggregate types. |
|
| 2 | 2 | record Point: Copy { x: i32, y: i32 } |
|
| 3 | 3 | ||
| 4 | - | fn test() -> i32 { |
|
| 4 | + | unsafe fn test() -> i32 { |
|
| 5 | 5 | let p: Point = undefined; |
|
| 6 | 6 | return p.x; |
|
| 7 | 7 | } |
test/tests/undefined.primitive.rad
+1 -1
| 1 | 1 | /// Test lowering of undefined for primitive types. |
|
| 2 | - | fn test() -> i32 { |
|
| 2 | + | unsafe fn test() -> i32 { |
|
| 3 | 3 | let x: i32 = undefined; |
|
| 4 | 4 | return x; |
|
| 5 | 5 | } |
test/tests/undefined.rad
+1 -1
| 1 | 1 | //! returns: 0 |
|
| 2 | 2 | //! Test undefined values for arrays and assignment. |
|
| 3 | - | @default fn main() -> i32 { |
|
| 3 | + | @default unsafe fn main() -> i32 { |
|
| 4 | 4 | let mut ary: [u16; 32] = undefined; |
|
| 5 | 5 | let x: u32 = 8; |
|
| 6 | 6 | let y: u32 = 9; |
|
| 7 | 7 | ||
| 8 | 8 | set ary[0] = 1; |
test/tests/undefined.record.field.rad
+3 -3
| 20 | 20 | len: i32, |
|
| 21 | 21 | } |
|
| 22 | 22 | ||
| 23 | 23 | /// Construct a record with one field `undefined` (named-field syntax). |
|
| 24 | 24 | /// The IL must not contain a `blit` or `store` for `x`. |
|
| 25 | - | fn partialInit() -> i32 { |
|
| 25 | + | unsafe fn partialInit() -> i32 { |
|
| 26 | 26 | let s = Small { x: undefined, y: 42 }; |
|
| 27 | 27 | return s.y; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | /// Construct a record with an array field `undefined` (named-field syntax). |
|
| 31 | 31 | /// The IL must not contain a `blit` for `data`. |
|
| 32 | - | fn arrayFieldUndef() -> i32 { |
|
| 32 | + | unsafe fn arrayFieldUndef() -> i32 { |
|
| 33 | 33 | let w = WithArray { data: undefined, len: 3 }; |
|
| 34 | 34 | return w.len; |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | /// Both fields defined - normal case for comparison. |
| 45 | 45 | B, |
|
| 46 | 46 | } |
|
| 47 | 47 | ||
| 48 | 48 | /// Union variant with record payload containing an `undefined` field. |
|
| 49 | 49 | /// This exercises `lowerRecordCtor` (positional constructor path). |
|
| 50 | - | fn unionPayloadUndef() -> i32 { |
|
| 50 | + | unsafe fn unionPayloadUndef() -> i32 { |
|
| 51 | 51 | let t = Tagged::A { data: undefined, tag: 99 }; |
|
| 52 | 52 | match t { |
|
| 53 | 53 | case Tagged::A { tag, .. } => return tag, |
|
| 54 | 54 | else => return -1, |
|
| 55 | 55 | } |
test/tests/undefined.unsafe.rad
added
+33 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Permanent storage for the initialized pointers. |
|
| 4 | + | static DATA: [u8; 2] = [7, 9]; |
|
| 5 | + | ||
| 6 | + | /// Initialize each array element before reading a pointer. |
|
| 7 | + | fn read() -> u8 { |
|
| 8 | + | unsafe { |
|
| 9 | + | let mut pointers: [*u8; 2] = undefined; |
|
| 10 | + | set pointers[0] = &DATA[0]; |
|
| 11 | + | set pointers[1] = &DATA[1]; |
|
| 12 | + | return *pointers[0] + *pointers[1]; |
|
| 13 | + | } |
|
| 14 | + | } |
|
| 15 | + | ||
| 16 | + | /// Initialize a scalar before returning its value. |
|
| 17 | + | unsafe fn scalar() -> u8 { |
|
| 18 | + | let mut value: u8 = undefined; |
|
| 19 | + | set value = 4; |
|
| 20 | + | return value; |
|
| 21 | + | } |
|
| 22 | + | ||
| 23 | + | /// Check unsafe initialization and safe empty values. |
|
| 24 | + | @default fn main() -> i32 { |
|
| 25 | + | let bytes: [u8; 2] = [0; 2]; |
|
| 26 | + | let pointer: ?*u8 = nil; |
|
| 27 | + | if bytes[0] <> 0 or pointer <> nil { return 1; } |
|
| 28 | + | if read() <> 16 { return 2; } |
|
| 29 | + | unsafe { |
|
| 30 | + | if scalar() <> 4 { return 3; } |
|
| 31 | + | } |
|
| 32 | + | return 0; |
|
| 33 | + | } |