add restrict qualifier on pointer arguments
This commit is contained in:
parent
d14a31100f
commit
14b9cbd43c
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -110,6 +110,7 @@ struct AstNodeType {
|
||||
AstNode *child_type;
|
||||
AstNode *array_size; // can be null
|
||||
bool is_const;
|
||||
bool is_restrict;
|
||||
AstNode *compiler_expr;
|
||||
};
|
||||
|
||||
|
@ -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";
|
||||
|
@ -36,6 +36,7 @@ enum TokenId {
|
||||
TokenIdKeywordContinue,
|
||||
TokenIdKeywordBreak,
|
||||
TokenIdKeywordNull,
|
||||
TokenIdKeywordRestrict,
|
||||
TokenIdLParen,
|
||||
TokenIdRParen,
|
||||
TokenIdComma,
|
||||
|
@ -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];
|
||||
|
Loading…
x
Reference in New Issue
Block a user