@@ -1630,6 +1630,8 @@ twithshadowcand = class
16301630 lifetime_name : TIDString;
16311631 lifetime_filepos : tfileposinfo;
16321632 lifetime_tcsym : tstaticvarsym;
1633+ lifetime_name_suffix : string[16 ];
1634+ withblockst : tblocksymtable;
16331635
16341636 procedure pushobjchild (withdef,obj:tobjectdef);
16351637 var
@@ -1669,11 +1671,20 @@ twithshadowcand = class
16691671 lifetime_autofree := false;
16701672 lifetime_init := nil ;
16711673 lifetime_tcsym := nil ;
1674+ withblockst := nil ;
16721675 hdef := nil ;
16731676 if (m_autofree in current_settings.modeswitches) and
16741677 (current_scanner.token in [_VAR,_AUTOFREE]) then
16751678 begin
16761679 lifetime_filepos := current_filepos;
1680+ { scope the inline var (and any hidden tcsym) to the with-body
1681+ via a dedicated block symtable, so the same name can appear
1682+ in a later sibling `with var NAME` in the same routine }
1683+ if assigned(current_procinfo) then
1684+ begin
1685+ withblockst := tblocksymtable.create(symtablestack.top);
1686+ symtablestack.push(withblockst);
1687+ end ;
16771688 if current_scanner.token = _VAR then
16781689 begin
16791690 { Form C: with var NAME := [autofree] EXPR do BODY
@@ -1682,6 +1693,11 @@ twithshadowcand = class
16821693 if current_scanner.token <> _ID then
16831694 begin
16841695 consume(_ID); { trigger expected-identifier error }
1696+ if assigned(withblockst) then
1697+ begin
1698+ symtablestack.pop(withblockst);
1699+ withblockst.free;
1700+ end ;
16851701 result := cerrornode.create;
16861702 exit;
16871703 end ;
@@ -1711,8 +1727,13 @@ twithshadowcand = class
17111727 else if (current_scanner.token = _LKLAMMER) and
17121728 ((hdef.typ = arraydef) or (hdef.typ = recorddef)) then
17131729 begin
1730+ { suffix with line number so multiple sibling
1731+ `with var NAME : TYPE := (...)` in the same
1732+ routine don't share an asm label }
1733+ system.str(lifetime_filepos.line, lifetime_name_suffix);
17141734 lifetime_tcsym := cstaticvarsym.create(
1715- ' $with_tc_' + lifetime_name, vs_const, hdef, []);
1735+ ' $with_tc_' + lifetime_name + ' _' + lifetime_name_suffix,
1736+ vs_const, hdef, []);
17161737 include(lifetime_tcsym.symoptions, sp_internal);
17171738 symtablestack.top.insertsym(lifetime_tcsym);
17181739 read_typed_const(current_asmdata.asmlists[al_typedconsts],
@@ -1758,6 +1779,11 @@ ((hdef.typ = arraydef) or (hdef.typ = recorddef
17581779 if not assigned(hdef) or (hdef = generrordef) then
17591780 begin
17601781 if assigned(lifetime_init) then lifetime_init.free;
1782+ if assigned(withblockst) then
1783+ begin
1784+ symtablestack.pop(withblockst);
1785+ withblockst.free;
1786+ end ;
17611787 result := cerrornode.create;
17621788 exit;
17631789 end ;
@@ -1766,18 +1792,23 @@ ((hdef.typ = arraydef) or (hdef.typ = recorddef
17661792 begin
17671793 Message(parser_e_autofree_requires_class);
17681794 if assigned(lifetime_init) then lifetime_init.free;
1795+ if assigned(withblockst) then
1796+ begin
1797+ symtablestack.pop(withblockst);
1798+ withblockst.free;
1799+ end ;
17691800 result := cerrornode.create;
17701801 exit;
17711802 end ;
1772- { create the holder variable in the enclosing routine scope
1773- (skip past any with-symtables already on the stack from
1774- earlier multi- with entries). }
1775- if assigned(current_procinfo) and
1776- assigned(current_procinfo.procdef.localst ) then
1803+ { create the holder variable scoped to the with-body. With
1804+ `withblockst` pushed, symtablestack.top is the block symtable
1805+ that gets popped at the end of ` with`, so a sibling `with var
1806+ NAME` can reuse the same name. }
1807+ if assigned(withblockst ) then
17771808 begin
17781809 lifetime_var := clocalvarsym.create(lifetime_name, vs_value, hdef, []);
17791810 lifetime_var.register_sym;
1780- current_procinfo.procdef.localst .insertsym(lifetime_var);
1811+ symtablestack.top .insertsym(lifetime_var);
17811812 end
17821813 else
17831814 begin
@@ -1904,7 +1935,7 @@ ((hdef.typ = arraydef) or (hdef.typ = recorddef
19041935 (
19051936 (tloadnode(hp).symtable=current_procinfo.procdef.localst) or
19061937 (tloadnode(hp).symtable=current_procinfo.procdef.parast) or
1907- (tloadnode(hp).symtable.symtabletype in [staticsymtable,globalsymtable])
1938+ (tloadnode(hp).symtable.symtabletype in [staticsymtable,globalsymtable,blocksymtable ])
19081939 ) and
19091940 { MacPas objects are mapped to classes, and the MacPas compilers
19101941 interpret with-statements with MacPas objects the same way
@@ -2097,6 +2128,19 @@ ((p.resultdef.typ=recorddef) or
20972128 withsymtablelist.free;
20982129 withsymtablelist := nil ;
20992130
2131+ { pop the with-var block symtable (if any) and hand it to the
2132+ procdef so its locals get stack space allocated; the wrapping
2133+ newblock keeps a reference for debug-info scoping }
2134+ if assigned(withblockst) then
2135+ begin
2136+ symtablestack.pop(withblockst);
2137+ if not assigned(current_procinfo.procdef.blocklocalsymtables) then
2138+ current_procinfo.procdef.blocklocalsymtables := tfpobjectlist.create(true);
2139+ current_procinfo.procdef.blocklocalsymtables.add(withblockst);
2140+ if assigned(newblock) then
2141+ tblocknode(newblock).blocksymtable := withblockst;
2142+ end ;
2143+
21002144 { FPC Unleashed: scoped-with -- rewrite any defers the body
21012145 registered (e.g. `with X do defer Foo;` or stray defers in
21022146 a begin..end body that wasn't already a defer-scope) so they
0 commit comments