nld.pas 40 KB

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