nld.pas 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Type checking and register allocation for load/assignment nodes
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit nld;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,
  22. {$ifdef state_tracking}
  23. nstate,
  24. {$endif}
  25. symconst,symbase,symtype,symsym,symdef;
  26. type
  27. tloadnode = class(tunarynode)
  28. protected
  29. procdef : tprocdef;
  30. procdefderef : tderef;
  31. public
  32. symtableentry : tsym;
  33. symtableentryderef : tderef;
  34. symtable : TSymtable;
  35. constructor create(v : tsym;st : TSymtable);virtual;
  36. constructor create_procvar(v : tsym;d:tprocdef;st : TSymtable);virtual;
  37. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  38. procedure ppuwrite(ppufile:tcompilerppufile);override;
  39. procedure buildderefimpl;override;
  40. procedure derefimpl;override;
  41. procedure set_mp(p:tnode);
  42. function is_addr_param_load:boolean;
  43. function dogetcopy : tnode;override;
  44. function pass_1 : tnode;override;
  45. function pass_typecheck:tnode;override;
  46. procedure mark_write;override;
  47. function docompare(p: tnode): boolean; override;
  48. procedure printnodedata(var t:text);override;
  49. procedure setprocdef(p : tprocdef);
  50. end;
  51. tloadnodeclass = class of tloadnode;
  52. { different assignment types }
  53. tassigntype = (at_normal,at_plus,at_minus,at_star,at_slash);
  54. tassignmentnode = class(tbinarynode)
  55. assigntype : tassigntype;
  56. constructor create(l,r : tnode);virtual;
  57. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  58. procedure ppuwrite(ppufile:tcompilerppufile);override;
  59. function dogetcopy : tnode;override;
  60. function pass_1 : tnode;override;
  61. function pass_typecheck:tnode;override;
  62. {$ifdef state_tracking}
  63. function track_state_pass(exec_known:boolean):boolean;override;
  64. {$endif state_tracking}
  65. function docompare(p: tnode): boolean; override;
  66. end;
  67. tassignmentnodeclass = class of tassignmentnode;
  68. tarrayconstructorrangenode = class(tbinarynode)
  69. constructor create(l,r : tnode);virtual;
  70. function pass_1 : tnode;override;
  71. function pass_typecheck:tnode;override;
  72. end;
  73. tarrayconstructorrangenodeclass = class of tarrayconstructorrangenode;
  74. tarrayconstructornode = class(tbinarynode)
  75. constructor create(l,r : tnode);virtual;
  76. function dogetcopy : tnode;override;
  77. function pass_1 : tnode;override;
  78. function pass_typecheck:tnode;override;
  79. function docompare(p: tnode): boolean; override;
  80. procedure force_type(def:tdef);
  81. procedure insert_typeconvs;
  82. end;
  83. tarrayconstructornodeclass = class of tarrayconstructornode;
  84. ttypenode = class(tnode)
  85. allowed : boolean;
  86. typedef : tdef;
  87. typedefderef : tderef;
  88. constructor create(def:tdef);virtual;
  89. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  90. procedure ppuwrite(ppufile:tcompilerppufile);override;
  91. procedure buildderefimpl;override;
  92. procedure derefimpl;override;
  93. function pass_1 : tnode;override;
  94. function pass_typecheck:tnode;override;
  95. function dogetcopy : tnode;override;
  96. function docompare(p: tnode): boolean; override;
  97. end;
  98. ttypenodeclass = class of ttypenode;
  99. trttinode = class(tnode)
  100. l1,l2 : longint;
  101. rttitype : trttitype;
  102. rttidef : tstoreddef;
  103. rttidefderef : tderef;
  104. constructor create(def:tstoreddef;rt:trttitype);virtual;
  105. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  106. procedure ppuwrite(ppufile:tcompilerppufile);override;
  107. procedure buildderefimpl;override;
  108. procedure derefimpl;override;
  109. function dogetcopy : tnode;override;
  110. function pass_1 : tnode;override;
  111. function pass_typecheck:tnode;override;
  112. function docompare(p: tnode): boolean; override;
  113. end;
  114. trttinodeclass = class of trttinode;
  115. var
  116. cloadnode : tloadnodeclass;
  117. cassignmentnode : tassignmentnodeclass;
  118. carrayconstructorrangenode : tarrayconstructorrangenodeclass;
  119. carrayconstructornode : tarrayconstructornodeclass;
  120. ctypenode : ttypenodeclass;
  121. crttinode : trttinodeclass;
  122. { Current assignment node }
  123. aktassignmentnode : tassignmentnode;
  124. implementation
  125. uses
  126. cutils,verbose,globtype,globals,systems,
  127. symnot,
  128. defutil,defcmp,
  129. htypechk,pass_1,procinfo,paramgr,
  130. ncon,ninl,ncnv,nmem,ncal,nutils,nbas,
  131. cgobj,cgbase
  132. ;
  133. {*****************************************************************************
  134. TLOADNODE
  135. *****************************************************************************}
  136. constructor tloadnode.create(v : tsym;st : TSymtable);
  137. begin
  138. inherited create(loadn,nil);
  139. if not assigned(v) then
  140. internalerror(200108121);
  141. symtableentry:=v;
  142. symtable:=st;
  143. procdef:=nil;
  144. end;
  145. constructor tloadnode.create_procvar(v : tsym;d:tprocdef;st : TSymtable);
  146. begin
  147. inherited create(loadn,nil);
  148. if not assigned(v) then
  149. internalerror(200108121);
  150. symtableentry:=v;
  151. symtable:=st;
  152. procdef:=d;
  153. end;
  154. constructor tloadnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  155. begin
  156. inherited ppuload(t,ppufile);
  157. ppufile.getderef(symtableentryderef);
  158. symtable:=nil;
  159. ppufile.getderef(procdefderef);
  160. end;
  161. procedure tloadnode.ppuwrite(ppufile:tcompilerppufile);
  162. begin
  163. inherited ppuwrite(ppufile);
  164. ppufile.putderef(symtableentryderef);
  165. ppufile.putderef(procdefderef);
  166. end;
  167. procedure tloadnode.buildderefimpl;
  168. begin
  169. inherited buildderefimpl;
  170. symtableentryderef.build(symtableentry);
  171. procdefderef.build(procdef);
  172. end;
  173. procedure tloadnode.derefimpl;
  174. begin
  175. inherited derefimpl;
  176. symtableentry:=tsym(symtableentryderef.resolve);
  177. symtable:=symtableentry.owner;
  178. procdef:=tprocdef(procdefderef.resolve);
  179. end;
  180. procedure tloadnode.set_mp(p:tnode);
  181. begin
  182. { typen nodes should not be set }
  183. if p.nodetype=typen then
  184. internalerror(200301042);
  185. left:=p;
  186. end;
  187. function tloadnode.dogetcopy : tnode;
  188. var
  189. n : tloadnode;
  190. begin
  191. n:=tloadnode(inherited dogetcopy);
  192. n.symtable:=symtable;
  193. n.symtableentry:=symtableentry;
  194. n.procdef:=procdef;
  195. result:=n;
  196. end;
  197. function tloadnode.is_addr_param_load:boolean;
  198. begin
  199. result:=(symtable.symtabletype=parasymtable) and
  200. (symtableentry.typ=paravarsym) and
  201. not(vo_has_local_copy in tparavarsym(symtableentry).varoptions) and
  202. not(nf_load_self_pointer in flags) and
  203. paramanager.push_addr_param(tparavarsym(symtableentry).varspez,tparavarsym(symtableentry).vardef,tprocdef(symtable.defowner).proccalloption);
  204. end;
  205. function tloadnode.pass_typecheck:tnode;
  206. begin
  207. result:=nil;
  208. case symtableentry.typ of
  209. absolutevarsym :
  210. resultdef:=tabsolutevarsym(symtableentry).vardef;
  211. constsym:
  212. begin
  213. if tconstsym(symtableentry).consttyp=constresourcestring then
  214. resultdef:=cansistringtype
  215. else
  216. internalerror(22799);
  217. end;
  218. globalvarsym,
  219. paravarsym,
  220. localvarsym :
  221. begin
  222. inc(tabstractvarsym(symtableentry).refs);
  223. { Nested variable? The we need to load the framepointer of
  224. the parent procedure }
  225. if assigned(current_procinfo) then
  226. begin
  227. if (symtable.symtabletype in [localsymtable,parasymtable]) and
  228. (symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) then
  229. begin
  230. if assigned(left) then
  231. internalerror(200309289);
  232. left:=cloadparentfpnode.create(tprocdef(symtable.defowner));
  233. { we can't inline the referenced parent procedure }
  234. exclude(tprocdef(symtable.defowner).procoptions,po_inline);
  235. { reference in nested procedures, variable needs to be in memory }
  236. make_not_regable(self,vr_none);
  237. end;
  238. { static variables referenced in procedures or from finalization,
  239. variable needs to be in memory.
  240. It is too hard and the benefit is too small to detect whether a
  241. variable is only used in the finalization to add support for it (PFV) }
  242. if (symtable.symtabletype=staticsymtable) and
  243. (
  244. (symtable.symtablelevel<>current_procinfo.procdef.localst.symtablelevel) or
  245. (current_procinfo.procdef.proctypeoption=potype_unitfinalize)
  246. ) then
  247. make_not_regable(self,vr_none);
  248. end;
  249. { fix self type which is declared as voidpointer in the
  250. definition }
  251. if vo_is_self in tabstractvarsym(symtableentry).varoptions then
  252. begin
  253. resultdef:=tprocdef(symtableentry.owner.defowner)._class;
  254. if (po_classmethod in tprocdef(symtableentry.owner.defowner).procoptions) or
  255. (po_staticmethod in tprocdef(symtableentry.owner.defowner).procoptions) then
  256. resultdef:=tclassrefdef.create(resultdef)
  257. else if is_object(resultdef) and
  258. (nf_load_self_pointer in flags) then
  259. resultdef:=tpointerdef.create(resultdef);
  260. end
  261. else if vo_is_vmt in tabstractvarsym(symtableentry).varoptions then
  262. begin
  263. resultdef:=tprocdef(symtableentry.owner.defowner)._class;
  264. resultdef:=tclassrefdef.create(resultdef);
  265. end
  266. else
  267. resultdef:=tabstractvarsym(symtableentry).vardef;
  268. end;
  269. typedconstsym :
  270. resultdef:=ttypedconstsym(symtableentry).typedconstdef;
  271. procsym :
  272. begin
  273. { Return the first procdef. In case of overlaoded
  274. procdefs the matching procdef will be choosen
  275. when the expected procvardef is known, see get_information
  276. in htypechk.pas (PFV) }
  277. if not assigned(procdef) then
  278. procdef:=tprocsym(symtableentry).first_procdef
  279. else if po_kylixlocal in procdef.procoptions then
  280. CGMessage(type_e_cant_take_address_of_local_subroutine);
  281. { the result is a procdef, addrn and proc_to_procvar
  282. typeconvn need this as resultdef so they know
  283. that the address needs to be returned }
  284. resultdef:=procdef;
  285. { process methodpointer }
  286. if assigned(left) then
  287. typecheckpass(left);
  288. end;
  289. labelsym:
  290. resultdef:=voidtype;
  291. else
  292. internalerror(200104141);
  293. end;
  294. end;
  295. procedure Tloadnode.mark_write;
  296. begin
  297. include(flags,nf_write);
  298. end;
  299. function tloadnode.pass_1 : tnode;
  300. begin
  301. result:=nil;
  302. expectloc:=LOC_REFERENCE;
  303. registersint:=0;
  304. registersfpu:=0;
  305. {$ifdef SUPPORT_MMX}
  306. registersmmx:=0;
  307. {$endif SUPPORT_MMX}
  308. if (cs_create_pic in current_settings.moduleswitches) and
  309. not(symtableentry.typ in [paravarsym,localvarsym]) then
  310. include(current_procinfo.flags,pi_needs_got);
  311. case symtableentry.typ of
  312. absolutevarsym :
  313. ;
  314. constsym:
  315. begin
  316. if tconstsym(symtableentry).consttyp=constresourcestring then
  317. expectloc:=LOC_CREFERENCE;
  318. end;
  319. globalvarsym,
  320. localvarsym,
  321. paravarsym :
  322. begin
  323. if assigned(left) then
  324. firstpass(left);
  325. if not is_addr_param_load and
  326. tabstractvarsym(symtableentry).is_regvar(is_addr_param_load) then
  327. begin
  328. case tabstractvarsym(symtableentry).varregable of
  329. vr_intreg,
  330. vr_addr :
  331. expectloc:=LOC_CREGISTER;
  332. vr_fpureg :
  333. expectloc:=LOC_CFPUREGISTER;
  334. vr_mmreg :
  335. expectloc:=LOC_CMMREGISTER;
  336. end
  337. end
  338. else
  339. if (tabstractvarsym(symtableentry).varspez=vs_const) then
  340. expectloc:=LOC_CREFERENCE;
  341. { we need a register for call by reference parameters }
  342. if paramanager.push_addr_param(tabstractvarsym(symtableentry).varspez,tabstractvarsym(symtableentry).vardef,pocall_default) then
  343. registersint:=1;
  344. if ([vo_is_thread_var,vo_is_dll_var]*tabstractvarsym(symtableentry).varoptions)<>[] then
  345. registersint:=1;
  346. if (target_info.system=system_powerpc_darwin) and
  347. ([vo_is_dll_var,vo_is_external] * tabstractvarsym(symtableentry).varoptions <> []) then
  348. include(current_procinfo.flags,pi_needs_got);
  349. { call to get address of threadvar }
  350. if (vo_is_thread_var in tabstractvarsym(symtableentry).varoptions) then
  351. include(current_procinfo.flags,pi_do_call);
  352. if nf_write in flags then
  353. Tabstractvarsym(symtableentry).trigger_notifications(vn_onwrite)
  354. else
  355. Tabstractvarsym(symtableentry).trigger_notifications(vn_onread);
  356. { count variable references }
  357. if cg.t_times>1 then
  358. inc(tabstractvarsym(symtableentry).refs,cg.t_times-1);
  359. end;
  360. typedconstsym :
  361. ;
  362. procsym :
  363. begin
  364. { method pointer ? }
  365. if assigned(left) then
  366. begin
  367. expectloc:=LOC_CREFERENCE;
  368. firstpass(left);
  369. registersint:=max(registersint,left.registersint);
  370. registersfpu:=max(registersfpu,left.registersfpu);
  371. {$ifdef SUPPORT_MMX}
  372. registersmmx:=max(registersmmx,left.registersmmx);
  373. {$endif SUPPORT_MMX}
  374. end;
  375. end;
  376. labelsym :
  377. ;
  378. else
  379. internalerror(200104143);
  380. end;
  381. end;
  382. function tloadnode.docompare(p: tnode): boolean;
  383. begin
  384. docompare :=
  385. inherited docompare(p) and
  386. (symtableentry = tloadnode(p).symtableentry) and
  387. (procdef = tloadnode(p).procdef) and
  388. (symtable = tloadnode(p).symtable);
  389. end;
  390. procedure tloadnode.printnodedata(var t:text);
  391. begin
  392. inherited printnodedata(t);
  393. write(t,printnodeindention,'symbol = ',symtableentry.name);
  394. if symtableentry.typ=procsym then
  395. write(t,printnodeindention,'procdef = ',procdef.mangledname);
  396. writeln(t,'');
  397. end;
  398. procedure tloadnode.setprocdef(p : tprocdef);
  399. begin
  400. procdef:=p;
  401. resultdef:=p;
  402. if po_local in p.procoptions then
  403. CGMessage(type_e_cant_take_address_of_local_subroutine);
  404. end;
  405. {*****************************************************************************
  406. TASSIGNMENTNODE
  407. *****************************************************************************}
  408. constructor tassignmentnode.create(l,r : tnode);
  409. begin
  410. inherited create(assignn,l,r);
  411. l.mark_write;
  412. assigntype:=at_normal;
  413. end;
  414. constructor tassignmentnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  415. begin
  416. inherited ppuload(t,ppufile);
  417. assigntype:=tassigntype(ppufile.getbyte);
  418. end;
  419. procedure tassignmentnode.ppuwrite(ppufile:tcompilerppufile);
  420. begin
  421. inherited ppuwrite(ppufile);
  422. ppufile.putbyte(byte(assigntype));
  423. end;
  424. function tassignmentnode.dogetcopy : tnode;
  425. var
  426. n : tassignmentnode;
  427. begin
  428. n:=tassignmentnode(inherited dogetcopy);
  429. n.assigntype:=assigntype;
  430. result:=n;
  431. end;
  432. function tassignmentnode.pass_typecheck:tnode;
  433. var
  434. hp : tnode;
  435. useshelper : boolean;
  436. begin
  437. result:=nil;
  438. resultdef:=voidtype;
  439. { must be made unique }
  440. set_unique(left);
  441. typecheckpass(left);
  442. {$ifdef old_append_str}
  443. if is_ansistring(left.resultdef) then
  444. begin
  445. { fold <ansistring>:=<ansistring>+<char|shortstring|ansistring> }
  446. if (right.nodetype=addn) and
  447. left.isequal(tbinarynode(right).left) and
  448. { don't fold multiple concatenations else we could get trouble
  449. with multiple uses of s
  450. }
  451. (tbinarynode(right).left.nodetype<>addn) and
  452. (tbinarynode(right).right.nodetype<>addn) then
  453. begin
  454. { don't do a typecheckpass(right), since then the addnode }
  455. { may insert typeconversions that make this optimization }
  456. { opportunity quite difficult to detect (JM) }
  457. typecheckpass(tbinarynode(right).left);
  458. typecheckpass(tbinarynode(right).right);
  459. if (tbinarynode(right).right.nodetype=stringconstn) or
  460. is_char(tbinarynode(right).right.resultdef) or
  461. is_shortstring(tbinarynode(right).right.resultdef) or
  462. is_ansistring(tbinarynode(right).right.resultdef) then
  463. begin
  464. { remove property flag so it'll not trigger an error }
  465. exclude(left.flags,nf_isproperty);
  466. { generate call to helper }
  467. hp:=ccallparanode.create(tbinarynode(right).right,
  468. ccallparanode.create(left,nil));
  469. if is_char(tbinarynode(right).right.resultdef) then
  470. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resultdef).stringtypname+'_append_char',hp)
  471. else if is_shortstring(tbinarynode(right).right.resultdef) then
  472. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resultdef).stringtypname+'_append_shortstring',hp)
  473. else
  474. result:=ccallnode.createintern('fpc_'+Tstringdef(left.resultdef).stringtypname+'_append_ansistring',hp);
  475. tbinarynode(right).right:=nil;
  476. left:=nil;
  477. exit;
  478. end;
  479. end;
  480. end
  481. else
  482. if is_shortstring(left.resultdef) then
  483. begin
  484. { fold <shortstring>:=<shortstring>+<shortstring>,
  485. <shortstring>+<char> is handled by an optimized node }
  486. if (right.nodetype=addn) and
  487. left.isequal(tbinarynode(right).left) and
  488. { don't fold multiple concatenations else we could get trouble
  489. with multiple uses of s }
  490. (tbinarynode(right).left.nodetype<>addn) and
  491. (tbinarynode(right).right.nodetype<>addn) then
  492. begin
  493. { don't do a typecheckpass(right), since then the addnode }
  494. { may insert typeconversions that make this optimization }
  495. { opportunity quite difficult to detect (JM) }
  496. typecheckpass(tbinarynode(right).left);
  497. typecheckpass(tbinarynode(right).right);
  498. if is_shortstring(tbinarynode(right).right.resultdef) then
  499. begin
  500. { remove property flag so it'll not trigger an error }
  501. exclude(left.flags,nf_isproperty);
  502. { generate call to helper }
  503. hp:=ccallparanode.create(tbinarynode(right).right,
  504. ccallparanode.create(left,nil));
  505. if is_shortstring(tbinarynode(right).right.resultdef) then
  506. result:=ccallnode.createintern('fpc_shortstr_append_shortstr',hp);
  507. tbinarynode(right).right:=nil;
  508. left:=nil;
  509. exit;
  510. end;
  511. end;
  512. end;
  513. {$endif old_append_str}
  514. typecheckpass(right);
  515. set_varstate(right,vs_read,[vsf_must_be_valid]);
  516. set_varstate(left,vs_written,[]);
  517. if codegenerror then
  518. exit;
  519. { tp procvar support, when we don't expect a procvar
  520. then we need to call the procvar }
  521. if (left.resultdef.typ<>procvardef) then
  522. maybe_call_procvar(right,true);
  523. { assignments to formaldefs and open arrays aren't allowed }
  524. if (left.resultdef.typ=formaldef) or
  525. is_open_array(left.resultdef) then
  526. CGMessage(type_e_operator_not_allowed);
  527. { test if node can be assigned, properties are allowed }
  528. valid_for_assignment(left,true);
  529. { assigning nil to a dynamic array clears the array }
  530. if is_dynamic_array(left.resultdef) and
  531. (right.nodetype=niln) then
  532. begin
  533. hp:=ccallparanode.create(caddrnode.create_internal
  534. (crttinode.create(tstoreddef(left.resultdef),initrtti)),
  535. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),nil));
  536. result := ccallnode.createintern('fpc_dynarray_clear',hp);
  537. left:=nil;
  538. exit;
  539. end;
  540. { shortstring helpers can do the conversion directly,
  541. so treat them separatly }
  542. if (is_shortstring(left.resultdef)) then
  543. begin
  544. { insert typeconv, except for chars that are handled in
  545. secondpass and except for ansi/wide string that can
  546. be converted immediatly }
  547. if not(is_char(right.resultdef) or
  548. (right.resultdef.typ=stringdef)) then
  549. inserttypeconv(right,left.resultdef);
  550. if right.resultdef.typ=stringdef then
  551. begin
  552. useshelper:=true;
  553. { convert constant strings to shortstrings. But
  554. skip empty constant strings, that will be handled
  555. in secondpass }
  556. if (right.nodetype=stringconstn) then
  557. begin
  558. { verify if range fits within shortstring }
  559. { just emit a warning, delphi gives an }
  560. { error, only if the type definition of }
  561. { of the string is less < 255 characters }
  562. if not is_open_string(left.resultdef) and
  563. (tstringconstnode(right).len > tstringdef(left.resultdef).len) then
  564. cgmessage(type_w_string_too_long);
  565. inserttypeconv(right,left.resultdef);
  566. if (tstringconstnode(right).len=0) then
  567. useshelper:=false;
  568. end;
  569. { rest is done in pass 1 (JM) }
  570. if useshelper then
  571. exit;
  572. end
  573. end
  574. else
  575. begin
  576. { check if the assignment may cause a range check error }
  577. check_ranges(fileinfo,right,left.resultdef);
  578. inserttypeconv(right,left.resultdef);
  579. end;
  580. { call helpers for interface }
  581. if is_interfacecom(left.resultdef) then
  582. begin
  583. {
  584. hp:=
  585. ccallparanode.create(
  586. ctypeconvnode.create_internal(right,voidpointertype),
  587. ccallparanode.create(
  588. ctypeconvnode.create_internal(left,voidpointertype),
  589. nil));
  590. result:=ccallnode.createintern('fpc_intf_assign',hp);
  591. }
  592. hp:=
  593. ccallparanode.create(
  594. cguidconstnode.create(tobjectdef(left.resultdef).iidguid^),
  595. ccallparanode.create(
  596. ctypeconvnode.create_internal(right,voidpointertype),
  597. ccallparanode.create(
  598. ctypeconvnode.create_internal(left,voidpointertype),
  599. nil)));
  600. result:=ccallnode.createintern('fpc_intf_assign_by_iid',hp);
  601. left:=nil;
  602. right:=nil;
  603. exit;
  604. end;
  605. { call helpers for variant, they can contain non ref. counted types like
  606. vararrays which must be really copied }
  607. if left.resultdef.typ=variantdef then
  608. begin
  609. hp:=ccallparanode.create(ctypeconvnode.create_internal(
  610. caddrnode.create_internal(right),voidpointertype),
  611. ccallparanode.create(ctypeconvnode.create_internal(
  612. caddrnode.create_internal(left),voidpointertype),
  613. nil));
  614. result:=ccallnode.createintern('fpc_variant_copy',hp);
  615. left:=nil;
  616. right:=nil;
  617. exit;
  618. end;
  619. { call helpers for windows widestrings, they aren't ref. counted }
  620. if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resultdef) then
  621. begin
  622. hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
  623. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
  624. nil));
  625. result:=ccallnode.createintern('fpc_widestr_assign',hp);
  626. left:=nil;
  627. right:=nil;
  628. exit;
  629. end;
  630. { check if local proc/func is assigned to procvar }
  631. if right.resultdef.typ=procvardef then
  632. test_local_to_procvar(tprocvardef(right.resultdef),left.resultdef);
  633. end;
  634. function tassignmentnode.pass_1 : tnode;
  635. var
  636. hp: tnode;
  637. oldassignmentnode : tassignmentnode;
  638. begin
  639. result:=nil;
  640. expectloc:=LOC_VOID;
  641. firstpass(left);
  642. { Optimize the reuse of the destination of the assingment in left.
  643. Allow the use of the left inside the tree generated on the right.
  644. This is especially usefull for string routines where the destination
  645. is pushed as a parameter. Using the final destination of left directly
  646. save a temp allocation and copy of data (PFV) }
  647. oldassignmentnode:=aktassignmentnode;
  648. if right.nodetype=addn then
  649. aktassignmentnode:=self
  650. else
  651. aktassignmentnode:=nil;
  652. firstpass(right);
  653. aktassignmentnode:=oldassignmentnode;
  654. if nf_assign_done_in_right in flags then
  655. begin
  656. result:=right;
  657. right:=nil;
  658. exit;
  659. end;
  660. if codegenerror then
  661. exit;
  662. if (cs_opt_level1 in current_settings.optimizerswitches) and
  663. (right.nodetype = calln) and
  664. (right.resultdef=left.resultdef) and
  665. { left must be a temp, since otherwise as soon as you modify the }
  666. { result, the current left node is modified and that one may }
  667. { still be an argument to the function or even accessed in the }
  668. { function }
  669. (
  670. (
  671. (left.nodetype = temprefn) and
  672. paramanager.ret_in_param(right.resultdef,tcallnode(right).procdefinition.proccalloption)
  673. ) or
  674. { there's special support for ansi/widestrings in the callnode }
  675. is_ansistring(right.resultdef) or
  676. is_widestring(right.resultdef)
  677. ) then
  678. begin
  679. make_not_regable(left,vr_addr);
  680. tcallnode(right).funcretnode := left;
  681. result := right;
  682. left := nil;
  683. right := nil;
  684. exit;
  685. end;
  686. { assignment to refcounted variable -> inc/decref }
  687. if (not is_class(left.resultdef) and
  688. left.resultdef.needs_inittable) then
  689. include(current_procinfo.flags,pi_do_call);
  690. if (is_shortstring(left.resultdef)) then
  691. begin
  692. if right.resultdef.typ=stringdef then
  693. begin
  694. if (right.nodetype<>stringconstn) or
  695. (tstringconstnode(right).len<>0) then
  696. begin
  697. {$ifdef old_append_str}
  698. if (cs_opt_level1 in current_settings.optimizerswitches) and
  699. (right.nodetype in [calln,blockn]) and
  700. (left.nodetype = temprefn) and
  701. is_shortstring(right.resultdef) and
  702. not is_open_string(left.resultdef) and
  703. (tstringdef(left.resultdef).len = 255) then
  704. begin
  705. { the blocknode case is handled in pass_generate_code at the temp }
  706. { reference level (mainly for callparatemp) (JM) }
  707. if (right.nodetype = calln) then
  708. begin
  709. tcallnode(right).funcretnode := left;
  710. result := right;
  711. end
  712. else
  713. exit;
  714. end
  715. else
  716. {$endif old_append_str}
  717. begin
  718. hp:=ccallparanode.create
  719. (right,
  720. ccallparanode.create(cinlinenode.create
  721. (in_high_x,false,left.getcopy),nil));
  722. result:=ccallnode.createinternreturn('fpc_'+tstringdef(right.resultdef).stringtypname+'_to_shortstr',hp,left);
  723. firstpass(result);
  724. end;
  725. left:=nil;
  726. right:=nil;
  727. exit;
  728. end;
  729. end;
  730. end;
  731. registersint:=left.registersint+right.registersint;
  732. registersfpu:=max(left.registersfpu,right.registersfpu);
  733. {$ifdef SUPPORT_MMX}
  734. registersmmx:=max(left.registersmmx,right.registersmmx);
  735. {$endif SUPPORT_MMX}
  736. end;
  737. function tassignmentnode.docompare(p: tnode): boolean;
  738. begin
  739. docompare :=
  740. inherited docompare(p) and
  741. (assigntype = tassignmentnode(p).assigntype);
  742. end;
  743. {$ifdef state_tracking}
  744. function Tassignmentnode.track_state_pass(exec_known:boolean):boolean;
  745. var se:Tstate_entry;
  746. begin
  747. track_state_pass:=false;
  748. if exec_known then
  749. begin
  750. track_state_pass:=right.track_state_pass(exec_known);
  751. {Force a new resultdef pass.}
  752. right.resultdef:=nil;
  753. do_typecheckpass(right);
  754. typecheckpass(right);
  755. aktstate.store_fact(left.getcopy,right.getcopy);
  756. end
  757. else
  758. aktstate.delete_fact(left);
  759. end;
  760. {$endif}
  761. {*****************************************************************************
  762. TARRAYCONSTRUCTORRANGENODE
  763. *****************************************************************************}
  764. constructor tarrayconstructorrangenode.create(l,r : tnode);
  765. begin
  766. inherited create(arrayconstructorrangen,l,r);
  767. end;
  768. function tarrayconstructorrangenode.pass_typecheck:tnode;
  769. begin
  770. result:=nil;
  771. typecheckpass(left);
  772. typecheckpass(right);
  773. set_varstate(left,vs_read,[vsf_must_be_valid]);
  774. set_varstate(right,vs_read,[vsf_must_be_valid]);
  775. if codegenerror then
  776. exit;
  777. resultdef:=left.resultdef;
  778. end;
  779. function tarrayconstructorrangenode.pass_1 : tnode;
  780. begin
  781. firstpass(left);
  782. firstpass(right);
  783. expectloc:=LOC_CREFERENCE;
  784. calcregisters(self,0,0,0);
  785. result:=nil;
  786. end;
  787. {****************************************************************************
  788. TARRAYCONSTRUCTORNODE
  789. *****************************************************************************}
  790. constructor tarrayconstructornode.create(l,r : tnode);
  791. begin
  792. inherited create(arrayconstructorn,l,r);
  793. end;
  794. function tarrayconstructornode.dogetcopy : tnode;
  795. var
  796. n : tarrayconstructornode;
  797. begin
  798. n:=tarrayconstructornode(inherited dogetcopy);
  799. result:=n;
  800. end;
  801. function tarrayconstructornode.pass_typecheck:tnode;
  802. var
  803. hdef : tdef;
  804. hp : tarrayconstructornode;
  805. len : longint;
  806. varia : boolean;
  807. begin
  808. result:=nil;
  809. { are we allowing array constructor? Then convert it to a set.
  810. Do this only if we didn't convert the arrayconstructor yet. This
  811. is needed for the cases where the resultdef is forced for a second
  812. run }
  813. if (not allow_array_constructor) then
  814. begin
  815. hp:=tarrayconstructornode(getcopy);
  816. arrayconstructor_to_set(tnode(hp));
  817. result:=hp;
  818. exit;
  819. end;
  820. { only pass left tree, right tree contains next construct if any }
  821. hdef:=nil;
  822. len:=0;
  823. varia:=false;
  824. if assigned(left) then
  825. begin
  826. hp:=self;
  827. while assigned(hp) do
  828. begin
  829. typecheckpass(hp.left);
  830. set_varstate(hp.left,vs_read,[vsf_must_be_valid]);
  831. if (hdef=nil) then
  832. hdef:=hp.left.resultdef
  833. else
  834. begin
  835. if (not varia) and (not equal_defs(hdef,hp.left.resultdef)) then
  836. begin
  837. { If both are integers we need to take the type that can hold both
  838. defs }
  839. if is_integer(hdef) and is_integer(hp.left.resultdef) then
  840. begin
  841. if is_in_limit(hdef,hp.left.resultdef) then
  842. hdef:=hp.left.resultdef;
  843. end
  844. else
  845. if (nf_novariaallowed in flags) then
  846. varia:=true;
  847. end;
  848. end;
  849. inc(len);
  850. hp:=tarrayconstructornode(hp.right);
  851. end;
  852. end;
  853. { Set the type of empty or varia arrays to void. Also
  854. do this if the type is array of const/open array
  855. because those can't be used with setelementdef }
  856. if not assigned(hdef) or
  857. varia or
  858. is_array_of_const(hdef) or
  859. is_open_array(hdef) then
  860. hdef:=voidtype;
  861. resultdef:=tarraydef.create(0,len-1,s32inttype);
  862. tarraydef(resultdef).elementdef:=hdef;
  863. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  864. if varia then
  865. include(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  866. end;
  867. procedure tarrayconstructornode.force_type(def:tdef);
  868. var
  869. hp : tarrayconstructornode;
  870. begin
  871. tarraydef(resultdef).elementdef:=def;
  872. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  873. exclude(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  874. if assigned(left) then
  875. begin
  876. hp:=self;
  877. while assigned(hp) do
  878. begin
  879. inserttypeconv(hp.left,def);
  880. hp:=tarrayconstructornode(hp.right);
  881. end;
  882. end;
  883. end;
  884. procedure tarrayconstructornode.insert_typeconvs;
  885. var
  886. hp : tarrayconstructornode;
  887. dovariant : boolean;
  888. begin
  889. dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  890. { only pass left tree, right tree contains next construct if any }
  891. if assigned(left) then
  892. begin
  893. hp:=self;
  894. while assigned(hp) do
  895. begin
  896. typecheckpass(hp.left);
  897. { Insert typeconvs for array of const }
  898. if dovariant then
  899. { at this time C varargs are no longer an arrayconstructornode }
  900. insert_varargstypeconv(hp.left,false);
  901. hp:=tarrayconstructornode(hp.right);
  902. end;
  903. end;
  904. end;
  905. function tarrayconstructornode.pass_1 : tnode;
  906. var
  907. hp : tarrayconstructornode;
  908. do_variant:boolean;
  909. begin
  910. do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  911. result:=nil;
  912. { Insert required type convs, this must be
  913. done in pass 1, because the call must be
  914. typecheckpassed already }
  915. if assigned(left) then
  916. begin
  917. insert_typeconvs;
  918. { call firstpass for all nodes }
  919. hp:=self;
  920. while assigned(hp) do
  921. begin
  922. if hp.left<>nil then
  923. begin
  924. {This check is pessimistic; a call will happen depending
  925. on the location in which the elements will be found in
  926. pass 2.}
  927. if not do_variant then
  928. include(current_procinfo.flags,pi_do_call);
  929. firstpass(hp.left);
  930. end;
  931. hp:=tarrayconstructornode(hp.right);
  932. end;
  933. end;
  934. expectloc:=LOC_CREFERENCE;
  935. calcregisters(self,0,0,0);
  936. end;
  937. function tarrayconstructornode.docompare(p: tnode): boolean;
  938. begin
  939. docompare:=inherited docompare(p);
  940. end;
  941. {*****************************************************************************
  942. TTYPENODE
  943. *****************************************************************************}
  944. constructor ttypenode.create(def:tdef);
  945. begin
  946. inherited create(typen);
  947. typedef:=def;
  948. allowed:=false;
  949. end;
  950. constructor ttypenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  951. begin
  952. inherited ppuload(t,ppufile);
  953. ppufile.getderef(typedefderef);
  954. allowed:=boolean(ppufile.getbyte);
  955. end;
  956. procedure ttypenode.ppuwrite(ppufile:tcompilerppufile);
  957. begin
  958. inherited ppuwrite(ppufile);
  959. ppufile.putderef(typedefderef);
  960. ppufile.putbyte(byte(allowed));
  961. end;
  962. procedure ttypenode.buildderefimpl;
  963. begin
  964. inherited buildderefimpl;
  965. typedefderef.build(typedef);
  966. end;
  967. procedure ttypenode.derefimpl;
  968. begin
  969. inherited derefimpl;
  970. typedef:=tdef(typedefderef.resolve);
  971. end;
  972. function ttypenode.pass_typecheck:tnode;
  973. begin
  974. result:=nil;
  975. resultdef:=typedef;
  976. { check if it's valid }
  977. if typedef.typ = errordef then
  978. CGMessage(parser_e_illegal_expression);
  979. end;
  980. function ttypenode.pass_1 : tnode;
  981. begin
  982. result:=nil;
  983. expectloc:=LOC_VOID;
  984. { a typenode can't generate code, so we give here
  985. an error. Else it'll be an abstract error in pass_generate_code.
  986. Only when the allowed flag is set we don't generate
  987. an error }
  988. if not allowed then
  989. Message(parser_e_no_type_not_allowed_here);
  990. end;
  991. function ttypenode.dogetcopy : tnode;
  992. var
  993. n : ttypenode;
  994. begin
  995. n:=ttypenode(inherited dogetcopy);
  996. n.allowed:=allowed;
  997. n.typedef:=typedef;
  998. result:=n;
  999. end;
  1000. function ttypenode.docompare(p: tnode): boolean;
  1001. begin
  1002. docompare :=
  1003. inherited docompare(p);
  1004. end;
  1005. {*****************************************************************************
  1006. TRTTINODE
  1007. *****************************************************************************}
  1008. constructor trttinode.create(def:tstoreddef;rt:trttitype);
  1009. begin
  1010. inherited create(rttin);
  1011. rttidef:=def;
  1012. rttitype:=rt;
  1013. end;
  1014. constructor trttinode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  1015. begin
  1016. inherited ppuload(t,ppufile);
  1017. ppufile.getderef(rttidefderef);
  1018. rttitype:=trttitype(ppufile.getbyte);
  1019. end;
  1020. procedure trttinode.ppuwrite(ppufile:tcompilerppufile);
  1021. begin
  1022. inherited ppuwrite(ppufile);
  1023. ppufile.putderef(rttidefderef);
  1024. ppufile.putbyte(byte(rttitype));
  1025. end;
  1026. procedure trttinode.buildderefimpl;
  1027. begin
  1028. inherited buildderefimpl;
  1029. rttidefderef.build(rttidef);
  1030. end;
  1031. procedure trttinode.derefimpl;
  1032. begin
  1033. inherited derefimpl;
  1034. rttidef:=tstoreddef(rttidefderef.resolve);
  1035. end;
  1036. function trttinode.dogetcopy : tnode;
  1037. var
  1038. n : trttinode;
  1039. begin
  1040. n:=trttinode(inherited dogetcopy);
  1041. n.rttidef:=rttidef;
  1042. n.rttitype:=rttitype;
  1043. result:=n;
  1044. end;
  1045. function trttinode.pass_typecheck:tnode;
  1046. begin
  1047. { rtti information will be returned as a void pointer }
  1048. result:=nil;
  1049. resultdef:=voidpointertype;
  1050. end;
  1051. function trttinode.pass_1 : tnode;
  1052. begin
  1053. result:=nil;
  1054. expectloc:=LOC_CREFERENCE;
  1055. end;
  1056. function trttinode.docompare(p: tnode): boolean;
  1057. begin
  1058. docompare :=
  1059. inherited docompare(p) and
  1060. (rttidef = trttinode(p).rttidef) and
  1061. (rttitype = trttinode(p).rttitype);
  1062. end;
  1063. begin
  1064. cloadnode:=tloadnode;
  1065. cassignmentnode:=tassignmentnode;
  1066. carrayconstructorrangenode:=tarrayconstructorrangenode;
  1067. carrayconstructornode:=tarrayconstructornode;
  1068. ctypenode:=ttypenode;
  1069. crttinode:=trttinode;
  1070. end.