authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-08 20:59:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-08 20:59:47-07:00
log14b9cbd43c21ad2ba75b38ef5fc681c044e7662e
tree1ce96ff4900ca3e9c3203f81ef8e884ec3b354ce
parentd14a31100f3f4e7b8d43c8ad794a82da36532aa7

add restrict qualifier on pointer arguments


10 files changed, 128 insertions(+), 57 deletions(-)

doc/langref.md+2-2
......@@ -68,11 +68,11 @@ CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(
6868
6969CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)
7070
71PointerType : token(Ampersand) option(token(Const)) Type
71PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type
7272
7373MaybeType : token(Question) Type
7474
75ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Type
75ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type
7676
7777Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
7878
doc/vim/syntax/zig.vim+1-1
......@@ -8,7 +8,7 @@ if exists("b:current_syntax")
88endif
99
1010syn keyword zigOperator as
11syn keyword zigStorage const var extern volatile export pub
11syn keyword zigStorage const var extern volatile export pub restrict
1212syn keyword zigStructure struct enum type
1313syn keyword zigStatement goto break return continue asm
1414syn keyword zigConditional if else match
src/analyze.cpp+63-35
......@@ -135,10 +135,8 @@ static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x)
135135 return g->num_lit_types[get_number_literal_kind_unsigned(x)];
136136}
137137
138TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
139 TypeTableEntry **parent_pointer = is_const ?
140 &child_type->pointer_const_parent :
141 &child_type->pointer_mut_parent;
138TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict) {
139 TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)];
142140 if (*parent_pointer) {
143141 return *parent_pointer;
144142 } else {
......@@ -153,6 +151,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
153151 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
154152 entry->data.pointer.child_type = child_type;
155153 entry->data.pointer.is_const = is_const;
154 entry->data.pointer.is_restrict = is_restrict;
156155
157156 *parent_pointer = entry;
158157 return entry;
......@@ -241,11 +240,9 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import,
241240}
242241
243242static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import,
244 TypeTableEntry *child_type, bool is_const)
243 TypeTableEntry *child_type, bool is_const, bool is_restrict)
245244{
246 TypeTableEntry **parent_pointer = is_const ?
247 &child_type->unknown_size_array_const_parent :
248 &child_type->unknown_size_array_mut_parent;
245 TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)];
249246 if (*parent_pointer) {
250247 return *parent_pointer;
251248 } else {
......@@ -255,7 +252,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry
255252 buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
256253 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
257254
258 TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
255 TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const, is_restrict);
259256
260257 unsigned element_count = 2;
261258 LLVMTypeRef element_types[] = {
......@@ -430,7 +427,9 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
430427 }
431428}
432429
433static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, BlockContext *context) {
430static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import,
431 BlockContext *context, bool restrict_allowed)
432{
434433 assert(node->type == NodeTypeType);
435434 alloc_codegen_node(node);
436435 TypeNode *type_node = &node->codegen_node->data.type_node;
......@@ -450,21 +449,47 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
450449 }
451450 case AstNodeTypeTypePointer:
452451 {
453 resolve_type(g, node->data.type.child_type, import, context);
452 bool use_restrict = false;
453 if (node->data.type.is_restrict) {
454 if (!restrict_allowed) {
455 add_node_error(g, node,
456 buf_create_from_str("invalid restrict qualifier"));
457 } else {
458 use_restrict = true;
459 }
460 }
461
462 resolve_type(g, node->data.type.child_type, import, context, false);
454463 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
455464 assert(child_type);
456465 if (child_type->id == TypeTableEntryIdUnreachable) {
457466 add_node_error(g, node,
458467 buf_create_from_str("pointer to unreachable not allowed"));
468 type_node->entry = g->builtin_types.entry_invalid;
469 return type_node->entry;
459470 } else if (child_type->id == TypeTableEntryIdInvalid) {
471 type_node->entry = child_type;
460472 return child_type;
473 } else {
474 type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_restrict);
475 return type_node->entry;
461476 }
462 type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const);
463 return type_node->entry;
464477 }
465478 case AstNodeTypeTypeArray:
466479 {
467 TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context);
480 AstNode *size_node = node->data.type.array_size;
481
482 bool use_restrict = false;
483 if (node->data.type.is_restrict) {
484 if (!restrict_allowed || size_node) {
485 add_node_error(g, node,
486 buf_create_from_str("invalid restrict qualifier"));
487 } else {
488 use_restrict = true;
489 }
490 }
491
492 TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context, false);
468493 if (child_type->id == TypeTableEntryIdUnreachable) {
469494 add_node_error(g, node,
470495 buf_create_from_str("array of unreachable not allowed"));
......@@ -472,8 +497,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
472497 return type_node->entry;
473498 }
474499
475 AstNode *size_node = node->data.type.array_size;
476
477500 if (size_node) {
478501 TypeTableEntry *size_type = analyze_expression(g, import, context,
479502 g->builtin_types.entry_usize, size_node);
......@@ -501,14 +524,14 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
501524 return type_node->entry;
502525 } else {
503526 type_node->entry = get_unknown_size_array_type(g, import, child_type,
504 node->data.type.is_const);
527 node->data.type.is_const, use_restrict);
505528 return type_node->entry;
506529 }
507530
508531 }
509532 case AstNodeTypeTypeMaybe:
510533 {
511 resolve_type(g, node->data.type.child_type, import, context);
534 resolve_type(g, node->data.type.child_type, import, context, false);
512535 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
513536 assert(child_type);
514537 if (child_type->id == TypeTableEntryIdUnreachable) {
......@@ -571,7 +594,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
571594 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
572595 AstNode *child = node->data.fn_proto.params.at(i);
573596 assert(child->type == NodeTypeParamDecl);
574 TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, import, import->block_context);
597 TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type,
598 import, import->block_context, true);
575599 if (type_entry->id == TypeTableEntryIdUnreachable) {
576600 add_node_error(g, child->data.param_decl.type,
577601 buf_sprintf("parameter of type 'unreachable' not allowed"));
......@@ -583,7 +607,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
583607 }
584608 }
585609
586 resolve_type(g, node->data.fn_proto.return_type, import, import->block_context);
610 resolve_type(g, node->data.fn_proto.return_type, import, import->block_context, true);
587611}
588612
589613static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
......@@ -644,7 +668,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
644668 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
645669 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
646670 type_struct_field->name = &field_node->data.struct_field.name;
647 type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, import, import->block_context);
671 type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type,
672 import, import->block_context, false);
648673
649674 if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {
650675 resolve_struct_type(g, import, type_struct_field->type_entry);
......@@ -1196,15 +1221,18 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
11961221 return expected_type;
11971222 }
11981223
1199 // implicit non-const to const
1224 // implicit non-const to const and ignore restrict
12001225 if (expected_type->id == TypeTableEntryIdPointer &&
12011226 actual_type->id == TypeTableEntryIdPointer &&
1202 expected_type->data.pointer.is_const &&
1203 !actual_type->data.pointer.is_const)
1227 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const))
12041228 {
1205 return resolve_type_compatibility(g, context, node,
1229 TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
12061230 expected_type->data.pointer.child_type,
12071231 actual_type->data.pointer.child_type);
1232 if (resolved_type->id == TypeTableEntryIdInvalid) {
1233 return resolved_type;
1234 }
1235 return expected_type;
12081236 }
12091237
12101238 add_node_error(g, first_executing_node(node),
......@@ -1335,7 +1363,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
13351363 return_type = g->builtin_types.entry_usize;
13361364 } else if (buf_eql_str(name, "ptr")) {
13371365 // TODO determine whether the pointer should be const
1338 return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false);
1366 return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false, false);
13391367 } else {
13401368 add_node_error(g, node,
13411369 buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
......@@ -1365,16 +1393,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
13651393 return_type = g->builtin_types.entry_invalid;
13661394 } else if (array_type->id == TypeTableEntryIdArray) {
13671395 return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type,
1368 node->data.slice_expr.is_const);
1396 node->data.slice_expr.is_const, false);
13691397 } else if (array_type->id == TypeTableEntryIdPointer) {
13701398 return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type,
1371 node->data.slice_expr.is_const);
1399 node->data.slice_expr.is_const, false);
13721400 } else if (array_type->id == TypeTableEntryIdStruct &&
13731401 array_type->data.structure.is_unknown_size_array)
13741402 {
13751403 return_type = get_unknown_size_array_type(g, import,
13761404 array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
1377 node->data.slice_expr.is_const);
1405 node->data.slice_expr.is_const, false);
13781406 } else {
13791407 add_node_error(g, node,
13801408 buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
......@@ -1490,7 +1518,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
14901518static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
14911519 TypeTableEntry *expected_type, AstNode *node)
14921520{
1493 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context);
1521 TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false);
14941522 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
14951523
14961524 if (wanted_type->id == TypeTableEntryIdInvalid ||
......@@ -1713,7 +1741,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
17131741{
17141742 TypeTableEntry *explicit_type = nullptr;
17151743 if (variable_declaration->type != nullptr) {
1716 explicit_type = resolve_type(g, variable_declaration->type, import, context);
1744 explicit_type = resolve_type(g, variable_declaration->type, import, context, false);
17171745 if (explicit_type->id == TypeTableEntryIdUnreachable) {
17181746 add_node_error(g, variable_declaration->type,
17191747 buf_sprintf("variable of type 'unreachable' not allowed"));
......@@ -1837,7 +1865,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp
18371865
18381866 AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;
18391867
1840 TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context);
1868 TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context, false);
18411869
18421870 if (type_entry->id == TypeTableEntryIdInvalid) {
18431871 return g->builtin_types.entry_invalid;
......@@ -2017,7 +2045,7 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im
20172045 assert(node->type == NodeTypeCompilerFnType);
20182046
20192047 Buf *name = &node->data.compiler_fn_type.name;
2020 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context);
2048 TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false);
20212049
20222050 if (buf_eql_str(name, "sizeof")) {
20232051 uint64_t size_in_bytes = type_entry->size_in_bits / 8;
......@@ -2221,7 +2249,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
22212249 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
22222250 if (asm_output->return_type) {
22232251 node->data.asm_expr.return_count += 1;
2224 return_type = resolve_type(g, asm_output->return_type, import, context);
2252 return_type = resolve_type(g, asm_output->return_type, import, context, false);
22252253 if (node->data.asm_expr.return_count > 1) {
22262254 add_node_error(g, node,
22272255 buf_sprintf("inline assembly allows up to one output value"));
......@@ -2357,7 +2385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
23572385 break;
23582386 }
23592387
2360 return_type = get_pointer_to_type(g, child_type, is_const);
2388 return_type = get_pointer_to_type(g, child_type, is_const, false);
23612389 break;
23622390 }
23632391 case PrefixOpDereference:
src/analyze.hpp+4-5
......@@ -23,6 +23,7 @@ struct StructValExprNode;
2323struct TypeTableEntryPointer {
2424 TypeTableEntry *child_type;
2525 bool is_const;
26 bool is_restrict;
2627};
2728
2829struct TypeTableEntryInt {
......@@ -97,12 +98,10 @@ struct TypeTableEntry {
9798 } data;
9899
99100 // use these fields to make sure we don't duplicate type table entries for the same type
100 TypeTableEntry *pointer_const_parent;
101 TypeTableEntry *pointer_mut_parent;
101 TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - restrict
102 TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - restrict
102103 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
103104 TypeTableEntry *maybe_parent;
104 TypeTableEntry *unknown_size_array_const_parent;
105 TypeTableEntry *unknown_size_array_mut_parent;
106105
107106};
108107
......@@ -379,7 +378,7 @@ void semantic_analyze(CodeGen *g);
379378void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
380379void alloc_codegen_node(AstNode *node);
381380TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
382TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
381TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict);
383382VariableTableEntry *find_variable(BlockContext *context, Buf *name);
384383BlockContext *new_block_context(AstNode *node, BlockContext *parent);
385384
src/codegen.cpp+27-5
......@@ -77,13 +77,13 @@ static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
7777 return type_node->codegen_node->data.type_node.entry;
7878}
7979
80static LLVMTypeRef fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
80static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
8181 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
8282
8383 if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
84 return get_pointer_to_type(g, type_entry, true)->type_ref;
84 return get_pointer_to_type(g, type_entry, true, true);
8585 } else {
86 return type_entry->type_ref;
86 return type_entry;
8787 }
8888}
8989
......@@ -1763,7 +1763,7 @@ static void do_code_gen(CodeGen *g) {
17631763 if (is_param_decl_type_void(g, param_node))
17641764 continue;
17651765 AstNode *type_node = param_node->data.param_decl.type;
1766 param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node);
1766 param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node)->type_ref;
17671767 gen_param_index += 1;
17681768 }
17691769 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);
......@@ -1785,6 +1785,28 @@ static void do_code_gen(CodeGen *g) {
17851785 LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute);
17861786 }
17871787
1788 // set parameter attributes
1789 gen_param_index = 0;
1790 for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) {
1791 AstNode *param_node = fn_proto->params.at(param_decl_i);
1792 assert(param_node->type == NodeTypeParamDecl);
1793 if (is_param_decl_type_void(g, param_node))
1794 continue;
1795 AstNode *type_node = param_node->data.param_decl.type;
1796 TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
1797 LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index);
1798 if (param_type->id == TypeTableEntryIdPointer &&
1799 param_type->data.pointer.is_restrict)
1800 {
1801 LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
1802 } else if (param_type->id == TypeTableEntryIdPointer &&
1803 param_type->data.pointer.is_const)
1804 {
1805 LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
1806 }
1807 gen_param_index += 1;
1808 }
1809
17881810 fn_table_entry->fn_value = fn;
17891811 }
17901812
......@@ -2032,7 +2054,7 @@ static void define_builtin_types(CodeGen *g) {
20322054 LLVMZigEncoding_DW_ATE_unsigned());
20332055 g->builtin_types.entry_u64 = entry;
20342056 }
2035 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
2057 g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false);
20362058 {
20372059 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
20382060 entry->type_ref = LLVMInt8Type();
src/parser.cpp+25-7
......@@ -224,16 +224,18 @@ void ast_print(AstNode *node, int indent) {
224224 }
225225 case AstNodeTypeTypePointer:
226226 {
227 const char *const_or_mut_str = node->data.type.is_const ? "const" : "var";
228 fprintf(stderr, "'%s' PointerType\n", const_or_mut_str);
227 const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
228 const char *restrict_or_not_str = node->data.type.is_restrict ? "restrict " : "";
229 fprintf(stderr, "%s%s PointerType\n", const_or_mut_str, restrict_or_not_str);
229230
230231 ast_print(node->data.type.child_type, indent + 2);
231232 break;
232233 }
233234 case AstNodeTypeTypeArray:
234235 {
235 const char *const_or_mut_str = node->data.type.is_const ? "const" : "var";
236 fprintf(stderr, "'%s' ArrayType\n", const_or_mut_str);
236 const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
237 const char *restrict_or_not_str = node->data.type.is_restrict ? "restrict " : "";
238 fprintf(stderr, "%s%s ArrayType\n", const_or_mut_str, restrict_or_not_str);
237239 if (node->data.type.array_size)
238240 ast_print(node->data.type.array_size, indent + 2);
239241 ast_print(node->data.type.child_type, indent + 2);
......@@ -1022,6 +1024,13 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod
10221024 node->data.type.is_const = true;
10231025 *token_index += 1;
10241026 first_type_token = &pc->tokens->at(*token_index);
1027 if (first_type_token->id == TokenIdKeywordRestrict) {
1028 node->data.type.is_restrict = true;
1029 *token_index += 1;
1030 }
1031 } else if (first_type_token->id == TokenIdKeywordRestrict) {
1032 node->data.type.is_restrict = true;
1033 *token_index += 1;
10251034 }
10261035
10271036 node->data.type.child_type = ast_parse_type(pc, token_index);
......@@ -1079,8 +1088,8 @@ static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, b
10791088
10801089/*
10811090Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
1082PointerType : token(Ampersand) option(token(Const)) Type
1083ArrayType : token(LBracket) option(Expression) token(RBracket) Type
1091PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type
1092ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type
10841093*/
10851094static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
10861095 Token *token = &pc->tokens->at(*token_index);
......@@ -1129,6 +1138,15 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
11291138 if (const_tok->id == TokenIdKeywordConst) {
11301139 *token_index += 1;
11311140 node->data.type.is_const = true;
1141
1142 Token *next_tok = &pc->tokens->at(*token_index);
1143 if (next_tok->id == TokenIdKeywordRestrict) {
1144 *token_index += 1;
1145 node->data.type.is_restrict = true;
1146 }
1147 } else if (const_tok->id == TokenIdKeywordRestrict) {
1148 *token_index += 1;
1149 node->data.type.is_restrict = true;
11321150 }
11331151
11341152 node->data.type.child_type = ast_parse_type(pc, token_index);
......@@ -1476,7 +1494,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
14761494}
14771495
14781496/*
1479PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
1497PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
14801498*/
14811499static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {
14821500 Token *token = &pc->tokens->at(*token_index);
src/parser.hpp+1
......@@ -110,6 +110,7 @@ struct AstNodeType {
110110 AstNode *child_type;
111111 AstNode *array_size; // can be null
112112 bool is_const;
113 bool is_restrict;
113114 AstNode *compiler_expr;
114115};
115116
src/tokenizer.cpp+3
......@@ -243,6 +243,8 @@ static void end_token(Tokenize *t) {
243243 t->cur_tok->id = TokenIdKeywordBreak;
244244 } else if (mem_eql_str(token_mem, token_len, "null")) {
245245 t->cur_tok->id = TokenIdKeywordNull;
246 } else if (mem_eql_str(token_mem, token_len, "restrict")) {
247 t->cur_tok->id = TokenIdKeywordRestrict;
246248 }
247249
248250 t->cur_tok = nullptr;
......@@ -1019,6 +1021,7 @@ static const char * token_name(Token *token) {
10191021 case TokenIdKeywordContinue: return "Continue";
10201022 case TokenIdKeywordBreak: return "Break";
10211023 case TokenIdKeywordNull: return "Null";
1024 case TokenIdKeywordRestrict: return "Restrict";
10221025 case TokenIdLParen: return "LParen";
10231026 case TokenIdRParen: return "RParen";
10241027 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
......@@ -36,6 +36,7 @@ enum TokenId {
3636 TokenIdKeywordContinue,
3737 TokenIdKeywordBreak,
3838 TokenIdKeywordNull,
39 TokenIdKeywordRestrict,
3940 TokenIdLParen,
4041 TokenIdRParen,
4142 TokenIdComma,
std/builtin.zig+1-2
......@@ -10,8 +10,7 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
1010 return dest;
1111}
1212
13// TODO annotate parameters with noalias
14export fn memcpy(dest: &u8, src: &const u8, n: usize) -> &u8 {
13export fn memcpy(dest: &restrict u8, src: &const restrict u8, n: usize) -> &u8 {
1514 var index : #typeof(n) = 0;
1615 while (index != n) {
1716 dest[index] = src[index];