Skip to content

Commit

Permalink
Parser: implement stdckdint.h
Browse files Browse the repository at this point in the history
Closes #578
  • Loading branch information
ehaas committed Feb 13, 2024
1 parent c72f45c commit 53907e5
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 1 deletion.
9 changes: 9 additions & 0 deletions include/stdckdint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* <stdckdint.h> for the Aro C compiler */

#pragma once

#define __STDC_VERSION_STDCKDINT_H__ 202311L

#define ckd_add(result, a, b) __builtin_add_overflow(a, b, result)
#define ckd_sub(result, a, b) __builtin_sub_overflow(a, b, result)
#define ckd_mul(result, a, b) __builtin_mul_overflow(a, b, result)
10 changes: 10 additions & 0 deletions src/aro/Diagnostics/messages.def
Original file line number Diff line number Diff line change
Expand Up @@ -2462,3 +2462,13 @@ complex_conj
.opt = W("pedantic")
.extra = .str
.kind = .off

overflow_builtin_requires_int
.msg = "operand argument to overflow builtin must be an integer ('{s}' invalid)"
.extra = .str
.kind = .@"error"

overflow_result_requires_ptr
.msg = "result argument to overflow builtin must be a pointer to a non-const integer ('{s}' invalid)"
.extra = .str
.kind = .@"error"
29 changes: 28 additions & 1 deletion src/aro/Parser.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4794,7 +4794,11 @@ const CallExpr = union(enum) {
Builtin.tagFromName("__va_start").?,
Builtin.tagFromName("va_start").?,
=> arg_idx != 1,
Builtin.tagFromName("__builtin_complex").? => false,
Builtin.tagFromName("__builtin_complex").?,
Builtin.tagFromName("__builtin_add_overflow").?,
Builtin.tagFromName("__builtin_sub_overflow").?,
Builtin.tagFromName("__builtin_mul_overflow").?,
=> false,
else => true,
},
};
Expand All @@ -4807,6 +4811,7 @@ const CallExpr = union(enum) {
}

fn checkVarArg(self: CallExpr, p: *Parser, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, arg_idx: u32) !void {
@setEvalBranchQuota(10_000);
if (self == .standard) return;

const builtin_tok = p.nodes.items(.data)[@intFromEnum(self.builtin.node)].decl.name;
Expand All @@ -4816,6 +4821,11 @@ const CallExpr = union(enum) {
Builtin.tagFromName("va_start").?,
=> return p.checkVaStartArg(builtin_tok, first_after, param_tok, arg, arg_idx),
Builtin.tagFromName("__builtin_complex").? => return p.checkComplexArg(builtin_tok, first_after, param_tok, arg, arg_idx),
Builtin.tagFromName("__builtin_add_overflow").?,
Builtin.tagFromName("__builtin_sub_overflow").?,
Builtin.tagFromName("__builtin_mul_overflow").?,
=> return p.checkArithOverflowArg(builtin_tok, first_after, param_tok, arg, arg_idx),

else => {},
}
}
Expand Down Expand Up @@ -4859,6 +4869,9 @@ const CallExpr = union(enum) {
Builtin.tagFromName("__atomic_xor_fetch").?,
Builtin.tagFromName("__atomic_or_fetch").?,
Builtin.tagFromName("__atomic_nand_fetch").?,
Builtin.tagFromName("__builtin_add_overflow").?,
Builtin.tagFromName("__builtin_sub_overflow").?,
Builtin.tagFromName("__builtin_mul_overflow").?,
=> 3,

Builtin.tagFromName("__c11_atomic_compare_exchange_strong").?,
Expand Down Expand Up @@ -7422,6 +7435,20 @@ fn checkVaStartArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex,
}
}

fn checkArithOverflowArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
_ = builtin_tok;
_ = first_after;
if (idx <= 1) {
if (!arg.ty.isInt()) {
return p.errStr(.overflow_builtin_requires_int, param_tok, try p.typeStr(arg.ty));
}
} else if (idx == 2) {
if (!arg.ty.isPtr()) return p.errStr(.overflow_result_requires_ptr, param_tok, try p.typeStr(arg.ty));
const child = arg.ty.elemType();
if (!child.isInt() or child.is(.bool) or child.is(.@"enum") or child.qual.@"const") return p.errStr(.overflow_result_requires_ptr, param_tok, try p.typeStr(arg.ty));
}
}

fn checkComplexArg(p: *Parser, builtin_tok: TokenIndex, first_after: TokenIndex, param_tok: TokenIndex, arg: *Result, idx: u32) !void {
_ = builtin_tok;
_ = first_after;
Expand Down
81 changes: 81 additions & 0 deletions test/cases/ast/stdckdint_ast.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
fn_def: 'fn () void'
name: foo
body:
compound_stmt: 'void'
var: 'char'
name: x
init:
implicit_cast: (int_cast) 'char'
int_literal: 'int' (value: 0)

var: 'unsigned int'
name: y
init:
implicit_cast: (int_cast) 'unsigned int'
int_literal: 'int' (value: 2)

var: '_Bool'
name: overflowed

var: 'long'
name: res

assign_expr: '_Bool'
lhs:
decl_ref_expr: '_Bool' lvalue
name: overflowed
rhs:
builtin_call_expr: '_Bool'
name: __builtin_add_overflow
args:
implicit_cast: (lval_to_rval) 'char'
decl_ref_expr: 'char' lvalue
name: x
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
operand:
decl_ref_expr: 'long' lvalue
name: res

assign_expr: '_Bool'
lhs:
decl_ref_expr: '_Bool' lvalue
name: overflowed
rhs:
builtin_call_expr: '_Bool'
name: __builtin_sub_overflow
args:
implicit_cast: (lval_to_rval) 'char'
decl_ref_expr: 'char' lvalue
name: x
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
operand:
decl_ref_expr: 'long' lvalue
name: res

assign_expr: '_Bool'
lhs:
decl_ref_expr: '_Bool' lvalue
name: overflowed
rhs:
builtin_call_expr: '_Bool'
name: __builtin_mul_overflow
args:
implicit_cast: (lval_to_rval) 'char'
decl_ref_expr: 'char' lvalue
name: x
implicit_cast: (lval_to_rval) 'unsigned int'
decl_ref_expr: 'unsigned int' lvalue
name: y
addr_of_expr: '*long'
operand:
decl_ref_expr: 'long' lvalue
name: res

implicit_return: 'void'

48 changes: 48 additions & 0 deletions test/cases/stdckdint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <stdckdint.h>

enum E {
A,
};

void foo(void) {
int x = 0;
unsigned y = 2;
_Bool b, overflowed;
enum E e;
unsigned res;
const unsigned const_res;
unsigned arr[2];

overflowed = ckd_add(&res, x, y);
overflowed = ckd_sub(&res, x, y);
overflowed = ckd_mul(&res, x, y);
overflowed = ckd_add(arr, x, y);

overflowed = ckd_add(res, x, y); // non-pointer result
overflowed = ckd_sub(&res, 1.2, y); // non-int argument
overflowed = ckd_mul(&b, x, y); // pointer to boolean result
overflowed = ckd_add(&const_res, x, y); // pointer to const result
overflowed = ckd_sub(&e, x, y); // pointer to enumerated result
overflowed = ckd_mul((void *)&res, x, y); // pointer to non-int result

}

#define EXPECTED_ERRORS "stdckdint.c:21:18: error: result argument to overflow builtin must be a pointer to a non-const integer ('unsigned int' invalid)" \
"stdckdint.h:7:60: note: expanded from here" \
"stdckdint.c:21:26: note: expanded from here" \
"stdckdint.c:22:18: error: operand argument to overflow builtin must be an integer ('double' invalid)" \
"stdckdint.h:8:54: note: expanded from here" \
"stdckdint.c:22:32: note: expanded from here" \
"stdckdint.c:23:18: error: result argument to overflow builtin must be a pointer to a non-const integer ('_Bool *' invalid)" \
"stdckdint.h:9:60: note: expanded from here" \
"stdckdint.c:23:26: note: expanded from here" \
"stdckdint.c:24:18: error: result argument to overflow builtin must be a pointer to a non-const integer ('const unsigned int *' invalid)" \
"stdckdint.h:7:60: note: expanded from here" \
"stdckdint.c:24:26: note: expanded from here" \
"stdckdint.c:25:18: error: result argument to overflow builtin must be a pointer to a non-const integer ('enum E *' invalid)" \
"stdckdint.h:8:60: note: expanded from here" \
"stdckdint.c:25:26: note: expanded from here" \
"stdckdint.c:26:18: error: result argument to overflow builtin must be a pointer to a non-const integer ('void *' invalid)" \
"stdckdint.h:9:60: note: expanded from here" \
"stdckdint.c:26:26: note: expanded from here" \

12 changes: 12 additions & 0 deletions test/cases/stdckdint_ast.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <stdckdint.h>

void foo(void) {
char x = 0;
unsigned y = 2;
_Bool overflowed;
long res;

overflowed = ckd_add(&res, x, y);
overflowed = ckd_sub(&res, x, y);
overflowed = ckd_mul(&res, x, y);
}

0 comments on commit 53907e5

Please sign in to comment.