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(...@@ -68,11 +68,11 @@ CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(
6868
69CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)69CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)
7070
71PointerType : token(Ampersand) option(token(Const)) Type71PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type
7272
73MaybeType : token(Question) Type73MaybeType : token(Question) Type
7474
75ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Type75ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type
7676
77Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)77Block : 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")...@@ -8,7 +8,7 @@ if exists("b:current_syntax")
8endif8endif
99
10syn keyword zigOperator as10syn keyword zigOperator as
11syn keyword zigStorage const var extern volatile export pub11syn keyword zigStorage const var extern volatile export pub restrict
12syn keyword zigStructure struct enum type12syn keyword zigStructure struct enum type
13syn keyword zigStatement goto break return continue asm13syn keyword zigStatement goto break return continue asm
14syn keyword zigConditional if else match14syn 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)...@@ -135,10 +135,8 @@ static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x)
135 return g->num_lit_types[get_number_literal_kind_unsigned(x)];135 return g->num_lit_types[get_number_literal_kind_unsigned(x)];
136}136}
137137
138TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {138TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict) {
139 TypeTableEntry **parent_pointer = is_const ?139 TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)];
140 &child_type->pointer_const_parent :
141 &child_type->pointer_mut_parent;
142 if (*parent_pointer) {140 if (*parent_pointer) {
143 return *parent_pointer;141 return *parent_pointer;
144 } else {142 } else {
...@@ -153,6 +151,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool...@@ -153,6 +151,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
153 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));151 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
154 entry->data.pointer.child_type = child_type;152 entry->data.pointer.child_type = child_type;
155 entry->data.pointer.is_const = is_const;153 entry->data.pointer.is_const = is_const;
154 entry->data.pointer.is_restrict = is_restrict;
156155
157 *parent_pointer = entry;156 *parent_pointer = entry;
158 return entry;157 return entry;
...@@ -241,11 +240,9 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import,...@@ -241,11 +240,9 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import,
241}240}
242241
243static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import,242static 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)
245{244{
246 TypeTableEntry **parent_pointer = is_const ?245 TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)];
247 &child_type->unknown_size_array_const_parent :
248 &child_type->unknown_size_array_mut_parent;
249 if (*parent_pointer) {246 if (*parent_pointer) {
250 return *parent_pointer;247 return *parent_pointer;
251 } else {248 } else {
...@@ -255,7 +252,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry...@@ -255,7 +252,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry
255 buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));252 buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
256 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));253 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
260 unsigned element_count = 2;257 unsigned element_count = 2;
261 LLVMTypeRef element_types[] = {258 LLVMTypeRef element_types[] = {
...@@ -430,7 +427,9 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,...@@ -430,7 +427,9 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
430 }427 }
431}428}
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{
434 assert(node->type == NodeTypeType);433 assert(node->type == NodeTypeType);
435 alloc_codegen_node(node);434 alloc_codegen_node(node);
436 TypeNode *type_node = &node->codegen_node->data.type_node;435 TypeNode *type_node = &node->codegen_node->data.type_node;
...@@ -450,21 +449,47 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry...@@ -450,21 +449,47 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
450 }449 }
451 case AstNodeTypeTypePointer:450 case AstNodeTypeTypePointer:
452 {451 {
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);
454 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;463 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
455 assert(child_type);464 assert(child_type);
456 if (child_type->id == TypeTableEntryIdUnreachable) {465 if (child_type->id == TypeTableEntryIdUnreachable) {
457 add_node_error(g, node,466 add_node_error(g, node,
458 buf_create_from_str("pointer to unreachable not allowed"));467 buf_create_from_str("pointer to unreachable not allowed"));
468 type_node->entry = g->builtin_types.entry_invalid;
469 return type_node->entry;
459 } else if (child_type->id == TypeTableEntryIdInvalid) {470 } else if (child_type->id == TypeTableEntryIdInvalid) {
471 type_node->entry = child_type;
460 return child_type;472 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;
461 }476 }
462 type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const);
463 return type_node->entry;
464 }477 }
465 case AstNodeTypeTypeArray:478 case AstNodeTypeTypeArray:
466 {479 {
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);
468 if (child_type->id == TypeTableEntryIdUnreachable) {493 if (child_type->id == TypeTableEntryIdUnreachable) {
469 add_node_error(g, node,494 add_node_error(g, node,
470 buf_create_from_str("array of unreachable not allowed"));495 buf_create_from_str("array of unreachable not allowed"));
...@@ -472,8 +497,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry...@@ -472,8 +497,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
472 return type_node->entry;497 return type_node->entry;
473 }498 }
474499
475 AstNode *size_node = node->data.type.array_size;
476
477 if (size_node) {500 if (size_node) {
478 TypeTableEntry *size_type = analyze_expression(g, import, context,501 TypeTableEntry *size_type = analyze_expression(g, import, context,
479 g->builtin_types.entry_usize, size_node);502 g->builtin_types.entry_usize, size_node);
...@@ -501,14 +524,14 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry...@@ -501,14 +524,14 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
501 return type_node->entry;524 return type_node->entry;
502 } else {525 } else {
503 type_node->entry = get_unknown_size_array_type(g, import, child_type,526 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);
505 return type_node->entry;528 return type_node->entry;
506 }529 }
507530
508 }531 }
509 case AstNodeTypeTypeMaybe:532 case AstNodeTypeTypeMaybe:
510 {533 {
511 resolve_type(g, node->data.type.child_type, import, context);534 resolve_type(g, node->data.type.child_type, import, context, false);
512 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;535 TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
513 assert(child_type);536 assert(child_type);
514 if (child_type->id == TypeTableEntryIdUnreachable) {537 if (child_type->id == TypeTableEntryIdUnreachable) {
...@@ -571,7 +594,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -571,7 +594,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
571 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {594 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
572 AstNode *child = node->data.fn_proto.params.at(i);595 AstNode *child = node->data.fn_proto.params.at(i);
573 assert(child->type == NodeTypeParamDecl);596 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);
575 if (type_entry->id == TypeTableEntryIdUnreachable) {599 if (type_entry->id == TypeTableEntryIdUnreachable) {
576 add_node_error(g, child->data.param_decl.type,600 add_node_error(g, child->data.param_decl.type,
577 buf_sprintf("parameter of type 'unreachable' not allowed"));601 buf_sprintf("parameter of type 'unreachable' not allowed"));
...@@ -583,7 +607,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -583,7 +607,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
583 }607 }
584 }608 }
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);
587}611}
588612
589static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {613static 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...@@ -644,7 +668,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
644 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);668 AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
645 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];669 TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
646 type_struct_field->name = &field_node->data.struct_field.name;670 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
649 if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {674 if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {
650 resolve_struct_type(g, import, type_struct_field->type_entry);675 resolve_struct_type(g, import, type_struct_field->type_entry);
...@@ -1196,15 +1221,18 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont...@@ -1196,15 +1221,18 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
1196 return expected_type;1221 return expected_type;
1197 }1222 }
11981223
1199 // implicit non-const to const1224 // implicit non-const to const and ignore restrict
1200 if (expected_type->id == TypeTableEntryIdPointer &&1225 if (expected_type->id == TypeTableEntryIdPointer &&
1201 actual_type->id == TypeTableEntryIdPointer &&1226 actual_type->id == TypeTableEntryIdPointer &&
1202 expected_type->data.pointer.is_const &&1227 (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const))
1203 !actual_type->data.pointer.is_const)
1204 {1228 {
1205 return resolve_type_compatibility(g, context, node,1229 TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
1206 expected_type->data.pointer.child_type,1230 expected_type->data.pointer.child_type,
1207 actual_type->data.pointer.child_type);1231 actual_type->data.pointer.child_type);
1232 if (resolved_type->id == TypeTableEntryIdInvalid) {
1233 return resolved_type;
1234 }
1235 return expected_type;
1208 }1236 }
12091237
1210 add_node_error(g, first_executing_node(node),1238 add_node_error(g, first_executing_node(node),
...@@ -1335,7 +1363,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -1335,7 +1363,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
1335 return_type = g->builtin_types.entry_usize;1363 return_type = g->builtin_types.entry_usize;
1336 } else if (buf_eql_str(name, "ptr")) {1364 } else if (buf_eql_str(name, "ptr")) {
1337 // TODO determine whether the pointer should be const1365 // 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);
1339 } else {1367 } else {
1340 add_node_error(g, node,1368 add_node_error(g, node,
1341 buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),1369 buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
...@@ -1365,16 +1393,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,...@@ -1365,16 +1393,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
1365 return_type = g->builtin_types.entry_invalid;1393 return_type = g->builtin_types.entry_invalid;
1366 } else if (array_type->id == TypeTableEntryIdArray) {1394 } else if (array_type->id == TypeTableEntryIdArray) {
1367 return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type,1395 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);
1369 } else if (array_type->id == TypeTableEntryIdPointer) {1397 } else if (array_type->id == TypeTableEntryIdPointer) {
1370 return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type,1398 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);
1372 } else if (array_type->id == TypeTableEntryIdStruct &&1400 } else if (array_type->id == TypeTableEntryIdStruct &&
1373 array_type->data.structure.is_unknown_size_array)1401 array_type->data.structure.is_unknown_size_array)
1374 {1402 {
1375 return_type = get_unknown_size_array_type(g, import,1403 return_type = get_unknown_size_array_type(g, import,
1376 array_type->data.structure.fields[0].type_entry->data.pointer.child_type,1404 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);
1378 } else {1406 } else {
1379 add_node_error(g, node,1407 add_node_error(g, node,
1380 buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));1408 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) {...@@ -1490,7 +1518,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
1490static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,1518static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1491 TypeTableEntry *expected_type, AstNode *node)1519 TypeTableEntry *expected_type, AstNode *node)
1492{1520{
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);
1494 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);1522 TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
14951523
1496 if (wanted_type->id == TypeTableEntryIdInvalid ||1524 if (wanted_type->id == TypeTableEntryIdInvalid ||
...@@ -1713,7 +1741,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa...@@ -1713,7 +1741,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
1713{1741{
1714 TypeTableEntry *explicit_type = nullptr;1742 TypeTableEntry *explicit_type = nullptr;
1715 if (variable_declaration->type != nullptr) {1743 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);
1717 if (explicit_type->id == TypeTableEntryIdUnreachable) {1745 if (explicit_type->id == TypeTableEntryIdUnreachable) {
1718 add_node_error(g, variable_declaration->type,1746 add_node_error(g, variable_declaration->type,
1719 buf_sprintf("variable of type 'unreachable' not allowed"));1747 buf_sprintf("variable of type 'unreachable' not allowed"));
...@@ -1837,7 +1865,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp...@@ -1837,7 +1865,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp
18371865
1838 AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;1866 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
1842 if (type_entry->id == TypeTableEntryIdInvalid) {1870 if (type_entry->id == TypeTableEntryIdInvalid) {
1843 return g->builtin_types.entry_invalid;1871 return g->builtin_types.entry_invalid;
...@@ -2017,7 +2045,7 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im...@@ -2017,7 +2045,7 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im
2017 assert(node->type == NodeTypeCompilerFnType);2045 assert(node->type == NodeTypeCompilerFnType);
20182046
2019 Buf *name = &node->data.compiler_fn_type.name;2047 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
2022 if (buf_eql_str(name, "sizeof")) {2050 if (buf_eql_str(name, "sizeof")) {
2023 uint64_t size_in_bytes = type_entry->size_in_bits / 8;2051 uint64_t size_in_bytes = type_entry->size_in_bits / 8;
...@@ -2221,7 +2249,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -2221,7 +2249,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
2221 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);2249 AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
2222 if (asm_output->return_type) {2250 if (asm_output->return_type) {
2223 node->data.asm_expr.return_count += 1;2251 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);
2225 if (node->data.asm_expr.return_count > 1) {2253 if (node->data.asm_expr.return_count > 1) {
2226 add_node_error(g, node,2254 add_node_error(g, node,
2227 buf_sprintf("inline assembly allows up to one output value"));2255 buf_sprintf("inline assembly allows up to one output value"));
...@@ -2357,7 +2385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -2357,7 +2385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
2357 break;2385 break;
2358 }2386 }
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);
2361 break;2389 break;
2362 }2390 }
2363 case PrefixOpDereference:2391 case PrefixOpDereference:
src/analyze.hpp+4-5
...@@ -23,6 +23,7 @@ struct StructValExprNode;...@@ -23,6 +23,7 @@ struct StructValExprNode;
23struct TypeTableEntryPointer {23struct TypeTableEntryPointer {
24 TypeTableEntry *child_type;24 TypeTableEntry *child_type;
25 bool is_const;25 bool is_const;
26 bool is_restrict;
26};27};
2728
28struct TypeTableEntryInt {29struct TypeTableEntryInt {
...@@ -97,12 +98,10 @@ struct TypeTableEntry {...@@ -97,12 +98,10 @@ struct TypeTableEntry {
97 } data;98 } data;
9899
99 // use these fields to make sure we don't duplicate type table entries for the same type100 // 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_parent[2][2]; // 0 - const. 1 - restrict
101 TypeTableEntry *pointer_mut_parent;102 TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - restrict
102 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;103 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
103 TypeTableEntry *maybe_parent;104 TypeTableEntry *maybe_parent;
104 TypeTableEntry *unknown_size_array_const_parent;
105 TypeTableEntry *unknown_size_array_mut_parent;
106105
107};106};
108107
...@@ -379,7 +378,7 @@ void semantic_analyze(CodeGen *g);...@@ -379,7 +378,7 @@ void semantic_analyze(CodeGen *g);
379void add_node_error(CodeGen *g, AstNode *node, Buf *msg);378void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
380void alloc_codegen_node(AstNode *node);379void alloc_codegen_node(AstNode *node);
381TypeTableEntry *new_type_table_entry(TypeTableEntryId id);380TypeTableEntry *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);
383VariableTableEntry *find_variable(BlockContext *context, Buf *name);382VariableTableEntry *find_variable(BlockContext *context, Buf *name);
384BlockContext *new_block_context(AstNode *node, BlockContext *parent);383BlockContext *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) {...@@ -77,13 +77,13 @@ static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
77 return type_node->codegen_node->data.type_node.entry;77 return type_node->codegen_node->data.type_node.entry;
78}78}
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) {
81 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);81 TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
8282
83 if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {83 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);
85 } else {85 } else {
86 return type_entry->type_ref;86 return type_entry;
87 }87 }
88}88}
8989
...@@ -1763,7 +1763,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1763,7 +1763,7 @@ static void do_code_gen(CodeGen *g) {
1763 if (is_param_decl_type_void(g, param_node))1763 if (is_param_decl_type_void(g, param_node))
1764 continue;1764 continue;
1765 AstNode *type_node = param_node->data.param_decl.type;1765 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;
1767 gen_param_index += 1;1767 gen_param_index += 1;
1768 }1768 }
1769 LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args);1769 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) {...@@ -1785,6 +1785,28 @@ static void do_code_gen(CodeGen *g) {
1785 LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute);1785 LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute);
1786 }1786 }
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
1788 fn_table_entry->fn_value = fn;1810 fn_table_entry->fn_value = fn;
1789 }1811 }
17901812
...@@ -2032,7 +2054,7 @@ static void define_builtin_types(CodeGen *g) {...@@ -2032,7 +2054,7 @@ static void define_builtin_types(CodeGen *g) {
2032 LLVMZigEncoding_DW_ATE_unsigned());2054 LLVMZigEncoding_DW_ATE_unsigned());
2033 g->builtin_types.entry_u64 = entry;2055 g->builtin_types.entry_u64 = entry;
2034 }2056 }
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);
2036 {2058 {
2037 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);2059 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
2038 entry->type_ref = LLVMInt8Type();2060 entry->type_ref = LLVMInt8Type();
src/parser.cpp+25-7
...@@ -224,16 +224,18 @@ void ast_print(AstNode *node, int indent) {...@@ -224,16 +224,18 @@ void ast_print(AstNode *node, int indent) {
224 }224 }
225 case AstNodeTypeTypePointer:225 case AstNodeTypeTypePointer:
226 {226 {
227 const char *const_or_mut_str = node->data.type.is_const ? "const" : "var";227 const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
228 fprintf(stderr, "'%s' PointerType\n", const_or_mut_str);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
230 ast_print(node->data.type.child_type, indent + 2);231 ast_print(node->data.type.child_type, indent + 2);
231 break;232 break;
232 }233 }
233 case AstNodeTypeTypeArray:234 case AstNodeTypeTypeArray:
234 {235 {
235 const char *const_or_mut_str = node->data.type.is_const ? "const" : "var";236 const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
236 fprintf(stderr, "'%s' ArrayType\n", const_or_mut_str);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);
237 if (node->data.type.array_size)239 if (node->data.type.array_size)
238 ast_print(node->data.type.array_size, indent + 2);240 ast_print(node->data.type.array_size, indent + 2);
239 ast_print(node->data.type.child_type, indent + 2);241 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...@@ -1022,6 +1024,13 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod
1022 node->data.type.is_const = true;1024 node->data.type.is_const = true;
1023 *token_index += 1;1025 *token_index += 1;
1024 first_type_token = &pc->tokens->at(*token_index);1026 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;
1025 }1034 }
10261035
1027 node->data.type.child_type = ast_parse_type(pc, token_index);1036 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...@@ -1079,8 +1088,8 @@ static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, b
10791088
1080/*1089/*
1081Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr1090Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
1082PointerType : token(Ampersand) option(token(Const)) Type1091PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type
1083ArrayType : token(LBracket) option(Expression) token(RBracket) Type1092ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type
1084*/1093*/
1085static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {1094static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
1086 Token *token = &pc->tokens->at(*token_index);1095 Token *token = &pc->tokens->at(*token_index);
...@@ -1129,6 +1138,15 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {...@@ -1129,6 +1138,15 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
1129 if (const_tok->id == TokenIdKeywordConst) {1138 if (const_tok->id == TokenIdKeywordConst) {
1130 *token_index += 1;1139 *token_index += 1;
1131 node->data.type.is_const = true;1140 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;
1132 }1150 }
11331151
1134 node->data.type.child_type = ast_parse_type(pc, token_index);1152 node->data.type.child_type = ast_parse_type(pc, token_index);
...@@ -1476,7 +1494,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {...@@ -1476,7 +1494,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
1476}1494}
14771495
1478/*1496/*
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)))
1480*/1498*/
1481static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {1499static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {
1482 Token *token = &pc->tokens->at(*token_index);1500 Token *token = &pc->tokens->at(*token_index);
src/parser.hpp+1
...@@ -110,6 +110,7 @@ struct AstNodeType {...@@ -110,6 +110,7 @@ struct AstNodeType {
110 AstNode *child_type;110 AstNode *child_type;
111 AstNode *array_size; // can be null111 AstNode *array_size; // can be null
112 bool is_const;112 bool is_const;
113 bool is_restrict;
113 AstNode *compiler_expr;114 AstNode *compiler_expr;
114};115};
115116
src/tokenizer.cpp+3
...@@ -243,6 +243,8 @@ static void end_token(Tokenize *t) {...@@ -243,6 +243,8 @@ static void end_token(Tokenize *t) {
243 t->cur_tok->id = TokenIdKeywordBreak;243 t->cur_tok->id = TokenIdKeywordBreak;
244 } else if (mem_eql_str(token_mem, token_len, "null")) {244 } else if (mem_eql_str(token_mem, token_len, "null")) {
245 t->cur_tok->id = TokenIdKeywordNull;245 t->cur_tok->id = TokenIdKeywordNull;
246 } else if (mem_eql_str(token_mem, token_len, "restrict")) {
247 t->cur_tok->id = TokenIdKeywordRestrict;
246 }248 }
247249
248 t->cur_tok = nullptr;250 t->cur_tok = nullptr;
...@@ -1019,6 +1021,7 @@ static const char * token_name(Token *token) {...@@ -1019,6 +1021,7 @@ static const char * token_name(Token *token) {
1019 case TokenIdKeywordContinue: return "Continue";1021 case TokenIdKeywordContinue: return "Continue";
1020 case TokenIdKeywordBreak: return "Break";1022 case TokenIdKeywordBreak: return "Break";
1021 case TokenIdKeywordNull: return "Null";1023 case TokenIdKeywordNull: return "Null";
1024 case TokenIdKeywordRestrict: return "Restrict";
1022 case TokenIdLParen: return "LParen";1025 case TokenIdLParen: return "LParen";
1023 case TokenIdRParen: return "RParen";1026 case TokenIdRParen: return "RParen";
1024 case TokenIdComma: return "Comma";1027 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
...@@ -36,6 +36,7 @@ enum TokenId {...@@ -36,6 +36,7 @@ enum TokenId {
36 TokenIdKeywordContinue,36 TokenIdKeywordContinue,
37 TokenIdKeywordBreak,37 TokenIdKeywordBreak,
38 TokenIdKeywordNull,38 TokenIdKeywordNull,
39 TokenIdKeywordRestrict,
39 TokenIdLParen,40 TokenIdLParen,
40 TokenIdRParen,41 TokenIdRParen,
41 TokenIdComma,42 TokenIdComma,
std/builtin.zig+1-2
...@@ -10,8 +10,7 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {...@@ -10,8 +10,7 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
10 return dest;10 return dest;
11}11}
1212
13// TODO annotate parameters with noalias13export fn memcpy(dest: &restrict u8, src: &const restrict u8, n: usize) -> &u8 {
14export fn memcpy(dest: &u8, src: &const u8, n: usize) -> &u8 {
15 var index : #typeof(n) = 0;14 var index : #typeof(n) = 0;
16 while (index != n) {15 while (index != n) {
17 dest[index] = src[index];16 dest[index] = src[index];