Skip to content

Commit b43670b

Browse files
committed
Add support for nested ifs/else-ifs
This change brings support for nested `if` or `else if`. It make possible to process the following code: ```cpp main: (args) = { p : *int; a := 1; b := 2; c := 3; d := 4; if args.cout == 3 { p = a&; } else if p = b& { if args.cout == 2 { p = c&; } else { if b > 0 { p = a&; } else { p = d&; } } } else { p = c&; } std::cout << p* << std::endl; } ``` And gets generated: ```cpp auto main(int const argc_, char const* const* const argv_) -> int{ auto args = cpp2::make_args(argc_, argv_); cpp2::deferred_init<int*> p; auto a {1}; auto b {2}; auto c {3}; auto d {4}; if (args.cout==3) { p.construct(&a); } else if (p.construct(&b)) { if (args.cout==2) { p.construct(&c); }else { if (cpp2::cmp_greater(std::move(b),0)) { p.construct(&a); } else { p.construct(&d); } } }else { p.construct(&c); } std::cout << *cpp2::assert_not_null(std::move(p.value())) << std::endl; } ``` Assignements are properly marked as `DEFINITE INITIALIZATION` ``` 0 | function main 1 | scope 2 | var p *** UNINITIALIZED 2 | /var 2 | var a 2 | /var 2 | var b 2 | /var 2 | var c 2 | /var 2 | var d 2 | /var 2 | selection 3 | if branch 4 | *** (10,9) DEFINITE INITIALIZATION OF p 4 | *** use of a 4 | /if branch 3 | *** (11,15) DEFINITE INITIALIZATION OF p 3 | *** use of b 3 | if else branch 4 | selection 5 | if branch 6 | *** (13,13) DEFINITE INITIALIZATION OF p 6 | *** (13,17) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of c 6 | /if branch 5 | else branch 6 | selection 7 | *** (15,16) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of b 7 | if branch 8 | *** (16,17) DEFINITE INITIALIZATION OF p 8 | *** (16,21) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of a 8 | /if branch 7 | else branch 8 | *** (19,17) DEFINITE INITIALIZATION OF p 8 | *** (19,21) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of d 8 | /else branch 7 | /selection 6 | /else branch 5 | /selection 4 | /if else branch 3 | else branch 4 | *** (23,9) DEFINITE INITIALIZATION OF p 4 | *** (23,13) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of c 4 | /else branch 3 | /selection 2 | *** (26,18) DEFINITE LAST POTENTIALLY MOVING USE OF *** use of p 2 | /scope 1 | /function ```
1 parent 3f64d1b commit b43670b

File tree

1 file changed

+22
-22
lines changed

1 file changed

+22
-22
lines changed

source/sema.h

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,8 @@ class sema
683683
branch(int s, bool r) : start{s}, result{r} { }
684684
};
685685
std::vector<branch> branches;
686+
bool in_branch = false;
687+
int initialized_in_condition_pos = -1;
686688

687689
stack_entry(int p) : pos{p} { }
688690

@@ -695,7 +697,6 @@ class sema
695697
}
696698
};
697699
std::vector<stack_entry> selection_stack;
698-
bool in_branch = false;
699700

700701
for (
701702
;
@@ -755,33 +756,23 @@ class sema
755756

756757
// Else if we're inside a selection statement but still in the condition
757758
// portion (there are no branches entered yet)
758-
else if (std::ssize(selection_stack.back().branches) == 0) {
759-
// If this is a top-level selection statement, handle it the same as
760-
// if we weren't an a selection statement
761-
if (std::ssize(selection_stack) == 1) {
759+
else if (!selection_stack.back().in_branch) {
762760
if (sym.assignment_to) {
763761
definite_initializations.push_back( sym.identifier );
762+
selection_stack.back().initialized_in_condition_pos = pos;
764763
}
765764
else {
766765
errors.emplace_back(
767766
sym.identifier->position(),
768767
"local variable " + name
769768
+ " is used in a condition before it was initialized");
770769
}
771-
return sym.assignment_to;
772-
}
773-
// Else we can skip the rest of this selection statement, and record
774-
// this as the result of the next outer selection statement's current branch
775-
else {
776-
selection_stack.pop_back();
777-
assert (std::ssize(selection_stack.back().branches) > 0);
778-
selection_stack.back().branches.back().result = sym.assignment_to;
779770

780-
int this_depth = symbols[pos].depth;
781-
while (symbols[pos + 1].depth >= this_depth) {
771+
int branch_depth = symbols[selection_stack.back().pos].depth;
772+
while (symbols[pos + 1].depth > branch_depth) {
782773
++pos;
783774
}
784-
}
775+
--pos; // to handle end of if/else branch
785776
}
786777

787778
// Else we're in a selection branch and can skip the rest of this branch
@@ -797,7 +788,7 @@ class sema
797788
+ " is used in a branch before it was initialized");
798789
}
799790

800-
if (!in_branch) {
791+
if (!selection_stack.back().in_branch) {
801792
return sym.assignment_to;
802793
}
803794

@@ -806,7 +797,11 @@ class sema
806797
// The depth of this branch should always be the depth of
807798
// the current selection statement + 1
808799
int branch_depth = symbols[selection_stack.back().pos].depth + 1;
809-
while (symbols[pos + 1].depth > branch_depth && symbols[pos + 1].start) {
800+
while (symbols[pos + 1].depth > branch_depth + 1
801+
|| (
802+
symbols[pos + 1].depth == branch_depth + 1 && symbols[pos + 1].start
803+
)
804+
) {
810805
++pos;
811806
}
812807
}
@@ -831,6 +826,7 @@ class sema
831826

832827
auto true_branches = std::string{};
833828
auto false_branches = std::string{};
829+
834830
for (auto const& b : selection_stack.back().branches)
835831
{
836832
// If this is not an implicit 'else' branch (i.e., if lineno > 0)
@@ -845,9 +841,13 @@ class sema
845841
}
846842
}
847843

844+
if (auto init_pos = selection_stack.back().initialized_in_condition_pos; init_pos != -1) {
845+
true_branches += "\n branch condition starting at line "
846+
+ std::to_string(symbols[init_pos].position().lineno);
847+
}
848+
848849
// If none of the branches was true
849-
if (true_branches.length() == 0)
850-
{
850+
if (true_branches.length() == 0) {
851851
selection_stack.pop_back();
852852
// Nothing else to do, just continue
853853
}
@@ -912,11 +912,11 @@ class sema
912912
)
913913
{
914914
selection_stack.back().branches.emplace_back( pos, false );
915-
in_branch = true;
915+
selection_stack.back().in_branch = true;
916916
}
917917

918918
if ( !sym.start ) {
919-
in_branch = false;
919+
selection_stack.back().in_branch = false;
920920
}
921921
}
922922
}

0 commit comments

Comments
 (0)