Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser: implement stdckdint.h #624

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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").?,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure these are memoized properly? Getting a bit worried about something like ziglang/zig#7948 happening here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how to know if that's happening - I had to up the eval branch quote for checkVarArg - is that why you ask?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that why you ask?

No just because there are so many calls now. I checked with @compileLog and they are getting memoized properly.

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);
}
Loading