Merge remote-tracking branch 'origin/master' into llvm6

This commit is contained in:
Andrew Kelley 2018-03-08 10:59:24 -05:00
commit b57cb04afc
22 changed files with 909 additions and 352 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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";

View File

@ -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);

View File

@ -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;

View File

@ -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:

View File

@ -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:

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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 {

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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{}));
}

View File

@ -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) {

View File

@ -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));
\\}
,

View File

@ -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;
\\ }
\\}
);
}