authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-07 16:58:50-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-10-07 16:58:50-04:00
log95a37373e9f576854956c2909cc128b5b6388ec6
tree647f62398f1afbc0546d223b05203e6c69372ba2
parent3c43eeceab70f78939401b68811f152a7f29b191
parentbf4bfe54ac13512d7553a7be83ae19e908e9c294
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6421 from tadeokondrak/opaque-syntax

Add opaque syntax that allows declarations

27 files changed, 371 insertions(+), 211 deletions(-)

doc/docgen.zig+1
...@@ -808,6 +808,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:...@@ -808,6 +808,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:
808 .Keyword_noalias,808 .Keyword_noalias,
809 .Keyword_noinline,809 .Keyword_noinline,
810 .Keyword_nosuspend,810 .Keyword_nosuspend,
811 .Keyword_opaque,
811 .Keyword_or,812 .Keyword_or,
812 .Keyword_orelse,813 .Keyword_orelse,
813 .Keyword_packed,814 .Keyword_packed,
doc/langref.html.in+11-9
...@@ -1988,7 +1988,7 @@ test "null terminated array" {...@@ -1988,7 +1988,7 @@ test "null terminated array" {
1988 <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li>1988 <li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li>
1989 <li>Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}</li>1989 <li>Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}</li>
1990 <li>{#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be1990 <li>{#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be
1991 {#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|Opaque Types#}.</li>1991 {#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|opaque#}.</li>
1992 </ul>1992 </ul>
1993 </li>1993 </li>
1994 </ul>1994 </ul>
...@@ -5545,7 +5545,7 @@ test "turn HashMap into a set with void" {...@@ -5545,7 +5545,7 @@ test "turn HashMap into a set with void" {
5545 </p>5545 </p>
5546 <p>5546 <p>
5547 {#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}, which is defined like this:5547 {#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}, which is defined like this:
5548 {#syntax#}pub const c_void = @Type(.Opaque);{#endsyntax#}.5548 {#syntax#}pub const c_void = opaque {};{#endsyntax#}.
5549 {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size.5549 {#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size.
5550 </p>5550 </p>
5551 <p>5551 <p>
...@@ -8471,7 +8471,7 @@ test "integer truncation" {...@@ -8471,7 +8471,7 @@ test "integer truncation" {
8471 <li>{#link|Error Set Type#}</li>8471 <li>{#link|Error Set Type#}</li>
8472 <li>{#link|Error Union Type#}</li>8472 <li>{#link|Error Union Type#}</li>
8473 <li>{#link|Vectors#}</li>8473 <li>{#link|Vectors#}</li>
8474 <li>{#link|Opaque Types#}</li>8474 <li>{#link|opaque#}</li>
8475 <li>{#link|@Frame#}</li>8475 <li>{#link|@Frame#}</li>
8476 <li>{#syntax#}anyframe{#endsyntax#}</li>8476 <li>{#syntax#}anyframe{#endsyntax#}</li>
8477 <li>{#link|struct#}</li>8477 <li>{#link|struct#}</li>
...@@ -8547,17 +8547,18 @@ fn foo(comptime T: type, ptr: *T) T {...@@ -8547,17 +8547,18 @@ fn foo(comptime T: type, ptr: *T) T {
8547 {#header_close#}8547 {#header_close#}
8548 {#header_close#}8548 {#header_close#}
85498549
8550 {#header_open|Opaque Types#}8550 {#header_open|opaque#}
8551 <p>8551 <p>
8552 {#syntax#}@Type(.Opaque){#endsyntax#} creates a new type with an unknown (but non-zero) size and alignment.8552 {#syntax#}opaque {}{#endsyntax#} declares a new type with an unknown (but non-zero) size and alignment.
8553 It can have declarations like structs, unions, or enums.
8553 </p>8554 </p>
8554 <p>8555 <p>
8555 This is typically used for type safety when interacting with C code that does not expose struct details.8556 This is typically used for type safety when interacting with C code that does not expose struct details.
8556 Example:8557 Example:
8557 </p>8558 </p>
8558 {#code_begin|test_err|expected type '*Derp', found '*Wat'#}8559 {#code_begin|test_err|expected type '*Derp', found '*Wat'#}
8559const Derp = @Type(.Opaque);8560const Derp = opaque {};
8560const Wat = @Type(.Opaque);8561const Wat = opaque {};
85618562
8562extern fn bar(d: *Derp) void;8563extern fn bar(d: *Derp) void;
8563fn foo(w: *Wat) callconv(.C) void {8564fn foo(w: *Wat) callconv(.C) void {
...@@ -11193,7 +11194,7 @@ PtrTypeStart...@@ -11193,7 +11194,7 @@ PtrTypeStart
11193ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE11194ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE
1119411195
11195ContainerDeclType11196ContainerDeclType
11196 &lt;- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?11197 &lt;- (KEYWORD_struct / KEYWORD_enum / KEYWORD_opaque) (LPAREN Expr RPAREN)?
11197 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?11198 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
1119811199
11199# Alignment11200# Alignment
...@@ -11340,6 +11341,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word...@@ -11340,6 +11341,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word
11340KEYWORD_noalias &lt;- 'noalias' end_of_word11341KEYWORD_noalias &lt;- 'noalias' end_of_word
11341KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word11342KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word
11342KEYWORD_null &lt;- 'null' end_of_word11343KEYWORD_null &lt;- 'null' end_of_word
11344KEYWORD_opaque &lt;- 'opaque' end_of_word
11343KEYWORD_or &lt;- 'or' end_of_word11345KEYWORD_or &lt;- 'or' end_of_word
11344KEYWORD_orelse &lt;- 'orelse' end_of_word11346KEYWORD_orelse &lt;- 'orelse' end_of_word
11345KEYWORD_packed &lt;- 'packed' end_of_word11347KEYWORD_packed &lt;- 'packed' end_of_word
...@@ -11368,7 +11370,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype...@@ -11368,7 +11370,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype
11368 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer11370 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
11369 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false11371 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
11370 / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline11372 / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline
11371 / KEYWORD_noalias / KEYWORD_null / KEYWORD_or11373 / KEYWORD_noalias / KEYWORD_null / KEYWORD_opaque / KEYWORD_or
11372 / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub11374 / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub
11373 / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection11375 / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
11374 / KEYWORD_struct / KEYWORD_suspend11376 / KEYWORD_struct / KEYWORD_suspend
lib/std/builtin.zig+7-1
...@@ -198,7 +198,7 @@ pub const TypeInfo = union(enum) {...@@ -198,7 +198,7 @@ pub const TypeInfo = union(enum) {
198 Union: Union,198 Union: Union,
199 Fn: Fn,199 Fn: Fn,
200 BoundFn: Fn,200 BoundFn: Fn,
201 Opaque: void,201 Opaque: Opaque,
202 Frame: Frame,202 Frame: Frame,
203 AnyFrame: AnyFrame,203 AnyFrame: AnyFrame,
204 Vector: Vector,204 Vector: Vector,
...@@ -359,6 +359,12 @@ pub const TypeInfo = union(enum) {...@@ -359,6 +359,12 @@ pub const TypeInfo = union(enum) {
359 args: []const FnArg,359 args: []const FnArg,
360 };360 };
361361
362 /// This data structure is used by the Zig language code generation and
363 /// therefore must be kept in sync with the compiler implementation.
364 pub const Opaque = struct {
365 decls: []const Declaration,
366 };
367
362 /// This data structure is used by the Zig language code generation and368 /// This data structure is used by the Zig language code generation and
363 /// therefore must be kept in sync with the compiler implementation.369 /// therefore must be kept in sync with the compiler implementation.
364 pub const Frame = struct {370 pub const Frame = struct {
lib/std/c.zig+2-2
...@@ -329,8 +329,8 @@ pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;...@@ -329,8 +329,8 @@ pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
329pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;329pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;
330pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;330pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
331331
332pub const pthread_t = *@Type(.Opaque);332pub const pthread_t = *opaque {};
333pub const FILE = @Type(.Opaque);333pub const FILE = opaque {};
334334
335pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;335pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;
336pub extern "c" fn dlclose(handle: *c_void) c_int;336pub extern "c" fn dlclose(handle: *c_void) c_int;
lib/std/os/linux/bpf/kern.zig+25-25
...@@ -12,28 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) {...@@ -12,28 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) {
1212
13pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};13pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};
1414
15pub const BpfSock = @Type(.Opaque);15pub const BpfSock = opaque {};
16pub const BpfSockAddr = @Type(.Opaque);16pub const BpfSockAddr = opaque {};
17pub const FibLookup = @Type(.Opaque);17pub const FibLookup = opaque {};
18pub const MapDef = @Type(.Opaque);18pub const MapDef = opaque {};
19pub const PerfEventData = @Type(.Opaque);19pub const PerfEventData = opaque {};
20pub const PerfEventValue = @Type(.Opaque);20pub const PerfEventValue = opaque {};
21pub const PidNsInfo = @Type(.Opaque);21pub const PidNsInfo = opaque {};
22pub const SeqFile = @Type(.Opaque);22pub const SeqFile = opaque {};
23pub const SkBuff = @Type(.Opaque);23pub const SkBuff = opaque {};
24pub const SkMsgMd = @Type(.Opaque);24pub const SkMsgMd = opaque {};
25pub const SkReusePortMd = @Type(.Opaque);25pub const SkReusePortMd = opaque {};
26pub const Sock = @Type(.Opaque);26pub const Sock = opaque {};
27pub const SockAddr = @Type(.Opaque);27pub const SockAddr = opaque {};
28pub const SockOps = @Type(.Opaque);28pub const SockOps = opaque {};
29pub const SockTuple = @Type(.Opaque);29pub const SockTuple = opaque {};
30pub const SpinLock = @Type(.Opaque);30pub const SpinLock = opaque {};
31pub const SysCtl = @Type(.Opaque);31pub const SysCtl = opaque {};
32pub const Tcp6Sock = @Type(.Opaque);32pub const Tcp6Sock = opaque {};
33pub const TcpRequestSock = @Type(.Opaque);33pub const TcpRequestSock = opaque {};
34pub const TcpSock = @Type(.Opaque);34pub const TcpSock = opaque {};
35pub const TcpTimewaitSock = @Type(.Opaque);35pub const TcpTimewaitSock = opaque {};
36pub const TunnelKey = @Type(.Opaque);36pub const TunnelKey = opaque {};
37pub const Udp6Sock = @Type(.Opaque);37pub const Udp6Sock = opaque {};
38pub const XdpMd = @Type(.Opaque);38pub const XdpMd = opaque {};
39pub const XfrmState = @Type(.Opaque);39pub const XfrmState = opaque {};
lib/std/os/uefi.zig+3-3
...@@ -17,7 +17,7 @@ pub var handle: Handle = undefined;...@@ -17,7 +17,7 @@ pub var handle: Handle = undefined;
17pub var system_table: *tables.SystemTable = undefined;17pub var system_table: *tables.SystemTable = undefined;
1818
19/// A handle to an event structure.19/// A handle to an event structure.
20pub const Event = *@Type(.Opaque);20pub const Event = *opaque {};
2121
22/// GUIDs must be align(8)22/// GUIDs must be align(8)
23pub const Guid = extern struct {23pub const Guid = extern struct {
...@@ -51,7 +51,7 @@ pub const Guid = extern struct {...@@ -51,7 +51,7 @@ pub const Guid = extern struct {
51};51};
5252
53/// An EFI Handle represents a collection of related interfaces.53/// An EFI Handle represents a collection of related interfaces.
54pub const Handle = *@Type(.Opaque);54pub const Handle = *opaque {};
5555
56/// This structure represents time information.56/// This structure represents time information.
57pub const Time = extern struct {57pub const Time = extern struct {
...@@ -108,4 +108,4 @@ pub const TimeCapabilities = extern struct {...@@ -108,4 +108,4 @@ pub const TimeCapabilities = extern struct {
108};108};
109109
110/// File Handle as specified in the EFI Shell Spec110/// File Handle as specified in the EFI Shell Spec
111pub const FileHandle = *@Type(.Opaque);111pub const FileHandle = *opaque {};
lib/std/os/uefi/protocols/hii.zig+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6const uefi = @import("std").os.uefi;6const uefi = @import("std").os.uefi;
7const Guid = uefi.Guid;7const Guid = uefi.Guid;
88
9pub const HIIHandle = *@Type(.Opaque);9pub const HIIHandle = *opaque {};
1010
11/// The header found at the start of each package.11/// The header found at the start of each package.
12pub const HIIPackageHeader = packed struct {12pub const HIIPackageHeader = packed struct {
lib/std/os/windows/bits.zig+15-15
...@@ -32,16 +32,16 @@ pub const UCHAR = u8;...@@ -32,16 +32,16 @@ pub const UCHAR = u8;
32pub const FLOAT = f32;32pub const FLOAT = f32;
33pub const HANDLE = *c_void;33pub const HANDLE = *c_void;
34pub const HCRYPTPROV = ULONG_PTR;34pub const HCRYPTPROV = ULONG_PTR;
35pub const HBRUSH = *@Type(.Opaque);35pub const HBRUSH = *opaque {};
36pub const HCURSOR = *@Type(.Opaque);36pub const HCURSOR = *opaque {};
37pub const HICON = *@Type(.Opaque);37pub const HICON = *opaque {};
38pub const HINSTANCE = *@Type(.Opaque);38pub const HINSTANCE = *opaque {};
39pub const HMENU = *@Type(.Opaque);39pub const HMENU = *opaque {};
40pub const HMODULE = *@Type(.Opaque);40pub const HMODULE = *opaque {};
41pub const HWND = *@Type(.Opaque);41pub const HWND = *opaque {};
42pub const HDC = *@Type(.Opaque);42pub const HDC = *opaque {};
43pub const HGLRC = *@Type(.Opaque);43pub const HGLRC = *opaque {};
44pub const FARPROC = *@Type(.Opaque);44pub const FARPROC = *opaque {};
45pub const INT = c_int;45pub const INT = c_int;
46pub const LPBYTE = *BYTE;46pub const LPBYTE = *BYTE;
47pub const LPCH = *CHAR;47pub const LPCH = *CHAR;
...@@ -81,7 +81,7 @@ pub const WPARAM = usize;...@@ -81,7 +81,7 @@ pub const WPARAM = usize;
81pub const LPARAM = ?*c_void;81pub const LPARAM = ?*c_void;
82pub const LRESULT = ?*c_void;82pub const LRESULT = ?*c_void;
8383
84pub const va_list = *@Type(.Opaque);84pub const va_list = *opaque {};
8585
86pub const TRUE = 1;86pub const TRUE = 1;
87pub const FALSE = 0;87pub const FALSE = 0;
...@@ -1175,10 +1175,10 @@ pub const UNICODE_STRING = extern struct {...@@ -1175,10 +1175,10 @@ pub const UNICODE_STRING = extern struct {
1175 Buffer: [*]WCHAR,1175 Buffer: [*]WCHAR,
1176};1176};
11771177
1178const ACTIVATION_CONTEXT_DATA = @Type(.Opaque);1178const ACTIVATION_CONTEXT_DATA = opaque {};
1179const ASSEMBLY_STORAGE_MAP = @Type(.Opaque);1179const ASSEMBLY_STORAGE_MAP = opaque {};
1180const FLS_CALLBACK_INFO = @Type(.Opaque);1180const FLS_CALLBACK_INFO = opaque {};
1181const RTL_BITMAP = @Type(.Opaque);1181const RTL_BITMAP = opaque {};
1182pub const PRTL_BITMAP = *RTL_BITMAP;1182pub const PRTL_BITMAP = *RTL_BITMAP;
1183const KAFFINITY = usize;1183const KAFFINITY = usize;
11841184
lib/std/os/windows/ws2_32.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// and substantial portions of the software.5// and substantial portions of the software.
6usingnamespace @import("bits.zig");6usingnamespace @import("bits.zig");
77
8pub const SOCKET = *@Type(.Opaque);8pub const SOCKET = *opaque {};
9pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));9pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
10pub const SOCKET_ERROR = -1;10pub const SOCKET_ERROR = -1;
1111
lib/std/zig/ast.zig+1-1
...@@ -288,7 +288,7 @@ pub const Error = union(enum) {...@@ -288,7 +288,7 @@ pub const Error = union(enum) {
288 pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");288 pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
289 pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");289 pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
290 pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");290 pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
291 pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");291 pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', '" ++ Token.Id.Keyword_enum.symbol() ++ "', or '" ++ Token.Id.Keyword_opaque.symbol() ++ "', found '{}'");
292 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");292 pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
293 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");293 pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
294 pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");294 pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");
lib/std/zig/parse.zig+2-1
...@@ -2896,11 +2896,12 @@ const Parser = struct {...@@ -2896,11 +2896,12 @@ const Parser = struct {
2896 /// <- KEYWORD_struct2896 /// <- KEYWORD_struct
2897 /// / KEYWORD_enum (LPAREN Expr RPAREN)?2897 /// / KEYWORD_enum (LPAREN Expr RPAREN)?
2898 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?2898 /// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2899 /// / KEYWORD_opaque
2899 fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {2900 fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
2900 const kind_token = p.nextToken();2901 const kind_token = p.nextToken();
29012902
2902 const init_arg_expr = switch (p.token_ids[kind_token]) {2903 const init_arg_expr = switch (p.token_ids[kind_token]) {
2903 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },2904 .Keyword_struct, .Keyword_opaque => Node.ContainerDecl.InitArg{ .None = {} },
2904 .Keyword_enum => blk: {2905 .Keyword_enum => blk: {
2905 if (p.eatToken(.LParen) != null) {2906 if (p.eatToken(.LParen) != null) {
2906 const expr = try p.expectNode(parseExpr, .{2907 const expr = try p.expectNode(parseExpr, .{
lib/std/zig/render.zig+13-1
...@@ -1492,7 +1492,19 @@ fn renderExpression(...@@ -1492,7 +1492,19 @@ fn renderExpression(
14921492
1493 // TODO remove after 0.7.0 release1493 // TODO remove after 0.7.0 release
1494 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))1494 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
1495 return ais.writer().writeAll("@Type(.Opaque)");1495 return ais.writer().writeAll("opaque {}");
1496
1497 // TODO remove after 0.7.0 release
1498 {
1499 const params = builtin_call.paramsConst();
1500 if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
1501 params.len == 1)
1502 {
1503 if (params[0].castTag(.EnumLiteral)) |enum_literal|
1504 if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
1505 return ais.writer().writeAll("opaque {}");
1506 }
1507 }
14961508
1497 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name1509 try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name
14981510
lib/std/zig/tokenizer.zig+3
...@@ -47,6 +47,7 @@ pub const Token = struct {...@@ -47,6 +47,7 @@ pub const Token = struct {
47 .{ "noinline", .Keyword_noinline },47 .{ "noinline", .Keyword_noinline },
48 .{ "nosuspend", .Keyword_nosuspend },48 .{ "nosuspend", .Keyword_nosuspend },
49 .{ "null", .Keyword_null },49 .{ "null", .Keyword_null },
50 .{ "opaque", .Keyword_opaque },
50 .{ "or", .Keyword_or },51 .{ "or", .Keyword_or },
51 .{ "orelse", .Keyword_orelse },52 .{ "orelse", .Keyword_orelse },
52 .{ "packed", .Keyword_packed },53 .{ "packed", .Keyword_packed },
...@@ -173,6 +174,7 @@ pub const Token = struct {...@@ -173,6 +174,7 @@ pub const Token = struct {
173 Keyword_noinline,174 Keyword_noinline,
174 Keyword_nosuspend,175 Keyword_nosuspend,
175 Keyword_null,176 Keyword_null,
177 Keyword_opaque,
176 Keyword_or,178 Keyword_or,
177 Keyword_orelse,179 Keyword_orelse,
178 Keyword_packed,180 Keyword_packed,
...@@ -296,6 +298,7 @@ pub const Token = struct {...@@ -296,6 +298,7 @@ pub const Token = struct {
296 .Keyword_noinline => "noinline",298 .Keyword_noinline => "noinline",
297 .Keyword_nosuspend => "nosuspend",299 .Keyword_nosuspend => "nosuspend",
298 .Keyword_null => "null",300 .Keyword_null => "null",
301 .Keyword_opaque => "opaque",
299 .Keyword_or => "or",302 .Keyword_or => "or",
300 .Keyword_orelse => "orelse",303 .Keyword_orelse => "orelse",
301 .Keyword_packed => "packed",304 .Keyword_packed => "packed",
src/clang.zig+86-86
...@@ -1,89 +1,89 @@...@@ -1,89 +1,89 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
22
3pub const struct_ZigClangConditionalOperator = @Type(.Opaque);3pub const struct_ZigClangConditionalOperator = opaque {};
4pub const struct_ZigClangBinaryConditionalOperator = @Type(.Opaque);4pub const struct_ZigClangBinaryConditionalOperator = opaque {};
5pub const struct_ZigClangAbstractConditionalOperator = @Type(.Opaque);5pub const struct_ZigClangAbstractConditionalOperator = opaque {};
6pub const struct_ZigClangAPInt = @Type(.Opaque);6pub const struct_ZigClangAPInt = opaque {};
7pub const struct_ZigClangAPSInt = @Type(.Opaque);7pub const struct_ZigClangAPSInt = opaque {};
8pub const struct_ZigClangAPFloat = @Type(.Opaque);8pub const struct_ZigClangAPFloat = opaque {};
9pub const struct_ZigClangASTContext = @Type(.Opaque);9pub const struct_ZigClangASTContext = opaque {};
10pub const struct_ZigClangASTUnit = @Type(.Opaque);10pub const struct_ZigClangASTUnit = opaque {};
11pub const struct_ZigClangArraySubscriptExpr = @Type(.Opaque);11pub const struct_ZigClangArraySubscriptExpr = opaque {};
12pub const struct_ZigClangArrayType = @Type(.Opaque);12pub const struct_ZigClangArrayType = opaque {};
13pub const struct_ZigClangAttributedType = @Type(.Opaque);13pub const struct_ZigClangAttributedType = opaque {};
14pub const struct_ZigClangBinaryOperator = @Type(.Opaque);14pub const struct_ZigClangBinaryOperator = opaque {};
15pub const struct_ZigClangBreakStmt = @Type(.Opaque);15pub const struct_ZigClangBreakStmt = opaque {};
16pub const struct_ZigClangBuiltinType = @Type(.Opaque);16pub const struct_ZigClangBuiltinType = opaque {};
17pub const struct_ZigClangCStyleCastExpr = @Type(.Opaque);17pub const struct_ZigClangCStyleCastExpr = opaque {};
18pub const struct_ZigClangCallExpr = @Type(.Opaque);18pub const struct_ZigClangCallExpr = opaque {};
19pub const struct_ZigClangCaseStmt = @Type(.Opaque);19pub const struct_ZigClangCaseStmt = opaque {};
20pub const struct_ZigClangCompoundAssignOperator = @Type(.Opaque);20pub const struct_ZigClangCompoundAssignOperator = opaque {};
21pub const struct_ZigClangCompoundStmt = @Type(.Opaque);21pub const struct_ZigClangCompoundStmt = opaque {};
22pub const struct_ZigClangConstantArrayType = @Type(.Opaque);22pub const struct_ZigClangConstantArrayType = opaque {};
23pub const struct_ZigClangContinueStmt = @Type(.Opaque);23pub const struct_ZigClangContinueStmt = opaque {};
24pub const struct_ZigClangDecayedType = @Type(.Opaque);24pub const struct_ZigClangDecayedType = opaque {};
25pub const ZigClangDecl = @Type(.Opaque);25pub const ZigClangDecl = opaque {};
26pub const struct_ZigClangDeclRefExpr = @Type(.Opaque);26pub const struct_ZigClangDeclRefExpr = opaque {};
27pub const struct_ZigClangDeclStmt = @Type(.Opaque);27pub const struct_ZigClangDeclStmt = opaque {};
28pub const struct_ZigClangDefaultStmt = @Type(.Opaque);28pub const struct_ZigClangDefaultStmt = opaque {};
29pub const struct_ZigClangDiagnosticOptions = @Type(.Opaque);29pub const struct_ZigClangDiagnosticOptions = opaque {};
30pub const struct_ZigClangDiagnosticsEngine = @Type(.Opaque);30pub const struct_ZigClangDiagnosticsEngine = opaque {};
31pub const struct_ZigClangDoStmt = @Type(.Opaque);31pub const struct_ZigClangDoStmt = opaque {};
32pub const struct_ZigClangElaboratedType = @Type(.Opaque);32pub const struct_ZigClangElaboratedType = opaque {};
33pub const struct_ZigClangEnumConstantDecl = @Type(.Opaque);33pub const struct_ZigClangEnumConstantDecl = opaque {};
34pub const struct_ZigClangEnumDecl = @Type(.Opaque);34pub const struct_ZigClangEnumDecl = opaque {};
35pub const struct_ZigClangEnumType = @Type(.Opaque);35pub const struct_ZigClangEnumType = opaque {};
36pub const struct_ZigClangExpr = @Type(.Opaque);36pub const struct_ZigClangExpr = opaque {};
37pub const struct_ZigClangFieldDecl = @Type(.Opaque);37pub const struct_ZigClangFieldDecl = opaque {};
38pub const struct_ZigClangFileID = @Type(.Opaque);38pub const struct_ZigClangFileID = opaque {};
39pub const struct_ZigClangForStmt = @Type(.Opaque);39pub const struct_ZigClangForStmt = opaque {};
40pub const struct_ZigClangFullSourceLoc = @Type(.Opaque);40pub const struct_ZigClangFullSourceLoc = opaque {};
41pub const struct_ZigClangFunctionDecl = @Type(.Opaque);41pub const struct_ZigClangFunctionDecl = opaque {};
42pub const struct_ZigClangFunctionProtoType = @Type(.Opaque);42pub const struct_ZigClangFunctionProtoType = opaque {};
43pub const struct_ZigClangIfStmt = @Type(.Opaque);43pub const struct_ZigClangIfStmt = opaque {};
44pub const struct_ZigClangImplicitCastExpr = @Type(.Opaque);44pub const struct_ZigClangImplicitCastExpr = opaque {};
45pub const struct_ZigClangIncompleteArrayType = @Type(.Opaque);45pub const struct_ZigClangIncompleteArrayType = opaque {};
46pub const struct_ZigClangIntegerLiteral = @Type(.Opaque);46pub const struct_ZigClangIntegerLiteral = opaque {};
47pub const struct_ZigClangMacroDefinitionRecord = @Type(.Opaque);47pub const struct_ZigClangMacroDefinitionRecord = opaque {};
48pub const struct_ZigClangMacroExpansion = @Type(.Opaque);48pub const struct_ZigClangMacroExpansion = opaque {};
49pub const struct_ZigClangMacroQualifiedType = @Type(.Opaque);49pub const struct_ZigClangMacroQualifiedType = opaque {};
50pub const struct_ZigClangMemberExpr = @Type(.Opaque);50pub const struct_ZigClangMemberExpr = opaque {};
51pub const struct_ZigClangNamedDecl = @Type(.Opaque);51pub const struct_ZigClangNamedDecl = opaque {};
52pub const struct_ZigClangNone = @Type(.Opaque);52pub const struct_ZigClangNone = opaque {};
53pub const struct_ZigClangOpaqueValueExpr = @Type(.Opaque);53pub const struct_ZigClangOpaqueValueExpr = opaque {};
54pub const struct_ZigClangPCHContainerOperations = @Type(.Opaque);54pub const struct_ZigClangPCHContainerOperations = opaque {};
55pub const struct_ZigClangParenExpr = @Type(.Opaque);55pub const struct_ZigClangParenExpr = opaque {};
56pub const struct_ZigClangParenType = @Type(.Opaque);56pub const struct_ZigClangParenType = opaque {};
57pub const struct_ZigClangParmVarDecl = @Type(.Opaque);57pub const struct_ZigClangParmVarDecl = opaque {};
58pub const struct_ZigClangPointerType = @Type(.Opaque);58pub const struct_ZigClangPointerType = opaque {};
59pub const struct_ZigClangPreprocessedEntity = @Type(.Opaque);59pub const struct_ZigClangPreprocessedEntity = opaque {};
60pub const struct_ZigClangRecordDecl = @Type(.Opaque);60pub const struct_ZigClangRecordDecl = opaque {};
61pub const struct_ZigClangRecordType = @Type(.Opaque);61pub const struct_ZigClangRecordType = opaque {};
62pub const struct_ZigClangReturnStmt = @Type(.Opaque);62pub const struct_ZigClangReturnStmt = opaque {};
63pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque);63pub const struct_ZigClangSkipFunctionBodiesScope = opaque {};
64pub const struct_ZigClangSourceManager = @Type(.Opaque);64pub const struct_ZigClangSourceManager = opaque {};
65pub const struct_ZigClangSourceRange = @Type(.Opaque);65pub const struct_ZigClangSourceRange = opaque {};
66pub const ZigClangStmt = @Type(.Opaque);66pub const ZigClangStmt = opaque {};
67pub const struct_ZigClangStringLiteral = @Type(.Opaque);67pub const struct_ZigClangStringLiteral = opaque {};
68pub const struct_ZigClangStringRef = @Type(.Opaque);68pub const struct_ZigClangStringRef = opaque {};
69pub const struct_ZigClangSwitchStmt = @Type(.Opaque);69pub const struct_ZigClangSwitchStmt = opaque {};
70pub const struct_ZigClangTagDecl = @Type(.Opaque);70pub const struct_ZigClangTagDecl = opaque {};
71pub const struct_ZigClangType = @Type(.Opaque);71pub const struct_ZigClangType = opaque {};
72pub const struct_ZigClangTypedefNameDecl = @Type(.Opaque);72pub const struct_ZigClangTypedefNameDecl = opaque {};
73pub const struct_ZigClangTypedefType = @Type(.Opaque);73pub const struct_ZigClangTypedefType = opaque {};
74pub const struct_ZigClangUnaryExprOrTypeTraitExpr = @Type(.Opaque);74pub const struct_ZigClangUnaryExprOrTypeTraitExpr = opaque {};
75pub const struct_ZigClangUnaryOperator = @Type(.Opaque);75pub const struct_ZigClangUnaryOperator = opaque {};
76pub const struct_ZigClangValueDecl = @Type(.Opaque);76pub const struct_ZigClangValueDecl = opaque {};
77pub const struct_ZigClangVarDecl = @Type(.Opaque);77pub const struct_ZigClangVarDecl = opaque {};
78pub const struct_ZigClangWhileStmt = @Type(.Opaque);78pub const struct_ZigClangWhileStmt = opaque {};
79pub const struct_ZigClangFunctionType = @Type(.Opaque);79pub const struct_ZigClangFunctionType = opaque {};
80pub const struct_ZigClangPredefinedExpr = @Type(.Opaque);80pub const struct_ZigClangPredefinedExpr = opaque {};
81pub const struct_ZigClangInitListExpr = @Type(.Opaque);81pub const struct_ZigClangInitListExpr = opaque {};
82pub const ZigClangPreprocessingRecord = @Type(.Opaque);82pub const ZigClangPreprocessingRecord = opaque {};
83pub const ZigClangFloatingLiteral = @Type(.Opaque);83pub const ZigClangFloatingLiteral = opaque {};
84pub const ZigClangConstantExpr = @Type(.Opaque);84pub const ZigClangConstantExpr = opaque {};
85pub const ZigClangCharacterLiteral = @Type(.Opaque);85pub const ZigClangCharacterLiteral = opaque {};
86pub const ZigClangStmtExpr = @Type(.Opaque);86pub const ZigClangStmtExpr = opaque {};
8787
88pub const ZigClangBO = extern enum {88pub const ZigClangBO = extern enum {
89 PtrMemD,89 PtrMemD,
...@@ -749,11 +749,11 @@ pub const ZigClangCharacterLiteral_CharacterKind = extern enum {...@@ -749,11 +749,11 @@ pub const ZigClangCharacterLiteral_CharacterKind = extern enum {
749};749};
750750
751pub const ZigClangRecordDecl_field_iterator = extern struct {751pub const ZigClangRecordDecl_field_iterator = extern struct {
752 opaque: *c_void,752 ptr: *c_void,
753};753};
754754
755pub const ZigClangEnumDecl_enumerator_iterator = extern struct {755pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
756 opaque: *c_void,756 ptr: *c_void,
757};757};
758758
759pub const ZigClangPreprocessingRecord_iterator = extern struct {759pub const ZigClangPreprocessingRecord_iterator = extern struct {
src/stage1/all_types.hpp+4
...@@ -1053,6 +1053,7 @@ enum ContainerKind {...@@ -1053,6 +1053,7 @@ enum ContainerKind {
1053 ContainerKindStruct,1053 ContainerKindStruct,
1054 ContainerKindEnum,1054 ContainerKindEnum,
1055 ContainerKindUnion,1055 ContainerKindUnion,
1056 ContainerKindOpaque,
1056};1057};
10571058
1058enum ContainerLayout {1059enum ContainerLayout {
...@@ -1570,7 +1571,10 @@ enum OnePossibleValue {...@@ -1570,7 +1571,10 @@ enum OnePossibleValue {
1570};1571};
15711572
1572struct ZigTypeOpaque {1573struct ZigTypeOpaque {
1574 AstNode *decl_node;
1573 Buf *bare_name;1575 Buf *bare_name;
1576
1577 ScopeDecls *decls_scope;
1574};1578};
15751579
1576struct ZigTypeFnFrame {1580struct ZigTypeFnFrame {
src/stage1/analyze.cpp+52-10
...@@ -86,14 +86,18 @@ ZigType *new_type_table_entry(ZigTypeId id) {...@@ -86,14 +86,18 @@ ZigType *new_type_table_entry(ZigTypeId id) {
86}86}
8787
88static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {88static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {
89 if (type_entry->id == ZigTypeIdStruct) {89 switch (type_entry->id) {
90 return &type_entry->data.structure.decls_scope;90 case ZigTypeIdStruct:
91 } else if (type_entry->id == ZigTypeIdEnum) {91 return &type_entry->data.structure.decls_scope;
92 return &type_entry->data.enumeration.decls_scope;92 case ZigTypeIdEnum:
93 } else if (type_entry->id == ZigTypeIdUnion) {93 return &type_entry->data.enumeration.decls_scope;
94 return &type_entry->data.unionation.decls_scope;94 case ZigTypeIdUnion:
95 return &type_entry->data.unionation.decls_scope;
96 case ZigTypeIdOpaque:
97 return &type_entry->data.opaque.decls_scope;
98 default:
99 zig_unreachable();
95 }100 }
96 zig_unreachable();
97}101}
98102
99static ScopeExpr *find_expr_scope(Scope *scope) {103static ScopeExpr *find_expr_scope(Scope *scope) {
...@@ -912,13 +916,17 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c...@@ -912,13 +916,17 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c
912 ZigType *import = scope ? get_scope_import(scope) : nullptr;916 ZigType *import = scope ? get_scope_import(scope) : nullptr;
913 unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;917 unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
914918
919 // Note: duplicated in get_partial_container_type
915 entry->llvm_type = LLVMInt8Type();920 entry->llvm_type = LLVMInt8Type();
916 entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,921 entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
917 ZigLLVMTag_DW_structure_type(), full_name,922 ZigLLVMTag_DW_structure_type(), full_name,
918 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,923 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
919 import ? import->data.structure.root_struct->di_file : nullptr,924 import ? import->data.structure.root_struct->di_file : nullptr,
920 line);925 line);
926 entry->data.opaque.decl_node = source_node;
921 entry->data.opaque.bare_name = bare_name;927 entry->data.opaque.bare_name = bare_name;
928 entry->data.opaque.decls_scope = create_decls_scope(
929 g, source_node, scope, entry, import, &entry->name);
922930
923 // The actual size is unknown, but the value must not be 0 because that931 // The actual size is unknown, but the value must not be 0 because that
924 // is how type_has_bits is determined.932 // is how type_has_bits is determined.
...@@ -1078,6 +1086,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {...@@ -1078,6 +1086,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {
1078 return ZigTypeIdEnum;1086 return ZigTypeIdEnum;
1079 case ContainerKindUnion:1087 case ContainerKindUnion:
1080 return ZigTypeIdUnion;1088 return ZigTypeIdUnion;
1089 case ContainerKindOpaque:
1090 return ZigTypeIdOpaque;
1081 }1091 }
1082 zig_unreachable();1092 zig_unreachable();
1083}1093}
...@@ -1119,6 +1129,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind...@@ -1119,6 +1129,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
1119 entry->data.unionation.decl_node = decl_node;1129 entry->data.unionation.decl_node = decl_node;
1120 entry->data.unionation.layout = layout;1130 entry->data.unionation.layout = layout;
1121 break;1131 break;
1132 case ContainerKindOpaque: {
1133 ZigType *import = scope ? get_scope_import(scope) : nullptr;
1134 unsigned line = decl_node ? (unsigned)(decl_node->line + 1) : 0;
1135 // Note: duplicated in get_opaque_type
1136 entry->llvm_type = LLVMInt8Type();
1137 entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
1138 ZigLLVMTag_DW_structure_type(), full_name,
1139 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
1140 import ? import->data.structure.root_struct->di_file : nullptr,
1141 line);
1142 entry->data.opaque.decl_node = decl_node;
1143 entry->abi_size = SIZE_MAX;
1144 entry->size_in_bits = SIZE_MAX;
1145 entry->abi_align = 1;
1146 break;
1147 }
1122 }1148 }
11231149
1124 buf_init_from_str(&entry->name, full_name);1150 buf_init_from_str(&entry->name, full_name);
...@@ -3428,6 +3454,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {...@@ -3428,6 +3454,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
3428 return ErrorNone;3454 return ErrorNone;
3429}3455}
34303456
3457static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
3458 Error err = ErrorNone;
3459 AstNode *container_node = opaque_type->data.opaque.decl_node;
3460 if (container_node != nullptr) {
3461 assert(container_node->type == NodeTypeContainerDecl);
3462 AstNodeContainerDecl *container_decl = &container_node->data.container_decl;
3463 for (size_t i = 0; i < container_decl->fields.length; i++) {
3464 AstNode *field_node = container_decl->fields.items[i];
3465 add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields"));
3466 err = ErrorSemanticAnalyzeFail;
3467 }
3468 }
3469 return err;
3470}
3471
3431void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {3472void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {
3432 if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;3473 if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;
3433 buf_append_buf(buf, &container_type->name);3474 buf_append_buf(buf, &container_type->name);
...@@ -3893,6 +3934,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {...@@ -3893,6 +3934,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {
3893 return resolve_enum_zero_bits(g, tld_container->type_entry);3934 return resolve_enum_zero_bits(g, tld_container->type_entry);
3894 case ZigTypeIdUnion:3935 case ZigTypeIdUnion:
3895 return resolve_union_type(g, tld_container->type_entry);3936 return resolve_union_type(g, tld_container->type_entry);
3937 case ZigTypeIdOpaque:
3938 return resolve_opaque_type(g, tld_container->type_entry);
3896 default:3939 default:
3897 zig_unreachable();3940 zig_unreachable();
3898 }3941 }
...@@ -4459,6 +4502,7 @@ bool is_container(ZigType *type_entry) {...@@ -4459,6 +4502,7 @@ bool is_container(ZigType *type_entry) {
4459 return type_entry->data.structure.special != StructSpecialSlice;4502 return type_entry->data.structure.special != StructSpecialSlice;
4460 case ZigTypeIdEnum:4503 case ZigTypeIdEnum:
4461 case ZigTypeIdUnion:4504 case ZigTypeIdUnion:
4505 case ZigTypeIdOpaque:
4462 return true;4506 return true;
4463 case ZigTypeIdPointer:4507 case ZigTypeIdPointer:
4464 case ZigTypeIdMetaType:4508 case ZigTypeIdMetaType:
...@@ -4478,7 +4522,6 @@ bool is_container(ZigType *type_entry) {...@@ -4478,7 +4522,6 @@ bool is_container(ZigType *type_entry) {
4478 case ZigTypeIdErrorSet:4522 case ZigTypeIdErrorSet:
4479 case ZigTypeIdFn:4523 case ZigTypeIdFn:
4480 case ZigTypeIdBoundFn:4524 case ZigTypeIdBoundFn:
4481 case ZigTypeIdOpaque:
4482 case ZigTypeIdVector:4525 case ZigTypeIdVector:
4483 case ZigTypeIdFnFrame:4526 case ZigTypeIdFnFrame:
4484 case ZigTypeIdAnyFrame:4527 case ZigTypeIdAnyFrame:
...@@ -8165,6 +8208,7 @@ const char *container_string(ContainerKind kind) {...@@ -8165,6 +8208,7 @@ const char *container_string(ContainerKind kind) {
8165 case ContainerKindEnum: return "enum";8208 case ContainerKindEnum: return "enum";
8166 case ContainerKindStruct: return "struct";8209 case ContainerKindStruct: return "struct";
8167 case ContainerKindUnion: return "union";8210 case ContainerKindUnion: return "union";
8211 case ContainerKindOpaque: return "opaque";
8168 }8212 }
8169 zig_unreachable();8213 zig_unreachable();
8170}8214}
...@@ -8183,8 +8227,6 @@ Buf *type_bare_name(ZigType *type_entry) {...@@ -8183,8 +8227,6 @@ Buf *type_bare_name(ZigType *type_entry) {
8183 return &type_entry->name;8227 return &type_entry->name;
8184 } else if (is_container(type_entry)) {8228 } else if (is_container(type_entry)) {
8185 return get_container_scope(type_entry)->bare_name;8229 return get_container_scope(type_entry)->bare_name;
8186 } else if (type_entry->id == ZigTypeIdOpaque) {
8187 return type_entry->data.opaque.bare_name;
8188 } else {8230 } else {
8189 return &type_entry->name;8231 return &type_entry->name;
8190 }8232 }
src/stage1/ir.cpp+37-2
...@@ -22386,6 +22386,8 @@ static IrInstGen *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -22386,6 +22386,8 @@ static IrInstGen *ir_analyze_container_member_access_inner(IrAnalyze *ira,
22386 prefix_name = "enum ";22386 prefix_name = "enum ";
22387 } else if (bare_struct_type->id == ZigTypeIdUnion) {22387 } else if (bare_struct_type->id == ZigTypeIdUnion) {
22388 prefix_name = "union ";22388 prefix_name = "union ";
22389 } else if (bare_struct_type->id == ZigTypeIdOpaque) {
22390 prefix_name = "opaque type ";
22389 } else {22391 } else {
22390 prefix_name = "";22392 prefix_name = "";
22391 }22393 }
...@@ -22586,7 +22588,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name...@@ -22586,7 +22588,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
22586 }22588 }
22587 }22589 }
2258822590
22589 if (bare_type->id == ZigTypeIdEnum) {22591 if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) {
22590 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,22592 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
22591 source_instr, container_ptr, container_ptr_src, container_type);22593 source_instr, container_ptr, container_ptr_src, container_type);
22592 }22594 }
...@@ -25182,7 +25184,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25182,7 +25184,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25182 case ZigTypeIdEnumLiteral:25184 case ZigTypeIdEnumLiteral:
25183 case ZigTypeIdUndefined:25185 case ZigTypeIdUndefined:
25184 case ZigTypeIdNull:25186 case ZigTypeIdNull:
25185 case ZigTypeIdOpaque:
25186 result = ira->codegen->intern.for_void();25187 result = ira->codegen->intern.for_void();
25187 break;25188 break;
25188 case ZigTypeIdInt:25189 case ZigTypeIdInt:
...@@ -25736,6 +25737,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25736,6 +25737,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25736 if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))25737 if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
25737 return err;25738 return err;
2573825739
25740 break;
25741 }
25742 case ZigTypeIdOpaque:
25743 {
25744 result = ira->codegen->pass1_arena->create<ZigValue>();
25745 result->special = ConstValSpecialStatic;
25746 result->type = ir_type_info_get_type(ira, "Opaque", nullptr);
25747
25748 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
25749 result->data.x_struct.fields = fields;
25750
25751 // decls: []TypeInfo.Declaration
25752 ensure_field_index(result->type, "decls", 0);
25753 if ((err = ir_make_type_info_decls(ira, source_instr, fields[0],
25754 type_entry->data.opaque.decls_scope, false)))
25755 {
25756 return err;
25757 }
25758
25739 break;25759 break;
25740 }25760 }
25741 case ZigTypeIdFnFrame:25761 case ZigTypeIdFnFrame:
...@@ -26043,6 +26063,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -26043,6 +26063,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
26043 return get_error_union_type(ira->codegen, err_set_type, payload_type);26063 return get_error_union_type(ira->codegen, err_set_type, payload_type);
26044 }26064 }
26045 case ZigTypeIdOpaque: {26065 case ZigTypeIdOpaque: {
26066 assert(payload->special == ConstValSpecialStatic);
26067 assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr));
26068
26069 ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 0);
26070 if (decls_value == nullptr)
26071 return ira->codegen->invalid_inst_gen->value->type;
26072 assert(decls_value->special == ConstValSpecialStatic);
26073 assert(is_slice(decls_value->type));
26074 ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
26075 size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
26076 if (decls_len != 0) {
26077 ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type"));
26078 return ira->codegen->invalid_inst_gen->value->type;
26079 }
26080
26046 Buf *bare_name = buf_alloc();26081 Buf *bare_name = buf_alloc();
26047 Buf *full_name = get_anon_type_name(ira->codegen,26082 Buf *full_name = get_anon_type_name(ira->codegen,
26048 ira->old_irb.exec, "opaque", source_instr->scope, source_instr->source_node, bare_name);26083 ira->old_irb.exec, "opaque", source_instr->scope, source_instr->source_node, bare_name);
src/stage1/parser.cpp+9
...@@ -2920,6 +2920,7 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {...@@ -2920,6 +2920,7 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
2920// <- KEYWORD_struct2920// <- KEYWORD_struct
2921// / KEYWORD_enum (LPAREN Expr RPAREN)?2921// / KEYWORD_enum (LPAREN Expr RPAREN)?
2922// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?2922// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
2923// / KEYWORD_opaque
2923static AstNode *ast_parse_container_decl_type(ParseContext *pc) {2924static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
2924 Token *first = eat_token_if(pc, TokenIdKeywordStruct);2925 Token *first = eat_token_if(pc, TokenIdKeywordStruct);
2925 if (first != nullptr) {2926 if (first != nullptr) {
...@@ -2929,6 +2930,14 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) {...@@ -2929,6 +2930,14 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
2929 return res;2930 return res;
2930 }2931 }
29312932
2933 first = eat_token_if(pc, TokenIdKeywordOpaque);
2934 if (first != nullptr) {
2935 AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
2936 res->data.container_decl.init_arg_expr = nullptr;
2937 res->data.container_decl.kind = ContainerKindOpaque;
2938 return res;
2939 }
2940
2932 first = eat_token_if(pc, TokenIdKeywordEnum);2941 first = eat_token_if(pc, TokenIdKeywordEnum);
2933 if (first != nullptr) {2942 if (first != nullptr) {
2934 AstNode *init_arg_expr = nullptr;2943 AstNode *init_arg_expr = nullptr;
src/stage1/tokenizer.cpp+2
...@@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {...@@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {
133 {"noinline", TokenIdKeywordNoInline},133 {"noinline", TokenIdKeywordNoInline},
134 {"nosuspend", TokenIdKeywordNoSuspend},134 {"nosuspend", TokenIdKeywordNoSuspend},
135 {"null", TokenIdKeywordNull},135 {"null", TokenIdKeywordNull},
136 {"opaque", TokenIdKeywordOpaque},
136 {"or", TokenIdKeywordOr},137 {"or", TokenIdKeywordOr},
137 {"orelse", TokenIdKeywordOrElse},138 {"orelse", TokenIdKeywordOrElse},
138 {"packed", TokenIdKeywordPacked},139 {"packed", TokenIdKeywordPacked},
...@@ -1595,6 +1596,7 @@ const char * token_name(TokenId id) {...@@ -1595,6 +1596,7 @@ const char * token_name(TokenId id) {
1595 case TokenIdKeywordNoInline: return "noinline";1596 case TokenIdKeywordNoInline: return "noinline";
1596 case TokenIdKeywordNoSuspend: return "nosuspend";1597 case TokenIdKeywordNoSuspend: return "nosuspend";
1597 case TokenIdKeywordNull: return "null";1598 case TokenIdKeywordNull: return "null";
1599 case TokenIdKeywordOpaque: return "opaque";
1598 case TokenIdKeywordOr: return "or";1600 case TokenIdKeywordOr: return "or";
1599 case TokenIdKeywordOrElse: return "orelse";1601 case TokenIdKeywordOrElse: return "orelse";
1600 case TokenIdKeywordPacked: return "packed";1602 case TokenIdKeywordPacked: return "packed";
src/stage1/tokenizer.hpp+1
...@@ -81,6 +81,7 @@ enum TokenId {...@@ -81,6 +81,7 @@ enum TokenId {
81 TokenIdKeywordNoAlias,81 TokenIdKeywordNoAlias,
82 TokenIdKeywordNoSuspend,82 TokenIdKeywordNoSuspend,
83 TokenIdKeywordNull,83 TokenIdKeywordNull,
84 TokenIdKeywordOpaque,
84 TokenIdKeywordOr,85 TokenIdKeywordOr,
85 TokenIdKeywordOrElse,86 TokenIdKeywordOrElse,
86 TokenIdKeywordPacked,87 TokenIdKeywordPacked,
src/translate_c.zig+20-12
...@@ -930,9 +930,9 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -930,9 +930,9 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
930 const init_node = blk: {930 const init_node = blk: {
931 const rp = makeRestorePoint(c);931 const rp = makeRestorePoint(c);
932 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {932 const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
933 const opaque = try transCreateNodeOpaqueType(c);933 const opaque_type = try transCreateNodeOpaqueType(c);
934 semicolon = try appendToken(c, .Semicolon, ";");934 semicolon = try appendToken(c, .Semicolon, ";");
935 break :blk opaque;935 break :blk opaque_type;
936 };936 };
937937
938 const layout_tok = try if (ZigClangRecordDecl_getPackedAttribute(record_decl))938 const layout_tok = try if (ZigClangRecordDecl_getPackedAttribute(record_decl))
...@@ -954,17 +954,17 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -954,17 +954,17 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
954 const field_qt = ZigClangFieldDecl_getType(field_decl);954 const field_qt = ZigClangFieldDecl_getType(field_decl);
955955
956 if (ZigClangFieldDecl_isBitField(field_decl)) {956 if (ZigClangFieldDecl_isBitField(field_decl)) {
957 const opaque = try transCreateNodeOpaqueType(c);957 const opaque_type = try transCreateNodeOpaqueType(c);
958 semicolon = try appendToken(c, .Semicolon, ";");958 semicolon = try appendToken(c, .Semicolon, ";");
959 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});959 try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
960 break :blk opaque;960 break :blk opaque_type;
961 }961 }
962962
963 if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {963 if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
964 const opaque = try transCreateNodeOpaqueType(c);964 const opaque_type = try transCreateNodeOpaqueType(c);
965 semicolon = try appendToken(c, .Semicolon, ";");965 semicolon = try appendToken(c, .Semicolon, ";");
966 try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});966 try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
967 break :blk opaque;967 break :blk opaque_type;
968 }968 }
969969
970 var is_anon = false;970 var is_anon = false;
...@@ -979,10 +979,10 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*...@@ -979,10 +979,10 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
979 _ = try appendToken(c, .Colon, ":");979 _ = try appendToken(c, .Colon, ":");
980 const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {980 const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
981 error.UnsupportedType => {981 error.UnsupportedType => {
982 const opaque = try transCreateNodeOpaqueType(c);982 const opaque_type = try transCreateNodeOpaqueType(c);
983 semicolon = try appendToken(c, .Semicolon, ";");983 semicolon = try appendToken(c, .Semicolon, ";");
984 try emitWarning(c, record_loc, "{} demoted to opaque type - unable to translate type of field {}", .{ container_kind_name, raw_name });984 try emitWarning(c, record_loc, "{} demoted to opaque type - unable to translate type of field {}", .{ container_kind_name, raw_name });
985 break :blk opaque;985 break :blk opaque_type;
986 },986 },
987 else => |e| return e,987 else => |e| return e,
988 };988 };
...@@ -4438,10 +4438,18 @@ fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {...@@ -4438,10 +4438,18 @@ fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {
4438}4438}
44394439
4440fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {4440fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
4441 const call_node = try c.createBuiltinCall("@Type", 1);4441 const container_tok = try appendToken(c, .Keyword_opaque, "opaque");
4442 call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque");4442 const lbrace_token = try appendToken(c, .LBrace, "{");
4443 call_node.rparen_token = try appendToken(c, .RParen, ")");4443 const container_node = try ast.Node.ContainerDecl.alloc(c.arena, 0);
4444 return &call_node.base;4444 container_node.* = .{
4445 .kind_token = container_tok,
4446 .layout_token = null,
4447 .lbrace_token = lbrace_token,
4448 .rbrace_token = try appendToken(c, .RBrace, "}"),
4449 .fields_and_decls_len = 0,
4450 .init_arg_expr = .None,
4451 };
4452 return &container_node.base;
4445}4453}
44464454
4447fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {4455fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
test/compile_errors.zig+37-27
...@@ -125,6 +125,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -125,6 +125,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
125 "tmp.zig:15:23: error: enum field missing: 'arst'",125 "tmp.zig:15:23: error: enum field missing: 'arst'",
126 "tmp.zig:27:24: note: referenced here",126 "tmp.zig:27:24: note: referenced here",
127 });127 });
128
129 cases.add("field access of opaque type",
130 \\const MyType = opaque {};
131 \\
132 \\export fn entry() bool {
133 \\ var x: i32 = 1;
134 \\ return bar(@ptrCast(*MyType, &x));
135 \\}
136 \\
137 \\fn bar(x: *MyType) bool {
138 \\ return x.blah;
139 \\}
140 , &[_][]const u8{
141 "tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'",
142 });
143
144 cases.add("opaque type with field",
145 \\const Opaque = opaque { foo: i32 };
146 \\export fn entry() void {
147 \\ const foo: ?*Opaque = null;
148 \\}
149 , &[_][]const u8{
150 "tmp.zig:1:25: error: opaque types cannot have fields",
151 });
152
128 cases.add("@Type(.Fn) with is_generic = true",153 cases.add("@Type(.Fn) with is_generic = true",
129 \\const Foo = @Type(.{154 \\const Foo = @Type(.{
130 \\ .Fn = .{155 \\ .Fn = .{
...@@ -180,7 +205,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -180,7 +205,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
180 \\ .layout = .Auto,205 \\ .layout = .Auto,
181 \\ .tag_type = null,206 \\ .tag_type = null,
182 \\ .fields = &[_]TypeInfo.UnionField{207 \\ .fields = &[_]TypeInfo.UnionField{
183 \\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 },208 \\ .{ .name = "foo", .field_type = opaque {}, .alignment = 1 },
184 \\ },209 \\ },
185 \\ .decls = &[_]TypeInfo.Declaration{},210 \\ .decls = &[_]TypeInfo.Declaration{},
186 \\ },211 \\ },
...@@ -2613,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2613,7 +2638,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2613 });2638 });
26142639
2615 cases.add("directly embedding opaque type in struct and union",2640 cases.add("directly embedding opaque type in struct and union",
2616 \\const O = @Type(.Opaque);2641 \\const O = opaque {};
2617 \\const Foo = struct {2642 \\const Foo = struct {
2618 \\ o: O,2643 \\ o: O,
2619 \\};2644 \\};
...@@ -2628,7 +2653,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -2628,7 +2653,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
2628 \\ var bar: Bar = undefined;2653 \\ var bar: Bar = undefined;
2629 \\}2654 \\}
2630 \\export fn c() void {2655 \\export fn c() void {
2631 \\ var baz: *@Type(.Opaque) = undefined;2656 \\ var baz: *opaque {} = undefined;
2632 \\ const qux = .{baz.*};2657 \\ const qux = .{baz.*};
2633 \\}2658 \\}
2634 , &[_][]const u8{2659 , &[_][]const u8{
...@@ -3592,7 +3617,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3592,7 +3617,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3592 });3617 });
35933618
3594 cases.add("unknown length pointer to opaque",3619 cases.add("unknown length pointer to opaque",
3595 \\export const T = [*]@Type(.Opaque);3620 \\export const T = [*]opaque {};
3596 , &[_][]const u8{3621 , &[_][]const u8{
3597 "tmp.zig:1:21: error: unknown-length pointer to opaque",3622 "tmp.zig:1:21: error: unknown-length pointer to opaque",
3598 });3623 });
...@@ -6827,8 +6852,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -6827,8 +6852,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
6827 "tmp.zig:2:31: error: index 2 outside array of size 2",6852 "tmp.zig:2:31: error: index 2 outside array of size 2",
6828 });6853 });
68296854
6830 cases.add("wrong pointer coerced to pointer to @Type(.Opaque)",6855 cases.add("wrong pointer coerced to pointer to opaque {}",
6831 \\const Derp = @Type(.Opaque);6856 \\const Derp = opaque {};
6832 \\extern fn bar(d: *Derp) void;6857 \\extern fn bar(d: *Derp) void;
6833 \\export fn foo() void {6858 \\export fn foo() void {
6834 \\ var x = @as(u8, 1);6859 \\ var x = @as(u8, 1);
...@@ -6854,8 +6879,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -6854,8 +6879,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
6854 \\export fn entry5() void {6879 \\export fn entry5() void {
6855 \\ var d = null;6880 \\ var d = null;
6856 \\}6881 \\}
6857 \\export fn entry6(opaque: *Opaque) void {6882 \\export fn entry6(opaque_: *Opaque) void {
6858 \\ var e = opaque.*;6883 \\ var e = opaque_.*;
6859 \\}6884 \\}
6860 \\export fn entry7() void {6885 \\export fn entry7() void {
6861 \\ var f = i32;6886 \\ var f = i32;
...@@ -6866,7 +6891,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -6866,7 +6891,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
6866 \\export fn entry9() void {6891 \\export fn entry9() void {
6867 \\ var z: noreturn = return;6892 \\ var z: noreturn = return;
6868 \\}6893 \\}
6869 \\const Opaque = @Type(.Opaque);6894 \\const Opaque = opaque {};
6870 \\const Foo = struct {6895 \\const Foo = struct {
6871 \\ fn bar(self: *const Foo) void {}6896 \\ fn bar(self: *const Foo) void {}
6872 \\};6897 \\};
...@@ -7019,21 +7044,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7019,21 +7044,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7019 "tmp.zig:37:29: error: cannot store runtime value in compile time variable",7044 "tmp.zig:37:29: error: cannot store runtime value in compile time variable",
7020 });7045 });
70217046
7022 cases.add("field access of opaque type",
7023 \\const MyType = @Type(.Opaque);
7024 \\
7025 \\export fn entry() bool {
7026 \\ var x: i32 = 1;
7027 \\ return bar(@ptrCast(*MyType, &x));
7028 \\}
7029 \\
7030 \\fn bar(x: *MyType) bool {
7031 \\ return x.blah;
7032 \\}
7033 , &[_][]const u8{
7034 "tmp.zig:9:13: error: type '*MyType' does not support field access",
7035 });
7036
7037 cases.add("invalid legacy unicode escape",7047 cases.add("invalid legacy unicode escape",
7038 \\export fn entry() void {7048 \\export fn entry() void {
7039 \\ const a = '\U1234';7049 \\ const a = '\U1234';
...@@ -7623,7 +7633,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7623,7 +7633,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7623 });7633 });
76247634
7625 cases.add("function returning opaque type",7635 cases.add("function returning opaque type",
7626 \\const FooType = @Type(.Opaque);7636 \\const FooType = opaque {};
7627 \\export fn bar() !FooType {7637 \\export fn bar() !FooType {
7628 \\ return error.InvalidValue;7638 \\ return error.InvalidValue;
7629 \\}7639 \\}
...@@ -7641,7 +7651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7641,7 +7651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7641 });7651 });
76427652
7643 cases.add("generic function returning opaque type",7653 cases.add("generic function returning opaque type",
7644 \\const FooType = @Type(.Opaque);7654 \\const FooType = opaque {};
7645 \\fn generic(comptime T: type) !T {7655 \\fn generic(comptime T: type) !T {
7646 \\ return undefined;7656 \\ return undefined;
7647 \\}7657 \\}
...@@ -7665,7 +7675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -7665,7 +7675,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
7665 });7675 });
76667676
7667 cases.add("function parameter is opaque",7677 cases.add("function parameter is opaque",
7668 \\const FooType = @Type(.Opaque);7678 \\const FooType = opaque {};
7669 \\export fn entry1() void {7679 \\export fn entry1() void {
7670 \\ const someFuncPtr: fn (FooType) void = undefined;7680 \\ const someFuncPtr: fn (FooType) void = undefined;
7671 \\}7681 \\}
test/gen_h.zig+1-1
...@@ -74,7 +74,7 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -74,7 +74,7 @@ pub fn addCases(cases: *tests.GenHContext) void {
74 });74 });
7575
76 cases.add("declare opaque type",76 cases.add("declare opaque type",
77 \\const Foo = @Type(.Opaque);77 \\const Foo = opaque {};
78 \\78 \\
79 \\export fn entry(foo: ?*Foo) void { }79 \\export fn entry(foo: ?*Foo) void { }
80 , &[_][]const u8{80 , &[_][]const u8{
test/stage1/behavior/misc.zig+3-3
...@@ -438,8 +438,8 @@ export fn writeToVRam() void {...@@ -438,8 +438,8 @@ export fn writeToVRam() void {
438 vram[0] = 'X';438 vram[0] = 'X';
439}439}
440440
441const OpaqueA = @Type(.Opaque);441const OpaqueA = opaque {};
442const OpaqueB = @Type(.Opaque);442const OpaqueB = opaque {};
443test "opaque types" {443test "opaque types" {
444 expect(*OpaqueA != *OpaqueB);444 expect(*OpaqueA != *OpaqueB);
445 expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));445 expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
...@@ -704,7 +704,7 @@ test "auto created variables have correct alignment" {...@@ -704,7 +704,7 @@ test "auto created variables have correct alignment" {
704 comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);704 comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
705}705}
706706
707extern var opaque_extern_var: @Type(.Opaque);707extern var opaque_extern_var: opaque {};
708var var_to_export: u32 = 42;708var var_to_export: u32 = 42;
709test "extern variable with non-pointer opaque type" {709test "extern variable with non-pointer opaque type" {
710 @export(var_to_export, .{ .name = "opaque_extern_var" });710 @export(var_to_export, .{ .name = "opaque_extern_var" });
test/stage1/behavior/type.zig+11-2
...@@ -190,8 +190,17 @@ test "Type.ErrorUnion" {...@@ -190,8 +190,17 @@ test "Type.ErrorUnion" {
190}190}
191191
192test "Type.Opaque" {192test "Type.Opaque" {
193 testing.expect(@Type(.Opaque) != @Type(.Opaque));193 const Opaque = @Type(.{
194 testing.expect(@typeInfo(@Type(.Opaque)) == .Opaque);194 .Opaque = .{
195 .decls = &[_]TypeInfo.Declaration{},
196 },
197 });
198 testing.expect(Opaque != opaque {});
199 testing.expectEqualSlices(
200 TypeInfo.Declaration,
201 &[_]TypeInfo.Declaration{},
202 @typeInfo(Opaque).Opaque.decls,
203 );
195}204}
196205
197test "Type.Vector" {206test "Type.Vector" {
test/stage1/behavior/type_info.zig+16-1
...@@ -199,7 +199,7 @@ fn testUnion() void {...@@ -199,7 +199,7 @@ fn testUnion() void {
199 expect(typeinfo_info.Union.tag_type.? == TypeId);199 expect(typeinfo_info.Union.tag_type.? == TypeId);
200 expect(typeinfo_info.Union.fields.len == 25);200 expect(typeinfo_info.Union.fields.len == 25);
201 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));201 expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
202 expect(typeinfo_info.Union.decls.len == 21);202 expect(typeinfo_info.Union.decls.len == 22);
203203
204 const TestNoTagUnion = union {204 const TestNoTagUnion = union {
205 Foo: void,205 Foo: void,
...@@ -265,6 +265,21 @@ const TestStruct = packed struct {...@@ -265,6 +265,21 @@ const TestStruct = packed struct {
265 const Self = @This();265 const Self = @This();
266};266};
267267
268test "type info: opaque info" {
269 testOpaque();
270 comptime testOpaque();
271}
272
273fn testOpaque() void {
274 const Foo = opaque {
275 const A = 1;
276 fn b() void {}
277 };
278
279 const foo_info = @typeInfo(Foo);
280 expect(foo_info.Opaque.decls.len == 2);
281}
282
268test "type info: function type info" {283test "type info: function type info" {
269 // wasm doesn't support align attributes on functions284 // wasm doesn't support align attributes on functions
270 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;285 if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
test/translate_c.zig+7-7
...@@ -137,9 +137,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -137,9 +137,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
137 \\struct foo { int x; int y[]; };137 \\struct foo { int x; int y[]; };
138 \\struct bar { int x; int y[0]; };138 \\struct bar { int x; int y[0]; };
139 , &[_][]const u8{139 , &[_][]const u8{
140 \\pub const struct_foo = @Type(.Opaque);140 \\pub const struct_foo = opaque {};
141 ,141 ,
142 \\pub const struct_bar = @Type(.Opaque);142 \\pub const struct_bar = opaque {};
143 });143 });
144144
145 cases.add("nested loops without blocks",145 cases.add("nested loops without blocks",
...@@ -207,7 +207,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -207,7 +207,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
207 \\pub const struct_arcan_shmif_page = //207 \\pub const struct_arcan_shmif_page = //
208 ,208 ,
209 \\warning: unsupported type: 'Atomic'209 \\warning: unsupported type: 'Atomic'
210 \\ @Type(.Opaque); //210 \\ opaque {}; //
211 ,211 ,
212 \\ warning: struct demoted to opaque type - unable to translate type of field abufused212 \\ warning: struct demoted to opaque type - unable to translate type of field abufused
213 , // TODO should be `addr: *struct_arcan_shmif_page`213 , // TODO should be `addr: *struct_arcan_shmif_page`
...@@ -386,8 +386,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -386,8 +386,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
386 \\ struct opaque_2 *cast = (struct opaque_2 *)opaque;386 \\ struct opaque_2 *cast = (struct opaque_2 *)opaque;
387 \\}387 \\}
388 , &[_][]const u8{388 , &[_][]const u8{
389 \\pub const struct_opaque = @Type(.Opaque);389 \\pub const struct_opaque = opaque {};
390 \\pub const struct_opaque_2 = @Type(.Opaque);390 \\pub const struct_opaque_2 = opaque {};
391 \\pub export fn function(arg_opaque_1: ?*struct_opaque) void {391 \\pub export fn function(arg_opaque_1: ?*struct_opaque) void {
392 \\ var opaque_1 = arg_opaque_1;392 \\ var opaque_1 = arg_opaque_1;
393 \\ var cast: ?*struct_opaque_2 = @ptrCast(?*struct_opaque_2, opaque_1);393 \\ var cast: ?*struct_opaque_2 = @ptrCast(?*struct_opaque_2, opaque_1);
...@@ -628,7 +628,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -628,7 +628,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
628 \\ struct Foo *foo;628 \\ struct Foo *foo;
629 \\};629 \\};
630 , &[_][]const u8{630 , &[_][]const u8{
631 \\pub const struct_Foo = @Type(.Opaque);631 \\pub const struct_Foo = opaque {};
632 ,632 ,
633 \\pub const struct_Bar = extern struct {633 \\pub const struct_Bar = extern struct {
634 \\ foo: ?*struct_Foo,634 \\ foo: ?*struct_Foo,
...@@ -705,7 +705,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -705,7 +705,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
705 \\struct Foo;705 \\struct Foo;
706 \\struct Foo *some_func(struct Foo *foo, int x);706 \\struct Foo *some_func(struct Foo *foo, int x);
707 , &[_][]const u8{707 , &[_][]const u8{
708 \\pub const struct_Foo = @Type(.Opaque);708 \\pub const struct_Foo = opaque {};
709 ,709 ,
710 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;710 \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
711 ,711 ,