mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
stage2: implement opaque declarations
* Module: implement opaque type namespace lookup * Add `Type.type` for convenience * Sema: fix `validateVarType` for pointer-to-opaque * x86_64 ABI: implement support for pointers * LLVM backend: fix lowering of opaque types * Type: implement equality checking for opaques
This commit is contained in:
parent
da7fcfd158
commit
df7d6d263e
@ -708,7 +708,9 @@ pub const Decl = struct {
|
|||||||
return ty.castTag(.empty_struct).?.data;
|
return ty.castTag(.empty_struct).?.data;
|
||||||
},
|
},
|
||||||
.@"opaque" => {
|
.@"opaque" => {
|
||||||
@panic("TODO opaque types");
|
const opaque_obj = ty.cast(Type.Payload.Opaque).?.data;
|
||||||
|
assert(opaque_obj.owner_decl == decl);
|
||||||
|
return &opaque_obj.namespace;
|
||||||
},
|
},
|
||||||
.@"union", .union_tagged => {
|
.@"union", .union_tagged => {
|
||||||
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
const union_obj = ty.cast(Type.Payload.Union).?.data;
|
||||||
@ -1080,6 +1082,27 @@ pub const Union = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Opaque = struct {
|
||||||
|
/// The Decl that corresponds to the opaque itself.
|
||||||
|
owner_decl: *Decl,
|
||||||
|
/// Represents the declarations inside this opaque.
|
||||||
|
namespace: Namespace,
|
||||||
|
/// Offset from `owner_decl`, points to the opaque decl AST node.
|
||||||
|
node_offset: i32,
|
||||||
|
|
||||||
|
pub fn srcLoc(self: Opaque) SrcLoc {
|
||||||
|
return .{
|
||||||
|
.file_scope = self.owner_decl.getFileScope(),
|
||||||
|
.parent_decl_node = self.owner_decl.src_node,
|
||||||
|
.lazy = .{ .node_offset = self.node_offset },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getFullyQualifiedName(s: *Opaque, gpa: *Allocator) ![:0]u8 {
|
||||||
|
return s.owner_decl.getFullyQualifiedName(gpa);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
|
/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
|
||||||
/// Extern functions do not have this data structure; they are represented by
|
/// Extern functions do not have this data structure; they are represented by
|
||||||
/// the `Decl` only, with a `Value` tag of `extern_fn`.
|
/// the `Decl` only, with a `Value` tag of `extern_fn`.
|
||||||
|
|||||||
81
src/Sema.zig
81
src/Sema.zig
@ -957,7 +957,7 @@ fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
|||||||
.struct_decl => return sema.zirStructDecl( block, extended, inst),
|
.struct_decl => return sema.zirStructDecl( block, extended, inst),
|
||||||
.enum_decl => return sema.zirEnumDecl( block, extended),
|
.enum_decl => return sema.zirEnumDecl( block, extended),
|
||||||
.union_decl => return sema.zirUnionDecl( block, extended, inst),
|
.union_decl => return sema.zirUnionDecl( block, extended, inst),
|
||||||
.opaque_decl => return sema.zirOpaqueDecl( block, extended, inst),
|
.opaque_decl => return sema.zirOpaqueDecl( block, extended),
|
||||||
.ret_ptr => return sema.zirRetPtr( block, extended),
|
.ret_ptr => return sema.zirRetPtr( block, extended),
|
||||||
.ret_type => return sema.zirRetType( block, extended),
|
.ret_type => return sema.zirRetType( block, extended),
|
||||||
.this => return sema.zirThis( block, extended),
|
.this => return sema.zirThis( block, extended),
|
||||||
@ -1432,7 +1432,7 @@ fn zirStructDecl(
|
|||||||
const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
|
const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
|
||||||
const type_name = try sema.createTypeName(block, small.name_strategy);
|
const type_name = try sema.createTypeName(block, small.name_strategy);
|
||||||
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = struct_val,
|
.val = struct_val,
|
||||||
}, type_name);
|
}, type_name);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
@ -1541,7 +1541,7 @@ fn zirEnumDecl(
|
|||||||
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
||||||
const type_name = try sema.createTypeName(block, small.name_strategy);
|
const type_name = try sema.createTypeName(block, small.name_strategy);
|
||||||
const new_decl = try mod.createAnonymousDeclNamed(block, .{
|
const new_decl = try mod.createAnonymousDeclNamed(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = enum_val,
|
.val = enum_val,
|
||||||
}, type_name);
|
}, type_name);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
@ -1731,7 +1731,7 @@ fn zirUnionDecl(
|
|||||||
const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty);
|
const union_val = try Value.Tag.ty.create(&new_decl_arena.allocator, union_ty);
|
||||||
const type_name = try sema.createTypeName(block, small.name_strategy);
|
const type_name = try sema.createTypeName(block, small.name_strategy);
|
||||||
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = union_val,
|
.val = union_val,
|
||||||
}, type_name);
|
}, type_name);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
@ -1764,14 +1764,63 @@ fn zirOpaqueDecl(
|
|||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
extended: Zir.Inst.Extended.InstData,
|
extended: Zir.Inst.Extended.InstData,
|
||||||
inst: Zir.Inst.Index,
|
|
||||||
) CompileError!Air.Inst.Ref {
|
) CompileError!Air.Inst.Ref {
|
||||||
const tracy = trace(@src());
|
const tracy = trace(@src());
|
||||||
defer tracy.end();
|
defer tracy.end();
|
||||||
|
|
||||||
_ = extended;
|
const mod = sema.mod;
|
||||||
_ = inst;
|
const gpa = sema.gpa;
|
||||||
return sema.fail(block, sema.src, "TODO implement zirOpaqueDecl", .{});
|
const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
|
||||||
|
var extra_index: usize = extended.operand;
|
||||||
|
|
||||||
|
const src: LazySrcLoc = if (small.has_src_node) blk: {
|
||||||
|
const node_offset = @bitCast(i32, sema.code.extra[extra_index]);
|
||||||
|
extra_index += 1;
|
||||||
|
break :blk .{ .node_offset = node_offset };
|
||||||
|
} else sema.src;
|
||||||
|
|
||||||
|
const decls_len = if (small.has_decls_len) blk: {
|
||||||
|
const decls_len = sema.code.extra[extra_index];
|
||||||
|
extra_index += 1;
|
||||||
|
break :blk decls_len;
|
||||||
|
} else 0;
|
||||||
|
|
||||||
|
var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
|
||||||
|
errdefer new_decl_arena.deinit();
|
||||||
|
|
||||||
|
const opaque_obj = try new_decl_arena.allocator.create(Module.Opaque);
|
||||||
|
const opaque_ty_payload = try new_decl_arena.allocator.create(Type.Payload.Opaque);
|
||||||
|
opaque_ty_payload.* = .{
|
||||||
|
.base = .{ .tag = .@"opaque" },
|
||||||
|
.data = opaque_obj,
|
||||||
|
};
|
||||||
|
const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
|
||||||
|
const opaque_val = try Value.Tag.ty.create(&new_decl_arena.allocator, opaque_ty);
|
||||||
|
const type_name = try sema.createTypeName(block, small.name_strategy);
|
||||||
|
const new_decl = try mod.createAnonymousDeclNamed(block, .{
|
||||||
|
.ty = Type.type,
|
||||||
|
.val = opaque_val,
|
||||||
|
}, type_name);
|
||||||
|
new_decl.owns_tv = true;
|
||||||
|
errdefer mod.abortAnonDecl(new_decl);
|
||||||
|
|
||||||
|
opaque_obj.* = .{
|
||||||
|
.owner_decl = new_decl,
|
||||||
|
.node_offset = src.node_offset,
|
||||||
|
.namespace = .{
|
||||||
|
.parent = block.namespace,
|
||||||
|
.ty = opaque_ty,
|
||||||
|
.file_scope = block.getFileScope(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{
|
||||||
|
&opaque_obj.namespace, new_decl, new_decl.name,
|
||||||
|
});
|
||||||
|
|
||||||
|
extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl);
|
||||||
|
|
||||||
|
try new_decl.finalizeNewArena(&new_decl_arena);
|
||||||
|
return sema.analyzeDeclVal(block, src, new_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirErrorSetDecl(
|
fn zirErrorSetDecl(
|
||||||
@ -1797,7 +1846,7 @@ fn zirErrorSetDecl(
|
|||||||
const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty);
|
const error_set_val = try Value.Tag.ty.create(&new_decl_arena.allocator, error_set_ty);
|
||||||
const type_name = try sema.createTypeName(block, name_strategy);
|
const type_name = try sema.createTypeName(block, name_strategy);
|
||||||
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
const new_decl = try sema.mod.createAnonymousDeclNamed(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = error_set_val,
|
.val = error_set_val,
|
||||||
}, type_name);
|
}, type_name);
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
@ -4278,7 +4327,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
|
|||||||
.names_len = @intCast(u32, new_names.len),
|
.names_len = @intCast(u32, new_names.len),
|
||||||
};
|
};
|
||||||
const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set);
|
const error_set_ty = try Type.Tag.error_set.create(sema.arena, new_error_set);
|
||||||
return sema.addConstant(Type.initTag(.type), try Value.Tag.ty.create(sema.arena, error_set_ty));
|
return sema.addConstant(Type.type, try Value.Tag.ty.create(sema.arena, error_set_ty));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||||
@ -10158,6 +10207,11 @@ fn validateVarType(
|
|||||||
.Null,
|
.Null,
|
||||||
=> break false,
|
=> break false,
|
||||||
|
|
||||||
|
.Pointer => {
|
||||||
|
const elem_ty = ty.childType();
|
||||||
|
if (elem_ty.zigTypeTag() == .Opaque) return;
|
||||||
|
ty = elem_ty;
|
||||||
|
},
|
||||||
.Opaque => break is_extern,
|
.Opaque => break is_extern,
|
||||||
|
|
||||||
.Optional => {
|
.Optional => {
|
||||||
@ -10165,7 +10219,8 @@ fn validateVarType(
|
|||||||
const child_ty = ty.optionalChild(&buf);
|
const child_ty = ty.optionalChild(&buf);
|
||||||
return validateVarType(sema, block, src, child_ty, is_extern);
|
return validateVarType(sema, block, src, child_ty, is_extern);
|
||||||
},
|
},
|
||||||
.Pointer, .Array, .Vector => ty = ty.elemType(),
|
.Array, .Vector => ty = ty.elemType(),
|
||||||
|
|
||||||
.ErrorUnion => ty = ty.errorUnionPayload(),
|
.ErrorUnion => ty = ty.errorUnionPayload(),
|
||||||
|
|
||||||
.Fn => @panic("TODO fn validateVarType"),
|
.Fn => @panic("TODO fn validateVarType"),
|
||||||
@ -12978,7 +13033,7 @@ fn generateUnionTagTypeNumbered(
|
|||||||
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
||||||
// TODO better type name
|
// TODO better type name
|
||||||
const new_decl = try mod.createAnonymousDecl(block, .{
|
const new_decl = try mod.createAnonymousDecl(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = enum_val,
|
.val = enum_val,
|
||||||
});
|
});
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
@ -13014,7 +13069,7 @@ fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: u32) !Type
|
|||||||
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
const enum_val = try Value.Tag.ty.create(&new_decl_arena.allocator, enum_ty);
|
||||||
// TODO better type name
|
// TODO better type name
|
||||||
const new_decl = try mod.createAnonymousDecl(block, .{
|
const new_decl = try mod.createAnonymousDecl(block, .{
|
||||||
.ty = Type.initTag(.type),
|
.ty = Type.type,
|
||||||
.val = enum_val,
|
.val = enum_val,
|
||||||
});
|
});
|
||||||
new_decl.owns_tv = true;
|
new_decl.owns_tv = true;
|
||||||
|
|||||||
@ -34,6 +34,17 @@ pub fn classifySystemV(ty: Type, target: Target) [8]Class {
|
|||||||
};
|
};
|
||||||
var result = [1]Class{.none} ** 8;
|
var result = [1]Class{.none} ** 8;
|
||||||
switch (ty.zigTypeTag()) {
|
switch (ty.zigTypeTag()) {
|
||||||
|
.Pointer => switch (ty.ptrSize()) {
|
||||||
|
.Slice => {
|
||||||
|
result[0] = .integer;
|
||||||
|
result[1] = .integer;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
result[0] = .integer;
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
},
|
||||||
.Int, .Enum, .ErrorSet => {
|
.Int, .Enum, .ErrorSet => {
|
||||||
const bits = ty.intInfo(target).bits;
|
const bits = ty.intInfo(target).bits;
|
||||||
if (bits <= 64) {
|
if (bits <= 64) {
|
||||||
|
|||||||
@ -758,11 +758,27 @@ pub const DeclGen = struct {
|
|||||||
};
|
};
|
||||||
return dg.context.structType(&fields, fields.len, .False);
|
return dg.context.structType(&fields, fields.len, .False);
|
||||||
} else {
|
} else {
|
||||||
const elem_type = try dg.llvmType(t.elemType());
|
|
||||||
const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
|
const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());
|
||||||
return elem_type.pointerType(llvm_addrspace);
|
const llvm_elem_ty = try dg.llvmType(t.childType());
|
||||||
|
return llvm_elem_ty.pointerType(llvm_addrspace);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.Opaque => {
|
||||||
|
const gop = try dg.object.type_map.getOrPut(gpa, t);
|
||||||
|
if (gop.found_existing) return gop.value_ptr.*;
|
||||||
|
|
||||||
|
// The Type memory is ephemeral; since we want to store a longer-lived
|
||||||
|
// reference, we need to copy it here.
|
||||||
|
gop.key_ptr.* = try t.copy(&dg.object.type_map_arena.allocator);
|
||||||
|
|
||||||
|
const opaque_obj = t.castTag(.@"opaque").?.data;
|
||||||
|
const name = try opaque_obj.getFullyQualifiedName(gpa);
|
||||||
|
defer gpa.free(name);
|
||||||
|
|
||||||
|
const llvm_struct_ty = dg.context.structCreateNamed(name);
|
||||||
|
gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
|
||||||
|
return llvm_struct_ty;
|
||||||
|
},
|
||||||
.Array => {
|
.Array => {
|
||||||
const elem_type = try dg.llvmType(t.elemType());
|
const elem_type = try dg.llvmType(t.elemType());
|
||||||
const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
|
const total_len = t.arrayLen() + @boolToInt(t.sentinel() != null);
|
||||||
@ -896,7 +912,6 @@ pub const DeclGen = struct {
|
|||||||
|
|
||||||
.BoundFn => @panic("TODO remove BoundFn from the language"),
|
.BoundFn => @panic("TODO remove BoundFn from the language"),
|
||||||
|
|
||||||
.Opaque,
|
|
||||||
.Frame,
|
.Frame,
|
||||||
.AnyFrame,
|
.AnyFrame,
|
||||||
.Vector,
|
.Vector,
|
||||||
|
|||||||
13
src/type.zig
13
src/type.zig
@ -571,6 +571,11 @@ pub const Type = extern union {
|
|||||||
}
|
}
|
||||||
return a.tag() == b.tag();
|
return a.tag() == b.tag();
|
||||||
},
|
},
|
||||||
|
.Opaque => {
|
||||||
|
const opaque_obj_a = a.castTag(.@"opaque").?.data;
|
||||||
|
const opaque_obj_b = b.castTag(.@"opaque").?.data;
|
||||||
|
return opaque_obj_a == opaque_obj_b;
|
||||||
|
},
|
||||||
.Union => {
|
.Union => {
|
||||||
if (a.cast(Payload.Union)) |a_payload| {
|
if (a.cast(Payload.Union)) |a_payload| {
|
||||||
if (b.cast(Payload.Union)) |b_payload| {
|
if (b.cast(Payload.Union)) |b_payload| {
|
||||||
@ -611,7 +616,6 @@ pub const Type = extern union {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
.Float => return a.tag() == b.tag(),
|
.Float => return a.tag() == b.tag(),
|
||||||
.Opaque,
|
|
||||||
.BoundFn,
|
.BoundFn,
|
||||||
.Frame,
|
.Frame,
|
||||||
=> std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
|
=> std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
|
||||||
@ -1408,6 +1412,7 @@ pub const Type = extern union {
|
|||||||
.extern_options,
|
.extern_options,
|
||||||
.@"anyframe",
|
.@"anyframe",
|
||||||
.anyframe_T,
|
.anyframe_T,
|
||||||
|
.@"opaque",
|
||||||
=> true,
|
=> true,
|
||||||
|
|
||||||
.function => !self.castTag(.function).?.data.is_generic,
|
.function => !self.castTag(.function).?.data.is_generic,
|
||||||
@ -1499,7 +1504,6 @@ pub const Type = extern union {
|
|||||||
.enum_literal,
|
.enum_literal,
|
||||||
.empty_struct,
|
.empty_struct,
|
||||||
.empty_struct_literal,
|
.empty_struct_literal,
|
||||||
.@"opaque",
|
|
||||||
.type_info,
|
.type_info,
|
||||||
.bound_fn,
|
.bound_fn,
|
||||||
=> false,
|
=> false,
|
||||||
@ -3097,7 +3101,7 @@ pub const Type = extern union {
|
|||||||
.enum_full => &self.castTag(.enum_full).?.data.namespace,
|
.enum_full => &self.castTag(.enum_full).?.data.namespace,
|
||||||
.enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace,
|
.enum_nonexhaustive => &self.castTag(.enum_nonexhaustive).?.data.namespace,
|
||||||
.empty_struct => self.castTag(.empty_struct).?.data,
|
.empty_struct => self.castTag(.empty_struct).?.data,
|
||||||
.@"opaque" => &self.castTag(.@"opaque").?.data,
|
.@"opaque" => &self.castTag(.@"opaque").?.data.namespace,
|
||||||
.@"union" => &self.castTag(.@"union").?.data.namespace,
|
.@"union" => &self.castTag(.@"union").?.data.namespace,
|
||||||
.union_tagged => &self.castTag(.union_tagged).?.data.namespace,
|
.union_tagged => &self.castTag(.union_tagged).?.data.namespace,
|
||||||
|
|
||||||
@ -3870,7 +3874,7 @@ pub const Type = extern union {
|
|||||||
|
|
||||||
pub const Opaque = struct {
|
pub const Opaque = struct {
|
||||||
base: Payload = .{ .tag = .@"opaque" },
|
base: Payload = .{ .tag = .@"opaque" },
|
||||||
data: Module.Namespace,
|
data: *Module.Opaque,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Struct = struct {
|
pub const Struct = struct {
|
||||||
@ -3904,6 +3908,7 @@ pub const Type = extern union {
|
|||||||
pub const @"usize" = initTag(.usize);
|
pub const @"usize" = initTag(.usize);
|
||||||
pub const @"comptime_int" = initTag(.comptime_int);
|
pub const @"comptime_int" = initTag(.comptime_int);
|
||||||
pub const @"void" = initTag(.void);
|
pub const @"void" = initTag(.void);
|
||||||
|
pub const @"type" = initTag(.type);
|
||||||
|
|
||||||
pub fn ptr(arena: *Allocator, d: Payload.Pointer.Data) !Type {
|
pub fn ptr(arena: *Allocator, d: Payload.Pointer.Data) !Type {
|
||||||
assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);
|
assert(d.host_size == 0 or d.bit_offset < d.host_size * 8);
|
||||||
|
|||||||
@ -188,3 +188,15 @@ fn testMemcpyMemset() !void {
|
|||||||
try expect(bar[11] == 'A');
|
try expect(bar[11] == 'A');
|
||||||
try expect(bar[19] == 'A');
|
try expect(bar[19] == 'A');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const OpaqueA = opaque {};
|
||||||
|
const OpaqueB = opaque {};
|
||||||
|
|
||||||
|
test "variable is allowed to be a pointer to an opaque type" {
|
||||||
|
var x: i32 = 1234;
|
||||||
|
_ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
|
||||||
|
}
|
||||||
|
fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
|
||||||
|
var a = ptr;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|||||||
@ -5,22 +5,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
|
|||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
test "slicing" {
|
|
||||||
var array: [20]i32 = undefined;
|
|
||||||
|
|
||||||
array[5] = 1234;
|
|
||||||
|
|
||||||
var slice = array[5..10];
|
|
||||||
|
|
||||||
if (slice.len != 5) unreachable;
|
|
||||||
|
|
||||||
const ptr = &slice[0];
|
|
||||||
if (ptr.* != 1234) unreachable;
|
|
||||||
|
|
||||||
var slice_rest = array[10..];
|
|
||||||
if (slice_rest.len != 10) unreachable;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "constant equal function pointers" {
|
test "constant equal function pointers" {
|
||||||
const alias = emptyFn;
|
const alias = emptyFn;
|
||||||
try expect(comptime x: {
|
try expect(comptime x: {
|
||||||
@ -230,15 +214,6 @@ test "opaque types" {
|
|||||||
try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
|
try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "variable is allowed to be a pointer to an opaque type" {
|
|
||||||
var x: i32 = 1234;
|
|
||||||
_ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
|
|
||||||
}
|
|
||||||
fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
|
|
||||||
var a = ptr;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
test "comptime if inside runtime while which unconditionally breaks" {
|
test "comptime if inside runtime while which unconditionally breaks" {
|
||||||
testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
||||||
comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
|
||||||
|
|||||||
@ -4,6 +4,22 @@ const expectEqualSlices = std.testing.expectEqualSlices;
|
|||||||
const expectEqual = std.testing.expectEqual;
|
const expectEqual = std.testing.expectEqual;
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
|
|
||||||
|
test "slicing" {
|
||||||
|
var array: [20]i32 = undefined;
|
||||||
|
|
||||||
|
array[5] = 1234;
|
||||||
|
|
||||||
|
var slice = array[5..10];
|
||||||
|
|
||||||
|
if (slice.len != 5) unreachable;
|
||||||
|
|
||||||
|
const ptr = &slice[0];
|
||||||
|
if (ptr.* != 1234) unreachable;
|
||||||
|
|
||||||
|
var slice_rest = array[10..];
|
||||||
|
if (slice_rest.len != 10) unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
|
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
|
||||||
const y = x[0x100..];
|
const y = x[0x100..];
|
||||||
test "compile time slice of pointer to hard coded address" {
|
test "compile time slice of pointer to hard coded address" {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user