Skip to content

Commit b2facc0

Browse files
committed
Merge pull request #94730 from dalexeev/gds-fix-while-locals-clearing
GDScript: Fix locals clearing after exiting `while` block
2 parents c331fb0 + 5350e1b commit b2facc0

File tree

3 files changed

+32
-7
lines changed

3 files changed

+32
-7
lines changed

modules/gdscript/gdscript_compiler.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,7 +1901,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
19011901
case GDScriptParser::Node::MATCH: {
19021902
const GDScriptParser::MatchNode *match = static_cast<const GDScriptParser::MatchNode *>(s);
19031903

1904-
codegen.start_block(); // Add an extra block, since the binding pattern and @special variables belong to the branch scope.
1904+
codegen.start_block(); // Add an extra block, since @special locals belong to the match scope.
19051905

19061906
// Evaluate the match expression.
19071907
GDScriptCodeGenerator::Address value = codegen.add_local("@match_value", _gdtype_from_datatype(match->test->get_datatype(), codegen.script));
@@ -1939,7 +1939,7 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
19391939

19401940
const GDScriptParser::MatchBranchNode *branch = match->branches[j];
19411941

1942-
codegen.start_block(); // Create an extra block around for binds.
1942+
codegen.start_block(); // Add an extra block, since binds belong to the match branch scope.
19431943

19441944
// Add locals in block before patterns, so temporaries don't use the stack address for binds.
19451945
List<GDScriptCodeGenerator::Address> branch_locals = _add_block_locals(codegen, branch->block);
@@ -1991,13 +1991,15 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
19911991

19921992
_clear_block_locals(codegen, branch_locals);
19931993

1994-
codegen.end_block(); // Get out of extra block.
1994+
codegen.end_block(); // Get out of extra block for binds.
19951995
}
19961996

19971997
// End all nested `if`s.
19981998
for (int j = 0; j < match->branches.size(); j++) {
19991999
gen->write_endif();
20002000
}
2001+
2002+
codegen.end_block(); // Get out of extra block for match's @special locals.
20012003
} break;
20022004
case GDScriptParser::Node::IF: {
20032005
const GDScriptParser::IfNode *if_n = static_cast<const GDScriptParser::IfNode *>(s);
@@ -2031,7 +2033,9 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
20312033
case GDScriptParser::Node::FOR: {
20322034
const GDScriptParser::ForNode *for_n = static_cast<const GDScriptParser::ForNode *>(s);
20332035

2034-
codegen.start_block(); // Add an extra block, since the iterator and @special variables belong to the loop scope.
2036+
// Add an extra block, since the iterator and @special locals belong to the loop scope.
2037+
// Also we use custom logic to clear block locals.
2038+
codegen.start_block();
20352039

20362040
GDScriptCodeGenerator::Address iterator = codegen.add_local(for_n->variable->name, _gdtype_from_datatype(for_n->variable->get_datatype(), codegen.script));
20372041

@@ -2064,11 +2068,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
20642068

20652069
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
20662070

2067-
codegen.end_block(); // Get out of extra block.
2071+
codegen.end_block(); // Get out of extra block for loop iterator, @special locals, and custom locals clearing.
20682072
} break;
20692073
case GDScriptParser::Node::WHILE: {
20702074
const GDScriptParser::WhileNode *while_n = static_cast<const GDScriptParser::WhileNode *>(s);
20712075

2076+
codegen.start_block(); // Add an extra block, since we use custom logic to clear block locals.
2077+
20722078
gen->start_while_condition();
20732079

20742080
GDScriptCodeGenerator::Address condition = _parse_expression(codegen, err, while_n->condition);
@@ -2095,6 +2101,8 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Sui
20952101
gen->write_endwhile();
20962102

20972103
_clear_block_locals(codegen, loop_locals); // Outside loop, after block - for `break` and normal exit.
2104+
2105+
codegen.end_block(); // Get out of extra block for custom locals clearing.
20982106
} break;
20992107
case GDScriptParser::Node::BREAK: {
21002108
gen->write_break();
Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
# GH-77666
2-
3-
func test():
2+
func test_exit_if():
43
var ref := RefCounted.new()
54
print(ref.get_reference_count())
65

76
if true:
87
var _temp := ref
98

109
print(ref.get_reference_count())
10+
11+
# GH-94654
12+
func test_exit_while():
13+
var slots_data := []
14+
15+
while true:
16+
@warning_ignore("confusable_local_declaration")
17+
var slot = 42
18+
slots_data.append(slot)
19+
break
20+
21+
var slot: int = slots_data[0]
22+
print(slot)
23+
24+
func test():
25+
test_exit_if()
26+
test_exit_while()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
GDTEST_OK
22
1
33
1
4+
42

0 commit comments

Comments
 (0)