mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
update bootstrap to work for macos too
* Directives can have arbitrary expressions as parameters * Fix switch statement not generating code sometimes * Rename "main" fn in bootstrap.zig to "zig_user_main" to avoid name collisions * codegen: fix badref when unreachable is last thing in an expression * support #condition directive on exported functions
This commit is contained in:
parent
91101f08c2
commit
77ffb5075b
@ -31,7 +31,7 @@ ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
|
|||||||
|
|
||||||
FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
|
FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
|
||||||
|
|
||||||
Directive = "#" "Symbol" "(" "String" ")"
|
Directive = "#" "Symbol" "(" Expression ")"
|
||||||
|
|
||||||
VisibleMod = "pub" | "export"
|
VisibleMod = "pub" | "export"
|
||||||
|
|
||||||
|
|||||||
@ -427,7 +427,7 @@ struct AstNodeFieldAccessExpr {
|
|||||||
|
|
||||||
struct AstNodeDirective {
|
struct AstNodeDirective {
|
||||||
Buf name;
|
Buf name;
|
||||||
Buf param;
|
AstNode *expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeRootExportDecl {
|
struct AstNodeRootExportDecl {
|
||||||
@ -526,6 +526,7 @@ struct AstNodeSwitchExpr {
|
|||||||
|
|
||||||
// populated by semantic analyzer
|
// populated by semantic analyzer
|
||||||
Expr resolved_expr;
|
Expr resolved_expr;
|
||||||
|
int const_chosen_prong_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeSwitchProng {
|
struct AstNodeSwitchProng {
|
||||||
|
|||||||
166
src/analyze.cpp
166
src/analyze.cpp
@ -816,6 +816,53 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
|
|||||||
return get_fn_type(g, &fn_type_id);
|
return get_fn_type(g, &fn_type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) {
|
||||||
|
TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
|
||||||
|
TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *node);
|
||||||
|
|
||||||
|
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstExprValue *const_str_val = &get_resolved_expr(*node)->const_val;
|
||||||
|
|
||||||
|
if (!const_str_val->ok) {
|
||||||
|
add_node_error(g, *node, buf_sprintf("unable to resolve constant expression"));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
|
||||||
|
uint64_t len = ptr_field->data.x_ptr.len;
|
||||||
|
Buf *result = buf_alloc();
|
||||||
|
for (uint64_t i = 0; i < len; i += 1) {
|
||||||
|
ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
|
||||||
|
uint64_t big_c = char_val->data.x_bignum.data.x_uint;
|
||||||
|
assert(big_c <= UINT8_MAX);
|
||||||
|
uint8_t c = big_c;
|
||||||
|
buf_append_char(result, c);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||||
|
AstNode **node, bool *value)
|
||||||
|
{
|
||||||
|
TypeTableEntry *resolved_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *node);
|
||||||
|
|
||||||
|
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstExprValue *const_bool_val = &get_resolved_expr(*node)->const_val;
|
||||||
|
|
||||||
|
if (!const_bool_val->ok) {
|
||||||
|
add_node_error(g, *node, buf_sprintf("unable to resolve constant expression"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = const_bool_val->data.x_bool;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
|
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
|
||||||
ImportTableEntry *import)
|
ImportTableEntry *import)
|
||||||
@ -839,23 +886,38 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||||||
Buf *name = &directive_node->data.directive.name;
|
Buf *name = &directive_node->data.directive.name;
|
||||||
|
|
||||||
if (buf_eql_str(name, "attribute")) {
|
if (buf_eql_str(name, "attribute")) {
|
||||||
Buf *attr_name = &directive_node->data.directive.param;
|
|
||||||
if (fn_table_entry->fn_def_node) {
|
if (fn_table_entry->fn_def_node) {
|
||||||
if (buf_eql_str(attr_name, "naked")) {
|
Buf *attr_name = resolve_const_expr_str(g, import, import->block_context,
|
||||||
is_naked = true;
|
&directive_node->data.directive.expr);
|
||||||
} else if (buf_eql_str(attr_name, "cold")) {
|
if (attr_name) {
|
||||||
is_cold = true;
|
if (buf_eql_str(attr_name, "naked")) {
|
||||||
} else if (buf_eql_str(attr_name, "test")) {
|
is_naked = true;
|
||||||
is_test = true;
|
} else if (buf_eql_str(attr_name, "cold")) {
|
||||||
g->test_fn_count += 1;
|
is_cold = true;
|
||||||
} else {
|
} else if (buf_eql_str(attr_name, "test")) {
|
||||||
add_node_error(g, directive_node,
|
is_test = true;
|
||||||
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
|
g->test_fn_count += 1;
|
||||||
|
} else {
|
||||||
|
add_node_error(g, directive_node,
|
||||||
|
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, directive_node,
|
add_node_error(g, directive_node,
|
||||||
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
|
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
|
||||||
}
|
}
|
||||||
|
} else if (buf_eql_str(name, "condition")) {
|
||||||
|
if (fn_proto->visib_mod == VisibModExport) {
|
||||||
|
bool include;
|
||||||
|
bool ok = resolve_const_expr_bool(g, import, import->block_context,
|
||||||
|
&directive_node->data.directive.expr, &include);
|
||||||
|
if (ok && !include) {
|
||||||
|
fn_proto->visib_mod = VisibModPub;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
add_node_error(g, directive_node,
|
||||||
|
buf_sprintf("#condition valid only on exported symbols"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, directive_node,
|
add_node_error(g, directive_node,
|
||||||
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
||||||
@ -863,6 +925,15 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_internal = (fn_proto->visib_mod != VisibModExport);
|
||||||
|
bool is_c_compat = !is_internal || fn_proto->is_extern;
|
||||||
|
fn_table_entry->internal_linkage = !is_c_compat;
|
||||||
|
if (!is_internal) {
|
||||||
|
fn_table_entry->ref_count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,
|
TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,
|
||||||
is_naked, is_cold);
|
is_naked, is_cold);
|
||||||
|
|
||||||
@ -1242,8 +1313,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
|
|||||||
|
|
||||||
auto entry = fn_table->maybe_get(proto_name);
|
auto entry = fn_table->maybe_get(proto_name);
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport);
|
|
||||||
bool is_c_compat = !is_internal || is_extern;
|
|
||||||
bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
|
bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
add_node_error(g, proto_node,
|
add_node_error(g, proto_node,
|
||||||
@ -1263,10 +1332,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
|
|||||||
fn_table_entry->import_entry = import;
|
fn_table_entry->import_entry = import;
|
||||||
fn_table_entry->proto_node = proto_node;
|
fn_table_entry->proto_node = proto_node;
|
||||||
fn_table_entry->fn_def_node = fn_def_node;
|
fn_table_entry->fn_def_node = fn_def_node;
|
||||||
fn_table_entry->internal_linkage = !is_c_compat;
|
|
||||||
fn_table_entry->is_extern = is_extern;
|
fn_table_entry->is_extern = is_extern;
|
||||||
fn_table_entry->member_of_struct = struct_type;
|
fn_table_entry->member_of_struct = struct_type;
|
||||||
fn_table_entry->ref_count = (proto_node->data.fn_proto.visib_mod == VisibModExport) ? 1 : 0;
|
|
||||||
|
|
||||||
if (struct_type) {
|
if (struct_type) {
|
||||||
buf_resize(&fn_table_entry->symbol_name, 0);
|
buf_resize(&fn_table_entry->symbol_name, 0);
|
||||||
@ -1290,7 +1357,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
|
|||||||
g->main_fn = fn_table_entry;
|
g->main_fn = fn_table_entry;
|
||||||
|
|
||||||
if (g->bootstrap_import && !g->is_test_build) {
|
if (g->bootstrap_import && !g->is_test_build) {
|
||||||
g->bootstrap_import->fn_table.put(proto_name, fn_table_entry);
|
g->bootstrap_import->fn_table.put(buf_create_from_str("zig_user_main"), fn_table_entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main");
|
bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main");
|
||||||
@ -4246,54 +4313,33 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
|||||||
{
|
{
|
||||||
AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
|
AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
|
||||||
|
|
||||||
TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
|
Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
|
||||||
TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);
|
if (!var_name) {
|
||||||
|
return g->builtin_types.entry_invalid;
|
||||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
|
||||||
return resolved_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val;
|
|
||||||
|
|
||||||
if (!const_str_val->ok) {
|
|
||||||
add_node_error(g, *str_node, buf_sprintf("@compile_var requires constant expression"));
|
|
||||||
return g->builtin_types.entry_void;
|
|
||||||
}
|
|
||||||
|
|
||||||
ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
|
|
||||||
uint64_t len = ptr_field->data.x_ptr.len;
|
|
||||||
Buf var_name = BUF_INIT;
|
|
||||||
buf_resize(&var_name, 0);
|
|
||||||
for (uint64_t i = 0; i < len; i += 1) {
|
|
||||||
ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
|
|
||||||
uint64_t big_c = char_val->data.x_bignum.data.x_uint;
|
|
||||||
assert(big_c <= UINT8_MAX);
|
|
||||||
uint8_t c = big_c;
|
|
||||||
buf_append_char(&var_name, c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||||
const_val->ok = true;
|
const_val->ok = true;
|
||||||
const_val->depends_on_compile_var = true;
|
const_val->depends_on_compile_var = true;
|
||||||
|
|
||||||
if (buf_eql_str(&var_name, "is_big_endian")) {
|
if (buf_eql_str(var_name, "is_big_endian")) {
|
||||||
return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
|
return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
|
||||||
} else if (buf_eql_str(&var_name, "is_release")) {
|
} else if (buf_eql_str(var_name, "is_release")) {
|
||||||
return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
|
return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
|
||||||
} else if (buf_eql_str(&var_name, "is_test")) {
|
} else if (buf_eql_str(var_name, "is_test")) {
|
||||||
return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
|
return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
|
||||||
} else if (buf_eql_str(&var_name, "os")) {
|
} else if (buf_eql_str(var_name, "os")) {
|
||||||
const_val->data.x_enum.tag = g->target_os_index;
|
const_val->data.x_enum.tag = g->target_os_index;
|
||||||
return g->builtin_types.entry_os_enum;
|
return g->builtin_types.entry_os_enum;
|
||||||
} else if (buf_eql_str(&var_name, "arch")) {
|
} else if (buf_eql_str(var_name, "arch")) {
|
||||||
const_val->data.x_enum.tag = g->target_arch_index;
|
const_val->data.x_enum.tag = g->target_arch_index;
|
||||||
return g->builtin_types.entry_arch_enum;
|
return g->builtin_types.entry_arch_enum;
|
||||||
} else if (buf_eql_str(&var_name, "environ")) {
|
} else if (buf_eql_str(var_name, "environ")) {
|
||||||
const_val->data.x_enum.tag = g->target_environ_index;
|
const_val->data.x_enum.tag = g->target_environ_index;
|
||||||
return g->builtin_types.entry_environ_enum;
|
return g->builtin_types.entry_environ_enum;
|
||||||
} else {
|
} else {
|
||||||
add_node_error(g, *str_node,
|
add_node_error(g, *str_node,
|
||||||
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));
|
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
|
||||||
return g->builtin_types.entry_invalid;
|
return g->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4740,7 +4786,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
|
field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
int const_chosen_prong_index = -1;
|
int *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index;
|
||||||
|
*const_chosen_prong_index = -1;
|
||||||
AstNode *else_prong = nullptr;
|
AstNode *else_prong = nullptr;
|
||||||
for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
|
for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
|
||||||
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
|
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
|
||||||
@ -4756,8 +4803,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
var_type = expr_type;
|
var_type = expr_type;
|
||||||
var_is_target_expr = true;
|
var_is_target_expr = true;
|
||||||
if (const_chosen_prong_index == -1) {
|
if (*const_chosen_prong_index == -1 && expr_val->ok) {
|
||||||
const_chosen_prong_index = prong_i;
|
*const_chosen_prong_index = prong_i;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool all_agree_on_var_type = true;
|
bool all_agree_on_var_type = true;
|
||||||
@ -4792,7 +4839,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
if (!any_errors && expr_val->ok) {
|
if (!any_errors && expr_val->ok) {
|
||||||
if (expr_val->data.x_enum.tag == type_enum_field->value) {
|
if (expr_val->data.x_enum.tag == type_enum_field->value) {
|
||||||
const_chosen_prong_index = prong_i;
|
*const_chosen_prong_index = prong_i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -4844,7 +4891,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
|
for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
|
||||||
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
|
AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
|
||||||
BlockContext *child_context = prong_node->data.switch_prong.block_context;
|
BlockContext *child_context = prong_node->data.switch_prong.block_context;
|
||||||
child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i);
|
child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
|
||||||
|
|
||||||
peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
|
peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
|
||||||
prong_node->data.switch_prong.expr);
|
prong_node->data.switch_prong.expr);
|
||||||
@ -4872,10 +4919,9 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expr_val->ok) {
|
if (expr_val->ok) {
|
||||||
assert(const_chosen_prong_index != -1);
|
assert(*const_chosen_prong_index != -1);
|
||||||
|
|
||||||
*const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val;
|
*const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val;
|
||||||
const_val->ok = true;
|
|
||||||
// the target expr depends on a compile var,
|
// the target expr depends on a compile var,
|
||||||
// so the entire if statement does too
|
// so the entire if statement does too
|
||||||
const_val->depends_on_compile_var = true;
|
const_val->depends_on_compile_var = true;
|
||||||
@ -5490,6 +5536,12 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
|||||||
AstNode *param = node->data.fn_proto.params.at(i);
|
AstNode *param = node->data.fn_proto.params.at(i);
|
||||||
collect_expr_decl_deps(g, import, param, decl_node);
|
collect_expr_decl_deps(g, import, param, decl_node);
|
||||||
}
|
}
|
||||||
|
if (node->data.fn_proto.directives) {
|
||||||
|
for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
|
||||||
|
AstNode *directive = node->data.fn_proto.directives->at(i);
|
||||||
|
collect_expr_decl_deps(g, import, directive, decl_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
|
collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
|
||||||
break;
|
break;
|
||||||
case NodeTypeParamDecl:
|
case NodeTypeParamDecl:
|
||||||
@ -5498,12 +5550,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
|||||||
case NodeTypeTypeDecl:
|
case NodeTypeTypeDecl:
|
||||||
collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
|
collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
|
||||||
break;
|
break;
|
||||||
|
case NodeTypeDirective:
|
||||||
|
collect_expr_decl_deps(g, import, node->data.directive.expr, decl_node);
|
||||||
|
break;
|
||||||
case NodeTypeVariableDeclaration:
|
case NodeTypeVariableDeclaration:
|
||||||
case NodeTypeRootExportDecl:
|
case NodeTypeRootExportDecl:
|
||||||
case NodeTypeFnDef:
|
case NodeTypeFnDef:
|
||||||
case NodeTypeRoot:
|
case NodeTypeRoot:
|
||||||
case NodeTypeFnDecl:
|
case NodeTypeFnDecl:
|
||||||
case NodeTypeDirective:
|
|
||||||
case NodeTypeImport:
|
case NodeTypeImport:
|
||||||
case NodeTypeCImport:
|
case NodeTypeCImport:
|
||||||
case NodeTypeLabel:
|
case NodeTypeLabel:
|
||||||
|
|||||||
@ -339,6 +339,7 @@ void ast_print(FILE *f, AstNode *node, int indent) {
|
|||||||
break;
|
break;
|
||||||
case NodeTypeDirective:
|
case NodeTypeDirective:
|
||||||
fprintf(f, "%s\n", node_type_str(node->type));
|
fprintf(f, "%s\n", node_type_str(node->type));
|
||||||
|
ast_print(f, node->data.directive.expr, indent + 2);
|
||||||
break;
|
break;
|
||||||
case NodeTypePrefixOpExpr:
|
case NodeTypePrefixOpExpr:
|
||||||
fprintf(f, "%s %s\n", node_type_str(node->type),
|
fprintf(f, "%s %s\n", node_type_str(node->type),
|
||||||
@ -631,8 +632,9 @@ static void render_node(AstRender *ar, AstNode *node) {
|
|||||||
fprintf(ar->f, "}");
|
fprintf(ar->f, "}");
|
||||||
break;
|
break;
|
||||||
case NodeTypeDirective:
|
case NodeTypeDirective:
|
||||||
fprintf(ar->f, "#%s(\"%s\")\n", buf_ptr(&node->data.directive.name),
|
fprintf(ar->f, "#%s(", buf_ptr(&node->data.directive.name));
|
||||||
buf_ptr(&node->data.directive.param));
|
render_node(ar, node->data.directive.expr);
|
||||||
|
fprintf(ar->f, ")\n");
|
||||||
break;
|
break;
|
||||||
case NodeTypeReturnExpr:
|
case NodeTypeReturnExpr:
|
||||||
zig_panic("TODO");
|
zig_panic("TODO");
|
||||||
|
|||||||
@ -2150,7 +2150,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
|
|||||||
if (!g->is_release_build) {
|
if (!g->is_release_build) {
|
||||||
LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
|
LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
|
||||||
}
|
}
|
||||||
return LLVMBuildUnreachable(g->builder);
|
LLVMBuildUnreachable(g->builder);
|
||||||
|
return nullptr;
|
||||||
} else if (type_entry->id == TypeTableEntryIdVoid) {
|
} else if (type_entry->id == TypeTableEntryIdVoid) {
|
||||||
assert(node->data.container_init_expr.entries.length == 0);
|
assert(node->data.container_init_expr.entries.length == 0);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -2487,6 +2488,13 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
|
|||||||
static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
|
static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
|
||||||
assert(node->type == NodeTypeSwitchExpr);
|
assert(node->type == NodeTypeSwitchExpr);
|
||||||
|
|
||||||
|
if (node->data.switch_expr.const_chosen_prong_index >= 0) {
|
||||||
|
AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index);
|
||||||
|
assert(prong_node->type == NodeTypeSwitchProng);
|
||||||
|
AstNode *prong_expr = prong_node->data.switch_prong.expr;
|
||||||
|
return gen_expr(g, prong_expr);
|
||||||
|
}
|
||||||
|
|
||||||
TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
|
TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
|
||||||
LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
|
LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
|
||||||
LLVMValueRef target_value;
|
LLVMValueRef target_value;
|
||||||
@ -3877,18 +3885,23 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||||||
for (int i = 0; i < directives->length; i += 1) {
|
for (int i = 0; i < directives->length; i += 1) {
|
||||||
AstNode *directive_node = directives->at(i);
|
AstNode *directive_node = directives->at(i);
|
||||||
Buf *name = &directive_node->data.directive.name;
|
Buf *name = &directive_node->data.directive.name;
|
||||||
Buf *param = &directive_node->data.directive.param;
|
AstNode *param_node = directive_node->data.directive.expr;
|
||||||
if (buf_eql_str(name, "version")) {
|
assert(param_node->type == NodeTypeStringLiteral);
|
||||||
set_root_export_version(g, param, directive_node);
|
Buf *param = ¶m_node->data.string_literal.buf;
|
||||||
} else if (buf_eql_str(name, "link")) {
|
|
||||||
if (buf_eql_str(param, "c")) {
|
if (param) {
|
||||||
g->link_libc = true;
|
if (buf_eql_str(name, "version")) {
|
||||||
|
set_root_export_version(g, param, directive_node);
|
||||||
|
} else if (buf_eql_str(name, "link")) {
|
||||||
|
if (buf_eql_str(param, "c")) {
|
||||||
|
g->link_libc = true;
|
||||||
|
} else {
|
||||||
|
g->link_libs.append(param);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
g->link_libs.append(param);
|
add_node_error(g, directive_node,
|
||||||
|
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
add_node_error(g, directive_node,
|
|
||||||
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
83
src/link.cpp
83
src/link.cpp
@ -580,35 +580,33 @@ static void construct_linker_job_darwin(LinkJob *lj) {
|
|||||||
lj->args.append("-o");
|
lj->args.append("-o");
|
||||||
lj->args.append(buf_ptr(&lj->out_file));
|
lj->args.append(buf_ptr(&lj->out_file));
|
||||||
|
|
||||||
if (lj->link_in_crt) {
|
if (shared) {
|
||||||
if (shared) {
|
zig_panic("TODO");
|
||||||
zig_panic("TODO");
|
} else if (g->is_static) {
|
||||||
} else if (g->is_static) {
|
lj->args.append("-lcrt0.o");
|
||||||
lj->args.append("-lcrt0.o");
|
} else {
|
||||||
} else {
|
switch (platform.kind) {
|
||||||
switch (platform.kind) {
|
case MacOS:
|
||||||
case MacOS:
|
if (darwin_version_lt(&platform, 10, 5)) {
|
||||||
if (darwin_version_lt(&platform, 10, 5)) {
|
lj->args.append("-lcrt1.o");
|
||||||
lj->args.append("-lcrt1.o");
|
} else if (darwin_version_lt(&platform, 10, 6)) {
|
||||||
} else if (darwin_version_lt(&platform, 10, 6)) {
|
lj->args.append("-lcrt1.10.5.o");
|
||||||
lj->args.append("-lcrt1.10.5.o");
|
} else if (darwin_version_lt(&platform, 10, 8)) {
|
||||||
} else if (darwin_version_lt(&platform, 10, 8)) {
|
lj->args.append("-lcrt1.10.6.o");
|
||||||
lj->args.append("-lcrt1.10.6.o");
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case IPhoneOS:
|
||||||
case IPhoneOS:
|
if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
|
||||||
if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
|
// iOS does not need any crt1 files for arm64
|
||||||
// iOS does not need any crt1 files for arm64
|
} else if (darwin_version_lt(&platform, 3, 1)) {
|
||||||
} else if (darwin_version_lt(&platform, 3, 1)) {
|
lj->args.append("-lcrt1.o");
|
||||||
lj->args.append("-lcrt1.o");
|
} else if (darwin_version_lt(&platform, 6, 0)) {
|
||||||
} else if (darwin_version_lt(&platform, 6, 0)) {
|
lj->args.append("-lcrt1.3.1.o");
|
||||||
lj->args.append("-lcrt1.3.1.o");
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case IPhoneOSSimulator:
|
||||||
case IPhoneOSSimulator:
|
// no crt1.o needed
|
||||||
// no crt1.o needed
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,29 +618,26 @@ static void construct_linker_job_darwin(LinkJob *lj) {
|
|||||||
|
|
||||||
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
|
lj->args.append((const char *)buf_ptr(&lj->out_file_o));
|
||||||
|
|
||||||
if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
|
|
||||||
Buf *builtin_o_path = build_o(g, "builtin");
|
|
||||||
lj->args.append(buf_ptr(builtin_o_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < g->link_libs.length; i += 1) {
|
for (int i = 0; i < g->link_libs.length; i += 1) {
|
||||||
Buf *link_lib = g->link_libs.at(i);
|
Buf *link_lib = g->link_libs.at(i);
|
||||||
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
|
||||||
lj->args.append(buf_ptr(arg));
|
lj->args.append(buf_ptr(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g->link_libc) {
|
// on Darwin, libSystem has libc in it, but also you have to use it
|
||||||
lj->args.append("-lSystem");
|
// to make syscalls because the syscall numbers are not documented
|
||||||
|
// and change between versions.
|
||||||
|
// so we always link against libSystem
|
||||||
|
lj->args.append("-lSystem");
|
||||||
|
|
||||||
if (platform.kind == MacOS) {
|
if (platform.kind == MacOS) {
|
||||||
if (darwin_version_lt(&platform, 10, 5)) {
|
if (darwin_version_lt(&platform, 10, 5)) {
|
||||||
lj->args.append("-lgcc_s.10.4");
|
lj->args.append("-lgcc_s.10.4");
|
||||||
} else if (darwin_version_lt(&platform, 10, 6)) {
|
} else if (darwin_version_lt(&platform, 10, 6)) {
|
||||||
lj->args.append("-lgcc_s.10.5");
|
lj->args.append("-lgcc_s.10.5");
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zig_panic("TODO");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
zig_panic("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -499,6 +499,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
|
|||||||
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
|
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
|
||||||
ZigList<AstNode*> *directives, VisibMod visib_mod);
|
ZigList<AstNode*> *directives, VisibMod visib_mod);
|
||||||
static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index);
|
static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index);
|
||||||
|
static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool mandatory);
|
||||||
|
|
||||||
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
|
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
|
||||||
if (token->id == token_id) {
|
if (token->id == token_id) {
|
||||||
@ -517,33 +518,19 @@ static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Directive = "#" "Symbol" "(" Expression ")"
|
||||||
|
*/
|
||||||
static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {
|
static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {
|
||||||
Token *number_sign = &pc->tokens->at(*token_index);
|
Token *number_sign = ast_eat_token(pc, token_index, TokenIdNumberSign);
|
||||||
*token_index += 1;
|
|
||||||
ast_expect_token(pc, number_sign, TokenIdNumberSign);
|
|
||||||
|
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
|
AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
|
||||||
|
|
||||||
Token *name_symbol = &pc->tokens->at(*token_index);
|
Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
|
||||||
*token_index += 1;
|
|
||||||
ast_expect_token(pc, name_symbol, TokenIdSymbol);
|
|
||||||
|
|
||||||
ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
|
ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
|
||||||
|
|
||||||
Token *l_paren = &pc->tokens->at(*token_index);
|
node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true);
|
||||||
*token_index += 1;
|
|
||||||
ast_expect_token(pc, l_paren, TokenIdLParen);
|
|
||||||
|
|
||||||
Token *param_str = &pc->tokens->at(*token_index);
|
|
||||||
*token_index += 1;
|
|
||||||
ast_expect_token(pc, param_str, TokenIdStringLiteral);
|
|
||||||
|
|
||||||
parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr);
|
|
||||||
|
|
||||||
Token *r_paren = &pc->tokens->at(*token_index);
|
|
||||||
*token_index += 1;
|
|
||||||
ast_expect_token(pc, r_paren, TokenIdRParen);
|
|
||||||
|
|
||||||
normalize_parent_ptrs(node);
|
normalize_parent_ptrs(node);
|
||||||
return node;
|
return node;
|
||||||
@ -2741,7 +2728,7 @@ void normalize_parent_ptrs(AstNode *node) {
|
|||||||
set_list_fields(&node->data.block.statements);
|
set_list_fields(&node->data.block.statements);
|
||||||
break;
|
break;
|
||||||
case NodeTypeDirective:
|
case NodeTypeDirective:
|
||||||
// none
|
set_field(&node->data.directive.expr);
|
||||||
break;
|
break;
|
||||||
case NodeTypeReturnExpr:
|
case NodeTypeReturnExpr:
|
||||||
set_field(&node->data.return_expr.expr);
|
set_field(&node->data.return_expr.expr);
|
||||||
|
|||||||
@ -1,24 +1,28 @@
|
|||||||
import "syscall.zig";
|
import "syscall.zig";
|
||||||
|
|
||||||
// The compiler treats this file special by implicitly importing the function `main`
|
// The compiler treats this file special by implicitly importing the function `main`
|
||||||
// from the root source file.
|
// from the root source file as the symbol `zig_user_main`.
|
||||||
|
|
||||||
|
const want_start_symbol = switch(@compile_var("os")) {
|
||||||
|
linux => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
const want_main_symbol = !want_start_symbol;
|
||||||
|
|
||||||
var argc: isize = undefined;
|
var argc: isize = undefined;
|
||||||
var argv: &&u8 = undefined;
|
var argv: &&u8 = undefined;
|
||||||
var env: &&u8 = undefined;
|
|
||||||
|
|
||||||
#attribute("naked")
|
#attribute("naked")
|
||||||
|
#condition(want_start_symbol)
|
||||||
export fn _start() -> unreachable {
|
export fn _start() -> unreachable {
|
||||||
switch (@compile_var("arch")) {
|
switch (@compile_var("arch")) {
|
||||||
x86_64 => {
|
x86_64 => {
|
||||||
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
|
argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
|
||||||
argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
|
||||||
env = asm("lea 0x10(%%rsp,[argc],8), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
|
|
||||||
},
|
},
|
||||||
i386 => {
|
i386 => {
|
||||||
argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize));
|
argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize));
|
||||||
argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
|
argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
|
||||||
env = asm("lea 0x8(%%esp,%[argc],4), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
|
|
||||||
},
|
},
|
||||||
else => unreachable{},
|
else => unreachable{},
|
||||||
}
|
}
|
||||||
@ -39,6 +43,17 @@ fn call_main() -> unreachable {
|
|||||||
const ptr = argv[i];
|
const ptr = argv[i];
|
||||||
args[i] = ptr[0...strlen(ptr)];
|
args[i] = ptr[0...strlen(ptr)];
|
||||||
}
|
}
|
||||||
main(args) %% exit(1);
|
zig_user_main(args) %% exit(1);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#condition(want_main_symbol)
|
||||||
|
export fn main(argc: i32, argv: &&u8) -> i32 {
|
||||||
|
var args: [argc][]u8 = undefined;
|
||||||
|
for (args) |arg, i| {
|
||||||
|
const ptr = argv[i];
|
||||||
|
args[i] = ptr[0...strlen(ptr)];
|
||||||
|
}
|
||||||
|
zig_user_main(args) %% return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user