Require unsafe functions for storage reinterpretation casts
ceaf9422d1bee3419c7e9b470171ed7f39e101188cad252b5a48753302fd8fa9
1 parent
5807f724
compiler/radiance.rad
+1 -1
| 578 | 578 | try lowerModuleTreeInto(ctx, &mut *low, graph, childId, false, pkg); |
|
| 579 | 579 | } |
|
| 580 | 580 | } |
|
| 581 | 581 | ||
| 582 | 582 | /// Build a scope access chain: a::b::c from a slice of identifiers. |
|
| 583 | - | fn synthScopeAccess(arena: &mut ast::NodeArena, path: &[*[u8]]) -> *ast::Node { |
|
| 583 | + | unsafe fn synthScopeAccess(arena: &mut ast::NodeArena, path: &[*[u8]]) -> *ast::Node { |
|
| 584 | 584 | let mut result = ast::synthNode( |
|
| 585 | 585 | arena, |
|
| 586 | 586 | ast::NodeValue::Ident(strings::intern(&mut STRING_POOL, path[0])) |
|
| 587 | 587 | ); |
|
| 588 | 588 | for i in 1..path.len { |
lib/std/arch/rv64.rad
+1 -1
| 297 | 297 | emit::emit(&mut generator.e, word); |
|
| 298 | 298 | } |
|
| 299 | 299 | } |
|
| 300 | 300 | ||
| 301 | 301 | /// Finish RV64 code generation and return the emitted program. |
|
| 302 | - | export fn finishProgram( |
|
| 302 | + | export unsafe fn finishProgram( |
|
| 303 | 303 | generator: &mut Generator, |
|
| 304 | 304 | globalData: *[il::Data], |
|
| 305 | 305 | storage: Storage, |
|
| 306 | 306 | roDataPrefix: *[u8], |
|
| 307 | 307 | roDataBuf: *mut [u8], |
lib/std/arch/rv64/printer.rad
+2 -2
| 42 | 42 | unsafe fn write(out: &mut sexpr::Output, s: &[u8]) { |
|
| 43 | 43 | sexpr::write(out, s); |
|
| 44 | 44 | } |
|
| 45 | 45 | ||
| 46 | 46 | /// Format `i32` into arena. |
|
| 47 | - | fn formatI32(a: &mut alloc::Arena, val: i32) -> *[u8] { |
|
| 47 | + | unsafe fn formatI32(a: &mut alloc::Arena, val: i32) -> *[u8] { |
|
| 48 | 48 | let mut digits: [u8; 12] = undefined; |
|
| 49 | 49 | let start = fmt::formatI32(val, &mut digits[..]); |
|
| 50 | 50 | let slice = try! alloc::allocSlice(a, 1, 1, digits.len - start) as *mut [u8]; |
|
| 51 | 51 | try! mem::copy(slice, &digits[start..]); |
|
| 52 | 52 | ||
| 53 | 53 | return slice; |
|
| 54 | 54 | } |
|
| 55 | 55 | ||
| 56 | 56 | /// Format `u32` into arena. |
|
| 57 | - | fn formatU32(a: &mut alloc::Arena, val: u32) -> *[u8] { |
|
| 57 | + | unsafe fn formatU32(a: &mut alloc::Arena, val: u32) -> *[u8] { |
|
| 58 | 58 | let mut digits: [u8; 10] = undefined; |
|
| 59 | 59 | let start = fmt::formatU32(val, &mut digits[..]); |
|
| 60 | 60 | let slice = try! alloc::allocSlice(a, 1, 1, digits.len - start) as *mut [u8]; |
|
| 61 | 61 | try! mem::copy(slice, &digits[start..]); |
|
| 62 | 62 |
lib/std/lang/ast.rad
+3 -3
| 26 | 26 | nextId: 0, |
|
| 27 | 27 | }; |
|
| 28 | 28 | } |
|
| 29 | 29 | ||
| 30 | 30 | /// Create an empty `*mut [*Node]` slice with the given capacity. |
|
| 31 | - | export fn nodeSlice(arena: &mut NodeArena, capacity: u32) -> *mut [*Node] { |
|
| 31 | + | export unsafe fn nodeSlice(arena: &mut NodeArena, capacity: u32) -> *mut [*Node] { |
|
| 32 | 32 | if capacity == 0 { |
|
| 33 | 33 | return &mut []; |
|
| 34 | 34 | } |
|
| 35 | 35 | let ptr = try! alloc::allocSlice(&mut arena.arena, @sizeOf(*Node), @alignOf(*Node), capacity); |
|
| 36 | 36 |
| 823 | 823 | else => return false, |
|
| 824 | 824 | } |
|
| 825 | 825 | } |
|
| 826 | 826 | ||
| 827 | 827 | /// Allocate a new AST node from the arena with the given span and value. |
|
| 828 | - | export fn allocNode(arena: &mut NodeArena, span: Span, value: NodeValue) -> *mut Node { |
|
| 828 | + | export unsafe fn allocNode(arena: &mut NodeArena, span: Span, value: NodeValue) -> *mut Node { |
|
| 829 | 829 | let p = try! alloc::alloc(&mut arena.arena, @sizeOf(Node), @alignOf(Node)); |
|
| 830 | 830 | let node = p as *mut Node; |
|
| 831 | 831 | let nodeId = arena.nextId; |
|
| 832 | 832 | set arena.nextId = nodeId + 1; |
|
| 833 | 833 |
| 835 | 835 | ||
| 836 | 836 | return node; |
|
| 837 | 837 | } |
|
| 838 | 838 | ||
| 839 | 839 | /// Allocate a synthetic AST node with a zero-length span. |
|
| 840 | - | export fn synthNode(arena: &mut NodeArena, value: NodeValue) -> *mut Node { |
|
| 840 | + | export unsafe fn synthNode(arena: &mut NodeArena, value: NodeValue) -> *mut Node { |
|
| 841 | 841 | return allocNode(arena, Span { offset: 0, length: 0 }, value); |
|
| 842 | 842 | } |
|
| 843 | 843 | ||
| 844 | 844 | /// Synthetic module with a single function in it. |
|
| 845 | 845 | record SynthFnMod: Copy { |
lib/std/lang/ast/printer.rad
+13 -13
| 82 | 82 | case types::PointerClass::Unsafe => return unsafeHead, |
|
| 83 | 83 | } |
|
| 84 | 84 | } |
|
| 85 | 85 | ||
| 86 | 86 | /// Convert a type signature to an S-expression. |
|
| 87 | - | fn typeSigToExpr(a: &mut alloc::Arena, sig: super::TypeSig) -> sexpr::Expr { |
|
| 87 | + | unsafe fn typeSigToExpr(a: &mut alloc::Arena, sig: super::TypeSig) -> sexpr::Expr { |
|
| 88 | 88 | match sig { |
|
| 89 | 89 | case super::TypeSig::Void => return sexpr::sym("void"), |
|
| 90 | 90 | case super::TypeSig::Opaque => return sexpr::sym("opaque"), |
|
| 91 | 91 | case super::TypeSig::Bool => return sexpr::sym("bool"), |
|
| 92 | 92 | case super::TypeSig::Integer { width, sign } => return sexpr::sym(intTypeName(width, sign)), |
| 122 | 122 | } |
|
| 123 | 123 | } |
|
| 124 | 124 | } |
|
| 125 | 125 | ||
| 126 | 126 | /// Convert a node slice to a slice of expressions. |
|
| 127 | - | fn nodeListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 127 | + | unsafe fn nodeListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 128 | 128 | if nodes.len == 0 { |
|
| 129 | 129 | return &[]; |
|
| 130 | 130 | } |
|
| 131 | 131 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 132 | 132 | for node, i in nodes { |
| 134 | 134 | } |
|
| 135 | 135 | return buf; |
|
| 136 | 136 | } |
|
| 137 | 137 | ||
| 138 | 138 | /// Convert optional attributes to an attribute list expression. |
|
| 139 | - | fn attributesToExpr(a: &mut alloc::Arena, attrs: ?super::Attributes) -> sexpr::Expr { |
|
| 139 | + | unsafe fn attributesToExpr(a: &mut alloc::Arena, attrs: ?super::Attributes) -> sexpr::Expr { |
|
| 140 | 140 | let mut exprs: *[sexpr::Expr] = &[]; |
|
| 141 | 141 | if let list = attrs { |
|
| 142 | 142 | set exprs = nodeListToExprs(a, &list.list[..]); |
|
| 143 | 143 | } |
|
| 144 | 144 | return sexpr::list(a, "attrs", exprs); |
|
| 145 | 145 | } |
|
| 146 | 146 | ||
| 147 | 147 | /// Convert an optional node to an expression, or return placeholder. |
|
| 148 | - | fn toExprOpt(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr { |
|
| 148 | + | unsafe fn toExprOpt(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr { |
|
| 149 | 149 | if let n = opt { |
|
| 150 | 150 | return toExpr(a, n); |
|
| 151 | 151 | } |
|
| 152 | 152 | return sexpr::sym("_"); |
|
| 153 | 153 | } |
|
| 154 | 154 | ||
| 155 | 155 | /// Convert an optional node to an expression, or return `Null`. |
|
| 156 | - | fn toExprOrNull(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr { |
|
| 156 | + | unsafe fn toExprOrNull(a: &mut alloc::Arena, opt: ?*super::Node) -> sexpr::Expr { |
|
| 157 | 157 | if let n = opt { |
|
| 158 | 158 | return toExpr(a, n); |
|
| 159 | 159 | } |
|
| 160 | 160 | return sexpr::Expr::Null; |
|
| 161 | 161 | } |
|
| 162 | 162 | ||
| 163 | 163 | /// Convert an optional guard. |
|
| 164 | - | fn guardExpr(a: &mut alloc::Arena, guard: ?*super::Node) -> sexpr::Expr { |
|
| 164 | + | unsafe fn guardExpr(a: &mut alloc::Arena, guard: ?*super::Node) -> sexpr::Expr { |
|
| 165 | 165 | if let g = guard { |
|
| 166 | 166 | return sexpr::list(a, "guard", &[toExpr(a, g)]); |
|
| 167 | 167 | } |
|
| 168 | 168 | return sexpr::Expr::Null; |
|
| 169 | 169 | } |
|
| 170 | 170 | ||
| 171 | 171 | /// Convert a list of match prongs to expressions. |
|
| 172 | - | fn prongListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 172 | + | unsafe fn prongListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 173 | 173 | if nodes.len == 0 { |
|
| 174 | 174 | return &[]; |
|
| 175 | 175 | } |
|
| 176 | 176 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 177 | 177 | for prong, i in nodes { |
| 186 | 186 | } |
|
| 187 | 187 | return buf; |
|
| 188 | 188 | } |
|
| 189 | 189 | ||
| 190 | 190 | /// Convert a match prong to an S-expression. |
|
| 191 | - | fn prongToExpr(a: &mut alloc::Arena, p: super::MatchProng) -> sexpr::Expr { |
|
| 191 | + | unsafe fn prongToExpr(a: &mut alloc::Arena, p: super::MatchProng) -> sexpr::Expr { |
|
| 192 | 192 | match p.arm { |
|
| 193 | 193 | case super::ProngArm::Case(patterns) => { |
|
| 194 | 194 | return sexpr::block(a, "case", &[ |
|
| 195 | 195 | sexpr::list(a, "patterns", nodeListToExprs(a, &patterns[..])), |
|
| 196 | 196 | guardExpr(a, p.guard) |
| 207 | 207 | } |
|
| 208 | 208 | } |
|
| 209 | 209 | } |
|
| 210 | 210 | ||
| 211 | 211 | /// Convert a record field declaration to an S-expression. |
|
| 212 | - | fn fieldToExpr( |
|
| 212 | + | unsafe fn fieldToExpr( |
|
| 213 | 213 | a: &mut alloc::Arena, |
|
| 214 | 214 | field: ?*super::Node, |
|
| 215 | 215 | type: *super::Node, |
|
| 216 | 216 | value: ?*super::Node |
|
| 217 | 217 | ) -> sexpr::Expr { |
|
| 218 | 218 | return sexpr::list(a, ":", &[toExprOpt(a, field), toExpr(a, type), toExprOrNull(a, value)]); |
|
| 219 | 219 | } |
|
| 220 | 220 | ||
| 221 | 221 | /// Convert a list of record fields to expressions. |
|
| 222 | - | fn fieldListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 222 | + | unsafe fn fieldListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 223 | 223 | if nodes.len == 0 { |
|
| 224 | 224 | return &[]; |
|
| 225 | 225 | } |
|
| 226 | 226 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 227 | 227 | for node, i in nodes { |
| 236 | 236 | } |
|
| 237 | 237 | return buf; |
|
| 238 | 238 | } |
|
| 239 | 239 | ||
| 240 | 240 | /// Convert a union variant to an S-expression. |
|
| 241 | - | fn variantToExpr(a: &mut alloc::Arena, name: *super::Node, type: ?*super::Node) -> sexpr::Expr { |
|
| 241 | + | unsafe fn variantToExpr(a: &mut alloc::Arena, name: *super::Node, type: ?*super::Node) -> sexpr::Expr { |
|
| 242 | 242 | return sexpr::list(a, "variant", &[toExpr(a, name), toExprOrNull(a, type)]); |
|
| 243 | 243 | } |
|
| 244 | 244 | ||
| 245 | 245 | /// Convert a list of union variants to expressions. |
|
| 246 | - | fn variantListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 246 | + | unsafe fn variantListToExprs(a: &mut alloc::Arena, nodes: *[*super::Node]) -> *[sexpr::Expr] { |
|
| 247 | 247 | if nodes.len == 0 { |
|
| 248 | 248 | return &[]; |
|
| 249 | 249 | } |
|
| 250 | 250 | let buf = try! sexpr::allocExprs(a, nodes.len as u32); |
|
| 251 | 251 | for node, i in nodes { |
| 260 | 260 | } |
|
| 261 | 261 | return buf; |
|
| 262 | 262 | } |
|
| 263 | 263 | ||
| 264 | 264 | /// Convert an AST node to an S-expression. |
|
| 265 | - | export fn toExpr(a: &mut alloc::Arena, node: *super::Node) -> sexpr::Expr { |
|
| 265 | + | export unsafe fn toExpr(a: &mut alloc::Arena, node: *super::Node) -> sexpr::Expr { |
|
| 266 | 266 | match node.value { |
|
| 267 | 267 | case super::NodeValue::Placeholder => return sexpr::sym("_"), |
|
| 268 | 268 | case super::NodeValue::Nil => return sexpr::sym("nil"), |
|
| 269 | 269 | case super::NodeValue::Undef => return sexpr::sym("undefined"), |
|
| 270 | 270 | case super::NodeValue::Bool(v) => { |
lib/std/lang/gen/data.rad
+2 -2
| 80 | 80 | } |
|
| 81 | 81 | ||
| 82 | 82 | /// Emit data bytes for a single section (read-only or read-write) into `buf`. |
|
| 83 | 83 | /// Iterates data requiring sidecar image bytes, serializing each data item. |
|
| 84 | 84 | /// Returns the total number of bytes written. |
|
| 85 | - | export fn emitSection( |
|
| 85 | + | export unsafe fn emitSection( |
|
| 86 | 86 | items: *[il::Data], |
|
| 87 | 87 | dataSymMap: &DataSymMap, |
|
| 88 | 88 | fnLabels: &labels::Labels, |
|
| 89 | 89 | codeBase: u32, |
|
| 90 | 90 | buf: *mut [u8], |
| 92 | 92 | ) -> u32 { |
|
| 93 | 93 | return emitSectionAtOffset(items, dataSymMap, fnLabels, codeBase, buf, readOnly, 0); |
|
| 94 | 94 | } |
|
| 95 | 95 | ||
| 96 | 96 | /// Emit data bytes for a single section starting at `startOffset`. |
|
| 97 | - | export fn emitSectionAtOffset( |
|
| 97 | + | export unsafe fn emitSectionAtOffset( |
|
| 98 | 98 | items: *[il::Data], |
|
| 99 | 99 | dataSymMap: &DataSymMap, |
|
| 100 | 100 | fnLabels: &labels::Labels, |
|
| 101 | 101 | codeBase: u32, |
|
| 102 | 102 | buf: *mut [u8], |
lib/std/lang/gen/regalloc/assign.rad
+2 -2
| 185 | 185 | usedCalleeSaved, |
|
| 186 | 186 | }; |
|
| 187 | 187 | } |
|
| 188 | 188 | ||
| 189 | 189 | /// Create an empty register map. |
|
| 190 | - | fn createRegMap(arena: &mut alloc::Arena) -> RegMap throws (alloc::AllocError) { |
|
| 190 | + | unsafe fn createRegMap(arena: &mut alloc::Arena) -> RegMap throws (alloc::AllocError) { |
|
| 191 | 191 | let virtRegs = try alloc::allocSlice(arena, @sizeOf(u32), @alignOf(u32), MAX_ACTIVE) as *mut [u32]; |
|
| 192 | 192 | let physRegs = try alloc::allocSlice(arena, @sizeOf(gen::Reg), @alignOf(gen::Reg), MAX_ACTIVE) as *mut [gen::Reg]; |
|
| 193 | 193 | ||
| 194 | 194 | return RegMap { virtRegs, physRegs, n: 0 }; |
|
| 195 | 195 | } |
| 270 | 270 | } |
|
| 271 | 271 | panic "rallocReg: no free register, spilling fault"; |
|
| 272 | 272 | } |
|
| 273 | 273 | ||
| 274 | 274 | /// Record the current index; forward traversal leaves the last operand use. |
|
| 275 | - | fn recordLastUseCb(reg: il::Reg, ctxPtr: &mut opaque) { |
|
| 275 | + | unsafe fn recordLastUseCb(reg: il::Reg, ctxPtr: &mut opaque) { |
|
| 276 | 276 | recordLastUse(reg, ctxPtr as &mut LastUseCtx); |
|
| 277 | 277 | } |
|
| 278 | 278 | ||
| 279 | 279 | /// Record the last instruction that uses the register. |
|
| 280 | 280 | fn recordLastUse(reg: il::Reg, ctx: &mut LastUseCtx) { |
lib/std/lang/gen/regalloc/liveness.rad
+2 -2
| 179 | 179 | bitset::put(c.uses, reg.n); |
|
| 180 | 180 | } |
|
| 181 | 181 | } |
|
| 182 | 182 | ||
| 183 | 183 | /// Callback for [`il::forEachReg`]: updates max register number. |
|
| 184 | - | fn maxRegCallback(reg: il::Reg, ctx: &mut opaque) { |
|
| 184 | + | unsafe fn maxRegCallback(reg: il::Reg, ctx: &mut opaque) { |
|
| 185 | 185 | updateMaxReg(reg, ctx as &mut u32); |
|
| 186 | 186 | } |
|
| 187 | 187 | ||
| 188 | 188 | /// Update the largest register number. |
|
| 189 | 189 | fn updateMaxReg(reg: il::Reg, max: &mut u32) { |
| 248 | 248 | il::forEachReg(instr, findRegCallback, &mut ctx as &mut opaque); |
|
| 249 | 249 | return ctx.found; |
|
| 250 | 250 | } |
|
| 251 | 251 | ||
| 252 | 252 | /// Callback for [`il::forEachReg`]: sets found if register matches target. |
|
| 253 | - | fn findRegCallback(reg: il::Reg, ctx: &mut opaque) { |
|
| 253 | + | unsafe fn findRegCallback(reg: il::Reg, ctx: &mut opaque) { |
|
| 254 | 254 | findReg(reg, ctx as &mut FindCtx); |
|
| 255 | 255 | } |
|
| 256 | 256 | ||
| 257 | 257 | /// Set the match flag when the register equals the target. |
|
| 258 | 258 | fn findReg(reg: il::Reg, c: &mut FindCtx) { |
lib/std/lang/gen/regalloc/spill.rad
+1 -1
| 310 | 310 | } |
|
| 311 | 311 | } |
|
| 312 | 312 | } |
|
| 313 | 313 | ||
| 314 | 314 | /// Callback for [`il::forEachReg`]: increments use count for register. |
|
| 315 | - | fn countRegUseCallback(reg: il::Reg, ctxPtr: &mut opaque) { |
|
| 315 | + | unsafe fn countRegUseCallback(reg: il::Reg, ctxPtr: &mut opaque) { |
|
| 316 | 316 | countRegUse(reg, ctxPtr as &mut CountCtx); |
|
| 317 | 317 | } |
|
| 318 | 318 | ||
| 319 | 319 | /// Add the block weight to the register use count. |
|
| 320 | 320 | fn countRegUse(reg: il::Reg, ctx: &mut CountCtx) { |
lib/std/lang/il.rad
+1 -1
| 80 | 80 | ||
| 81 | 81 | /// Separator for qualified symbol names. |
|
| 82 | 82 | export constant PATH_SEPARATOR: *[u8] = "::"; |
|
| 83 | 83 | ||
| 84 | 84 | /// Format a qualified symbol name: `pkg::mod::path::name`. |
|
| 85 | - | export fn formatQualifiedName(arena: &mut alloc::Arena, path: *[*[u8]], name: *[u8]) -> *[u8] { |
|
| 85 | + | export unsafe fn formatQualifiedName(arena: &mut alloc::Arena, path: *[*[u8]], name: *[u8]) -> *[u8] { |
|
| 86 | 86 | let mut totalLen: u32 = name.len; |
|
| 87 | 87 | for segment in path { |
|
| 88 | 88 | set totalLen += segment.len + PATH_SEPARATOR.len; |
|
| 89 | 89 | } |
|
| 90 | 90 | let buf = try! alloc::allocSlice(arena, 1, 1, totalLen) as *mut [u8]; |
lib/std/lang/module/printer.rad
+2 -2
| 5 | 5 | use std::io; |
|
| 6 | 6 | use std::lang::sexpr; |
|
| 7 | 7 | use std::lang::alloc; |
|
| 8 | 8 | ||
| 9 | 9 | /// Format a u32 and allocate the result in the arena. |
|
| 10 | - | fn formatId(a: &mut alloc::Arena, id: u32) -> *[u8] { |
|
| 10 | + | unsafe fn formatId(a: &mut alloc::Arena, id: u32) -> *[u8] { |
|
| 11 | 11 | let mut digits: [u8; 10] = undefined; |
|
| 12 | 12 | let start = fmt::formatU32(id, &mut digits[..]); |
|
| 13 | 13 | let ptr = try alloc::allocSlice(a, 1, 1, digits.len - start) catch { return "?"; }; |
|
| 14 | 14 | let slice = ptr as *mut [u8]; |
|
| 15 | 15 | try mem::copy(slice, &digits[start..]) catch { return "?"; }; |
| 27 | 27 | case super::ModuleState::Ready => return sexpr::sym("ready"), |
|
| 28 | 28 | } |
|
| 29 | 29 | } |
|
| 30 | 30 | ||
| 31 | 31 | /// Recursively convert a module entry and its descendants to an S-expression. |
|
| 32 | - | fn subtreeToExpr( |
|
| 32 | + | unsafe fn subtreeToExpr( |
|
| 33 | 33 | a: &mut alloc::Arena, |
|
| 34 | 34 | graph: &super::ModuleGraph, |
|
| 35 | 35 | entry: *super::ModuleEntry |
|
| 36 | 36 | ) -> sexpr::Expr { |
|
| 37 | 37 | let idText = formatId(a, entry.id as u32); |
lib/std/lang/resolver.rad
+30 -16
| 888 | 888 | ty: Type, |
|
| 889 | 889 | next: ?*TypeNode, |
|
| 890 | 890 | } |
|
| 891 | 891 | ||
| 892 | 892 | /// Allocate and intern a type in the arena, returning a pointer for deduplication. |
|
| 893 | - | export fn allocType(self: &mut Resolver, ty: Type) -> *Type { |
|
| 893 | + | export unsafe fn allocType(self: &mut Resolver, ty: Type) -> *Type { |
|
| 894 | 894 | // Search existing types for a match. |
|
| 895 | 895 | let mut cursor = self.types; |
|
| 896 | 896 | while let node = cursor { |
|
| 897 | 897 | if node.ty == ty { |
|
| 898 | 898 | return &node.ty; |
| 909 | 909 | ||
| 910 | 910 | return &node.ty; |
|
| 911 | 911 | } |
|
| 912 | 912 | ||
| 913 | 913 | /// Allocate a nominal type descriptor and return a pointer to it. |
|
| 914 | - | fn allocNominalType(self: &mut Resolver, info: NominalType) -> *mut NominalType { |
|
| 914 | + | unsafe fn allocNominalType(self: &mut Resolver, info: NominalType) -> *mut NominalType { |
|
| 915 | 915 | // Nb. We don't attempt to de-duplicate nominal type entries, |
|
| 916 | 916 | // since they don't carry node information and we create |
|
| 917 | 917 | // placeholder entries when binding symbols. |
|
| 918 | 918 | let entry = try! alloc::alloc( |
|
| 919 | 919 | &mut self.arena, @sizeOf(NominalType), @alignOf(NominalType) |
| 923 | 923 | ||
| 924 | 924 | return entry; |
|
| 925 | 925 | } |
|
| 926 | 926 | ||
| 927 | 927 | /// Allocate a function type descriptor and return a pointer to it. |
|
| 928 | - | fn allocFnType(self: &mut Resolver, info: FnType) -> *FnType { |
|
| 928 | + | unsafe fn allocFnType(self: &mut Resolver, info: FnType) -> *FnType { |
|
| 929 | 929 | let entry = try! alloc::alloc( |
|
| 930 | 930 | &mut self.arena, @sizeOf(FnType), @alignOf(FnType) |
|
| 931 | 931 | ) as *mut FnType; |
|
| 932 | 932 | ||
| 933 | 933 | set *entry = info; |
| 965 | 965 | /// Root AST node. |
|
| 966 | 966 | rootAst: *ast::Node, |
|
| 967 | 967 | } |
|
| 968 | 968 | ||
| 969 | 969 | /// Construct a resolver with module context and backing storage. |
|
| 970 | - | export fn resolver( |
|
| 970 | + | export unsafe fn resolver( |
|
| 971 | 971 | storage: ResolverStorage, |
|
| 972 | 972 | config: Config |
|
| 973 | 973 | ) -> Resolver { |
|
| 974 | 974 | let mut arena = storage.arena; |
|
| 975 | 975 | let symbols = try! alloc::allocSlice( |
| 1061 | 1061 | fn emitTypeMismatch(self: &mut Resolver, node: ?*ast::Node, mismatch: TypeMismatch) -> ResolveError { |
|
| 1062 | 1062 | return emitError(self, node, ErrorKind::TypeMismatch(mismatch)); |
|
| 1063 | 1063 | } |
|
| 1064 | 1064 | ||
| 1065 | 1065 | /// Allocate a scope object with the given symbol capacity. |
|
| 1066 | - | fn allocScope(self: &mut Resolver, owner: *ast::Node, capacity: u32) -> *mut Scope { |
|
| 1066 | + | unsafe fn allocScope(self: &mut Resolver, owner: *ast::Node, capacity: u32) -> *mut Scope { |
|
| 1067 | 1067 | // Check for an existing scope for this node, and don't allocate a new |
|
| 1068 | 1068 | // one in that case. |
|
| 1069 | 1069 | if let scope = scopeFor(self, owner) { |
|
| 1070 | 1070 | return scope; |
|
| 1071 | 1071 | } |
| 1085 | 1085 | } |
|
| 1086 | 1086 | ||
| 1087 | 1087 | /// Enter a new local scope that is the child of the current scope. |
|
| 1088 | 1088 | /// This creates a parent/child relationship that means that lookups in the |
|
| 1089 | 1089 | /// child scope can recurse upwards. |
|
| 1090 | - | export fn enterScope(self: &mut Resolver, owner: *ast::Node) -> *Scope { |
|
| 1090 | + | export unsafe fn enterScope(self: &mut Resolver, owner: *ast::Node) -> *Scope { |
|
| 1091 | 1091 | let scope = allocScope(self, owner, MAX_LOCAL_SYMBOLS); |
|
| 1092 | 1092 | set scope.parent = self.scope; |
|
| 1093 | 1093 | set self.scope = scope; |
|
| 1094 | 1094 | return scope; |
|
| 1095 | 1095 | } |
|
| 1096 | 1096 | ||
| 1097 | 1097 | /// Enter a module scope. Returns an object that can be used to exit the scope. |
|
| 1098 | - | export fn enterModuleScope(self: &mut Resolver, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope { |
|
| 1098 | + | export unsafe fn enterModuleScope(self: &mut Resolver, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope { |
|
| 1099 | 1099 | let prevScope = self.scope; |
|
| 1100 | 1100 | let prevMod = self.currentMod; |
|
| 1101 | 1101 | let scope = allocScope(self, owner, MAX_MODULE_SYMBOLS); |
|
| 1102 | 1102 | ||
| 1103 | 1103 | set self.scope = scope; |
| 1402 | 1402 | } |
|
| 1403 | 1403 | return arg; |
|
| 1404 | 1404 | } |
|
| 1405 | 1405 | ||
| 1406 | 1406 | /// Allocate a new symbol, and return a reference to it. |
|
| 1407 | - | fn allocSymbol(self: &mut Resolver, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *mut Symbol { |
|
| 1407 | + | unsafe fn allocSymbol(self: &mut Resolver, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *mut Symbol { |
|
| 1408 | 1408 | let sym = try! alloc::alloc(&mut self.arena, @sizeOf(Symbol), @alignOf(Symbol)) as *mut Symbol; |
|
| 1409 | 1409 | set *sym = Symbol { name, data, attrs, node, moduleId: nil }; |
|
| 1410 | 1410 | ||
| 1411 | 1411 | return sym; |
|
| 1412 | 1412 | } |
| 2224 | 2224 | } |
|
| 2225 | 2225 | return actualTy; |
|
| 2226 | 2226 | } |
|
| 2227 | 2227 | ||
| 2228 | 2228 | /// Bind an identifier in the given scope. |
|
| 2229 | - | fn bindIdent( |
|
| 2229 | + | unsafe fn bindIdent( |
|
| 2230 | 2230 | self: &mut Resolver, |
|
| 2231 | 2231 | name: *[u8], |
|
| 2232 | 2232 | owner: *ast::Node, |
|
| 2233 | 2233 | data: SymbolData, |
|
| 2234 | 2234 | attrs: u32, |
| 2290 | 2290 | } |
|
| 2291 | 2291 | return sym; |
|
| 2292 | 2292 | } |
|
| 2293 | 2293 | ||
| 2294 | 2294 | /// Bind a constant identifier in the current scope. |
|
| 2295 | - | fn bindConstIdent( |
|
| 2295 | + | unsafe fn bindConstIdent( |
|
| 2296 | 2296 | self: &mut Resolver, |
|
| 2297 | 2297 | ident: *ast::Node, |
|
| 2298 | 2298 | owner: *ast::Node, |
|
| 2299 | 2299 | type: Type, |
|
| 2300 | 2300 | val: ?ConstValue, |
| 2311 | 2311 | } |
|
| 2312 | 2312 | ||
| 2313 | 2313 | /// Bind a module identifier in the given scope. |
|
| 2314 | 2314 | /// This is used when declaring modules with `mod` or |
|
| 2315 | 2315 | /// importing modules with `use`. |
|
| 2316 | - | fn bindModuleIdent( |
|
| 2316 | + | unsafe fn bindModuleIdent( |
|
| 2317 | 2317 | self: &mut Resolver, |
|
| 2318 | 2318 | entry: *module::ModuleEntry, |
|
| 2319 | 2319 | scope: *mut Scope, |
|
| 2320 | 2320 | owner: *ast::Node, |
|
| 2321 | 2321 | attrs: u32, |
| 2326 | 2326 | ||
| 2327 | 2327 | return try bindIdent(self, name, owner, data, attrs, bindingScope); |
|
| 2328 | 2328 | } |
|
| 2329 | 2329 | ||
| 2330 | 2330 | /// Bind a type identifier in the current scope. |
|
| 2331 | - | fn bindTypeIdent( |
|
| 2331 | + | unsafe fn bindTypeIdent( |
|
| 2332 | 2332 | self: &mut Resolver, |
|
| 2333 | 2333 | ident: *ast::Node, |
|
| 2334 | 2334 | owner: *ast::Node, |
|
| 2335 | 2335 | type: *mut NominalType, |
|
| 2336 | 2336 | attrs: u32 |
| 3621 | 3621 | ||
| 3622 | 3622 | set *nominalTy = NominalType::Record(recordType); |
|
| 3623 | 3623 | } |
|
| 3624 | 3624 | ||
| 3625 | 3625 | /// Bind a type name. |
|
| 3626 | - | fn bindTypeName(self: &mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol |
|
| 3626 | + | unsafe fn bindTypeName(self: &mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol |
|
| 3627 | 3627 | throws (ResolveError) |
|
| 3628 | 3628 | { |
|
| 3629 | 3629 | let attrMask = resolveAttributes(self, attrs); |
|
| 3630 | 3630 | try ensureDefaultAttrNotAllowed(self, node, attrMask); |
|
| 3631 | 3631 |
| 3635 | 3635 | ||
| 3636 | 3636 | return try bindTypeIdent(self, name, node, nominalTy, attrMask); |
|
| 3637 | 3637 | } |
|
| 3638 | 3638 | ||
| 3639 | 3639 | /// Allocate a trait type descriptor and return a pointer to it. |
|
| 3640 | - | fn allocTraitType(self: &mut Resolver, name: *[u8]) -> *mut TraitType { |
|
| 3640 | + | unsafe fn allocTraitType(self: &mut Resolver, name: *[u8]) -> *mut TraitType { |
|
| 3641 | 3641 | let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType)); |
|
| 3642 | 3642 | let entry = p as *mut TraitType; |
|
| 3643 | 3643 | set *entry = TraitType { name, methods: &mut [], supertraits: &mut [] }; |
|
| 3644 | 3644 | ||
| 3645 | 3645 | return entry; |
|
| 3646 | 3646 | } |
|
| 3647 | 3647 | ||
| 3648 | 3648 | /// Bind a trait name in the current scope. |
|
| 3649 | - | fn bindTraitName(self: &mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol |
|
| 3649 | + | unsafe fn bindTraitName(self: &mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol |
|
| 3650 | 3650 | throws (ResolveError) |
|
| 3651 | 3651 | { |
|
| 3652 | 3652 | let attrMask = resolveAttributes(self, attrs); |
|
| 3653 | 3653 | try ensureDefaultAttrNotAllowed(self, node, attrMask); |
|
| 3654 | 3654 |
| 6610 | 6610 | set valid = true; |
|
| 6611 | 6611 | } |
|
| 6612 | 6612 | } |
|
| 6613 | 6613 | } |
|
| 6614 | 6614 | if valid { |
|
| 6615 | + | if let case Type::Pointer { target: sourceTarget, .. } = sourceTy { |
|
| 6616 | + | if let case Type::Pointer { target: targetTarget, .. } = targetTy { |
|
| 6617 | + | if *targetTarget <> Type::Opaque and not typesEqual(*sourceTarget, *targetTarget) { |
|
| 6618 | + | try requireUnsafe(self, node); |
|
| 6619 | + | } |
|
| 6620 | + | } |
|
| 6621 | + | } |
|
| 6622 | + | if let case Type::Slice { item: sourceItem, .. } = sourceTy { |
|
| 6623 | + | if let case Type::Slice { item: targetItem, .. } = targetTy { |
|
| 6624 | + | if *targetItem <> Type::Opaque and not typesEqual(*sourceItem, *targetItem) { |
|
| 6625 | + | try requireUnsafe(self, node); |
|
| 6626 | + | } |
|
| 6627 | + | } |
|
| 6628 | + | } |
|
| 6615 | 6629 | // Propagate the constant value after applying the cast's target-width |
|
| 6616 | 6630 | // truncation and signed interpretation. |
|
| 6617 | 6631 | if let value = constValueEntry(self, expr.value) { |
|
| 6618 | 6632 | if let case ConstValue::Int(i) = value { |
|
| 6619 | 6633 | setNodeConstValue(self, node, castConstInt(i, targetTy)); |
| 7390 | 7404 | } |
|
| 7391 | 7405 | } |
|
| 7392 | 7406 | ||
| 7393 | 7407 | /// Bind all type names in a module. |
|
| 7394 | 7408 | /// Skips declarations that have already been bound. |
|
| 7395 | - | fn bindTypeNames(self: &mut Resolver, block: &ast::Block) throws (ResolveError) { |
|
| 7409 | + | unsafe fn bindTypeNames(self: &mut Resolver, block: &ast::Block) throws (ResolveError) { |
|
| 7396 | 7410 | for node in block.statements { |
|
| 7397 | 7411 | match node.value { |
|
| 7398 | 7412 | case ast::NodeValue::RecordDecl(decl) => { |
|
| 7399 | 7413 | if symbolFor(self, node) == nil { |
|
| 7400 | 7414 | try bindTypeName(self, node, decl.name, decl.attrs) catch {}; |
lib/std/lang/resolver/tests.rad
+36 -9
| 3641 | 3641 | // Opaque pointer tests. |
|
| 3642 | 3642 | ||
| 3643 | 3643 | /// You can assign any pointer (*T) to an opaque pointer (*opaque) without a cast. |
|
| 3644 | 3644 | @test unsafe fn testOpaquePointerAutoCoercion() throws (testing::TestError) { |
|
| 3645 | 3645 | let mut a = testResolver(); |
|
| 3646 | - | let result = try resolveProgramStr(&mut a, "fn f(x: *i32) { let mut ptr: *i32 = x; let o: *opaque = ptr; set ptr = o as *i32; }"); |
|
| 3646 | + | let result = try resolveProgramStr(&mut a, "unsafe fn f(x: *i32) { let mut ptr: *i32 = x; let o: *opaque = ptr; set ptr = o as *i32; }"); |
|
| 3647 | 3647 | try expectNoErrors(&result); |
|
| 3648 | 3648 | } |
|
| 3649 | 3649 | ||
| 3650 | 3650 | /// You cannot assign an opaque pointer to a non-opaque pointer without a cast. |
|
| 3651 | 3651 | @test unsafe fn testOpaquePointerNoReverseCoercion() throws (testing::TestError) { |
| 3692 | 3692 | } |
|
| 3693 | 3693 | ||
| 3694 | 3694 | /// Test that you can dereference after casting. |
|
| 3695 | 3695 | @test unsafe fn testOpaquePointerDereferenceAfterCast() throws (testing::TestError) { |
|
| 3696 | 3696 | let mut a = testResolver(); |
|
| 3697 | - | let result = try resolveProgramStr(&mut a, "fn f() { let o: *opaque = undefined; let x = *(o as *i32); }"); |
|
| 3697 | + | let result = try resolveProgramStr(&mut a, "unsafe fn f() { let o: *opaque = undefined; let x = *(o as *i32); }"); |
|
| 3698 | 3698 | try expectNoErrors(&result); |
|
| 3699 | 3699 | } |
|
| 3700 | 3700 | ||
| 3701 | 3701 | /// You cannot do pointer arithmetic with an opaque pointer. |
|
| 3702 | 3702 | @test unsafe fn testOpaquePointerNoArithmetic() throws (testing::TestError) { |
| 4502 | 4502 | let mut a = testResolver(); |
|
| 4503 | 4503 | let result = try resolveBlockStr(&mut a, "let f: fn() = undefined; f as u32;"); |
|
| 4504 | 4504 | try expectNoErrors(&result); |
|
| 4505 | 4505 | } { // *u8 to *i32 (u8 to i32 is valid). |
|
| 4506 | 4506 | let mut a = testResolver(); |
|
| 4507 | - | let result = try resolveBlockStr(&mut a, "let p: *u8 = undefined; p as *i32;"); |
|
| 4507 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: *u8 = undefined; p as *i32; }"); |
|
| 4508 | 4508 | try expectNoErrors(&result); |
|
| 4509 | 4509 | } { // **u8 to **i32 (*u8 to *i32 is valid). |
|
| 4510 | 4510 | let mut a = testResolver(); |
|
| 4511 | - | let result = try resolveBlockStr(&mut a, "let p: **u8 = undefined; p as **i32;"); |
|
| 4511 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let p: **u8 = undefined; p as **i32; }"); |
|
| 4512 | 4512 | try expectNoErrors(&result); |
|
| 4513 | 4513 | } |
|
| 4514 | 4514 | ||
| 4515 | 4515 | { // *[i32] to *[opaque]. |
|
| 4516 | 4516 | let mut a = testResolver(); |
|
| 4517 | 4517 | let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *[opaque];"); |
|
| 4518 | 4518 | try expectNoErrors(&result); |
|
| 4519 | 4519 | } { // *[opaque] to *[i32]. |
|
| 4520 | 4520 | let mut a = testResolver(); |
|
| 4521 | - | let result = try resolveBlockStr(&mut a, "let s: *[opaque] = undefined; s as *[i32];"); |
|
| 4521 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[opaque] = undefined; s as *[i32]; }"); |
|
| 4522 | 4522 | try expectNoErrors(&result); |
|
| 4523 | 4523 | } |
|
| 4524 | 4524 | ||
| 4525 | 4525 | { // *[i32] to *[u8]. |
|
| 4526 | 4526 | let mut a = testResolver(); |
|
| 4527 | - | let result = try resolveBlockStr(&mut a, "let s: *[i32] = undefined; s as *[u8];"); |
|
| 4527 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[i32] = undefined; s as *[u8]; }"); |
|
| 4528 | 4528 | try expectNoErrors(&result); |
|
| 4529 | 4529 | } { // *[record] to *[u8]. |
|
| 4530 | 4530 | let mut a = testResolver(); |
|
| 4531 | - | let result = try resolveProgramStr(&mut a, "record R { x: i32 } fn f(s: *[R]) { s as *[u8]; }"); |
|
| 4531 | + | let result = try resolveProgramStr(&mut a, "record R { x: i32 } unsafe fn f(s: *[R]) { s as *[u8]; }"); |
|
| 4532 | 4532 | try expectNoErrors(&result); |
|
| 4533 | 4533 | } |
|
| 4534 | 4534 | ||
| 4535 | 4535 | { // *[u8] to *[i32]. |
|
| 4536 | 4536 | let mut a = testResolver(); |
|
| 4537 | - | let result = try resolveBlockStr(&mut a, "let s: *[u8] = undefined; s as *[i32];"); |
|
| 4537 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[u8] = undefined; s as *[i32]; }"); |
|
| 4538 | 4538 | try expectNoErrors(&result); |
|
| 4539 | 4539 | } { // *[*u8] to *[*i32] |
|
| 4540 | 4540 | let mut a = testResolver(); |
|
| 4541 | - | let result = try resolveBlockStr(&mut a, "let s: *[*u8] = undefined; s as *[*i32];"); |
|
| 4541 | + | let result = try resolveProgramStr(&mut a, "unsafe fn run() { let s: *[*u8] = undefined; s as *[*i32]; }"); |
|
| 4542 | 4542 | try expectNoErrors(&result); |
|
| 4543 | 4543 | } |
|
| 4544 | 4544 | ||
| 4545 | 4545 | { // Identity cast: *mut [i32] to *mut [i32]. |
|
| 4546 | 4546 | let mut a = testResolver(); |
| 5481 | 5481 | try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return 1 + p; }"); |
|
| 5482 | 5482 | try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut u8 { return p - 1; }"); |
|
| 5483 | 5483 | try expectAnalyzeOk("fn run(value: u32) -> u32 { return value + 1; }"); |
|
| 5484 | 5484 | } |
|
| 5485 | 5485 | ||
| 5486 | + | /// Casts that reinterpret storage require an unsafe function. |
|
| 5487 | + | @test unsafe fn testStorageCastsRequireUnsafe() throws (testing::TestError) { |
|
| 5488 | + | let programs = &[ |
|
| 5489 | + | "fn run(p: *u8) -> *u64 { return p as *u64; }", |
|
| 5490 | + | "fn run(p: &u8) -> u64 { return *(p as &u64); }", |
|
| 5491 | + | "fn run(p: *mut u8) -> *mut u64 { return p as *mut u64; }", |
|
| 5492 | + | "fn run(p: *opaque) -> *u64 { return p as *u64; }", |
|
| 5493 | + | "fn run(p: **u8) -> **u64 { return p as **u64; }", |
|
| 5494 | + | "fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }", |
|
| 5495 | + | "fn run(s: *[opaque]) -> *[u64] { return s as *[u64]; }", |
|
| 5496 | + | "fn run(s: &mut [u64]) { let _ = s as &mut [u8]; }", |
|
| 5497 | + | "static DATA: [u8; 1] = [42]; fn run() -> u64 { return *(&DATA[0] as *u64); }", |
|
| 5498 | + | ]; |
|
| 5499 | + | for program in programs { |
|
| 5500 | + | let mut a = testResolver(); |
|
| 5501 | + | let result = try resolveProgramStr(&mut a, program); |
|
| 5502 | + | try expectErrorKind(&result, super::ErrorKind::UnsafeOperation); |
|
| 5503 | + | } |
|
| 5504 | + | try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u64 { return p as *u64; }"); |
|
| 5505 | + | try expectAnalyzeOk("unsafe fn run(p: &u8) -> u64 { return *(p as &u64); }"); |
|
| 5506 | + | try expectAnalyzeOk("unsafe fn run(s: *[u8]) -> *[u64] { return s as *[u64]; }"); |
|
| 5507 | + | try expectAnalyzeOk("fn run(p: *u8) -> *u8 { return p as *u8; }"); |
|
| 5508 | + | try expectAnalyzeOk("fn run(p: *u8) -> *opaque { return p as *opaque; }"); |
|
| 5509 | + | try expectAnalyzeOk("fn run(s: *[u8]) -> *[opaque] { return s as *[opaque]; }"); |
|
| 5510 | + | try expectAnalyzeOk("fn run(p: *mut u8) -> *u8 { return p as *u8; }"); |
|
| 5511 | + | } |
|
| 5512 | + | ||
| 5486 | 5513 | /// Unsafe declarations may compose unsafe operations and calls. |
|
| 5487 | 5514 | @test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) { |
|
| 5488 | 5515 | 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); }"; |
|
| 5489 | 5516 | try expectAnalyzeOk(program); |
|
| 5490 | 5517 | } |
lib/std/lang/sexpr.rad
+5 -5
| 31 | 31 | /// A block with a name, inline items, and child statements on separate lines. |
|
| 32 | 32 | Block { name: *[u8], items: *[Expr], children: *[Expr] }, |
|
| 33 | 33 | } |
|
| 34 | 34 | ||
| 35 | 35 | /// Allocate an array of Expr in the arena. |
|
| 36 | - | export fn allocExprs(arena: &mut alloc::Arena, len: u32) -> *mut [Expr] throws (alloc::AllocError) { |
|
| 36 | + | export unsafe fn allocExprs(arena: &mut alloc::Arena, len: u32) -> *mut [Expr] throws (alloc::AllocError) { |
|
| 37 | 37 | if len == 0 { |
|
| 38 | 38 | throw alloc::AllocError::OutOfMemory; |
|
| 39 | 39 | } |
|
| 40 | 40 | let ptr = try alloc::allocSlice(arena, @sizeOf(Expr), @alignOf(Expr), len); |
|
| 41 | 41 | return ptr as *mut [Expr]; |
|
| 42 | 42 | } |
|
| 43 | 43 | ||
| 44 | 44 | /// Allocate and copy items into the arena. |
|
| 45 | - | export fn allocItems(a: &mut alloc::Arena, items: &[Expr]) -> *[Expr] { |
|
| 45 | + | export unsafe fn allocItems(a: &mut alloc::Arena, items: &[Expr]) -> *[Expr] { |
|
| 46 | 46 | if items.len == 0 { |
|
| 47 | 47 | return &[]; |
|
| 48 | 48 | } |
|
| 49 | 49 | let buf = try! allocExprs(a, items.len); |
|
| 50 | 50 | for item, i in items { |
| 62 | 62 | export fn str(s: *[u8]) -> Expr { |
|
| 63 | 63 | return Expr::Str(s); |
|
| 64 | 64 | } |
|
| 65 | 65 | ||
| 66 | 66 | /// Shorthand for creating a list. |
|
| 67 | - | export fn list(a: &mut alloc::Arena, head: *[u8], tail: &[Expr]) -> Expr { |
|
| 67 | + | export unsafe fn list(a: &mut alloc::Arena, head: *[u8], tail: &[Expr]) -> Expr { |
|
| 68 | 68 | return Expr::List { head, tail: allocItems(a, tail), multiline: false }; |
|
| 69 | 69 | } |
|
| 70 | 70 | ||
| 71 | 71 | /// Shorthand for creating a bracket-delimited vector. |
|
| 72 | - | export fn vec(a: &mut alloc::Arena, items: &[Expr]) -> Expr { |
|
| 72 | + | export unsafe fn vec(a: &mut alloc::Arena, items: &[Expr]) -> Expr { |
|
| 73 | 73 | return Expr::Vec { items: allocItems(a, items) }; |
|
| 74 | 74 | } |
|
| 75 | 75 | ||
| 76 | 76 | /// Shorthand for creating a block with inline items and child expressions. |
|
| 77 | - | export fn block(a: &mut alloc::Arena, name: *[u8], items: &[Expr], children: &[Expr]) -> Expr { |
|
| 77 | + | export unsafe fn block(a: &mut alloc::Arena, name: *[u8], items: &[Expr], children: &[Expr]) -> Expr { |
|
| 78 | 78 | return Expr::Block { name, items: allocItems(a, items), children: allocItems(a, children) }; |
|
| 79 | 79 | } |
|
| 80 | 80 | ||
| 81 | 81 | /// Write a string to the output target. |
|
| 82 | 82 | export unsafe fn write(out: &mut Output, s: &[u8]) { |
lib/std/vec.rad
+2 -2
| 76 | 76 | ||
| 77 | 77 | /// Pop an element from the end of the vector. |
|
| 78 | 78 | /// |
|
| 79 | 79 | /// Copies the element into the provided output pointer. |
|
| 80 | 80 | /// Returns false if the vector is empty. |
|
| 81 | - | export fn pop(vec: &mut RawVec, out: &mut opaque) -> bool { |
|
| 81 | + | export unsafe fn pop(vec: &mut RawVec, out: &mut opaque) -> bool { |
|
| 82 | 82 | if vec.len == 0 { |
|
| 83 | 83 | return false; |
|
| 84 | 84 | } |
|
| 85 | 85 | set vec.len -= 1; |
|
| 86 | 86 |
| 91 | 91 | } |
|
| 92 | 92 | ||
| 93 | 93 | /// Set the element at the given index. |
|
| 94 | 94 | /// |
|
| 95 | 95 | /// Returns false if index is out of bounds. |
|
| 96 | - | export fn put(vec: &mut RawVec, index: u32, elem: &opaque) -> bool { |
|
| 96 | + | export unsafe fn put(vec: &mut RawVec, index: u32, elem: &opaque) -> bool { |
|
| 97 | 97 | if index >= vec.len { |
|
| 98 | 98 | return false; |
|
| 99 | 99 | } |
|
| 100 | 100 | let off: u32 = index * vec.stride; |
|
| 101 | 101 | copyBytes(&mut vec.data[off..off + vec.stride], @sliceOf(elem as &u8, vec.stride)); |
test/tests/cast.basic.rad
+1 -1
| 37 | 37 | fn i32ToI16(x: i32) -> i16 { |
|
| 38 | 38 | return x as i16; |
|
| 39 | 39 | } |
|
| 40 | 40 | ||
| 41 | 41 | /// Cast pointer types (same size, no instruction). |
|
| 42 | - | fn ptrCast(x: *u8) -> *i32 { |
|
| 42 | + | unsafe fn ptrCast(x: *u8) -> *i32 { |
|
| 43 | 43 | return x as *i32; |
|
| 44 | 44 | } |
test/tests/fn.callback.nested.rad
+8 -4
| 20 | 20 | /// Update the maximum register count through a borrowed counter. |
|
| 21 | 21 | fn updateMax(reg: Reg, max: &mut u32) { |
|
| 22 | 22 | set *max = maxRegNum(reg.n, *max); |
|
| 23 | 23 | } |
|
| 24 | 24 | ||
| 25 | - | fn maxRegCallback(reg: Reg, ctx: &mut opaque) { |
|
| 25 | + | /// Update a register counter through an opaque context. |
|
| 26 | + | unsafe fn maxRegCallback(reg: Reg, ctx: &mut opaque) { |
|
| 26 | 27 | updateMax(reg, ctx as &mut u32); |
|
| 27 | 28 | } |
|
| 28 | 29 | ||
| 29 | - | fn withReg(val: Val, callback: fn(Reg, &mut opaque), ctx: &mut opaque) { |
|
| 30 | + | /// Call the callback for a register value. |
|
| 31 | + | unsafe fn withReg(val: Val, callback: unsafe fn(Reg, &mut opaque), ctx: &mut opaque) { |
|
| 30 | 32 | if let case Val::Reg(r) = val { |
|
| 31 | 33 | callback(r, ctx); |
|
| 32 | 34 | } |
|
| 33 | 35 | } |
|
| 34 | 36 | ||
| 35 | - | fn forEachVal(a: Val, b: Val, c: Val, callback: fn(Reg, &mut opaque), ctx: &mut opaque) { |
|
| 37 | + | /// Visit the register values with an opaque context. |
|
| 38 | + | unsafe fn forEachVal(a: Val, b: Val, c: Val, callback: unsafe fn(Reg, &mut opaque), ctx: &mut opaque) { |
|
| 36 | 39 | withReg(a, callback, ctx); |
|
| 37 | 40 | withReg(b, callback, ctx); |
|
| 38 | 41 | withReg(c, callback, ctx); |
|
| 39 | 42 | } |
|
| 40 | 43 | ||
| 41 | - | @default fn main() -> i32 { |
|
| 44 | + | /// Exercise a callback that calls another function. |
|
| 45 | + | @default unsafe fn main() -> i32 { |
|
| 42 | 46 | let mut maxReg: u32 = 0; |
|
| 43 | 47 | ||
| 44 | 48 | forEachVal( |
|
| 45 | 49 | Val::Reg(Reg { n: 0 }), |
|
| 46 | 50 | Val::Reg(Reg { n: 5 }), |
test/tests/pointer.cast.unsafe.rad
added
+16 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Aligned storage for pointer and slice views. |
|
| 4 | + | static DATA: [u64; 1] = [42]; |
|
| 5 | + | ||
| 6 | + | /// Reinterpret valid storage in an unsafe function. |
|
| 7 | + | @default unsafe fn main() -> i32 { |
|
| 8 | + | let bytes = &mut DATA[..] as *mut [u8]; |
|
| 9 | + | if bytes[0] <> 42 { return 1; } |
|
| 10 | + | set bytes[0] = 43; |
|
| 11 | + | let word = bytes.ptr as *u64; |
|
| 12 | + | if *word <> 43 { return 2; } |
|
| 13 | + | let words = bytes as *[u64]; |
|
| 14 | + | if words[0] <> 43 { return 3; } |
|
| 15 | + | return 0; |
|
| 16 | + | } |
test/tests/slice.append.rad
+3 -3
| 23 | 23 | return base as *mut opaque; |
|
| 24 | 24 | } |
|
| 25 | 25 | ||
| 26 | 26 | /// Allocator record matching the compiler's expected layout. |
|
| 27 | 27 | record Allocator: Copy { |
|
| 28 | - | func: fn(*mut opaque, u32, u32) -> *mut opaque, |
|
| 28 | + | func: unsafe fn(*mut opaque, u32, u32) -> *mut opaque, |
|
| 29 | 29 | ctx: *mut opaque, |
|
| 30 | 30 | } |
|
| 31 | 31 | ||
| 32 | - | fn arenaAllocFn(ctx: *mut opaque, size: u32, al: u32) -> *mut opaque { |
|
| 32 | + | unsafe fn arenaAllocFn(ctx: *mut opaque, size: u32, al: u32) -> *mut opaque { |
|
| 33 | 33 | let arena = ctx as *mut Arena; |
|
| 34 | 34 | return arenaAlloc(arena, size, al); |
|
| 35 | 35 | } |
|
| 36 | 36 | ||
| 37 | 37 | fn arenaAllocator(arena: *mut Arena) -> Allocator { |
| 41 | 41 | }; |
|
| 42 | 42 | } |
|
| 43 | 43 | ||
| 44 | 44 | static BUF: [u8; 4096] = undefined; |
|
| 45 | 45 | ||
| 46 | - | @default fn main() -> i32 { |
|
| 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); |
|
| 50 | 50 | ||
| 51 | 51 | // Allocate initial capacity of 4. |