@@ -88,6 +88,7 @@ struct identifier_sym {
88
88
enum kind { use, using_declaration, deactivation } kind_ = use;
89
89
bool standalone_assignment_to = false ;
90
90
bool is_captured = false ;
91
+ bool is_after_dot = false ;
91
92
bool safe_to_move = true ;
92
93
int safe_to_move_context = 0 ;
93
94
token const * identifier = {};
@@ -97,10 +98,12 @@ struct identifier_sym {
97
98
token const * id,
98
99
kind k = use,
99
100
bool mv = true ,
100
- int mvc = 0
101
+ int mvc = 0 ,
102
+ bool after_dot = false
101
103
)
102
104
: kind_{k}
103
105
, standalone_assignment_to{a}
106
+ , is_after_dot{after_dot}
104
107
, safe_to_move{mv}
105
108
, safe_to_move_context{mvc}
106
109
, identifier{id}
@@ -731,7 +734,8 @@ class sema
731
734
find_definite_last_uses (
732
735
decl->identifier ,
733
736
sympos,
734
- decl->parameter ? std::optional{decl->parameter ->pass } : std::optional<passing_style>{}
737
+ decl->parameter ? std::optional{decl->parameter ->pass } : std::optional<passing_style>{},
738
+ decl->parameter
735
739
);
736
740
}
737
741
}
@@ -746,7 +750,8 @@ class sema
746
750
auto find_definite_last_uses (
747
751
token const * id,
748
752
int pos,
749
- std::optional<passing_style> pass
753
+ std::optional<passing_style> pass,
754
+ bool is_parameter
750
755
) const
751
756
-> void
752
757
{
@@ -883,12 +888,47 @@ class sema
883
888
};
884
889
885
890
// Scan forward to the end of this scope
891
+ auto found_end_of_our_initialization = false ;
886
892
for (auto start_depth = symbols[pos].depth ;
887
893
i < std::ssize (symbols)
888
894
&& symbols[i].depth >= start_depth;
889
895
++i
890
896
)
891
897
{
898
+ // While we're here, if this is a non-parameter local, check for
899
+ // any uses before the end of the initializer
900
+ if (
901
+ !is_parameter
902
+ && !found_end_of_our_initialization
903
+ )
904
+ {
905
+ if (symbols[i].depth == start_depth)
906
+ {
907
+ if (auto decl = std::get_if<symbol::active::declaration>(&symbols[i].sym );
908
+ decl
909
+ && decl->declaration ->is_object ()
910
+ && decl->declaration ->has_name (*id)
911
+ && !decl->start
912
+ )
913
+ {
914
+ found_end_of_our_initialization = true ;
915
+ }
916
+ }
917
+
918
+ if (auto sym = std::get_if<symbol::active::identifier>(&symbols[i].sym );
919
+ sym
920
+ && !sym->is_after_dot
921
+ && is_a_use (sym)
922
+ )
923
+ {
924
+ assert (sym->identifier );
925
+ errors.emplace_back (
926
+ sym->identifier ->position (),
927
+ " local variable " + sym->identifier ->to_string ()
928
+ + " cannot be used in its own initializer" );
929
+ }
930
+ }
931
+
892
932
if (
893
933
skip_function_expression ()
894
934
|| skip_hidden_name (true )
@@ -1565,9 +1605,9 @@ class sema
1565
1605
if (n.identifier && *n.identifier ->identifier == " this" )
1566
1606
{
1567
1607
if (
1568
- n.is_template_parameter
1608
+ n.is_template_parameter ()
1569
1609
|| (
1570
- !n.is_parameter
1610
+ !n.is_parameter ()
1571
1611
&& !n.parent_is_type ()
1572
1612
)
1573
1613
)
@@ -2430,12 +2470,19 @@ class sema
2430
2470
// or it's a 'copy' parameter (but to be a use it must be after
2431
2471
// the declaration, not the token in the decl's name itself)
2432
2472
// including an implicit 'this' access of a member name
2433
- auto push_use = [&](token const * u) {
2434
- this ->push_use ( identifier_sym ( false , u, {}, !inside_next_expression, safe_to_move_context ) );
2473
+ auto push_use = [&](token const * u, bool is_dot_access = false ) {
2474
+ this ->push_use ( identifier_sym (
2475
+ false ,
2476
+ u,
2477
+ {},
2478
+ !inside_next_expression,
2479
+ safe_to_move_context,
2480
+ is_dot_access
2481
+ ) );
2435
2482
};
2436
2483
if (accessed_member_for_ufcs) {
2437
2484
if (t == " (" ) {
2438
- push_use (accessed_member_for_ufcs);
2485
+ push_use (accessed_member_for_ufcs, true );
2439
2486
}
2440
2487
accessed_member_for_ufcs = nullptr ;
2441
2488
}
0 commit comments