From 7e18d092e8226d15726dcfd3f2227c4b7c26ea8c Mon Sep 17 00:00:00 2001 From: Ivan Bondarev Date: Sun, 21 Nov 2021 12:43:55 +0100 Subject: [PATCH] bug fix #2568 --- TestSuite/errors/err0442.pas | 9 +++++ TestSuite/errors/err0443.pas | 9 +++++ TestSuite/errors/err0444.pas | 8 +++++ TestSuite/errors/err0445.pas | 16 +++++++++ TestSuite/errors/err0446.pas | 16 +++++++++ TestSuite/errors/err0447.pas | 20 +++++++++++ TestSuite/exceptions5.pas | 15 ++++++++ .../Closure/CapturedVariablesTreeBuilder.cs | 8 ++--- .../SyntaxTreeVisitorNodes/ForLoop.cs | 4 +-- .../SyntaxTreeVisitorNodes/Foreach.cs | 4 +-- .../TreeConversion/compilation_context.cs | 31 ++++++++++++++++ .../TreeConversion/syntax_tree_visitor.cs | 36 +++++++++++++++---- bin/Lng/Eng/SemanticErrors_ib.dat | 1 + bin/Lng/Rus/SemanticErrors_ib.dat | 1 + bin/Lng/Ukr/SemanticErrors_ib.dat | 1 + 15 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 TestSuite/errors/err0442.pas create mode 100644 TestSuite/errors/err0443.pas create mode 100644 TestSuite/errors/err0444.pas create mode 100644 TestSuite/errors/err0445.pas create mode 100644 TestSuite/errors/err0446.pas create mode 100644 TestSuite/errors/err0447.pas create mode 100644 TestSuite/exceptions5.pas diff --git a/TestSuite/errors/err0442.pas b/TestSuite/errors/err0442.pas new file mode 100644 index 000000000..96b3a1aba --- /dev/null +++ b/TestSuite/errors/err0442.pas @@ -0,0 +1,9 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + for var i := 1 to 10 do + try + + finally + break; + end; +end. \ No newline at end of file diff --git a/TestSuite/errors/err0443.pas b/TestSuite/errors/err0443.pas new file mode 100644 index 000000000..05749bc65 --- /dev/null +++ b/TestSuite/errors/err0443.pas @@ -0,0 +1,9 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + for var i := 1 to 10 do + try + + finally + continue; + end; +end. \ No newline at end of file diff --git a/TestSuite/errors/err0444.pas b/TestSuite/errors/err0444.pas new file mode 100644 index 000000000..660469e67 --- /dev/null +++ b/TestSuite/errors/err0444.pas @@ -0,0 +1,8 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + try + + finally + exit; + end; +end. \ No newline at end of file diff --git a/TestSuite/errors/err0445.pas b/TestSuite/errors/err0445.pas new file mode 100644 index 000000000..e844e6535 --- /dev/null +++ b/TestSuite/errors/err0445.pas @@ -0,0 +1,16 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + var k := 0; + for var i := 1 to 3 do + try + + finally + for var j := 1 to 10 do + begin + k := j; + exit; + end; + + end; + assert(k = 1); +end. \ No newline at end of file diff --git a/TestSuite/errors/err0446.pas b/TestSuite/errors/err0446.pas new file mode 100644 index 000000000..f1c44f7c1 --- /dev/null +++ b/TestSuite/errors/err0446.pas @@ -0,0 +1,16 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + var k := 0; + for var i := 1 to 3 do + try + + finally + for var j := 1 to 10 do + begin + k := j; + continue; + end; + break; + end; + assert(k = 1); +end. \ No newline at end of file diff --git a/TestSuite/errors/err0447.pas b/TestSuite/errors/err0447.pas new file mode 100644 index 000000000..5c65c99ac --- /dev/null +++ b/TestSuite/errors/err0447.pas @@ -0,0 +1,20 @@ +//!Использование exit, break и continue в блоке finally недопустимо +begin + var k := 0; + for var i := 1 to 3 do + try + + finally + for var j := 1 to 10 do + begin + try + k := j; + continue; + finally + break; + end; + end; + + end; + assert(k = 1); +end. \ No newline at end of file diff --git a/TestSuite/exceptions5.pas b/TestSuite/exceptions5.pas new file mode 100644 index 000000000..b8397e860 --- /dev/null +++ b/TestSuite/exceptions5.pas @@ -0,0 +1,15 @@ +begin + var k := 0; + for var i := 1 to 3 do + try + + finally + for var j := 1 to 10 do + begin + k := j; + break; + end; + + end; + assert(k = 1); +end. \ No newline at end of file diff --git a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs index 8cdbacbad..387377c4e 100644 --- a/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs +++ b/TreeConverter/LambdaExpressions/Closure/CapturedVariablesTreeBuilder.cs @@ -649,7 +649,7 @@ namespace TreeConverter.LambdaExpressions.Closure _visitor.convertion_data_and_alghoritms.check_convert_type_with_inheritance(vdn.type, elemType, _visitor.get_location(_foreach_stmt.identifier)); var fn = new foreach_node(vdn, inWhat, null, _visitor.get_location(_foreach_stmt)); - _visitor.context.cycle_stack.push(fn); + _visitor.context.enter_in_cycle(fn); _visitor.context.loop_var_stack.Push(vdn); ProcessNode(_foreach_stmt.in_what); @@ -664,7 +664,7 @@ namespace TreeConverter.LambdaExpressions.Closure _visitor.context.loop_var_stack.Pop(); _visitor.convertion_data_and_alghoritms.statement_list_stack.pop(); - _visitor.context.cycle_stack.pop(); + _visitor.context.leave_cycle(); _currentTreeNode = _currentTreeNode.ParentNode; } @@ -727,7 +727,7 @@ namespace TreeConverter.LambdaExpressions.Closure { fn.bool_cycle = true; } - _visitor.context.cycle_stack.push(fn); + _visitor.context.enter_in_cycle(fn); _visitor.context.loop_var_stack.Push(vdn); nodesToProcess.Add(_for_node.initial_value); @@ -746,7 +746,7 @@ namespace TreeConverter.LambdaExpressions.Closure } ProcessNode(_for_node.statements); - _visitor.context.cycle_stack.pop(); + _visitor.context.leave_cycle(); _visitor.context.loop_var_stack.Pop(); _visitor.convertion_data_and_alghoritms.statement_list_stack.pop(); diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/ForLoop.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/ForLoop.cs index 34ce77f99..a03cde181 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/ForLoop.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/ForLoop.cs @@ -156,7 +156,7 @@ namespace PascalABCCompiler.TreeConverter TreeRealization.for_node forNode = new TreeRealization.for_node(null, sn_while, sn_init_while, sn_inc, null, get_location(_for_node)); if (vdn.type == SystemLibrary.SystemLibrary.bool_type) forNode.bool_cycle = true; - context.cycle_stack.push(forNode); + context.enter_in_cycle(forNode); context.loop_var_stack.Push(vdn); statements_list slst = new statements_list(get_location(_for_node.statements)); convertion_data_and_alghoritms.statement_list_stack_push(slst); @@ -172,7 +172,7 @@ namespace PascalABCCompiler.TreeConverter forNode.body = slst; } - context.cycle_stack.pop(); + context.leave_cycle(); context.loop_var_stack.Pop(); head_stmts = convertion_data_and_alghoritms.statement_list_stack.pop(); head_stmts.statements.AddElement(forNode); diff --git a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs index 78506773f..1e1864201 100644 --- a/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs +++ b/TreeConverter/TreeConversion/SyntaxTreeVisitorNodes/Foreach.cs @@ -46,13 +46,13 @@ namespace PascalABCCompiler.TreeConverter foreach_node foreachNode = new foreach_node(foreachVariable, foreachCollection, null, get_location(_foreach_stmt)); - context.cycle_stack.push(foreachNode); + context.enter_in_cycle(foreachNode); context.loop_var_stack.Push(foreachVariable); context.enter_code_block_with_bind(); statement_node body = convert_strong(_foreach_stmt.stmt); context.leave_code_block(); context.loop_var_stack.Pop(); - context.cycle_stack.pop(); + context.leave_cycle(); sl = convertion_data_and_alghoritms.statement_list_stack.pop(); diff --git a/TreeConverter/TreeConversion/compilation_context.cs b/TreeConverter/TreeConversion/compilation_context.cs index 5c405db2d..6736ae2f1 100644 --- a/TreeConverter/TreeConversion/compilation_context.cs +++ b/TreeConverter/TreeConversion/compilation_context.cs @@ -3958,6 +3958,37 @@ namespace PascalABCCompiler.TreeConverter _block_stack.Push(new code_block(null)); } + int finally_blocks_depth = 0; + bool disable_finally_control_break_check = false; + + public void enter_finally_block() + { + finally_blocks_depth++; + disable_finally_control_break_check = false; + } + + public void leave_finally_block() + { + finally_blocks_depth--; + } + + public bool in_finally_block(bool ignore_disable_finally_control_break_check = false) + { + return (!disable_finally_control_break_check || ignore_disable_finally_control_break_check) && finally_blocks_depth > 0; + } + + public void enter_in_cycle(statement_node stmt) + { + cycle_stack.push(stmt); + disable_finally_control_break_check = true; + } + + public void leave_cycle() + { + cycle_stack.pop(); + disable_finally_control_break_check = false; + } + //Убирает блок со стека public void leave_code_block() { diff --git a/TreeConverter/TreeConversion/syntax_tree_visitor.cs b/TreeConverter/TreeConversion/syntax_tree_visitor.cs index 1b86ef785..21fc973f6 100644 --- a/TreeConverter/TreeConversion/syntax_tree_visitor.cs +++ b/TreeConverter/TreeConversion/syntax_tree_visitor.cs @@ -1766,6 +1766,10 @@ namespace PascalABCCompiler.TreeConverter { AddError(new BreakStatementWithoutComprehensiveCycle(call_location)); } + if (context.in_finally_block()) + { + AddError(call_location, "EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK"); + } statement_node sn = context.cycle_stack.top(); switch (sn.semantic_node_type) { @@ -1803,6 +1807,10 @@ namespace PascalABCCompiler.TreeConverter { AddError(new ContinueStatementWithoutComprehensiveCycle(call_location)); } + if (context.in_finally_block()) + { + AddError(call_location, "EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK"); + } statement_node sn = context.cycle_stack.top(); switch (sn.semantic_node_type) { @@ -1836,6 +1844,10 @@ namespace PascalABCCompiler.TreeConverter { return null; } + if (context.in_finally_block(true)) + { + AddError(call_location, "EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK"); + } if (!TreeConverter.SemanticRules.EnableExitProcedure) AddError(new TreeConverter.UndefinedNameReference(TreeConverter.compiler_string_consts.exit_procedure_name, call_location)); return new exit_procedure(call_location); @@ -1932,7 +1944,9 @@ namespace PascalABCCompiler.TreeConverter statements_list stm = new statements_list(null); SyntaxTree.try_handler_finally try_hndlr_finally = _try_stmt.handler as SyntaxTree.try_handler_finally; context.enter_code_block_without_bind(); + context.enter_finally_block(); statement_node finally_stmt = convert_strong(try_hndlr_finally.stmt_list); + context.leave_finally_block(); context.leave_code_block(); stm.statements.AddElement(finally_stmt); @@ -1956,7 +1970,15 @@ namespace PascalABCCompiler.TreeConverter if (try_handler_finally != null) { context.enter_code_block_without_bind(); - finally_st = convert_strong(try_handler_finally.stmt_list); + context.enter_finally_block(); + try + { + finally_st = convert_strong(try_handler_finally.stmt_list); + } + finally + { + context.leave_finally_block(); + } context.leave_code_block(); } try_block tb = new try_block(try_statements, finally_st, efl, loc); @@ -15811,7 +15833,7 @@ namespace PascalABCCompiler.TreeConverter } while_node wn = new while_node(expr, get_location(_while_node)); - context.cycle_stack.push(wn); + context.enter_in_cycle(wn); statements_list sl = new statements_list(get_location(_while_node.statements)); convertion_data_and_alghoritms.statement_list_stack_push(sl); @@ -15828,14 +15850,14 @@ namespace PascalABCCompiler.TreeConverter } wn.body = st; - context.cycle_stack.pop(); + context.leave_cycle(); return_value(wn); } public override void visit(SyntaxTree.repeat_node _repeat_node) { repeat_node rep = new repeat_node(get_location(_repeat_node)); - context.cycle_stack.push(rep); + context.enter_in_cycle(rep); statements_list sl = new statements_list(get_location(_repeat_node.statements)); convertion_data_and_alghoritms.statement_list_stack_push(sl); @@ -15861,7 +15883,7 @@ namespace PascalABCCompiler.TreeConverter try_convert_typed_expression_to_function_call(ref expr, true); rep.condition = expr; } - context.cycle_stack.pop(); + context.leave_cycle(); return_value(rep); } @@ -20005,7 +20027,7 @@ namespace PascalABCCompiler.TreeConverter CheckToEmbeddedStatementCannotBeADeclaration(node.stmt); for_node fn = new for_node(sn_init, sn_cond, null, sn_next, null, get_location(node)); - context.cycle_stack.push(fn); + context.enter_in_cycle(fn); statements_list slst = new statements_list(get_location(node.stmt)); convertion_data_and_alghoritms.statement_list_stack_push(slst); @@ -20021,7 +20043,7 @@ namespace PascalABCCompiler.TreeConverter fn.body = slst; } - context.cycle_stack.pop(); + context.leave_cycle(); head_stmts = convertion_data_and_alghoritms.statement_list_stack.pop(); head_stmts.statements.AddElement(fn); diff --git a/bin/Lng/Eng/SemanticErrors_ib.dat b/bin/Lng/Eng/SemanticErrors_ib.dat index 2b28bafbc..70e76ef95 100644 --- a/bin/Lng/Eng/SemanticErrors_ib.dat +++ b/bin/Lng/Eng/SemanticErrors_ib.dat @@ -175,6 +175,7 @@ AMBIGUOUS_DELEGATES=Ambiguous delegates detected EXPECTED_INTERFACE=Interface expected EXPECTED_PROPERTY=Property expected NON_PUBLIC_RECORD_CONSTRUCTORS_NOT_ALLOWED=Records can not have non-public default constructor +EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK=exit, break and continue are not allowed in finally %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Unit expected, library found ASSEMBLY_{0}_READING_ERROR=Error by reading assembly '{0}' diff --git a/bin/Lng/Rus/SemanticErrors_ib.dat b/bin/Lng/Rus/SemanticErrors_ib.dat index 9f5d6a5da..b8322f99a 100644 --- a/bin/Lng/Rus/SemanticErrors_ib.dat +++ b/bin/Lng/Rus/SemanticErrors_ib.dat @@ -170,6 +170,7 @@ AMBIGUOUS_DELEGATES=Невозможно выбрать конкретный д EXPECTED_INTERFACE=Ожидалось имя интерфейса EXPECTED_PROPERTY=Ожидалось свойство NON_PUBLIC_RECORD_CONSTRUCTORS_NOT_ALLOWED=Записи могут иметь только публичный конструктор по умолчанию +EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK=Использование exit, break и continue в блоке finally недопустимо %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Ожидался модуль, а встречена библиотека ASSEMBLY_{0}_READING_ERROR=Ошибка при чтении сборки '{0}' diff --git a/bin/Lng/Ukr/SemanticErrors_ib.dat b/bin/Lng/Ukr/SemanticErrors_ib.dat index eb78532a9..ee529de10 100644 --- a/bin/Lng/Ukr/SemanticErrors_ib.dat +++ b/bin/Lng/Ukr/SemanticErrors_ib.dat @@ -167,6 +167,7 @@ AMBIGUOUS_DELEGATES=Невозможно выбрать конкретный д EXPECTED_INTERFACE=Ожидалось имя интерфейса EXPECTED_PROPERTY=Ожидалось свойство NON_PUBLIC_RECORD_CONSTRUCTORS_NOT_ALLOWED=Записи могут иметь только публичный конструктор по умолчанию +EXIT_BREAK_CONTINUE_IN_FINALLY_BLOCK=Использование exit, break и continue в блоке finally недопустимо %PREFIX%=COMPILATIONERROR_ UNIT_MODULE_EXPECTED_LIBRARY_FOUND=Очікувався модуль, а зустріли бібліотеку ASSEMBLY_{0}_READING_ERROR=Помилка при читанні збірки '{0}'