From 14b9cbd43c21ad2ba75b38ef5fc681c044e7662e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 8 Jan 2016 20:59:47 -0700 Subject: [PATCH] add restrict qualifier on pointer arguments --- doc/langref.md | 4 +- doc/vim/syntax/zig.vim | 2 +- src/analyze.cpp | 108 ++++++++++++++++++++++++++--------------- src/analyze.hpp | 9 ++-- src/codegen.cpp | 32 ++++++++++-- src/parser.cpp | 32 +++++++++--- src/parser.hpp | 1 + src/tokenizer.cpp | 3 ++ src/tokenizer.hpp | 1 + std/builtin.zig | 3 +- 10 files changed, 133 insertions(+), 62 deletions(-) diff --git a/doc/langref.md b/doc/langref.md index 7d8efef42160fee2ff8d2972ae0563beba6f5f60..3930b3f9b2df01960a414487f457825eb8eaa744 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -68,11 +68,11 @@ CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token( CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen) -PointerType : token(Ampersand) option(token(Const)) Type +PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type MaybeType : token(Question) Type -ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Type +ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace) diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index ffb08fc388ace8eabe77551a62f4338227c72a27..c505a7e58c50c30ea44c2714b78601b51c20862c 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -8,7 +8,7 @@ if exists("b:current_syntax") endif syn keyword zigOperator as -syn keyword zigStorage const var extern volatile export pub +syn keyword zigStorage const var extern volatile export pub restrict syn keyword zigStructure struct enum type syn keyword zigStatement goto break return continue asm syn keyword zigConditional if else match diff --git a/src/analyze.cpp b/src/analyze.cpp index 68bfd6c3c74f310c20689fdf1235031f043e5cf3..18afb9eb05eb51cf6bacdb033ec7a3d7269e1b2f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -135,10 +135,8 @@ static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x) return g->num_lit_types[get_number_literal_kind_unsigned(x)]; } -TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { - TypeTableEntry **parent_pointer = is_const ? - &child_type->pointer_const_parent : - &child_type->pointer_mut_parent; +TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict) { + TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)]; if (*parent_pointer) { return *parent_pointer; } else { @@ -153,6 +151,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name)); entry->data.pointer.child_type = child_type; entry->data.pointer.is_const = is_const; + entry->data.pointer.is_restrict = is_restrict; *parent_pointer = entry; return entry; @@ -241,11 +240,9 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import, } static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import, - TypeTableEntry *child_type, bool is_const) + TypeTableEntry *child_type, bool is_const, bool is_restrict) { - TypeTableEntry **parent_pointer = is_const ? - &child_type->unknown_size_array_const_parent : - &child_type->unknown_size_array_mut_parent; + TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)][(is_restrict ? 1 : 0)]; if (*parent_pointer) { return *parent_pointer; } else { @@ -255,7 +252,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name)); entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name)); - TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const); + TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const, is_restrict); unsigned element_count = 2; LLVMTypeRef element_types[] = { @@ -430,7 +427,9 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, } } -static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, BlockContext *context) { +static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, + BlockContext *context, bool restrict_allowed) +{ assert(node->type == NodeTypeType); alloc_codegen_node(node); TypeNode *type_node = &node->codegen_node->data.type_node; @@ -450,30 +449,54 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry } case AstNodeTypeTypePointer: { - resolve_type(g, node->data.type.child_type, import, context); + bool use_restrict = false; + if (node->data.type.is_restrict) { + if (!restrict_allowed) { + add_node_error(g, node, + buf_create_from_str("invalid restrict qualifier")); + } else { + use_restrict = true; + } + } + + resolve_type(g, node->data.type.child_type, import, context, false); TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; assert(child_type); if (child_type->id == TypeTableEntryIdUnreachable) { add_node_error(g, node, buf_create_from_str("pointer to unreachable not allowed")); + type_node->entry = g->builtin_types.entry_invalid; + return type_node->entry; } else if (child_type->id == TypeTableEntryIdInvalid) { + type_node->entry = child_type; return child_type; + } else { + type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_restrict); + return type_node->entry; } - type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); - return type_node->entry; } case AstNodeTypeTypeArray: { - TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context); - if (child_type->id == TypeTableEntryIdUnreachable) { - add_node_error(g, node, - buf_create_from_str("array of unreachable not allowed")); - type_node->entry = g->builtin_types.entry_invalid; - return type_node->entry; - } - AstNode *size_node = node->data.type.array_size; + bool use_restrict = false; + if (node->data.type.is_restrict) { + if (!restrict_allowed || size_node) { + add_node_error(g, node, + buf_create_from_str("invalid restrict qualifier")); + } else { + use_restrict = true; + } + } + + TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context, false); + if (child_type->id == TypeTableEntryIdUnreachable) { + add_node_error(g, node, + buf_create_from_str("array of unreachable not allowed")); + type_node->entry = g->builtin_types.entry_invalid; + return type_node->entry; + } + if (size_node) { TypeTableEntry *size_type = analyze_expression(g, import, context, g->builtin_types.entry_usize, size_node); @@ -501,14 +524,14 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry return type_node->entry; } else { type_node->entry = get_unknown_size_array_type(g, import, child_type, - node->data.type.is_const); + node->data.type.is_const, use_restrict); return type_node->entry; } } case AstNodeTypeTypeMaybe: { - resolve_type(g, node->data.type.child_type, import, context); + resolve_type(g, node->data.type.child_type, import, context, false); TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; assert(child_type); if (child_type->id == TypeTableEntryIdUnreachable) { @@ -571,7 +594,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { AstNode *child = node->data.fn_proto.params.at(i); assert(child->type == NodeTypeParamDecl); - TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, import, import->block_context); + TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, + import, import->block_context, true); if (type_entry->id == TypeTableEntryIdUnreachable) { add_node_error(g, child->data.param_decl.type, buf_sprintf("parameter of type 'unreachable' not allowed")); @@ -583,7 +607,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t } } - resolve_type(g, node->data.fn_proto.return_type, import, import->block_context); + resolve_type(g, node->data.fn_proto.return_type, import, import->block_context, true); } static 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 AstNode *field_node = decl_node->data.struct_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; type_struct_field->name = &field_node->data.struct_field.name; - type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, import, import->block_context); + type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, + import, import->block_context, false); if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) { resolve_struct_type(g, import, type_struct_field->type_entry); @@ -1196,15 +1221,18 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont return expected_type; } - // implicit non-const to const + // implicit non-const to const and ignore restrict if (expected_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer && - expected_type->data.pointer.is_const && - !actual_type->data.pointer.is_const) + (!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const)) { - return resolve_type_compatibility(g, context, node, + TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node, expected_type->data.pointer.child_type, actual_type->data.pointer.child_type); + if (resolved_type->id == TypeTableEntryIdInvalid) { + return resolved_type; + } + return expected_type; } add_node_error(g, first_executing_node(node), @@ -1335,7 +1363,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i return_type = g->builtin_types.entry_usize; } else if (buf_eql_str(name, "ptr")) { // TODO determine whether the pointer should be const - return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false); + return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false, false); } else { add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), @@ -1365,16 +1393,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, return_type = g->builtin_types.entry_invalid; } else if (array_type->id == TypeTableEntryIdArray) { return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type, - node->data.slice_expr.is_const); + node->data.slice_expr.is_const, false); } else if (array_type->id == TypeTableEntryIdPointer) { return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type, - node->data.slice_expr.is_const); + node->data.slice_expr.is_const, false); } else if (array_type->id == TypeTableEntryIdStruct && array_type->data.structure.is_unknown_size_array) { return_type = get_unknown_size_array_type(g, import, array_type->data.structure.fields[0].type_entry->data.pointer.child_type, - node->data.slice_expr.is_const); + node->data.slice_expr.is_const, false); } else { add_node_error(g, node, 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) { static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, TypeTableEntry *expected_type, AstNode *node) { - TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context); + TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false); TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); if (wanted_type->id == TypeTableEntryIdInvalid || @@ -1713,7 +1741,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa { TypeTableEntry *explicit_type = nullptr; if (variable_declaration->type != nullptr) { - explicit_type = resolve_type(g, variable_declaration->type, import, context); + explicit_type = resolve_type(g, variable_declaration->type, import, context, false); if (explicit_type->id == TypeTableEntryIdUnreachable) { add_node_error(g, variable_declaration->type, buf_sprintf("variable of type 'unreachable' not allowed")); @@ -1837,7 +1865,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr; - TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context); + TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context, false); if (type_entry->id == TypeTableEntryIdInvalid) { return g->builtin_types.entry_invalid; @@ -2017,7 +2045,7 @@ static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *im assert(node->type == NodeTypeCompilerFnType); Buf *name = &node->data.compiler_fn_type.name; - TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context); + TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false); if (buf_eql_str(name, "sizeof")) { uint64_t size_in_bytes = type_entry->size_in_bits / 8; @@ -2221,7 +2249,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); if (asm_output->return_type) { node->data.asm_expr.return_count += 1; - return_type = resolve_type(g, asm_output->return_type, import, context); + return_type = resolve_type(g, asm_output->return_type, import, context, false); if (node->data.asm_expr.return_count > 1) { add_node_error(g, node, buf_sprintf("inline assembly allows up to one output value")); @@ -2357,7 +2385,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, break; } - return_type = get_pointer_to_type(g, child_type, is_const); + return_type = get_pointer_to_type(g, child_type, is_const, false); break; } case PrefixOpDereference: diff --git a/src/analyze.hpp b/src/analyze.hpp index 886bc5ec97f6f2363498486bc4765a1b405093ce..fd2d11cb71be6b50c5bc8587871a1d5524311c46 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -23,6 +23,7 @@ struct StructValExprNode; struct TypeTableEntryPointer { TypeTableEntry *child_type; bool is_const; + bool is_restrict; }; struct TypeTableEntryInt { @@ -97,12 +98,10 @@ struct TypeTableEntry { } data; // use these fields to make sure we don't duplicate type table entries for the same type - TypeTableEntry *pointer_const_parent; - TypeTableEntry *pointer_mut_parent; + TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - restrict + TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - restrict HashMap arrays_by_size; TypeTableEntry *maybe_parent; - TypeTableEntry *unknown_size_array_const_parent; - TypeTableEntry *unknown_size_array_mut_parent; }; @@ -379,7 +378,7 @@ void semantic_analyze(CodeGen *g); void add_node_error(CodeGen *g, AstNode *node, Buf *msg); void alloc_codegen_node(AstNode *node); TypeTableEntry *new_type_table_entry(TypeTableEntryId id); -TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); +TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_restrict); VariableTableEntry *find_variable(BlockContext *context, Buf *name); BlockContext *new_block_context(AstNode *node, BlockContext *parent); diff --git a/src/codegen.cpp b/src/codegen.cpp index dcb543bbf9a69c90baefbd9e273da5a1e2807b65..5ea7ff401f733eb3d9dc35076db095a2380ccf6d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -77,13 +77,13 @@ static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) { return type_node->codegen_node->data.type_node.entry; } -static LLVMTypeRef fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { +static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { TypeTableEntry *type_entry = get_type_for_type_node(g, type_node); if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) { - return get_pointer_to_type(g, type_entry, true)->type_ref; + return get_pointer_to_type(g, type_entry, true, true); } else { - return type_entry->type_ref; + return type_entry; } } @@ -1763,7 +1763,7 @@ static void do_code_gen(CodeGen *g) { if (is_param_decl_type_void(g, param_node)) continue; AstNode *type_node = param_node->data.param_decl.type; - param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node); + param_types[gen_param_index] = fn_proto_type_from_type_node(g, type_node)->type_ref; gen_param_index += 1; } 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) { LLVMAddFunctionAttr(fn, LLVMNoUnwindAttribute); } + // set parameter attributes + gen_param_index = 0; + for (int param_decl_i = 0; param_decl_i < fn_proto->params.length; param_decl_i += 1) { + AstNode *param_node = fn_proto->params.at(param_decl_i); + assert(param_node->type == NodeTypeParamDecl); + if (is_param_decl_type_void(g, param_node)) + continue; + AstNode *type_node = param_node->data.param_decl.type; + TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node); + LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index); + if (param_type->id == TypeTableEntryIdPointer && + param_type->data.pointer.is_restrict) + { + LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); + } else if (param_type->id == TypeTableEntryIdPointer && + param_type->data.pointer.is_const) + { + LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute); + } + gen_param_index += 1; + } + fn_table_entry->fn_value = fn; } @@ -2032,7 +2054,7 @@ static void define_builtin_types(CodeGen *g) { LLVMZigEncoding_DW_ATE_unsigned()); g->builtin_types.entry_u64 = entry; } - g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true); + g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false); { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMInt8Type(); diff --git a/src/parser.cpp b/src/parser.cpp index e8da95bb3d9ba5069959d1d00d4cb4334cb2c9cb..0a1fb654b3f155675635410da2f2f3f34f7c212b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -224,16 +224,18 @@ void ast_print(AstNode *node, int indent) { } case AstNodeTypeTypePointer: { - const char *const_or_mut_str = node->data.type.is_const ? "const" : "var"; - fprintf(stderr, "'%s' PointerType\n", const_or_mut_str); + const char *const_or_mut_str = node->data.type.is_const ? "const " : ""; + const char *restrict_or_not_str = node->data.type.is_restrict ? "restrict " : ""; + fprintf(stderr, "%s%s PointerType\n", const_or_mut_str, restrict_or_not_str); ast_print(node->data.type.child_type, indent + 2); break; } case AstNodeTypeTypeArray: { - const char *const_or_mut_str = node->data.type.is_const ? "const" : "var"; - fprintf(stderr, "'%s' ArrayType\n", const_or_mut_str); + const char *const_or_mut_str = node->data.type.is_const ? "const " : ""; + const char *restrict_or_not_str = node->data.type.is_restrict ? "restrict " : ""; + fprintf(stderr, "%s%s ArrayType\n", const_or_mut_str, restrict_or_not_str); if (node->data.type.array_size) ast_print(node->data.type.array_size, indent + 2); 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 node->data.type.is_const = true; *token_index += 1; first_type_token = &pc->tokens->at(*token_index); + if (first_type_token->id == TokenIdKeywordRestrict) { + node->data.type.is_restrict = true; + *token_index += 1; + } + } else if (first_type_token->id == TokenIdKeywordRestrict) { + node->data.type.is_restrict = true; + *token_index += 1; } 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 /* Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr -PointerType : token(Ampersand) option(token(Const)) Type -ArrayType : token(LBracket) option(Expression) token(RBracket) Type +PointerType : token(Ampersand) option(token(Const)) option(token(Restrict)) Type +ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(Restrict)) Type */ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { Token *token = &pc->tokens->at(*token_index); @@ -1129,6 +1138,15 @@ static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { if (const_tok->id == TokenIdKeywordConst) { *token_index += 1; node->data.type.is_const = true; + + Token *next_tok = &pc->tokens->at(*token_index); + if (next_tok->id == TokenIdKeywordRestrict) { + *token_index += 1; + node->data.type.is_restrict = true; + } + } else if (const_tok->id == TokenIdKeywordRestrict) { + *token_index += 1; + node->data.type.is_restrict = true; } node->data.type.child_type = ast_parse_type(pc, token_index); @@ -1476,7 +1494,7 @@ static PrefixOp tok_to_prefix_op(Token *token) { } /* -PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) +PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) */ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) { Token *token = &pc->tokens->at(*token_index); diff --git a/src/parser.hpp b/src/parser.hpp index 75d0f822efbee78a737f68bcc7242d7b7ce36eee..182ac13fd0f568a39e555be35c59119f4a64515b 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -110,6 +110,7 @@ struct AstNodeType { AstNode *child_type; AstNode *array_size; // can be null bool is_const; + bool is_restrict; AstNode *compiler_expr; }; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index b70bea7057b2b20555fc478467df38b7e10dd81d..94f10c6e03ab13f31a4b610b1180f43403bf3a2b 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -243,6 +243,8 @@ static void end_token(Tokenize *t) { t->cur_tok->id = TokenIdKeywordBreak; } else if (mem_eql_str(token_mem, token_len, "null")) { t->cur_tok->id = TokenIdKeywordNull; + } else if (mem_eql_str(token_mem, token_len, "restrict")) { + t->cur_tok->id = TokenIdKeywordRestrict; } t->cur_tok = nullptr; @@ -1019,6 +1021,7 @@ static const char * token_name(Token *token) { case TokenIdKeywordContinue: return "Continue"; case TokenIdKeywordBreak: return "Break"; case TokenIdKeywordNull: return "Null"; + case TokenIdKeywordRestrict: return "Restrict"; case TokenIdLParen: return "LParen"; case TokenIdRParen: return "RParen"; case TokenIdComma: return "Comma"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 2169db9c1b16bebc3d1839bb25b6a6a51f5a5ea5..f9224de98cf00d9bf788e4b02089708d186a86ce 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -36,6 +36,7 @@ enum TokenId { TokenIdKeywordContinue, TokenIdKeywordBreak, TokenIdKeywordNull, + TokenIdKeywordRestrict, TokenIdLParen, TokenIdRParen, TokenIdComma, diff --git a/std/builtin.zig b/std/builtin.zig index 572adf00cc3d4abafa7ae5b1f2d86f9fe6021bd0..b57c440c07924141309eb3ac172f8c788784ab89 100644 --- a/std/builtin.zig +++ b/std/builtin.zig @@ -10,8 +10,7 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 { return dest; } -// TODO annotate parameters with noalias -export fn memcpy(dest: &u8, src: &const u8, n: usize) -> &u8 { +export fn memcpy(dest: &restrict u8, src: &const restrict u8, n: usize) -> &u8 { var index : #typeof(n) = 0; while (index != n) { dest[index] = src[index]; -- 2.54.0