mirror of
https://github.com/ziglang/zig.git
synced 2024-11-30 09:02:32 +00:00
Merge remote-tracking branch 'origin/master' into llvm6
This commit is contained in:
commit
b57cb04afc
@ -125,13 +125,13 @@ libc. Create demo games using Zig.
|
||||
|
||||
* cmake >= 2.8.5
|
||||
* gcc >= 5.0.0 or clang >= 3.6.0
|
||||
* LLVM, Clang, LLD libraries == 6.x, compiled with the same gcc or clang version above
|
||||
* LLVM, Clang, LLD development libraries == 6.x, compiled with the same gcc or clang version above
|
||||
|
||||
##### Windows
|
||||
|
||||
* cmake >= 2.8.5
|
||||
* Microsoft Visual Studio 2015
|
||||
* LLVM, Clang, LLD libraries == 6.x, compiled with the same MSVC version above
|
||||
* LLVM, Clang, LLD development libraries == 6.x, compiled with the same MSVC version above
|
||||
|
||||
#### Instructions
|
||||
|
||||
|
@ -5733,19 +5733,19 @@ UseDecl = "use" Expression ";"
|
||||
|
||||
ExternDecl = "extern" option(String) (FnProto | VariableDeclaration) ";"
|
||||
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
|
||||
|
||||
FnDef = option("inline" | "export") FnProto Block
|
||||
|
||||
ParamDeclList = "(" list(ParamDecl, ",") ")"
|
||||
|
||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "var" | "...")
|
||||
|
||||
Block = option(Symbol ":") "{" many(Statement) "}"
|
||||
|
||||
Statement = LocalVarDecl ";" | Defer(Block) | Defer(Expression) ";" | BlockExpression(Block) | Expression ";" | ";"
|
||||
|
||||
TypeExpr = ErrorSetExpr | "var"
|
||||
TypeExpr = ErrorSetExpr
|
||||
|
||||
ErrorSetExpr = (PrefixOpExpression "!" PrefixOpExpression) | PrefixOpExpression
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "bigint.hpp"
|
||||
#include "bigfloat.hpp"
|
||||
#include "target.hpp"
|
||||
#include "tokenizer.hpp"
|
||||
|
||||
struct AstNode;
|
||||
struct ImportTableEntry;
|
||||
@ -399,7 +400,6 @@ enum NodeType {
|
||||
NodeTypeStructValueField,
|
||||
NodeTypeArrayType,
|
||||
NodeTypeErrorType,
|
||||
NodeTypeVarLiteral,
|
||||
NodeTypeIfErrorExpr,
|
||||
NodeTypeTestExpr,
|
||||
NodeTypeErrorSetDecl,
|
||||
@ -427,6 +427,7 @@ struct AstNodeFnProto {
|
||||
Buf *name;
|
||||
ZigList<AstNode *> params;
|
||||
AstNode *return_type;
|
||||
Token *return_var_token;
|
||||
bool is_var_args;
|
||||
bool is_extern;
|
||||
bool is_export;
|
||||
@ -456,6 +457,7 @@ struct AstNodeFnDecl {
|
||||
struct AstNodeParamDecl {
|
||||
Buf *name;
|
||||
AstNode *type;
|
||||
Token *var_token;
|
||||
bool is_noalias;
|
||||
bool is_inline;
|
||||
bool is_var_args;
|
||||
@ -866,9 +868,6 @@ struct AstNodeUnreachableExpr {
|
||||
struct AstNodeErrorType {
|
||||
};
|
||||
|
||||
struct AstNodeVarLiteral {
|
||||
};
|
||||
|
||||
struct AstNodeAwaitExpr {
|
||||
AstNode *expr;
|
||||
};
|
||||
@ -933,7 +932,6 @@ struct AstNode {
|
||||
AstNodeUnreachableExpr unreachable_expr;
|
||||
AstNodeArrayType array_type;
|
||||
AstNodeErrorType error_type;
|
||||
AstNodeVarLiteral var_literal;
|
||||
AstNodeErrorSetDecl err_set_decl;
|
||||
AstNodeCancelExpr cancel_expr;
|
||||
AstNodeResumeExpr resume_expr;
|
||||
@ -1098,6 +1096,8 @@ struct TypeTableEntryUnion {
|
||||
size_t gen_union_index;
|
||||
size_t gen_tag_index;
|
||||
|
||||
bool have_explicit_tag_type;
|
||||
|
||||
uint32_t union_size_bytes;
|
||||
TypeTableEntry *most_aligned_union_member;
|
||||
|
||||
@ -1134,7 +1134,6 @@ struct TypeTableEntryPromise {
|
||||
|
||||
enum TypeTableEntryId {
|
||||
TypeTableEntryIdInvalid,
|
||||
TypeTableEntryIdVar,
|
||||
TypeTableEntryIdMetaType,
|
||||
TypeTableEntryIdVoid,
|
||||
TypeTableEntryIdBool,
|
||||
|
@ -200,7 +200,6 @@ static uint8_t bits_needed_for_unsigned(uint64_t x) {
|
||||
bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdStruct:
|
||||
return type_entry->data.structure.complete;
|
||||
@ -239,7 +238,6 @@ bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdStruct:
|
||||
return type_entry->data.structure.zero_bits_known;
|
||||
@ -466,9 +464,8 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
|
||||
TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
|
||||
const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};
|
||||
TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};
|
||||
size_t field_count = type_has_bits(result_ptr_type) ? 3 : 1;
|
||||
Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
|
||||
TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, field_count);
|
||||
TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3);
|
||||
|
||||
return_type->promise_frame_parent = entry;
|
||||
return entry;
|
||||
@ -1281,7 +1278,6 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
|
||||
static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
@ -1324,7 +1320,6 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
||||
static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
@ -1428,6 +1423,14 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (param_node->data.param_decl.var_token != nullptr) {
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
}
|
||||
|
||||
TypeTableEntry *type_entry = analyze_type_expr(g, child_scope, param_node->data.param_decl.type);
|
||||
@ -1463,14 +1466,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
buf_sprintf("parameter of type '%s' not allowed", buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdVar:
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
buf_sprintf("parameter of type 'var' not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return get_generic_fn_type(g, &fn_type_id);
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdNamespace:
|
||||
@ -1514,6 +1509,19 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
}
|
||||
}
|
||||
|
||||
if (fn_proto->return_var_token != nullptr) {
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
add_node_error(g, fn_proto->return_type,
|
||||
buf_sprintf("return type 'var' not allowed in function with calling convention '%s'",
|
||||
calling_convention_name(fn_type_id.cc)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
add_node_error(g, proto_node,
|
||||
buf_sprintf("TODO implement inferred return types https://github.com/zig-lang/zig/issues/447"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
//return get_generic_fn_type(g, &fn_type_id);
|
||||
}
|
||||
|
||||
TypeTableEntry *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
|
||||
if (type_is_invalid(specified_return_type)) {
|
||||
fn_type_id.return_type = g->builtin_types.entry_invalid;
|
||||
@ -1552,7 +1560,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
|
||||
add_node_error(g, fn_proto->return_type,
|
||||
@ -1707,7 +1714,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
buf_init_from_str(&struct_type->name, type_name);
|
||||
|
||||
struct_type->data.structure.src_field_count = field_count;
|
||||
struct_type->data.structure.gen_field_count = field_count;
|
||||
struct_type->data.structure.gen_field_count = 0;
|
||||
struct_type->data.structure.zero_bits_known = true;
|
||||
struct_type->data.structure.complete = true;
|
||||
struct_type->data.structure.fields = allocate<TypeStructField>(field_count);
|
||||
@ -1716,22 +1723,26 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
ZigLLVMDIType **di_element_types = allocate<ZigLLVMDIType*>(field_count);
|
||||
LLVMTypeRef *element_types = allocate<LLVMTypeRef>(field_count);
|
||||
for (size_t i = 0; i < field_count; i += 1) {
|
||||
element_types[i] = field_types[i]->type_ref;
|
||||
element_types[struct_type->data.structure.gen_field_count] = field_types[i]->type_ref;
|
||||
|
||||
TypeStructField *field = &struct_type->data.structure.fields[i];
|
||||
field->name = buf_create_from_str(field_names[i]);
|
||||
field->type_entry = field_types[i];
|
||||
field->src_index = i;
|
||||
field->gen_index = i;
|
||||
|
||||
assert(type_has_bits(field->type_entry));
|
||||
if (type_has_bits(field->type_entry)) {
|
||||
field->gen_index = struct_type->data.structure.gen_field_count;
|
||||
struct_type->data.structure.gen_field_count += 1;
|
||||
} else {
|
||||
field->gen_index = SIZE_MAX;
|
||||
}
|
||||
|
||||
auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
|
||||
assert(prev_entry == nullptr);
|
||||
}
|
||||
|
||||
struct_type->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), type_name);
|
||||
LLVMStructSetBody(struct_type->type_ref, element_types, field_count, false);
|
||||
LLVMStructSetBody(struct_type->type_ref, element_types, struct_type->data.structure.gen_field_count, false);
|
||||
|
||||
struct_type->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder,
|
||||
ZigLLVMTag_DW_structure_type(), type_name,
|
||||
@ -1739,11 +1750,14 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
|
||||
for (size_t i = 0; i < field_count; i += 1) {
|
||||
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
|
||||
if (type_struct_field->gen_index == SIZE_MAX) {
|
||||
continue;
|
||||
}
|
||||
TypeTableEntry *field_type = type_struct_field->type_entry;
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
|
||||
uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, i);
|
||||
di_element_types[i] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
uint64_t debug_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, struct_type->type_ref, type_struct_field->gen_index);
|
||||
di_element_types[type_struct_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(struct_type->di_type), buf_ptr(type_struct_field->name),
|
||||
nullptr, 0,
|
||||
debug_size_in_bits,
|
||||
@ -1751,7 +1765,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
debug_offset_in_bits,
|
||||
0, field_type->di_type);
|
||||
|
||||
assert(di_element_types[i]);
|
||||
assert(di_element_types[type_struct_field->gen_index]);
|
||||
}
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, struct_type->type_ref);
|
||||
@ -1762,7 +1776,7 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
debug_size_in_bits,
|
||||
debug_align_in_bits,
|
||||
0,
|
||||
nullptr, di_element_types, field_count, 0, nullptr, "");
|
||||
nullptr, di_element_types, struct_type->data.structure.gen_field_count, 0, nullptr, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, struct_type->di_type, replacement_di_type);
|
||||
struct_type->di_type = replacement_di_type;
|
||||
@ -2544,6 +2558,8 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
|
||||
AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
|
||||
union_type->data.unionation.have_explicit_tag_type = decl_node->data.container_decl.auto_enum ||
|
||||
enum_type_node != nullptr;
|
||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
||||
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
|
||||
TypeTableEntry *tag_type;
|
||||
@ -3226,7 +3242,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorType:
|
||||
case NodeTypeVarLiteral:
|
||||
case NodeTypeIfErrorExpr:
|
||||
case NodeTypeTestExpr:
|
||||
case NodeTypeErrorSetDecl:
|
||||
@ -3262,7 +3277,6 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
|
||||
case TypeTableEntryIdInvalid:
|
||||
return g->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
@ -3641,7 +3655,6 @@ TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *t
|
||||
static bool is_container(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdEnum:
|
||||
@ -3716,7 +3729,6 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdPromise:
|
||||
@ -3753,6 +3765,19 @@ uint32_t get_ptr_align(TypeTableEntry *type) {
|
||||
}
|
||||
}
|
||||
|
||||
bool get_ptr_const(TypeTableEntry *type) {
|
||||
TypeTableEntry *ptr_type = get_codegen_ptr_type(type);
|
||||
if (ptr_type->id == TypeTableEntryIdPointer) {
|
||||
return ptr_type->data.pointer.is_const;
|
||||
} else if (ptr_type->id == TypeTableEntryIdFn) {
|
||||
return true;
|
||||
} else if (ptr_type->id == TypeTableEntryIdPromise) {
|
||||
return true;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index) {
|
||||
if (fn_entry->param_source_nodes)
|
||||
return fn_entry->param_source_nodes[index];
|
||||
@ -4203,7 +4228,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
zig_unreachable();
|
||||
@ -4502,7 +4526,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -4600,7 +4623,6 @@ bool type_has_bits(TypeTableEntry *type_entry) {
|
||||
bool type_requires_comptime(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdOpaque:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
@ -5096,7 +5118,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdPromise:
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -5176,9 +5197,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
buf_appendf(buf, "(invalid)");
|
||||
return;
|
||||
case TypeTableEntryIdVar:
|
||||
buf_appendf(buf, "(var)");
|
||||
return;
|
||||
case TypeTableEntryIdVoid:
|
||||
buf_appendf(buf, "{}");
|
||||
return;
|
||||
@ -5414,7 +5432,6 @@ TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits)
|
||||
uint32_t type_id_hash(TypeId x) {
|
||||
switch (x.id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
@ -5461,7 +5478,6 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
return false;
|
||||
switch (a.id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
@ -5616,7 +5632,6 @@ size_t type_id_len() {
|
||||
size_t type_id_index(TypeTableEntryId id) {
|
||||
switch (id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
return 0;
|
||||
@ -5675,7 +5690,6 @@ size_t type_id_index(TypeTableEntryId id) {
|
||||
const char *type_id_name(TypeTableEntryId id) {
|
||||
switch (id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
return "Type";
|
||||
|
@ -55,6 +55,7 @@ bool type_is_codegen_pointer(TypeTableEntry *type);
|
||||
|
||||
TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type);
|
||||
uint32_t get_ptr_align(TypeTableEntry *type);
|
||||
bool get_ptr_const(TypeTableEntry *type);
|
||||
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
|
||||
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
|
||||
bool type_is_complete(TypeTableEntry *type_entry);
|
||||
|
@ -236,8 +236,6 @@ static const char *node_type_str(NodeType node_type) {
|
||||
return "ArrayType";
|
||||
case NodeTypeErrorType:
|
||||
return "ErrorType";
|
||||
case NodeTypeVarLiteral:
|
||||
return "VarLiteral";
|
||||
case NodeTypeIfErrorExpr:
|
||||
return "IfErrorExpr";
|
||||
case NodeTypeTestExpr:
|
||||
@ -436,6 +434,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
}
|
||||
if (param_decl->data.param_decl.is_var_args) {
|
||||
fprintf(ar->f, "...");
|
||||
} else if (param_decl->data.param_decl.var_token != nullptr) {
|
||||
fprintf(ar->f, "var");
|
||||
} else {
|
||||
render_node_grouped(ar, param_decl->data.param_decl.type);
|
||||
}
|
||||
@ -456,6 +456,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, ")");
|
||||
}
|
||||
|
||||
if (node->data.fn_proto.return_var_token != nullptr) {
|
||||
fprintf(ar->f, "var");
|
||||
} else {
|
||||
AstNode *return_type_node = node->data.fn_proto.return_type;
|
||||
assert(return_type_node != nullptr);
|
||||
fprintf(ar->f, " ");
|
||||
@ -463,6 +466,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, "!");
|
||||
}
|
||||
render_node_grouped(ar, return_type_node);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NodeTypeFnDef:
|
||||
@ -486,7 +490,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
AstNode *statement = node->data.block.statements.at(i);
|
||||
print_indent(ar);
|
||||
render_node_grouped(ar, statement);
|
||||
|
||||
if (!statement_terminates_without_semicolon(statement))
|
||||
fprintf(ar->f, ";");
|
||||
|
||||
fprintf(ar->f, "\n");
|
||||
}
|
||||
ar->indent -= ar->indent_size;
|
||||
@ -768,9 +775,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypeErrorType:
|
||||
fprintf(ar->f, "error");
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
fprintf(ar->f, "var");
|
||||
break;
|
||||
case NodeTypeAsmExpr:
|
||||
{
|
||||
AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
|
||||
|
@ -4508,7 +4508,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
assert(!type_entry->zero_bits);
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
@ -4960,7 +4959,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdPromise:
|
||||
@ -5611,11 +5609,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->zero_bits = true;
|
||||
g->builtin_types.entry_null = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVar);
|
||||
buf_init_from_str(&entry->name, "(var)");
|
||||
g->builtin_types.entry_var = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArgTuple);
|
||||
buf_init_from_str(&entry->name, "(args)");
|
||||
@ -6444,7 +6437,6 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry
|
||||
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
@ -6639,7 +6631,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdPromise:
|
||||
zig_unreachable();
|
||||
@ -6781,7 +6772,6 @@ static void gen_h_file(CodeGen *g) {
|
||||
TypeTableEntry *type_entry = gen_h->types_to_declare.at(type_i);
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
|
112
src/ir.cpp
112
src/ir.cpp
@ -948,12 +948,10 @@ static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope,
|
||||
const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
|
||||
const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
|
||||
const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
|
||||
if (struct_type->data.structure.src_field_count > 1) {
|
||||
const_instruction->base.value.data.x_struct.fields[1].type = return_type;
|
||||
const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
|
||||
const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
|
||||
const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
|
||||
}
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
@ -2147,7 +2145,7 @@ static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
size_t param_count = source_node->data.fn_proto.params.length;
|
||||
if (is_var_args) param_count -= 1;
|
||||
for (size_t i = 0; i < param_count; i += 1) {
|
||||
ir_ref_instruction(param_types[i], irb->current_basic_block);
|
||||
if (param_types[i] != nullptr) ir_ref_instruction(param_types[i], irb->current_basic_block);
|
||||
}
|
||||
if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block);
|
||||
ir_ref_instruction(return_type, irb->current_basic_block);
|
||||
@ -2741,10 +2739,8 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
|
||||
return return_inst;
|
||||
}
|
||||
|
||||
if (irb->exec->coro_result_ptr_field_ptr) {
|
||||
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
|
||||
ir_build_store_ptr(irb, scope, node, result_ptr, return_value);
|
||||
}
|
||||
IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
|
||||
get_maybe_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
|
||||
// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
|
||||
@ -3305,12 +3301,6 @@ static IrInstruction *ir_gen_null_literal(IrBuilder *irb, Scope *scope, AstNode
|
||||
return ir_build_const_null(irb, scope, node);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_var_literal(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
assert(node->type == NodeTypeVarLiteral);
|
||||
|
||||
return ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
|
||||
assert(node->type == NodeTypeSymbol);
|
||||
|
||||
@ -5916,11 +5906,15 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
is_var_args = true;
|
||||
break;
|
||||
}
|
||||
if (param_node->data.param_decl.var_token == nullptr) {
|
||||
AstNode *type_node = param_node->data.param_decl.type;
|
||||
IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
|
||||
if (type_value == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
param_types[i] = type_value;
|
||||
} else {
|
||||
param_types[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *align_value = nullptr;
|
||||
@ -5931,6 +5925,7 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
}
|
||||
|
||||
IrInstruction *return_type;
|
||||
if (node->data.fn_proto.return_var_token == nullptr) {
|
||||
if (node->data.fn_proto.return_type == nullptr) {
|
||||
return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
|
||||
} else {
|
||||
@ -5938,6 +5933,9 @@ static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNo
|
||||
if (return_type == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
} else {
|
||||
return_type = nullptr;
|
||||
}
|
||||
|
||||
return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, return_type, is_var_args);
|
||||
}
|
||||
@ -6189,8 +6187,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
|
||||
return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval);
|
||||
case NodeTypeNullLiteral:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval);
|
||||
case NodeTypeVarLiteral:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_var_literal(irb, scope, node), lval);
|
||||
case NodeTypeIfErrorExpr:
|
||||
return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval);
|
||||
case NodeTypeTestExpr:
|
||||
@ -6328,14 +6324,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
|
||||
irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
|
||||
awaiter_handle_field_name);
|
||||
if (type_has_bits(return_type)) {
|
||||
Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
|
||||
coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
|
||||
result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
|
||||
irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
|
||||
result_ptr_field_name);
|
||||
irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
|
||||
ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, coro_result_field_ptr);
|
||||
}
|
||||
|
||||
|
||||
irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
|
||||
@ -7515,11 +7508,6 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
|
||||
return ImplicitCastMatchResultReportedError;
|
||||
}
|
||||
|
||||
// implicit conversion from anything to var
|
||||
if (expected_type->id == TypeTableEntryIdVar) {
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
|
||||
// implicit conversion from non maybe type to maybe type
|
||||
if (expected_type->id == TypeTableEntryIdMaybe &&
|
||||
ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value))
|
||||
@ -9341,9 +9329,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (wanted_type->id == TypeTableEntryIdVar)
|
||||
return value;
|
||||
|
||||
// explicit match or non-const to const
|
||||
if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node).id == ConstCastResultIdOk) {
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
|
||||
@ -10311,9 +10296,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
IrInstruction *casted_op1 = ir_implicit_cast(ira, op1, resolved_type);
|
||||
@ -11106,7 +11088,6 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdVar:
|
||||
return VarClassRequiredIllegal;
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
@ -11279,7 +11260,6 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
|
||||
|
||||
switch (target->value.type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdFn: {
|
||||
@ -11332,7 +11312,6 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
|
||||
TypeTableEntry *type_value = target->value.data.x_type;
|
||||
switch (type_value->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdStruct:
|
||||
if (is_slice(type_value)) {
|
||||
@ -11543,14 +11522,20 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node
|
||||
{
|
||||
AstNode *param_decl_node = fn_proto_node->data.fn_proto.params.at(*next_proto_i);
|
||||
assert(param_decl_node->type == NodeTypeParamDecl);
|
||||
|
||||
IrInstruction *casted_arg;
|
||||
if (param_decl_node->data.param_decl.var_token == nullptr) {
|
||||
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
||||
TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *exec_scope, param_type_node);
|
||||
if (type_is_invalid(param_type))
|
||||
return false;
|
||||
|
||||
IrInstruction *casted_arg = ir_implicit_cast(ira, arg, param_type);
|
||||
casted_arg = ir_implicit_cast(ira, arg, param_type);
|
||||
if (type_is_invalid(casted_arg->value.type))
|
||||
return false;
|
||||
} else {
|
||||
casted_arg = arg;
|
||||
}
|
||||
|
||||
ConstExprValue *arg_val = ir_resolve_const(ira, casted_arg, UndefBad);
|
||||
if (!arg_val)
|
||||
@ -11579,19 +11564,18 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
||||
arg_part_of_generic_id = true;
|
||||
casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
|
||||
} else {
|
||||
if (param_decl_node->data.param_decl.var_token == nullptr) {
|
||||
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
||||
TypeTableEntry *param_type = analyze_type_expr(ira->codegen, *child_scope, param_type_node);
|
||||
if (type_is_invalid(param_type))
|
||||
return false;
|
||||
|
||||
bool is_var_type = (param_type->id == TypeTableEntryIdVar);
|
||||
if (is_var_type) {
|
||||
arg_part_of_generic_id = true;
|
||||
casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
|
||||
} else {
|
||||
casted_arg = ir_implicit_cast(ira, arg, param_type);
|
||||
if (type_is_invalid(casted_arg->value.type))
|
||||
return false;
|
||||
} else {
|
||||
arg_part_of_generic_id = true;
|
||||
casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -12028,7 +12012,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
||||
inst_fn_type_id.alignment = align_bytes;
|
||||
}
|
||||
|
||||
{
|
||||
if (fn_proto_node->data.fn_proto.return_var_token == nullptr) {
|
||||
AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
|
||||
TypeTableEntry *specified_return_type = analyze_type_expr(ira->codegen, impl_fn->child_scope, return_type_node);
|
||||
if (type_is_invalid(specified_return_type))
|
||||
@ -12304,7 +12288,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
@ -13539,10 +13522,6 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
zig_unreachable(); // handled above
|
||||
case TypeTableEntryIdVar:
|
||||
ir_add_error_node(ira, expr_value->source_node,
|
||||
buf_sprintf("type '%s' not eligible for @typeOf", buf_ptr(&type_entry->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
@ -13807,7 +13786,6 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
switch (child_type->id) {
|
||||
case TypeTableEntryIdInvalid: // handled above
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
@ -13916,7 +13894,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
switch (child_type->id) {
|
||||
case TypeTableEntryIdInvalid: // handled above
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
@ -13968,7 +13945,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid: // handled above
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
@ -14161,6 +14137,14 @@ static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source
|
||||
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
if (!value->value.type->data.unionation.have_explicit_tag_type && !source_instr->is_gen) {
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("union has no associated enum"));
|
||||
if (value->value.type->data.unionation.decl_node != nullptr) {
|
||||
add_error_note(ira->codegen, msg, value->value.type->data.unionation.decl_node,
|
||||
buf_sprintf("declared here"));
|
||||
}
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
TypeTableEntry *tag_type = value->value.type->data.unionation.tag_type;
|
||||
assert(tag_type->id == TypeTableEntryIdEnum);
|
||||
@ -14316,7 +14300,6 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
|
||||
switch (target_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
@ -14911,7 +14894,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
zig_panic("TODO min/max value for enum type");
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdPointer:
|
||||
@ -15821,9 +15803,13 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
|
||||
TypeTableEntry *return_type;
|
||||
|
||||
if (array_type->id == TypeTableEntryIdArray) {
|
||||
uint32_t byte_alignment = ptr_type->data.pointer.alignment;
|
||||
if (array_type->data.array.len == 0 && byte_alignment == 0) {
|
||||
byte_alignment = get_abi_alignment(ira->codegen, array_type->data.array.child_type);
|
||||
}
|
||||
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
ptr_type->data.pointer.alignment, 0, 0);
|
||||
byte_alignment, 0, 0);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else if (array_type->id == TypeTableEntryIdPointer) {
|
||||
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
|
||||
@ -16155,7 +16141,6 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
|
||||
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
@ -16457,21 +16442,23 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
|
||||
if (type_is_invalid(param_type_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
|
||||
param_info->is_noalias = param_node->data.param_decl.is_noalias;
|
||||
param_info->type = ir_resolve_type(ira, param_type_value);
|
||||
if (type_is_invalid(param_info->type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (param_info->type->id == TypeTableEntryIdVar) {
|
||||
if (instruction->param_types[fn_type_id.next_param_index] == nullptr) {
|
||||
param_info->type = nullptr;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = get_generic_fn_type(ira->codegen, &fn_type_id);
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
} else {
|
||||
IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
|
||||
if (type_is_invalid(param_type_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
param_info->type = ir_resolve_type(ira, param_type_value);
|
||||
if (type_is_invalid(param_info->type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (instruction->align_value != nullptr) {
|
||||
@ -16816,6 +16803,11 @@ static TypeTableEntry *ir_analyze_instruction_ptr_cast(IrAnalyze *ira, IrInstruc
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("cast discards const qualifier"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
if (instr_is_comptime(ptr)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk);
|
||||
if (!val)
|
||||
@ -16860,7 +16852,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
assert(val->special == ConstValSpecialStatic);
|
||||
switch (val->type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
@ -16928,7 +16919,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
assert(val->special == ConstValSpecialStatic);
|
||||
switch (val->type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
@ -17005,7 +16995,6 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
|
||||
|
||||
switch (src_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
@ -17032,7 +17021,6 @@ static TypeTableEntry *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruc
|
||||
|
||||
switch (dest_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
|
@ -263,21 +263,14 @@ static AstNode *ast_parse_error_set_expr(ParseContext *pc, size_t *token_index,
|
||||
}
|
||||
|
||||
/*
|
||||
TypeExpr = ErrorSetExpr | "var"
|
||||
TypeExpr = ErrorSetExpr
|
||||
*/
|
||||
static AstNode *ast_parse_type_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
if (token->id == TokenIdKeywordVar) {
|
||||
AstNode *node = ast_create_node(pc, NodeTypeVarLiteral, token);
|
||||
*token_index += 1;
|
||||
return node;
|
||||
} else {
|
||||
return ast_parse_error_set_expr(pc, token_index, mandatory);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "...")
|
||||
ParamDecl = option("noalias" | "comptime") option(Symbol ":") (TypeExpr | "var" | "...")
|
||||
*/
|
||||
static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -308,6 +301,9 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, size_t *token_index) {
|
||||
if (ellipsis_tok->id == TokenIdEllipsis3) {
|
||||
*token_index += 1;
|
||||
node->data.param_decl.is_var_args = true;
|
||||
} else if (ellipsis_tok->id == TokenIdKeywordVar) {
|
||||
*token_index += 1;
|
||||
node->data.param_decl.var_token = ellipsis_tok;
|
||||
} else {
|
||||
node->data.param_decl.type = ast_parse_type_expr(pc, token_index, true);
|
||||
}
|
||||
@ -2319,7 +2315,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, size_t *token_index, bool
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool statement_terminates_without_semicolon(AstNode *node) {
|
||||
bool statement_terminates_without_semicolon(AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeIfBoolExpr:
|
||||
if (node->data.if_bool_expr.else_node)
|
||||
@ -2421,7 +2417,7 @@ static AstNode *ast_parse_block(ParseContext *pc, size_t *token_index, bool mand
|
||||
}
|
||||
|
||||
/*
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") TypeExpr
|
||||
FnProto = option("nakedcc" | "stdcallcc" | "extern" | ("async" option("(" Expression ")"))) "fn" option(Symbol) ParamDeclList option("align" "(" Expression ")") option("section" "(" Expression ")") option("!") (TypeExpr | "var")
|
||||
*/
|
||||
static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -2507,6 +2503,11 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
if (next_token->id == TokenIdKeywordVar) {
|
||||
node->data.fn_proto.return_var_token = next_token;
|
||||
*token_index += 1;
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
} else {
|
||||
if (next_token->id == TokenIdKeywordError) {
|
||||
Token *maybe_lbrace_tok = &pc->tokens->at(*token_index + 1);
|
||||
if (maybe_lbrace_tok->id == TokenIdLBrace) {
|
||||
@ -2520,6 +2521,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool m
|
||||
next_token = &pc->tokens->at(*token_index);
|
||||
}
|
||||
node->data.fn_proto.return_type = ast_parse_type_expr(pc, token_index, true);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -3069,9 +3071,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
case NodeTypeErrorType:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeVarLiteral:
|
||||
// none
|
||||
break;
|
||||
case NodeTypeAddrOfExpr:
|
||||
visit_field(&node->data.addr_of_expr.align_expr, visit, context);
|
||||
visit_field(&node->data.addr_of_expr.op_expr, visit, context);
|
||||
|
@ -23,4 +23,6 @@ void ast_print(AstNode *node, int indent);
|
||||
|
||||
void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context);
|
||||
|
||||
bool statement_terminates_without_semicolon(AstNode *node);
|
||||
|
||||
#endif
|
||||
|
@ -787,7 +787,7 @@ static FloatAbi get_float_abi(ZigTarget *target) {
|
||||
{
|
||||
return FloatAbiHard;
|
||||
} else {
|
||||
zig_panic("TODO: user needs to input if they want hard or soft floating point");
|
||||
return FloatAbiSoft;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,6 +104,7 @@ static TransScopeRoot *trans_scope_root_create(Context *c);
|
||||
static TransScopeWhile *trans_scope_while_create(Context *c, TransScope *parent_scope);
|
||||
static TransScopeBlock *trans_scope_block_create(Context *c, TransScope *parent_scope);
|
||||
static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scope, Buf *wanted_name);
|
||||
static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope);
|
||||
|
||||
static TransScopeBlock *trans_scope_block_find(TransScope *scope);
|
||||
|
||||
@ -118,7 +119,7 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
|
||||
static TransScope *trans_stmt(Context *c, TransScope *scope, const Stmt *stmt, AstNode **out_node);
|
||||
static AstNode *trans_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
|
||||
static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc);
|
||||
|
||||
static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval);
|
||||
|
||||
ATTRIBUTE_PRINTF(3, 4)
|
||||
static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) {
|
||||
@ -466,6 +467,14 @@ static QualType get_expr_qual_type(Context *c, const Expr *expr) {
|
||||
return expr->getType();
|
||||
}
|
||||
|
||||
static QualType get_expr_qual_type_before_implicit_cast(Context *c, const Expr *expr) {
|
||||
if (expr->getStmtClass() == Stmt::ImplicitCastExprClass) {
|
||||
const ImplicitCastExpr *cast_expr = static_cast<const ImplicitCastExpr *>(expr);
|
||||
return get_expr_qual_type(c, cast_expr->getSubExpr());
|
||||
}
|
||||
return expr->getType();
|
||||
}
|
||||
|
||||
static AstNode *get_expr_type(Context *c, const Expr *expr) {
|
||||
return trans_qual_type(c, get_expr_qual_type(c, expr), expr->getLocStart());
|
||||
}
|
||||
@ -499,15 +508,31 @@ static bool qual_type_is_ptr(QualType qt) {
|
||||
return ty->getTypeClass() == Type::Pointer;
|
||||
}
|
||||
|
||||
static bool qual_type_is_fn_ptr(Context *c, QualType qt) {
|
||||
static const FunctionProtoType *qual_type_get_fn_proto(QualType qt, bool *is_ptr) {
|
||||
const Type *ty = qual_type_canon(qt);
|
||||
if (ty->getTypeClass() != Type::Pointer) {
|
||||
return false;
|
||||
}
|
||||
*is_ptr = false;
|
||||
|
||||
if (ty->getTypeClass() == Type::Pointer) {
|
||||
*is_ptr = true;
|
||||
const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
|
||||
QualType child_qt = pointer_ty->getPointeeType();
|
||||
const Type *child_ty = child_qt.getTypePtr();
|
||||
return child_ty->getTypeClass() == Type::FunctionProto;
|
||||
ty = child_qt.getTypePtr();
|
||||
}
|
||||
|
||||
if (ty->getTypeClass() == Type::FunctionProto) {
|
||||
return static_cast<const FunctionProtoType*>(ty);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool qual_type_is_fn_ptr(QualType qt) {
|
||||
bool is_ptr;
|
||||
if (qual_type_get_fn_proto(qt, &is_ptr)) {
|
||||
return is_ptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) {
|
||||
@ -1138,6 +1163,22 @@ static AstNode *trans_create_bin_op(Context *c, TransScope *scope, Expr *lhs, Bi
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_bool_bin_op(Context *c, TransScope *scope, Expr *lhs, BinOpType bin_op, Expr *rhs) {
|
||||
assert(bin_op == BinOpTypeBoolAnd || bin_op == BinOpTypeBoolOr);
|
||||
AstNode *node = trans_create_node(c, NodeTypeBinOpExpr);
|
||||
node->data.bin_op_expr.bin_op = bin_op;
|
||||
|
||||
node->data.bin_op_expr.op1 = trans_bool_expr(c, ResultUsedYes, scope, lhs, TransRValue);
|
||||
if (node->data.bin_op_expr.op1 == nullptr)
|
||||
return nullptr;
|
||||
|
||||
node->data.bin_op_expr.op2 = trans_bool_expr(c, ResultUsedYes, scope, rhs, TransRValue);
|
||||
if (node->data.bin_op_expr.op2 == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *trans_create_assign(Context *c, ResultUsed result_used, TransScope *scope, Expr *lhs, Expr *rhs) {
|
||||
if (result_used == ResultUsedNo) {
|
||||
// common case
|
||||
@ -1282,10 +1323,9 @@ static AstNode *trans_binary_operator(Context *c, ResultUsed result_used, TransS
|
||||
case BO_Or:
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS());
|
||||
case BO_LAnd:
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
|
||||
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS());
|
||||
case BO_LOr:
|
||||
// TODO: int vs bool
|
||||
return trans_create_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
|
||||
return trans_create_bool_bin_op(c, scope, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS());
|
||||
case BO_Assign:
|
||||
return trans_create_assign(c, result_used, scope, stmt->getLHS(), stmt->getRHS());
|
||||
case BO_Comma:
|
||||
@ -1879,7 +1919,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
||||
AstNode *value_node = trans_expr(c, result_used, scope, stmt->getSubExpr(), TransRValue);
|
||||
if (value_node == nullptr)
|
||||
return nullptr;
|
||||
bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType());
|
||||
bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType());
|
||||
if (is_fn_ptr)
|
||||
return value_node;
|
||||
AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node);
|
||||
@ -1922,11 +1962,18 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc
|
||||
AstNode *sub_node = trans_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
|
||||
if (sub_node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return trans_create_node_prefix_op(c, PrefixOpBinNot, sub_node);
|
||||
}
|
||||
case UO_LNot:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot");
|
||||
{
|
||||
Expr *op_expr = stmt->getSubExpr();
|
||||
AstNode *sub_node = trans_bool_expr(c, ResultUsedYes, scope, op_expr, TransRValue);
|
||||
if (sub_node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return trans_create_node_prefix_op(c, PrefixOpBoolNot, sub_node);
|
||||
}
|
||||
case UO_Real:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real");
|
||||
return nullptr;
|
||||
@ -2206,10 +2253,240 @@ static int trans_local_declaration(Context *c, TransScope *scope, const DeclStmt
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static AstNode *to_enum_zero_cmp(Context *c, AstNode *expr, AstNode *enum_type) {
|
||||
AstNode *tag_type = trans_create_node_builtin_fn_call_str(c, "TagType");
|
||||
tag_type->data.fn_call_expr.params.append(enum_type);
|
||||
|
||||
// @TagType(Enum)(0)
|
||||
AstNode *zero = trans_create_node_unsigned_negative(c, 0, false);
|
||||
AstNode *casted_zero = trans_create_node_fn_call_1(c, tag_type, zero);
|
||||
|
||||
// @bitCast(Enum, @TagType(Enum)(0))
|
||||
AstNode *bitcast = trans_create_node_builtin_fn_call_str(c, "bitCast");
|
||||
bitcast->data.fn_call_expr.params.append(enum_type);
|
||||
bitcast->data.fn_call_expr.params.append(casted_zero);
|
||||
|
||||
return trans_create_node_bin_op(c, expr, BinOpTypeCmpNotEq, bitcast);
|
||||
}
|
||||
|
||||
static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *scope, const Expr *expr, TransLRValue lrval) {
|
||||
AstNode *res = trans_expr(c, result_used, scope, expr, lrval);
|
||||
if (res == nullptr)
|
||||
return nullptr;
|
||||
|
||||
switch (res->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
switch (res->data.bin_op_expr.bin_op) {
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
case BinOpTypeCmpEq:
|
||||
case BinOpTypeCmpNotEq:
|
||||
case BinOpTypeCmpLessThan:
|
||||
case BinOpTypeCmpGreaterThan:
|
||||
case BinOpTypeCmpLessOrEq:
|
||||
case BinOpTypeCmpGreaterOrEq:
|
||||
return res;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case NodeTypePrefixOpExpr:
|
||||
switch (res->data.prefix_op_expr.prefix_op) {
|
||||
case PrefixOpBoolNot:
|
||||
return res;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
case NodeTypeBoolLiteral:
|
||||
return res;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
const Type *ty = get_expr_qual_type_before_implicit_cast(c, expr).getTypePtr();
|
||||
auto classs = ty->getTypeClass();
|
||||
switch (classs) {
|
||||
case Type::Builtin:
|
||||
{
|
||||
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty);
|
||||
switch (builtin_ty->getKind()) {
|
||||
case BuiltinType::Bool:
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::SChar:
|
||||
case BuiltinType::UShort:
|
||||
case BuiltinType::UInt:
|
||||
case BuiltinType::ULong:
|
||||
case BuiltinType::ULongLong:
|
||||
case BuiltinType::Short:
|
||||
case BuiltinType::Int:
|
||||
case BuiltinType::Long:
|
||||
case BuiltinType::LongLong:
|
||||
case BuiltinType::UInt128:
|
||||
case BuiltinType::Int128:
|
||||
case BuiltinType::Float:
|
||||
case BuiltinType::Double:
|
||||
case BuiltinType::Float128:
|
||||
case BuiltinType::LongDouble:
|
||||
case BuiltinType::WChar_U:
|
||||
case BuiltinType::Char16:
|
||||
case BuiltinType::Char32:
|
||||
case BuiltinType::WChar_S:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
|
||||
case BuiltinType::NullPtr:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
|
||||
case BuiltinType::Void:
|
||||
case BuiltinType::Half:
|
||||
case BuiltinType::ObjCId:
|
||||
case BuiltinType::ObjCClass:
|
||||
case BuiltinType::ObjCSel:
|
||||
case BuiltinType::OMPArraySection:
|
||||
case BuiltinType::Dependent:
|
||||
case BuiltinType::Overload:
|
||||
case BuiltinType::BoundMember:
|
||||
case BuiltinType::PseudoObject:
|
||||
case BuiltinType::UnknownAny:
|
||||
case BuiltinType::BuiltinFn:
|
||||
case BuiltinType::ARCUnbridgedCast:
|
||||
case BuiltinType::OCLImage1dRO:
|
||||
case BuiltinType::OCLImage1dArrayRO:
|
||||
case BuiltinType::OCLImage1dBufferRO:
|
||||
case BuiltinType::OCLImage2dRO:
|
||||
case BuiltinType::OCLImage2dArrayRO:
|
||||
case BuiltinType::OCLImage2dDepthRO:
|
||||
case BuiltinType::OCLImage2dArrayDepthRO:
|
||||
case BuiltinType::OCLImage2dMSAARO:
|
||||
case BuiltinType::OCLImage2dArrayMSAARO:
|
||||
case BuiltinType::OCLImage2dMSAADepthRO:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthRO:
|
||||
case BuiltinType::OCLImage3dRO:
|
||||
case BuiltinType::OCLImage1dWO:
|
||||
case BuiltinType::OCLImage1dArrayWO:
|
||||
case BuiltinType::OCLImage1dBufferWO:
|
||||
case BuiltinType::OCLImage2dWO:
|
||||
case BuiltinType::OCLImage2dArrayWO:
|
||||
case BuiltinType::OCLImage2dDepthWO:
|
||||
case BuiltinType::OCLImage2dArrayDepthWO:
|
||||
case BuiltinType::OCLImage2dMSAAWO:
|
||||
case BuiltinType::OCLImage2dArrayMSAAWO:
|
||||
case BuiltinType::OCLImage2dMSAADepthWO:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthWO:
|
||||
case BuiltinType::OCLImage3dWO:
|
||||
case BuiltinType::OCLImage1dRW:
|
||||
case BuiltinType::OCLImage1dArrayRW:
|
||||
case BuiltinType::OCLImage1dBufferRW:
|
||||
case BuiltinType::OCLImage2dRW:
|
||||
case BuiltinType::OCLImage2dArrayRW:
|
||||
case BuiltinType::OCLImage2dDepthRW:
|
||||
case BuiltinType::OCLImage2dArrayDepthRW:
|
||||
case BuiltinType::OCLImage2dMSAARW:
|
||||
case BuiltinType::OCLImage2dArrayMSAARW:
|
||||
case BuiltinType::OCLImage2dMSAADepthRW:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepthRW:
|
||||
case BuiltinType::OCLImage3dRW:
|
||||
case BuiltinType::OCLSampler:
|
||||
case BuiltinType::OCLEvent:
|
||||
case BuiltinType::OCLClkEvent:
|
||||
case BuiltinType::OCLQueue:
|
||||
case BuiltinType::OCLReserveID:
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::Pointer:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
|
||||
case Type::Typedef:
|
||||
{
|
||||
const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty);
|
||||
const TypedefNameDecl *typedef_decl = typedef_ty->getDecl();
|
||||
auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl());
|
||||
if (existing_entry) {
|
||||
return existing_entry->value;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
case Type::Enum:
|
||||
{
|
||||
const EnumType *enum_ty = static_cast<const EnumType*>(ty);
|
||||
AstNode *enum_type = resolve_enum_decl(c, enum_ty->getDecl());
|
||||
return to_enum_zero_cmp(c, res, enum_type);
|
||||
}
|
||||
|
||||
case Type::Elaborated:
|
||||
{
|
||||
const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty);
|
||||
switch (elaborated_ty->getKeyword()) {
|
||||
case ETK_Enum: {
|
||||
AstNode *enum_type = trans_qual_type(c, elaborated_ty->getNamedType(), expr->getLocStart());
|
||||
return to_enum_zero_cmp(c, res, enum_type);
|
||||
}
|
||||
case ETK_Struct:
|
||||
case ETK_Union:
|
||||
case ETK_Interface:
|
||||
case ETK_Class:
|
||||
case ETK_Typename:
|
||||
case ETK_None:
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
case Type::FunctionProto:
|
||||
case Type::Record:
|
||||
case Type::ConstantArray:
|
||||
case Type::Paren:
|
||||
case Type::Decayed:
|
||||
case Type::Attributed:
|
||||
case Type::IncompleteArray:
|
||||
case Type::BlockPointer:
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
case Type::MemberPointer:
|
||||
case Type::VariableArray:
|
||||
case Type::DependentSizedArray:
|
||||
case Type::DependentSizedExtVector:
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
case Type::FunctionNoProto:
|
||||
case Type::UnresolvedUsing:
|
||||
case Type::Adjusted:
|
||||
case Type::TypeOfExpr:
|
||||
case Type::TypeOf:
|
||||
case Type::Decltype:
|
||||
case Type::UnaryTransform:
|
||||
case Type::TemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParm:
|
||||
case Type::SubstTemplateTypeParmPack:
|
||||
case Type::TemplateSpecialization:
|
||||
case Type::Auto:
|
||||
case Type::InjectedClassName:
|
||||
case Type::DependentName:
|
||||
case Type::DependentTemplateSpecialization:
|
||||
case Type::PackExpansion:
|
||||
case Type::ObjCObject:
|
||||
case Type::ObjCInterface:
|
||||
case Type::Complex:
|
||||
case Type::ObjCObjectPointer:
|
||||
case Type::Atomic:
|
||||
case Type::Pipe:
|
||||
case Type::ObjCTypeParam:
|
||||
case Type::DeducedTemplateSpecialization:
|
||||
return res;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static AstNode *trans_while_loop(Context *c, TransScope *scope, const WhileStmt *stmt) {
|
||||
TransScopeWhile *while_scope = trans_scope_while_create(c, scope);
|
||||
|
||||
while_scope->node->data.while_expr.condition = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (while_scope->node->data.while_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
|
||||
@ -2236,87 +2513,11 @@ static AstNode *trans_if_statement(Context *c, TransScope *scope, const IfStmt *
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AstNode *condition_node = trans_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (condition_node == nullptr)
|
||||
if_node->data.if_bool_expr.condition = trans_bool_expr(c, ResultUsedYes, scope, stmt->getCond(), TransRValue);
|
||||
if (if_node->data.if_bool_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
|
||||
switch (condition_node->type) {
|
||||
case NodeTypeBinOpExpr:
|
||||
switch (condition_node->data.bin_op_expr.bin_op) {
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
case BinOpTypeCmpEq:
|
||||
case BinOpTypeCmpNotEq:
|
||||
case BinOpTypeCmpLessThan:
|
||||
case BinOpTypeCmpGreaterThan:
|
||||
case BinOpTypeCmpLessOrEq:
|
||||
case BinOpTypeCmpGreaterOrEq:
|
||||
if_node->data.if_bool_expr.condition = condition_node;
|
||||
return if_node;
|
||||
default:
|
||||
goto convert_to_bitcast;
|
||||
}
|
||||
|
||||
case NodeTypePrefixOpExpr:
|
||||
switch (condition_node->data.prefix_op_expr.prefix_op) {
|
||||
case PrefixOpBoolNot:
|
||||
if_node->data.if_bool_expr.condition = condition_node;
|
||||
return if_node;
|
||||
default:
|
||||
goto convert_to_bitcast;
|
||||
}
|
||||
|
||||
case NodeTypeBoolLiteral:
|
||||
if_node->data.if_bool_expr.condition = condition_node;
|
||||
return if_node;
|
||||
|
||||
default: {
|
||||
// In Zig, float, int and pointer does not work in if statements.
|
||||
// To make it work, we bitcast any value we get to an int of the right size
|
||||
// and comp it to 0
|
||||
// TODO: This doesn't work for pointers, as they become nullable on
|
||||
// translate
|
||||
// c: if (cond) { }
|
||||
// zig: {
|
||||
// zig: const _tmp = cond;
|
||||
// zig: if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
|
||||
// zig: }
|
||||
convert_to_bitcast:
|
||||
TransScopeBlock *child_scope = trans_scope_block_create(c, scope);
|
||||
|
||||
// const _tmp = cond;
|
||||
// TODO: avoid name collisions with generated variable names
|
||||
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
||||
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, condition_node);
|
||||
child_scope->node->data.block.statements.append(tmp_var_decl);
|
||||
|
||||
// @sizeOf(@typeOf(_tmp)) * 8
|
||||
AstNode *typeof_tmp = trans_create_node_builtin_fn_call_str(c, "typeOf");
|
||||
typeof_tmp->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
|
||||
AstNode *sizeof_tmp = trans_create_node_builtin_fn_call_str(c, "sizeOf");
|
||||
sizeof_tmp->data.fn_call_expr.params.append(typeof_tmp);
|
||||
AstNode *sizeof_tmp_in_bits = trans_create_node_bin_op(
|
||||
c, sizeof_tmp, BinOpTypeMult,
|
||||
trans_create_node_unsigned_negative(c, 8, false));
|
||||
|
||||
// @IntType(false, @sizeOf(@typeOf(_tmp)) * 8)
|
||||
AstNode *int_type = trans_create_node_builtin_fn_call_str(c, "IntType");
|
||||
int_type->data.fn_call_expr.params.append(trans_create_node_bool(c, false));
|
||||
int_type->data.fn_call_expr.params.append(sizeof_tmp_in_bits);
|
||||
|
||||
// @bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp)
|
||||
AstNode *bit_cast = trans_create_node_builtin_fn_call_str(c, "bitCast");
|
||||
bit_cast->data.fn_call_expr.params.append(int_type);
|
||||
bit_cast->data.fn_call_expr.params.append(trans_create_node_symbol(c, tmp_var_name));
|
||||
|
||||
// if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) { }
|
||||
AstNode *not_eql_zero = trans_create_node_bin_op(c, bit_cast, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
|
||||
if_node->data.if_bool_expr.condition = not_eql_zero;
|
||||
child_scope->node->data.block.statements.append(if_node);
|
||||
|
||||
return child_scope->node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *scope, const CallExpr *stmt) {
|
||||
@ -2326,8 +2527,10 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
|
||||
if (callee_raw_node == nullptr)
|
||||
return nullptr;
|
||||
|
||||
bool is_ptr = false;
|
||||
const FunctionProtoType *fn_ty = qual_type_get_fn_proto(stmt->getCallee()->getType(), &is_ptr);
|
||||
AstNode *callee_node = nullptr;
|
||||
if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) {
|
||||
if (is_ptr && fn_ty) {
|
||||
if (stmt->getCallee()->getStmtClass() == Stmt::ImplicitCastExprClass) {
|
||||
const ImplicitCastExpr *implicit_cast = static_cast<const ImplicitCastExpr *>(stmt->getCallee());
|
||||
if (implicit_cast->getCastKind() == CK_FunctionToPointerDecay) {
|
||||
@ -2359,6 +2562,10 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope *
|
||||
node->data.fn_call_expr.params.append(arg_node);
|
||||
}
|
||||
|
||||
if (result_used == ResultUsedNo && fn_ty && !qual_type_canon(fn_ty->getReturnType())->isVoidType()) {
|
||||
node = trans_create_node_bin_op(c, trans_create_node_symbol_str(c, "_"), BinOpTypeAssign, node);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -2500,12 +2707,20 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
|
||||
const Stmt *cond_stmt = stmt->getCond();
|
||||
if (cond_stmt == nullptr) {
|
||||
while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
|
||||
} else {
|
||||
if (Expr::classof(cond_stmt)) {
|
||||
const Expr *cond_expr = static_cast<const Expr*>(cond_stmt);
|
||||
while_scope->node->data.while_expr.condition = trans_bool_expr(c, ResultUsedYes, cond_scope, cond_expr, TransRValue);
|
||||
|
||||
if (while_scope->node->data.while_expr.condition == nullptr)
|
||||
return nullptr;
|
||||
} else {
|
||||
TransScope *end_cond_scope = trans_stmt(c, cond_scope, cond_stmt,
|
||||
&while_scope->node->data.while_expr.condition);
|
||||
if (end_cond_scope == nullptr)
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const Stmt *inc_stmt = stmt->getInc();
|
||||
if (inc_stmt != nullptr) {
|
||||
@ -2525,6 +2740,155 @@ static AstNode *trans_for_loop(Context *c, TransScope *parent_scope, const ForSt
|
||||
return loop_block_node;
|
||||
}
|
||||
|
||||
static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
|
||||
TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
|
||||
|
||||
TransScopeSwitch *switch_scope;
|
||||
|
||||
const DeclStmt *var_decl_stmt = stmt->getConditionVariableDeclStmt();
|
||||
if (var_decl_stmt == nullptr) {
|
||||
switch_scope = trans_scope_switch_create(c, &block_scope->base);
|
||||
} else {
|
||||
AstNode *vars_node;
|
||||
TransScope *var_scope = trans_stmt(c, &block_scope->base, var_decl_stmt, &vars_node);
|
||||
if (var_scope == nullptr)
|
||||
return nullptr;
|
||||
if (vars_node != nullptr)
|
||||
block_scope->node->data.block.statements.append(vars_node);
|
||||
switch_scope = trans_scope_switch_create(c, var_scope);
|
||||
}
|
||||
block_scope->node->data.block.statements.append(switch_scope->switch_node);
|
||||
|
||||
// TODO avoid name collisions
|
||||
Buf *end_label_name = buf_create_from_str("__switch");
|
||||
switch_scope->end_label_name = end_label_name;
|
||||
block_scope->node->data.block.name = end_label_name;
|
||||
|
||||
const Expr *cond_expr = stmt->getCond();
|
||||
assert(cond_expr != nullptr);
|
||||
|
||||
AstNode *expr_node = trans_expr(c, ResultUsedYes, &block_scope->base, cond_expr, TransRValue);
|
||||
if (expr_node == nullptr)
|
||||
return nullptr;
|
||||
switch_scope->switch_node->data.switch_expr.expr = expr_node;
|
||||
|
||||
AstNode *body_node;
|
||||
const Stmt *body_stmt = stmt->getBody();
|
||||
if (body_stmt->getStmtClass() == Stmt::CompoundStmtClass) {
|
||||
if (trans_compound_stmt_inline(c, &switch_scope->base, (const CompoundStmt *)body_stmt,
|
||||
block_scope->node, nullptr))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
TransScope *body_scope = trans_stmt(c, &switch_scope->base, body_stmt, &body_node);
|
||||
if (body_scope == nullptr)
|
||||
return nullptr;
|
||||
if (body_node != nullptr)
|
||||
block_scope->node->data.block.statements.append(body_node);
|
||||
}
|
||||
|
||||
if (!switch_scope->found_default && !stmt->isAllEnumCasesCovered()) {
|
||||
AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
|
||||
prong_node->data.switch_prong.expr = trans_create_node_break(c, end_label_name, nullptr);
|
||||
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
|
||||
}
|
||||
|
||||
return block_scope->node;
|
||||
}
|
||||
|
||||
static TransScopeSwitch *trans_scope_switch_find(TransScope *scope) {
|
||||
while (scope != nullptr) {
|
||||
if (scope->id == TransScopeIdSwitch) {
|
||||
return (TransScopeSwitch *)scope;
|
||||
}
|
||||
scope = scope->parent;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
|
||||
TransScope **out_scope) {
|
||||
*out_node = nullptr;
|
||||
|
||||
if (stmt->getRHS() != nullptr) {
|
||||
emit_warning(c, stmt->getLocStart(), "TODO support GNU switch case a ... b extension");
|
||||
return ErrorUnexpected;
|
||||
}
|
||||
|
||||
TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
|
||||
assert(switch_scope != nullptr);
|
||||
|
||||
Buf *label_name = buf_sprintf("__case_%" PRIu32, switch_scope->case_index);
|
||||
switch_scope->case_index += 1;
|
||||
|
||||
{
|
||||
// Add the prong
|
||||
AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
|
||||
AstNode *item_node = trans_expr(c, ResultUsedYes, &switch_scope->base, stmt->getLHS(), TransRValue);
|
||||
if (item_node == nullptr)
|
||||
return ErrorUnexpected;
|
||||
prong_node->data.switch_prong.items.append(item_node);
|
||||
prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr);
|
||||
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
|
||||
}
|
||||
|
||||
TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
|
||||
|
||||
AstNode *case_block = trans_create_node(c, NodeTypeBlock);
|
||||
case_block->data.block.name = label_name;
|
||||
case_block->data.block.statements = scope_block->node->data.block.statements;
|
||||
scope_block->node->data.block.statements = {0};
|
||||
scope_block->node->data.block.statements.append(case_block);
|
||||
|
||||
AstNode *sub_stmt_node;
|
||||
TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
|
||||
if (new_scope == nullptr)
|
||||
return ErrorUnexpected;
|
||||
if (sub_stmt_node != nullptr)
|
||||
scope_block->node->data.block.statements.append(sub_stmt_node);
|
||||
|
||||
*out_scope = new_scope;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static int trans_switch_default(Context *c, TransScope *parent_scope, const DefaultStmt *stmt, AstNode **out_node,
|
||||
TransScope **out_scope)
|
||||
{
|
||||
*out_node = nullptr;
|
||||
|
||||
TransScopeSwitch *switch_scope = trans_scope_switch_find(parent_scope);
|
||||
assert(switch_scope != nullptr);
|
||||
|
||||
Buf *label_name = buf_sprintf("__default");
|
||||
|
||||
{
|
||||
// Add the prong
|
||||
AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
|
||||
prong_node->data.switch_prong.expr = trans_create_node_break(c, label_name, nullptr);
|
||||
switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
|
||||
switch_scope->found_default = true;
|
||||
}
|
||||
|
||||
TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
|
||||
|
||||
AstNode *case_block = trans_create_node(c, NodeTypeBlock);
|
||||
case_block->data.block.name = label_name;
|
||||
case_block->data.block.statements = scope_block->node->data.block.statements;
|
||||
scope_block->node->data.block.statements = {0};
|
||||
scope_block->node->data.block.statements.append(case_block);
|
||||
|
||||
AstNode *sub_stmt_node;
|
||||
TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
|
||||
if (new_scope == nullptr)
|
||||
return ErrorUnexpected;
|
||||
if (sub_stmt_node != nullptr)
|
||||
scope_block->node->data.block.statements.append(sub_stmt_node);
|
||||
|
||||
*out_scope = new_scope;
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
static AstNode *trans_string_literal(Context *c, TransScope *scope, const StringLiteral *stmt) {
|
||||
switch (stmt->getKind()) {
|
||||
case StringLiteral::Ascii:
|
||||
@ -2549,7 +2913,8 @@ static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt
|
||||
if (cur_scope->id == TransScopeIdWhile) {
|
||||
return trans_create_node(c, NodeTypeBreak);
|
||||
} else if (cur_scope->id == TransScopeIdSwitch) {
|
||||
zig_panic("TODO");
|
||||
TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
|
||||
return trans_create_node_break(c, switch_scope->end_label_name, nullptr);
|
||||
}
|
||||
cur_scope = cur_scope->parent;
|
||||
}
|
||||
@ -2649,14 +3014,12 @@ static int trans_stmt_extra(Context *c, TransScope *scope, const Stmt *stmt,
|
||||
return wrap_stmt(out_node, out_child_scope, scope,
|
||||
trans_expr(c, result_used, scope, ((const ParenExpr*)stmt)->getSubExpr(), lrvalue));
|
||||
case Stmt::SwitchStmtClass:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass");
|
||||
return ErrorUnexpected;
|
||||
return wrap_stmt(out_node, out_child_scope, scope,
|
||||
trans_switch_stmt(c, scope, (const SwitchStmt *)stmt));
|
||||
case Stmt::CaseStmtClass:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass");
|
||||
return ErrorUnexpected;
|
||||
return trans_switch_case(c, scope, (const CaseStmt *)stmt, out_node, out_child_scope);
|
||||
case Stmt::DefaultStmtClass:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass");
|
||||
return ErrorUnexpected;
|
||||
return trans_switch_default(c, scope, (const DefaultStmt *)stmt, out_node, out_child_scope);
|
||||
case Stmt::NoStmtClass:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass");
|
||||
return ErrorUnexpected;
|
||||
@ -3826,6 +4189,14 @@ static TransScopeVar *trans_scope_var_create(Context *c, TransScope *parent_scop
|
||||
return result;
|
||||
}
|
||||
|
||||
static TransScopeSwitch *trans_scope_switch_create(Context *c, TransScope *parent_scope) {
|
||||
TransScopeSwitch *result = allocate<TransScopeSwitch>(1);
|
||||
result->base.id = TransScopeIdSwitch;
|
||||
result->base.parent = parent_scope;
|
||||
result->switch_node = trans_create_node(c, NodeTypeSwitchExpr);
|
||||
return result;
|
||||
}
|
||||
|
||||
static TransScopeBlock *trans_scope_block_find(TransScope *scope) {
|
||||
while (scope != nullptr) {
|
||||
if (scope->id == TransScopeIdBlock) {
|
||||
|
@ -62,9 +62,7 @@ pub const BufMap = struct {
|
||||
}
|
||||
|
||||
fn free(self: &BufMap, value: []const u8) void {
|
||||
// remove the const
|
||||
const mut_value = @ptrCast(&u8, value.ptr)[0..value.len];
|
||||
self.hash_map.allocator.free(mut_value);
|
||||
self.hash_map.allocator.free(value);
|
||||
}
|
||||
|
||||
fn copy(self: &BufMap, value: []const u8) ![]const u8 {
|
||||
|
@ -50,9 +50,7 @@ pub const BufSet = struct {
|
||||
}
|
||||
|
||||
fn free(self: &BufSet, value: []const u8) void {
|
||||
// remove the const
|
||||
const mut_value = @ptrCast(&u8, value.ptr)[0..value.len];
|
||||
self.hash_map.allocator.free(mut_value);
|
||||
self.hash_map.allocator.free(value);
|
||||
}
|
||||
|
||||
fn copy(self: &BufSet, value: []const u8) ![]const u8 {
|
||||
|
@ -1634,7 +1634,7 @@ pub fn argsFree(allocator: &mem.Allocator, args_alloc: []const []u8) void {
|
||||
for (args_alloc) |arg| {
|
||||
total_bytes += @sizeOf([]u8) + arg.len;
|
||||
}
|
||||
const unaligned_allocated_buf = @ptrCast(&u8, args_alloc.ptr)[0..total_bytes];
|
||||
const unaligned_allocated_buf = @ptrCast(&const u8, args_alloc.ptr)[0..total_bytes];
|
||||
const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
|
||||
return allocator.free(aligned_allocated_buf);
|
||||
}
|
||||
|
@ -11,8 +11,8 @@ pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem:
|
||||
const SignedDoubleInt = @IntType(true, DoubleInt.bit_count);
|
||||
const Log2SingleInt = @import("../../math/index.zig").Log2Int(SingleInt);
|
||||
|
||||
const n = *@ptrCast(&[2]SingleInt, &a); // TODO issue #421
|
||||
const d = *@ptrCast(&[2]SingleInt, &b); // TODO issue #421
|
||||
const n = *@ptrCast(&const [2]SingleInt, &a); // TODO issue #421
|
||||
const d = *@ptrCast(&const [2]SingleInt, &b); // TODO issue #421
|
||||
var q: [2]SingleInt = undefined;
|
||||
var r: [2]SingleInt = undefined;
|
||||
var sr: c_uint = undefined;
|
||||
|
@ -96,7 +96,15 @@ pub fn utf8ValidateSlice(s: []const u8) bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
const Utf8View = struct {
|
||||
/// Utf8View iterates the code points of a utf-8 encoded string.
|
||||
///
|
||||
/// ```
|
||||
/// var utf8 = (try std.unicode.Utf8View.init("hi there")).iterator();
|
||||
/// while (utf8.nextCodepointSlice()) |codepoint| {
|
||||
/// std.debug.warn("got codepoint {}\n", codepoint);
|
||||
/// }
|
||||
/// ```
|
||||
pub const Utf8View = struct {
|
||||
bytes: []const u8,
|
||||
|
||||
pub fn init(s: []const u8) !Utf8View {
|
||||
@ -124,7 +132,7 @@ const Utf8View = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn Iterator(s: &const Utf8View) Utf8Iterator {
|
||||
pub fn iterator(s: &const Utf8View) Utf8Iterator {
|
||||
return Utf8Iterator {
|
||||
.bytes = s.bytes,
|
||||
.i = 0,
|
||||
@ -165,13 +173,13 @@ const Utf8Iterator = struct {
|
||||
test "utf8 iterator on ascii" {
|
||||
const s = Utf8View.initComptime("abc");
|
||||
|
||||
var it1 = s.Iterator();
|
||||
var it1 = s.iterator();
|
||||
debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice()));
|
||||
debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice()));
|
||||
debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice()));
|
||||
debug.assert(it1.nextCodepointSlice() == null);
|
||||
|
||||
var it2 = s.Iterator();
|
||||
var it2 = s.iterator();
|
||||
debug.assert(??it2.nextCodepoint() == 'a');
|
||||
debug.assert(??it2.nextCodepoint() == 'b');
|
||||
debug.assert(??it2.nextCodepoint() == 'c');
|
||||
@ -189,13 +197,13 @@ test "utf8 view bad" {
|
||||
test "utf8 view ok" {
|
||||
const s = Utf8View.initComptime("東京市");
|
||||
|
||||
var it1 = s.Iterator();
|
||||
var it1 = s.iterator();
|
||||
debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice()));
|
||||
debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice()));
|
||||
debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice()));
|
||||
debug.assert(it1.nextCodepointSlice() == null);
|
||||
|
||||
var it2 = s.Iterator();
|
||||
var it2 = s.iterator();
|
||||
debug.assert(??it2.nextCodepoint() == 0x6771);
|
||||
debug.assert(??it2.nextCodepoint() == 0x4eac);
|
||||
debug.assert(??it2.nextCodepoint() == 0x5e02);
|
||||
|
@ -16,7 +16,7 @@ test "integer literal to pointer cast" {
|
||||
test "pointer reinterpret const float to int" {
|
||||
const float: f64 = 5.99999999999994648725e-01;
|
||||
const float_ptr = &float;
|
||||
const int_ptr = @ptrCast(&i32, float_ptr);
|
||||
const int_ptr = @ptrCast(&const i32, float_ptr);
|
||||
const int_val = *int_ptr;
|
||||
assert(int_val == 858993411);
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ test "generic malloc free" {
|
||||
const a = memAlloc(u8, 10) catch unreachable;
|
||||
memFree(u8, a);
|
||||
}
|
||||
const some_mem : [100]u8 = undefined;
|
||||
var some_mem : [100]u8 = undefined;
|
||||
fn memAlloc(comptime T: type, n: usize) error![]T {
|
||||
return @ptrCast(&T, &some_mem[0])[0..n];
|
||||
}
|
||||
@ -650,3 +650,13 @@ test "packed struct, enum, union parameters in extern function" {
|
||||
|
||||
export fn testPackedStuff(a: &const PackedStruct, b: &const PackedUnion, c: PackedEnum) void {
|
||||
}
|
||||
|
||||
|
||||
test "slicing zero length array" {
|
||||
const s1 = ""[0..];
|
||||
const s2 = ([]u32{})[0..];
|
||||
assert(s1.len == 0);
|
||||
assert(s2.len == 0);
|
||||
assert(mem.eql(u8, s1, ""));
|
||||
assert(mem.eql(u32, s2, []u32{}));
|
||||
}
|
||||
|
@ -285,8 +285,8 @@ pub fn addCases(cases: &tests.CompareOutputContext) void {
|
||||
\\const c = @cImport(@cInclude("stdlib.h"));
|
||||
\\
|
||||
\\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) c_int {
|
||||
\\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable);
|
||||
\\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable);
|
||||
\\ const a_int = @ptrCast(&align(1) const i32, a ?? unreachable);
|
||||
\\ const b_int = @ptrCast(&align(1) const i32, b ?? unreachable);
|
||||
\\ if (*a_int < *b_int) {
|
||||
\\ return -1;
|
||||
\\ } else if (*a_int > *b_int) {
|
||||
|
@ -1,6 +1,45 @@
|
||||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: &tests.CompileErrorContext) void {
|
||||
cases.add("@tagName used on union with no associated enum tag",
|
||||
\\const FloatInt = extern union {
|
||||
\\ Float: f32,
|
||||
\\ Int: i32,
|
||||
\\};
|
||||
\\export fn entry() void {
|
||||
\\ var fi = FloatInt{.Float = 123.45};
|
||||
\\ var tagName = @tagName(fi);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:7:19: error: union has no associated enum",
|
||||
".tmp_source.zig:1:18: note: declared here");
|
||||
|
||||
cases.add("returning error from void async function",
|
||||
\\const std = @import("std");
|
||||
\\export fn entry() void {
|
||||
\\ const p = async(std.debug.global_allocator) amain() catch unreachable;
|
||||
\\}
|
||||
\\async fn amain() void {
|
||||
\\ return error.ShouldBeCompileError;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:17: error: expected type 'void', found 'error{ShouldBeCompileError}'");
|
||||
|
||||
cases.add("var not allowed in structs",
|
||||
\\export fn entry() void {
|
||||
\\ var s = (struct{v: var}){.v=i32(10)};
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:23: error: invalid token: 'var'");
|
||||
|
||||
cases.add("@ptrCast discards const qualifier",
|
||||
\\export fn entry() void {
|
||||
\\ const x: i32 = 1234;
|
||||
\\ const y = @ptrCast(&i32, &x);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:15: error: cast discards const qualifier");
|
||||
|
||||
cases.add("comptime slice of undefined pointer non-zero len",
|
||||
\\export fn entry() void {
|
||||
\\ const slice = (&i32)(undefined)[0..1];
|
||||
@ -2432,7 +2471,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) void {
|
||||
\\const Derp = @OpaqueType();
|
||||
\\extern fn bar(d: &Derp) void;
|
||||
\\export fn foo() void {
|
||||
\\ const x = u8(1);
|
||||
\\ var x = u8(1);
|
||||
\\ bar(@ptrCast(&c_void, &x));
|
||||
\\}
|
||||
,
|
||||
|
@ -351,7 +351,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (a > c_uint(0)) {
|
||||
\\ a >>= @import("std").math.Log2Int(c_uint)(1);
|
||||
\\ };
|
||||
\\ }
|
||||
\\ return i;
|
||||
\\}
|
||||
);
|
||||
@ -451,6 +451,28 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("logical and, logical or on none bool values",
|
||||
\\int and_or_none_bool(int a, float b, void *c) {
|
||||
\\ if (a && b) return 0;
|
||||
\\ if (b && c) return 1;
|
||||
\\ if (a && c) return 2;
|
||||
\\ if (a || b) return 3;
|
||||
\\ if (b || c) return 4;
|
||||
\\ if (a || c) return 5;
|
||||
\\ return 6;
|
||||
\\}
|
||||
,
|
||||
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ if ((a != 0) and (b != 0)) return 0;
|
||||
\\ if ((b != 0) and (c != null)) return 1;
|
||||
\\ if ((a != 0) and (c != null)) return 2;
|
||||
\\ if ((a != 0) or (b != 0)) return 3;
|
||||
\\ if ((b != 0) or (c != null)) return 4;
|
||||
\\ if ((a != 0) or (c != null)) return 5;
|
||||
\\ return 6;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("assign",
|
||||
\\int max(int a) {
|
||||
\\ int tmp;
|
||||
@ -498,7 +520,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (a > c_uint(0)) {
|
||||
\\ a >>= u5(1);
|
||||
\\ };
|
||||
\\ }
|
||||
\\ return i;
|
||||
\\}
|
||||
);
|
||||
@ -515,11 +537,19 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
|
||||
cases.addC("function call",
|
||||
\\static void bar(void) { }
|
||||
\\void foo(void) { bar(); }
|
||||
\\static int baz(void) { return 0; }
|
||||
\\void foo(void) {
|
||||
\\ bar();
|
||||
\\ baz();
|
||||
\\}
|
||||
,
|
||||
\\pub fn bar() void {}
|
||||
\\pub fn baz() c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
\\pub export fn foo() void {
|
||||
\\ bar();
|
||||
\\ _ = baz();
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -867,32 +897,42 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\ while (true) {
|
||||
\\ a -= 1;
|
||||
\\ if (!(a != 0)) break;
|
||||
\\ };
|
||||
\\ }
|
||||
\\ var b: c_int = 2;
|
||||
\\ while (true) {
|
||||
\\ b -= 1;
|
||||
\\ if (!(b != 0)) break;
|
||||
\\ };
|
||||
\\ }
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addC("deref function pointer",
|
||||
\\void foo(void) {}
|
||||
\\void baz(void) {}
|
||||
\\int baz(void) { return 0; }
|
||||
\\void bar(void) {
|
||||
\\ void(*f)(void) = foo;
|
||||
\\ int(*b)(void) = baz;
|
||||
\\ f();
|
||||
\\ (*(f))();
|
||||
\\ foo();
|
||||
\\ b();
|
||||
\\ (*(b))();
|
||||
\\ baz();
|
||||
\\}
|
||||
,
|
||||
\\pub export fn foo() void {}
|
||||
\\pub export fn baz() void {}
|
||||
\\pub export fn baz() c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
\\pub export fn bar() void {
|
||||
\\ var f: ?extern fn() void = foo;
|
||||
\\ var b: ?extern fn() c_int = baz;
|
||||
\\ (??f)();
|
||||
\\ (??f)();
|
||||
\\ baz();
|
||||
\\ foo();
|
||||
\\ _ = (??b)();
|
||||
\\ _ = (??b)();
|
||||
\\ _ = baz();
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -962,8 +1002,8 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\pub fn foo() void {
|
||||
\\ {
|
||||
\\ var i: c_int = 0;
|
||||
\\ while (i < 10) : (i += 1) {};
|
||||
\\ };
|
||||
\\ while (i < 10) : (i += 1) {}
|
||||
\\ }
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -973,7 +1013,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\}
|
||||
,
|
||||
\\pub fn foo() void {
|
||||
\\ while (true) {};
|
||||
\\ while (true) {}
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -987,7 +1027,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\pub fn foo() void {
|
||||
\\ while (true) {
|
||||
\\ break;
|
||||
\\ };
|
||||
\\ }
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1001,7 +1041,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\pub fn foo() void {
|
||||
\\ while (true) {
|
||||
\\ continue;
|
||||
\\ };
|
||||
\\ }
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1058,7 +1098,7 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\ {
|
||||
\\ var x_0: c_int = 2;
|
||||
\\ x_0 += 1;
|
||||
\\ };
|
||||
\\ }
|
||||
\\ return x;
|
||||
\\}
|
||||
);
|
||||
@ -1083,6 +1123,22 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("bool not",
|
||||
\\int foo(int a, float b, void *c) {
|
||||
\\ return !(a == 0);
|
||||
\\ return !a;
|
||||
\\ return !b;
|
||||
\\ return !c;
|
||||
\\}
|
||||
,
|
||||
\\pub fn foo(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("primitive types included in defined symbols",
|
||||
\\int foo(int u32) {
|
||||
\\ return u32;
|
||||
@ -1115,24 +1171,104 @@ pub fn addCases(cases: &tests.TranslateCContext) void {
|
||||
\\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr(&NRF_GPIO_Type, NRF_GPIO_BASE) else (&NRF_GPIO_Type)(NRF_GPIO_BASE);
|
||||
);
|
||||
|
||||
cases.add("if on int",
|
||||
\\int if_int(int i) {
|
||||
\\ if (i) {
|
||||
\\ return 0;
|
||||
\\ } else {
|
||||
\\ return 1;
|
||||
cases.add("if on none bool",
|
||||
\\enum SomeEnum { A, B, C };
|
||||
\\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
|
||||
\\ if (a) return 0;
|
||||
\\ if (b) return 1;
|
||||
\\ if (c) return 2;
|
||||
\\ if (d) return 3;
|
||||
\\ return 4;
|
||||
\\}
|
||||
,
|
||||
\\pub const A = enum_SomeEnum.A;
|
||||
\\pub const B = enum_SomeEnum.B;
|
||||
\\pub const C = enum_SomeEnum.C;
|
||||
\\pub const enum_SomeEnum = extern enum {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\};
|
||||
\\pub fn if_none_bool(a: c_int, b: f32, c: ?&c_void, d: enum_SomeEnum) c_int {
|
||||
\\ if (a != 0) return 0;
|
||||
\\ if (b != 0) return 1;
|
||||
\\ if (c != null) return 2;
|
||||
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
|
||||
\\ return 4;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("while on none bool",
|
||||
\\int while_none_bool(int a, float b, void *c) {
|
||||
\\ while (a) return 0;
|
||||
\\ while (b) return 1;
|
||||
\\ while (c) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
,
|
||||
\\pub fn while_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("for on none bool",
|
||||
\\int for_none_bool(int a, float b, void *c) {
|
||||
\\ for (;a;) return 0;
|
||||
\\ for (;b;) return 1;
|
||||
\\ for (;c;) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
,
|
||||
\\pub fn for_none_bool(a: c_int, b: f32, c: ?&c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("switch on int",
|
||||
\\int switch_fn(int i) {
|
||||
\\ int res = 0;
|
||||
\\ switch (i) {
|
||||
\\ case 0:
|
||||
\\ res = 1;
|
||||
\\ case 1:
|
||||
\\ res = 2;
|
||||
\\ default:
|
||||
\\ res = 3 * i;
|
||||
\\ break;
|
||||
\\ case 2:
|
||||
\\ res = 5;
|
||||
\\ }
|
||||
\\}
|
||||
,
|
||||
\\pub fn if_int(i: c_int) c_int {
|
||||
\\ {
|
||||
\\ const _tmp = i;
|
||||
\\ if (@bitCast(@IntType(false, @sizeOf(@typeOf(_tmp)) * 8), _tmp) != 0) {
|
||||
\\ return 0;
|
||||
\\ } else {
|
||||
\\ return 1;
|
||||
\\ };
|
||||
\\ };
|
||||
\\pub fn switch_fn(i: c_int) c_int {
|
||||
\\ var res: c_int = 0;
|
||||
\\ __switch: {
|
||||
\\ __case_2: {
|
||||
\\ __default: {
|
||||
\\ __case_1: {
|
||||
\\ __case_0: {
|
||||
\\ switch (i) {
|
||||
\\ 0 => break :__case_0,
|
||||
\\ 1 => break :__case_1,
|
||||
\\ else => break :__default,
|
||||
\\ 2 => break :__case_2,
|
||||
\\ }
|
||||
\\ }
|
||||
\\ res = 1;
|
||||
\\ }
|
||||
\\ res = 2;
|
||||
\\ }
|
||||
\\ res = (3 * i);
|
||||
\\ break :__switch;
|
||||
\\ }
|
||||
\\ res = 5;
|
||||
\\ }
|
||||
\\}
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user