Merge remote-tracking branch 'origin/master' into llvm7

This commit is contained in:
Andrew Kelley 2018-05-04 13:39:27 -04:00
commit 7e37d268c8
41 changed files with 5282 additions and 129 deletions

View File

@ -454,6 +454,7 @@ set(ZIG_STD_FILES
"heap.zig"
"index.zig"
"io.zig"
"json.zig"
"linked_list.zig"
"macho.zig"
"math/acos.zig"

View File

@ -4809,6 +4809,182 @@ pub const TypeId = enum {
BoundFn,
ArgTuple,
Opaque,
};
{#code_end#}
{#header_close#}
{#header_open|@typeInfo#}
<pre><code class="zig">@typeInfo(comptime T: type) -&gt; @import("builtin").TypeInfo</code></pre>
<p>
Returns information on the type. Returns a value of the following union:
</p>
{#code_begin|syntax#}
pub const TypeInfo = union(TypeId) {
Type: void,
Void: void,
Bool: void,
NoReturn: void,
Int: Int,
Float: Float,
Pointer: Pointer,
Array: Array,
Struct: Struct,
FloatLiteral: void,
IntLiteral: void,
UndefinedLiteral: void,
NullLiteral: void,
Nullable: Nullable,
ErrorUnion: ErrorUnion,
ErrorSet: ErrorSet,
Enum: Enum,
Union: Union,
Fn: Fn,
Namespace: void,
Block: void,
BoundFn: Fn,
ArgTuple: void,
Opaque: void,
Promise: Promise,
pub const Int = struct {
is_signed: bool,
bits: u8,
};
pub const Float = struct {
bits: u8,
};
pub const Pointer = struct {
is_const: bool,
is_volatile: bool,
alignment: u32,
child: type,
};
pub const Array = struct {
len: usize,
child: type,
};
pub const ContainerLayout = enum {
Auto,
Extern,
Packed,
};
pub const StructField = struct {
name: []const u8,
offset: ?usize,
field_type: type,
};
pub const Struct = struct {
layout: ContainerLayout,
fields: []StructField,
defs: []Definition,
};
pub const Nullable = struct {
child: type,
};
pub const ErrorUnion = struct {
error_set: type,
payload: type,
};
pub const Error = struct {
name: []const u8,
value: usize,
};
pub const ErrorSet = struct {
errors: []Error,
};
pub const EnumField = struct {
name: []const u8,
value: usize,
};
pub const Enum = struct {
layout: ContainerLayout,
tag_type: type,
fields: []EnumField,
defs: []Definition,
};
pub const UnionField = struct {
name: []const u8,
enum_field: ?EnumField,
field_type: type,
};
pub const Union = struct {
layout: ContainerLayout,
tag_type: type,
fields: []UnionField,
defs: []Definition,
};
pub const CallingConvention = enum {
Unspecified,
C,
Cold,
Naked,
Stdcall,
Async,
};
pub const FnArg = struct {
is_generic: bool,
is_noalias: bool,
arg_type: type,
};
pub const Fn = struct {
calling_convention: CallingConvention,
is_generic: bool,
is_var_args: bool,
return_type: type,
async_allocator_type: type,
args: []FnArg,
};
pub const Promise = struct {
child: type,
};
pub const Definition = struct {
name: []const u8,
is_pub: bool,
data: Data,
pub const Data = union(enum) {
Type: type,
Var: type,
Fn: FnDef,
pub const FnDef = struct {
fn_type: type,
inline_type: Inline,
calling_convention: CallingConvention,
is_var_args: bool,
is_extern: bool,
is_export: bool,
lib_name: ?[]const u8,
return_type: type,
arg_names: [][] const u8,
pub const Inline = enum {
Auto,
Always,
Never,
};
};
};
};
};
{#code_end#}
{#header_close#}
@ -5226,7 +5402,6 @@ pub const Os = enum {
rtems,
nacl,
cnk,
bitrig,
aix,
cuda,
nvcl,
@ -5237,10 +5412,12 @@ pub const Os = enum {
watchos,
mesa3d,
contiki,
amdpal,
zen,
};
pub const Arch = enum {
armv8_3a,
armv8_2a,
armv8_1a,
armv8,
@ -5260,9 +5437,29 @@ pub const Arch = enum {
armv5,
armv5te,
armv4t,
armeb,
armebv8_3a,
armebv8_2a,
armebv8_1a,
armebv8,
armebv8r,
armebv8m_baseline,
armebv8m_mainline,
armebv7,
armebv7em,
armebv7m,
armebv7s,
armebv7k,
armebv7ve,
armebv6,
armebv6m,
armebv6k,
armebv6t2,
armebv5,
armebv5te,
armebv4t,
aarch64,
aarch64_be,
arc,
avr,
bpfel,
bpfeb,
@ -5315,6 +5512,7 @@ pub const Arch = enum {
pub const Environ = enum {
unknown,
gnu,
gnuabin32,
gnuabi64,
gnueabi,
gnueabihf,
@ -5332,6 +5530,7 @@ pub const Environ = enum {
amdopencl,
coreclr,
opencl,
simulator,
};
pub const ObjectFormat = enum {
@ -5358,10 +5557,23 @@ pub const AtomicOrder = enum {
SeqCst,
};
pub const AtomicRmwOp = enum {
Xchg,
Add,
Sub,
And,
Nand,
Or,
Xor,
Max,
Min,
};
pub const Mode = enum {
Debug,
ReleaseSafe,
ReleaseFast,
ReleaseSmall,
};
pub const TypeId = enum {
@ -5380,7 +5592,7 @@ pub const TypeId = enum {
NullLiteral,
Nullable,
ErrorUnion,
Error,
ErrorSet,
Enum,
Union,
Fn,
@ -5389,6 +5601,176 @@ pub const TypeId = enum {
BoundFn,
ArgTuple,
Opaque,
Promise,
};
pub const TypeInfo = union(TypeId) {
Type: void,
Void: void,
Bool: void,
NoReturn: void,
Int: Int,
Float: Float,
Pointer: Pointer,
Array: Array,
Struct: Struct,
FloatLiteral: void,
IntLiteral: void,
UndefinedLiteral: void,
NullLiteral: void,
Nullable: Nullable,
ErrorUnion: ErrorUnion,
ErrorSet: ErrorSet,
Enum: Enum,
Union: Union,
Fn: Fn,
Namespace: void,
Block: void,
BoundFn: Fn,
ArgTuple: void,
Opaque: void,
Promise: Promise,
pub const Int = struct {
is_signed: bool,
bits: u8,
};
pub const Float = struct {
bits: u8,
};
pub const Pointer = struct {
is_const: bool,
is_volatile: bool,
alignment: u32,
child: type,
};
pub const Array = struct {
len: usize,
child: type,
};
pub const ContainerLayout = enum {
Auto,
Extern,
Packed,
};
pub const StructField = struct {
name: []const u8,
offset: ?usize,
field_type: type,
};
pub const Struct = struct {
layout: ContainerLayout,
fields: []StructField,
defs: []Definition,
};
pub const Nullable = struct {
child: type,
};
pub const ErrorUnion = struct {
error_set: type,
payload: type,
};
pub const Error = struct {
name: []const u8,
value: usize,
};
pub const ErrorSet = struct {
errors: []Error,
};
pub const EnumField = struct {
name: []const u8,
value: usize,
};
pub const Enum = struct {
layout: ContainerLayout,
tag_type: type,
fields: []EnumField,
defs: []Definition,
};
pub const UnionField = struct {
name: []const u8,
enum_field: ?EnumField,
field_type: type,
};
pub const Union = struct {
layout: ContainerLayout,
tag_type: type,
fields: []UnionField,
defs: []Definition,
};
pub const CallingConvention = enum {
Unspecified,
C,
Cold,
Naked,
Stdcall,
Async,
};
pub const FnArg = struct {
is_generic: bool,
is_noalias: bool,
arg_type: type,
};
pub const Fn = struct {
calling_convention: CallingConvention,
is_generic: bool,
is_var_args: bool,
return_type: type,
async_allocator_type: type,
args: []FnArg,
};
pub const Promise = struct {
child: type,
};
pub const Definition = struct {
name: []const u8,
is_pub: bool,
data: Data,
pub const Data = union(enum) {
Type: type,
Var: type,
Fn: FnDef,
pub const FnDef = struct {
fn_type: type,
inline_type: Inline,
calling_convention: CallingConvention,
is_var_args: bool,
is_extern: bool,
is_export: bool,
lib_name: ?[]const u8,
return_type: type,
arg_names: [][] const u8,
pub const Inline = enum {
Auto,
Always,
Never,
};
};
};
};
};
pub const FloatMode = enum {
@ -5402,7 +5784,7 @@ pub const Endian = enum {
};
pub const endian = Endian.Little;
pub const is_test = false;
pub const is_test = true;
pub const os = Os.linux;
pub const arch = Arch.x86_64;
pub const environ = Environ.gnu;
@ -5410,6 +5792,7 @@ pub const object_format = ObjectFormat.elf;
pub const mode = Mode.Debug;
pub const link_libc = false;
pub const have_error_return_tracing = true;
pub const __zig_test_fn_slice = {}; // overwritten later
{#code_end#}
{#see_also|Build Mode#}
{#header_close#}
@ -6068,7 +6451,7 @@ hljs.registerLanguage("zig", function(t) {
a = t.IR + "\\s*\\(",
c = {
keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field",
built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo",
literal: "true false null undefined"
},
n = [e, t.CLCM, t.CBCM, s, r];

View File

@ -1293,6 +1293,7 @@ enum BuiltinFnId {
BuiltinFnIdMemberType,
BuiltinFnIdMemberName,
BuiltinFnIdField,
BuiltinFnIdTypeInfo,
BuiltinFnIdTypeof,
BuiltinFnIdAddWithOverflow,
BuiltinFnIdSubWithOverflow,
@ -1506,6 +1507,7 @@ struct CodeGen {
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
HashMap<const TypeTableEntry *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
ZigList<ImportTableEntry *> import_queue;
@ -2035,6 +2037,7 @@ enum IrInstructionId {
IrInstructionIdTagType,
IrInstructionIdFieldParentPtr,
IrInstructionIdOffsetOf,
IrInstructionIdTypeInfo,
IrInstructionIdTypeId,
IrInstructionIdSetEvalBranchQuota,
IrInstructionIdPtrTypeOf,
@ -2856,6 +2859,12 @@ struct IrInstructionOffsetOf {
IrInstruction *field_name;
};
struct IrInstructionTypeInfo {
IrInstruction base;
IrInstruction *type_value;
};
struct IrInstructionTypeId {
IrInstruction base;

View File

@ -2325,8 +2325,14 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
occupied_tag_values.init(field_count);
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
TypeTableEntry *tag_int_type;
if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
tag_int_type = get_c_int_type(g, CIntTypeInt);
} else {
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
}
// TODO: Are extern enums allowed to have an init_arg_expr?
if (decl_node->data.container_decl.init_arg_expr != nullptr) {
TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
if (type_is_invalid(wanted_tag_int_type)) {

View File

@ -728,7 +728,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
render_node_grouped(ar, field_node->data.struct_field.type);
}
if (field_node->data.struct_field.value != nullptr) {
fprintf(ar->f, "= ");
fprintf(ar->f, " = ");
render_node_grouped(ar, field_node->data.struct_field.value);
}
fprintf(ar->f, ",\n");

View File

@ -88,6 +88,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
g->exported_symbol_names.init(8);
g->external_prototypes.init(8);
g->string_literals_table.init(16);
g->type_info_cache.init(32);
g->is_test_build = false;
g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib);
buf_resize(&g->global_asm, 0);
@ -4417,6 +4418,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdDeclRef:
case IrInstructionIdSwitchVar:
case IrInstructionIdOffsetOf:
case IrInstructionIdTypeInfo:
case IrInstructionIdTypeId:
case IrInstructionIdSetEvalBranchQuota:
case IrInstructionIdPtrTypeOf:
@ -6040,6 +6042,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
create_builtin_fn(g, BuiltinFnIdField, "field", 2);
create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1);
create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
@ -6259,6 +6262,190 @@ static void define_builtin_compile_vars(CodeGen *g) {
}
buf_appendf(contents, "};\n\n");
}
{
buf_appendf(contents,
"pub const TypeInfo = union(TypeId) {\n"
" Type: void,\n"
" Void: void,\n"
" Bool: void,\n"
" NoReturn: void,\n"
" Int: Int,\n"
" Float: Float,\n"
" Pointer: Pointer,\n"
" Array: Array,\n"
" Struct: Struct,\n"
" FloatLiteral: void,\n"
" IntLiteral: void,\n"
" UndefinedLiteral: void,\n"
" NullLiteral: void,\n"
" Nullable: Nullable,\n"
" ErrorUnion: ErrorUnion,\n"
" ErrorSet: ErrorSet,\n"
" Enum: Enum,\n"
" Union: Union,\n"
" Fn: Fn,\n"
" Namespace: void,\n"
" Block: void,\n"
" BoundFn: Fn,\n"
" ArgTuple: void,\n"
" Opaque: void,\n"
" Promise: Promise,\n"
"\n\n"
" pub const Int = struct {\n"
" is_signed: bool,\n"
" bits: u8,\n"
" };\n"
"\n"
" pub const Float = struct {\n"
" bits: u8,\n"
" };\n"
"\n"
" pub const Pointer = struct {\n"
" is_const: bool,\n"
" is_volatile: bool,\n"
" alignment: u32,\n"
" child: type,\n"
" };\n"
"\n"
" pub const Array = struct {\n"
" len: usize,\n"
" child: type,\n"
" };\n"
"\n"
" pub const ContainerLayout = enum {\n"
" Auto,\n"
" Extern,\n"
" Packed,\n"
" };\n"
"\n"
" pub const StructField = struct {\n"
" name: []const u8,\n"
" offset: ?usize,\n"
" field_type: type,\n"
" };\n"
"\n"
" pub const Struct = struct {\n"
" layout: ContainerLayout,\n"
" fields: []StructField,\n"
" defs: []Definition,\n"
" };\n"
"\n"
" pub const Nullable = struct {\n"
" child: type,\n"
" };\n"
"\n"
" pub const ErrorUnion = struct {\n"
" error_set: type,\n"
" payload: type,\n"
" };\n"
"\n"
" pub const Error = struct {\n"
" name: []const u8,\n"
" value: usize,\n"
" };\n"
"\n"
" pub const ErrorSet = struct {\n"
" errors: []Error,\n"
" };\n"
"\n"
" pub const EnumField = struct {\n"
" name: []const u8,\n"
" value: usize,\n"
" };\n"
"\n"
" pub const Enum = struct {\n"
" layout: ContainerLayout,\n"
" tag_type: type,\n"
" fields: []EnumField,\n"
" defs: []Definition,\n"
" };\n"
"\n"
" pub const UnionField = struct {\n"
" name: []const u8,\n"
" enum_field: ?EnumField,\n"
" field_type: type,\n"
" };\n"
"\n"
" pub const Union = struct {\n"
" layout: ContainerLayout,\n"
" tag_type: type,\n"
" fields: []UnionField,\n"
" defs: []Definition,\n"
" };\n"
"\n"
" pub const CallingConvention = enum {\n"
" Unspecified,\n"
" C,\n"
" Cold,\n"
" Naked,\n"
" Stdcall,\n"
" Async,\n"
" };\n"
"\n"
" pub const FnArg = struct {\n"
" is_generic: bool,\n"
" is_noalias: bool,\n"
" arg_type: type,\n"
" };\n"
"\n"
" pub const Fn = struct {\n"
" calling_convention: CallingConvention,\n"
" is_generic: bool,\n"
" is_var_args: bool,\n"
" return_type: type,\n"
" async_allocator_type: type,\n"
" args: []FnArg,\n"
" };\n"
"\n"
" pub const Promise = struct {\n"
" child: type,\n"
" };\n"
"\n"
" pub const Definition = struct {\n"
" name: []const u8,\n"
" is_pub: bool,\n"
" data: Data,\n"
"\n"
" pub const Data = union(enum) {\n"
" Type: type,\n"
" Var: type,\n"
" Fn: FnDef,\n"
"\n"
" pub const FnDef = struct {\n"
" fn_type: type,\n"
" inline_type: Inline,\n"
" calling_convention: CallingConvention,\n"
" is_var_args: bool,\n"
" is_extern: bool,\n"
" is_export: bool,\n"
" lib_name: ?[]const u8,\n"
" return_type: type,\n"
" arg_names: [][] const u8,\n"
"\n"
" pub const Inline = enum {\n"
" Auto,\n"
" Always,\n"
" Never,\n"
" };\n"
" };\n"
" };\n"
" };\n"
"};\n\n");
assert(ContainerLayoutAuto == 0);
assert(ContainerLayoutExtern == 1);
assert(ContainerLayoutPacked == 2);
assert(CallingConventionUnspecified == 0);
assert(CallingConventionC == 1);
assert(CallingConventionCold == 2);
assert(CallingConventionNaked == 3);
assert(CallingConventionStdcall == 4);
assert(CallingConventionAsync == 5);
assert(FnInlineAuto == 0);
assert(FnInlineAlways == 1);
assert(FnInlineNever == 2);
}
{
buf_appendf(contents,
"pub const FloatMode = enum {\n"

File diff suppressed because it is too large Load Diff

View File

@ -966,6 +966,12 @@ static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction)
fprintf(irp->f, ")");
}
static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) {
fprintf(irp->f, "@typeInfo(");
ir_print_other_instruction(irp, instruction->type_value);
fprintf(irp->f, ")");
}
static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) {
fprintf(irp->f, "@typeId(");
ir_print_other_instruction(irp, instruction->type_value);
@ -1536,6 +1542,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdOffsetOf:
ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction);
break;
case IrInstructionIdTypeInfo:
ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction);
break;
case IrInstructionIdTypeId:
ir_print_type_id(irp, (IrInstructionTypeId *)instruction);
break;

View File

@ -3746,6 +3746,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name);
}
bool pure_enum = true;
uint32_t field_count = 0;
for (auto it = enum_def->enumerator_begin(),
@ -3757,84 +3758,53 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
pure_enum = false;
}
}
AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation());
assert(tag_int_type);
if (pure_enum) {
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}
enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
for (auto it = enum_def->enumerator_begin(),
it_end = enum_def->enumerator_end();
it != it_end; ++it, i += 1)
{
const EnumConstantDecl *enum_const = *it;
Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
Buf *field_name;
if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
} else {
field_name = enum_val_name;
}
AstNode *field_node = trans_create_node(c, NodeTypeStructField);
field_node->data.struct_field.name = field_name;
field_node->data.struct_field.type = nullptr;
enum_node->data.container_decl.fields.items[i] = field_node;
// in C each enum value is in the global namespace. so we put them there too.
// at this point we can rely on the enum emitting successfully
if (is_anonymous) {
AstNode *lit_node = trans_create_node_unsigned(c, i);
add_global_var(c, enum_val_name, lit_node);
} else {
AstNode *field_access_node = trans_create_node_field_access(c,
trans_create_node_symbol(c, full_type_name), field_name);
add_global_var(c, enum_val_name, field_access_node);
}
}
if (is_anonymous) {
c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node);
return enum_node;
} else {
AstNode *symbol_node = trans_create_node_symbol(c, full_type_name);
add_global_weak_alias(c, bare_name, full_type_name);
add_global_var(c, full_type_name, enum_node);
c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
return enum_node;
}
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}
// TODO after issue #305 is solved, make this be an enum with tag_int_type
// as the integer type and set the custom enum values
AstNode *enum_node = tag_int_type;
// add variables for all the values with enum_node
enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
for (auto it = enum_def->enumerator_begin(),
it_end = enum_def->enumerator_end();
it != it_end; ++it)
it != it_end; ++it, i += 1)
{
const EnumConstantDecl *enum_const = *it;
Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal());
AstNode *var_node = add_global_var(c, enum_val_name, int_node);
var_node->data.variable_declaration.type = tag_int_type;
Buf *field_name;
if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) {
field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name));
} else {
field_name = enum_val_name;
}
AstNode *int_node = pure_enum && !is_anonymous ? nullptr : trans_create_node_apint(c, enum_const->getInitVal());
AstNode *field_node = trans_create_node(c, NodeTypeStructField);
field_node->data.struct_field.name = field_name;
field_node->data.struct_field.type = nullptr;
field_node->data.struct_field.value = int_node;
enum_node->data.container_decl.fields.items[i] = field_node;
// in C each enum value is in the global namespace. so we put them there too.
// at this point we can rely on the enum emitting successfully
if (is_anonymous) {
Buf *enum_val_name = buf_create_from_str(decl_name(enum_const));
add_global_var(c, enum_val_name, int_node);
} else {
AstNode *field_access_node = trans_create_node_field_access(c,
trans_create_node_symbol(c, full_type_name), field_name);
add_global_var(c, enum_val_name, field_access_node);
}
}
if (is_anonymous) {
@ -3845,7 +3815,7 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
add_global_weak_alias(c, bare_name, full_type_name);
add_global_var(c, full_type_name, enum_node);
c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node);
return symbol_node;
return enum_node;
}
}

View File

@ -44,6 +44,10 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
return l.toSliceConst()[n];
}
pub fn count(self: &const Self) usize {
return self.len;
}
/// ArrayList takes ownership of the passed in slice. The slice must have been
/// allocated with `allocator`.
/// Deinitialize with `deinit` or use `toOwnedSlice`.
@ -128,6 +132,27 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type{
return null;
return self.pop();
}
pub const Iterator = struct {
list: &const Self,
// how many items have we returned
count: usize,
pub fn next(it: &Iterator) ?T {
if (it.count >= it.list.len) return null;
const val = it.list.at(it.count);
it.count += 1;
return val;
}
pub fn reset(it: &Iterator) void {
it.count = 0;
}
};
pub fn iterator(self: &Self) Iterator {
return Iterator { .list = self, .count = 0 };
}
};
}
@ -157,6 +182,35 @@ test "basic ArrayList test" {
assert(list.len == 9);
}
test "iterator ArrayList test" {
var list = ArrayList(i32).init(debug.global_allocator);
defer list.deinit();
try list.append(1);
try list.append(2);
try list.append(3);
var count : i32 = 0;
var it = list.iterator();
while (it.next()) |next| {
assert(next == count + 1);
count += 1;
}
assert(count == 3);
assert(it.next() == null);
it.reset();
count = 0;
while (it.next()) |next| {
assert(next == count + 1);
count += 1;
if (count == 2) break;
}
it.reset();
assert(?? it.next() == 1);
}
test "insert ArrayList test" {
var list = ArrayList(i32).init(debug.global_allocator);
defer list.deinit();
@ -174,4 +228,4 @@ test "insert ArrayList test" {
const items = []const i32 { 1 };
try list.insertSlice(0, items[0..0]);
assert(list.items[0] == 5);
}
}

View File

@ -31,10 +31,10 @@ pub fn Queue(comptime T: type) type {
}
pub fn get(self: &Self) ?&Node {
var head = @atomicLoad(&Node, &self.head, AtomicOrder.Acquire);
var head = @atomicLoad(&Node, &self.head, AtomicOrder.SeqCst);
while (true) {
const node = head.next ?? return null;
head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.Release, AtomicOrder.Acquire) ?? return node;
head = @cmpxchgWeak(&Node, &self.head, head, node, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return node;
}
}
};
@ -49,14 +49,20 @@ const Context = struct {
get_count: usize,
puts_done: u8, // TODO make this a bool
};
const puts_per_thread = 10000;
// TODO add lazy evaluated build options and then put puts_per_thread behind
// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
// CI we would use a less aggressive setting since at 1 core, while we still
// want this test to pass, we need a smaller value since there is so much thrashing
// we would also use a less aggressive setting when running in valgrind
const puts_per_thread = 500;
const put_thread_count = 3;
test "std.atomic.queue" {
var direct_allocator = std.heap.DirectAllocator.init();
defer direct_allocator.deinit();
var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);
var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
defer direct_allocator.allocator.free(plenty_of_memory);
var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);

View File

@ -35,7 +35,7 @@ pub fn Stack(comptime T: type) type {
}
pub fn pop(self: &Self) ?&Node {
var root = @atomicLoad(?&Node, &self.root, AtomicOrder.Acquire);
var root = @atomicLoad(?&Node, &self.root, AtomicOrder.SeqCst);
while (true) {
root = @cmpxchgWeak(?&Node, &self.root, root, (root ?? return null).next, AtomicOrder.SeqCst, AtomicOrder.SeqCst) ?? return root;
}
@ -56,14 +56,19 @@ const Context = struct {
get_count: usize,
puts_done: u8, // TODO make this a bool
};
const puts_per_thread = 1000;
// TODO add lazy evaluated build options and then put puts_per_thread behind
// some option such as: "AggressiveMultithreadedFuzzTest". In the AppVeyor
// CI we would use a less aggressive setting since at 1 core, while we still
// want this test to pass, we need a smaller value since there is so much thrashing
// we would also use a less aggressive setting when running in valgrind
const puts_per_thread = 500;
const put_thread_count = 3;
test "std.atomic.stack" {
var direct_allocator = std.heap.DirectAllocator.init();
defer direct_allocator.deinit();
var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 64 * 1024 * 1024);
var plenty_of_memory = try direct_allocator.allocator.alloc(u8, 300 * 1024);
defer direct_allocator.allocator.free(plenty_of_memory);
var fixed_buffer_allocator = std.heap.ThreadSafeFixedBufferAllocator.init(plenty_of_memory);

View File

@ -50,7 +50,7 @@ pub const BufMap = struct {
}
pub fn count(self: &const BufMap) usize {
return self.hash_map.size;
return self.hash_map.count();
}
pub fn iterator(self: &const BufMap) BufMapHashMap.Iterator {
@ -87,4 +87,4 @@ test "BufMap" {
bufmap.delete("x");
assert(0 == bufmap.count());
}
}

View File

@ -38,7 +38,7 @@ pub const BufSet = struct {
}
pub fn count(self: &const BufSet) usize {
return self.hash_map.size;
return self.hash_map.count();
}
pub fn iterator(self: &const BufSet) BufSetHashMap.Iterator {
@ -59,4 +59,3 @@ pub const BufSet = struct {
return result;
}
};

View File

@ -54,6 +54,14 @@ pub fn HashMap(comptime K: type, comptime V: type,
}
unreachable; // no next item
}
// Reset the iterator to the initial index
pub fn reset(it: &Iterator) void {
it.count = 0;
it.index = 0;
// Resetting the modification count too
it.initial_modification_count = it.hm.modification_count;
}
};
pub fn init(allocator: &Allocator) Self {
@ -79,6 +87,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
hm.incrementModificationCount();
}
pub fn count(hm: &const Self) usize {
return hm.size;
}
/// Returns the value that was already there.
pub fn put(hm: &Self, key: K, value: &const V) !?V {
if (hm.entries.len == 0) {
@ -258,10 +270,49 @@ test "basic hash map usage" {
assert(map.get(2) == null);
}
test "iterator hash map" {
var direct_allocator = std.heap.DirectAllocator.init();
defer direct_allocator.deinit();
var reset_map = HashMap(i32, i32, hash_i32, eql_i32).init(&direct_allocator.allocator);
defer reset_map.deinit();
assert((reset_map.put(1, 11) catch unreachable) == null);
assert((reset_map.put(2, 22) catch unreachable) == null);
assert((reset_map.put(3, 33) catch unreachable) == null);
var keys = []i32 { 1, 2, 3 };
var values = []i32 { 11, 22, 33 };
var it = reset_map.iterator();
var count : usize = 0;
while (it.next()) |next| {
assert(next.key == keys[count]);
assert(next.value == values[count]);
count += 1;
}
assert(count == 3);
assert(it.next() == null);
it.reset();
count = 0;
while (it.next()) |next| {
assert(next.key == keys[count]);
assert(next.value == values[count]);
count += 1;
if (count == 2) break;
}
it.reset();
var entry = ?? it.next();
assert(entry.key == keys[0]);
assert(entry.value == values[0]);
}
fn hash_i32(x: i32) u32 {
return @bitCast(u32, x);
}
fn eql_i32(a: i32, b: i32) bool {
return a == b;
}
}

View File

@ -23,6 +23,7 @@ pub const fmt = @import("fmt/index.zig");
pub const hash = @import("hash/index.zig");
pub const heap = @import("heap.zig");
pub const io = @import("io.zig");
pub const json = @import("json.zig");
pub const macho = @import("macho.zig");
pub const math = @import("math/index.zig");
pub const mem = @import("mem.zig");
@ -56,6 +57,7 @@ test "std" {
_ = @import("fmt/index.zig");
_ = @import("hash/index.zig");
_ = @import("io.zig");
_ = @import("json.zig");
_ = @import("macho.zig");
_ = @import("math/index.zig");
_ = @import("mem.zig");

1304
std/json.zig Normal file

File diff suppressed because it is too large Load Diff

1942
std/json_test.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2477,6 +2477,7 @@ pub const Thread = struct {
},
builtin.Os.windows => {
assert(windows.WaitForSingleObject(self.data.handle, windows.INFINITE) == windows.WAIT_OBJECT_0);
assert(windows.CloseHandle(self.data.handle) != 0);
assert(windows.HeapFree(self.data.heap_handle, 0, self.data.alloc_start) != 0);
},
else => @compileError("Unsupported OS"),

View File

@ -1,5 +1,5 @@
const is_test = @import("builtin").is_test;
const Log2Int = @import("../../math/index.zig").Log2Int;
const Log2Int = @import("std").math.Log2Int;
pub fn fixuint(comptime fp_t: type, comptime fixuint_t: type, a: fp_t) fixuint_t {
@setRuntimeSafety(is_test);

View File

@ -1,5 +1,5 @@
const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunsdfdi(a: f64, expected: u64) void {
const x = __fixunsdfdi(a);

View File

@ -1,5 +1,5 @@
const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunsdfsi(a: f64, expected: u32) void {
const x = __fixunsdfsi(a);

View File

@ -1,5 +1,5 @@
const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunsdfti(a: f64, expected: u128) void {
const x = __fixunsdfti(a);

View File

@ -1,5 +1,5 @@
const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunssfdi(a: f32, expected: u64) void {
const x = __fixunssfdi(a);

View File

@ -1,5 +1,5 @@
const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunssfsi(a: f32, expected: u32) void {
const x = __fixunssfsi(a);

View File

@ -1,5 +1,5 @@
const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunssfti(a: f32, expected: u128) void {
const x = __fixunssfti(a);

View File

@ -1,5 +1,5 @@
const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunstfdi(a: f128, expected: u64) void {
const x = __fixunstfdi(a);

View File

@ -1,5 +1,5 @@
const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunstfsi(a: f128, expected: u32) void {
const x = __fixunstfsi(a);

View File

@ -1,5 +1,5 @@
const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
const assert = @import("../../index.zig").debug.assert;
const assert = @import("std").debug.assert;
fn test__fixunstfti(a: f128, expected: u128) void {
const x = __fixunstfti(a);

View File

@ -71,7 +71,8 @@ comptime {
}
}
const assert = @import("../../index.zig").debug.assert;
const std = @import("std");
const assert = std.debug.assert;
const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
@ -80,7 +81,7 @@ const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
pub fn panic(msg: []const u8, error_return_trace: ?&builtin.StackTrace) noreturn {
@setCold(true);
if (is_test) {
@import("std").debug.panic("{}", msg);
std.debug.panic("{}", msg);
} else {
unreachable;
}

View File

@ -9,7 +9,7 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
const SingleInt = @IntType(false, @divExact(DoubleInt.bit_count, 2));
const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt);
const Log2SingleInt = @import("std").math.Log2Int(SingleInt);
const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421
const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421

View File

@ -1,3 +1,30 @@
// TODO
//if (sr > n_uword_bits - 1) // d > r
// return 0;
// TODO switch with no body
// format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
//TODO
//test "zig fmt: same-line comptime" {
// try testCanonical(
// \\test "" {
// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
// \\}
// \\
// );
//}
//TODO
//test "zig fmt: number literals" {
// try testCanonical(
// \\pub const f64_true_min = 4.94065645841246544177e-324;
// \\
// );
//}
test "zig fmt: line comments in struct initializer" {
try testCanonical(
\\fn foo() void {
@ -20,25 +47,6 @@ test "zig fmt: line comments in struct initializer" {
);
}
//TODO
//test "zig fmt: same-line comptime" {
// try testCanonical(
// \\test "" {
// \\ comptime assert(@typeId(T) == builtin.TypeId.Int); // must pass an integer to absInt
// \\}
// \\
// );
//}
//TODO
//test "zig fmt: number literals" {
// try testCanonical(
// \\pub const f64_true_min = 4.94065645841246544177e-324;
// \\
// );
//}
test "zig fmt: doc comments before struct field" {
try testCanonical(
\\pub const Allocator = struct {

View File

@ -36,6 +36,7 @@ comptime {
_ = @import("cases/pub_enum/index.zig");
_ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
_ = @import("cases/reflection.zig");
_ = @import("cases/type_info.zig");
_ = @import("cases/sizeof_and_typeof.zig");
_ = @import("cases/slice.zig");
_ = @import("cases/struct.zig");
@ -52,4 +53,5 @@ comptime {
_ = @import("cases/var_args.zig");
_ = @import("cases/void.zig");
_ = @import("cases/while.zig");
_ = @import("cases/fn_in_struct_in_comptime.zig");
}

View File

@ -219,8 +219,9 @@ async fn printTrace(p: promise->error!void) void {
std.debug.assert(e == error.Fail);
if (@errorReturnTrace()) |trace| {
assert(trace.index == 1);
} else if (builtin.mode != builtin.Mode.ReleaseFast) {
@panic("expected return trace");
} else switch (builtin.mode) {
builtin.Mode.Debug, builtin.Mode.ReleaseSafe => @panic("expected return trace"),
builtin.Mode.ReleaseFast, builtin.Mode.ReleaseSmall => {},
}
};
}

View File

@ -392,3 +392,12 @@ test "enum with 1 field but explicit tag type should still have the tag type" {
const Enum = enum(u8) { B = 2 };
comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
}
test "empty extern enum with members" {
const E = extern enum {
A,
B,
C,
};
assert(@sizeOf(E) == @sizeOf(c_int));
}

View File

@ -0,0 +1,17 @@
const assert = @import("std").debug.assert;
fn get_foo() fn(&u8)usize {
comptime {
return struct {
fn func(ptr: &u8) usize {
var u = @ptrToInt(ptr);
return u;
}
}.func;
}
}
test "define a function in an anonymous struct in comptime" {
const foo = get_foo();
assert(foo(@intToPtr(&u8, 12345)) == 12345);
}

181
test/cases/type_info.zig Normal file
View File

@ -0,0 +1,181 @@
const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const TypeInfo = @import("builtin").TypeInfo;
const TypeId = @import("builtin").TypeId;
test "type info: tag type, void info" {
comptime {
assert(@TagType(TypeInfo) == TypeId);
const void_info = @typeInfo(void);
assert(TypeId(void_info) == TypeId.Void);
assert(void_info.Void == {});
}
}
test "type info: integer, floating point type info" {
comptime {
const u8_info = @typeInfo(u8);
assert(TypeId(u8_info) == TypeId.Int);
assert(!u8_info.Int.is_signed);
assert(u8_info.Int.bits == 8);
const f64_info = @typeInfo(f64);
assert(TypeId(f64_info) == TypeId.Float);
assert(f64_info.Float.bits == 64);
}
}
test "type info: pointer, array and nullable type info" {
comptime {
const u32_ptr_info = @typeInfo(&u32);
assert(TypeId(u32_ptr_info) == TypeId.Pointer);
assert(u32_ptr_info.Pointer.is_const == false);
assert(u32_ptr_info.Pointer.is_volatile == false);
assert(u32_ptr_info.Pointer.alignment == 4);
assert(u32_ptr_info.Pointer.child == u32);
const arr_info = @typeInfo([42]bool);
assert(TypeId(arr_info) == TypeId.Array);
assert(arr_info.Array.len == 42);
assert(arr_info.Array.child == bool);
const null_info = @typeInfo(?void);
assert(TypeId(null_info) == TypeId.Nullable);
assert(null_info.Nullable.child == void);
}
}
test "type info: promise info" {
comptime {
const null_promise_info = @typeInfo(promise);
assert(TypeId(null_promise_info) == TypeId.Promise);
assert(null_promise_info.Promise.child == @typeOf(undefined));
const promise_info = @typeInfo(promise->usize);
assert(TypeId(promise_info) == TypeId.Promise);
assert(promise_info.Promise.child == usize);
}
}
test "type info: error set, error union info" {
comptime {
const TestErrorSet = error {
First,
Second,
Third,
};
const error_set_info = @typeInfo(TestErrorSet);
assert(TypeId(error_set_info) == TypeId.ErrorSet);
assert(error_set_info.ErrorSet.errors.len == 3);
assert(mem.eql(u8, error_set_info.ErrorSet.errors[0].name, "First"));
assert(error_set_info.ErrorSet.errors[2].value == usize(TestErrorSet.Third));
const error_union_info = @typeInfo(TestErrorSet!usize);
assert(TypeId(error_union_info) == TypeId.ErrorUnion);
assert(error_union_info.ErrorUnion.error_set == TestErrorSet);
assert(error_union_info.ErrorUnion.payload == usize);
}
}
test "type info: enum info" {
comptime {
const Os = @import("builtin").Os;
const os_info = @typeInfo(Os);
assert(TypeId(os_info) == TypeId.Enum);
assert(os_info.Enum.layout == TypeInfo.ContainerLayout.Auto);
assert(os_info.Enum.fields.len == 32);
assert(mem.eql(u8, os_info.Enum.fields[1].name, "ananas"));
assert(os_info.Enum.fields[10].value == 10);
assert(os_info.Enum.tag_type == u5);
assert(os_info.Enum.defs.len == 0);
}
}
test "type info: union info" {
comptime {
const typeinfo_info = @typeInfo(TypeInfo);
assert(TypeId(typeinfo_info) == TypeId.Union);
assert(typeinfo_info.Union.layout == TypeInfo.ContainerLayout.Auto);
assert(typeinfo_info.Union.tag_type == TypeId);
assert(typeinfo_info.Union.fields.len == 25);
assert(typeinfo_info.Union.fields[4].enum_field != null);
assert((??typeinfo_info.Union.fields[4].enum_field).value == 4);
assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int));
assert(typeinfo_info.Union.defs.len == 20);
const TestNoTagUnion = union {
Foo: void,
Bar: u32,
};
const notag_union_info = @typeInfo(TestNoTagUnion);
assert(TypeId(notag_union_info) == TypeId.Union);
assert(notag_union_info.Union.tag_type == @typeOf(undefined));
assert(notag_union_info.Union.layout == TypeInfo.ContainerLayout.Auto);
assert(notag_union_info.Union.fields.len == 2);
assert(notag_union_info.Union.fields[0].enum_field == null);
assert(notag_union_info.Union.fields[1].field_type == u32);
const TestExternUnion = extern union {
foo: &c_void,
};
const extern_union_info = @typeInfo(TestExternUnion);
assert(extern_union_info.Union.layout == TypeInfo.ContainerLayout.Extern);
assert(extern_union_info.Union.tag_type == @typeOf(undefined));
assert(extern_union_info.Union.fields[0].enum_field == null);
assert(extern_union_info.Union.fields[0].field_type == &c_void);
}
}
test "type info: struct info" {
comptime {
const struct_info = @typeInfo(TestStruct);
assert(TypeId(struct_info) == TypeId.Struct);
assert(struct_info.Struct.layout == TypeInfo.ContainerLayout.Packed);
assert(struct_info.Struct.fields.len == 3);
assert(struct_info.Struct.fields[1].offset == null);
assert(struct_info.Struct.fields[2].field_type == &TestStruct);
assert(struct_info.Struct.defs.len == 2);
assert(struct_info.Struct.defs[0].is_pub);
assert(!struct_info.Struct.defs[0].data.Fn.is_extern);
assert(struct_info.Struct.defs[0].data.Fn.lib_name == null);
assert(struct_info.Struct.defs[0].data.Fn.return_type == void);
assert(struct_info.Struct.defs[0].data.Fn.fn_type == fn(&const TestStruct)void);
}
}
const TestStruct = packed struct {
const Self = this;
fieldA: usize,
fieldB: void,
fieldC: &Self,
pub fn foo(self: &const Self) void {}
};
test "type info: function type info" {
comptime {
const fn_info = @typeInfo(@typeOf(foo));
assert(TypeId(fn_info) == TypeId.Fn);
assert(fn_info.Fn.calling_convention == TypeInfo.CallingConvention.Unspecified);
assert(fn_info.Fn.is_generic);
assert(fn_info.Fn.args.len == 2);
assert(fn_info.Fn.is_var_args);
assert(fn_info.Fn.return_type == @typeOf(undefined));
assert(fn_info.Fn.async_allocator_type == @typeOf(undefined));
const test_instance: TestStruct = undefined;
const bound_fn_info = @typeInfo(@typeOf(test_instance.foo));
assert(TypeId(bound_fn_info) == TypeId.BoundFn);
assert(bound_fn_info.BoundFn.args[0].arg_type == &const TestStruct);
}
}
fn foo(comptime a: usize, b: bool, args: ...) usize {
return 0;
}

View File

@ -45,6 +45,16 @@ test "basic unions" {
assert(foo.float == 12.34);
}
test "comptime union field access" {
comptime {
var foo = Foo { .int = 0 };
assert(foo.int == 0);
foo = Foo { .float = 42.42 };
assert(foo.float == 42.42);
}
}
test "init union with runtime value" {
var foo: Foo = undefined;

View File

@ -3210,6 +3210,18 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
,
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset");
cases.add("invalid union field access in comptime",
\\const Foo = union {
\\ Bar: u8,
\\ Baz: void,
\\};
\\comptime {
\\ var foo = Foo {.Baz = {}};
\\ const bar_val = foo.Bar;
\\}
,
".tmp_source.zig:7:24: error: accessing union field 'Bar' while field 'Baz' is set");
cases.add("getting return type of generic function",
\\fn generic(a: var) void {}
\\comptime {
@ -3225,5 +3237,4 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
\\}
,
".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic");
}

View File

@ -152,7 +152,7 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
const step = b.step(b.fmt("test-{}", name), desc);
for (test_targets) |test_target| {
const is_native = (test_target.os == builtin.os and test_target.arch == builtin.arch);
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
for ([]bool{false, true}) |link_libc| {
if (link_libc and !is_native) {
// don't assume we have a cross-compiling libc set up
@ -451,7 +451,7 @@ pub const CompareOutputContext = struct {
self.step.dependOn(&run_and_cmp_output.step);
},
Special.None => {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})",
"compare-output", case.name, @tagName(mode)) catch unreachable;
if (self.test_filter) |filter| {
@ -705,7 +705,7 @@ pub const CompileErrorContext = struct {
pub fn addCase(self: &CompileErrorContext, case: &const TestCase) void {
const b = self.b;
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
for ([]Mode{Mode.Debug, Mode.ReleaseFast}) |mode| {
const annotated_case_name = fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
case.name, @tagName(mode)) catch unreachable;
if (self.test_filter) |filter| {
@ -773,7 +773,7 @@ pub const BuildExamplesContext = struct {
pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) void {
const b = self.b;
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast, Mode.ReleaseSmall}) |mode| {
const annotated_case_name = fmt.allocPrint(self.b.allocator, "build {} ({})",
root_src, @tagName(mode)) catch unreachable;
if (self.test_filter) |filter| {

View File

@ -53,6 +53,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
\\pub const Foo = enum_Foo;
);
cases.add("enums",
\\enum Foo {
\\ FooA = 2,
\\ FooB = 5,
\\ Foo1,
\\};
,
\\pub const enum_Foo = extern enum {
\\ A = 2,
\\ B = 5,
\\ @"1" = 6,
\\};
,
\\pub const FooA = enum_Foo.A;
,
\\pub const FooB = enum_Foo.B;
,
\\pub const Foo1 = enum_Foo.@"1";
,
\\pub const Foo = enum_Foo;
);
cases.add("restrict -> noalias",
\\void foo(void *restrict bar, void *restrict);
,