From 0ad1239522c70418990dc7b9da4e128da7cdd1d5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 3 Dec 2017 20:43:56 -0500 Subject: rework enums and unions and their relationship to each other * @enumTagName renamed to @tagName and it works on enums and union-enums * Remove the EnumTag type. Now there is only enum and union, and the tag type of a union is always an enum. * unions support specifying the tag enum type, and they support inferring an enum tag type. * Enums no longer support field types but they do support setting the tag values. Likewise union-enums when inferring an enum tag type support setting the tag values. * It is now an error for enums and unions to have 0 fields. * switch statements support union-enums closes #618 --- src/codegen.cpp | 239 ++++++++++++++++---------------------------------------- 1 file changed, 68 insertions(+), 171 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 0ac8ffb7e1..dbf4f8522b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1631,12 +1631,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed); return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); } else if (type_entry->id == TypeTableEntryIdEnum) { - if (type_entry->data.enumeration.gen_field_count == 0) { - LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); - return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); - } else { - zig_unreachable(); - } + LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); + return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); } else if (type_entry->id == TypeTableEntryIdPureError || type_entry->id == TypeTableEntryIdPointer || type_entry->id == TypeTableEntryIdBool) @@ -1920,9 +1916,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa // enum_tag to the underlying int type TypeTableEntry *int_type; if (actual_type->id == TypeTableEntryIdEnum) { - TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type; - assert(tag_type->id == TypeTableEntryIdEnumTag); - int_type = tag_type->data.enum_tag.int_type; + int_type = actual_type->data.enumeration.tag_int_type; } else { int_type = actual_type; } @@ -1946,19 +1940,11 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) { TypeTableEntry *wanted_type = instruction->base.value.type; assert(wanted_type->id == TypeTableEntryIdEnum); - TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type; - TypeTableEntry *wanted_int_type; - if (tag_type->id == TypeTableEntryIdEnumTag) { - wanted_int_type = tag_type->data.enum_tag.int_type; - } else if (tag_type->id == TypeTableEntryIdInt) { - wanted_int_type = tag_type; - } else { - zig_unreachable(); - } + TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type; LLVMValueRef target_val = ir_llvm_value(g, instruction->target); return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), - instruction->target->value.type, wanted_int_type, target_val); + instruction->target->value.type, tag_int_type, target_val); } static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) { @@ -2378,27 +2364,6 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); } -static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable, - IrInstructionEnumFieldPtr *instruction) -{ - TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type; - assert(enum_ptr_type->id == TypeTableEntryIdPointer); - TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type; - assert(enum_type->id == TypeTableEntryIdEnum); - - TypeEnumField *field = instruction->field; - - if (!type_has_bits(field->type_entry)) - return nullptr; - - LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr); - LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); - LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); - - return bitcasted_union_field_ptr; -} - static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionUnionFieldPtr *instruction) { @@ -2427,7 +2392,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref, - &field->value); + &field->enum_field->value); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, ""); @@ -2754,19 +2719,19 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, IrInstructionEnumTagName *instruction) { - TypeTableEntry *enum_tag_type = instruction->target->value.type; - assert(enum_tag_type->data.enum_tag.generate_name_table); + TypeTableEntry *enum_type = instruction->target->value.type; + assert(enum_type->id == TypeTableEntryIdEnum); + assert(enum_type->data.enumeration.generate_name_table); + TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); if (ir_want_debug_safety(g, &instruction->base)) { - TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; size_t field_count = enum_type->data.enumeration.src_field_count; - // if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly + // if the field_count can't fit in the bits of the enum_type, then it can't possibly // be the wrong value BigInt field_bi; bigint_init_unsigned(&field_bi, field_count); - TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type; if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) { LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false); add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val); @@ -2775,10 +2740,10 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable LLVMValueRef indices[] = { LLVMConstNull(g->builtin_types.entry_usize->type_ref), - gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type, + gen_widen_or_shorten(g, false, tag_int_type, g->builtin_types.entry_usize, enum_tag_value), }; - return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); + return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, ""); } static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, @@ -3352,48 +3317,24 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa return instruction->tmp_ptr; } -static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) { - TypeTableEntry *enum_type = instruction->value->value.type; - TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type; +static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) { + TypeTableEntry *union_type = instruction->value->value.type; + assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); + + TypeTableEntry *tag_type = union_type->data.unionation.tag_type; if (!type_has_bits(tag_type)) return nullptr; - LLVMValueRef enum_val = ir_llvm_value(g, instruction->value); - if (enum_type->data.enumeration.gen_field_count == 0) - return enum_val; + LLVMValueRef union_val = ir_llvm_value(g, instruction->value); + if (union_type->data.unionation.gen_field_count == 0) + return union_val; - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, ""); + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val, + union_type->data.unionation.gen_tag_index, ""); TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false); return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); } -static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) { - TypeTableEntry *enum_type = instruction->enum_type; - LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref; - - LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &instruction->field->value); - - if (enum_type->data.enumeration.gen_field_count == 0) - return tag_value; - - LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; - - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, ""); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - - TypeTableEntry *union_val_type = instruction->field->type_entry; - if (type_has_bits(union_val_type)) { - LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value); - LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, ""); - LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, - LLVMPointerType(union_val_type->type_ref, 0), ""); - - gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val); - } - - return tmp_struct_ptr; -} - static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { for (size_t i = 0; i < instruction->field_count; i += 1) { IrInstructionStructInitField *field = &instruction->fields[i]; @@ -3436,7 +3377,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref, - &type_union_field->value); + &type_union_field->enum_field->value); gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, @@ -3573,8 +3514,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_call(g, executable, (IrInstructionCall *)instruction); case IrInstructionIdStructFieldPtr: return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); - case IrInstructionIdEnumFieldPtr: - return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); case IrInstructionIdUnionFieldPtr: return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction); case IrInstructionIdAsm: @@ -3629,10 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); case IrInstructionIdErrWrapPayload: return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); - case IrInstructionIdEnumTag: - return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); - case IrInstructionIdInitEnum: - return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); + case IrInstructionIdUnionTag: + return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); case IrInstructionIdStructInit: return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdUnionInit: @@ -3768,7 +3705,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con case TypeTableEntryIdNullLit: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdPureError: - case TypeTableEntryIdEnumTag: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: @@ -3780,7 +3716,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false); case TypeTableEntryIdEnum: { - assert(type_entry->data.enumeration.gen_field_count == 0); assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr); LLVMValueRef int_val = gen_const_val(g, const_val); return LLVMConstZExt(int_val, big_int_type_ref); @@ -3852,7 +3787,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { switch (type_entry->id) { case TypeTableEntryIdInt: - case TypeTableEntryIdEnumTag: return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); case TypeTableEntryIdPureError: assert(const_val->data.x_pure_err); @@ -4015,34 +3949,48 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { ConstExprValue *payload_value = const_val->data.x_union.payload; assert(payload_value != nullptr); - if (!type_has_bits(payload_value->type)) { - return LLVMGetUndef(union_type_ref); + if (type_entry->data.unionation.gen_field_count == 0) { + if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { + return nullptr; + } else { + return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, + &const_val->data.x_union.tag); + } } - uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); - uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; - LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); - bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || - payload_value->type != type_entry->data.unionation.most_aligned_union_member; - LLVMValueRef union_value_ref; - { - if (pad_bytes == 0) { - union_value_ref = correctly_typed_value; - } else { - LLVMValueRef fields[2]; - fields[0] = correctly_typed_value; - fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); - if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { - union_value_ref = LLVMConstStruct(fields, 2, false); + bool make_unnamed_struct; + if (!type_has_bits(payload_value->type)) { + if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) + return LLVMGetUndef(type_entry->type_ref); + + union_value_ref = LLVMGetUndef(type_entry->data.unionation.most_aligned_union_member->type_ref); + make_unnamed_struct = false; + } else { + uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); + uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; + LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); + make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || + payload_value->type != type_entry->data.unionation.most_aligned_union_member; + + { + if (pad_bytes == 0) { + union_value_ref = correctly_typed_value; } else { - union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); + LLVMValueRef fields[2]; + fields[0] = correctly_typed_value; + fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); + if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { + union_value_ref = LLVMConstStruct(fields, 2, false); + } else { + union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); + } } } - } - if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { - return union_value_ref; + if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { + return union_value_ref; + } } LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, @@ -4059,55 +4007,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { } } - case TypeTableEntryIdEnum: - { - LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; - LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &const_val->data.x_enum.tag); - if (type_entry->data.enumeration.gen_field_count == 0) { - return tag_value; - } else { - LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref; - TypeEnumField *enum_field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum.tag); - assert(bigint_cmp(&enum_field->value, &const_val->data.x_enum.tag) == CmpEQ); - LLVMValueRef union_value; - - bool make_unnamed_struct; - if (type_has_bits(enum_field->type_entry)) { - uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, - enum_field->type_entry->type_ref); - uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes; - - ConstExprValue *payload_value = const_val->data.x_enum.payload; - LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); - - make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || - payload_value->type != type_entry->data.enumeration.most_aligned_union_member; - - if (pad_bytes == 0) { - union_value = correctly_typed_value; - } else { - LLVMValueRef fields[] = { - correctly_typed_value, - LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)), - }; - union_value = LLVMConstStruct(fields, 2, false); - } - } else { - make_unnamed_struct = false; - union_value = LLVMGetUndef(union_type_ref); - } - LLVMValueRef fields[2]; - fields[type_entry->data.enumeration.gen_tag_index] = tag_value; - fields[type_entry->data.enumeration.gen_union_index] = union_value; - - if (make_unnamed_struct) { - return LLVMConstStruct(fields, 2, false); - } else { - return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); - } - } - } + case TypeTableEntryIdEnum: + return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag); case TypeTableEntryIdFn: return fn_llvm_value(g, const_val->data.x_fn.fn_entry); case TypeTableEntryIdPointer: @@ -4318,9 +4220,8 @@ static void generate_enum_name_tables(CodeGen *g) { for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) { - TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i); - assert(enum_tag_type->id == TypeTableEntryIdEnumTag); - TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; + TypeTableEntry *enum_type = g->name_table_enums.at(enum_i); + assert(enum_type->id == TypeTableEntryIdEnum); size_t field_count = enum_type->data.enumeration.src_field_count; LLVMValueRef *values = allocate(field_count); @@ -4351,7 +4252,7 @@ static void generate_enum_name_tables(CodeGen *g) { LLVMSetGlobalConstant(name_table, true); LLVMSetUnnamedAddr(name_table, true); LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init))); - enum_tag_type->data.enum_tag.name_table = name_table; + enum_type->data.enumeration.name_table = name_table; } } @@ -4555,9 +4456,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdErrWrapCode) { IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; slot = &err_wrap_code_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdInitEnum) { - IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction; - slot = &init_enum_instruction->tmp_ptr; } else { zig_unreachable(); } @@ -5054,7 +4952,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2); create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); - create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); + create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); @@ -5064,7 +4962,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1); - create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); // TODO rename to memberName + create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1); create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); @@ -5681,7 +5579,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: case TypeTableEntryIdFn: - case TypeTableEntryIdEnumTag: zig_panic("TODO implement get_c_type for more types"); case TypeTableEntryIdInvalid: case TypeTableEntryIdMetaType: -- cgit v1.2.3