authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-08 23:41:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-08 23:41:40-07:00
logb7dd88ad68aab5b6bc8321431d1a53b343b2dd37
tree78a9cd198eb94529a5841eb68c6bf57f9be21607
parent14b9cbd43c21ad2ba75b38ef5fc681c044e7662e

suport checked arithmetic operations via intrinsics

closes #32

10 files changed, 205 insertions(+), 19 deletions(-)

doc/langref.md+1-1
...@@ -160,7 +160,7 @@ SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression)...@@ -160,7 +160,7 @@ SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression)
160160
161PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))161PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
162162
163PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType163PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
164164
165StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)165StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
166166
src/analyze.cpp+40-2
...@@ -2064,6 +2064,41 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im...@@ -2064,6 +2064,41 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im
2064 }2064 }
2065}2065}
20662066
2067static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2068 TypeTableEntry *expected_type, AstNode *node)
2069{
2070 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
2071 Buf *name = &fn_ref_expr->data.symbol;
2072
2073 auto entry = g->builtin_fn_table.maybe_get(name);
2074
2075 if (entry) {
2076 BuiltinFnEntry *builtin_fn = entry->value;
2077 int actual_param_count = node->data.fn_call_expr.params.length;
2078
2079 assert(node->codegen_node);
2080 node->codegen_node->data.fn_call_node.builtin_fn = builtin_fn;
2081
2082 if (builtin_fn->param_count != actual_param_count) {
2083 add_node_error(g, node,
2084 buf_sprintf("expected %d arguments, got %d",
2085 builtin_fn->param_count, actual_param_count));
2086 }
2087
2088 for (int i = 0; i < actual_param_count; i += 1) {
2089 AstNode *child = node->data.fn_call_expr.params.at(i);
2090 TypeTableEntry *expected_param_type = builtin_fn->param_types[i];
2091 analyze_expression(g, import, context, expected_param_type, child);
2092 }
2093
2094 return builtin_fn->return_type;
2095 } else {
2096 add_node_error(g, node,
2097 buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
2098 return g->builtin_types.entry_invalid;
2099 }
2100}
2101
2067static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2102static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2068 TypeTableEntry *expected_type, AstNode *node)2103 TypeTableEntry *expected_type, AstNode *node)
2069{2104{
...@@ -2091,6 +2126,9 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -2091,6 +2126,9 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
2091 return g->builtin_types.entry_invalid;2126 return g->builtin_types.entry_invalid;
2092 }2127 }
2093 } else if (fn_ref_expr->type == NodeTypeSymbol) {2128 } else if (fn_ref_expr->type == NodeTypeSymbol) {
2129 if (node->data.fn_call_expr.is_builtin) {
2130 return analyze_builtin_fn_call_expr(g, import, context, expected_type, node);
2131 }
2094 name = &fn_ref_expr->data.symbol;2132 name = &fn_ref_expr->data.symbol;
2095 } else {2133 } else {
2096 add_node_error(g, node,2134 add_node_error(g, node,
...@@ -2126,12 +2164,12 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import...@@ -2126,12 +2164,12 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
2126 if (fn_proto->is_var_args) {2164 if (fn_proto->is_var_args) {
2127 if (actual_param_count < expected_param_count) {2165 if (actual_param_count < expected_param_count) {
2128 add_node_error(g, node,2166 add_node_error(g, node,
2129 buf_sprintf("wrong number of arguments. Expected at least %d, got %d.",2167 buf_sprintf("expected at least %d arguments, got %d",
2130 expected_param_count, actual_param_count));2168 expected_param_count, actual_param_count));
2131 }2169 }
2132 } else if (expected_param_count != actual_param_count) {2170 } else if (expected_param_count != actual_param_count) {
2133 add_node_error(g, node,2171 add_node_error(g, node,
2134 buf_sprintf("wrong number of arguments. Expected %d, got %d.",2172 buf_sprintf("expected %d arguments, got %d",
2135 expected_param_count, actual_param_count));2173 expected_param_count, actual_param_count));
2136 }2174 }
21372175
src/analyze.hpp+20-7
...@@ -148,6 +148,20 @@ struct FnTableEntry {...@@ -148,6 +148,20 @@ struct FnTableEntry {
148 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;148 HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
149};149};
150150
151enum BuiltinFnId {
152 BuiltinFnIdInvalid,
153 BuiltinFnIdArithmeticWithOverflow,
154};
155
156struct BuiltinFnEntry {
157 BuiltinFnId id;
158 Buf name;
159 int param_count;
160 TypeTableEntry *return_type;
161 TypeTableEntry **param_types;
162 LLVMValueRef fn_val;
163};
164
151struct CodeGen {165struct CodeGen {
152 LLVMModuleRef module;166 LLVMModuleRef module;
153 ZigList<ErrorMsg*> errors;167 ZigList<ErrorMsg*> errors;
...@@ -161,6 +175,7 @@ struct CodeGen {...@@ -161,6 +175,7 @@ struct CodeGen {
161 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;175 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
162 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;176 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
163 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;177 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
178 HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
164179
165 struct {180 struct {
166 TypeTableEntry *entry_bool;181 TypeTableEntry *entry_bool;
...@@ -342,6 +357,10 @@ struct WhileNode {...@@ -342,6 +357,10 @@ struct WhileNode {
342 bool contains_break;357 bool contains_break;
343};358};
344359
360struct FnCallNode {
361 BuiltinFnEntry *builtin_fn;
362};
363
345struct CodeGenNode {364struct CodeGenNode {
346 union {365 union {
347 TypeNode type_node; // for NodeTypeType366 TypeNode type_node; // for NodeTypeType
...@@ -363,17 +382,11 @@ struct CodeGenNode {...@@ -363,17 +382,11 @@ struct CodeGenNode {
363 ParamDeclNode param_decl_node; // for NodeTypeParamDecl382 ParamDeclNode param_decl_node; // for NodeTypeParamDecl
364 ImportNode import_node; // for NodeTypeUse383 ImportNode import_node; // for NodeTypeUse
365 WhileNode while_node; // for NodeTypeWhileExpr384 WhileNode while_node; // for NodeTypeWhileExpr
385 FnCallNode fn_call_node; // for NodeTypeFnCallExpr
366 } data;386 } data;
367 ExprNode expr_node; // for all the expression nodes387 ExprNode expr_node; // for all the expression nodes
368};388};
369389
370static inline Buf *hack_get_fn_call_name(CodeGen *g, AstNode *node) {
371 // Assume that the expression evaluates to a simple name and return the buf
372 // TODO after type checking works we should be able to remove this hack
373 assert(node->type == NodeTypeSymbol);
374 return &node->data.symbol;
375}
376
377void semantic_analyze(CodeGen *g);390void semantic_analyze(CodeGen *g);
378void add_node_error(CodeGen *g, AstNode *node, Buf *msg);391void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
379void alloc_codegen_node(AstNode *node);392void alloc_codegen_node(AstNode *node);
src/codegen.cpp+105-2
...@@ -22,6 +22,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {...@@ -22,6 +22,7 @@ CodeGen *codegen_create(Buf *root_source_dir) {
22 g->str_table.init(32);22 g->str_table.init(32);
23 g->link_table.init(32);23 g->link_table.init(32);
24 g->import_table.init(32);24 g->import_table.init(32);
25 g->builtin_fn_table.init(32);
25 g->build_type = CodeGenBuildTypeDebug;26 g->build_type = CodeGenBuildTypeDebug;
26 g->root_source_dir = root_source_dir;27 g->root_source_dir = root_source_dir;
2728
...@@ -139,6 +140,41 @@ static TypeTableEntry *get_expr_type(AstNode *node) {...@@ -139,6 +140,41 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
139 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;140 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
140}141}
141142
143static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
144 assert(node->type == NodeTypeFnCallExpr);
145 AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
146 assert(fn_ref_expr->type == NodeTypeSymbol);
147 BuiltinFnEntry *builtin_fn = node->codegen_node->data.fn_call_node.builtin_fn;
148
149 switch (builtin_fn->id) {
150 case BuiltinFnIdInvalid:
151 zig_unreachable();
152 case BuiltinFnIdArithmeticWithOverflow:
153 {
154 int fn_call_param_count = node->data.fn_call_expr.params.length;
155 assert(fn_call_param_count == 3);
156
157 LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(0));
158 LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(1));
159 LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(2));
160
161 LLVMValueRef params[] = {
162 op1,
163 op2,
164 };
165
166 add_debug_source_node(g, node);
167 LLVMValueRef result_struct = LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 2, "");
168 LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, "");
169 LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, "");
170 LLVMBuildStore(g->builder, result, ptr_result);
171
172 return overflow_bit;
173 }
174 }
175 zig_unreachable();
176}
177
142static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {178static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
143 assert(node->type == NodeTypeFnCallExpr);179 assert(node->type == NodeTypeFnCallExpr);
144180
...@@ -159,7 +195,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {...@@ -159,7 +195,15 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
159 zig_unreachable();195 zig_unreachable();
160 }196 }
161 } else if (fn_ref_expr->type == NodeTypeSymbol) {197 } else if (fn_ref_expr->type == NodeTypeSymbol) {
162 Buf *name = hack_get_fn_call_name(g, fn_ref_expr);198 if (node->data.fn_call_expr.is_builtin) {
199 return gen_builtin_fn_call_expr(g, node);
200 }
201
202 // Assume that the expression evaluates to a simple name and return the buf
203 // TODO after we support function pointers we can make this generic
204 assert(fn_ref_expr->type == NodeTypeSymbol);
205 Buf *name = &fn_ref_expr->data.symbol;
206
163 struct_type = nullptr;207 struct_type = nullptr;
164 first_param_expr = nullptr;208 first_param_expr = nullptr;
165 fn_table_entry = g->cur_fn->import_entry->fn_table.get(name);209 fn_table_entry = g->cur_fn->import_entry->fn_table.get(name);
...@@ -2167,6 +2211,64 @@ static void define_builtin_types(CodeGen *g) {...@@ -2167,6 +2211,64 @@ static void define_builtin_types(CodeGen *g) {
2167 }2211 }
2168}2212}
21692213
2214static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
2215 assert(type_entry->id == TypeTableEntryIdInt);
2216 struct OverflowFn {
2217 const char *bare_name;
2218 const char *signed_name;
2219 const char *unsigned_name;
2220 };
2221 OverflowFn overflow_fns[] = {
2222 {"add", "sadd", "uadd"},
2223 {"sub", "ssub", "usub"},
2224 {"mul", "smul", "umul"},
2225 };
2226 for (int i = 0; i < sizeof(overflow_fns)/sizeof(overflow_fns[0]); i += 1) {
2227 OverflowFn *overflow_fn = &overflow_fns[i];
2228 BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
2229 buf_resize(&builtin_fn->name, 0);
2230 buf_appendf(&builtin_fn->name, "%s_with_overflow_%s", overflow_fn->bare_name, buf_ptr(&type_entry->name));
2231 builtin_fn->id = BuiltinFnIdArithmeticWithOverflow;
2232 builtin_fn->return_type = g->builtin_types.entry_bool;
2233 builtin_fn->param_count = 3;
2234 builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
2235 builtin_fn->param_types[0] = type_entry;
2236 builtin_fn->param_types[1] = type_entry;
2237 builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false, false);
2238
2239
2240 const char *signed_str = type_entry->data.integral.is_signed ?
2241 overflow_fn->signed_name : overflow_fn->unsigned_name;
2242 Buf *llvm_name = buf_sprintf("llvm.%s.with.overflow.i%" PRIu64, signed_str, type_entry->size_in_bits);
2243
2244 LLVMTypeRef return_elem_types[] = {
2245 type_entry->type_ref,
2246 LLVMInt1Type(),
2247 };
2248 LLVMTypeRef param_types[] = {
2249 type_entry->type_ref,
2250 type_entry->type_ref,
2251 };
2252 LLVMTypeRef return_struct_type = LLVMStructType(return_elem_types, 2, false);
2253 LLVMTypeRef fn_type = LLVMFunctionType(return_struct_type, param_types, 2, false);
2254 builtin_fn->fn_val = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type);
2255 assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
2256
2257 g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
2258 }
2259}
2260
2261static void define_builtin_fns(CodeGen *g) {
2262 define_builtin_fns_int(g, g->builtin_types.entry_u8);
2263 define_builtin_fns_int(g, g->builtin_types.entry_u16);
2264 define_builtin_fns_int(g, g->builtin_types.entry_u32);
2265 define_builtin_fns_int(g, g->builtin_types.entry_u64);
2266 define_builtin_fns_int(g, g->builtin_types.entry_i8);
2267 define_builtin_fns_int(g, g->builtin_types.entry_i16);
2268 define_builtin_fns_int(g, g->builtin_types.entry_i32);
2269 define_builtin_fns_int(g, g->builtin_types.entry_i64);
2270}
2271
21702272
21712273
2172static void init(CodeGen *g, Buf *source_path) {2274static void init(CodeGen *g, Buf *source_path) {
...@@ -2228,9 +2330,10 @@ static void init(CodeGen *g, Buf *source_path) {...@@ -2228,9 +2330,10 @@ static void init(CodeGen *g, Buf *source_path) {
2228 "", 0, !g->strip_debug_symbols);2330 "", 0, !g->strip_debug_symbols);
22292331
2230 // This is for debug stuff that doesn't have a real file.2332 // This is for debug stuff that doesn't have a real file.
2231 g->dummy_di_file = nullptr; //LLVMZigCreateFile(g->dbuilder, "", "");2333 g->dummy_di_file = nullptr;
22322334
2233 define_builtin_types(g);2335 define_builtin_types(g);
2336 define_builtin_fns(g);
22342337
2235}2338}
22362339
src/parser.cpp+13-1
...@@ -1313,7 +1313,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {...@@ -1313,7 +1313,7 @@ static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
1313}1313}
13141314
1315/*1315/*
1316PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType1316PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
1317KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)1317KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
1318*/1318*/
1319static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {1319static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
...@@ -1356,6 +1356,18 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1356,6 +1356,18 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
1356 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);1356 AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
1357 *token_index += 1;1357 *token_index += 1;
1358 return node;1358 return node;
1359 } else if (token->id == TokenIdAtSign) {
1360 *token_index += 1;
1361 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
1362 AstNode *name_node = ast_create_node(pc, NodeTypeSymbol, name_tok);
1363 ast_buf_from_token(pc, name_tok, &name_node->data.symbol);
1364
1365 AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
1366 node->data.fn_call_expr.fn_ref_expr = name_node;
1367 ast_eat_token(pc, token_index, TokenIdLParen);
1368 ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
1369 node->data.fn_call_expr.is_builtin = true;
1370 return node;
1359 } else if (token->id == TokenIdSymbol) {1371 } else if (token->id == TokenIdSymbol) {
1360 Token *next_token = &pc->tokens->at(*token_index + 1);1372 Token *next_token = &pc->tokens->at(*token_index + 1);
13611373
src/parser.hpp+1
...@@ -176,6 +176,7 @@ struct AstNodeBinOpExpr {...@@ -176,6 +176,7 @@ struct AstNodeBinOpExpr {
176struct AstNodeFnCallExpr {176struct AstNodeFnCallExpr {
177 AstNode *fn_ref_expr;177 AstNode *fn_ref_expr;
178 ZigList<AstNode *> params;178 ZigList<AstNode *> params;
179 bool is_builtin;
179};180};
180181
181struct AstNodeArrayAccessExpr {182struct AstNodeArrayAccessExpr {
src/tokenizer.cpp+5
...@@ -376,6 +376,10 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -376,6 +376,10 @@ void tokenize(Buf *buf, Tokenization *out) {
376 begin_token(&t, TokenIdTilde);376 begin_token(&t, TokenIdTilde);
377 end_token(&t);377 end_token(&t);
378 break;378 break;
379 case '@':
380 begin_token(&t, TokenIdAtSign);
381 end_token(&t);
382 break;
379 case '-':383 case '-':
380 begin_token(&t, TokenIdDash);384 begin_token(&t, TokenIdDash);
381 t.state = TokenizeStateSawDash;385 t.state = TokenizeStateSawDash;
...@@ -1074,6 +1078,7 @@ static const char * token_name(Token *token) {...@@ -1074,6 +1078,7 @@ static const char * token_name(Token *token) {
1074 case TokenIdMaybe: return "Maybe";1078 case TokenIdMaybe: return "Maybe";
1075 case TokenIdDoubleQuestion: return "DoubleQuestion";1079 case TokenIdDoubleQuestion: return "DoubleQuestion";
1076 case TokenIdMaybeAssign: return "MaybeAssign";1080 case TokenIdMaybeAssign: return "MaybeAssign";
1081 case TokenIdAtSign: return "AtSign";
1077 }1082 }
1078 return "(invalid token)";1083 return "(invalid token)";
1079}1084}
src/tokenizer.hpp+1
...@@ -89,6 +89,7 @@ enum TokenId {...@@ -89,6 +89,7 @@ enum TokenId {
89 TokenIdMaybe,89 TokenIdMaybe,
90 TokenIdDoubleQuestion,90 TokenIdDoubleQuestion,
91 TokenIdMaybeAssign,91 TokenIdMaybeAssign,
92 TokenIdAtSign,
92};93};
9394
94struct Token {95struct Token {
std/std.zig-5
...@@ -63,10 +63,6 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {...@@ -63,10 +63,6 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
63 return true;63 return true;
64 }64 }
6565
66 x *= radix;
67 x += digit;
68
69 /* TODO intrinsics mul and add with overflow
70 // x *= radix66 // x *= radix
71 if (@mul_with_overflow_u64(x, radix, &x)) {67 if (@mul_with_overflow_u64(x, radix, &x)) {
72 return true;68 return true;
...@@ -76,7 +72,6 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {...@@ -76,7 +72,6 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
76 if (@add_with_overflow_u64(x, digit, &x)) {72 if (@add_with_overflow_u64(x, digit, &x)) {
77 return true;73 return true;
78 }74 }
79 */
8075
81 i += 1;76 i += 1;
82 }77 }
test/run_tests.cpp+19-1
...@@ -953,6 +953,24 @@ fn f(c: u8) -> u8 {...@@ -953,6 +953,24 @@ fn f(c: u8) -> u8 {
953 } else {953 } else {
954 2954 2
955 }955 }
956}
957 )SOURCE", "OK\n");
958
959 add_simple_case("overflow intrinsics", R"SOURCE(
960use "std.zig";
961pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
962 var result: u8;
963 if (!@add_with_overflow_u8(250, 100, &result)) {
964 print_str("BAD\n");
965 }
966 if (@add_with_overflow_u8(100, 150, &result)) {
967 print_str("BAD\n");
968 }
969 if (result != 250) {
970 print_str("BAD\n");
971 }
972 print_str("OK\n");
973 return 0;
956}974}
957 )SOURCE", "OK\n");975 )SOURCE", "OK\n");
958}976}
...@@ -995,7 +1013,7 @@ fn a() {...@@ -995,7 +1013,7 @@ fn a() {
995 b(1);1013 b(1);
996}1014}
997fn b(a: i32, b: i32, c: i32) { }1015fn b(a: i32, b: i32, c: i32) { }
998 )SOURCE", 1, ".tmp_source.zig:3:6: error: wrong number of arguments. Expected 3, got 1.");1016 )SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, got 1");
9991017
1000 add_compile_fail_case("invalid type", R"SOURCE(1018 add_compile_fail_case("invalid type", R"SOURCE(
1001fn a() -> bogus {}1019fn a() -> bogus {}