From ff2ed966bb37079217ee7a7753cb63a763b8c3b5 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 26 Aug 2020 08:43:03 -0600 Subject: [PATCH 01/14] Implement @Type for Union This removes TypeInfo.UnionField.enum_field, which is redundant with TypeInfo.Union.tag_type. --- lib/std/builtin.zig | 1 - src/analyze.cpp | 300 ++++++++++++++++------------- src/ir.cpp | 102 ++++++++-- test/compile_errors.zig | 74 ++++++- test/stage1/behavior/type.zig | 61 ++++++ test/stage1/behavior/type_info.zig | 4 - 6 files changed, 380 insertions(+), 162 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 911a0eb15c..52b8f641cd 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -317,7 +317,6 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const UnionField = struct { name: []const u8, - enum_field: ?EnumField, field_type: type, }; diff --git a/src/analyze.cpp b/src/analyze.cpp index b1d362f6e9..b70e756f47 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2372,7 +2372,10 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { if (field->gen_index == UINT32_MAX) continue; - AstNode *align_expr = field->decl_node->data.struct_field.align_expr; + AstNode *align_expr = nullptr; + if (union_type->data.unionation.decl_node->type == NodeTypeContainerDecl) { + align_expr = field->decl_node->data.struct_field.align_expr; + } if (align_expr != nullptr) { if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, &field->align)) @@ -2468,9 +2471,6 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { AstNode *decl_node = union_type->data.unionation.decl_node; - - assert(decl_node->type == NodeTypeContainerDecl); - uint32_t field_count = union_type->data.unionation.src_field_count; TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; @@ -3055,7 +3055,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorNone; AstNode *decl_node = union_type->data.unionation.decl_node; - assert(decl_node->type == NodeTypeContainerDecl); if (union_type->data.unionation.resolve_loop_flag_zero_bits) { if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { @@ -3069,30 +3068,50 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { union_type->data.unionation.resolve_loop_flag_zero_bits = true; - assert(union_type->data.unionation.fields == nullptr); - uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); + uint32_t field_count; + if (decl_node->type == NodeTypeContainerDecl) { + assert(union_type->data.unionation.fields == nullptr); + field_count = (uint32_t)decl_node->data.container_decl.fields.length; + if (field_count == 0) { + add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); + union_type->data.unionation.src_field_count = field_count; + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); + union_type->data.unionation.fields_by_name.init(field_count); + } else { + assert(union_type->data.unionation.fields != nullptr); + field_count = union_type->data.unionation.src_field_count; } - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); - union_type->data.unionation.fields_by_name.init(field_count); Scope *scope = &union_type->data.unionation.decls_scope->base; HashMap occupied_tag_values = {}; - AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr; - union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum || - enum_type_node != nullptr; - bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); - bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr) && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); + bool is_auto_enum; // union(enum) or union(enum(expr)) + bool is_explicit_enum; // union(expr) + AstNode *enum_type_node; // expr in union(enum(expr)) or union(expr) + if (decl_node->type == NodeTypeContainerDecl) { + is_auto_enum = decl_node->data.container_decl.auto_enum; + is_explicit_enum = decl_node->data.container_decl.init_arg_expr != nullptr; + enum_type_node = decl_node->data.container_decl.init_arg_expr; + } else { + is_auto_enum = false; + is_explicit_enum = union_type->data.unionation.tag_type != nullptr; + enum_type_node = nullptr; + } + union_type->data.unionation.have_explicit_tag_type = is_auto_enum || is_explicit_enum; + + bool is_auto_layout = union_type->data.unionation.layout == ContainerLayoutAuto; + bool want_safety = (field_count >= 2) + && (is_auto_layout || is_explicit_enum) + && !(g->build_mode == BuildModeFastRelease || g->build_mode == BuildModeSmallRelease); ZigType *tag_type; - bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); + bool create_enum_type = is_auto_enum || (!is_explicit_enum && want_safety); bool *covered_enum_fields; + bool *is_zero_bits = heap::c_allocator.allocate(field_count); ZigLLVMDIEnumerator **di_enumerators; if (create_enum_type) { occupied_tag_values.init(field_count); @@ -3150,105 +3169,111 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return err; } tag_type = enum_type; - covered_enum_fields = heap::c_allocator.allocate(enum_type->data.enumeration.src_field_count); } else { - tag_type = nullptr; + if (decl_node->type == NodeTypeContainerDecl) { + tag_type = nullptr; + } else { + tag_type = union_type->data.unionation.tag_type; + } + } + if (tag_type != nullptr) { + covered_enum_fields = heap::c_allocator.allocate(tag_type->data.enumeration.src_field_count); } union_type->data.unionation.tag_type = tag_type; - uint32_t gen_field_index = 0; for (uint32_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(i); - Buf *field_name = field_node->data.struct_field.name; TypeUnionField *union_field = &union_type->data.unionation.fields[i]; - union_field->name = field_node->data.struct_field.name; - union_field->decl_node = field_node; - union_field->gen_index = UINT32_MAX; + if (decl_node->type == NodeTypeContainerDecl) { + AstNode *field_node = decl_node->data.container_decl.fields.at(i); + union_field->name = field_node->data.struct_field.name; + union_field->decl_node = field_node; + union_field->gen_index = UINT32_MAX; + is_zero_bits[i] = false; - auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); - if (field_entry != nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); - add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - bool field_is_zero_bits; - if (field_node->data.struct_field.type == nullptr) { - if (decl_node->data.container_decl.auto_enum || - decl_node->data.container_decl.init_arg_expr != nullptr) - { - union_field->type_entry = g->builtin_types.entry_void; - field_is_zero_bits = true; - } else { - add_node_error(g, field_node, buf_sprintf("union field missing type")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - } else { - ZigValue *field_type_val = analyze_const_value(g, scope, - field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); - if (type_is_invalid(field_type_val->type)) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - assert(field_type_val->special != ConstValSpecialRuntime); - union_field->type_val = field_type_val; - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, field_node, - buf_create_from_str( - "opaque types have unknown size and therefore cannot be directly embedded in unions")); + auto field_entry = union_type->data.unionation.fields_by_name.put_unique(union_field->name, union_field); + if (field_entry != nullptr) { + ErrorMsg *msg = add_node_error(g, union_field->decl_node, + buf_sprintf("duplicate union field: '%s'", buf_ptr(union_field->name))); + add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; } - switch (type_val_resolve_requires_comptime(g, field_type_val)) { - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field_node, - buf_create_from_str("while checking this field")); - } + if (field_node->data.struct_field.type == nullptr) { + if (is_auto_enum || is_explicit_enum) { + union_field->type_entry = g->builtin_types.entry_void; + is_zero_bits[i] = true; + } else { + add_node_error(g, field_node, buf_sprintf("union field missing type")); union_type->data.unionation.resolve_status = ResolveStatusInvalid; return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; + } + } else { + ZigValue *field_type_val = analyze_const_value(g, scope, + field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); + if (type_is_invalid(field_type_val->type)) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + assert(field_type_val->special != ConstValSpecialRuntime); + union_field->type_val = field_type_val; + if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) + return ErrorSemanticAnalyzeFail; + + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_opaque_type) { + add_node_error(g, field_node, + buf_create_from_str( + "opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + + switch (type_val_resolve_requires_comptime(g, field_type_val)) { + case ReqCompTimeInvalid: + if (g->trace_err != nullptr) { + g->trace_err = add_error_note(g, g->trace_err, field_node, + buf_create_from_str("while checking this field")); + } + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; + } + + if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &is_zero_bits[i]))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } } - if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; + if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { + ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, + buf_create_from_str("untagged union field assignment")); + add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); } } - if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { - ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, - buf_create_from_str("untagged union field assignment")); - add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); - } - if (create_enum_type) { - di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i); + di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i); union_field->enum_field = &tag_type->data.enumeration.fields[i]; - union_field->enum_field->name = field_name; + union_field->enum_field->name = union_field->name; union_field->enum_field->decl_index = i; - union_field->enum_field->decl_node = field_node; + union_field->enum_field->decl_node = union_field->decl_node; auto prev_entry = tag_type->data.enumeration.fields_by_name.put_unique(union_field->enum_field->name, union_field->enum_field); assert(prev_entry == nullptr); // caught by union de-duplicator above - AstNode *tag_value = field_node->data.struct_field.value; + AstNode *tag_value = decl_node->type == NodeTypeContainerDecl + ? union_field->decl_node->data.struct_field.value : nullptr; + // In this first pass we resolve explicit tag values. // In a second pass we will fill in the unspecified ones. if (tag_value != nullptr) { @@ -3276,11 +3301,11 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { return ErrorSemanticAnalyzeFail; } } - } else if (enum_type_node != nullptr) { - union_field->enum_field = find_enum_type_field(tag_type, field_name); + } else if (tag_type != nullptr) { + union_field->enum_field = find_enum_type_field(tag_type, union_field->name); if (union_field->enum_field == nullptr) { - ErrorMsg *msg = add_node_error(g, field_node, - buf_sprintf("enum field not found: '%s'", buf_ptr(field_name))); + ErrorMsg *msg = add_node_error(g, union_field->decl_node, + buf_sprintf("enum field not found: '%s'", buf_ptr(union_field->name))); add_error_note(g, msg, tag_type->data.enumeration.decl_node, buf_sprintf("enum declared here")); union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -3289,21 +3314,23 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { covered_enum_fields[union_field->enum_field->decl_index] = true; } else { union_field->enum_field = heap::c_allocator.create(); - union_field->enum_field->name = field_name; + union_field->enum_field->name = union_field->name; union_field->enum_field->decl_index = i; bigint_init_unsigned(&union_field->enum_field->value, i); } assert(union_field->enum_field != nullptr); - - if (field_is_zero_bits) - continue; - - union_field->gen_index = gen_field_index; - gen_field_index += 1; } - bool src_have_tag = decl_node->data.container_decl.auto_enum || - decl_node->data.container_decl.init_arg_expr != nullptr; + uint32_t gen_field_index = 0; + for (uint32_t i = 0; i < field_count; i += 1) { + TypeUnionField *union_field = &union_type->data.unionation.fields[i]; + if (!is_zero_bits[i]) { + union_field->gen_index = gen_field_index; + gen_field_index += 1; + } + } + + bool src_have_tag = is_auto_enum || is_explicit_enum; if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { const char *qual_str; @@ -3317,8 +3344,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { qual_str = "extern"; break; } - AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ? - decl_node->data.container_decl.init_arg_expr : decl_node; + AstNode *source_node = enum_type_node != nullptr ? enum_type_node : decl_node; add_node_error(g, source_node, buf_sprintf("%s union does not support enum tag type", qual_str)); union_type->data.unionation.resolve_status = ResolveStatusInvalid; @@ -3326,43 +3352,47 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } if (create_enum_type) { - // Now iterate again and populate the unspecified tag values - uint32_t next_maybe_unoccupied_index = 0; + if (decl_node->type == NodeTypeContainerDecl) { + // Now iterate again and populate the unspecified tag values + uint32_t next_maybe_unoccupied_index = 0; - for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { - AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); - TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; - AstNode *tag_value = field_node->data.struct_field.value; + for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { + AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); + TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; + AstNode *tag_value = field_node->data.struct_field.value; - if (tag_value == nullptr) { - if (occupied_tag_values.size() == 0) { - bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); - next_maybe_unoccupied_index += 1; - } else { - BigInt proposed_value; - for (;;) { - bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); + if (tag_value == nullptr) { + if (occupied_tag_values.size() == 0) { + bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); next_maybe_unoccupied_index += 1; - auto entry = occupied_tag_values.put_unique(proposed_value, field_node); - if (entry != nullptr) { - continue; + } else { + BigInt proposed_value; + for (;;) { + bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); + next_maybe_unoccupied_index += 1; + auto entry = occupied_tag_values.put_unique(proposed_value, field_node); + if (entry != nullptr) { + continue; + } + break; } - break; + bigint_init_bigint(&union_field->enum_field->value, &proposed_value); } - bigint_init_bigint(&union_field->enum_field->value, &proposed_value); } } } - } else if (enum_type_node != nullptr) { + } else if (tag_type != nullptr) { for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; if (!covered_enum_fields[i]) { - AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; - AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); ErrorMsg *msg = add_node_error(g, decl_node, buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); - add_error_note(g, msg, field_node, - buf_sprintf("declared here")); + if (decl_node->type == NodeTypeContainerDecl) { + AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; + AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); + add_error_note(g, msg, field_node, + buf_sprintf("declared here")); + } union_type->data.unionation.resolve_status = ResolveStatusInvalid; } } @@ -8350,7 +8380,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS ZigLLVMDIFile *di_file; ZigLLVMDIScope *di_scope; unsigned line; - if (decl_node != nullptr && !struct_type->data.structure.created_by_at_type) { + if (decl_node != nullptr) { Scope *scope = &struct_type->data.structure.decls_scope->base; ZigType *import = get_scope_import(scope); di_file = import->data.structure.root_struct->di_file; @@ -8713,7 +8743,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta uint64_t store_size_in_bits = union_field->type_entry->size_in_bits; uint64_t abi_align_in_bits = 8*union_field->type_entry->abi_align; - AstNode *field_node = decl_node->data.container_decl.fields.at(i); + AstNode *field_node = union_field->decl_node; union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, ZigLLVMTypeToScope(union_type->llvm_di_type), buf_ptr(union_field->enum_field->name), import->data.structure.root_struct->di_file, (unsigned)(field_node->line + 1), diff --git a/src/ir.cpp b/src/ir.cpp index 803b97891f..36852de706 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25424,8 +25424,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy init_const_slice(ira->codegen, fields[2], union_field_array, 0, union_field_count, false); - ZigType *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField", nullptr); - for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; ZigValue *union_field_val = &union_field_array->data.x_array.data.s_none.elements[union_field_index]; @@ -25433,20 +25431,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy union_field_val->special = ConstValSpecialStatic; union_field_val->type = type_info_union_field_type; - ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 3); + ZigValue **inner_fields = alloc_const_vals_ptrs(ira->codegen, 2); inner_fields[1]->special = ConstValSpecialStatic; - inner_fields[1]->type = get_optional_type(ira->codegen, type_info_enum_field_type); - - if (fields[1]->data.x_optional == nullptr) { - inner_fields[1]->data.x_optional = nullptr; - } else { - inner_fields[1]->data.x_optional = ira->codegen->pass1_arena->create(); - make_enum_field_val(ira, inner_fields[1]->data.x_optional, union_field->enum_field, type_info_enum_field_type); - } - - inner_fields[2]->special = ConstValSpecialStatic; - inner_fields[2]->type = ira->codegen->builtin_types.entry_type; - inner_fields[2]->data.x_type = union_field->type_entry; + inner_fields[1]->type = ira->codegen->builtin_types.entry_type; + inner_fields[1]->data.x_type = union_field->type_entry; ZigValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true); @@ -26102,7 +26090,8 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI entry->data.structure.layout = layout; entry->data.structure.special = is_tuple ? StructSpecialInferredTuple : StructSpecialNone; entry->data.structure.created_by_at_type = true; - entry->data.structure.decls_scope = create_decls_scope(ira->codegen, nullptr, nullptr, entry, entry, &entry->name); + entry->data.structure.decls_scope = create_decls_scope( + ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name); assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); @@ -26226,13 +26215,84 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI return ira->codegen->invalid_inst_gen->value->type; field->value = *field_int_value; } - return entry; } - case ZigTypeIdUnion: - ir_add_error(ira, source_instr, buf_sprintf( - "TODO implement @Type for 'TypeInfo.%s': see https://github.com/ziglang/zig/issues/2907", type_id_name(tagTypeId))); - return ira->codegen->invalid_inst_gen->value->type; + case ZigTypeIdUnion: { + assert(payload->special == ConstValSpecialStatic); + assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); + + ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); + assert(layout_value->special == ConstValSpecialStatic); + assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); + ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); + + ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1); + if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { + ir_add_error(ira, source_instr, buf_sprintf( + "union tag type must be an enum, not %s", type_id_name(tag_type->id))); + return ira->codegen->invalid_inst_gen->value->type; + } + + ZigValue *fields_value = get_const_field(ira, source_instr->source_node, payload, "fields", 2); + if (fields_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + + assert(fields_value->special == ConstValSpecialStatic); + assert(is_slice(fields_value->type)); + ZigValue *fields_ptr = fields_value->data.x_struct.fields[slice_ptr_index]; + ZigValue *fields_len_value = fields_value->data.x_struct.fields[slice_len_index]; + size_t fields_len = bigint_as_usize(&fields_len_value->data.x_bigint); + + ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 3); + if (decls_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + + assert(decls_value->special == ConstValSpecialStatic); + assert(is_slice(decls_value->type)); + ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index]; + size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint); + if (decls_len != 0) { + ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Union.decls must be empty for @Type")); + return ira->codegen->invalid_inst_gen->value->type; + } + + ZigType *entry = new_type_table_entry(ZigTypeIdUnion); + buf_init_from_buf(&entry->name, + get_anon_type_name(ira->codegen, ira->old_irb.exec, "union", source_instr->scope, source_instr->source_node, &entry->name)); + entry->data.unionation.decl_node = source_instr->source_node; + entry->data.unionation.fields = heap::c_allocator.allocate(fields_len); + entry->data.unionation.fields_by_name.init(fields_len); + entry->data.unionation.decls_scope = create_decls_scope( + ira->codegen, source_instr->source_node, source_instr->scope, entry, get_scope_import(source_instr->scope), &entry->name); + entry->data.unionation.tag_type = tag_type; + entry->data.unionation.src_field_count = fields_len; + entry->data.unionation.layout = layout; + + assert(fields_ptr->data.x_ptr.special == ConstPtrSpecialBaseArray); + assert(fields_ptr->data.x_ptr.data.base_array.elem_index == 0); + ZigValue *fields_arr = fields_ptr->data.x_ptr.data.base_array.array_val; + assert(fields_arr->special == ConstValSpecialStatic); + assert(fields_arr->data.x_array.special == ConstArraySpecialNone); + for (size_t i = 0; i < fields_len; i++) { + ZigValue *field_value = &fields_arr->data.x_array.data.s_none.elements[i]; + assert(field_value->type == ir_type_info_get_type(ira, "UnionField", nullptr)); + TypeUnionField *field = &entry->data.unionation.fields[i]; + field->name = buf_alloc(); + if ((err = get_const_field_buf(ira, source_instr->source_node, field_value, "name", 0, field->name))) + return ira->codegen->invalid_inst_gen->value->type; + if (entry->data.unionation.fields_by_name.put_unique(field->name, field) != nullptr) { + ir_add_error(ira, source_instr, buf_sprintf("duplicate union field '%s'", buf_ptr(field->name))); + return ira->codegen->invalid_inst_gen->value->type; + } + field->decl_node = source_instr->source_node; + ZigValue *type_value = get_const_field(ira, source_instr->source_node, field_value, "field_type", 1); + if (type_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; + field->type_val = type_value; + field->type_entry = type_value->data.x_type; + } + return entry; + } case ZigTypeIdFn: case ZigTypeIdBoundFn: ir_add_error(ira, source_instr, buf_sprintf( diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 31f2b57dc8..741c5fdb71 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -10,6 +10,78 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", }); + cases.add("@Type for tagged union with extra union field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = u1, + \\ .fields = &[_]TypeInfo.EnumField{ + \\ .{ .name = "signed", .value = 0 }, + \\ .{ .name = "unsigned", .value = 1 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = true, + \\ }, + \\}); + \\const Tagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = Tag, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "signed", .field_type = i32 }, + \\ .{ .name = "unsigned", .field_type = u32 }, + \\ .{ .name = "arst", .field_type = f32 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ var tagged = Tagged{ .signed = -1 }; + \\ tagged = .{ .unsigned = 1 }; + \\} + , &[_][]const u8{ + "tmp.zig:14:23: error: enum field not found: 'arst'", + "tmp.zig:2:20: note: enum declared here", + "tmp.zig:27:24: note: referenced here", + }); + + cases.add("@Type for tagged union with extra enum field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = u2, + \\ .fields = &[_]TypeInfo.EnumField{ + \\ .{ .name = "signed", .value = 0 }, + \\ .{ .name = "unsigned", .value = 1 }, + \\ .{ .name = "arst", .field_type = 2 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = true, + \\ }, + \\}); + \\const Tagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = Tag, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "signed", .field_type = i32 }, + \\ .{ .name = "unsigned", .field_type = u32 }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ var tagged = Tagged{ .signed = -1 }; + \\ tagged = .{ .unsigned = 1 }; + \\} + , &[_][]const u8{ + "tmp.zig:9:32: error: no member named 'field_type' in struct 'std.builtin.EnumField'", + "tmp.zig:18:21: note: referenced here", + "tmp.zig:27:18: note: referenced here", + }); + cases.add("@Type with undefined", \\comptime { \\ _ = @Type(.{ .Array = .{ .len = 0, .child = u8, .sentinel = undefined } }); @@ -7419,7 +7491,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { }); cases.add( // fixed bug #2032 - "compile diagnostic string for top level decl type", + "compile diagnostic string for top level decl type", \\export fn entry() void { \\ var foo: u32 = @This(){}; \\} diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 81bd741ecc..eac76c9f98 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -313,3 +313,64 @@ test "Type.Enum" { testing.expectEqual(@as(u32, 5), @enumToInt(Bar.b)); testing.expectEqual(@as(u32, 6), @enumToInt(@intToEnum(Bar, 6))); } + +test "Type.Union" { + const Untagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = null, + .fields = &[_]TypeInfo.UnionField{ + .{ .name = "int", .field_type = i32 }, + .{ .name = "float", .field_type = f32 }, + }, + .decls = &[_]TypeInfo.Declaration{}, + }, + }); + var untagged = Untagged{ .int = 1 }; + untagged.float = 2.0; + untagged.int = 3; + testing.expectEqual(@as(i32, 3), untagged.int); + + const PackedUntagged = @Type(.{ + .Union = .{ + .layout = .Packed, + .tag_type = null, + .fields = &[_]TypeInfo.UnionField{ + .{ .name = "signed", .field_type = i32 }, + .{ .name = "unsigned", .field_type = u32 }, + }, + .decls = &[_]TypeInfo.Declaration{}, + }, + }); + var packed_untagged = PackedUntagged{ .signed = -1 }; + testing.expectEqual(@as(i32, -1), packed_untagged.signed); + testing.expectEqual(~@as(u32, 0), packed_untagged.unsigned); + + const Tag = @Type(.{ + .Enum = .{ + .layout = .Auto, + .tag_type = u1, + .fields = &[_]TypeInfo.EnumField{ + .{ .name = "signed", .value = 0 }, + .{ .name = "unsigned", .value = 1 }, + }, + .decls = &[_]TypeInfo.Declaration{}, + .is_exhaustive = true, + }, + }); + const Tagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = Tag, + .fields = &[_]TypeInfo.UnionField{ + .{ .name = "signed", .field_type = i32 }, + .{ .name = "unsigned", .field_type = u32 }, + }, + .decls = &[_]TypeInfo.Declaration{}, + }, + }); + var tagged = Tagged{ .signed = -1 }; + testing.expectEqual(Tag.signed, tagged); + tagged = .{ .unsigned = 1 }; + testing.expectEqual(Tag.unsigned, tagged); +} diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index 409993a741..9e066d5f1a 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -198,8 +198,6 @@ fn testUnion() void { expect(typeinfo_info.Union.layout == .Auto); expect(typeinfo_info.Union.tag_type.? == TypeId); expect(typeinfo_info.Union.fields.len == 25); - expect(typeinfo_info.Union.fields[4].enum_field != null); - expect(typeinfo_info.Union.fields[4].enum_field.?.value == 4); expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int)); expect(typeinfo_info.Union.decls.len == 21); @@ -213,7 +211,6 @@ fn testUnion() void { expect(notag_union_info.Union.tag_type == null); expect(notag_union_info.Union.layout == .Auto); expect(notag_union_info.Union.fields.len == 2); - expect(notag_union_info.Union.fields[0].enum_field == null); expect(notag_union_info.Union.fields[1].field_type == u32); const TestExternUnion = extern union { @@ -223,7 +220,6 @@ fn testUnion() void { const extern_union_info = @typeInfo(TestExternUnion); expect(extern_union_info.Union.layout == .Extern); expect(extern_union_info.Union.tag_type == null); - expect(extern_union_info.Union.fields[0].enum_field == null); expect(extern_union_info.Union.fields[0].field_type == *c_void); } From ac19ccf5955488a43b29ea13675c33426aada430 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 26 Aug 2020 12:20:27 -0600 Subject: [PATCH 02/14] Update standard library for removal of TypeInfo.UnionField.enum_field --- lib/std/fmt.zig | 8 +++++++- lib/std/hash/auto_hash.zig | 11 ++++++++--- lib/std/io/serialization.zig | 18 ++++++++++++++++-- lib/std/json.zig | 16 ++++++++++++++-- lib/std/meta.zig | 24 +++++++++++++++++++----- 5 files changed, 64 insertions(+), 13 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index a652bd8c21..3aa6278d5d 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -395,11 +395,17 @@ pub fn formatType( } const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; try writer.writeAll("{ ."); try writer.writeAll(@tagName(@as(UnionTagType, value))); try writer.writeAll(" = "); inline for (info.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); } } diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 5877c77b5d..c3beabe007 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -136,12 +136,17 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { .Union => |info| { if (info.tag_type) |tag_type| { + const tag_info = @typeInfo(tag_type).Enum; const tag = meta.activeTag(key); const s = hash(hasher, tag, strat); inline for (info.fields) |field| { - const enum_field = field.enum_field.?; - if (enum_field.value == @enumToInt(tag)) { - hash(hasher, @field(key, enum_field.name), strat); + comptime var tag_value: @TagType(tag_type) = undefined; + inline for (tag_info.fields) |enum_field| { + if (comptime mem.eql(u8, field.name, enum_field.name)) + tag_value = enum_field.value; + } + if (@enumToInt(tag) == tag_value) { + hash(hasher, @field(key, field.name), strat); // TODO use a labelled break when it does not crash the compiler. cf #2908 // break :blk; return; diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index 925c929cee..fa5172e57f 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -149,6 +149,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, .Union => { const info = @typeInfo(C).Union; if (info.tag_type) |TagType| { + const tag_info = @typeInfo(TagType).Enum; //we avoid duplicate iteration over the enum tags // by getting the int directly and casting it without // safety. If it is bad, it will be caught anyway. @@ -156,7 +157,13 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, const tag = try self.deserializeInt(TagInt); inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == tag) { + comptime var tag_value: TagInt = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { + tag_value = enum_field_info.value; + } + } + if (tag_value == tag) { const name = field_info.name; const FieldType = field_info.field_type; ptr.* = @unionInit(C, name, undefined); @@ -314,13 +321,20 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co .Union => { const info = @typeInfo(T).Union; if (info.tag_type) |TagType| { + const tag_info = @typeInfo(TagType).Enum; const active_tag = meta.activeTag(value); try self.serialize(active_tag); //This inline loop is necessary because active_tag is a runtime // value, but @field requires a comptime value. Our alternative // is to check each field for a match inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == @enumToInt(active_tag)) { + comptime var tag_value: @TagType(TagType) = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { + tag_value = enum_field_info.value; + } + } + if (tag_value == @enumToInt(active_tag)) { const name = field_info.name; const FieldType = field_info.field_type; try self.serialize(@field(value, name)); diff --git a/lib/std/json.zig b/lib/std/json.zig index 2f8a70d0ef..31f8a91127 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1612,8 +1612,14 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { }, .Union => |unionInfo| { if (unionInfo.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; inline for (unionInfo.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { parseFree(u_field.field_type, @field(value, u_field.name), options); break; } @@ -2457,8 +2463,14 @@ pub fn stringify( const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { + const tag_info = @typeInfo(UnionTagType).Enum; inline for (info.fields) |u_field| { - if (@enumToInt(@as(UnionTagType, value)) == u_field.enum_field.?.value) { + comptime var tag_value: @TagType(UnionTagType) = undefined; + inline for (tag_info.fields) |e_field| { + if (comptime mem.eql(u8, u_field.name, e_field.name)) + tag_value = e_field.value; + } + if (@enumToInt(@as(UnionTagType, value)) == tag_value) { return try stringify(@field(value, u_field.name), options, out_stream); } } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 73e0661498..8cb1ba155d 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -465,10 +465,19 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type { testing.expect(trait.is(.Union)(U)); const info = @typeInfo(U).Union; + const tag_info = @typeInfo(@TagType(U)).Enum; + + comptime var name: []const u8 = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (@enumToInt(tag) == enum_field_info.value) + name = enum_field_info.name; + } inline for (info.fields) |field_info| { - if (field_info.enum_field.?.value == @enumToInt(tag)) return field_info.field_type; + if (comptime mem.eql(u8, field_info.name, name)) + return field_info.field_type; } + unreachable; } @@ -504,15 +513,20 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { } }, .Union => |info| { - if (info.tag_type) |_| { + if (info.tag_type) |Tag| { const tag_a = activeTag(a); const tag_b = activeTag(b); if (tag_a != tag_b) return false; + const tag_info = @typeInfo(Tag).Enum; inline for (info.fields) |field_info| { - const enum_field = field_info.enum_field.?; - if (enum_field.value == @enumToInt(tag_a)) { - return eql(@field(a, enum_field.name), @field(b, enum_field.name)); + comptime var tag_value: @TagType(Tag) = undefined; + inline for (tag_info.fields) |enum_field_info| { + if (comptime mem.eql(u8, field_info.name, enum_field_info.name)) + tag_value = enum_field_info.value; + } + if (tag_value == @enumToInt(tag_a)) { + return eql(@field(a, field_info.name), @field(b, field_info.name)); } } return false; From 771f35c59381dc6359640d7f572411d24e379240 Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Wed, 26 Aug 2020 13:38:58 -0600 Subject: [PATCH 03/14] Use less inefficient method of replacing TypeInfo.UnionField.enum_field --- lib/std/fmt.zig | 8 +------- lib/std/hash/auto_hash.zig | 8 +------- lib/std/io/serialization.zig | 18 ++---------------- lib/std/json.zig | 16 ++-------------- lib/std/meta.zig | 16 ++-------------- 5 files changed, 8 insertions(+), 58 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 3aa6278d5d..8d31733959 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -395,17 +395,11 @@ pub fn formatType( } const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { - const tag_info = @typeInfo(UnionTagType).Enum; try writer.writeAll("{ ."); try writer.writeAll(@tagName(@as(UnionTagType, value))); try writer.writeAll(" = "); inline for (info.fields) |u_field| { - comptime var tag_value: @TagType(UnionTagType) = undefined; - inline for (tag_info.fields) |e_field| { - if (comptime mem.eql(u8, u_field.name, e_field.name)) - tag_value = e_field.value; - } - if (@enumToInt(@as(UnionTagType, value)) == tag_value) { + if (value == @field(UnionTagType, u_field.name)) { try formatType(@field(value, u_field.name), fmt, options, writer, max_depth - 1); } } diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index c3beabe007..2e707d5450 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -136,16 +136,10 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void { .Union => |info| { if (info.tag_type) |tag_type| { - const tag_info = @typeInfo(tag_type).Enum; const tag = meta.activeTag(key); const s = hash(hasher, tag, strat); inline for (info.fields) |field| { - comptime var tag_value: @TagType(tag_type) = undefined; - inline for (tag_info.fields) |enum_field| { - if (comptime mem.eql(u8, field.name, enum_field.name)) - tag_value = enum_field.value; - } - if (@enumToInt(tag) == tag_value) { + if (@field(tag_type, field.name) == tag) { hash(hasher, @field(key, field.name), strat); // TODO use a labelled break when it does not crash the compiler. cf #2908 // break :blk; diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index fa5172e57f..79a12989b8 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -149,7 +149,6 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, .Union => { const info = @typeInfo(C).Union; if (info.tag_type) |TagType| { - const tag_info = @typeInfo(TagType).Enum; //we avoid duplicate iteration over the enum tags // by getting the int directly and casting it without // safety. If it is bad, it will be caught anyway. @@ -157,13 +156,7 @@ pub fn Deserializer(comptime endian: builtin.Endian, comptime packing: Packing, const tag = try self.deserializeInt(TagInt); inline for (info.fields) |field_info| { - comptime var tag_value: TagInt = undefined; - inline for (tag_info.fields) |enum_field_info| { - if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { - tag_value = enum_field_info.value; - } - } - if (tag_value == tag) { + if (@enumToInt(@field(TagType, field_info.name)) == tag) { const name = field_info.name; const FieldType = field_info.field_type; ptr.* = @unionInit(C, name, undefined); @@ -321,20 +314,13 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co .Union => { const info = @typeInfo(T).Union; if (info.tag_type) |TagType| { - const tag_info = @typeInfo(TagType).Enum; const active_tag = meta.activeTag(value); try self.serialize(active_tag); //This inline loop is necessary because active_tag is a runtime // value, but @field requires a comptime value. Our alternative // is to check each field for a match inline for (info.fields) |field_info| { - comptime var tag_value: @TagType(TagType) = undefined; - inline for (tag_info.fields) |enum_field_info| { - if (comptime std.mem.eql(u8, field_info.name, enum_field_info.name)) { - tag_value = enum_field_info.value; - } - } - if (tag_value == @enumToInt(active_tag)) { + if (@field(TagType, field_info.name) == active_tag) { const name = field_info.name; const FieldType = field_info.field_type; try self.serialize(@field(value, name)); diff --git a/lib/std/json.zig b/lib/std/json.zig index 31f8a91127..cf479ab2cd 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -1612,14 +1612,8 @@ pub fn parseFree(comptime T: type, value: T, options: ParseOptions) void { }, .Union => |unionInfo| { if (unionInfo.tag_type) |UnionTagType| { - const tag_info = @typeInfo(UnionTagType).Enum; inline for (unionInfo.fields) |u_field| { - comptime var tag_value: @TagType(UnionTagType) = undefined; - inline for (tag_info.fields) |e_field| { - if (comptime mem.eql(u8, u_field.name, e_field.name)) - tag_value = e_field.value; - } - if (@enumToInt(@as(UnionTagType, value)) == tag_value) { + if (value == @field(UnionTagType, u_field.name)) { parseFree(u_field.field_type, @field(value, u_field.name), options); break; } @@ -2463,14 +2457,8 @@ pub fn stringify( const info = @typeInfo(T).Union; if (info.tag_type) |UnionTagType| { - const tag_info = @typeInfo(UnionTagType).Enum; inline for (info.fields) |u_field| { - comptime var tag_value: @TagType(UnionTagType) = undefined; - inline for (tag_info.fields) |e_field| { - if (comptime mem.eql(u8, u_field.name, e_field.name)) - tag_value = e_field.value; - } - if (@enumToInt(@as(UnionTagType, value)) == tag_value) { + if (value == @field(UnionTagType, u_field.name)) { return try stringify(@field(value, u_field.name), options, out_stream); } } diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 8cb1ba155d..b27f168ac9 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -467,14 +467,8 @@ pub fn TagPayloadType(comptime U: type, tag: @TagType(U)) type { const info = @typeInfo(U).Union; const tag_info = @typeInfo(@TagType(U)).Enum; - comptime var name: []const u8 = undefined; - inline for (tag_info.fields) |enum_field_info| { - if (@enumToInt(tag) == enum_field_info.value) - name = enum_field_info.name; - } - inline for (info.fields) |field_info| { - if (comptime mem.eql(u8, field_info.name, name)) + if (comptime mem.eql(u8, field_info.name, @tagName(tag))) return field_info.field_type; } @@ -518,14 +512,8 @@ pub fn eql(a: anytype, b: @TypeOf(a)) bool { const tag_b = activeTag(b); if (tag_a != tag_b) return false; - const tag_info = @typeInfo(Tag).Enum; inline for (info.fields) |field_info| { - comptime var tag_value: @TagType(Tag) = undefined; - inline for (tag_info.fields) |enum_field_info| { - if (comptime mem.eql(u8, field_info.name, enum_field_info.name)) - tag_value = enum_field_info.value; - } - if (tag_value == @enumToInt(tag_a)) { + if (@field(Tag, field_info.name) == tag_a) { return eql(@field(a, field_info.name), @field(b, field_info.name)); } } From acdf1f0bde9a07cae2fbe33739f5f4aee7989f7b Mon Sep 17 00:00:00 2001 From: Tadeo Kondrak Date: Thu, 27 Aug 2020 13:34:02 -0600 Subject: [PATCH 04/14] @Type for union fixes --- src/analyze.cpp | 103 ++++++++++++++++++++-------------------- src/ir.cpp | 7 ++- test/compile_errors.zig | 57 ++++++++++++++++++++++ 3 files changed, 115 insertions(+), 52 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index b70e756f47..6086ff2bf3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2603,16 +2603,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (decl_node->type == NodeTypeContainerDecl) { assert(!enum_type->data.enumeration.fields); field_count = (uint32_t)decl_node->data.container_decl.fields.length; - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); - - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = nullptr; - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } else { - field_count = enum_type->data.enumeration.src_field_count; + field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive; + } + + if (field_count == 0) { + add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); + enum_type->data.enumeration.src_field_count = field_count; + enum_type->data.enumeration.fields = nullptr; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; } Scope *scope = &enum_type->data.enumeration.decls_scope->base; @@ -3072,18 +3072,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (decl_node->type == NodeTypeContainerDecl) { assert(union_type->data.unionation.fields == nullptr); field_count = (uint32_t)decl_node->data.container_decl.fields.length; - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } union_type->data.unionation.src_field_count = field_count; union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); union_type->data.unionation.fields_by_name.init(field_count); } else { - assert(union_type->data.unionation.fields != nullptr); field_count = union_type->data.unionation.src_field_count; + assert(field_count == 0 || union_type->data.unionation.fields != nullptr); + } + + if (field_count == 0) { + add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); + union_type->data.unionation.src_field_count = field_count; + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; } Scope *scope = &union_type->data.unionation.decls_scope->base; @@ -3217,41 +3218,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } assert(field_type_val->special != ConstValSpecialRuntime); union_field->type_val = field_type_val; - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, field_node, - buf_create_from_str( - "opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - switch (type_val_resolve_requires_comptime(g, field_type_val)) { - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; - } - - if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &is_zero_bits[i]))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { @@ -3261,6 +3227,41 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } } + if (union_field->type_val != nullptr) { + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_opaque_type) { + add_node_error(g, union_field->decl_node, + buf_create_from_str( + "opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + + switch (type_val_resolve_requires_comptime(g, union_field->type_val)) { + case ReqCompTimeInvalid: + if (g->trace_err != nullptr) { + g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node, + buf_create_from_str("while checking this field")); + } + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; + } + + if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + } + if (create_enum_type) { di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i); union_field->enum_field = &tag_type->data.enumeration.fields[i]; diff --git a/src/ir.cpp b/src/ir.cpp index 36852de706..6cb5d8bc2d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26222,14 +26222,19 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); + if (layout_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; assert(layout_value->special == ConstValSpecialStatic); assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1); + if (tag_type != nullptr && type_is_invalid(tag_type)) { + return ira->codegen->invalid_inst_gen->value->type; + } if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { ir_add_error(ira, source_instr, buf_sprintf( - "union tag type must be an enum, not %s", type_id_name(tag_type->id))); + "expected enum type, found '%s'", type_id_name(tag_type->id))); return ira->codegen->invalid_inst_gen->value->type; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 741c5fdb71..f457c74609 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -10,6 +10,63 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", }); + cases.add("@Type for union with opaque field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Untagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = null, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "foo", .field_type = @Type(.Opaque) }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = Untagged{}; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", + "tmp.zig:13:17: note: referenced here", + }); + + cases.add("@Type for union with zero fields", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Untagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = null, + \\ .fields = &[_]TypeInfo.UnionField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = Untagged{}; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: unions must have 1 or more fields", + "tmp.zig:11:17: note: referenced here", + }); + + cases.add("@Type for exhaustive enum with zero fields", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = u1, + \\ .fields = &[_]TypeInfo.EnumField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = true, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = @intToEnum(Tag, 0); + \\} + , &[_][]const u8{ + "tmp.zig:2:20: error: enums must have 1 or more fields", + "tmp.zig:12:9: note: referenced here", + }); + cases.add("@Type for tagged union with extra union field", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{ From b043a318893ad4e8de1e376ba16be6e3ed201a76 Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sat, 12 Sep 2020 23:45:35 -0700 Subject: [PATCH 05/14] added helper definitions --- lib/std/os/linux/bpf.zig | 1 + lib/std/os/linux/bpf/helpers.zig | 183 +++++++++++++++++++++++++++++++ lib/std/os/linux/bpf/kern.zig | 39 +++++++ 3 files changed, 223 insertions(+) create mode 100644 lib/std/os/linux/bpf/helpers.zig create mode 100644 lib/std/os/linux/bpf/kern.zig diff --git a/lib/std/os/linux/bpf.zig b/lib/std/os/linux/bpf.zig index be9f599d92..44c938feb8 100644 --- a/lib/std/os/linux/bpf.zig +++ b/lib/std/os/linux/bpf.zig @@ -12,6 +12,7 @@ const expectError = std.testing.expectError; const expect = std.testing.expect; pub const btf = @import("bpf/btf.zig"); +pub const kern = @import("bpf/kern.zig"); // instruction classes pub const LD = 0x00; diff --git a/lib/std/os/linux/bpf/helpers.zig b/lib/std/os/linux/bpf/helpers.zig new file mode 100644 index 0000000000..0a49885460 --- /dev/null +++ b/lib/std/os/linux/bpf/helpers.zig @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const kern = @import("kern.zig"); + +// opting to not use 'usingnamespace' because of future name collisions +const MapDef = kern.MapDef; +const SkBuff = kern.SkBuff; +const TunnelKey = kern.TunnelKey; +const XdpMd = kern.XdpMd; +const BpfSockAddr = kern.BpfSockAddr; +const FibLookup = kern.FibLookup; +const PerfEventData = kern.PerfEventData; +const PerfEventValue = kern.PerfEventValue; +const PidNsInfo = kern.PidNsInfo; +const SkLookup = kern.SkLookup; +const SkMsgBuff = kern.SkMsgBuff; +const SkReusePortMd = kern.SkReusePortMd; +const Sock = kern.Sock; +const SockAddr = kern.SockAddr; +const SockOps = kern.SockOps; +const SockTuple = kern.SockTuple; +const SpinLock = kern.SpinLock; +const SysCtl = kern.SysCtl; +const Tcp6Sock = kern.Tcp6Sock; +const TcpRequestSock = kern.TcpRequestSock; +const TcpSock = kern.TcpSock; +const TcpTimewaitSock = kern.TcpTimewaitSock; +const Udp6Sock = kern.Udp6Sock; +const XfrmState = kern.XfrmState; + +// in BPF, all the helper calls +// TODO: when https://github.com/ziglang/zig/issues/1717 is here, make a nice +// function that uses the Helper enum +// +// Note, these function signatures were created from documentation found in +// '/usr/include/linux/bpf.h' +pub const map_lookup_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void) ?*c_void, 1); +pub const map_update_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void, value: ?*const c_void, flags: u64) c_long, 2); +pub const map_delete_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void) c_long, 3); +pub const probe_read = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 4); +pub const ktime_get_ns = @intToPtr(fn () u64, 5); +pub const trace_printk = @intToPtr(fn (fmt: [*:0]const u8, fmt_size: u32, arg1: u64, arg2: u64, arg3: u64) c_long, 6); +pub const get_prandom_u32 = @intToPtr(fn () u32, 7); +pub const get_smp_processor_id = @intToPtr(fn () u32, 8); +pub const skb_store_bytes = @intToPtr(fn (skb: *SkBuff, offset: u32, from: ?*const c_void, len: u32, flags: u64) c_long, 9); +pub const l3_csum_replace = @intToPtr(fn (skb: *SkBuff, offset: u32, from: u64, to: u64, size: u64) c_long, 10); +pub const l4_csum_replace = @intToPtr(fn (skb: *SkBuff, offset: u32, from: u64, to: u64, flags: u64) c_long, 11); +pub const tail_call = @intToPtr(fn (ctx: ?*c_void, prog_array_map: *const MapDef, index: u32) c_long, 12); +pub const clone_redirect = @intToPtr(fn (skb: *SkBuff, ifindex: u32, flags: u64) c_long, 13); +pub const get_current_pid_tgid = @intToPtr(fn () u64, 14); +pub const get_current_uid_gid = @intToPtr(fn () u64, 15); +pub const get_current_comm = @intToPtr(fn (buf: ?*c_void, size_of_buf: u32) c_long, 16); +pub const get_cgroup_classid = @intToPtr(fn (skb: *SkBuff) u32, 17); +// Note vlan_proto is big endian +pub const skb_vlan_push = @intToPtr(fn (skb: *SkBuff, vlan_proto: u16, vlan_tci: u16) c_long, 18); +pub const skb_vlan_pop = @intToPtr(fn (skb: *SkBuff) c_long, 19); +pub const skb_get_tunnel_key = @intToPtr(fn (skb: *SkBuff, key: *TunnelKey, size: u32, flags: u64) c_long, 20); +pub const skb_set_tunnel_key = @intToPtr(fn (skb: *SkBuff, key: *TunnelKey, size: u32, flags: u64) c_long, 21); +pub const perf_event_read = @intToPtr(fn (map: *const MapDef, flags: u64) u64, 22); +pub const redirect = @intToPtr(fn (ifindex: u32, flags: u64) c_long, 23); +pub const get_route_realm = @intToPtr(fn (skb: *SkBuff) u32, 24); +pub const perf_event_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 25); +pub const skb_load_bytes = @intToPtr(fn (skb: ?*c_void, offset: u32, to: ?*c_void, len: u32) c_long, 26); +pub const get_stackid = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64) c_long, 27); +// from and to point to __be32 +pub const csum_diff = @intToPtr(fn (from: *u32, from_size: u32, to: *u32, to_size: u32, seed: u32) i64, 28); +pub const skb_get_tunnel_opt = @intToPtr(fn (skb: *SkBuff, opt: ?*c_void, size: u32) c_long, 29); +pub const skb_set_tunnel_opt = @intToPtr(fn (skb: *SkBuff, opt: ?*c_void, size: u32) c_long, 30); +// proto is __be16 +pub const skb_change_proto = @intToPtr(fn (skb: *SkBuff, proto: u16, flags: u64) c_long, 31); +pub const skb_change_type = @intToPtr(fn (skb: *SkBuff, skb_type: u32) c_long, 32); +pub const skb_under_cgroup = @intToPtr(fn (skb: *SkBuff, map: ?*const c_void, index: u32) c_long, 33); +pub const get_hash_recalc = @intToPtr(fn (skb: *SkBuff) u32, 34); +pub const get_current_task = @intToPtr(fn () u64, 35); +pub const probe_write_user = @intToPtr(fn (dst: ?*c_void, src: ?*const c_void, len: u32) c_long, 36); +pub const current_task_under_cgroup = @intToPtr(fn (map: *const MapDef, index: u32) c_long, 37); +pub const skb_change_tail = @intToPtr(fn (skb: *SkBuff, len: u32, flags: u64) c_long, 38); +pub const skb_pull_data = @intToPtr(fn (skb: *SkBuff, len: u32) c_long, 39); +pub const csum_update = @intToPtr(fn (skb: *SkBuff, csum: u32) i64, 40); +pub const set_hash_invalid = @intToPtr(fn (skb: *SkBuff) void, 41); +pub const get_numa_node_id = @intToPtr(fn () c_long, 42); +pub const skb_change_head = @intToPtr(fn (skb: *SkBuff, len: u32, flags: u64) c_long, 43); +pub const xdp_adjust_head = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 44); +pub const probe_read_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 45); +pub const get_socket_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 46); +pub const get_socket_uid = @intToPtr(fn (skb: *SkBuff) u32, 47); +pub const set_hash = @intToPtr(fn (skb: *SkBuff, hash: u32) c_long, 48); +pub const setsockopt = @intToPtr(fn (bpf_socket: *SockOps, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 49); +pub const skb_adjust_room = @intToPtr(fn (skb: *SkBuff, len_diff: i32, mode: u32, flags: u64) c_long, 50); +pub const redirect_map = @intToPtr(fn (map: *const MapDef, key: u32, flags: u64) c_long, 51); +pub const sk_redirect_map = @intToPtr(fn (skb: *SkBuff, map: *const MapDef, key: u32, flags: u64) c_long, 52); +pub const sock_map_update = @intToPtr(fn (skops: *SockOps, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 53); +pub const xdp_adjust_meta = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 54); +pub const perf_event_read_value = @intToPtr(fn (map: *const MapDef, flags: u64, buf: *PerfEventValue, buf_size: u32) c_long, 55); +pub const perf_prog_read_value = @intToPtr(fn (ctx: *PerfEventData, buf: *PerfEventValue, buf_size: u32) c_long, 56); +pub const getsockopt = @intToPtr(fn (bpf_socket: ?*c_void, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 57); +pub const override_return = @intToPtr(fn (regs: *PtRegs, rc: u64) c_long, 58); +pub const sock_ops_cb_flags_set = @intToPtr(fn (bpf_sock: *SockOps, argval: c_int) c_long, 59); +pub const msg_redirect_map = @intToPtr(fn (msg: *SkMsgMd, map: *const MapDef, key: u32, flags: u64) c_long, 60); +pub const msg_apply_bytes = @intToPtr(fn (msg: *SkMsgMd, bytes: u32) c_long, 61); +pub const msg_cork_bytes = @intToPtr(fn (msg: *SkMsgMd, bytes: u32) c_long, 62); +pub const msg_pull_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, end: u32, flags: u64) c_long, 63); +pub const bind = @intToPtr(fn (ctx: *BpfSockAddr, addr: *SockAddr, addr_len: c_int) c_long, 64); +pub const xdp_adjust_tail = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 65); +pub const skb_get_xfrm_state = @intToPtr(fn (skb: *SkBuff, index: u32, xfrm_state: *XfrmState, size: u32, flags: u64) c_long, 66); +pub const get_stack = @intToPtr(fn (ctx: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 67); +pub const skb_load_bytes_relative = @intToPtr(fn (skb: ?*const c_void, offset: u32, to: ?*c_void, len: u32, start_header: u32) c_long, 68); +pub const fib_lookup = @intToPtr(fn (ctx: ?*c_void, params: *FibLookup, plen: c_int, flags: u32) c_long, 69); +pub const sock_hash_update = @intToPtr(fn (skops: *SockOps, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 70); +pub const msg_redirect_hash = @intToPtr(fn (msg: *SkMsgMd, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 71); +pub const sk_redirect_hash = @intToPtr(fn (skb: *SkBuff, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 72); +pub const lwt_push_encap = @intToPtr(fn (skb: *SkBuff, typ: u32, hdr: ?*c_void, len: u32) c_long, 73); +pub const lwt_seg6_store_bytes = @intToPtr(fn (skb: *SkBuff, offset: u32, from: ?*const c_void, len: u32) c_long, 74); +pub const lwt_seg6_adjust_srh = @intToPtr(fn (skb: *SkBuff, offset: u32, delta: i32) c_long, 75); +pub const lwt_seg6_action = @intToPtr(fn (skb: *SkBuff, action: u32, param: ?*c_void, param_len: u32) c_long, 76); +pub const rc_repeat = @intToPtr(fn (ctx: ?*c_void) c_long, 77); +pub const rc_keydown = @intToPtr(fn (ctx: ?*c_void, protocol: u32, scancode: u64, toggle: u32) c_long, 78); +pub const skb_cgroup_id = @intToPtr(fn (skb: *SkBuff) u64, 79); +pub const get_current_cgroup_id = @intToPtr(fn () u64, 80); +pub const get_local_storage = @intToPtr(fn (map: ?*c_void, flags: u64) ?*c_void, 81); +pub const sk_select_reuseport = @intToPtr(fn (reuse: *SkReusePortMd, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 82); +pub const skb_ancestor_cgroup_id = @intToPtr(fn (skb: *SkBuff, ancestor_level: c_int) u64, 83); +pub const sk_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 84); +pub const sk_lookup_udp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 85); +pub const sk_release = @intToPtr(fn (sock: *Sock) c_long, 86); +pub const map_push_elem = @intToPtr(fn (map: *const MapDef, value: ?*const c_void, flags: u64) c_long, 87); +pub const map_pop_elem = @intToPtr(fn (map: *const MapDef, value: ?*c_void) c_long, 88); +pub const map_peek_elem = @intToPtr(fn (map: *const MapDef, value: ?*c_void) c_long, 89); +pub const msg_push_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, len: u32, flags: u64) c_long, 90); +pub const msg_pop_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, len: u32, flags: u64) c_long, 91); +pub const rc_pointer_rel = @intToPtr(fn (ctx: ?*c_void, rel_x: i32, rel_y: i32) c_long, 92); +pub const spin_lock = @intToPtr(fn (lock: *SpinLock) c_long, 93); +pub const spin_unlock = @intToPtr(fn (lock: *SpinLock) c_long, 94); +pub const sk_fullsock = @intToPtr(fn (sk: *Sock) ?*SkFullSock, 95); +pub const tcp_sock = @intToPtr(fn (sk: *Sock) ?*TcpSock, 96); +pub const skb_ecn_set_ce = @intToPtr(fn (skb: *SkBuff) c_long, 97); +pub const get_listener_sock = @intToPtr(fn (sk: *Sock) ?*Sock, 98); +pub const skc_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 99); +pub const tcp_check_syncookie = @intToPtr(fn (sk: *Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) c_long, 100); +pub const sysctl_get_name = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong, flags: u64) c_long, 101); +pub const sysctl_get_current_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 102); +pub const sysctl_get_new_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 103); +pub const sysctl_set_new_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*const u8, buf_len: c_ulong) c_long, 104); +pub const strtol = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_long) c_long, 105); +pub const strtoul = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_ulong) c_long, 106); +pub const sk_storage_get = @intToPtr(fn (map: *const MapDef, sk: *Sock, value: ?*c_void, flags: u64) ?*c_void, 107); +pub const sk_storage_delete = @intToPtr(fn (map: *const MapDef, sk: *Sock) c_long, 108); +pub const send_signal = @intToPtr(fn (sig: u32) c_long, 109); +pub const tcp_gen_syncookie = @intToPtr(fn (sk: *Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) i64, 110); +pub const skb_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 111); +pub const probe_read_user = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 112); +pub const probe_read_kernel = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 113); +pub const probe_read_user_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 114); +pub const probe_read_kernel_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 115); +pub const tcp_send_ack = @intToPtr(fn (tp: ?*c_void, rcv_nxt: u32) c_long, 116); +pub const send_signal_thread = @intToPtr(fn (sig: u32) c_long, 117); +pub const jiffies64 = @intToPtr(fn () u64, 118); +pub const read_branch_records = @intToPtr(fn (ctx: *PerfEventData, buf: ?*c_void, size: u32, flags: u64) c_long, 119); +pub const get_ns_current_pid_tgid = @intToPtr(fn (dev: u64, ino: u64, nsdata: *PidNsInfo, size: u32) c_long, 120); +pub const xdp_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 121); +pub const get_netns_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 122); +pub const get_current_ancestor_cgroup_id = @intToPtr(fn (ancestor_level: c_int) u64, 123); +pub const sk_assign = @intToPtr(fn (skb: *SkBuff, sk: *Sock, flags: u64) c_long, 124); +pub const ktime_get_boot_ns = @intToPtr(fn () u64, 125); +pub const seq_printf = @intToPtr(fn (m: *SeqFile, fmt: ?*const u8, fmt_size: u32, data: ?*const c_void, data_len: u32) c_long, 126); +pub const seq_write = @intToPtr(fn (m: *SeqFile, data: ?*const u8, len: u32) c_long, 127); +pub const sk_cgroup_id = @intToPtr(fn (sk: *BpfSock) u64, 128); +pub const sk_ancestor_cgroup_id = @intToPtr(fn (sk: *BpfSock, ancestor_level: c_long) u64, 129); +pub const ringbuf_output = @intToPtr(fn (ringbuf: ?*c_void, data: ?*c_void, size: u64, flags: u64) ?*c_void, 130); +pub const ringbuf_reserve = @intToPtr(fn (ringbuf: ?*c_void, size: u64, flags: u64) ?*c_void, 131); +pub const ringbuf_submit = @intToPtr(fn (data: ?*c_void, flags: u64) void, 132); +pub const ringbuf_discard = @intToPtr(fn (data: ?*c_void, flags: u64) void, 133); +pub const ringbuf_query = @intToPtr(fn (ringbuf: ?*c_void, flags: u64) u64, 134); +pub const csum_level = @intToPtr(fn (skb: *SkBuff, level: u64) c_long, 134); +pub const skc_to_tcp6_sock = @intToPtr(fn (sk: ?*c_void) ?*Tcp6Sock, 135); +pub const skc_to_tcp_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpSock, 136); +pub const skc_to_tcp_timewait_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpTimewaitSock, 137); +pub const skc_to_tcp_request_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpRequestSock, 138); +pub const skc_to_udp6_sock = @intToPtr(fn (sk: ?*c_void) ?*Udp6Sock, 139); +pub const get_task_stack = @intToPtr(fn (task: ?*TaskStruct, buf: ?*c_void, size: u32, flags: u64) c_long, 140); diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig new file mode 100644 index 0000000000..6e9b51737e --- /dev/null +++ b/lib/std/os/linux/bpf/kern.zig @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("../../../std.zig"); + +const in_bpf_program = switch (std.builtin.arch) { + .bpfel, .bpfeb => false, + else => true, +}; + +pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {}; + +// TODO: fill these in +pub const MapDef = packed struct {}; +pub const SkBuff = packed struct {}; +pub const TunnelKey = packed struct {}; +pub const XdpMd = packed struct {}; +pub const BpfSockAddr = packed struct {}; +pub const FibLookup = packed struct {}; +pub const PerfEventData = packed struct {}; +pub const PerfEventValue = packed struct {}; +pub const PidNsInfo = packed struct {}; +pub const SkLookup = packed struct {}; +pub const SkMsgBuff = packed struct {}; +pub const SkReusePortMd = packed struct {}; +pub const Sock = packed struct {}; +pub const SockAddr = packed struct {}; +pub const SockOps = packed struct {}; +pub const SockTuple = packed struct {}; +pub const SpinLock = packed struct {}; +pub const SysCtl = packed struct {}; +pub const Tcp6Sock = packed struct {}; +pub const TcpRequestSock = packed struct {}; +pub const TcpSock = packed struct {}; +pub const TcpTimewaitSock = packed struct {}; +pub const Udp6Sock = packed struct {}; +pub const XfrmState = packed struct {}; From cb5f76bb1ceb82d68c400b7330b73a8583c0613f Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sun, 13 Sep 2020 09:24:56 -0700 Subject: [PATCH 06/14] got booleans wrong --- lib/std/os/linux/bpf/kern.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig index 6e9b51737e..13b0e5b1cf 100644 --- a/lib/std/os/linux/bpf/kern.zig +++ b/lib/std/os/linux/bpf/kern.zig @@ -6,8 +6,8 @@ const std = @import("../../../std.zig"); const in_bpf_program = switch (std.builtin.arch) { - .bpfel, .bpfeb => false, - else => true, + .bpfel, .bpfeb => true, + else => false, }; pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {}; From 1afbf4fb21e516693161121cf3cb484b4c7374ef Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sun, 13 Sep 2020 09:43:49 -0700 Subject: [PATCH 07/14] removed all those kern aliases --- lib/std/os/linux/bpf/helpers.zig | 222 ++++++++++++++----------------- lib/std/os/linux/bpf/kern.zig | 13 +- 2 files changed, 105 insertions(+), 130 deletions(-) diff --git a/lib/std/os/linux/bpf/helpers.zig b/lib/std/os/linux/bpf/helpers.zig index 0a49885460..9228e1f1fd 100644 --- a/lib/std/os/linux/bpf/helpers.zig +++ b/lib/std/os/linux/bpf/helpers.zig @@ -5,152 +5,126 @@ // and substantial portions of the software. const kern = @import("kern.zig"); -// opting to not use 'usingnamespace' because of future name collisions -const MapDef = kern.MapDef; -const SkBuff = kern.SkBuff; -const TunnelKey = kern.TunnelKey; -const XdpMd = kern.XdpMd; -const BpfSockAddr = kern.BpfSockAddr; -const FibLookup = kern.FibLookup; -const PerfEventData = kern.PerfEventData; -const PerfEventValue = kern.PerfEventValue; -const PidNsInfo = kern.PidNsInfo; -const SkLookup = kern.SkLookup; -const SkMsgBuff = kern.SkMsgBuff; -const SkReusePortMd = kern.SkReusePortMd; -const Sock = kern.Sock; -const SockAddr = kern.SockAddr; -const SockOps = kern.SockOps; -const SockTuple = kern.SockTuple; -const SpinLock = kern.SpinLock; -const SysCtl = kern.SysCtl; -const Tcp6Sock = kern.Tcp6Sock; -const TcpRequestSock = kern.TcpRequestSock; -const TcpSock = kern.TcpSock; -const TcpTimewaitSock = kern.TcpTimewaitSock; -const Udp6Sock = kern.Udp6Sock; -const XfrmState = kern.XfrmState; - // in BPF, all the helper calls // TODO: when https://github.com/ziglang/zig/issues/1717 is here, make a nice // function that uses the Helper enum // // Note, these function signatures were created from documentation found in // '/usr/include/linux/bpf.h' -pub const map_lookup_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void) ?*c_void, 1); -pub const map_update_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void, value: ?*const c_void, flags: u64) c_long, 2); -pub const map_delete_elem = @intToPtr(fn (map: *const MapDef, key: ?*const c_void) c_long, 3); +pub const map_lookup_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) ?*c_void, 1); +pub const map_update_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void, value: ?*const c_void, flags: u64) c_long, 2); +pub const map_delete_elem = @intToPtr(fn (map: *const kern.MapDef, key: ?*const c_void) c_long, 3); pub const probe_read = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 4); pub const ktime_get_ns = @intToPtr(fn () u64, 5); pub const trace_printk = @intToPtr(fn (fmt: [*:0]const u8, fmt_size: u32, arg1: u64, arg2: u64, arg3: u64) c_long, 6); pub const get_prandom_u32 = @intToPtr(fn () u32, 7); pub const get_smp_processor_id = @intToPtr(fn () u32, 8); -pub const skb_store_bytes = @intToPtr(fn (skb: *SkBuff, offset: u32, from: ?*const c_void, len: u32, flags: u64) c_long, 9); -pub const l3_csum_replace = @intToPtr(fn (skb: *SkBuff, offset: u32, from: u64, to: u64, size: u64) c_long, 10); -pub const l4_csum_replace = @intToPtr(fn (skb: *SkBuff, offset: u32, from: u64, to: u64, flags: u64) c_long, 11); -pub const tail_call = @intToPtr(fn (ctx: ?*c_void, prog_array_map: *const MapDef, index: u32) c_long, 12); -pub const clone_redirect = @intToPtr(fn (skb: *SkBuff, ifindex: u32, flags: u64) c_long, 13); +pub const skb_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32, flags: u64) c_long, 9); +pub const l3_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, size: u64) c_long, 10); +pub const l4_csum_replace = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: u64, to: u64, flags: u64) c_long, 11); +pub const tail_call = @intToPtr(fn (ctx: ?*c_void, prog_array_map: *const kern.MapDef, index: u32) c_long, 12); +pub const clone_redirect = @intToPtr(fn (skb: *kern.SkBuff, ifindex: u32, flags: u64) c_long, 13); pub const get_current_pid_tgid = @intToPtr(fn () u64, 14); pub const get_current_uid_gid = @intToPtr(fn () u64, 15); pub const get_current_comm = @intToPtr(fn (buf: ?*c_void, size_of_buf: u32) c_long, 16); -pub const get_cgroup_classid = @intToPtr(fn (skb: *SkBuff) u32, 17); +pub const get_cgroup_classid = @intToPtr(fn (skb: *kern.SkBuff) u32, 17); // Note vlan_proto is big endian -pub const skb_vlan_push = @intToPtr(fn (skb: *SkBuff, vlan_proto: u16, vlan_tci: u16) c_long, 18); -pub const skb_vlan_pop = @intToPtr(fn (skb: *SkBuff) c_long, 19); -pub const skb_get_tunnel_key = @intToPtr(fn (skb: *SkBuff, key: *TunnelKey, size: u32, flags: u64) c_long, 20); -pub const skb_set_tunnel_key = @intToPtr(fn (skb: *SkBuff, key: *TunnelKey, size: u32, flags: u64) c_long, 21); -pub const perf_event_read = @intToPtr(fn (map: *const MapDef, flags: u64) u64, 22); +pub const skb_vlan_push = @intToPtr(fn (skb: *kern.SkBuff, vlan_proto: u16, vlan_tci: u16) c_long, 18); +pub const skb_vlan_pop = @intToPtr(fn (skb: *kern.SkBuff) c_long, 19); +pub const skb_get_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 20); +pub const skb_set_tunnel_key = @intToPtr(fn (skb: *kern.SkBuff, key: *kern.TunnelKey, size: u32, flags: u64) c_long, 21); +pub const perf_event_read = @intToPtr(fn (map: *const kern.MapDef, flags: u64) u64, 22); pub const redirect = @intToPtr(fn (ifindex: u32, flags: u64) c_long, 23); -pub const get_route_realm = @intToPtr(fn (skb: *SkBuff) u32, 24); -pub const perf_event_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 25); +pub const get_route_realm = @intToPtr(fn (skb: *kern.SkBuff) u32, 24); +pub const perf_event_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 25); pub const skb_load_bytes = @intToPtr(fn (skb: ?*c_void, offset: u32, to: ?*c_void, len: u32) c_long, 26); -pub const get_stackid = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64) c_long, 27); +pub const get_stackid = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64) c_long, 27); // from and to point to __be32 pub const csum_diff = @intToPtr(fn (from: *u32, from_size: u32, to: *u32, to_size: u32, seed: u32) i64, 28); -pub const skb_get_tunnel_opt = @intToPtr(fn (skb: *SkBuff, opt: ?*c_void, size: u32) c_long, 29); -pub const skb_set_tunnel_opt = @intToPtr(fn (skb: *SkBuff, opt: ?*c_void, size: u32) c_long, 30); +pub const skb_get_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 29); +pub const skb_set_tunnel_opt = @intToPtr(fn (skb: *kern.SkBuff, opt: ?*c_void, size: u32) c_long, 30); // proto is __be16 -pub const skb_change_proto = @intToPtr(fn (skb: *SkBuff, proto: u16, flags: u64) c_long, 31); -pub const skb_change_type = @intToPtr(fn (skb: *SkBuff, skb_type: u32) c_long, 32); -pub const skb_under_cgroup = @intToPtr(fn (skb: *SkBuff, map: ?*const c_void, index: u32) c_long, 33); -pub const get_hash_recalc = @intToPtr(fn (skb: *SkBuff) u32, 34); +pub const skb_change_proto = @intToPtr(fn (skb: *kern.SkBuff, proto: u16, flags: u64) c_long, 31); +pub const skb_change_type = @intToPtr(fn (skb: *kern.SkBuff, skb_type: u32) c_long, 32); +pub const skb_under_cgroup = @intToPtr(fn (skb: *kern.SkBuff, map: ?*const c_void, index: u32) c_long, 33); +pub const get_hash_recalc = @intToPtr(fn (skb: *kern.SkBuff) u32, 34); pub const get_current_task = @intToPtr(fn () u64, 35); pub const probe_write_user = @intToPtr(fn (dst: ?*c_void, src: ?*const c_void, len: u32) c_long, 36); -pub const current_task_under_cgroup = @intToPtr(fn (map: *const MapDef, index: u32) c_long, 37); -pub const skb_change_tail = @intToPtr(fn (skb: *SkBuff, len: u32, flags: u64) c_long, 38); -pub const skb_pull_data = @intToPtr(fn (skb: *SkBuff, len: u32) c_long, 39); -pub const csum_update = @intToPtr(fn (skb: *SkBuff, csum: u32) i64, 40); -pub const set_hash_invalid = @intToPtr(fn (skb: *SkBuff) void, 41); +pub const current_task_under_cgroup = @intToPtr(fn (map: *const kern.MapDef, index: u32) c_long, 37); +pub const skb_change_tail = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 38); +pub const skb_pull_data = @intToPtr(fn (skb: *kern.SkBuff, len: u32) c_long, 39); +pub const csum_update = @intToPtr(fn (skb: *kern.SkBuff, csum: u32) i64, 40); +pub const set_hash_invalid = @intToPtr(fn (skb: *kern.SkBuff) void, 41); pub const get_numa_node_id = @intToPtr(fn () c_long, 42); -pub const skb_change_head = @intToPtr(fn (skb: *SkBuff, len: u32, flags: u64) c_long, 43); -pub const xdp_adjust_head = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 44); +pub const skb_change_head = @intToPtr(fn (skb: *kern.SkBuff, len: u32, flags: u64) c_long, 43); +pub const xdp_adjust_head = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 44); pub const probe_read_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 45); pub const get_socket_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 46); -pub const get_socket_uid = @intToPtr(fn (skb: *SkBuff) u32, 47); -pub const set_hash = @intToPtr(fn (skb: *SkBuff, hash: u32) c_long, 48); -pub const setsockopt = @intToPtr(fn (bpf_socket: *SockOps, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 49); -pub const skb_adjust_room = @intToPtr(fn (skb: *SkBuff, len_diff: i32, mode: u32, flags: u64) c_long, 50); -pub const redirect_map = @intToPtr(fn (map: *const MapDef, key: u32, flags: u64) c_long, 51); -pub const sk_redirect_map = @intToPtr(fn (skb: *SkBuff, map: *const MapDef, key: u32, flags: u64) c_long, 52); -pub const sock_map_update = @intToPtr(fn (skops: *SockOps, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 53); -pub const xdp_adjust_meta = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 54); -pub const perf_event_read_value = @intToPtr(fn (map: *const MapDef, flags: u64, buf: *PerfEventValue, buf_size: u32) c_long, 55); -pub const perf_prog_read_value = @intToPtr(fn (ctx: *PerfEventData, buf: *PerfEventValue, buf_size: u32) c_long, 56); +pub const get_socket_uid = @intToPtr(fn (skb: *kern.SkBuff) u32, 47); +pub const set_hash = @intToPtr(fn (skb: *kern.SkBuff, hash: u32) c_long, 48); +pub const setsockopt = @intToPtr(fn (bpf_socket: *kern.SockOps, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 49); +pub const skb_adjust_room = @intToPtr(fn (skb: *kern.SkBuff, len_diff: i32, mode: u32, flags: u64) c_long, 50); +pub const redirect_map = @intToPtr(fn (map: *const kern.MapDef, key: u32, flags: u64) c_long, 51); +pub const sk_redirect_map = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: u32, flags: u64) c_long, 52); +pub const sock_map_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 53); +pub const xdp_adjust_meta = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 54); +pub const perf_event_read_value = @intToPtr(fn (map: *const kern.MapDef, flags: u64, buf: *kern.PerfEventValue, buf_size: u32) c_long, 55); +pub const perf_prog_read_value = @intToPtr(fn (ctx: *kern.PerfEventData, buf: *kern.PerfEventValue, buf_size: u32) c_long, 56); pub const getsockopt = @intToPtr(fn (bpf_socket: ?*c_void, level: c_int, optname: c_int, optval: ?*c_void, optlen: c_int) c_long, 57); pub const override_return = @intToPtr(fn (regs: *PtRegs, rc: u64) c_long, 58); -pub const sock_ops_cb_flags_set = @intToPtr(fn (bpf_sock: *SockOps, argval: c_int) c_long, 59); -pub const msg_redirect_map = @intToPtr(fn (msg: *SkMsgMd, map: *const MapDef, key: u32, flags: u64) c_long, 60); -pub const msg_apply_bytes = @intToPtr(fn (msg: *SkMsgMd, bytes: u32) c_long, 61); -pub const msg_cork_bytes = @intToPtr(fn (msg: *SkMsgMd, bytes: u32) c_long, 62); -pub const msg_pull_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, end: u32, flags: u64) c_long, 63); -pub const bind = @intToPtr(fn (ctx: *BpfSockAddr, addr: *SockAddr, addr_len: c_int) c_long, 64); -pub const xdp_adjust_tail = @intToPtr(fn (xdp_md: *XdpMd, delta: c_int) c_long, 65); -pub const skb_get_xfrm_state = @intToPtr(fn (skb: *SkBuff, index: u32, xfrm_state: *XfrmState, size: u32, flags: u64) c_long, 66); +pub const sock_ops_cb_flags_set = @intToPtr(fn (bpf_sock: *kern.SockOps, argval: c_int) c_long, 59); +pub const msg_redirect_map = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: u32, flags: u64) c_long, 60); +pub const msg_apply_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 61); +pub const msg_cork_bytes = @intToPtr(fn (msg: *kern.SkMsgMd, bytes: u32) c_long, 62); +pub const msg_pull_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, end: u32, flags: u64) c_long, 63); +pub const bind = @intToPtr(fn (ctx: *kern.BpfSockAddr, addr: *kern.SockAddr, addr_len: c_int) c_long, 64); +pub const xdp_adjust_tail = @intToPtr(fn (xdp_md: *kern.XdpMd, delta: c_int) c_long, 65); +pub const skb_get_xfrm_state = @intToPtr(fn (skb: *kern.SkBuff, index: u32, xfrm_state: *kern.XfrmState, size: u32, flags: u64) c_long, 66); pub const get_stack = @intToPtr(fn (ctx: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 67); pub const skb_load_bytes_relative = @intToPtr(fn (skb: ?*const c_void, offset: u32, to: ?*c_void, len: u32, start_header: u32) c_long, 68); -pub const fib_lookup = @intToPtr(fn (ctx: ?*c_void, params: *FibLookup, plen: c_int, flags: u32) c_long, 69); -pub const sock_hash_update = @intToPtr(fn (skops: *SockOps, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 70); -pub const msg_redirect_hash = @intToPtr(fn (msg: *SkMsgMd, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 71); -pub const sk_redirect_hash = @intToPtr(fn (skb: *SkBuff, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 72); -pub const lwt_push_encap = @intToPtr(fn (skb: *SkBuff, typ: u32, hdr: ?*c_void, len: u32) c_long, 73); -pub const lwt_seg6_store_bytes = @intToPtr(fn (skb: *SkBuff, offset: u32, from: ?*const c_void, len: u32) c_long, 74); -pub const lwt_seg6_adjust_srh = @intToPtr(fn (skb: *SkBuff, offset: u32, delta: i32) c_long, 75); -pub const lwt_seg6_action = @intToPtr(fn (skb: *SkBuff, action: u32, param: ?*c_void, param_len: u32) c_long, 76); +pub const fib_lookup = @intToPtr(fn (ctx: ?*c_void, params: *kern.FibLookup, plen: c_int, flags: u32) c_long, 69); +pub const sock_hash_update = @intToPtr(fn (skops: *kern.SockOps, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 70); +pub const msg_redirect_hash = @intToPtr(fn (msg: *kern.SkMsgMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 71); +pub const sk_redirect_hash = @intToPtr(fn (skb: *kern.SkBuff, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 72); +pub const lwt_push_encap = @intToPtr(fn (skb: *kern.SkBuff, typ: u32, hdr: ?*c_void, len: u32) c_long, 73); +pub const lwt_seg6_store_bytes = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, from: ?*const c_void, len: u32) c_long, 74); +pub const lwt_seg6_adjust_srh = @intToPtr(fn (skb: *kern.SkBuff, offset: u32, delta: i32) c_long, 75); +pub const lwt_seg6_action = @intToPtr(fn (skb: *kern.SkBuff, action: u32, param: ?*c_void, param_len: u32) c_long, 76); pub const rc_repeat = @intToPtr(fn (ctx: ?*c_void) c_long, 77); pub const rc_keydown = @intToPtr(fn (ctx: ?*c_void, protocol: u32, scancode: u64, toggle: u32) c_long, 78); -pub const skb_cgroup_id = @intToPtr(fn (skb: *SkBuff) u64, 79); +pub const skb_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff) u64, 79); pub const get_current_cgroup_id = @intToPtr(fn () u64, 80); pub const get_local_storage = @intToPtr(fn (map: ?*c_void, flags: u64) ?*c_void, 81); -pub const sk_select_reuseport = @intToPtr(fn (reuse: *SkReusePortMd, map: *const MapDef, key: ?*c_void, flags: u64) c_long, 82); -pub const skb_ancestor_cgroup_id = @intToPtr(fn (skb: *SkBuff, ancestor_level: c_int) u64, 83); -pub const sk_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 84); -pub const sk_lookup_udp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 85); -pub const sk_release = @intToPtr(fn (sock: *Sock) c_long, 86); -pub const map_push_elem = @intToPtr(fn (map: *const MapDef, value: ?*const c_void, flags: u64) c_long, 87); -pub const map_pop_elem = @intToPtr(fn (map: *const MapDef, value: ?*c_void) c_long, 88); -pub const map_peek_elem = @intToPtr(fn (map: *const MapDef, value: ?*c_void) c_long, 89); -pub const msg_push_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, len: u32, flags: u64) c_long, 90); -pub const msg_pop_data = @intToPtr(fn (msg: *SkMsgMd, start: u32, len: u32, flags: u64) c_long, 91); +pub const sk_select_reuseport = @intToPtr(fn (reuse: *kern.SkReusePortMd, map: *const kern.MapDef, key: ?*c_void, flags: u64) c_long, 82); +pub const skb_ancestor_cgroup_id = @intToPtr(fn (skb: *kern.SkBuff, ancestor_level: c_int) u64, 83); +pub const sk_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 84); +pub const sk_lookup_udp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 85); +pub const sk_release = @intToPtr(fn (sock: *kern.Sock) c_long, 86); +pub const map_push_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*const c_void, flags: u64) c_long, 87); +pub const map_pop_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 88); +pub const map_peek_elem = @intToPtr(fn (map: *const kern.MapDef, value: ?*c_void) c_long, 89); +pub const msg_push_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 90); +pub const msg_pop_data = @intToPtr(fn (msg: *kern.SkMsgMd, start: u32, len: u32, flags: u64) c_long, 91); pub const rc_pointer_rel = @intToPtr(fn (ctx: ?*c_void, rel_x: i32, rel_y: i32) c_long, 92); -pub const spin_lock = @intToPtr(fn (lock: *SpinLock) c_long, 93); -pub const spin_unlock = @intToPtr(fn (lock: *SpinLock) c_long, 94); -pub const sk_fullsock = @intToPtr(fn (sk: *Sock) ?*SkFullSock, 95); -pub const tcp_sock = @intToPtr(fn (sk: *Sock) ?*TcpSock, 96); -pub const skb_ecn_set_ce = @intToPtr(fn (skb: *SkBuff) c_long, 97); -pub const get_listener_sock = @intToPtr(fn (sk: *Sock) ?*Sock, 98); -pub const skc_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*Sock, 99); -pub const tcp_check_syncookie = @intToPtr(fn (sk: *Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) c_long, 100); -pub const sysctl_get_name = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong, flags: u64) c_long, 101); -pub const sysctl_get_current_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 102); -pub const sysctl_get_new_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 103); -pub const sysctl_set_new_value = @intToPtr(fn (ctx: *SysCtl, buf: ?*const u8, buf_len: c_ulong) c_long, 104); +pub const spin_lock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 93); +pub const spin_unlock = @intToPtr(fn (lock: *kern.SpinLock) c_long, 94); +pub const sk_fullsock = @intToPtr(fn (sk: *kern.Sock) ?*SkFullSock, 95); +pub const tcp_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.TcpSock, 96); +pub const skb_ecn_set_ce = @intToPtr(fn (skb: *kern.SkBuff) c_long, 97); +pub const get_listener_sock = @intToPtr(fn (sk: *kern.Sock) ?*kern.Sock, 98); +pub const skc_lookup_tcp = @intToPtr(fn (ctx: ?*c_void, tuple: *kern.SockTuple, tuple_size: u32, netns: u64, flags: u64) ?*kern.Sock, 99); +pub const tcp_check_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) c_long, 100); +pub const sysctl_get_name = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong, flags: u64) c_long, 101); +pub const sysctl_get_current_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 102); +pub const sysctl_get_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*u8, buf_len: c_ulong) c_long, 103); +pub const sysctl_set_new_value = @intToPtr(fn (ctx: *kern.SysCtl, buf: ?*const u8, buf_len: c_ulong) c_long, 104); pub const strtol = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_long) c_long, 105); pub const strtoul = @intToPtr(fn (buf: *const u8, buf_len: c_ulong, flags: u64, res: *c_ulong) c_long, 106); -pub const sk_storage_get = @intToPtr(fn (map: *const MapDef, sk: *Sock, value: ?*c_void, flags: u64) ?*c_void, 107); -pub const sk_storage_delete = @intToPtr(fn (map: *const MapDef, sk: *Sock) c_long, 108); +pub const sk_storage_get = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock, value: ?*c_void, flags: u64) ?*c_void, 107); +pub const sk_storage_delete = @intToPtr(fn (map: *const kern.MapDef, sk: *kern.Sock) c_long, 108); pub const send_signal = @intToPtr(fn (sig: u32) c_long, 109); -pub const tcp_gen_syncookie = @intToPtr(fn (sk: *Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) i64, 110); -pub const skb_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 111); +pub const tcp_gen_syncookie = @intToPtr(fn (sk: *kern.Sock, iph: ?*c_void, iph_len: u32, th: *TcpHdr, th_len: u32) i64, 110); +pub const skb_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 111); pub const probe_read_user = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 112); pub const probe_read_kernel = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 113); pub const probe_read_user_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe_ptr: ?*const c_void) c_long, 114); @@ -158,26 +132,26 @@ pub const probe_read_kernel_str = @intToPtr(fn (dst: ?*c_void, size: u32, unsafe pub const tcp_send_ack = @intToPtr(fn (tp: ?*c_void, rcv_nxt: u32) c_long, 116); pub const send_signal_thread = @intToPtr(fn (sig: u32) c_long, 117); pub const jiffies64 = @intToPtr(fn () u64, 118); -pub const read_branch_records = @intToPtr(fn (ctx: *PerfEventData, buf: ?*c_void, size: u32, flags: u64) c_long, 119); -pub const get_ns_current_pid_tgid = @intToPtr(fn (dev: u64, ino: u64, nsdata: *PidNsInfo, size: u32) c_long, 120); -pub const xdp_output = @intToPtr(fn (ctx: ?*c_void, map: *const MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 121); +pub const read_branch_records = @intToPtr(fn (ctx: *kern.PerfEventData, buf: ?*c_void, size: u32, flags: u64) c_long, 119); +pub const get_ns_current_pid_tgid = @intToPtr(fn (dev: u64, ino: u64, nsdata: *kern.PidNsInfo, size: u32) c_long, 120); +pub const xdp_output = @intToPtr(fn (ctx: ?*c_void, map: *const kern.MapDef, flags: u64, data: ?*c_void, size: u64) c_long, 121); pub const get_netns_cookie = @intToPtr(fn (ctx: ?*c_void) u64, 122); pub const get_current_ancestor_cgroup_id = @intToPtr(fn (ancestor_level: c_int) u64, 123); -pub const sk_assign = @intToPtr(fn (skb: *SkBuff, sk: *Sock, flags: u64) c_long, 124); +pub const sk_assign = @intToPtr(fn (skb: *kern.SkBuff, sk: *kern.Sock, flags: u64) c_long, 124); pub const ktime_get_boot_ns = @intToPtr(fn () u64, 125); -pub const seq_printf = @intToPtr(fn (m: *SeqFile, fmt: ?*const u8, fmt_size: u32, data: ?*const c_void, data_len: u32) c_long, 126); -pub const seq_write = @intToPtr(fn (m: *SeqFile, data: ?*const u8, len: u32) c_long, 127); -pub const sk_cgroup_id = @intToPtr(fn (sk: *BpfSock) u64, 128); -pub const sk_ancestor_cgroup_id = @intToPtr(fn (sk: *BpfSock, ancestor_level: c_long) u64, 129); +pub const seq_printf = @intToPtr(fn (m: *kern.SeqFile, fmt: ?*const u8, fmt_size: u32, data: ?*const c_void, data_len: u32) c_long, 126); +pub const seq_write = @intToPtr(fn (m: *kern.SeqFile, data: ?*const u8, len: u32) c_long, 127); +pub const sk_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock) u64, 128); +pub const sk_ancestor_cgroup_id = @intToPtr(fn (sk: *kern.BpfSock, ancestor_level: c_long) u64, 129); pub const ringbuf_output = @intToPtr(fn (ringbuf: ?*c_void, data: ?*c_void, size: u64, flags: u64) ?*c_void, 130); pub const ringbuf_reserve = @intToPtr(fn (ringbuf: ?*c_void, size: u64, flags: u64) ?*c_void, 131); pub const ringbuf_submit = @intToPtr(fn (data: ?*c_void, flags: u64) void, 132); pub const ringbuf_discard = @intToPtr(fn (data: ?*c_void, flags: u64) void, 133); pub const ringbuf_query = @intToPtr(fn (ringbuf: ?*c_void, flags: u64) u64, 134); -pub const csum_level = @intToPtr(fn (skb: *SkBuff, level: u64) c_long, 134); -pub const skc_to_tcp6_sock = @intToPtr(fn (sk: ?*c_void) ?*Tcp6Sock, 135); -pub const skc_to_tcp_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpSock, 136); -pub const skc_to_tcp_timewait_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpTimewaitSock, 137); -pub const skc_to_tcp_request_sock = @intToPtr(fn (sk: ?*c_void) ?*TcpRequestSock, 138); -pub const skc_to_udp6_sock = @intToPtr(fn (sk: ?*c_void) ?*Udp6Sock, 139); -pub const get_task_stack = @intToPtr(fn (task: ?*TaskStruct, buf: ?*c_void, size: u32, flags: u64) c_long, 140); +pub const csum_level = @intToPtr(fn (skb: *kern.SkBuff, level: u64) c_long, 134); +pub const skc_to_tcp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Tcp6Sock, 135); +pub const skc_to_tcp_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpSock, 136); +pub const skc_to_tcp_timewait_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpTimewaitSock, 137); +pub const skc_to_tcp_request_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.TcpRequestSock, 138); +pub const skc_to_udp6_sock = @intToPtr(fn (sk: ?*c_void) ?*kern.Udp6Sock, 139); +pub const get_task_stack = @intToPtr(fn (task: ?*c_void, buf: ?*c_void, size: u32, flags: u64) c_long, 140); diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig index 13b0e5b1cf..0b54b938e9 100644 --- a/lib/std/os/linux/bpf/kern.zig +++ b/lib/std/os/linux/bpf/kern.zig @@ -13,17 +13,16 @@ const in_bpf_program = switch (std.builtin.arch) { pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {}; // TODO: fill these in -pub const MapDef = packed struct {}; -pub const SkBuff = packed struct {}; -pub const TunnelKey = packed struct {}; -pub const XdpMd = packed struct {}; +pub const BpfSock = packed struct {}; pub const BpfSockAddr = packed struct {}; pub const FibLookup = packed struct {}; +pub const MapDef = packed struct {}; pub const PerfEventData = packed struct {}; pub const PerfEventValue = packed struct {}; pub const PidNsInfo = packed struct {}; -pub const SkLookup = packed struct {}; -pub const SkMsgBuff = packed struct {}; +pub const SeqFile = packed struct {}; +pub const SkBuff = packed struct {}; +pub const SkMsgMd = packed struct {}; pub const SkReusePortMd = packed struct {}; pub const Sock = packed struct {}; pub const SockAddr = packed struct {}; @@ -35,5 +34,7 @@ pub const Tcp6Sock = packed struct {}; pub const TcpRequestSock = packed struct {}; pub const TcpSock = packed struct {}; pub const TcpTimewaitSock = packed struct {}; +pub const TunnelKey = packed struct {}; pub const Udp6Sock = packed struct {}; +pub const XdpMd = packed struct {}; pub const XfrmState = packed struct {}; From 88dacd3b70118710884f53f55d5a8ec9a78f149f Mon Sep 17 00:00:00 2001 From: Matt Knight Date: Sun, 13 Sep 2020 09:53:20 -0700 Subject: [PATCH 08/14] changed to opaque --- lib/std/os/linux/bpf/kern.zig | 51 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig index 0b54b938e9..3bd605301a 100644 --- a/lib/std/os/linux/bpf/kern.zig +++ b/lib/std/os/linux/bpf/kern.zig @@ -12,29 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) { pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {}; -// TODO: fill these in -pub const BpfSock = packed struct {}; -pub const BpfSockAddr = packed struct {}; -pub const FibLookup = packed struct {}; -pub const MapDef = packed struct {}; -pub const PerfEventData = packed struct {}; -pub const PerfEventValue = packed struct {}; -pub const PidNsInfo = packed struct {}; -pub const SeqFile = packed struct {}; -pub const SkBuff = packed struct {}; -pub const SkMsgMd = packed struct {}; -pub const SkReusePortMd = packed struct {}; -pub const Sock = packed struct {}; -pub const SockAddr = packed struct {}; -pub const SockOps = packed struct {}; -pub const SockTuple = packed struct {}; -pub const SpinLock = packed struct {}; -pub const SysCtl = packed struct {}; -pub const Tcp6Sock = packed struct {}; -pub const TcpRequestSock = packed struct {}; -pub const TcpSock = packed struct {}; -pub const TcpTimewaitSock = packed struct {}; -pub const TunnelKey = packed struct {}; -pub const Udp6Sock = packed struct {}; -pub const XdpMd = packed struct {}; -pub const XfrmState = packed struct {}; +pub const BpfSock = @Type(.Opaque); +pub const BpfSockAddr = @Type(.Opaque); +pub const FibLookup = @Type(.Opaque); +pub const MapDef = @Type(.Opaque); +pub const PerfEventData = @Type(.Opaque); +pub const PerfEventValue = @Type(.Opaque); +pub const PidNsInfo = @Type(.Opaque); +pub const SeqFile = @Type(.Opaque); +pub const SkBuff = @Type(.Opaque); +pub const SkMsgMd = @Type(.Opaque); +pub const SkReusePortMd = @Type(.Opaque); +pub const Sock = @Type(.Opaque); +pub const SockAddr = @Type(.Opaque); +pub const SockOps = @Type(.Opaque); +pub const SockTuple = @Type(.Opaque); +pub const SpinLock = @Type(.Opaque); +pub const SysCtl = @Type(.Opaque); +pub const Tcp6Sock = @Type(.Opaque); +pub const TcpRequestSock = @Type(.Opaque); +pub const TcpSock = @Type(.Opaque); +pub const TcpTimewaitSock = @Type(.Opaque); +pub const TunnelKey = @Type(.Opaque); +pub const Udp6Sock = @Type(.Opaque); +pub const XdpMd = @Type(.Opaque); +pub const XfrmState = @Type(.Opaque); From 5e50d145d964238a68d4780e253d26431e7c7994 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 13 Sep 2020 09:42:00 +0200 Subject: [PATCH 09/14] std: Limit the read/write size on Darwin It turns out that the kernel won't read or write more than 0x7fffffff bytes in a single call, failing with EINVAL when trying to do so. Adjust the limit and curse whoever is responsible for this. Closes #6332 --- lib/std/os.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 91365c81dd..bdc746419a 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -320,6 +320,7 @@ pub const ReadError = error{ /// Linux has a limit on how many bytes may be transferred in one `read` call, which is `0x7ffff000` /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as /// well as stuffing the errno codes into the last `4096` values. This is noted on the `read` man page. +/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. /// For POSIX the limit is `math.maxInt(isize)`. pub fn read(fd: fd_t, buf: []u8) ReadError!usize { if (builtin.os.tag == .windows) { @@ -353,6 +354,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize { // Prevents EINVAL. const max_count = switch (std.Target.current.os.tag) { .linux => 0x7ffff000, + .macosx, .ios, .watchos, .tvos => math.maxInt(i32), else => math.maxInt(isize), }; const adjusted_len = math.min(max_count, buf.len); @@ -693,6 +695,7 @@ pub const WriteError = error{ /// Linux has a limit on how many bytes may be transferred in one `write` call, which is `0x7ffff000` /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. +/// The limit on Darwin is `0x7fffffff`, trying to read more than that returns EINVAL. /// The corresponding POSIX limit is `math.maxInt(isize)`. pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { if (builtin.os.tag == .windows) { @@ -726,6 +729,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize { const max_count = switch (std.Target.current.os.tag) { .linux => 0x7ffff000, + .macosx, .ios, .watchos, .tvos => math.maxInt(i32), else => math.maxInt(isize), }; const adjusted_len = math.min(max_count, bytes.len); @@ -851,6 +855,7 @@ pub const PWriteError = WriteError || error{Unseekable}; /// Linux has a limit on how many bytes may be transferred in one `pwrite` call, which is `0x7ffff000` /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as /// well as stuffing the errno codes into the last `4096` values. This is noted on the `write` man page. +/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. /// The corresponding POSIX limit is `math.maxInt(isize)`. pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { if (std.Target.current.os.tag == .windows) { @@ -888,6 +893,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize { // Prevent EINVAL. const max_count = switch (std.Target.current.os.tag) { .linux => 0x7ffff000, + .macosx, .ios, .watchos, .tvos => math.maxInt(i32), else => math.maxInt(isize), }; const adjusted_len = math.min(max_count, bytes.len); @@ -3084,7 +3090,7 @@ pub fn connect(sockfd: socket_t, sock_addr: *const sockaddr, len: socklen_t) Con .WSAECONNREFUSED => return error.ConnectionRefused, .WSAETIMEDOUT => return error.ConnectionTimedOut, .WSAEHOSTUNREACH // TODO: should we return NetworkUnreachable in this case as well? - , .WSAENETUNREACH => return error.NetworkUnreachable, + , .WSAENETUNREACH => return error.NetworkUnreachable, .WSAEFAULT => unreachable, .WSAEINVAL => unreachable, .WSAEISCONN => unreachable, @@ -4711,6 +4717,7 @@ fn count_iovec_bytes(iovs: []const iovec_const) usize { /// Linux has a limit on how many bytes may be transferred in one `sendfile` call, which is `0x7ffff000` /// on both 64-bit and 32-bit systems. This is due to using a signed C int as the return value, as /// well as stuffing the errno codes into the last `4096` values. This is cited on the `sendfile` man page. +/// The limit on Darwin is `0x7fffffff`, trying to write more than that returns EINVAL. /// The corresponding POSIX limit on this is `math.maxInt(isize)`. pub fn sendfile( out_fd: fd_t, @@ -4733,6 +4740,7 @@ pub fn sendfile( }); const max_count = switch (std.Target.current.os.tag) { .linux => 0x7ffff000, + .macosx, .ios, .watchos, .tvos => math.maxInt(i32), else => math.maxInt(size_t), }; From 61e9e82bdc10110b74bdeb973cc542c7b73a4ae2 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 13 Sep 2020 21:12:21 +0200 Subject: [PATCH 10/14] std: Make the CRC32 calculation slightly faster Speed up a little the slicing-by-8 code path by replacing the (load+shift+xor)*4 sequence with a single u32 load plus a xor. Before: ``` iterative: 1018 MiB/s [000000006c3b110d] small keys: 1075 MiB/s [0035bf3dcac00000] ``` After: ``` iterative: 1114 MiB/s [000000006c3b110d] small keys: 1324 MiB/s [0035bf3dcac00000] ``` --- lib/std/hash/crc.zig | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/std/hash/crc.zig b/lib/std/hash/crc.zig index 37695df8b3..6290369fca 100644 --- a/lib/std/hash/crc.zig +++ b/lib/std/hash/crc.zig @@ -71,10 +71,7 @@ pub fn Crc32WithPoly(comptime poly: Polynomial) type { const p = input[i .. i + 8]; // Unrolling this way gives ~50Mb/s increase - self.crc ^= (@as(u32, p[0]) << 0); - self.crc ^= (@as(u32, p[1]) << 8); - self.crc ^= (@as(u32, p[2]) << 16); - self.crc ^= (@as(u32, p[3]) << 24); + self.crc ^= std.mem.readIntLittle(u32, p[0..4]); self.crc = lookup_tables[0][p[7]] ^ From 01c24c45093f70b5a9c1e415ed69c274cb61b303 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Sep 2020 18:22:16 -0700 Subject: [PATCH 11/14] ci: enable std lib tests for freebsd --- ci/srht/freebsd_script | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 97b869c9f9..539051f401 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -28,11 +28,7 @@ make $JOBS install release/bin/zig build test-fmt release/bin/zig build test-behavior - -# This test is disabled because it triggers "out of memory" on the sr.ht CI service. -# See https://github.com/ziglang/zig/issues/3210 -# release/bin/zig build test-std - +release/bin/zig build test-std release/bin/zig build test-compiler-rt release/bin/zig build test-compare-output release/bin/zig build test-standalone From 558e22b2d021797e4d2fb2ef7fedb38690f8beb0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Sep 2020 18:45:30 -0700 Subject: [PATCH 12/14] ci: update freebsd to use hut.lavatech.top instead of sr.ht --- .builds/freebsd.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 9b936657fa..d53ab9167d 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,7 +1,7 @@ image: freebsd/latest secrets: - - 6c60aaee-92e7-4e7d-812c-114817689b4d - - dd0bd962-7664-4d3e-b0f3-41c9ee96b8b8 + - 51bfddf5-86a6-4e01-8576-358c72a4a0a4 + - 58f8601f-dcff-4983-8e59-06b4631ca47f sources: - https://github.com/ziglang/zig tasks: From 44ef270de1b8dfd176f27adf5638ca2f36d700d5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Sep 2020 19:37:59 -0700 Subject: [PATCH 13/14] ci: use hut.lavatech.top for updating the download page --- .builds/freebsd.yml | 2 +- ci/srht/freebsd_script | 3 ++- ci/srht/on_master_success | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index d53ab9167d..37e6a65680 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -1,7 +1,7 @@ image: freebsd/latest secrets: - 51bfddf5-86a6-4e01-8576-358c72a4a0a4 - - 58f8601f-dcff-4983-8e59-06b4631ca47f + - 5cfede76-914e-4071-893e-e5e2e6ae3cea sources: - https://github.com/ziglang/zig tasks: diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 539051f401..569c5277af 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -28,7 +28,8 @@ make $JOBS install release/bin/zig build test-fmt release/bin/zig build test-behavior -release/bin/zig build test-std +# TODO get these tests passing on freebsd and re-enable +#release/bin/zig build test-std release/bin/zig build test-compiler-rt release/bin/zig build test-compare-output release/bin/zig build test-standalone diff --git a/ci/srht/on_master_success b/ci/srht/on_master_success index c5a01f3bfe..4c28d2af38 100755 --- a/ci/srht/on_master_success +++ b/ci/srht/on_master_success @@ -36,4 +36,4 @@ jq <$YML_FILE -sR '{ -H Authorization:"token $OAUTH_TOKEN" \ -H Content-Type:application/json \ -X POST \ - -d @- "https://builds.sr.ht/api/jobs" + -d @- "https://builds.hut.lavatech.top/api/jobs" From 5e39ab460073b0068d30a74488abf83333761c8d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Sep 2020 21:11:34 -0700 Subject: [PATCH 14/14] ci: disable some freebsd tests to save time --- ci/srht/freebsd_script | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 569c5277af..31aea6c3dc 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -41,7 +41,8 @@ release/bin/zig build test-translate-c release/bin/zig build test-run-translated-c # TODO disabled until we are shipping self-hosted #release/bin/zig build test-gen-h -release/bin/zig build test-compile-errors +# TODO disabled to save time and hit that 45 minute limit +#release/bin/zig build test-compile-errors release/bin/zig build docs if [ -f ~/.s3cfg ]; then