authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-26 04:37:34-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-11-26 04:37:34-05:00
log24b65e41ee241c805e0eff8212ef49c5c39e4b8e
tree21a244d5af04f68a9eb4e88ea7ce025758f6fcab
parent697c768730ad4c095c376079adbb97854db84cb9

IR: add error for non static const on switch case range


5 files changed, 80 insertions(+), 38 deletions(-)

doc/langref.md+1-1
...@@ -531,7 +531,7 @@ Build scripts can set additional compile variables of any name and type....@@ -531,7 +531,7 @@ Build scripts can set additional compile variables of any name and type.
531The result of this function is a compile time constant that is marked as531The result of this function is a compile time constant that is marked as
532depending on a compile variable.532depending on a compile variable.
533533
534### @constEval(expression) -> @typeof(expression)534### @staticEval(expression) -> @typeOf(expression)
535535
536This function wraps an expression and generates a compile error if the536This function wraps an expression and generates a compile error if the
537expression is not known at compile time.537expression is not known at compile time.
src/all_types.hpp+8-1
...@@ -1146,7 +1146,7 @@ enum BuiltinFnId {...@@ -1146,7 +1146,7 @@ enum BuiltinFnId {
1146 BuiltinFnIdCUndef,1146 BuiltinFnIdCUndef,
1147 BuiltinFnIdCompileVar,1147 BuiltinFnIdCompileVar,
1148 BuiltinFnIdCompileErr,1148 BuiltinFnIdCompileErr,
1149 BuiltinFnIdConstEval,1149 BuiltinFnIdStaticEval,
1150 BuiltinFnIdCtz,1150 BuiltinFnIdCtz,
1151 BuiltinFnIdClz,1151 BuiltinFnIdClz,
1152 BuiltinFnIdImport,1152 BuiltinFnIdImport,
...@@ -1458,6 +1458,7 @@ enum IrInstructionId {...@@ -1458,6 +1458,7 @@ enum IrInstructionId {
1458 IrInstructionIdEnumTag,1458 IrInstructionIdEnumTag,
1459 IrInstructionIdClz,1459 IrInstructionIdClz,
1460 IrInstructionIdCtz,1460 IrInstructionIdCtz,
1461 IrInstructionIdStaticEval,
1461};1462};
14621463
1463struct IrInstruction {1464struct IrInstruction {
...@@ -1808,6 +1809,12 @@ struct IrInstructionEnumTag {...@@ -1808,6 +1809,12 @@ struct IrInstructionEnumTag {
1808 IrInstruction *value;1809 IrInstruction *value;
1809};1810};
18101811
1812struct IrInstructionStaticEval {
1813 IrInstruction base;
1814
1815 IrInstruction *value;
1816};
1817
1811enum LValPurpose {1818enum LValPurpose {
1812 LValPurposeNone,1819 LValPurposeNone,
1813 LValPurposeAssign,1820 LValPurposeAssign,
src/codegen.cpp+2-1
...@@ -1681,6 +1681,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -1681,6 +1681,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
1681 case IrInstructionIdCompileVar:1681 case IrInstructionIdCompileVar:
1682 case IrInstructionIdSizeOf:1682 case IrInstructionIdSizeOf:
1683 case IrInstructionIdSwitchTarget:1683 case IrInstructionIdSwitchTarget:
1684 case IrInstructionIdStaticEval:
1684 zig_unreachable();1685 zig_unreachable();
1685 case IrInstructionIdReturn:1686 case IrInstructionIdReturn:
1686 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);1687 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
...@@ -2968,7 +2969,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -2968,7 +2969,7 @@ static void define_builtin_fns(CodeGen *g) {
2968 create_builtin_fn_with_arg_count(g, BuiltinFnIdCDefine, "cDefine", 2);2969 create_builtin_fn_with_arg_count(g, BuiltinFnIdCDefine, "cDefine", 2);
2969 create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "cUndef", 1);2970 create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "cUndef", 1);
2970 create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileVar, "compileVar", 1);2971 create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileVar, "compileVar", 1);
2971 create_builtin_fn_with_arg_count(g, BuiltinFnIdConstEval, "constEval", 1);2972 create_builtin_fn_with_arg_count(g, BuiltinFnIdStaticEval, "staticEval", 1);
2972 create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 1);2973 create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 1);
2973 create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 1);2974 create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 1);
2974 create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);2975 create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
src/ir.cpp+60-35
...@@ -263,6 +263,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) {...@@ -263,6 +263,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) {
263 return IrInstructionIdEnumTag;263 return IrInstructionIdEnumTag;
264}264}
265265
266static constexpr IrInstructionId ir_instruction_id(IrInstructionStaticEval *) {
267 return IrInstructionIdStaticEval;
268}
269
266template<typename T>270template<typename T>
267static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {271static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
268 T *special_instruction = allocate<T>(1);272 T *special_instruction = allocate<T>(1);
...@@ -1074,6 +1078,15 @@ static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_...@@ -1074,6 +1078,15 @@ static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_
1074 return new_instruction;1078 return new_instruction;
1075}1079}
10761080
1081static IrInstruction *ir_build_static_eval(IrBuilder *irb, AstNode *source_node, IrInstruction *value) {
1082 IrInstructionStaticEval *instruction = ir_build_instruction<IrInstructionStaticEval>(irb, source_node);
1083 instruction->value = value;
1084
1085 ir_ref_instruction(value);
1086
1087 return &instruction->base;
1088}
1089
1077static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,1090static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
1078 bool gen_error_defers, bool gen_maybe_defers)1091 bool gen_error_defers, bool gen_maybe_defers)
1079{1092{
...@@ -1606,6 +1619,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {...@@ -1606,6 +1619,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
16061619
1607 return ir_build_clz(irb, node, arg0_value);1620 return ir_build_clz(irb, node, arg0_value);
1608 }1621 }
1622 case BuiltinFnIdStaticEval:
1623 {
1624 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
1625 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
1626 if (arg0_value == irb->codegen->invalid_instruction)
1627 return arg0_value;
1628
1629 return ir_build_static_eval(irb, node, arg0_value);
1630 }
1609 case BuiltinFnIdMemcpy:1631 case BuiltinFnIdMemcpy:
1610 case BuiltinFnIdMemset:1632 case BuiltinFnIdMemset:
1611 case BuiltinFnIdAlignof:1633 case BuiltinFnIdAlignof:
...@@ -1620,7 +1642,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {...@@ -1620,7 +1642,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
1620 case BuiltinFnIdCDefine:1642 case BuiltinFnIdCDefine:
1621 case BuiltinFnIdCUndef:1643 case BuiltinFnIdCUndef:
1622 case BuiltinFnIdCompileErr:1644 case BuiltinFnIdCompileErr:
1623 case BuiltinFnIdConstEval:
1624 case BuiltinFnIdImport:1645 case BuiltinFnIdImport:
1625 case BuiltinFnIdCImport:1646 case BuiltinFnIdCImport:
1626 case BuiltinFnIdErrName:1647 case BuiltinFnIdErrName:
...@@ -2285,14 +2306,18 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {...@@ -2285,14 +2306,18 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
2285 IrInstruction *start_value = ir_gen_node(irb, start_node, node->block_context);2306 IrInstruction *start_value = ir_gen_node(irb, start_node, node->block_context);
2286 if (start_value == irb->codegen->invalid_instruction)2307 if (start_value == irb->codegen->invalid_instruction)
2287 return irb->codegen->invalid_instruction;2308 return irb->codegen->invalid_instruction;
2309
2288 IrInstruction *end_value = ir_gen_node(irb, end_node, node->block_context);2310 IrInstruction *end_value = ir_gen_node(irb, end_node, node->block_context);
2289 if (end_value == irb->codegen->invalid_instruction)2311 if (end_value == irb->codegen->invalid_instruction)
2290 return irb->codegen->invalid_instruction;2312 return irb->codegen->invalid_instruction;
22912313
2314 IrInstruction *start_value_const = ir_build_static_eval(irb, start_node, start_value);
2315 IrInstruction *end_value_const = ir_build_static_eval(irb, start_node, end_value);
2316
2292 IrInstruction *lower_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpGreaterOrEq,2317 IrInstruction *lower_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpGreaterOrEq,
2293 target_value, start_value);2318 target_value, start_value_const);
2294 IrInstruction *upper_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpLessOrEq,2319 IrInstruction *upper_range_ok = ir_build_bin_op(irb, item_node, IrBinOpCmpLessOrEq,
2295 target_value, end_value);2320 target_value, end_value_const);
2296 IrInstruction *both_ok = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd,2321 IrInstruction *both_ok = ir_build_bin_op(irb, item_node, IrBinOpBoolAnd,
2297 lower_range_ok, upper_range_ok);2322 lower_range_ok, upper_range_ok);
2298 if (ok_bit) {2323 if (ok_bit) {
...@@ -3291,16 +3316,21 @@ static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructio...@@ -3291,16 +3316,21 @@ static TypeTableEntry *ir_analyze_instruction_const(IrAnalyze *ira, IrInstructio
3291}3316}
32923317
3293static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {3318static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) {
3294 IrInstruction *op1 = bin_op_instruction->op1;3319 IrInstruction *op1 = bin_op_instruction->op1->other;
3295 IrInstruction *op2 = bin_op_instruction->op2;3320 if (op1->type_entry->id == TypeTableEntryIdInvalid)
3321 return ira->codegen->builtin_types.entry_invalid;
3322
3323 IrInstruction *op2 = bin_op_instruction->op2->other;
3324 if (op2->type_entry->id == TypeTableEntryIdInvalid)
3325 return ira->codegen->builtin_types.entry_invalid;
32963326
3297 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;3327 TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
32983328
3299 IrInstruction *casted_op1 = ir_get_casted_value(ira, op1->other, bool_type);3329 IrInstruction *casted_op1 = ir_get_casted_value(ira, op1, bool_type);
3300 if (casted_op1 == ira->codegen->invalid_instruction)3330 if (casted_op1 == ira->codegen->invalid_instruction)
3301 return ira->codegen->builtin_types.entry_invalid;3331 return ira->codegen->builtin_types.entry_invalid;
33023332
3303 IrInstruction *casted_op2 = ir_get_casted_value(ira, op2->other, bool_type);3333 IrInstruction *casted_op2 = ir_get_casted_value(ira, op2, bool_type);
3304 if (casted_op2 == ira->codegen->invalid_instruction)3334 if (casted_op2 == ira->codegen->invalid_instruction)
3305 return ira->codegen->builtin_types.entry_invalid;3335 return ira->codegen->builtin_types.entry_invalid;
33063336
...@@ -3310,8 +3340,8 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp...@@ -3310,8 +3340,8 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
3310 bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;3340 bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var;
3311 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var);3341 ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var);
33123342
3313 assert(op1->type_entry->id == TypeTableEntryIdBool);3343 assert(casted_op1->type_entry->id == TypeTableEntryIdBool);
3314 assert(op2->type_entry->id == TypeTableEntryIdBool);3344 assert(casted_op2->type_entry->id == TypeTableEntryIdBool);
3315 if (bin_op_instruction->op_id == IrBinOpBoolOr) {3345 if (bin_op_instruction->op_id == IrBinOpBoolOr) {
3316 out_val->data.x_bool = op1_val->data.x_bool || op2_val->data.x_bool;3346 out_val->data.x_bool = op1_val->data.x_bool || op2_val->data.x_bool;
3317 } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) {3347 } else if (bin_op_instruction->op_id == IrBinOpBoolAnd) {
...@@ -3322,7 +3352,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp...@@ -3322,7 +3352,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp
3322 return bool_type;3352 return bool_type;
3323 }3353 }
33243354
3325 ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, bin_op_instruction->op_id, op1->other, op2->other);3355 ir_build_bin_op_from(&ira->new_irb, &bin_op_instruction->base, bin_op_instruction->op_id, casted_op1, casted_op2);
3326 return bool_type;3356 return bool_type;
3327}3357}
33283358
...@@ -5238,11 +5268,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,...@@ -5238,11 +5268,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
5238 if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)5268 if (casted_new_value->type_entry->id == TypeTableEntryIdInvalid)
5239 continue;5269 continue;
52405270
5241 if (casted_new_value->static_value.special != ConstValSpecialStatic) {5271 if (!ir_resolve_const(ira, casted_new_value))
5242 add_node_error(ira->codegen, casted_new_value->source_node,
5243 buf_sprintf("unable to evaluate constant expression"));
5244 continue;5272 continue;
5245 }
52465273
5247 new_case->value = casted_new_value;5274 new_case->value = casted_new_value;
5248 }5275 }
...@@ -5340,6 +5367,22 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira,...@@ -5340,6 +5367,22 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira,
5340 zig_panic("TODO ir_analyze_instruction_enum_tag");5367 zig_panic("TODO ir_analyze_instruction_enum_tag");
5341}5368}
53425369
5370static TypeTableEntry *ir_analyze_instruction_static_eval(IrAnalyze *ira,
5371 IrInstructionStaticEval *static_eval_instruction)
5372{
5373 IrInstruction *value = static_eval_instruction->value->other;
5374 if (value->type_entry->id == TypeTableEntryIdInvalid)
5375 return ira->codegen->builtin_types.entry_invalid;
5376
5377 ConstExprValue *val = ir_resolve_const(ira, value);
5378 if (!val)
5379 return ira->codegen->builtin_types.entry_invalid;
5380
5381 ConstExprValue *out_val = ir_build_const_from(ira, &static_eval_instruction->base, val->depends_on_compile_var);
5382 *out_val = *val;
5383 return value->type_entry;
5384}
5385
5343static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {5386static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
5344 switch (instruction->id) {5387 switch (instruction->id) {
5345 case IrInstructionIdInvalid:5388 case IrInstructionIdInvalid:
...@@ -5414,6 +5457,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -5414,6 +5457,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
5414 return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);5457 return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
5415 case IrInstructionIdEnumTag:5458 case IrInstructionIdEnumTag:
5416 return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction);5459 return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction);
5460 case IrInstructionIdStaticEval:
5461 return ir_analyze_instruction_static_eval(ira, (IrInstructionStaticEval *)instruction);
5417 case IrInstructionIdCast:5462 case IrInstructionIdCast:
5418 case IrInstructionIdContainerInitList:5463 case IrInstructionIdContainerInitList:
5419 case IrInstructionIdContainerInitFields:5464 case IrInstructionIdContainerInitFields:
...@@ -5533,6 +5578,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -5533,6 +5578,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
5533 case IrInstructionIdSwitchVar:5578 case IrInstructionIdSwitchVar:
5534 case IrInstructionIdSwitchTarget:5579 case IrInstructionIdSwitchTarget:
5535 case IrInstructionIdEnumTag:5580 case IrInstructionIdEnumTag:
5581 case IrInstructionIdStaticEval:
5536 return false;5582 return false;
5537 case IrInstructionIdAsm:5583 case IrInstructionIdAsm:
5538 {5584 {
...@@ -6243,26 +6289,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {...@@ -6243,26 +6289,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
6243// case BuiltinFnIdCUndef:6289// case BuiltinFnIdCUndef:
6244// zig_panic("TODO");6290// zig_panic("TODO");
6245//6291//
6246// case BuiltinFnIdConstEval:
6247// {
6248// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;
6249// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_type, *expr_node);
6250// if (resolved_type->id == TypeTableEntryIdInvalid) {
6251// return resolved_type;
6252// }
6253//
6254// ConstExprValue *const_expr_val = &get_resolved_expr(*expr_node)->const_val;
6255//
6256// if (!const_expr_val->ok) {
6257// add_node_error(g, *expr_node, buf_sprintf("unable to evaluate constant expression"));
6258// return g->builtin_types.entry_invalid;
6259// }
6260//
6261// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
6262// *const_val = *const_expr_val;
6263//
6264// return resolved_type;
6265// }
6266// case BuiltinFnIdImport:6292// case BuiltinFnIdImport:
6267// return analyze_import(g, import, context, node);6293// return analyze_import(g, import, context, node);
6268// case BuiltinFnIdCImport:6294// case BuiltinFnIdCImport:
...@@ -8553,7 +8579,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no...@@ -8553,7 +8579,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
8553// case BuiltinFnIdMinValue:8579// case BuiltinFnIdMinValue:
8554// case BuiltinFnIdMaxValue:8580// case BuiltinFnIdMaxValue:
8555// case BuiltinFnIdMemberCount:8581// case BuiltinFnIdMemberCount:
8556// case BuiltinFnIdConstEval:
8557// case BuiltinFnIdEmbedFile:8582// case BuiltinFnIdEmbedFile:
8558// // caught by constant expression eval codegen8583// // caught by constant expression eval codegen
8559// zig_unreachable();8584// zig_unreachable();
src/ir_print.cpp+9
...@@ -569,6 +569,12 @@ static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {...@@ -569,6 +569,12 @@ static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {
569 ir_print_other_instruction(irp, instruction->value);569 ir_print_other_instruction(irp, instruction->value);
570}570}
571571
572static void ir_print_static_eval(IrPrint *irp, IrInstructionStaticEval *instruction) {
573 fprintf(irp->f, "@staticEval(");
574 ir_print_other_instruction(irp, instruction->value);
575 fprintf(irp->f, ")");
576}
577
572static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {578static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
573 ir_print_prefix(irp, instruction);579 ir_print_prefix(irp, instruction);
574 switch (instruction->id) {580 switch (instruction->id) {
...@@ -691,6 +697,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -691,6 +697,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
691 case IrInstructionIdEnumTag:697 case IrInstructionIdEnumTag:
692 ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);698 ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);
693 break;699 break;
700 case IrInstructionIdStaticEval:
701 ir_print_static_eval(irp, (IrInstructionStaticEval *)instruction);
702 break;
694 }703 }
695 fprintf(irp->f, "\n");704 fprintf(irp->f, "\n");
696}705}