| author | |
| committer | |
| log | 069fbb3c01d8be0940d60e3324213a0cde4a42d5 |
| tree | 6e236ae2f9cca59057afd945ec5cad6fee855d27 |
| parent | 7f7e2d608adb81cd00e54fd7fe5e7035a890565f |
| signature |
15 files changed, 159 insertions(+), 29 deletions(-)
doc/langref.html.in+3-2| ... | @@ -11193,7 +11193,7 @@ PtrTypeStart | ... | @@ -11193,7 +11193,7 @@ PtrTypeStart |
| 11193 | ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE | 11193 | ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE |
| 11194 | 11194 | ||
| 11195 | ContainerDeclType | 11195 | ContainerDeclType |
| 11196 | <- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)? | 11196 | <- (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)? |
| 11198 | 11198 | ||
| 11199 | # Alignment | 11199 | # Alignment |
| ... | @@ -11340,6 +11340,7 @@ KEYWORD_inline <- 'inline' end_of_word | ... | @@ -11340,6 +11340,7 @@ KEYWORD_inline <- 'inline' end_of_word |
| 11340 | KEYWORD_noalias <- 'noalias' end_of_word | 11340 | KEYWORD_noalias <- 'noalias' end_of_word |
| 11341 | KEYWORD_nosuspend <- 'nosuspend' end_of_word | 11341 | KEYWORD_nosuspend <- 'nosuspend' end_of_word |
| 11342 | KEYWORD_null <- 'null' end_of_word | 11342 | KEYWORD_null <- 'null' end_of_word |
| 11343 | KEYWORD_opaque <- 'opaque' end_of_word | ||
| 11343 | KEYWORD_or <- 'or' end_of_word | 11344 | KEYWORD_or <- 'or' end_of_word |
| 11344 | KEYWORD_orelse <- 'orelse' end_of_word | 11345 | KEYWORD_orelse <- 'orelse' end_of_word |
| 11345 | KEYWORD_packed <- 'packed' end_of_word | 11346 | KEYWORD_packed <- 'packed' end_of_word |
| ... | @@ -11368,7 +11369,7 @@ keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype | ... | @@ -11368,7 +11369,7 @@ keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype |
| 11368 | / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer | 11369 | / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer |
| 11369 | / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false | 11370 | / KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false |
| 11370 | / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline | 11371 | / KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline |
| 11371 | / KEYWORD_noalias / KEYWORD_null / KEYWORD_or | 11372 | / KEYWORD_noalias / KEYWORD_null / KEYWORD_opaque / KEYWORD_or |
| 11372 | / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub | 11373 | / KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub |
| 11373 | / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection | 11374 | / KEYWORD_resume / KEYWORD_return / KEYWORD_linksection |
| 11374 | / KEYWORD_struct / KEYWORD_suspend | 11375 | / 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 | }; |
| 362 | 362 | ||
| 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 and | 369 | /// 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_struct | 2896 | /// <- 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(); |
| 2901 | 2902 | ||
| 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( |
| 1492 | 1492 | ||
| 1493 | // TODO remove after 0.7.0 release | 1493 | // 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 | } | ||
| 1496 | 1508 | ||
| 1497 | try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name | 1509 | try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name |
| 1498 | 1510 |
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 | }; |
| 1058 | 1059 | ||
| 1059 | enum ContainerLayout { | 1060 | enum ContainerLayout { |
| ... | @@ -1571,7 +1572,10 @@ enum OnePossibleValue { | ... | @@ -1571,7 +1572,10 @@ enum OnePossibleValue { |
| 1571 | }; | 1572 | }; |
| 1572 | 1573 | ||
| 1573 | struct ZigTypeOpaque { | 1574 | struct ZigTypeOpaque { |
| 1575 | AstNode *decl_node; | ||
| 1574 | Buf *bare_name; | 1576 | Buf *bare_name; |
| 1577 | |||
| 1578 | ScopeDecls *decls_scope; | ||
| 1575 | }; | 1579 | }; |
| 1576 | 1580 | ||
| 1577 | struct ZigTypeFnFrame { | 1581 | struct 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 | } |
| 87 | 87 | ||
| 88 | static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) { | 88 | static 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 | } |
| 98 | 102 | ||
| 99 | static ScopeExpr *find_expr_scope(Scope *scope) { | 103 | static 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; |
| 914 | 918 | ||
| 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); | ||
| 922 | 930 | ||
| 923 | // The actual size is unknown, but the value must not be 0 because that | 931 | // 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 | } |
| 1125 | 1151 | ||
| 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 | } |
| 3432 | 3458 | ||
| 3459 | static 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 | |||
| 3433 | void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) { | 3466 | void 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 | } |
| 22589 | 22589 | ||
| 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; |
| 25739 | 25738 | ||
| 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_struct | 2920 | // <- 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 | ||
| 2923 | static AstNode *ast_parse_container_decl_type(ParseContext *pc) { | 2924 | static 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 | } |
| 2931 | 2932 | ||
| 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 | }; |
| 937 | 937 | ||
| 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); |
| 955 | 955 | ||
| 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 | } |
| 962 | 962 | ||
| 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 | } |
| 969 | 969 | ||
| 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 | } |
| 191 | 191 | ||
| 192 | test "Type.Opaque" { | 192 | test "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 | } |
| 196 | 205 | ||
| 197 | test "Type.Vector" { | 206 | test "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); |
| 203 | 203 | ||
| 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 | }; |
| 267 | 267 | ||
| 268 | test "type info: opaque info" { | ||
| 269 | testOpaque(); | ||
| 270 | comptime testOpaque(); | ||
| 271 | } | ||
| 272 | |||
| 273 | fn 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 | |||
| 268 | test "type info: function type info" { | 283 | test "type info: function type info" { |
| 269 | // wasm doesn't support align attributes on functions | 284 | // 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; |