From 069fbb3c01d8be0940d60e3324213a0cde4a42d5 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Fri, 25 Sep 2020 14:12:11 -0600
Subject: [PATCH 1/7] Add opaque type syntax
---
doc/langref.html.in | 5 +--
lib/std/builtin.zig | 8 ++++-
lib/std/zig/ast.zig | 2 +-
lib/std/zig/parse.zig | 3 +-
lib/std/zig/render.zig | 14 +++++++-
lib/std/zig/tokenizer.zig | 3 ++
src/stage1/all_types.hpp | 4 +++
src/stage1/analyze.cpp | 54 ++++++++++++++++++++++++------
src/stage1/ir.cpp | 37 ++++++++++++++++++--
src/stage1/parser.cpp | 9 +++++
src/stage1/tokenizer.cpp | 2 ++
src/stage1/tokenizer.hpp | 1 +
src/translate_c.zig | 16 ++++-----
test/stage1/behavior/type.zig | 13 +++++--
test/stage1/behavior/type_info.zig | 17 +++++++++-
15 files changed, 159 insertions(+), 29 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 22faf7fd8f..690614ff99 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -11193,7 +11193,7 @@ PtrTypeStart
ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
ContainerDeclType
- <- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?
+ <- (KEYWORD_struct / KEYWORD_enum / KEYWORD_opaque) (LPAREN Expr RPAREN)?
/ KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
# Alignment
@@ -11340,6 +11340,7 @@ KEYWORD_inline <- 'inline' end_of_word
KEYWORD_noalias <- 'noalias' end_of_word
KEYWORD_nosuspend <- 'nosuspend' end_of_word
KEYWORD_null <- 'null' end_of_word
+KEYWORD_opaque <- 'opaque' end_of_word
KEYWORD_or <- 'or' end_of_word
KEYWORD_orelse <- 'orelse' end_of_word
KEYWORD_packed <- 'packed' end_of_word
@@ -11368,7 +11369,7 @@ keyword <- 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
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 68bbbe3b2d..fe72046e36 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -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,
@@ -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 {
diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig
index d8943adde0..0973877aa8 100644
--- a/lib/std/zig/ast.zig
+++ b/lib/std/zig/ast.zig
@@ -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 '{}'");
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 2af2ee4a45..467b06a5ca 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -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, .{
diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig
index 67afbb77d9..8c8a2fc50b 100644
--- a/lib/std/zig/render.zig
+++ b/lib/std/zig/render.zig
@@ -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
diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig
index e40483c022..c8f33dbfaa 100644
--- a/lib/std/zig/tokenizer.zig
+++ b/lib/std/zig/tokenizer.zig
@@ -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 },
@@ -173,6 +174,7 @@ pub const Token = struct {
Keyword_noinline,
Keyword_nosuspend,
Keyword_null,
+ Keyword_opaque,
Keyword_or,
Keyword_orelse,
Keyword_packed,
@@ -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",
diff --git a/src/stage1/all_types.hpp b/src/stage1/all_types.hpp
index c9d7755942..f43f28a85d 100644
--- a/src/stage1/all_types.hpp
+++ b/src/stage1/all_types.hpp
@@ -1054,6 +1054,7 @@ enum ContainerKind {
ContainerKindStruct,
ContainerKindEnum,
ContainerKindUnion,
+ ContainerKindOpaque,
};
enum ContainerLayout {
@@ -1571,7 +1572,10 @@ enum OnePossibleValue {
};
struct ZigTypeOpaque {
+ AstNode *decl_node;
Buf *bare_name;
+
+ ScopeDecls *decls_scope;
};
struct ZigTypeFnFrame {
diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp
index 99af1db098..6008496fe2 100644
--- a/src/stage1/analyze.cpp
+++ b/src/stage1/analyze.cpp
@@ -86,14 +86,18 @@ ZigType *new_type_table_entry(ZigTypeId id) {
}
static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {
- if (type_entry->id == ZigTypeIdStruct) {
- return &type_entry->data.structure.decls_scope;
- } else if (type_entry->id == ZigTypeIdEnum) {
- return &type_entry->data.enumeration.decls_scope;
- } else if (type_entry->id == ZigTypeIdUnion) {
- return &type_entry->data.unionation.decls_scope;
+ switch (type_entry->id) {
+ case ZigTypeIdStruct:
+ return &type_entry->data.structure.decls_scope;
+ case ZigTypeIdEnum:
+ return &type_entry->data.enumeration.decls_scope;
+ case ZigTypeIdUnion:
+ return &type_entry->data.unionation.decls_scope;
+ case ZigTypeIdOpaque:
+ return &type_entry->data.opaque.decls_scope;
+ default:
+ zig_unreachable();
}
- zig_unreachable();
}
static ScopeExpr *find_expr_scope(Scope *scope) {
@@ -912,13 +916,17 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c
ZigType *import = scope ? get_scope_import(scope) : nullptr;
unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
+ // Note: duplicated in get_partial_container_type
entry->llvm_type = LLVMInt8Type();
entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
ZigLLVMTag_DW_structure_type(), full_name,
import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
import ? import->data.structure.root_struct->di_file : nullptr,
line);
+ entry->data.opaque.decl_node = source_node;
entry->data.opaque.bare_name = bare_name;
+ entry->data.opaque.decls_scope = create_decls_scope(
+ g, source_node, scope, entry, import, &entry->name);
// The actual size is unknown, but the value must not be 0 because that
// is how type_has_bits is determined.
@@ -1080,6 +1088,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {
return ZigTypeIdEnum;
case ContainerKindUnion:
return ZigTypeIdUnion;
+ case ContainerKindOpaque:
+ return ZigTypeIdOpaque;
}
zig_unreachable();
}
@@ -1121,6 +1131,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
entry->data.unionation.decl_node = decl_node;
entry->data.unionation.layout = layout;
break;
+ case ContainerKindOpaque: {
+ ZigType *import = scope ? get_scope_import(scope) : nullptr;
+ unsigned line = decl_node ? (unsigned)(decl_node->line + 1) : 0;
+ // Note: duplicated in get_opaque_type
+ entry->llvm_type = LLVMInt8Type();
+ entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
+ ZigLLVMTag_DW_structure_type(), full_name,
+ import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
+ import ? import->data.structure.root_struct->di_file : nullptr,
+ line);
+ entry->data.opaque.decl_node = decl_node;
+ entry->abi_size = SIZE_MAX;
+ entry->size_in_bits = SIZE_MAX;
+ entry->abi_align = 1;
+ break;
+ }
}
buf_init_from_str(&entry->name, full_name);
@@ -3430,6 +3456,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorNone;
}
+static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
+ opaque_type->abi_align = UINT32_MAX;
+ opaque_type->abi_size = SIZE_MAX;
+ opaque_type->size_in_bits = SIZE_MAX;
+ return ErrorNone;
+}
+
void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {
if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;
buf_append_buf(buf, &container_type->name);
@@ -3896,6 +3929,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {
return resolve_enum_zero_bits(g, tld_container->type_entry);
case ZigTypeIdUnion:
return resolve_union_type(g, tld_container->type_entry);
+ case ZigTypeIdOpaque:
+ return resolve_opaque_type(g, tld_container->type_entry);
default:
zig_unreachable();
}
@@ -4462,6 +4497,7 @@ bool is_container(ZigType *type_entry) {
return type_entry->data.structure.special != StructSpecialSlice;
case ZigTypeIdEnum:
case ZigTypeIdUnion:
+ case ZigTypeIdOpaque:
return true;
case ZigTypeIdPointer:
case ZigTypeIdMetaType:
@@ -4481,7 +4517,6 @@ bool is_container(ZigType *type_entry) {
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
- case ZigTypeIdOpaque:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
@@ -8168,6 +8203,7 @@ const char *container_string(ContainerKind kind) {
case ContainerKindEnum: return "enum";
case ContainerKindStruct: return "struct";
case ContainerKindUnion: return "union";
+ case ContainerKindOpaque: return "opaque";
}
zig_unreachable();
}
@@ -8186,8 +8222,6 @@ Buf *type_bare_name(ZigType *type_entry) {
return &type_entry->name;
} else if (is_container(type_entry)) {
return get_container_scope(type_entry)->bare_name;
- } else if (type_entry->id == ZigTypeIdOpaque) {
- return type_entry->data.opaque.bare_name;
} else {
return &type_entry->name;
}
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
index ebda9b88f6..ad58f23ec3 100644
--- a/src/stage1/ir.cpp
+++ b/src/stage1/ir.cpp
@@ -22587,7 +22587,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
}
}
- if (bare_type->id == ZigTypeIdEnum) {
+ if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
source_instr, container_ptr, container_ptr_src, container_type);
}
@@ -25183,7 +25183,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
case ZigTypeIdEnumLiteral:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
- case ZigTypeIdOpaque:
result = ira->codegen->intern.for_void();
break;
case ZigTypeIdInt:
@@ -25737,6 +25736,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
return err;
+ break;
+ }
+ case ZigTypeIdOpaque:
+ {
+ result = ira->codegen->pass1_arena->create();
+ result->special = ConstValSpecialStatic;
+ result->type = ir_type_info_get_type(ira, "Opaque", nullptr);
+
+ ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
+ result->data.x_struct.fields = fields;
+
+ // decls: []TypeInfo.Declaration
+ ensure_field_index(result->type, "decls", 0);
+ if ((err = ir_make_type_info_decls(ira, source_instr, fields[0],
+ type_entry->data.opaque.decls_scope, false)))
+ {
+ return err;
+ }
+
break;
}
case ZigTypeIdFnFrame:
@@ -26044,6 +26062,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return get_error_union_type(ira->codegen, err_set_type, payload_type);
}
case ZigTypeIdOpaque: {
+ assert(payload->special == ConstValSpecialStatic);
+ assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr));
+
+ ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 0);
+ if (decls_value == nullptr)
+ return ira->codegen->invalid_inst_gen->value->type;
+ assert(decls_value->special == ConstValSpecialStatic);
+ assert(is_slice(decls_value->type));
+ ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
+ size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
+ if (decls_len != 0) {
+ ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type"));
+ return ira->codegen->invalid_inst_gen->value->type;
+ }
+
Buf *bare_name = buf_alloc();
Buf *full_name = get_anon_type_name(ira->codegen,
ira->old_irb.exec, "opaque", source_instr->scope, source_instr->source_node, bare_name);
diff --git a/src/stage1/parser.cpp b/src/stage1/parser.cpp
index 1253baf9ea..219f767a9c 100644
--- a/src/stage1/parser.cpp
+++ b/src/stage1/parser.cpp
@@ -2920,6 +2920,7 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
// <- KEYWORD_struct
// / KEYWORD_enum (LPAREN Expr RPAREN)?
// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
+// / KEYWORD_opaque
static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
Token *first = eat_token_if(pc, TokenIdKeywordStruct);
if (first != nullptr) {
@@ -2929,6 +2930,14 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
return res;
}
+ first = eat_token_if(pc, TokenIdKeywordOpaque);
+ if (first != nullptr) {
+ AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
+ res->data.container_decl.init_arg_expr = nullptr;
+ res->data.container_decl.kind = ContainerKindOpaque;
+ return res;
+ }
+
first = eat_token_if(pc, TokenIdKeywordEnum);
if (first != nullptr) {
AstNode *init_arg_expr = nullptr;
diff --git a/src/stage1/tokenizer.cpp b/src/stage1/tokenizer.cpp
index fa14dd40fa..f597acb701 100644
--- a/src/stage1/tokenizer.cpp
+++ b/src/stage1/tokenizer.cpp
@@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"noinline", TokenIdKeywordNoInline},
{"nosuspend", TokenIdKeywordNoSuspend},
{"null", TokenIdKeywordNull},
+ {"opaque", TokenIdKeywordOpaque},
{"or", TokenIdKeywordOr},
{"orelse", TokenIdKeywordOrElse},
{"packed", TokenIdKeywordPacked},
@@ -1595,6 +1596,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordNoInline: return "noinline";
case TokenIdKeywordNoSuspend: return "nosuspend";
case TokenIdKeywordNull: return "null";
+ case TokenIdKeywordOpaque: return "opaque";
case TokenIdKeywordOr: return "or";
case TokenIdKeywordOrElse: return "orelse";
case TokenIdKeywordPacked: return "packed";
diff --git a/src/stage1/tokenizer.hpp b/src/stage1/tokenizer.hpp
index d8af21ee00..dc12242268 100644
--- a/src/stage1/tokenizer.hpp
+++ b/src/stage1/tokenizer.hpp
@@ -81,6 +81,7 @@ enum TokenId {
TokenIdKeywordNoAlias,
TokenIdKeywordNoSuspend,
TokenIdKeywordNull,
+ TokenIdKeywordOpaque,
TokenIdKeywordOr,
TokenIdKeywordOrElse,
TokenIdKeywordPacked,
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 66b5752930..5e2c412f19 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -930,9 +930,9 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
const init_node = blk: {
const rp = makeRestorePoint(c);
const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse {
- const opaque = try transCreateNodeOpaqueType(c);
+ const opaque_type = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
- break :blk opaque;
+ break :blk opaque_type;
};
const layout_tok = try if (ZigClangRecordDecl_getPackedAttribute(record_decl))
@@ -954,17 +954,17 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
const field_qt = ZigClangFieldDecl_getType(field_decl);
if (ZigClangFieldDecl_isBitField(field_decl)) {
- const opaque = try transCreateNodeOpaqueType(c);
+ const opaque_type = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name});
- break :blk opaque;
+ break :blk opaque_type;
}
if (ZigClangType_isIncompleteOrZeroLengthArrayType(qualTypeCanon(field_qt), c.clang_context)) {
- const opaque = try transCreateNodeOpaqueType(c);
+ const opaque_type = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
try emitWarning(c, field_loc, "{} demoted to opaque type - has variable length array", .{container_kind_name});
- break :blk opaque;
+ break :blk opaque_type;
}
var is_anon = false;
@@ -979,10 +979,10 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
_ = try appendToken(c, .Colon, ":");
const field_type = transQualType(rp, field_qt, field_loc) catch |err| switch (err) {
error.UnsupportedType => {
- const opaque = try transCreateNodeOpaqueType(c);
+ const opaque_type = try transCreateNodeOpaqueType(c);
semicolon = try appendToken(c, .Semicolon, ";");
try emitWarning(c, record_loc, "{} demoted to opaque type - unable to translate type of field {}", .{ container_kind_name, raw_name });
- break :blk opaque;
+ break :blk opaque_type;
},
else => |e| return e,
};
diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig
index 60a23ffa94..53a47228db 100644
--- a/test/stage1/behavior/type.zig
+++ b/test/stage1/behavior/type.zig
@@ -190,8 +190,17 @@ test "Type.ErrorUnion" {
}
test "Type.Opaque" {
- testing.expect(@Type(.Opaque) != @Type(.Opaque));
- testing.expect(@typeInfo(@Type(.Opaque)) == .Opaque);
+ const Opaque = @Type(.{
+ .Opaque = .{
+ .decls = &[_]TypeInfo.Declaration{},
+ },
+ });
+ testing.expect(Opaque != opaque {});
+ testing.expectEqualSlices(
+ TypeInfo.Declaration,
+ &[_]TypeInfo.Declaration{},
+ @typeInfo(Opaque).Opaque.decls,
+ );
}
test "Type.Vector" {
diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig
index 8b413bf031..e663284d0d 100644
--- a/test/stage1/behavior/type_info.zig
+++ b/test/stage1/behavior/type_info.zig
@@ -199,7 +199,7 @@ fn testUnion() void {
expect(typeinfo_info.Union.tag_type.? == TypeId);
expect(typeinfo_info.Union.fields.len == 25);
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
- expect(typeinfo_info.Union.decls.len == 21);
+ expect(typeinfo_info.Union.decls.len == 22);
const TestNoTagUnion = union {
Foo: void,
@@ -265,6 +265,21 @@ const TestStruct = packed struct {
const Self = @This();
};
+test "type info: opaque info" {
+ testOpaque();
+ comptime testOpaque();
+}
+
+fn testOpaque() void {
+ const Foo = opaque {
+ const A = 1;
+ fn b() void {}
+ };
+
+ const foo_info = @typeInfo(Foo);
+ expect(foo_info.Opaque.decls.len == 2);
+}
+
test "type info: function type info" {
// wasm doesn't support align attributes on functions
if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;
From 2b4b03d301ee12126f3bb5ce1d350bac7ad48b84 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Fri, 25 Sep 2020 14:29:03 -0600
Subject: [PATCH 2/7] Update zig files for opaque type syntax
---
lib/std/c.zig | 4 +-
lib/std/os/linux/bpf/kern.zig | 50 ++++-----
lib/std/os/uefi.zig | 6 +-
lib/std/os/uefi/protocols/hii.zig | 2 +-
lib/std/os/windows/bits.zig | 30 +++---
lib/std/os/windows/ws2_32.zig | 2 +-
src/clang.zig | 172 +++++++++++++++---------------
test/compile_errors.zig | 26 ++---
test/gen_h.zig | 2 +-
test/stage1/behavior/misc.zig | 6 +-
test/translate_c.zig | 14 +--
11 files changed, 157 insertions(+), 157 deletions(-)
diff --git a/lib/std/c.zig b/lib/std/c.zig
index 7cfc44714f..a75fcaa84b 100644
--- a/lib/std/c.zig
+++ b/lib/std/c.zig
@@ -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;
diff --git a/lib/std/os/linux/bpf/kern.zig b/lib/std/os/linux/bpf/kern.zig
index 3bd605301a..a2e9d36aa1 100644
--- a/lib/std/os/linux/bpf/kern.zig
+++ b/lib/std/os/linux/bpf/kern.zig
@@ -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 {};
diff --git a/lib/std/os/uefi.zig b/lib/std/os/uefi.zig
index 0127033db2..ba1544105c 100644
--- a/lib/std/os/uefi.zig
+++ b/lib/std/os/uefi.zig
@@ -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 {
@@ -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 {
@@ -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 {};
diff --git a/lib/std/os/uefi/protocols/hii.zig b/lib/std/os/uefi/protocols/hii.zig
index 960402828e..ed7c40d6ac 100644
--- a/lib/std/os/uefi/protocols/hii.zig
+++ b/lib/std/os/uefi/protocols/hii.zig
@@ -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 {
diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig
index d22f42d6e8..bf786d5c91 100644
--- a/lib/std/os/windows/bits.zig
+++ b/lib/std/os/windows/bits.zig
@@ -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;
@@ -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;
@@ -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;
diff --git a/lib/std/os/windows/ws2_32.zig b/lib/std/os/windows/ws2_32.zig
index ac21b6ffc9..19bfc0d83e 100644
--- a/lib/std/os/windows/ws2_32.zig
+++ b/lib/std/os/windows/ws2_32.zig
@@ -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;
diff --git a/src/clang.zig b/src/clang.zig
index 2551829084..e93060edc5 100644
--- a/src/clang.zig
+++ b/src/clang.zig
@@ -1,89 +1,89 @@
const builtin = @import("builtin");
-pub const struct_ZigClangConditionalOperator = @Type(.Opaque);
-pub const struct_ZigClangBinaryConditionalOperator = @Type(.Opaque);
-pub const struct_ZigClangAbstractConditionalOperator = @Type(.Opaque);
-pub const struct_ZigClangAPInt = @Type(.Opaque);
-pub const struct_ZigClangAPSInt = @Type(.Opaque);
-pub const struct_ZigClangAPFloat = @Type(.Opaque);
-pub const struct_ZigClangASTContext = @Type(.Opaque);
-pub const struct_ZigClangASTUnit = @Type(.Opaque);
-pub const struct_ZigClangArraySubscriptExpr = @Type(.Opaque);
-pub const struct_ZigClangArrayType = @Type(.Opaque);
-pub const struct_ZigClangAttributedType = @Type(.Opaque);
-pub const struct_ZigClangBinaryOperator = @Type(.Opaque);
-pub const struct_ZigClangBreakStmt = @Type(.Opaque);
-pub const struct_ZigClangBuiltinType = @Type(.Opaque);
-pub const struct_ZigClangCStyleCastExpr = @Type(.Opaque);
-pub const struct_ZigClangCallExpr = @Type(.Opaque);
-pub const struct_ZigClangCaseStmt = @Type(.Opaque);
-pub const struct_ZigClangCompoundAssignOperator = @Type(.Opaque);
-pub const struct_ZigClangCompoundStmt = @Type(.Opaque);
-pub const struct_ZigClangConstantArrayType = @Type(.Opaque);
-pub const struct_ZigClangContinueStmt = @Type(.Opaque);
-pub const struct_ZigClangDecayedType = @Type(.Opaque);
-pub const ZigClangDecl = @Type(.Opaque);
-pub const struct_ZigClangDeclRefExpr = @Type(.Opaque);
-pub const struct_ZigClangDeclStmt = @Type(.Opaque);
-pub const struct_ZigClangDefaultStmt = @Type(.Opaque);
-pub const struct_ZigClangDiagnosticOptions = @Type(.Opaque);
-pub const struct_ZigClangDiagnosticsEngine = @Type(.Opaque);
-pub const struct_ZigClangDoStmt = @Type(.Opaque);
-pub const struct_ZigClangElaboratedType = @Type(.Opaque);
-pub const struct_ZigClangEnumConstantDecl = @Type(.Opaque);
-pub const struct_ZigClangEnumDecl = @Type(.Opaque);
-pub const struct_ZigClangEnumType = @Type(.Opaque);
-pub const struct_ZigClangExpr = @Type(.Opaque);
-pub const struct_ZigClangFieldDecl = @Type(.Opaque);
-pub const struct_ZigClangFileID = @Type(.Opaque);
-pub const struct_ZigClangForStmt = @Type(.Opaque);
-pub const struct_ZigClangFullSourceLoc = @Type(.Opaque);
-pub const struct_ZigClangFunctionDecl = @Type(.Opaque);
-pub const struct_ZigClangFunctionProtoType = @Type(.Opaque);
-pub const struct_ZigClangIfStmt = @Type(.Opaque);
-pub const struct_ZigClangImplicitCastExpr = @Type(.Opaque);
-pub const struct_ZigClangIncompleteArrayType = @Type(.Opaque);
-pub const struct_ZigClangIntegerLiteral = @Type(.Opaque);
-pub const struct_ZigClangMacroDefinitionRecord = @Type(.Opaque);
-pub const struct_ZigClangMacroExpansion = @Type(.Opaque);
-pub const struct_ZigClangMacroQualifiedType = @Type(.Opaque);
-pub const struct_ZigClangMemberExpr = @Type(.Opaque);
-pub const struct_ZigClangNamedDecl = @Type(.Opaque);
-pub const struct_ZigClangNone = @Type(.Opaque);
-pub const struct_ZigClangOpaqueValueExpr = @Type(.Opaque);
-pub const struct_ZigClangPCHContainerOperations = @Type(.Opaque);
-pub const struct_ZigClangParenExpr = @Type(.Opaque);
-pub const struct_ZigClangParenType = @Type(.Opaque);
-pub const struct_ZigClangParmVarDecl = @Type(.Opaque);
-pub const struct_ZigClangPointerType = @Type(.Opaque);
-pub const struct_ZigClangPreprocessedEntity = @Type(.Opaque);
-pub const struct_ZigClangRecordDecl = @Type(.Opaque);
-pub const struct_ZigClangRecordType = @Type(.Opaque);
-pub const struct_ZigClangReturnStmt = @Type(.Opaque);
-pub const struct_ZigClangSkipFunctionBodiesScope = @Type(.Opaque);
-pub const struct_ZigClangSourceManager = @Type(.Opaque);
-pub const struct_ZigClangSourceRange = @Type(.Opaque);
-pub const ZigClangStmt = @Type(.Opaque);
-pub const struct_ZigClangStringLiteral = @Type(.Opaque);
-pub const struct_ZigClangStringRef = @Type(.Opaque);
-pub const struct_ZigClangSwitchStmt = @Type(.Opaque);
-pub const struct_ZigClangTagDecl = @Type(.Opaque);
-pub const struct_ZigClangType = @Type(.Opaque);
-pub const struct_ZigClangTypedefNameDecl = @Type(.Opaque);
-pub const struct_ZigClangTypedefType = @Type(.Opaque);
-pub const struct_ZigClangUnaryExprOrTypeTraitExpr = @Type(.Opaque);
-pub const struct_ZigClangUnaryOperator = @Type(.Opaque);
-pub const struct_ZigClangValueDecl = @Type(.Opaque);
-pub const struct_ZigClangVarDecl = @Type(.Opaque);
-pub const struct_ZigClangWhileStmt = @Type(.Opaque);
-pub const struct_ZigClangFunctionType = @Type(.Opaque);
-pub const struct_ZigClangPredefinedExpr = @Type(.Opaque);
-pub const struct_ZigClangInitListExpr = @Type(.Opaque);
-pub const ZigClangPreprocessingRecord = @Type(.Opaque);
-pub const ZigClangFloatingLiteral = @Type(.Opaque);
-pub const ZigClangConstantExpr = @Type(.Opaque);
-pub const ZigClangCharacterLiteral = @Type(.Opaque);
-pub const ZigClangStmtExpr = @Type(.Opaque);
+pub const struct_ZigClangConditionalOperator = opaque {};
+pub const struct_ZigClangBinaryConditionalOperator = opaque {};
+pub const struct_ZigClangAbstractConditionalOperator = opaque {};
+pub const struct_ZigClangAPInt = opaque {};
+pub const struct_ZigClangAPSInt = opaque {};
+pub const struct_ZigClangAPFloat = opaque {};
+pub const struct_ZigClangASTContext = opaque {};
+pub const struct_ZigClangASTUnit = opaque {};
+pub const struct_ZigClangArraySubscriptExpr = opaque {};
+pub const struct_ZigClangArrayType = opaque {};
+pub const struct_ZigClangAttributedType = opaque {};
+pub const struct_ZigClangBinaryOperator = opaque {};
+pub const struct_ZigClangBreakStmt = opaque {};
+pub const struct_ZigClangBuiltinType = opaque {};
+pub const struct_ZigClangCStyleCastExpr = opaque {};
+pub const struct_ZigClangCallExpr = opaque {};
+pub const struct_ZigClangCaseStmt = opaque {};
+pub const struct_ZigClangCompoundAssignOperator = opaque {};
+pub const struct_ZigClangCompoundStmt = opaque {};
+pub const struct_ZigClangConstantArrayType = opaque {};
+pub const struct_ZigClangContinueStmt = opaque {};
+pub const struct_ZigClangDecayedType = opaque {};
+pub const ZigClangDecl = opaque {};
+pub const struct_ZigClangDeclRefExpr = opaque {};
+pub const struct_ZigClangDeclStmt = opaque {};
+pub const struct_ZigClangDefaultStmt = opaque {};
+pub const struct_ZigClangDiagnosticOptions = opaque {};
+pub const struct_ZigClangDiagnosticsEngine = opaque {};
+pub const struct_ZigClangDoStmt = opaque {};
+pub const struct_ZigClangElaboratedType = opaque {};
+pub const struct_ZigClangEnumConstantDecl = opaque {};
+pub const struct_ZigClangEnumDecl = opaque {};
+pub const struct_ZigClangEnumType = opaque {};
+pub const struct_ZigClangExpr = opaque {};
+pub const struct_ZigClangFieldDecl = opaque {};
+pub const struct_ZigClangFileID = opaque {};
+pub const struct_ZigClangForStmt = opaque {};
+pub const struct_ZigClangFullSourceLoc = opaque {};
+pub const struct_ZigClangFunctionDecl = opaque {};
+pub const struct_ZigClangFunctionProtoType = opaque {};
+pub const struct_ZigClangIfStmt = opaque {};
+pub const struct_ZigClangImplicitCastExpr = opaque {};
+pub const struct_ZigClangIncompleteArrayType = opaque {};
+pub const struct_ZigClangIntegerLiteral = opaque {};
+pub const struct_ZigClangMacroDefinitionRecord = opaque {};
+pub const struct_ZigClangMacroExpansion = opaque {};
+pub const struct_ZigClangMacroQualifiedType = opaque {};
+pub const struct_ZigClangMemberExpr = opaque {};
+pub const struct_ZigClangNamedDecl = opaque {};
+pub const struct_ZigClangNone = opaque {};
+pub const struct_ZigClangOpaqueValueExpr = opaque {};
+pub const struct_ZigClangPCHContainerOperations = opaque {};
+pub const struct_ZigClangParenExpr = opaque {};
+pub const struct_ZigClangParenType = opaque {};
+pub const struct_ZigClangParmVarDecl = opaque {};
+pub const struct_ZigClangPointerType = opaque {};
+pub const struct_ZigClangPreprocessedEntity = opaque {};
+pub const struct_ZigClangRecordDecl = opaque {};
+pub const struct_ZigClangRecordType = opaque {};
+pub const struct_ZigClangReturnStmt = opaque {};
+pub const struct_ZigClangSkipFunctionBodiesScope = opaque {};
+pub const struct_ZigClangSourceManager = opaque {};
+pub const struct_ZigClangSourceRange = opaque {};
+pub const ZigClangStmt = opaque {};
+pub const struct_ZigClangStringLiteral = opaque {};
+pub const struct_ZigClangStringRef = opaque {};
+pub const struct_ZigClangSwitchStmt = opaque {};
+pub const struct_ZigClangTagDecl = opaque {};
+pub const struct_ZigClangType = opaque {};
+pub const struct_ZigClangTypedefNameDecl = opaque {};
+pub const struct_ZigClangTypedefType = opaque {};
+pub const struct_ZigClangUnaryExprOrTypeTraitExpr = opaque {};
+pub const struct_ZigClangUnaryOperator = opaque {};
+pub const struct_ZigClangValueDecl = opaque {};
+pub const struct_ZigClangVarDecl = opaque {};
+pub const struct_ZigClangWhileStmt = opaque {};
+pub const struct_ZigClangFunctionType = opaque {};
+pub const struct_ZigClangPredefinedExpr = opaque {};
+pub const struct_ZigClangInitListExpr = opaque {};
+pub const ZigClangPreprocessingRecord = opaque {};
+pub const ZigClangFloatingLiteral = opaque {};
+pub const ZigClangConstantExpr = opaque {};
+pub const ZigClangCharacterLiteral = opaque {};
+pub const ZigClangStmtExpr = opaque {};
pub const ZigClangBO = extern enum {
PtrMemD,
@@ -749,11 +749,11 @@ pub const ZigClangCharacterLiteral_CharacterKind = extern enum {
};
pub const ZigClangRecordDecl_field_iterator = extern struct {
- opaque: *c_void,
+ ptr: *c_void,
};
pub const ZigClangEnumDecl_enumerator_iterator = extern struct {
- opaque: *c_void,
+ ptr: *c_void,
};
pub const ZigClangPreprocessingRecord_iterator = extern struct {
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 816d569b4d..f19e3c44c1 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -180,7 +180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{
- \\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 },
+ \\ .{ .name = "foo", .field_type = opaque {}, .alignment = 1 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
@@ -2613,7 +2613,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("directly embedding opaque type in struct and union",
- \\const O = @Type(.Opaque);
+ \\const O = opaque {};
\\const Foo = struct {
\\ o: O,
\\};
@@ -2628,7 +2628,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bar: Bar = undefined;
\\}
\\export fn c() void {
- \\ var baz: *@Type(.Opaque) = undefined;
+ \\ var baz: *opaque {} = undefined;
\\ const qux = .{baz.*};
\\}
, &[_][]const u8{
@@ -3592,7 +3592,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("unknown length pointer to opaque",
- \\export const T = [*]@Type(.Opaque);
+ \\export const T = [*]opaque {};
, &[_][]const u8{
"tmp.zig:1:21: error: unknown-length pointer to opaque",
});
@@ -6827,8 +6827,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:31: error: index 2 outside array of size 2",
});
- cases.add("wrong pointer coerced to pointer to @Type(.Opaque)",
- \\const Derp = @Type(.Opaque);
+ cases.add("wrong pointer coerced to pointer to opaque {}",
+ \\const Derp = opaque {};
\\extern fn bar(d: *Derp) void;
\\export fn foo() void {
\\ var x = @as(u8, 1);
@@ -6854,8 +6854,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry5() void {
\\ var d = null;
\\}
- \\export fn entry6(opaque: *Opaque) void {
- \\ var e = opaque.*;
+ \\export fn entry6(opaque_: *Opaque) void {
+ \\ var e = opaque_.*;
\\}
\\export fn entry7() void {
\\ var f = i32;
@@ -6866,7 +6866,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry9() void {
\\ var z: noreturn = return;
\\}
- \\const Opaque = @Type(.Opaque);
+ \\const Opaque = opaque {};
\\const Foo = struct {
\\ fn bar(self: *const Foo) void {}
\\};
@@ -7020,7 +7020,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("field access of opaque type",
- \\const MyType = @Type(.Opaque);
+ \\const MyType = opaque {};
\\
\\export fn entry() bool {
\\ var x: i32 = 1;
@@ -7623,7 +7623,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("function returning opaque type",
- \\const FooType = @Type(.Opaque);
+ \\const FooType = opaque {};
\\export fn bar() !FooType {
\\ return error.InvalidValue;
\\}
@@ -7641,7 +7641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("generic function returning opaque type",
- \\const FooType = @Type(.Opaque);
+ \\const FooType = opaque {};
\\fn generic(comptime T: type) !T {
\\ return undefined;
\\}
@@ -7665,7 +7665,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("function parameter is opaque",
- \\const FooType = @Type(.Opaque);
+ \\const FooType = opaque {};
\\export fn entry1() void {
\\ const someFuncPtr: fn (FooType) void = undefined;
\\}
diff --git a/test/gen_h.zig b/test/gen_h.zig
index 7a86d914d7..2122558079 100644
--- a/test/gen_h.zig
+++ b/test/gen_h.zig
@@ -74,7 +74,7 @@ pub fn addCases(cases: *tests.GenHContext) void {
});
cases.add("declare opaque type",
- \\const Foo = @Type(.Opaque);
+ \\const Foo = opaque {};
\\
\\export fn entry(foo: ?*Foo) void { }
, &[_][]const u8{
diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig
index a71d6f86f3..04087dd4af 100644
--- a/test/stage1/behavior/misc.zig
+++ b/test/stage1/behavior/misc.zig
@@ -438,8 +438,8 @@ export fn writeToVRam() void {
vram[0] = 'X';
}
-const OpaqueA = @Type(.Opaque);
-const OpaqueB = @Type(.Opaque);
+const OpaqueA = opaque {};
+const OpaqueB = opaque {};
test "opaque types" {
expect(*OpaqueA != *OpaqueB);
expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
@@ -704,7 +704,7 @@ test "auto created variables have correct alignment" {
comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
}
-extern var opaque_extern_var: @Type(.Opaque);
+extern var opaque_extern_var: opaque {};
var var_to_export: u32 = 42;
test "extern variable with non-pointer opaque type" {
@export(var_to_export, .{ .name = "opaque_extern_var" });
diff --git a/test/translate_c.zig b/test/translate_c.zig
index 83fdda8d81..812b3620f0 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -121,9 +121,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\struct foo { int x; int y[]; };
\\struct bar { int x; int y[0]; };
, &[_][]const u8{
- \\pub const struct_foo = @Type(.Opaque);
+ \\pub const struct_foo = opaque {};
,
- \\pub const struct_bar = @Type(.Opaque);
+ \\pub const struct_bar = opaque {};
});
cases.add("nested loops without blocks",
@@ -191,7 +191,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const struct_arcan_shmif_page = //
,
\\warning: unsupported type: 'Atomic'
- \\ @Type(.Opaque); //
+ \\ opaque {}; //
,
\\ warning: struct demoted to opaque type - unable to translate type of field abufused
, // TODO should be `addr: *struct_arcan_shmif_page`
@@ -370,8 +370,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ struct opaque_2 *cast = (struct opaque_2 *)opaque;
\\}
, &[_][]const u8{
- \\pub const struct_opaque = @Type(.Opaque);
- \\pub const struct_opaque_2 = @Type(.Opaque);
+ \\pub const struct_opaque = opaque {};
+ \\pub const struct_opaque_2 = opaque {};
\\pub export fn function(arg_opaque_1: ?*struct_opaque) void {
\\ var opaque_1 = arg_opaque_1;
\\ var cast: ?*struct_opaque_2 = @ptrCast(?*struct_opaque_2, opaque_1);
@@ -612,7 +612,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ struct Foo *foo;
\\};
, &[_][]const u8{
- \\pub const struct_Foo = @Type(.Opaque);
+ \\pub const struct_Foo = opaque {};
,
\\pub const struct_Bar = extern struct {
\\ foo: ?*struct_Foo,
@@ -689,7 +689,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\struct Foo;
\\struct Foo *some_func(struct Foo *foo, int x);
, &[_][]const u8{
- \\pub const struct_Foo = @Type(.Opaque);
+ \\pub const struct_Foo = opaque {};
,
\\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
,
From d5b8172a82f5b301b518501958ca1db11d07bc38 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Fri, 25 Sep 2020 14:49:35 -0600
Subject: [PATCH 3/7] translate_c: emit opaque {} instead of @Type(.Opaque)
---
src/translate_c.zig | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 5e2c412f19..40a46fd5ab 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -4438,10 +4438,18 @@ fn transCreateNodeFloat(c: *Context, int: anytype) !*ast.Node {
}
fn transCreateNodeOpaqueType(c: *Context) !*ast.Node {
- const call_node = try c.createBuiltinCall("@Type", 1);
- call_node.params()[0] = try transCreateNodeEnumLiteral(c, "Opaque");
- call_node.rparen_token = try appendToken(c, .RParen, ")");
- return &call_node.base;
+ const container_tok = try appendToken(c, .Keyword_opaque, "opaque");
+ const lbrace_token = try appendToken(c, .LBrace, "{");
+ const container_node = try ast.Node.ContainerDecl.alloc(c.arena, 0);
+ container_node.* = .{
+ .kind_token = container_tok,
+ .layout_token = null,
+ .lbrace_token = lbrace_token,
+ .rbrace_token = try appendToken(c, .RBrace, "}"),
+ .fields_and_decls_len = 0,
+ .init_arg_expr = .None,
+ };
+ return &container_node.base;
}
fn transCreateNodeMacroFn(c: *Context, name: []const u8, ref: *ast.Node, proto_alias: *ast.Node.FnProto) !*ast.Node {
From d71f339395f8a3a3c09bbb2d51e6f35cb5295d14 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Fri, 25 Sep 2020 17:14:13 -0600
Subject: [PATCH 4/7] stage1: disallow fields in opaque types
---
src/stage1/analyze.cpp | 16 ++++++++++++----
test/compile_errors.zig | 10 ++++++++++
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp
index 6008496fe2..b22f0ef393 100644
--- a/src/stage1/analyze.cpp
+++ b/src/stage1/analyze.cpp
@@ -3457,10 +3457,18 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
- opaque_type->abi_align = UINT32_MAX;
- opaque_type->abi_size = SIZE_MAX;
- opaque_type->size_in_bits = SIZE_MAX;
- return ErrorNone;
+ Error err = ErrorNone;
+ AstNode *container_node = opaque_type->data.opaque.decl_node;
+ if (container_node != nullptr) {
+ assert(container_node->type == NodeTypeContainerDecl);
+ AstNodeContainerDecl *container_decl = &container_node->data.container_decl;
+ for (int i = 0; i < container_decl->fields.length; i++) {
+ AstNode *field_node = container_decl->fields.items[i];
+ add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields"));
+ err = ErrorSemanticAnalyzeFail;
+ }
+ }
+ return err;
}
void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index f19e3c44c1..6c2e96fc5e 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -125,6 +125,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:23: error: enum field missing: 'arst'",
"tmp.zig:27:24: note: referenced here",
});
+
+ cases.add("opaque type with field",
+ \\const Opaque = opaque { foo: i32 };
+ \\export fn entry() void {
+ \\ const foo: ?*Opaque = null;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:1:25: error: opaque types cannot have fields",
+ });
+
cases.add("@Type(.Fn) with is_generic = true",
\\const Foo = @Type(.{
\\ .Fn = .{
From 0a563902305369ca298f5b2d360be55f4d5a95e8 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Fri, 25 Sep 2020 17:19:32 -0600
Subject: [PATCH 5/7] stage1: use size_t over int as index in
resolve_opaque_type
---
src/stage1/analyze.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/stage1/analyze.cpp b/src/stage1/analyze.cpp
index b22f0ef393..e7fd421fd1 100644
--- a/src/stage1/analyze.cpp
+++ b/src/stage1/analyze.cpp
@@ -3462,7 +3462,7 @@ static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
if (container_node != nullptr) {
assert(container_node->type == NodeTypeContainerDecl);
AstNodeContainerDecl *container_decl = &container_node->data.container_decl;
- for (int i = 0; i < container_decl->fields.length; i++) {
+ for (size_t i = 0; i < container_decl->fields.length; i++) {
AstNode *field_node = container_decl->fields.items[i];
add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields"));
err = ErrorSemanticAnalyzeFail;
From 6b8ae6fffb71128169de447851244869aebb882b Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Sat, 26 Sep 2020 09:05:11 -0600
Subject: [PATCH 6/7] langref: update for opaque {} syntax
---
doc/docgen.zig | 1 +
doc/langref.html.in | 15 ++++++++-------
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/doc/docgen.zig b/doc/docgen.zig
index 50523d0948..52f373f5b1 100644
--- a/doc/docgen.zig
+++ b/doc/docgen.zig
@@ -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,
diff --git a/doc/langref.html.in b/doc/langref.html.in
index 690614ff99..021fc76289 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -1988,7 +1988,7 @@ test "null terminated array" {
Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}
Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}
{#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#}.
+ {#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|opaque#}.
@@ -5545,7 +5545,7 @@ test "turn HashMap into a set with void" {
{#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.
@@ -8471,7 +8471,7 @@ test "integer truncation" {
{#link|Error Set Type#}
{#link|Error Union Type#}
{#link|Vectors#}
- {#link|Opaque Types#}
+ {#link|opaque#}
{#link|@Frame#}
{#syntax#}anyframe{#endsyntax#}
{#link|struct#}
@@ -8547,17 +8547,18 @@ fn foo(comptime T: type, ptr: *T) T {
{#header_close#}
{#header_close#}
- {#header_open|Opaque Types#}
+ {#header_open|opaque#}
- {#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.
This is typically used for type safety when interacting with C code that does not expose struct details.
Example:
{#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 {
From bf4bfe54ac13512d7553a7be83ae19e908e9c294 Mon Sep 17 00:00:00 2001
From: Tadeo Kondrak
Date: Sat, 26 Sep 2020 11:55:56 -0600
Subject: [PATCH 7/7] Update compile error test for field access of opaque type
---
src/stage1/ir.cpp | 2 ++
test/compile_errors.zig | 30 +++++++++++++++---------------
2 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/src/stage1/ir.cpp b/src/stage1/ir.cpp
index ad58f23ec3..002b7f3c87 100644
--- a/src/stage1/ir.cpp
+++ b/src/stage1/ir.cpp
@@ -22387,6 +22387,8 @@ static IrInstGen *ir_analyze_container_member_access_inner(IrAnalyze *ira,
prefix_name = "enum ";
} else if (bare_struct_type->id == ZigTypeIdUnion) {
prefix_name = "union ";
+ } else if (bare_struct_type->id == ZigTypeIdOpaque) {
+ prefix_name = "opaque type ";
} else {
prefix_name = "";
}
diff --git a/test/compile_errors.zig b/test/compile_errors.zig
index 6c2e96fc5e..d5c4fd3ec1 100644
--- a/test/compile_errors.zig
+++ b/test/compile_errors.zig
@@ -126,6 +126,21 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:27:24: note: referenced here",
});
+ cases.add("field access of opaque type",
+ \\const MyType = opaque {};
+ \\
+ \\export fn entry() bool {
+ \\ var x: i32 = 1;
+ \\ return bar(@ptrCast(*MyType, &x));
+ \\}
+ \\
+ \\fn bar(x: *MyType) bool {
+ \\ return x.blah;
+ \\}
+ , &[_][]const u8{
+ "tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'",
+ });
+
cases.add("opaque type with field",
\\const Opaque = opaque { foo: i32 };
\\export fn entry() void {
@@ -7029,21 +7044,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:37:29: error: cannot store runtime value in compile time variable",
});
- cases.add("field access of opaque type",
- \\const MyType = opaque {};
- \\
- \\export fn entry() bool {
- \\ var x: i32 = 1;
- \\ return bar(@ptrCast(*MyType, &x));
- \\}
- \\
- \\fn bar(x: *MyType) bool {
- \\ return x.blah;
- \\}
- , &[_][]const u8{
- "tmp.zig:9:13: error: type '*MyType' does not support field access",
- });
-
cases.add("invalid legacy unicode escape",
\\export fn entry() void {
\\ const a = '\U1234';