Require unsafe functions for pointer arithmetic

5807f724d98a1885f0df04b1d6f6d07ee73b023f71aca1dab1f1b0c4216e85d6
Alexis Sellier committed ago 1 parent a9d3b2cf
lib/std/lang/resolver.rad +2 -6
7097 7097
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
7098 7098
                    }
7099 7099
                    if leftClass <> types::PointerClass::Ref
7100 7100
                        and isNumericType(rightTy)
7101 7101
                    {
7102 -
                        if leftClass == types::PointerClass::Unsafe {
7103 -
                            try requireUnsafe(self, node);
7104 -
                        }
7102 +
                        try requireUnsafe(self, node);
7105 7103
                        return setNodeType(self, node, leftTy);
7106 7104
                    }
7107 7105
                }
7108 7106
                if let case Type::Pointer { class: rightClass, target: rightTarget, .. } = rightTy {
7109 7107
                    if *rightTarget == Type::Opaque {
7111 7109
                    }
7112 7110
                    if binop.op == ast::BinaryOp::Add
7113 7111
                        and rightClass <> types::PointerClass::Ref
7114 7112
                        and isNumericType(leftTy)
7115 7113
                    {
7116 -
                        if rightClass == types::PointerClass::Unsafe {
7117 -
                            try requireUnsafe(self, node);
7118 -
                        }
7114 +
                        try requireUnsafe(self, node);
7119 7115
                        return setNodeType(self, node, rightTy);
7120 7116
                    }
7121 7117
                }
7122 7118
            }
7123 7119
            let leftTy = try checkNumeric(self, binop.left);
lib/std/lang/resolver/tests.rad +20 -0
5461 5461
        let result = try resolveProgramStr(&mut a, program);
5462 5462
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
5463 5463
    }
5464 5464
}
5465 5465
5466 +
/// Pointer offsets require an unsafe function for either operand order.
5467 +
@test unsafe fn testPointerArithmeticRequiresUnsafe() throws (testing::TestError) {
5468 +
    let programs = &[
5469 +
        "fn run(p: *u8) -> *u8 { return p + 1; }",
5470 +
        "fn run(p: *u8) -> *u8 { return 1 + p; }",
5471 +
        "fn run(p: *u8) -> *u8 { return p - 1; }",
5472 +
        "fn run(p: *mut u8) { set p += 1; }",
5473 +
        "static DATA: [u8; 1] = [42]; fn run() -> u8 { let p = &DATA[0]; return *(p + 1); }",
5474 +
    ];
5475 +
    for program in programs {
5476 +
        let mut a = testResolver();
5477 +
        let result = try resolveProgramStr(&mut a, program);
5478 +
        try expectErrorKind(&result, super::ErrorKind::UnsafeOperation);
5479 +
    }
5480 +
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return p + 1; }");
5481 +
    try expectAnalyzeOk("unsafe fn run(p: *u8) -> *u8 { return 1 + p; }");
5482 +
    try expectAnalyzeOk("unsafe fn run(p: *mut u8) -> *mut u8 { return p - 1; }");
5483 +
    try expectAnalyzeOk("fn run(value: u32) -> u32 { return value + 1; }");
5484 +
}
5485 +
5466 5486
/// Unsafe declarations may compose unsafe operations and calls.
5467 5487
@test unsafe fn testUnsafePointerOperationsAllowed() throws (testing::TestError) {
5468 5488
    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); }";
5469 5489
    try expectAnalyzeOk(program);
5470 5490
}
test/tests/pointer.arithmetic.unsafe.rad added +16 -0
1 +
//! returns: 0
2 +
3 +
/// Backing storage for pointer offsets.
4 +
static DATA: [u8; 3] = [11, 22, 33];
5 +
6 +
/// Read and write valid offsets in an unsafe function.
7 +
@default unsafe fn main() -> i32 {
8 +
    let p = &mut DATA[0];
9 +
    let q = p + 1;
10 +
    if *q <> 22 { return 1; }
11 +
    if *(1 + q) <> 33 { return 2; }
12 +
    if *(q - 1) <> 11 { return 3; }
13 +
    set *q = 44;
14 +
    if DATA[1] <> 44 { return 4; }
15 +
    return 0;
16 +
}