Commit 14b9cbd43c
Changed files (10)
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
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)
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,21 +449,47 @@ 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);
+ 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"));
@@ -472,8 +497,6 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry
return type_node->entry;
}
- AstNode *size_node = node->data.type.array_size;
-
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:
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<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> 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);
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();
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);
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;
};
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";
src/tokenizer.hpp
@@ -36,6 +36,7 @@ enum TokenId {
TokenIdKeywordContinue,
TokenIdKeywordBreak,
TokenIdKeywordNull,
+ TokenIdKeywordRestrict,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,
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];