Skip to content

Commit d043380

Browse files
committed
Add multi-variable initialization ({$modeswitch multivarinit})
var a, b, c: integer = 42; Static vars use token record/replay so each gets its own typed constant data. Local vars share a single `defaultconstsym`. Enabled by default in unleashed mode.
1 parent 0110bc5 commit d043380

5 files changed

Lines changed: 70 additions & 13 deletions

File tree

compiler/globals.pas

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ interface
6868
m_property,m_default_inline,m_except,m_multiline_strings];
6969
unleashedmodeswitches = objfpcmodeswitches+[m_default_ansistring,m_underscoreisseparator,m_duplicate_names,
7070
m_advanced_records,m_array_operators,m_anonymous_functions,m_function_references,
71-
m_statement_expressions,m_array_equality,m_inline_var,m_multiline_strings];
71+
m_statement_expressions,m_array_equality,m_inline_var,m_multiline_strings,
72+
m_multi_var_init];
7273
tpmodeswitches =
7374
[m_tp7,m_tp_procvar,m_duplicate_names];
7475
{$ifdef gpc_mode}

compiler/globtype.pas

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,8 @@ ttargetswitchinfo = record
561561
m_statement_expressions, { enables expressions using statements like if, case, try }
562562
m_array_equality, { enables equality operator in addition to ArrayOperators modeswitch }
563563
m_no_rtti, { hides RTTI ASCII text }
564-
m_inline_var { allow inline variable declarations inside statement blocks }
564+
m_inline_var, { allow inline variable declarations inside statement blocks }
565+
m_multi_var_init { allow initializing multiple variables in one declaration }
565566
);
566567
tmodeswitches = set of tmodeswitch;
567568

@@ -773,7 +774,8 @@ ttargetswitchinfo = record
773774
'STATEMENTEXPRESSIONS',
774775
'ARRAYEQUALITY',
775776
'NORTTI',
776-
'INLINEVARS'
777+
'INLINEVARS',
778+
'MULTIVARINIT'
777779
);
778780

779781

compiler/pdecvar.pas

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,9 +1135,13 @@ implementation
11351135
vs : tabstractnormalvarsym;
11361136
tcsym : tstaticvarsym;
11371137
templist : tasmlist;
1138+
i : longint;
1139+
tokenbuf : tdynamicarray;
1140+
already_recording : boolean;
11381141
begin
11391142
vs:=tabstractnormalvarsym(sc[0]);
1140-
if sc.count>1 then
1143+
if (sc.count>1) and
1144+
not(m_multi_var_init in current_settings.modeswitches) then
11411145
Message(parser_e_initialized_only_one_var);
11421146
if vo_is_thread_var in vs.varoptions then
11431147
Message(parser_e_initialized_not_for_threadvar);
@@ -1156,7 +1160,11 @@ implementation
11561160
generation for LLVM) }
11571161
if not parse_generic then
11581162
begin
1159-
vs.defaultconstsym:=tcsym;
1163+
for i:=0 to sc.count-1 do
1164+
begin
1165+
tabstractnormalvarsym(sc[i]).defaultconstsym:=tcsym;
1166+
tabstractnormalvarsym(sc[i]).varstate:=vs_initialised;
1167+
end;
11601168
current_asmdata.asmlists[al_typedconsts].concatlist(templist);
11611169
end;
11621170
templist.free;
@@ -1165,12 +1173,33 @@ implementation
11651173
staticvarsym :
11661174
begin
11671175
maybe_guarantee_record_typesym(vs.vardef,vs.vardef.owner);
1168-
read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(vs),false);
1176+
if sc.count<=1 then
1177+
read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(vs),false)
1178+
else
1179+
begin
1180+
{ record tokens so we can replay them for each variable }
1181+
already_recording:=current_scanner.is_recording_tokens;
1182+
tokenbuf:=tdynamicarray.create(256);
1183+
if not already_recording then
1184+
current_scanner.startrecordtokens(tokenbuf);
1185+
read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(vs),false);
1186+
if not already_recording then
1187+
current_scanner.stoprecordtokens;
1188+
for i:=1 to sc.count-1 do
1189+
begin
1190+
maybe_guarantee_record_typesym(tabstractnormalvarsym(sc[i]).vardef,tabstractnormalvarsym(sc[i]).vardef.owner);
1191+
tokenbuf.seek(0);
1192+
current_scanner.startreplaytokens(tokenbuf,false);
1193+
read_typed_const(current_asmdata.asmlists[al_typedconsts],tstaticvarsym(sc[i]),false);
1194+
end;
1195+
tokenbuf.free;
1196+
end;
11691197
end;
11701198
else
11711199
internalerror(200611051);
11721200
end;
1173-
vs.varstate:=vs_initialised;
1201+
for i:=0 to sc.count-1 do
1202+
tabstractnormalvarsym(sc[i]).varstate:=vs_initialised;
11741203
end;
11751204

11761205
{$ifdef gpc_mode}

compiler/pstatmnt.pas

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,6 +1813,8 @@ ((p.resultdef.typ=recorddef) or
18131813
i : longint;
18141814
sc : TFPObjectList;
18151815
old_block_type : tblock_type;
1816+
statements : tstatementnode;
1817+
tempnode : ttempcreatenode;
18161818
begin
18171819
result := nil;
18181820
consume(_VAR);
@@ -1867,14 +1869,36 @@ ((p.resultdef.typ=recorddef) or
18671869
if try_to_consume(_ASSIGNMENT) then
18681870
begin
18691871
{ Only one variable may be initialised at a time. }
1870-
if sc.count > 1 then
1872+
if (sc.count > 1) and
1873+
not(m_multi_var_init in current_settings.modeswitches) then
18711874
Message(parser_e_initialized_only_one_var);
18721875
block_type := old_block_type;
18731876
initexpr := expr(true);
1874-
tabstractnormalvarsym(sc[0]).varstate := vs_initialised;
1875-
result := cassignmentnode.create(
1876-
cloadnode.create(tsym(sc[0]), tsym(sc[0]).owner),
1877-
initexpr);
1877+
if sc.count = 1 then
1878+
begin
1879+
tabstractnormalvarsym(sc[0]).varstate := vs_initialised;
1880+
result := cassignmentnode.create(
1881+
cloadnode.create(tsym(sc[0]), tsym(sc[0]).owner),
1882+
initexpr);
1883+
end
1884+
else
1885+
begin
1886+
{ multi-var: temp := expr; a := temp; b := temp; }
1887+
do_typecheckpass(initexpr);
1888+
result := internalstatements(statements);
1889+
tempnode := ctempcreatenode.create(hdef, hdef.size, tt_persistent, true);
1890+
addstatement(statements, tempnode);
1891+
addstatement(statements, cassignmentnode.create(
1892+
ctemprefnode.create(tempnode), initexpr));
1893+
for i := 0 to sc.count - 1 do
1894+
begin
1895+
tabstractnormalvarsym(sc[i]).varstate := vs_initialised;
1896+
addstatement(statements, cassignmentnode.create(
1897+
cloadnode.create(tsym(sc[i]), tsym(sc[i]).owner),
1898+
ctemprefnode.create(tempnode)));
1899+
end;
1900+
addstatement(statements, ctempdeletenode.create(tempnode));
1901+
end;
18781902
end
18791903
else
18801904
result := cnothingnode.create;

compiler/utils/ppuutils/ppudump.pp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,7 +2497,8 @@ (* tsettings = record
24972497
'm_statement_expressions', { enables expressions using statements like if, case, try }
24982498
'm_array_equality', { enables equality operator in addition to ArrayOperators modeswitch }
24992499
'm_no_rtti', { hides RTTI ASCII text }
2500-
'm_inline_var' { allow inline variable declarations inside statement blocks }
2500+
'm_inline_var', { allow inline variable declarations inside statement blocks }
2501+
'm_multi_var_init' { allow initializing multiple variables in one declaration }
25012502
);
25022503
{ optimizer }
25032504
optimizerswitchname : array[toptimizerswitch] of string[50] =

0 commit comments

Comments
 (0)