nld.pas 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  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. staticvarsym :
  219. begin
  220. tabstractvarsym(symtableentry).IncRefCountBy(1);
  221. { static variables referenced in procedures or from finalization,
  222. variable needs to be in memory.
  223. It is too hard and the benefit is too small to detect whether a
  224. variable is only used in the finalization to add support for it (PFV) }
  225. if assigned(current_procinfo) and
  226. (symtable.symtabletype=staticsymtable) and
  227. (
  228. (symtable.symtablelevel<>current_procinfo.procdef.localst.symtablelevel) or
  229. (current_procinfo.procdef.proctypeoption=potype_unitfinalize)
  230. ) then
  231. make_not_regable(self,[ra_addr_taken]);
  232. resultdef:=tabstractvarsym(symtableentry).vardef;
  233. end;
  234. paravarsym,
  235. localvarsym :
  236. begin
  237. tabstractvarsym(symtableentry).IncRefCountBy(1);
  238. { Nested variable? The we need to load the framepointer of
  239. the parent procedure }
  240. if assigned(current_procinfo) and
  241. (symtable.symtabletype in [localsymtable,parasymtable]) and
  242. (symtable.symtablelevel<>current_procinfo.procdef.parast.symtablelevel) then
  243. begin
  244. if assigned(left) then
  245. internalerror(200309289);
  246. left:=cloadparentfpnode.create(tprocdef(symtable.defowner));
  247. { we can't inline the referenced parent procedure }
  248. exclude(tprocdef(symtable.defowner).procoptions,po_inline);
  249. { reference in nested procedures, variable needs to be in memory }
  250. { and behaves as if its address escapes its parent block }
  251. make_not_regable(self,[ra_addr_taken]);
  252. end;
  253. { fix self type which is declared as voidpointer in the
  254. definition }
  255. if vo_is_self in tabstractvarsym(symtableentry).varoptions then
  256. begin
  257. resultdef:=tprocdef(symtableentry.owner.defowner)._class;
  258. if (po_classmethod in tprocdef(symtableentry.owner.defowner).procoptions) or
  259. (po_staticmethod in tprocdef(symtableentry.owner.defowner).procoptions) then
  260. resultdef:=tclassrefdef.create(resultdef)
  261. else if is_object(resultdef) and
  262. (nf_load_self_pointer in flags) then
  263. resultdef:=tpointerdef.create(resultdef);
  264. end
  265. else if vo_is_vmt in tabstractvarsym(symtableentry).varoptions then
  266. begin
  267. resultdef:=tprocdef(symtableentry.owner.defowner)._class;
  268. resultdef:=tclassrefdef.create(resultdef);
  269. end
  270. else
  271. resultdef:=tabstractvarsym(symtableentry).vardef;
  272. end;
  273. procsym :
  274. begin
  275. { Return the first procdef. In case of overlaoded
  276. procdefs the matching procdef will be choosen
  277. when the expected procvardef is known, see get_information
  278. in htypechk.pas (PFV) }
  279. if not assigned(procdef) then
  280. procdef:=tprocdef(tprocsym(symtableentry).ProcdefList[0])
  281. else if po_kylixlocal in procdef.procoptions then
  282. CGMessage(type_e_cant_take_address_of_local_subroutine);
  283. { the result is a procdef, addrn and proc_to_procvar
  284. typeconvn need this as resultdef so they know
  285. that the address needs to be returned }
  286. resultdef:=procdef;
  287. { process methodpointer }
  288. if assigned(left) then
  289. typecheckpass(left);
  290. end;
  291. labelsym:
  292. resultdef:=voidtype;
  293. else
  294. internalerror(200104141);
  295. end;
  296. end;
  297. procedure Tloadnode.mark_write;
  298. begin
  299. include(flags,nf_write);
  300. end;
  301. function tloadnode.pass_1 : tnode;
  302. begin
  303. result:=nil;
  304. expectloc:=LOC_REFERENCE;
  305. registersint:=0;
  306. registersfpu:=0;
  307. {$ifdef SUPPORT_MMX}
  308. registersmmx:=0;
  309. {$endif SUPPORT_MMX}
  310. if (cs_create_pic in current_settings.moduleswitches) and
  311. not(symtableentry.typ in [paravarsym,localvarsym]) then
  312. include(current_procinfo.flags,pi_needs_got);
  313. case symtableentry.typ of
  314. absolutevarsym :
  315. ;
  316. constsym:
  317. begin
  318. if tconstsym(symtableentry).consttyp=constresourcestring then
  319. expectloc:=LOC_CREFERENCE;
  320. end;
  321. staticvarsym,
  322. localvarsym,
  323. paravarsym :
  324. begin
  325. if assigned(left) then
  326. firstpass(left);
  327. if not is_addr_param_load and
  328. tabstractvarsym(symtableentry).is_regvar(is_addr_param_load) then
  329. expectloc:=tvarregable2tcgloc[tabstractvarsym(symtableentry).varregable]
  330. else
  331. if (tabstractvarsym(symtableentry).varspez=vs_const) then
  332. expectloc:=LOC_CREFERENCE;
  333. { we need a register for call by reference parameters }
  334. if paramanager.push_addr_param(tabstractvarsym(symtableentry).varspez,tabstractvarsym(symtableentry).vardef,pocall_default) then
  335. registersint:=1;
  336. if ([vo_is_thread_var,vo_is_dll_var]*tabstractvarsym(symtableentry).varoptions)<>[] then
  337. registersint:=1;
  338. if (target_info.system=system_powerpc_darwin) and
  339. ([vo_is_dll_var,vo_is_external] * tabstractvarsym(symtableentry).varoptions <> []) then
  340. include(current_procinfo.flags,pi_needs_got);
  341. { call to get address of threadvar }
  342. if (vo_is_thread_var in tabstractvarsym(symtableentry).varoptions) then
  343. include(current_procinfo.flags,pi_do_call);
  344. if nf_write in flags then
  345. Tabstractvarsym(symtableentry).trigger_notifications(vn_onwrite)
  346. else
  347. Tabstractvarsym(symtableentry).trigger_notifications(vn_onread);
  348. { count variable references }
  349. if cg.t_times>1 then
  350. tabstractvarsym(symtableentry).IncRefCountBy(cg.t_times-1);
  351. end;
  352. procsym :
  353. begin
  354. { method pointer ? }
  355. if assigned(left) then
  356. begin
  357. expectloc:=LOC_CREFERENCE;
  358. firstpass(left);
  359. registersint:=max(registersint,left.registersint);
  360. registersfpu:=max(registersfpu,left.registersfpu);
  361. {$ifdef SUPPORT_MMX}
  362. registersmmx:=max(registersmmx,left.registersmmx);
  363. {$endif SUPPORT_MMX}
  364. end;
  365. end;
  366. labelsym :
  367. ;
  368. else
  369. internalerror(200104143);
  370. end;
  371. end;
  372. function tloadnode.docompare(p: tnode): boolean;
  373. begin
  374. docompare :=
  375. inherited docompare(p) and
  376. (symtableentry = tloadnode(p).symtableentry) and
  377. (procdef = tloadnode(p).procdef) and
  378. (symtable = tloadnode(p).symtable);
  379. end;
  380. procedure tloadnode.printnodedata(var t:text);
  381. begin
  382. inherited printnodedata(t);
  383. write(t,printnodeindention,'symbol = ',symtableentry.name);
  384. if symtableentry.typ=procsym then
  385. write(t,printnodeindention,'procdef = ',procdef.mangledname);
  386. writeln(t,'');
  387. end;
  388. procedure tloadnode.setprocdef(p : tprocdef);
  389. begin
  390. procdef:=p;
  391. resultdef:=p;
  392. if po_local in p.procoptions then
  393. CGMessage(type_e_cant_take_address_of_local_subroutine);
  394. end;
  395. {*****************************************************************************
  396. TASSIGNMENTNODE
  397. *****************************************************************************}
  398. constructor tassignmentnode.create(l,r : tnode);
  399. begin
  400. inherited create(assignn,l,r);
  401. l.mark_write;
  402. assigntype:=at_normal;
  403. end;
  404. constructor tassignmentnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  405. begin
  406. inherited ppuload(t,ppufile);
  407. assigntype:=tassigntype(ppufile.getbyte);
  408. end;
  409. procedure tassignmentnode.ppuwrite(ppufile:tcompilerppufile);
  410. begin
  411. inherited ppuwrite(ppufile);
  412. ppufile.putbyte(byte(assigntype));
  413. end;
  414. function tassignmentnode.dogetcopy : tnode;
  415. var
  416. n : tassignmentnode;
  417. begin
  418. n:=tassignmentnode(inherited dogetcopy);
  419. n.assigntype:=assigntype;
  420. result:=n;
  421. end;
  422. function tassignmentnode.pass_typecheck:tnode;
  423. var
  424. hp : tnode;
  425. useshelper : boolean;
  426. begin
  427. result:=nil;
  428. resultdef:=voidtype;
  429. { must be made unique }
  430. set_unique(left);
  431. typecheckpass(left);
  432. typecheckpass(right);
  433. set_varstate(right,vs_read,[vsf_must_be_valid]);
  434. set_varstate(left,vs_written,[]);
  435. if codegenerror then
  436. exit;
  437. { tp procvar support, when we don't expect a procvar
  438. then we need to call the procvar }
  439. if (left.resultdef.typ<>procvardef) then
  440. maybe_call_procvar(right,true);
  441. { assignments to formaldefs and open arrays aren't allowed }
  442. if (left.resultdef.typ=formaldef) or
  443. is_open_array(left.resultdef) then
  444. CGMessage(type_e_assignment_not_allowed);
  445. { test if node can be assigned, properties are allowed }
  446. valid_for_assignment(left,true);
  447. { assigning nil to a dynamic array clears the array }
  448. if is_dynamic_array(left.resultdef) and
  449. (right.nodetype=niln) then
  450. begin
  451. hp:=ccallparanode.create(caddrnode.create_internal
  452. (crttinode.create(tstoreddef(left.resultdef),initrtti)),
  453. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),nil));
  454. result := ccallnode.createintern('fpc_dynarray_clear',hp);
  455. left:=nil;
  456. exit;
  457. end;
  458. { shortstring helpers can do the conversion directly,
  459. so treat them separatly }
  460. if (is_shortstring(left.resultdef)) then
  461. begin
  462. { insert typeconv, except for chars that are handled in
  463. secondpass and except for ansi/wide string that can
  464. be converted immediatly }
  465. if not(is_char(right.resultdef) or
  466. (right.resultdef.typ=stringdef)) then
  467. inserttypeconv(right,left.resultdef);
  468. if right.resultdef.typ=stringdef then
  469. begin
  470. useshelper:=true;
  471. { convert constant strings to shortstrings. But
  472. skip empty constant strings, that will be handled
  473. in secondpass }
  474. if (right.nodetype=stringconstn) then
  475. begin
  476. { verify if range fits within shortstring }
  477. { just emit a warning, delphi gives an }
  478. { error, only if the type definition of }
  479. { of the string is less < 255 characters }
  480. if not is_open_string(left.resultdef) and
  481. (tstringconstnode(right).len > tstringdef(left.resultdef).len) then
  482. cgmessage(type_w_string_too_long);
  483. inserttypeconv(right,left.resultdef);
  484. if (right.nodetype=stringconstn) and
  485. (tstringconstnode(right).len=0) then
  486. useshelper:=false;
  487. end;
  488. { rest is done in pass 1 (JM) }
  489. if useshelper then
  490. exit;
  491. end
  492. end
  493. else
  494. begin
  495. { check if the assignment may cause a range check error }
  496. check_ranges(fileinfo,right,left.resultdef);
  497. inserttypeconv(right,left.resultdef);
  498. end;
  499. { call helpers for interface }
  500. if is_interfacecom(left.resultdef) then
  501. begin
  502. { Normal interface assignments are handled by the generic refcount incr/decr }
  503. if not right.resultdef.is_related(left.resultdef) then
  504. begin
  505. { remove property flag to avoid errors, see comments for }
  506. { tf_winlikewidestring assignments below }
  507. exclude(left.flags,nf_isproperty);
  508. hp:=
  509. ccallparanode.create(
  510. cguidconstnode.create(tobjectdef(left.resultdef).iidguid^),
  511. ccallparanode.create(
  512. ctypeconvnode.create_internal(right,voidpointertype),
  513. ccallparanode.create(
  514. ctypeconvnode.create_internal(left,voidpointertype),
  515. nil)));
  516. result:=ccallnode.createintern('fpc_intf_assign_by_iid',hp);
  517. left:=nil;
  518. right:=nil;
  519. exit;
  520. end;
  521. end
  522. { call helpers for variant, they can contain non ref. counted types like
  523. vararrays which must be really copied }
  524. else if left.resultdef.typ=variantdef then
  525. begin
  526. hp:=ccallparanode.create(ctypeconvnode.create_internal(
  527. caddrnode.create_internal(right),voidpointertype),
  528. ccallparanode.create(ctypeconvnode.create_internal(
  529. caddrnode.create_internal(left),voidpointertype),
  530. nil));
  531. result:=ccallnode.createintern('fpc_variant_copy',hp);
  532. left:=nil;
  533. right:=nil;
  534. exit;
  535. end
  536. { call helpers for composite types containing automated types }
  537. else if (left.resultdef.needs_inittable) and
  538. (left.resultdef.typ in [arraydef,objectdef,recorddef]) then
  539. begin
  540. hp:=ccallparanode.create(caddrnode.create_internal(
  541. crttinode.create(tstoreddef(left.resultdef),initrtti)),
  542. ccallparanode.create(ctypeconvnode.create_internal(
  543. caddrnode.create_internal(left),voidpointertype),
  544. ccallparanode.create(ctypeconvnode.create_internal(
  545. caddrnode.create_internal(right),voidpointertype),
  546. nil)));
  547. result:=ccallnode.createintern('fpc_copy',hp);
  548. left:=nil;
  549. right:=nil;
  550. exit;
  551. end
  552. { call helpers for windows widestrings, they aren't ref. counted }
  553. else if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resultdef) then
  554. begin
  555. hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
  556. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
  557. nil));
  558. result:=ccallnode.createintern('fpc_widestr_assign',hp);
  559. left:=nil;
  560. right:=nil;
  561. exit;
  562. end;
  563. { check if local proc/func is assigned to procvar }
  564. if right.resultdef.typ=procvardef then
  565. test_local_to_procvar(tprocvardef(right.resultdef),left.resultdef);
  566. end;
  567. function tassignmentnode.pass_1 : tnode;
  568. var
  569. hp: tnode;
  570. oldassignmentnode : tassignmentnode;
  571. begin
  572. result:=nil;
  573. expectloc:=LOC_VOID;
  574. firstpass(left);
  575. { Optimize the reuse of the destination of the assingment in left.
  576. Allow the use of the left inside the tree generated on the right.
  577. This is especially usefull for string routines where the destination
  578. is pushed as a parameter. Using the final destination of left directly
  579. save a temp allocation and copy of data (PFV) }
  580. oldassignmentnode:=aktassignmentnode;
  581. if right.nodetype=addn then
  582. aktassignmentnode:=self
  583. else
  584. aktassignmentnode:=nil;
  585. firstpass(right);
  586. aktassignmentnode:=oldassignmentnode;
  587. if nf_assign_done_in_right in flags then
  588. begin
  589. result:=right;
  590. right:=nil;
  591. exit;
  592. end;
  593. if codegenerror then
  594. exit;
  595. { if right is a function call for which the address of the result }
  596. { is allocated by the caller and passed to the function via an }
  597. { invisible function result, try to pass the x in "x:=f(...)" as }
  598. { that function result instead. Condition: x cannot be accessible }
  599. { from within f. This is the case if x is a temp, or x is a local }
  600. { variable or value parameter of the current block and its address }
  601. { is not passed to f. One problem: what if someone takes the }
  602. { address of x, puts it in a pointer variable/field and then }
  603. { accesses it that way from within the function? This is solved }
  604. { (in a conservative way) using the ti_addr_taken/addr_taken flags }
  605. if (cs_opt_level1 in current_settings.optimizerswitches) and
  606. (right.nodetype = calln) and
  607. (right.resultdef=left.resultdef) and
  608. { left must be a temp, since otherwise as soon as you modify the }
  609. { result, the current left node is modified and that one may }
  610. { still be an argument to the function or even accessed in the }
  611. { function }
  612. (
  613. (
  614. (((left.nodetype = temprefn) and
  615. not(ti_addr_taken in ttemprefnode(left).tempinfo^.flags) and
  616. not(ti_may_be_in_reg in ttemprefnode(left).tempinfo^.flags)) or
  617. ((left.nodetype = loadn) and
  618. { nested procedures may access the current procedure's locals }
  619. (tcallnode(right).procdefinition.parast.symtablelevel=normal_function_level) and
  620. { must be a local variable or a value para }
  621. ((tloadnode(left).symtableentry.typ = localvarsym) or
  622. ((tloadnode(left).symtableentry.typ = paravarsym) and
  623. (tparavarsym(tloadnode(left).symtableentry).varspez = vs_value)
  624. )
  625. ) and
  626. { the address may not have been taken of the variable/parameter, because }
  627. { otherwise it's possible that the called function can access it via a }
  628. { global variable or other stored state }
  629. not(tabstractvarsym(tloadnode(left).symtableentry).addr_taken) and
  630. (tabstractvarsym(tloadnode(left).symtableentry).varregable in [vr_none,vr_addr])
  631. )
  632. ) and
  633. paramanager.ret_in_param(right.resultdef,tcallnode(right).procdefinition.proccalloption)
  634. ) or
  635. { there's special support for ansi/widestrings in the callnode }
  636. is_ansistring(right.resultdef) or
  637. is_widestring(right.resultdef)
  638. ) then
  639. begin
  640. if assigned(tcallnode(right).funcretnode) then
  641. internalerror(2007080201);
  642. tcallnode(right).funcretnode := left;
  643. result := right;
  644. left := nil;
  645. right := nil;
  646. exit;
  647. end;
  648. { assignment to refcounted variable -> inc/decref }
  649. if (not is_class(left.resultdef) and
  650. left.resultdef.needs_inittable) then
  651. include(current_procinfo.flags,pi_do_call);
  652. if (is_shortstring(left.resultdef)) then
  653. begin
  654. if right.resultdef.typ=stringdef then
  655. begin
  656. if (right.nodetype<>stringconstn) or
  657. (tstringconstnode(right).len<>0) then
  658. begin
  659. hp:=ccallparanode.create
  660. (right,
  661. ccallparanode.create(cinlinenode.create
  662. (in_high_x,false,left.getcopy),nil));
  663. result:=ccallnode.createinternreturn('fpc_'+tstringdef(right.resultdef).stringtypname+'_to_shortstr',hp,left);
  664. firstpass(result);
  665. left:=nil;
  666. right:=nil;
  667. exit;
  668. end;
  669. end;
  670. end;
  671. registersint:=left.registersint+right.registersint;
  672. registersfpu:=max(left.registersfpu,right.registersfpu);
  673. {$ifdef SUPPORT_MMX}
  674. registersmmx:=max(left.registersmmx,right.registersmmx);
  675. {$endif SUPPORT_MMX}
  676. end;
  677. function tassignmentnode.docompare(p: tnode): boolean;
  678. begin
  679. docompare :=
  680. inherited docompare(p) and
  681. (assigntype = tassignmentnode(p).assigntype);
  682. end;
  683. {$ifdef state_tracking}
  684. function Tassignmentnode.track_state_pass(exec_known:boolean):boolean;
  685. var se:Tstate_entry;
  686. begin
  687. track_state_pass:=false;
  688. if exec_known then
  689. begin
  690. track_state_pass:=right.track_state_pass(exec_known);
  691. {Force a new resultdef pass.}
  692. right.resultdef:=nil;
  693. do_typecheckpass(right);
  694. typecheckpass(right);
  695. aktstate.store_fact(left.getcopy,right.getcopy);
  696. end
  697. else
  698. aktstate.delete_fact(left);
  699. end;
  700. {$endif}
  701. {*****************************************************************************
  702. TARRAYCONSTRUCTORRANGENODE
  703. *****************************************************************************}
  704. constructor tarrayconstructorrangenode.create(l,r : tnode);
  705. begin
  706. inherited create(arrayconstructorrangen,l,r);
  707. end;
  708. function tarrayconstructorrangenode.pass_typecheck:tnode;
  709. begin
  710. result:=nil;
  711. typecheckpass(left);
  712. typecheckpass(right);
  713. set_varstate(left,vs_read,[vsf_must_be_valid]);
  714. set_varstate(right,vs_read,[vsf_must_be_valid]);
  715. if codegenerror then
  716. exit;
  717. resultdef:=left.resultdef;
  718. end;
  719. function tarrayconstructorrangenode.pass_1 : tnode;
  720. begin
  721. firstpass(left);
  722. firstpass(right);
  723. expectloc:=LOC_CREFERENCE;
  724. calcregisters(self,0,0,0);
  725. result:=nil;
  726. end;
  727. {****************************************************************************
  728. TARRAYCONSTRUCTORNODE
  729. *****************************************************************************}
  730. constructor tarrayconstructornode.create(l,r : tnode);
  731. begin
  732. inherited create(arrayconstructorn,l,r);
  733. end;
  734. function tarrayconstructornode.dogetcopy : tnode;
  735. var
  736. n : tarrayconstructornode;
  737. begin
  738. n:=tarrayconstructornode(inherited dogetcopy);
  739. result:=n;
  740. end;
  741. function tarrayconstructornode.pass_typecheck:tnode;
  742. var
  743. hdef : tdef;
  744. hp : tarrayconstructornode;
  745. len : longint;
  746. varia : boolean;
  747. eq : tequaltype;
  748. hnodetype : tnodetype;
  749. begin
  750. result:=nil;
  751. { are we allowing array constructor? Then convert it to a set.
  752. Do this only if we didn't convert the arrayconstructor yet. This
  753. is needed for the cases where the resultdef is forced for a second
  754. run }
  755. if (not allow_array_constructor) then
  756. begin
  757. hp:=tarrayconstructornode(getcopy);
  758. arrayconstructor_to_set(tnode(hp));
  759. result:=hp;
  760. exit;
  761. end;
  762. { only pass left tree, right tree contains next construct if any }
  763. hdef:=nil;
  764. hnodetype:=errorn;
  765. len:=0;
  766. varia:=false;
  767. if assigned(left) then
  768. begin
  769. hp:=self;
  770. while assigned(hp) do
  771. begin
  772. typecheckpass(hp.left);
  773. set_varstate(hp.left,vs_read,[vsf_must_be_valid]);
  774. if (hdef=nil) then
  775. begin
  776. hdef:=hp.left.resultdef;
  777. hnodetype:=hp.left.nodetype;
  778. end
  779. else
  780. begin
  781. { If we got a niln we don't know the type yet and need to take the
  782. type of the next array element.
  783. This is to handle things like [nil,tclass,tclass], see also tw8371 (PFV) }
  784. if hnodetype=niln then
  785. begin
  786. eq:=compare_defs(hp.left.resultdef,hdef,hnodetype);
  787. if eq>te_incompatible then
  788. begin
  789. hdef:=hp.left.resultdef;
  790. hnodetype:=hp.left.nodetype;
  791. end;
  792. end
  793. else
  794. eq:=compare_defs(hdef,hp.left.resultdef,hp.left.nodetype);
  795. if (not varia) and (eq<te_equal) then
  796. begin
  797. { If both are integers we need to take the type that can hold both
  798. defs }
  799. if is_integer(hdef) and is_integer(hp.left.resultdef) then
  800. begin
  801. if is_in_limit(hdef,hp.left.resultdef) then
  802. hdef:=hp.left.resultdef;
  803. end
  804. else
  805. if (nf_novariaallowed in flags) then
  806. varia:=true;
  807. end;
  808. end;
  809. inc(len);
  810. hp:=tarrayconstructornode(hp.right);
  811. end;
  812. end;
  813. { Set the type of empty or varia arrays to void. Also
  814. do this if the type is array of const/open array
  815. because those can't be used with setelementdef }
  816. if not assigned(hdef) or
  817. varia or
  818. is_array_of_const(hdef) or
  819. is_open_array(hdef) then
  820. hdef:=voidtype;
  821. resultdef:=tarraydef.create(0,len-1,s32inttype);
  822. tarraydef(resultdef).elementdef:=hdef;
  823. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  824. if varia then
  825. include(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  826. end;
  827. procedure tarrayconstructornode.force_type(def:tdef);
  828. var
  829. hp : tarrayconstructornode;
  830. begin
  831. tarraydef(resultdef).elementdef:=def;
  832. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  833. exclude(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  834. if assigned(left) then
  835. begin
  836. hp:=self;
  837. while assigned(hp) do
  838. begin
  839. inserttypeconv(hp.left,def);
  840. hp:=tarrayconstructornode(hp.right);
  841. end;
  842. end;
  843. end;
  844. procedure tarrayconstructornode.insert_typeconvs;
  845. var
  846. hp : tarrayconstructornode;
  847. dovariant : boolean;
  848. begin
  849. dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  850. { only pass left tree, right tree contains next construct if any }
  851. if assigned(left) then
  852. begin
  853. hp:=self;
  854. while assigned(hp) do
  855. begin
  856. typecheckpass(hp.left);
  857. { Insert typeconvs for array of const }
  858. if dovariant then
  859. { at this time C varargs are no longer an arrayconstructornode }
  860. insert_varargstypeconv(hp.left,false);
  861. hp:=tarrayconstructornode(hp.right);
  862. end;
  863. end;
  864. end;
  865. function tarrayconstructornode.pass_1 : tnode;
  866. var
  867. hp : tarrayconstructornode;
  868. do_variant:boolean;
  869. begin
  870. do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  871. result:=nil;
  872. { Insert required type convs, this must be
  873. done in pass 1, because the call must be
  874. typecheckpassed already }
  875. if assigned(left) then
  876. begin
  877. insert_typeconvs;
  878. { call firstpass for all nodes }
  879. hp:=self;
  880. while assigned(hp) do
  881. begin
  882. if hp.left<>nil then
  883. begin
  884. {This check is pessimistic; a call will happen depending
  885. on the location in which the elements will be found in
  886. pass 2.}
  887. if not do_variant then
  888. include(current_procinfo.flags,pi_do_call);
  889. firstpass(hp.left);
  890. end;
  891. hp:=tarrayconstructornode(hp.right);
  892. end;
  893. end;
  894. expectloc:=LOC_CREFERENCE;
  895. calcregisters(self,0,0,0);
  896. end;
  897. function tarrayconstructornode.docompare(p: tnode): boolean;
  898. begin
  899. docompare:=inherited docompare(p);
  900. end;
  901. {*****************************************************************************
  902. TTYPENODE
  903. *****************************************************************************}
  904. constructor ttypenode.create(def:tdef);
  905. begin
  906. inherited create(typen);
  907. typedef:=def;
  908. allowed:=false;
  909. end;
  910. constructor ttypenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  911. begin
  912. inherited ppuload(t,ppufile);
  913. ppufile.getderef(typedefderef);
  914. allowed:=boolean(ppufile.getbyte);
  915. end;
  916. procedure ttypenode.ppuwrite(ppufile:tcompilerppufile);
  917. begin
  918. inherited ppuwrite(ppufile);
  919. ppufile.putderef(typedefderef);
  920. ppufile.putbyte(byte(allowed));
  921. end;
  922. procedure ttypenode.buildderefimpl;
  923. begin
  924. inherited buildderefimpl;
  925. typedefderef.build(typedef);
  926. end;
  927. procedure ttypenode.derefimpl;
  928. begin
  929. inherited derefimpl;
  930. typedef:=tdef(typedefderef.resolve);
  931. end;
  932. function ttypenode.pass_typecheck:tnode;
  933. begin
  934. result:=nil;
  935. resultdef:=typedef;
  936. { check if it's valid }
  937. if typedef.typ = errordef then
  938. CGMessage(parser_e_illegal_expression);
  939. end;
  940. function ttypenode.pass_1 : tnode;
  941. begin
  942. result:=nil;
  943. expectloc:=LOC_VOID;
  944. { a typenode can't generate code, so we give here
  945. an error. Else it'll be an abstract error in pass_generate_code.
  946. Only when the allowed flag is set we don't generate
  947. an error }
  948. if not allowed then
  949. Message(parser_e_no_type_not_allowed_here);
  950. end;
  951. function ttypenode.dogetcopy : tnode;
  952. var
  953. n : ttypenode;
  954. begin
  955. n:=ttypenode(inherited dogetcopy);
  956. n.allowed:=allowed;
  957. n.typedef:=typedef;
  958. result:=n;
  959. end;
  960. function ttypenode.docompare(p: tnode): boolean;
  961. begin
  962. docompare :=
  963. inherited docompare(p);
  964. end;
  965. {*****************************************************************************
  966. TRTTINODE
  967. *****************************************************************************}
  968. constructor trttinode.create(def:tstoreddef;rt:trttitype);
  969. begin
  970. inherited create(rttin);
  971. rttidef:=def;
  972. rttitype:=rt;
  973. end;
  974. constructor trttinode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  975. begin
  976. inherited ppuload(t,ppufile);
  977. ppufile.getderef(rttidefderef);
  978. rttitype:=trttitype(ppufile.getbyte);
  979. end;
  980. procedure trttinode.ppuwrite(ppufile:tcompilerppufile);
  981. begin
  982. inherited ppuwrite(ppufile);
  983. ppufile.putderef(rttidefderef);
  984. ppufile.putbyte(byte(rttitype));
  985. end;
  986. procedure trttinode.buildderefimpl;
  987. begin
  988. inherited buildderefimpl;
  989. rttidefderef.build(rttidef);
  990. end;
  991. procedure trttinode.derefimpl;
  992. begin
  993. inherited derefimpl;
  994. rttidef:=tstoreddef(rttidefderef.resolve);
  995. end;
  996. function trttinode.dogetcopy : tnode;
  997. var
  998. n : trttinode;
  999. begin
  1000. n:=trttinode(inherited dogetcopy);
  1001. n.rttidef:=rttidef;
  1002. n.rttitype:=rttitype;
  1003. result:=n;
  1004. end;
  1005. function trttinode.pass_typecheck:tnode;
  1006. begin
  1007. { rtti information will be returned as a void pointer }
  1008. result:=nil;
  1009. resultdef:=voidpointertype;
  1010. end;
  1011. function trttinode.pass_1 : tnode;
  1012. begin
  1013. result:=nil;
  1014. expectloc:=LOC_CREFERENCE;
  1015. end;
  1016. function trttinode.docompare(p: tnode): boolean;
  1017. begin
  1018. docompare :=
  1019. inherited docompare(p) and
  1020. (rttidef = trttinode(p).rttidef) and
  1021. (rttitype = trttinode(p).rttitype);
  1022. end;
  1023. begin
  1024. cloadnode:=tloadnode;
  1025. cassignmentnode:=tassignmentnode;
  1026. carrayconstructorrangenode:=tarrayconstructorrangenode;
  1027. carrayconstructornode:=tarrayconstructornode;
  1028. ctypenode:=ttypenode;
  1029. crttinode:=trttinode;
  1030. end.