Skip to content

Add opaque syntax that allows declarations #6421

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/docgen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:
.Keyword_noalias,
.Keyword_noinline,
.Keyword_nosuspend,
.Keyword_opaque,
.Keyword_or,
.Keyword_orelse,
.Keyword_packed,
Expand Down
20 changes: 11 additions & 9 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -1988,7 +1988,7 @@ test "null terminated array" {
<li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li>
<li>Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}</li>
<li>{#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be
{#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|Opaque Types#}.</li>
{#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|opaque#}.</li>
</ul>
</li>
</ul>
Expand Down Expand Up @@ -5545,7 +5545,7 @@ test "turn HashMap into a set with void" {
</p>
<p>
{#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}, which is defined like this:
{#syntax#}pub const c_void = @Type(.Opaque);{#endsyntax#}.
{#syntax#}pub const c_void = opaque {};{#endsyntax#}.
{#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size.
</p>
<p>
Expand Down Expand Up @@ -8471,7 +8471,7 @@ test "integer truncation" {
<li>{#link|Error Set Type#}</li>
<li>{#link|Error Union Type#}</li>
<li>{#link|Vectors#}</li>
<li>{#link|Opaque Types#}</li>
<li>{#link|opaque#}</li>
<li>{#link|@Frame#}</li>
<li>{#syntax#}anyframe{#endsyntax#}</li>
<li>{#link|struct#}</li>
Expand Down Expand Up @@ -8547,17 +8547,18 @@ fn foo(comptime T: type, ptr: *T) T {
{#header_close#}
{#header_close#}

{#header_open|Opaque Types#}
{#header_open|opaque#}
<p>
{#syntax#}@Type(.Opaque){#endsyntax#} creates a new type with an unknown (but non-zero) size and alignment.
{#syntax#}opaque {}{#endsyntax#} declares a new type with an unknown (but non-zero) size and alignment.
It can have declarations like structs, unions, or enums.
</p>
<p>
This is typically used for type safety when interacting with C code that does not expose struct details.
Example:
</p>
{#code_begin|test_err|expected type '*Derp', found '*Wat'#}
const Derp = @Type(.Opaque);
const Wat = @Type(.Opaque);
const Derp = opaque {};
const Wat = opaque {};

extern fn bar(d: *Derp) void;
fn foo(w: *Wat) callconv(.C) void {
Expand Down Expand Up @@ -11193,7 +11194,7 @@ PtrTypeStart
ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE

ContainerDeclType
&lt;- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?
&lt;- (KEYWORD_struct / KEYWORD_enum / KEYWORD_opaque) (LPAREN Expr RPAREN)?
/ KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?

# Alignment
Expand Down Expand Up @@ -11340,6 +11341,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word
KEYWORD_noalias &lt;- 'noalias' end_of_word
KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word
KEYWORD_null &lt;- 'null' end_of_word
KEYWORD_opaque &lt;- 'opaque' end_of_word
KEYWORD_or &lt;- 'or' end_of_word
KEYWORD_orelse &lt;- 'orelse' end_of_word
KEYWORD_packed &lt;- 'packed' end_of_word
Expand Down Expand Up @@ -11368,7 +11370,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype
/ KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
/ KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
/ KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline
/ KEYWORD_noalias / KEYWORD_null / KEYWORD_or
/ KEYWORD_noalias / KEYWORD_null / KEYWORD_opaque / KEYWORD_or
/ KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub
/ KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
/ KEYWORD_struct / KEYWORD_suspend
Expand Down
8 changes: 7 additions & 1 deletion lib/std/builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub const TypeInfo = union(enum) {
Union: Union,
Fn: Fn,
BoundFn: Fn,
Opaque: void,
Opaque: Opaque,
Frame: Frame,
AnyFrame: AnyFrame,
Vector: Vector,
Expand Down Expand Up @@ -360,6 +360,12 @@ pub const TypeInfo = union(enum) {
args: []const FnArg,
};

/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Opaque = struct {
decls: []const Declaration,
};

/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Frame = struct {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;

pub const pthread_t = *@Type(.Opaque);
pub const FILE = @Type(.Opaque);
pub const pthread_t = *opaque {};
pub const FILE = opaque {};

pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;
pub extern "c" fn dlclose(handle: *c_void) c_int;
Expand Down
50 changes: 25 additions & 25 deletions lib/std/os/linux/bpf/kern.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) {

pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};

pub const BpfSock = @Type(.Opaque);
pub const BpfSockAddr = @Type(.Opaque);
pub const FibLookup = @Type(.Opaque);
pub const MapDef = @Type(.Opaque);
pub const PerfEventData = @Type(.Opaque);
pub const PerfEventValue = @Type(.Opaque);
pub const PidNsInfo = @Type(.Opaque);
pub const SeqFile = @Type(.Opaque);
pub const SkBuff = @Type(.Opaque);
pub const SkMsgMd = @Type(.Opaque);
pub const SkReusePortMd = @Type(.Opaque);
pub const Sock = @Type(.Opaque);
pub const SockAddr = @Type(.Opaque);
pub const SockOps = @Type(.Opaque);
pub const SockTuple = @Type(.Opaque);
pub const SpinLock = @Type(.Opaque);
pub const SysCtl = @Type(.Opaque);
pub const Tcp6Sock = @Type(.Opaque);
pub const TcpRequestSock = @Type(.Opaque);
pub const TcpSock = @Type(.Opaque);
pub const TcpTimewaitSock = @Type(.Opaque);
pub const TunnelKey = @Type(.Opaque);
pub const Udp6Sock = @Type(.Opaque);
pub const XdpMd = @Type(.Opaque);
pub const XfrmState = @Type(.Opaque);
pub const BpfSock = opaque {};
pub const BpfSockAddr = opaque {};
pub const FibLookup = opaque {};
pub const MapDef = opaque {};
pub const PerfEventData = opaque {};
pub const PerfEventValue = opaque {};
pub const PidNsInfo = opaque {};
pub const SeqFile = opaque {};
pub const SkBuff = opaque {};
pub const SkMsgMd = opaque {};
pub const SkReusePortMd = opaque {};
pub const Sock = opaque {};
pub const SockAddr = opaque {};
pub const SockOps = opaque {};
pub const SockTuple = opaque {};
pub const SpinLock = opaque {};
pub const SysCtl = opaque {};
pub const Tcp6Sock = opaque {};
pub const TcpRequestSock = opaque {};
pub const TcpSock = opaque {};
pub const TcpTimewaitSock = opaque {};
pub const TunnelKey = opaque {};
pub const Udp6Sock = opaque {};
pub const XdpMd = opaque {};
pub const XfrmState = opaque {};
6 changes: 3 additions & 3 deletions lib/std/os/uefi.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub var handle: Handle = undefined;
pub var system_table: *tables.SystemTable = undefined;

/// A handle to an event structure.
pub const Event = *@Type(.Opaque);
pub const Event = *opaque {};

/// GUIDs must be align(8)
pub const Guid = extern struct {
Expand Down Expand Up @@ -51,7 +51,7 @@ pub const Guid = extern struct {
};

/// An EFI Handle represents a collection of related interfaces.
pub const Handle = *@Type(.Opaque);
pub const Handle = *opaque {};

/// This structure represents time information.
pub const Time = extern struct {
Expand Down Expand Up @@ -108,4 +108,4 @@ pub const TimeCapabilities = extern struct {
};

/// File Handle as specified in the EFI Shell Spec
pub const FileHandle = *@Type(.Opaque);
pub const FileHandle = *opaque {};
2 changes: 1 addition & 1 deletion lib/std/os/uefi/protocols/hii.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
const uefi = @import("std").os.uefi;
const Guid = uefi.Guid;

pub const HIIHandle = *@Type(.Opaque);
pub const HIIHandle = *opaque {};

/// The header found at the start of each package.
pub const HIIPackageHeader = packed struct {
Expand Down
30 changes: 15 additions & 15 deletions lib/std/os/windows/bits.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ pub const UCHAR = u8;
pub const FLOAT = f32;
pub const HANDLE = *c_void;
pub const HCRYPTPROV = ULONG_PTR;
pub const HBRUSH = *@Type(.Opaque);
pub const HCURSOR = *@Type(.Opaque);
pub const HICON = *@Type(.Opaque);
pub const HINSTANCE = *@Type(.Opaque);
pub const HMENU = *@Type(.Opaque);
pub const HMODULE = *@Type(.Opaque);
pub const HWND = *@Type(.Opaque);
pub const HDC = *@Type(.Opaque);
pub const HGLRC = *@Type(.Opaque);
pub const FARPROC = *@Type(.Opaque);
pub const HBRUSH = *opaque {};
pub const HCURSOR = *opaque {};
pub const HICON = *opaque {};
pub const HINSTANCE = *opaque {};
pub const HMENU = *opaque {};
pub const HMODULE = *opaque {};
pub const HWND = *opaque {};
pub const HDC = *opaque {};
pub const HGLRC = *opaque {};
pub const FARPROC = *opaque {};
pub const INT = c_int;
pub const LPBYTE = *BYTE;
pub const LPCH = *CHAR;
Expand Down Expand Up @@ -81,7 +81,7 @@ pub const WPARAM = usize;
pub const LPARAM = ?*c_void;
pub const LRESULT = ?*c_void;

pub const va_list = *@Type(.Opaque);
pub const va_list = *opaque {};

pub const TRUE = 1;
pub const FALSE = 0;
Expand Down Expand Up @@ -1175,10 +1175,10 @@ pub const UNICODE_STRING = extern struct {
Buffer: [*]WCHAR,
};

const ACTIVATION_CONTEXT_DATA = @Type(.Opaque);
const ASSEMBLY_STORAGE_MAP = @Type(.Opaque);
const FLS_CALLBACK_INFO = @Type(.Opaque);
const RTL_BITMAP = @Type(.Opaque);
const ACTIVATION_CONTEXT_DATA = opaque {};
const ASSEMBLY_STORAGE_MAP = opaque {};
const FLS_CALLBACK_INFO = opaque {};
const RTL_BITMAP = opaque {};
pub const PRTL_BITMAP = *RTL_BITMAP;
const KAFFINITY = usize;

Expand Down
2 changes: 1 addition & 1 deletion lib/std/os/windows/ws2_32.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// and substantial portions of the software.
usingnamespace @import("bits.zig");

pub const SOCKET = *@Type(.Opaque);
pub const SOCKET = *opaque {};
pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
pub const SOCKET_ERROR = -1;

Expand Down
2 changes: 1 addition & 1 deletion lib/std/zig/ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ pub const Error = union(enum) {
pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");
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 '{}'");
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");
Expand Down
3 changes: 2 additions & 1 deletion lib/std/zig/parse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2896,11 +2896,12 @@ const Parser = struct {
/// <- KEYWORD_struct
/// / KEYWORD_enum (LPAREN Expr RPAREN)?
/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
/// / KEYWORD_opaque
fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
const kind_token = p.nextToken();

const init_arg_expr = switch (p.token_ids[kind_token]) {
.Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
.Keyword_struct, .Keyword_opaque => Node.ContainerDecl.InitArg{ .None = {} },
.Keyword_enum => blk: {
if (p.eatToken(.LParen) != null) {
const expr = try p.expectNode(parseExpr, .{
Expand Down
14 changes: 13 additions & 1 deletion lib/std/zig/render.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,19 @@ fn renderExpression(

// TODO remove after 0.7.0 release
if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
return ais.writer().writeAll("@Type(.Opaque)");
return ais.writer().writeAll("opaque {}");

// TODO remove after 0.7.0 release
{
const params = builtin_call.paramsConst();
if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
params.len == 1)
{
if (params[0].castTag(.EnumLiteral)) |enum_literal|
if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
return ais.writer().writeAll("opaque {}");
}
}

try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name

Expand Down
3 changes: 3 additions & 0 deletions lib/std/zig/tokenizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub const Token = struct {
.{ "noinline", .Keyword_noinline },
.{ "nosuspend", .Keyword_nosuspend },
.{ "null", .Keyword_null },
.{ "opaque", .Keyword_opaque },
.{ "or", .Keyword_or },
.{ "orelse", .Keyword_orelse },
.{ "packed", .Keyword_packed },
Expand Down Expand Up @@ -173,6 +174,7 @@ pub const Token = struct {
Keyword_noinline,
Keyword_nosuspend,
Keyword_null,
Keyword_opaque,
Keyword_or,
Keyword_orelse,
Keyword_packed,
Expand Down Expand Up @@ -296,6 +298,7 @@ pub const Token = struct {
.Keyword_noinline => "noinline",
.Keyword_nosuspend => "nosuspend",
.Keyword_null => "null",
.Keyword_opaque => "opaque",
.Keyword_or => "or",
.Keyword_orelse => "orelse",
.Keyword_packed => "packed",
Expand Down
Loading