authorgravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-09-25 14:12:11-06:00
committergravatar for me@tadeo.caTadeo Kondrak <me@tadeo.ca> 2020-10-06 22:08:24-06:00
log069fbb3c01d8be0940d60e3324213a0cde4a42d5
tree6e236ae2f9cca59057afd945ec5cad6fee855d27
parent7f7e2d608adb81cd00e54fd7fe5e7035a890565f
signaturelock-open Commit is signed but in an unrecognized format.

Add opaque type syntax


15 files changed, 159 insertions(+), 29 deletions(-)

doc/langref.html.in+3-2
...@@ -11193,7 +11193,7 @@ PtrTypeStart...@@ -11193,7 +11193,7 @@ PtrTypeStart
11193ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE11193ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE
1119411194
11195ContainerDeclType11195ContainerDeclType
11196 &lt;- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?11196 &lt;- (KEYWORD_struct / KEYWORD_enum / KEYWORD_opaque) (LPAREN Expr RPAREN)?
11197 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?11197 / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
1119811198
11199# Alignment11199# Alignment
...@@ -11340,6 +11340,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word...@@ -11340,6 +11340,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word
11340KEYWORD_noalias &lt;- 'noalias' end_of_word11340KEYWORD_noalias &lt;- 'noalias' end_of_word
11341KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word11341KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word
11342KEYWORD_null &lt;- 'null' end_of_word11342KEYWORD_null &lt;- 'null' end_of_word
11343KEYWORD_opaque &lt;- 'opaque' end_of_word
11343KEYWORD_or &lt;- 'or' end_of_word11344KEYWORD_or &lt;- 'or' end_of_word
11344KEYWORD_orelse &lt;- 'orelse' end_of_word11345KEYWORD_orelse &lt;- 'orelse' end_of_word
11345KEYWORD_packed &lt;- 'packed' end_of_word11346KEYWORD_packed &lt;- 'packed' end_of_word
...@@ -11368,7 +11369,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype...@@ -11368,7 +11369,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype
11368 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer11369 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
11369 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false11370 / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
11370 / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline11371 / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline
11371 / KEYWORD_noalias / KEYWORD_null / KEYWORD_or11372 / KEYWORD_noalias / KEYWORD_null / KEYWORD_opaque / KEYWORD_or
11372 / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub11373 / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub
11373 / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection11374 / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
11374 / KEYWORD_struct / KEYWORD_suspend11375 / KEYWORD_struct / KEYWORD_suspend
lib/std/builtin.zig+7-1
...@@ -199,7 +199,7 @@ pub const TypeInfo = union(enum) {...@@ -199,7 +199,7 @@ pub const TypeInfo = union(enum) {
199 Union: Union,199 Union: Union,
200 Fn: Fn,200 Fn: Fn,
201 BoundFn: Fn,201 BoundFn: Fn,
202 Opaque: void,202 Opaque: Opaque,
203 Frame: Frame,203 Frame: Frame,
204 AnyFrame: AnyFrame,204 AnyFrame: AnyFrame,
205 Vector: Vector,205 Vector: Vector,
...@@ -360,6 +360,12 @@ pub const TypeInfo = union(enum) {...@@ -360,6 +360,12 @@ pub const TypeInfo = union(enum) {
360 args: []const FnArg,360 args: []const FnArg,
361 };361 };
362362
363 /// This data structure is used by the Zig language code generation and
364 /// therefore must be kept in sync with the compiler implementation.
365 pub const Opaque = struct {
366 decls: []const Declaration,
367 };
368
363 /// This data structure is used by the Zig language code generation and369 /// This data structure is used by the Zig language code generation and
364 /// therefore must be kept in sync with the compiler implementation.370 /// therefore must be kept in sync with the compiler implementation.
365 pub const Frame = struct {371 pub const Frame = struct {
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/stage1/all_types.hpp+4
...@@ -1054,6 +1054,7 @@ enum ContainerKind {...@@ -1054,6 +1054,7 @@ enum ContainerKind {
1054 ContainerKindStruct,1054 ContainerKindStruct,
1055 ContainerKindEnum,1055 ContainerKindEnum,
1056 ContainerKindUnion,1056 ContainerKindUnion,
1057 ContainerKindOpaque,
1057};1058};
10581059
1059enum ContainerLayout {1060enum ContainerLayout {
...@@ -1571,7 +1572,10 @@ enum OnePossibleValue {...@@ -1571,7 +1572,10 @@ enum OnePossibleValue {
1571};1572};
15721573
1573struct ZigTypeOpaque {1574struct ZigTypeOpaque {
1575 AstNode *decl_node;
1574 Buf *bare_name;1576 Buf *bare_name;
1577
1578 ScopeDecls *decls_scope;
1575};1579};
15761580
1577struct ZigTypeFnFrame {1581struct ZigTypeFnFrame {
src/stage1/analyze.cpp+44-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.
...@@ -1080,6 +1088,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {...@@ -1080,6 +1088,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {
1080 return ZigTypeIdEnum;1088 return ZigTypeIdEnum;
1081 case ContainerKindUnion:1089 case ContainerKindUnion:
1082 return ZigTypeIdUnion;1090 return ZigTypeIdUnion;
1091 case ContainerKindOpaque:
1092 return ZigTypeIdOpaque;
1083 }1093 }
1084 zig_unreachable();1094 zig_unreachable();
1085}1095}
...@@ -1121,6 +1131,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind...@@ -1121,6 +1131,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
1121 entry->data.unionation.decl_node = decl_node;1131 entry->data.unionation.decl_node = decl_node;
1122 entry->data.unionation.layout = layout;1132 entry->data.unionation.layout = layout;
1123 break;1133 break;
1134 case ContainerKindOpaque: {
1135 ZigType *import = scope ? get_scope_import(scope) : nullptr;
1136 unsigned line = decl_node ? (unsigned)(decl_node->line + 1) : 0;
1137 // Note: duplicated in get_opaque_type
1138 entry->llvm_type = LLVMInt8Type();
1139 entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
1140 ZigLLVMTag_DW_structure_type(), full_name,
1141 import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
1142 import ? import->data.structure.root_struct->di_file : nullptr,
1143 line);
1144 entry->data.opaque.decl_node = decl_node;
1145 entry->abi_size = SIZE_MAX;
1146 entry->size_in_bits = SIZE_MAX;
1147 entry->abi_align = 1;
1148 break;
1149 }
1124 }1150 }
11251151
1126 buf_init_from_str(&entry->name, full_name);1152 buf_init_from_str(&entry->name, full_name);
...@@ -3430,6 +3456,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {...@@ -3430,6 +3456,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
3430 return ErrorNone;3456 return ErrorNone;
3431}3457}
34323458
3459static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
3460 opaque_type->abi_align = UINT32_MAX;
3461 opaque_type->abi_size = SIZE_MAX;
3462 opaque_type->size_in_bits = SIZE_MAX;
3463 return ErrorNone;
3464}
3465
3433void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {3466void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {
3434 if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;3467 if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;
3435 buf_append_buf(buf, &container_type->name);3468 buf_append_buf(buf, &container_type->name);
...@@ -3896,6 +3929,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {...@@ -3896,6 +3929,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {
3896 return resolve_enum_zero_bits(g, tld_container->type_entry);3929 return resolve_enum_zero_bits(g, tld_container->type_entry);
3897 case ZigTypeIdUnion:3930 case ZigTypeIdUnion:
3898 return resolve_union_type(g, tld_container->type_entry);3931 return resolve_union_type(g, tld_container->type_entry);
3932 case ZigTypeIdOpaque:
3933 return resolve_opaque_type(g, tld_container->type_entry);
3899 default:3934 default:
3900 zig_unreachable();3935 zig_unreachable();
3901 }3936 }
...@@ -4462,6 +4497,7 @@ bool is_container(ZigType *type_entry) {...@@ -4462,6 +4497,7 @@ bool is_container(ZigType *type_entry) {
4462 return type_entry->data.structure.special != StructSpecialSlice;4497 return type_entry->data.structure.special != StructSpecialSlice;
4463 case ZigTypeIdEnum:4498 case ZigTypeIdEnum:
4464 case ZigTypeIdUnion:4499 case ZigTypeIdUnion:
4500 case ZigTypeIdOpaque:
4465 return true;4501 return true;
4466 case ZigTypeIdPointer:4502 case ZigTypeIdPointer:
4467 case ZigTypeIdMetaType:4503 case ZigTypeIdMetaType:
...@@ -4481,7 +4517,6 @@ bool is_container(ZigType *type_entry) {...@@ -4481,7 +4517,6 @@ bool is_container(ZigType *type_entry) {
4481 case ZigTypeIdErrorSet:4517 case ZigTypeIdErrorSet:
4482 case ZigTypeIdFn:4518 case ZigTypeIdFn:
4483 case ZigTypeIdBoundFn:4519 case ZigTypeIdBoundFn:
4484 case ZigTypeIdOpaque:
4485 case ZigTypeIdVector:4520 case ZigTypeIdVector:
4486 case ZigTypeIdFnFrame:4521 case ZigTypeIdFnFrame:
4487 case ZigTypeIdAnyFrame:4522 case ZigTypeIdAnyFrame:
...@@ -8168,6 +8203,7 @@ const char *container_string(ContainerKind kind) {...@@ -8168,6 +8203,7 @@ const char *container_string(ContainerKind kind) {
8168 case ContainerKindEnum: return "enum";8203 case ContainerKindEnum: return "enum";
8169 case ContainerKindStruct: return "struct";8204 case ContainerKindStruct: return "struct";
8170 case ContainerKindUnion: return "union";8205 case ContainerKindUnion: return "union";
8206 case ContainerKindOpaque: return "opaque";
8171 }8207 }
8172 zig_unreachable();8208 zig_unreachable();
8173}8209}
...@@ -8186,8 +8222,6 @@ Buf *type_bare_name(ZigType *type_entry) {...@@ -8186,8 +8222,6 @@ Buf *type_bare_name(ZigType *type_entry) {
8186 return &type_entry->name;8222 return &type_entry->name;
8187 } else if (is_container(type_entry)) {8223 } else if (is_container(type_entry)) {
8188 return get_container_scope(type_entry)->bare_name;8224 return get_container_scope(type_entry)->bare_name;
8189 } else if (type_entry->id == ZigTypeIdOpaque) {
8190 return type_entry->data.opaque.bare_name;
8191 } else {8225 } else {
8192 return &type_entry->name;8226 return &type_entry->name;
8193 }8227 }
src/stage1/ir.cpp+35-2
...@@ -22587,7 +22587,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name...@@ -22587,7 +22587,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
22587 }22587 }
22588 }22588 }
2258922589
22590 if (bare_type->id == ZigTypeIdEnum) {22590 if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) {
22591 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,22591 return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
22592 source_instr, container_ptr, container_ptr_src, container_type);22592 source_instr, container_ptr, container_ptr_src, container_type);
22593 }22593 }
...@@ -25183,7 +25183,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25183,7 +25183,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25183 case ZigTypeIdEnumLiteral:25183 case ZigTypeIdEnumLiteral:
25184 case ZigTypeIdUndefined:25184 case ZigTypeIdUndefined:
25185 case ZigTypeIdNull:25185 case ZigTypeIdNull:
25186 case ZigTypeIdOpaque:
25187 result = ira->codegen->intern.for_void();25186 result = ira->codegen->intern.for_void();
25188 break;25187 break;
25189 case ZigTypeIdInt:25188 case ZigTypeIdInt:
...@@ -25737,6 +25736,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy...@@ -25737,6 +25736,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
25737 if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))25736 if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
25738 return err;25737 return err;
2573925738
25739 break;
25740 }
25741 case ZigTypeIdOpaque:
25742 {
25743 result = ira->codegen->pass1_arena->create<ZigValue>();
25744 result->special = ConstValSpecialStatic;
25745 result->type = ir_type_info_get_type(ira, "Opaque", nullptr);
25746
25747 ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
25748 result->data.x_struct.fields = fields;
25749
25750 // decls: []TypeInfo.Declaration
25751 ensure_field_index(result->type, "decls", 0);
25752 if ((err = ir_make_type_info_decls(ira, source_instr, fields[0],
25753 type_entry->data.opaque.decls_scope, false)))
25754 {
25755 return err;
25756 }
25757
25740 break;25758 break;
25741 }25759 }
25742 case ZigTypeIdFnFrame:25760 case ZigTypeIdFnFrame:
...@@ -26044,6 +26062,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI...@@ -26044,6 +26062,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
26044 return get_error_union_type(ira->codegen, err_set_type, payload_type);26062 return get_error_union_type(ira->codegen, err_set_type, payload_type);
26045 }26063 }
26046 case ZigTypeIdOpaque: {26064 case ZigTypeIdOpaque: {
26065 assert(payload->special == ConstValSpecialStatic);
26066 assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr));
26067
26068 ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 0);
26069 if (decls_value == nullptr)
26070 return ira->codegen->invalid_inst_gen->value->type;
26071 assert(decls_value->special == ConstValSpecialStatic);
26072 assert(is_slice(decls_value->type));
26073 ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
26074 size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
26075 if (decls_len != 0) {
26076 ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type"));
26077 return ira->codegen->invalid_inst_gen->value->type;
26078 }
26079
26047 Buf *bare_name = buf_alloc();26080 Buf *bare_name = buf_alloc();
26048 Buf *full_name = get_anon_type_name(ira->codegen,26081 Buf *full_name = get_anon_type_name(ira->codegen,
26049 ira->old_irb.exec, "opaque", source_instr->scope, source_instr->source_node, bare_name);26082 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+8-8
...@@ -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 };
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;