diff options
Diffstat (limited to 'src/analyze.cpp')
| -rw-r--r-- | src/analyze.cpp | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index 68bfd6c3c7..18afb9eb05 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,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: |
