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 {
12071207
12081208 LLVMZigDIScope *di_scope;
12091209 Buf *c_import_buf;
1210
1211 // if this is true, then this code will not be generated
1212 bool codegen_excluded;
12101213};
12111214
12121215
src/analyze.cpp+136-133
......@@ -27,7 +27,8 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
2727static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2828 TypeTableEntry *expected_type, AstNode *node);
2929static 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);
3132static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type);
3233static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
3334 TypeTableEntry *expected_type, uint64_t x);
......@@ -1990,6 +1991,7 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
19901991 if (parent) {
19911992 context->parent_loop_node = parent->parent_loop_node;
19921993 context->c_import_buf = parent->c_import_buf;
1994 context->codegen_excluded = parent->codegen_excluded;
19931995 }
19941996
19951997 if (node && node->type == NodeTypeFnDef) {
......@@ -2271,7 +2273,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
22712273 auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(field_name);
22722274 if (table_entry) {
22732275 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);
22752277 } else {
22762278 add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'",
22772279 buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
......@@ -2304,7 +2306,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
23042306 } else if (child_type->id == TypeTableEntryIdStruct) {
23052307 auto entry = child_type->data.structure.fn_table.maybe_get(field_name);
23062308 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);
23082310 } else {
23092311 add_node_error(g, node,
23102312 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
24212423 return other_expr->type_entry;
24222424}
24232425
2424static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) {
2425 fn->ref_count += 1;
2426static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context,
2427 FnTableEntry *fn)
2428{
2429 if (!context->codegen_excluded) {
2430 fn->ref_count += 1;
2431 }
24262432 Expr *expr = get_resolved_expr(node);
24272433 expr->const_val.ok = true;
24282434 expr->const_val.data.x_fn = fn;
......@@ -2604,7 +2610,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
26042610 if (fn_table_entry) {
26052611 assert(fn_table_entry->value->type_entry);
26062612 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);
26082614 }
26092615
26102616 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,
43444350
43454351 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
43494357 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,
46504658{
46514659 AstNode **expr_node = &node->data.switch_expr.expr;
46524660 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
46544669 int prong_count = node->data.switch_expr.prongs.length;
46554670 AstNode **peer_nodes = allocate<AstNode*>(prong_count);
......@@ -4662,113 +4677,132 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
46624677 add_node_error(g, first_executing_node(*expr_node),
46634678 buf_sprintf("switch on unreachable expression not allowed"));
46644679 return g->builtin_types.entry_invalid;
4665 } else {
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 }
4680 }
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;
4676 bool var_is_target_expr;
4677 if (prong_node->data.switch_prong.items.length == 0) {
4678 if (else_prong) {
4679 add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression"));
4680 any_errors = true;
4681 } else {
4682 else_prong = prong_node;
4683 }
4684 var_type = expr_type;
4685 var_is_target_expr = true;
4683 int *field_use_counts = nullptr;
4684 if (expr_type->id == TypeTableEntryIdEnum) {
4685 field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
4686 }
4687
4688 int const_chosen_prong_index = -1;
4689 AstNode *else_prong = nullptr;
4690 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4691 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4692
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;
46864699 } else {
4687 bool all_agree_on_var_type = true;
4688 var_type = nullptr;
4700 else_prong = prong_node;
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) {
4691 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
4692 if (item_node->type == NodeTypeSwitchRange) {
4693 zig_panic("TODO range in switch statement");
4694 }
4711 for (int item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) {
4712 AstNode *item_node = prong_node->data.switch_prong.items.at(item_i);
4713 if (item_node->type == NodeTypeSwitchRange) {
4714 zig_panic("TODO range in switch statement");
4715 }
46954716
4696 if (expr_type->id == TypeTableEntryIdEnum) {
4697 if (item_node->type == NodeTypeSymbol) {
4698 Buf *field_name = &item_node->data.symbol_expr.symbol;
4699 TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name);
4700 if (type_enum_field) {
4701 item_node->data.symbol_expr.enum_field = type_enum_field;
4702 if (!var_type) {
4703 var_type = type_enum_field->type_entry;
4704 }
4705 if (type_enum_field->type_entry != var_type) {
4706 all_agree_on_var_type = false;
4707 }
4708 uint32_t field_index = type_enum_field->value;
4709 assert(field_use_counts);
4710 field_use_counts[field_index] += 1;
4711 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 {
4717 if (expr_type->id == TypeTableEntryIdEnum) {
4718 if (item_node->type == NodeTypeSymbol) {
4719 Buf *field_name = &item_node->data.symbol_expr.symbol;
4720 TypeEnumField *type_enum_field = get_enum_field(expr_type, field_name);
4721 if (type_enum_field) {
4722 item_node->data.symbol_expr.enum_field = type_enum_field;
4723 if (!var_type) {
4724 var_type = type_enum_field->type_entry;
4725 }
4726 if (type_enum_field->type_entry != var_type) {
4727 all_agree_on_var_type = false;
4728 }
4729 uint32_t field_index = type_enum_field->value;
4730 assert(field_use_counts);
4731 field_use_counts[field_index] += 1;
4732 if (field_use_counts[field_index] > 1) {
47184733 add_node_error(g, item_node,
4719 buf_sprintf("enum '%s' has no field '%s'",
4720 buf_ptr(&expr_type->name), buf_ptr(field_name)));
4734 buf_sprintf("duplicate switch value: '%s'",
4735 buf_ptr(type_enum_field->name)));
47214736 any_errors = true;
47224737 }
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 }
47234743 } 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)));
47254747 any_errors = true;
47264748 }
47274749 } else {
4728 TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node);
4729 if (item_type->id != TypeTableEntryIdInvalid) {
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 }
4750 add_node_error(g, item_node, buf_sprintf("expected enum tag name"));
4751 any_errors = true;
47374752 }
4738 }
4739 if (!var_type || !all_agree_on_var_type) {
4740 var_type = expr_type;
4741 var_is_target_expr = true;
47424753 } 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 }
47444766 }
47454767 }
4746
4747 BlockContext *child_context = new_block_context(node, context);
4748 prong_node->data.switch_prong.block_context = child_context;
4749 AstNode *var_node = prong_node->data.switch_prong.var_symbol;
4750 if (var_node) {
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;
4768 if (!var_type || !all_agree_on_var_type) {
4769 var_type = expr_type;
4770 var_is_target_expr = true;
4771 } else {
4772 var_is_target_expr = false;
47574773 }
4774 }
47584775
4759 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
4760 prong_node->data.switch_prong.expr);
4761 peer_nodes[prong_i] = prong_node->data.switch_prong.expr;
4776 BlockContext *child_context = new_block_context(node, context);
4777 prong_node->data.switch_prong.block_context = child_context;
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;
47624786 }
4787 }
47634788
4764 if (expr_type->id == TypeTableEntryIdEnum && !else_prong) {
4765 for (uint32_t i = 0; i < expr_type->data.enumeration.field_count; i += 1) {
4766 if (field_use_counts[i] == 0) {
4767 add_node_error(g, node,
4768 buf_sprintf("enumeration value '%s' not handled in switch",
4769 buf_ptr(expr_type->data.enumeration.fields[i].name)));
4770 any_errors = true;
4771 }
4789 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4790 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4791 BlockContext *child_context = prong_node->data.switch_prong.block_context;
4792 child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i);
4793
4794 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
4795 prong_node->data.switch_prong.expr);
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;
47724806 }
47734807 }
47744808 }
......@@ -4782,49 +4816,18 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
47824816 return g->builtin_types.entry_invalid;
47834817 }
47844818
4785 TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
4786 peer_nodes, peer_types, prong_count);
4787
4788 if (resolved_type->id == TypeTableEntryIdInvalid) {
4789 return resolved_type;
4790 }
4819 if (expr_val->ok) {
4820 assert(const_chosen_prong_index != -1);
47914821
4792 ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val;
4793 if (!expr_val->ok) {
4794 return resolved_type;
4795 }
4796
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"));
4822 *const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val;
4823 const_val->ok = true;
4824 // the target expr depends on a compile var,
4825 // so the entire if statement does too
4826 const_val->depends_on_compile_var = true;
48004827 }
48014828
4802 if (!expr_val->ok) {
4803 return resolved_type;
4804 }
48054829
4806 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
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();
4830 return resolve_peer_type_compatibility(g, import, context, node, peer_nodes, peer_types, prong_count);
48284831}
48294832
48304833static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
test/run_tests.cpp+2-2
......@@ -1584,8 +1584,8 @@ fn f(Foo: i32) {
15841584 ".tmp_source.zig:6:5: error: variable shadows type 'Bar'");
15851585
15861586 add_compile_fail_case("multiple else prongs in a switch", R"SOURCE(
1587fn f() {
1588 const value: bool = switch (u32(111)) {
1587fn f(x: u32) {
1588 const value: bool = switch (x) {
15891589 1234 => false,
15901590 else => true,
15911591 else => true,