authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-12 15:51:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-12 15:51:12-07:00
logb8a1cb299eccce24410454d36ebc755dfd0293cd
tree8969d97b750abd41b10f23f0bc05a10f1d81c728
parent9bf9be993791833f88bfbf049875dce50b64cd45

avoid codegening functions never called from conditional compilation


3 files changed, 141 insertions(+), 135 deletions(-)

src/all_types.hpp+3
...@@ -1207,6 +1207,9 @@ struct BlockContext {...@@ -1207,6 +1207,9 @@ struct BlockContext {
12071207
1208 LLVMZigDIScope *di_scope;1208 LLVMZigDIScope *di_scope;
1209 Buf *c_import_buf;1209 Buf *c_import_buf;
1210
1211 // if this is true, then this code will not be generated
1212 bool codegen_excluded;
1210};1213};
12111214
12121215
src/analyze.cpp+136-133
...@@ -27,7 +27,8 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *...@@ -27,7 +27,8 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
27static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,27static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
28 TypeTableEntry *expected_type, AstNode *node);28 TypeTableEntry *expected_type, AstNode *node);
29static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);29static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
30static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn);30static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context,
31 FnTableEntry *fn);
31static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type);32static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type);
32static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,33static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
33 TypeTableEntry *expected_type, uint64_t x);34 TypeTableEntry *expected_type, uint64_t x);
...@@ -1990,6 +1991,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {...@@ -1990,6 +1991,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
1990 if (parent) {1991 if (parent) {
1991 context->parent_loop_node = parent->parent_loop_node;1992 context->parent_loop_node = parent->parent_loop_node;
1992 context->c_import_buf = parent->c_import_buf;1993 context->c_import_buf = parent->c_import_buf;
1994 context->codegen_excluded = parent->codegen_excluded;
1993 }1995 }
19941996
1995 if (node && node->type == NodeTypeFnDef) {1997 if (node && node->type == NodeTypeFnDef) {
...@@ -2271,7 +2273,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -2271,7 +2273,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
2271 auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(field_name);2273 auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(field_name);
2272 if (table_entry) {2274 if (table_entry) {
2273 node->data.field_access_expr.is_member_fn = true;2275 node->data.field_access_expr.is_member_fn = true;
2274 return resolve_expr_const_val_as_fn(g, node, table_entry->value);2276 return resolve_expr_const_val_as_fn(g, node, context, table_entry->value);
2275 } else {2277 } else {
2276 add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'",2278 add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'",
2277 buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));2279 buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
...@@ -2304,7 +2306,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i...@@ -2304,7 +2306,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
2304 } else if (child_type->id == TypeTableEntryIdStruct) {2306 } else if (child_type->id == TypeTableEntryIdStruct) {
2305 auto entry = child_type->data.structure.fn_table.maybe_get(field_name);2307 auto entry = child_type->data.structure.fn_table.maybe_get(field_name);
2306 if (entry) {2308 if (entry) {
2307 return resolve_expr_const_val_as_fn(g, node, entry->value);2309 return resolve_expr_const_val_as_fn(g, node, context, entry->value);
2308 } else {2310 } else {
2309 add_node_error(g, node,2311 add_node_error(g, node,
2310 buf_sprintf("struct '%s' has no function called '%s'",2312 buf_sprintf("struct '%s' has no function called '%s'",
...@@ -2421,8 +2423,12 @@ static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode...@@ -2421,8 +2423,12 @@ static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode
2421 return other_expr->type_entry;2423 return other_expr->type_entry;
2422}2424}
24232425
2424static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) {2426static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context,
2425 fn->ref_count += 1;2427 FnTableEntry *fn)
2428{
2429 if (!context->codegen_excluded) {
2430 fn->ref_count += 1;
2431 }
2426 Expr *expr = get_resolved_expr(node);2432 Expr *expr = get_resolved_expr(node);
2427 expr->const_val.ok = true;2433 expr->const_val.ok = true;
2428 expr->const_val.data.x_fn = fn;2434 expr->const_val.data.x_fn = fn;
...@@ -2604,7 +2610,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,...@@ -2604,7 +2610,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
2604 if (fn_table_entry) {2610 if (fn_table_entry) {
2605 assert(fn_table_entry->value->type_entry);2611 assert(fn_table_entry->value->type_entry);
2606 node->data.symbol_expr.fn_entry = fn_table_entry->value;2612 node->data.symbol_expr.fn_entry = fn_table_entry->value;
2607 return resolve_expr_const_val_as_fn(g, node, fn_table_entry->value);2613 return resolve_expr_const_val_as_fn(g, node, context, fn_table_entry->value);
2608 }2614 }
26092615
2610 add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));2616 add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
...@@ -4344,7 +4350,9 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,...@@ -4344,7 +4350,9 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,
43444350
4345 node->data.fn_call_expr.fn_entry = fn_table_entry;4351 node->data.fn_call_expr.fn_entry = fn_table_entry;
43464352
4347 fn_table_entry->ref_count += 1;4353 if (!context->codegen_excluded) {
4354 fn_table_entry->ref_count += 1;
4355 }
43484356
4349 return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type);4357 return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type);
43504358
...@@ -4650,6 +4658,13 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4650,6 +4658,13 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4650{4658{
4651 AstNode **expr_node = &node->data.switch_expr.expr;4659 AstNode **expr_node = &node->data.switch_expr.expr;
4652 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);4660 TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
4661 ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
4662 if (expr_val->ok && !expr_val->depends_on_compile_var) {
4663 add_node_error(g, first_executing_node(*expr_node),
4664 buf_sprintf("value is constant; unnecessary switch statement"));
4665 }
4666 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4667
46534668
4654 int prong_count = node->data.switch_expr.prongs.length;4669 int prong_count = node->data.switch_expr.prongs.length;
4655 AstNode **peer_nodes = allocate<AstNode*>(prong_count);4670 AstNode **peer_nodes = allocate<AstNode*>(prong_count);
...@@ -4662,113 +4677,132 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4662,113 +4677,132 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4662 add_node_error(g, first_executing_node(*expr_node),4677 add_node_error(g, first_executing_node(*expr_node),
4663 buf_sprintf("switch on unreachable expression not allowed"));4678 buf_sprintf("switch on unreachable expression not allowed"));
4664 return g->builtin_types.entry_invalid;4679 return g->builtin_types.entry_invalid;
4665 } else {4680 }
4666 int *field_use_counts = nullptr;
4667 if (expr_type->id == TypeTableEntryIdEnum) {
4668 field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
4669 }
46704681
4671 AstNode *else_prong = nullptr;
4672 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4673 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
46744682
4675 TypeTableEntry *var_type;4683 int *field_use_counts = nullptr;
4676 bool var_is_target_expr;4684 if (expr_type->id == TypeTableEntryIdEnum) {
4677 if (prong_node->data.switch_prong.items.length == 0) {4685 field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
4678 if (else_prong) {4686 }
4679 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));4687
4680 any_errors = true;4688 int const_chosen_prong_index = -1;
4681 } else {4689 AstNode *else_prong = nullptr;
4682 else_prong = prong_node;4690 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4683 }4691 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4684 var_type = expr_type;4692
4685 var_is_target_expr = true;4693 TypeTableEntry *var_type;
4694 bool var_is_target_expr;
4695 if (prong_node->data.switch_prong.items.length == 0) {
4696 if (else_prong) {
4697 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
4698 any_errors = true;
4686 } else {4699 } else {
4687 bool all_agree_on_var_type = true;4700 else_prong = prong_node;
4688 var_type = nullptr;4701 }
4702 var_type = expr_type;
4703 var_is_target_expr = true;
4704 if (const_chosen_prong_index == -1) {
4705 const_chosen_prong_index = prong_i;
4706 }
4707 } else {
4708 bool all_agree_on_var_type = true;
4709 var_type = nullptr;
46894710
4690 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {4711 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
4691 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);4712 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
4692 if (item_node->type == NodeTypeSwitchRange) {4713 if (item_node->type == NodeTypeSwitchRange) {
4693 zig_panic("TODO range in switch statement");4714 zig_panic("TODO range in switch statement");
4694 }4715 }
46954716
4696 if (expr_type->id == TypeTableEntryIdEnum) {4717 if (expr_type->id == TypeTableEntryIdEnum) {
4697 if (item_node->type == NodeTypeSymbol) {4718 if (item_node->type == NodeTypeSymbol) {
4698 Buf *field_name = &item_node->data.symbol_expr.symbol;4719 Buf *field_name = &item_node->data.symbol_expr.symbol;
4699 TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name);4720 TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name);
4700 if (type_enum_field) {4721 if (type_enum_field) {
4701 item_node->data.symbol_expr.enum_field = type_enum_field;4722 item_node->data.symbol_expr.enum_field = type_enum_field;
4702 if (!var_type) {4723 if (!var_type) {
4703 var_type = type_enum_field->type_entry;4724 var_type = type_enum_field->type_entry;
4704 }4725 }
4705 if (type_enum_field->type_entry != var_type) {4726 if (type_enum_field->type_entry != var_type) {
4706 all_agree_on_var_type = false;4727 all_agree_on_var_type = false;
4707 }4728 }
4708 uint32_t field_index = type_enum_field->value;4729 uint32_t field_index = type_enum_field->value;
4709 assert(field_use_counts);4730 assert(field_use_counts);
4710 field_use_counts[field_index] += 1;4731 field_use_counts[field_index] += 1;
4711 if (field_use_counts[field_index] > 1) {4732 if (field_use_counts[field_index] > 1) {
4712 add_node_error(g, item_node,
4713 buf_sprintf("duplicate switch value: '%s'",
4714 buf_ptr(type_enum_field->name)));
4715 any_errors = true;
4716 }
4717 } else {
4718 add_node_error(g, item_node,4733 add_node_error(g, item_node,
4719 buf_sprintf("enum '%s' has no field '%s'",4734 buf_sprintf("duplicate switch value: '%s'",
4720 buf_ptr(&expr_type->name), buf_ptr(field_name)));4735 buf_ptr(type_enum_field->name)));
4721 any_errors = true;4736 any_errors = true;
4722 }4737 }
4738 if (!any_errors && expr_val->ok) {
4739 if (expr_val->data.x_enum.tag == type_enum_field->value) {
4740 const_chosen_prong_index = prong_i;
4741 }
4742 }
4723 } else {4743 } else {
4724 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));4744 add_node_error(g, item_node,
4745 buf_sprintf("enum '%s' has no field '%s'",
4746 buf_ptr(&expr_type->name), buf_ptr(field_name)));
4725 any_errors = true;4747 any_errors = true;
4726 }4748 }
4727 } else {4749 } else {
4728 TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);4750 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
4729 if (item_type->id != TypeTableEntryIdInvalid) {4751 any_errors = true;
4730 ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;
4731 if (!const_val->ok) {
4732 add_node_error(g, item_node,
4733 buf_sprintf("unable to resolve constant expression"));
4734 any_errors = true;
4735 }
4736 }
4737 }4752 }
4738 }
4739 if (!var_type || !all_agree_on_var_type) {
4740 var_type = expr_type;
4741 var_is_target_expr = true;
4742 } else {4753 } else {
4743 var_is_target_expr = false;4754 if (!any_errors && expr_val->ok) {
4755 zig_panic("TODO determine if const exprs are equal");
4756 }
4757 TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
4758 if (item_type->id != TypeTableEntryIdInvalid) {
4759 ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val;
4760 if (!const_val->ok) {
4761 add_node_error(g, item_node,
4762 buf_sprintf("unable to resolve constant expression"));
4763 any_errors = true;
4764 }
4765 }
4744 }4766 }
4745 }4767 }
47464768 if (!var_type || !all_agree_on_var_type) {
4747 BlockContext *child_context = new_block_context(node, context);4769 var_type = expr_type;
4748 prong_node->data.switch_prong.block_context = child_context;4770 var_is_target_expr = true;
4749 AstNode *var_node = prong_node->data.switch_prong.var_symbol;4771 } else {
4750 if (var_node) {4772 var_is_target_expr = false;
4751 assert(var_node->type == NodeTypeSymbol);
4752 Buf *var_name = &var_node->data.symbol_expr.symbol;
4753 var_node->block_context = child_context;
4754 prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
4755 child_context, var_name, var_type, true);
4756 prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr;
4757 }4773 }
4774 }
47584775
4759 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,4776 BlockContext *child_context = new_block_context(node, context);
4760 prong_node->data.switch_prong.expr);4777 prong_node->data.switch_prong.block_context = child_context;
4761 peer_nodes[prong_i] = prong_node->data.switch_prong.expr;4778 AstNode *var_node = prong_node->data.switch_prong.var_symbol;
4779 if (var_node) {
4780 assert(var_node->type == NodeTypeSymbol);
4781 Buf *var_name = &var_node->data.symbol_expr.symbol;
4782 var_node->block_context = child_context;
4783 prong_node->data.switch_prong.var = add_local_var(g, var_node, import,
4784 child_context, var_name, var_type, true);
4785 prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr;
4762 }4786 }
4787 }
47634788
4764 if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {4789 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4765 for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) {4790 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4766 if (field_use_counts[i] == 0) {4791 BlockContext *child_context = prong_node->data.switch_prong.block_context;
4767 add_node_error(g, node,4792 child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i);
4768 buf_sprintf("enumeration value '%s' not handled in switch",4793
4769 buf_ptr(expr_type->data.enumeration.fields[i].name)));4794 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
4770 any_errors = true;4795 prong_node->data.switch_prong.expr);
4771 }4796 peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
4797 }
4798
4799 if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
4800 for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) {
4801 if (field_use_counts[i] == 0) {
4802 add_node_error(g, node,
4803 buf_sprintf("enumeration value '%s' not handled in switch",
4804 buf_ptr(expr_type->data.enumeration.fields[i].name)));
4805 any_errors = true;
4772 }4806 }
4773 }4807 }
4774 }4808 }
...@@ -4782,49 +4816,18 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4782,49 +4816,18 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4782 return g->builtin_types.entry_invalid;4816 return g->builtin_types.entry_invalid;
4783 }4817 }
47844818
4785 TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,4819 if (expr_val->ok) {
4786 peer_nodes, peer_types, prong_count);4820 assert(const_chosen_prong_index != -1);
4787
4788 if (resolved_type->id == TypeTableEntryIdInvalid) {
4789 return resolved_type;
4790 }
47914821
4792 ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;4822 *const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val;
4793 if (!expr_val->ok) {4823 const_val->ok = true;
4794 return resolved_type;4824 // the target expr depends on a compile var,
4795 }4825 // so the entire if statement does too
47964826 const_val->depends_on_compile_var = true;
4797 if (expr_val->ok && !expr_val->depends_on_compile_var) {
4798 add_node_error(g, first_executing_node(*expr_node),
4799 buf_sprintf("value is constant; unnecessary switch statement"));
4800 }4827 }
48014828
4802 if (!expr_val->ok) {
4803 return resolved_type;
4804 }
48054829
4806 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;4830 return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);
4807
4808 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4809 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4810 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
4811 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
4812 if (expr_type->id == TypeTableEntryIdEnum) {
4813 TypeEnumField *type_enum_field = item_node->data.symbol_expr.enum_field;
4814 if (expr_val->data.x_enum.tag == type_enum_field->value) {
4815 *const_val = get_resolved_expr(peer_nodes[prong_i])->const_val;
4816 const_val->ok = true;
4817 // the target expr depends on a compile var, so the entire if statement does too
4818 const_val->depends_on_compile_var = true;
4819 return resolved_type;
4820 }
4821 } else {
4822 zig_panic("TODO determine if const exprs are equal");
4823 }
4824 }
4825 }
4826
4827 zig_unreachable();
4828}4831}
48294832
4830static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,4833static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
test/run_tests.cpp+2-2
...@@ -1584,8 +1584,8 @@ fn f(Foo: i32) {...@@ -1584,8 +1584,8 @@ fn f(Foo: i32) {
1584 ".tmp_source.zig:6:5: error: variable shadows type 'Bar'");1584 ".tmp_source.zig:6:5: error: variable shadows type 'Bar'");
15851585
1586 add_compile_fail_case("multiple else prongs in a switch", R"SOURCE(1586 add_compile_fail_case("multiple else prongs in a switch", R"SOURCE(
1587fn f() {1587fn f(x: u32) {
1588 const value: bool = switch (u32(111)) {1588 const value: bool = switch (x) {
1589 1234 => false,1589 1234 => false,
1590 else => true,1590 else => true,
1591 else => true,1591 else => true,