nld.pas 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  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. { check if local proc/func is assigned to procvar }
  523. if right.resultdef.typ=procvardef then
  524. test_local_to_procvar(tprocvardef(right.resultdef),left.resultdef);
  525. end;
  526. function tassignmentnode.pass_1 : tnode;
  527. var
  528. hp: tnode;
  529. oldassignmentnode : tassignmentnode;
  530. begin
  531. result:=nil;
  532. expectloc:=LOC_VOID;
  533. firstpass(left);
  534. { Optimize the reuse of the destination of the assingment in left.
  535. Allow the use of the left inside the tree generated on the right.
  536. This is especially usefull for string routines where the destination
  537. is pushed as a parameter. Using the final destination of left directly
  538. save a temp allocation and copy of data (PFV) }
  539. oldassignmentnode:=aktassignmentnode;
  540. if right.nodetype=addn then
  541. aktassignmentnode:=self
  542. else
  543. aktassignmentnode:=nil;
  544. firstpass(right);
  545. aktassignmentnode:=oldassignmentnode;
  546. if nf_assign_done_in_right in flags then
  547. begin
  548. result:=right;
  549. right:=nil;
  550. exit;
  551. end;
  552. if codegenerror then
  553. exit;
  554. { if right is a function call for which the address of the result }
  555. { is allocated by the caller and passed to the function via an }
  556. { invisible function result, try to pass the x in "x:=f(...)" as }
  557. { that function result instead. Condition: x cannot be accessible }
  558. { from within f. This is the case if x is a temp, or x is a local }
  559. { variable or value parameter of the current block and its address }
  560. { is not passed to f. One problem: what if someone takes the }
  561. { address of x, puts it in a pointer variable/field and then }
  562. { accesses it that way from within the function? This is solved }
  563. { (in a conservative way) using the ti_addr_taken/addr_taken flags }
  564. if (cs_opt_level1 in current_settings.optimizerswitches) and
  565. (right.nodetype = calln) and
  566. (right.resultdef=left.resultdef) and
  567. { left must be a temp, since otherwise as soon as you modify the }
  568. { result, the current left node is modified and that one may }
  569. { still be an argument to the function or even accessed in the }
  570. { function }
  571. (
  572. (
  573. (((left.nodetype = temprefn) and
  574. not(ti_addr_taken in ttemprefnode(left).tempinfo^.flags) and
  575. not(ti_may_be_in_reg in ttemprefnode(left).tempinfo^.flags)) or
  576. ((left.nodetype = loadn) and
  577. { nested procedures may access the current procedure's locals }
  578. (tcallnode(right).procdefinition.parast.symtablelevel=normal_function_level) and
  579. { must be a local variable or a value para }
  580. ((tloadnode(left).symtableentry.typ = localvarsym) or
  581. ((tloadnode(left).symtableentry.typ = paravarsym) and
  582. (tparavarsym(tloadnode(left).symtableentry).varspez = vs_value)
  583. )
  584. ) and
  585. { the address may not have been taken of the variable/parameter, because }
  586. { otherwise it's possible that the called function can access it via a }
  587. { global variable or other stored state }
  588. not(tabstractvarsym(tloadnode(left).symtableentry).addr_taken) and
  589. (tabstractvarsym(tloadnode(left).symtableentry).varregable in [vr_none,vr_addr])
  590. )
  591. ) and
  592. paramanager.ret_in_param(right.resultdef,tcallnode(right).procdefinition.proccalloption)
  593. ) or
  594. { there's special support for ansi/widestrings in the callnode }
  595. is_ansistring(right.resultdef) or
  596. is_widestring(right.resultdef)
  597. ) then
  598. begin
  599. if assigned(tcallnode(right).funcretnode) then
  600. internalerror(2007080201);
  601. tcallnode(right).funcretnode := left;
  602. result := right;
  603. left := nil;
  604. right := nil;
  605. exit;
  606. end;
  607. { assignment to refcounted variable -> inc/decref }
  608. if (not is_class(left.resultdef) and
  609. left.resultdef.needs_inittable) then
  610. include(current_procinfo.flags,pi_do_call);
  611. if (is_shortstring(left.resultdef)) then
  612. begin
  613. if right.resultdef.typ=stringdef then
  614. begin
  615. if (right.nodetype<>stringconstn) or
  616. (tstringconstnode(right).len<>0) then
  617. begin
  618. hp:=ccallparanode.create
  619. (right,
  620. ccallparanode.create(left,nil));
  621. result:=ccallnode.createintern('fpc_'+tstringdef(right.resultdef).stringtypname+'_to_shortstr',hp);
  622. firstpass(result);
  623. left:=nil;
  624. right:=nil;
  625. exit;
  626. end;
  627. end;
  628. end
  629. { call helpers for composite types containing automated types }
  630. else if (left.resultdef.needs_inittable) and
  631. (left.resultdef.typ in [arraydef,objectdef,recorddef]) and
  632. not is_interfacecom(left.resultdef) and
  633. not is_dynamic_array(left.resultdef) then
  634. begin
  635. hp:=ccallparanode.create(caddrnode.create_internal(
  636. crttinode.create(tstoreddef(left.resultdef),initrtti)),
  637. ccallparanode.create(ctypeconvnode.create_internal(
  638. caddrnode.create_internal(left),voidpointertype),
  639. ccallparanode.create(ctypeconvnode.create_internal(
  640. caddrnode.create_internal(right),voidpointertype),
  641. nil)));
  642. result:=ccallnode.createintern('fpc_copy_proc',hp);
  643. firstpass(result);
  644. left:=nil;
  645. right:=nil;
  646. exit;
  647. end
  648. { call helpers for variant, they can contain non ref. counted types like
  649. vararrays which must be really copied }
  650. else if left.resultdef.typ=variantdef then
  651. begin
  652. hp:=ccallparanode.create(ctypeconvnode.create_internal(
  653. caddrnode.create_internal(right),voidpointertype),
  654. ccallparanode.create(ctypeconvnode.create_internal(
  655. caddrnode.create_internal(left),voidpointertype),
  656. nil));
  657. result:=ccallnode.createintern('fpc_variant_copy',hp);
  658. firstpass(result);
  659. left:=nil;
  660. right:=nil;
  661. exit;
  662. end
  663. { call helpers for windows widestrings, they aren't ref. counted }
  664. else if (tf_winlikewidestring in target_info.flags) and is_widestring(left.resultdef) then
  665. begin
  666. { The first argument of fpc_widestr_assign is a var parameter. Properties cannot }
  667. { be passed to var or out parameters, because in that case setters/getters are not }
  668. { used. Further, if we would allow it in case there are no getters or setters, you }
  669. { would need source changes in case these are introduced later on, thus defeating }
  670. { part of the transparency advantages of properties. In this particular case, }
  671. { however: }
  672. { a) if there is a setter, this code will not be used since then the assignment }
  673. { will be converted to a procedure call }
  674. { b) the getter is irrelevant, because fpc_widestr_assign must always decrease }
  675. { the refcount of the field to which we are writing }
  676. { c) source code changes are not required if a setter is added/removed, because }
  677. { this transformation is handled at compile time }
  678. { -> we can remove the nf_isproperty flag (if any) from left, so that in case it }
  679. { is a property which refers to a field without a setter call, we will not get }
  680. { an error about trying to pass a property as a var parameter }
  681. exclude(left.flags,nf_isproperty);
  682. hp:=ccallparanode.create(ctypeconvnode.create_internal(right,voidpointertype),
  683. ccallparanode.create(ctypeconvnode.create_internal(left,voidpointertype),
  684. nil));
  685. result:=ccallnode.createintern('fpc_widestr_assign',hp);
  686. firstpass(result);
  687. left:=nil;
  688. right:=nil;
  689. exit;
  690. end;
  691. registersint:=left.registersint+right.registersint;
  692. registersfpu:=max(left.registersfpu,right.registersfpu);
  693. {$ifdef SUPPORT_MMX}
  694. registersmmx:=max(left.registersmmx,right.registersmmx);
  695. {$endif SUPPORT_MMX}
  696. end;
  697. function tassignmentnode.docompare(p: tnode): boolean;
  698. begin
  699. docompare :=
  700. inherited docompare(p) and
  701. (assigntype = tassignmentnode(p).assigntype);
  702. end;
  703. {$ifdef state_tracking}
  704. function Tassignmentnode.track_state_pass(exec_known:boolean):boolean;
  705. var se:Tstate_entry;
  706. begin
  707. track_state_pass:=false;
  708. if exec_known then
  709. begin
  710. track_state_pass:=right.track_state_pass(exec_known);
  711. {Force a new resultdef pass.}
  712. right.resultdef:=nil;
  713. do_typecheckpass(right);
  714. typecheckpass(right);
  715. aktstate.store_fact(left.getcopy,right.getcopy);
  716. end
  717. else
  718. aktstate.delete_fact(left);
  719. end;
  720. {$endif}
  721. {*****************************************************************************
  722. TARRAYCONSTRUCTORRANGENODE
  723. *****************************************************************************}
  724. constructor tarrayconstructorrangenode.create(l,r : tnode);
  725. begin
  726. inherited create(arrayconstructorrangen,l,r);
  727. end;
  728. function tarrayconstructorrangenode.pass_typecheck:tnode;
  729. begin
  730. result:=nil;
  731. typecheckpass(left);
  732. typecheckpass(right);
  733. set_varstate(left,vs_read,[vsf_must_be_valid]);
  734. set_varstate(right,vs_read,[vsf_must_be_valid]);
  735. if codegenerror then
  736. exit;
  737. resultdef:=left.resultdef;
  738. end;
  739. function tarrayconstructorrangenode.pass_1 : tnode;
  740. begin
  741. firstpass(left);
  742. firstpass(right);
  743. expectloc:=LOC_CREFERENCE;
  744. calcregisters(self,0,0,0);
  745. result:=nil;
  746. end;
  747. {****************************************************************************
  748. TARRAYCONSTRUCTORNODE
  749. *****************************************************************************}
  750. constructor tarrayconstructornode.create(l,r : tnode);
  751. begin
  752. inherited create(arrayconstructorn,l,r);
  753. end;
  754. function tarrayconstructornode.dogetcopy : tnode;
  755. var
  756. n : tarrayconstructornode;
  757. begin
  758. n:=tarrayconstructornode(inherited dogetcopy);
  759. result:=n;
  760. end;
  761. function tarrayconstructornode.pass_typecheck:tnode;
  762. var
  763. hdef : tdef;
  764. hp : tarrayconstructornode;
  765. len : longint;
  766. varia : boolean;
  767. eq : tequaltype;
  768. hnodetype : tnodetype;
  769. begin
  770. result:=nil;
  771. { are we allowing array constructor? Then convert it to a set.
  772. Do this only if we didn't convert the arrayconstructor yet. This
  773. is needed for the cases where the resultdef is forced for a second
  774. run }
  775. if (not allow_array_constructor) then
  776. begin
  777. hp:=tarrayconstructornode(getcopy);
  778. arrayconstructor_to_set(tnode(hp));
  779. result:=hp;
  780. exit;
  781. end;
  782. { only pass left tree, right tree contains next construct if any }
  783. hdef:=nil;
  784. hnodetype:=errorn;
  785. len:=0;
  786. varia:=false;
  787. if assigned(left) then
  788. begin
  789. hp:=self;
  790. while assigned(hp) do
  791. begin
  792. typecheckpass(hp.left);
  793. set_varstate(hp.left,vs_read,[vsf_must_be_valid]);
  794. if (hdef=nil) then
  795. begin
  796. hdef:=hp.left.resultdef;
  797. hnodetype:=hp.left.nodetype;
  798. end
  799. else
  800. begin
  801. { If we got a niln we don't know the type yet and need to take the
  802. type of the next array element.
  803. This is to handle things like [nil,tclass,tclass], see also tw8371 (PFV) }
  804. if hnodetype=niln then
  805. begin
  806. eq:=compare_defs(hp.left.resultdef,hdef,hnodetype);
  807. if eq>te_incompatible then
  808. begin
  809. hdef:=hp.left.resultdef;
  810. hnodetype:=hp.left.nodetype;
  811. end;
  812. end
  813. else
  814. eq:=compare_defs(hdef,hp.left.resultdef,hp.left.nodetype);
  815. if (not varia) and (eq<te_equal) then
  816. begin
  817. { If both are integers we need to take the type that can hold both
  818. defs }
  819. if is_integer(hdef) and is_integer(hp.left.resultdef) then
  820. begin
  821. if is_in_limit(hdef,hp.left.resultdef) then
  822. hdef:=hp.left.resultdef;
  823. end
  824. else
  825. if (nf_novariaallowed in flags) then
  826. varia:=true;
  827. end;
  828. end;
  829. inc(len);
  830. hp:=tarrayconstructornode(hp.right);
  831. end;
  832. end;
  833. { Set the type of empty or varia arrays to void. Also
  834. do this if the type is array of const/open array
  835. because those can't be used with setelementdef }
  836. if not assigned(hdef) or
  837. varia or
  838. is_array_of_const(hdef) or
  839. is_open_array(hdef) then
  840. hdef:=voidtype;
  841. resultdef:=tarraydef.create(0,len-1,s32inttype);
  842. tarraydef(resultdef).elementdef:=hdef;
  843. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  844. if varia then
  845. include(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  846. end;
  847. procedure tarrayconstructornode.force_type(def:tdef);
  848. var
  849. hp : tarrayconstructornode;
  850. begin
  851. tarraydef(resultdef).elementdef:=def;
  852. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  853. exclude(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  854. if assigned(left) then
  855. begin
  856. hp:=self;
  857. while assigned(hp) do
  858. begin
  859. inserttypeconv(hp.left,def);
  860. hp:=tarrayconstructornode(hp.right);
  861. end;
  862. end;
  863. end;
  864. procedure tarrayconstructornode.insert_typeconvs;
  865. var
  866. hp : tarrayconstructornode;
  867. dovariant : boolean;
  868. begin
  869. dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  870. { only pass left tree, right tree contains next construct if any }
  871. if assigned(left) then
  872. begin
  873. hp:=self;
  874. while assigned(hp) do
  875. begin
  876. typecheckpass(hp.left);
  877. { Insert typeconvs for array of const }
  878. if dovariant then
  879. { at this time C varargs are no longer an arrayconstructornode }
  880. insert_varargstypeconv(hp.left,false);
  881. hp:=tarrayconstructornode(hp.right);
  882. end;
  883. end;
  884. end;
  885. function tarrayconstructornode.pass_1 : tnode;
  886. var
  887. hp : tarrayconstructornode;
  888. do_variant:boolean;
  889. begin
  890. do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  891. result:=nil;
  892. { Insert required type convs, this must be
  893. done in pass 1, because the call must be
  894. typecheckpassed already }
  895. if assigned(left) then
  896. begin
  897. insert_typeconvs;
  898. { call firstpass for all nodes }
  899. hp:=self;
  900. while assigned(hp) do
  901. begin
  902. if hp.left<>nil then
  903. begin
  904. {This check is pessimistic; a call will happen depending
  905. on the location in which the elements will be found in
  906. pass 2.}
  907. if not do_variant then
  908. include(current_procinfo.flags,pi_do_call);
  909. firstpass(hp.left);
  910. end;
  911. hp:=tarrayconstructornode(hp.right);
  912. end;
  913. end;
  914. expectloc:=LOC_CREFERENCE;
  915. calcregisters(self,0,0,0);
  916. end;
  917. function tarrayconstructornode.docompare(p: tnode): boolean;
  918. begin
  919. docompare:=inherited docompare(p);
  920. end;
  921. {*****************************************************************************
  922. TTYPENODE
  923. *****************************************************************************}
  924. constructor ttypenode.create(def:tdef);
  925. begin
  926. inherited create(typen);
  927. typedef:=def;
  928. allowed:=false;
  929. end;
  930. constructor ttypenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  931. begin
  932. inherited ppuload(t,ppufile);
  933. ppufile.getderef(typedefderef);
  934. allowed:=boolean(ppufile.getbyte);
  935. end;
  936. procedure ttypenode.ppuwrite(ppufile:tcompilerppufile);
  937. begin
  938. inherited ppuwrite(ppufile);
  939. ppufile.putderef(typedefderef);
  940. ppufile.putbyte(byte(allowed));
  941. end;
  942. procedure ttypenode.buildderefimpl;
  943. begin
  944. inherited buildderefimpl;
  945. typedefderef.build(typedef);
  946. end;
  947. procedure ttypenode.derefimpl;
  948. begin
  949. inherited derefimpl;
  950. typedef:=tdef(typedefderef.resolve);
  951. end;
  952. function ttypenode.pass_typecheck:tnode;
  953. begin
  954. result:=nil;
  955. resultdef:=typedef;
  956. { check if it's valid }
  957. if typedef.typ = errordef then
  958. CGMessage(parser_e_illegal_expression);
  959. end;
  960. function ttypenode.pass_1 : tnode;
  961. begin
  962. result:=nil;
  963. expectloc:=LOC_VOID;
  964. { a typenode can't generate code, so we give here
  965. an error. Else it'll be an abstract error in pass_generate_code.
  966. Only when the allowed flag is set we don't generate
  967. an error }
  968. if not allowed then
  969. Message(parser_e_no_type_not_allowed_here);
  970. end;
  971. function ttypenode.dogetcopy : tnode;
  972. var
  973. n : ttypenode;
  974. begin
  975. n:=ttypenode(inherited dogetcopy);
  976. n.allowed:=allowed;
  977. n.typedef:=typedef;
  978. result:=n;
  979. end;
  980. function ttypenode.docompare(p: tnode): boolean;
  981. begin
  982. docompare :=
  983. inherited docompare(p);
  984. end;
  985. {*****************************************************************************
  986. TRTTINODE
  987. *****************************************************************************}
  988. constructor trttinode.create(def:tstoreddef;rt:trttitype);
  989. begin
  990. inherited create(rttin);
  991. rttidef:=def;
  992. rttitype:=rt;
  993. end;
  994. constructor trttinode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  995. begin
  996. inherited ppuload(t,ppufile);
  997. ppufile.getderef(rttidefderef);
  998. rttitype:=trttitype(ppufile.getbyte);
  999. end;
  1000. procedure trttinode.ppuwrite(ppufile:tcompilerppufile);
  1001. begin
  1002. inherited ppuwrite(ppufile);
  1003. ppufile.putderef(rttidefderef);
  1004. ppufile.putbyte(byte(rttitype));
  1005. end;
  1006. procedure trttinode.buildderefimpl;
  1007. begin
  1008. inherited buildderefimpl;
  1009. rttidefderef.build(rttidef);
  1010. end;
  1011. procedure trttinode.derefimpl;
  1012. begin
  1013. inherited derefimpl;
  1014. rttidef:=tstoreddef(rttidefderef.resolve);
  1015. end;
  1016. function trttinode.dogetcopy : tnode;
  1017. var
  1018. n : trttinode;
  1019. begin
  1020. n:=trttinode(inherited dogetcopy);
  1021. n.rttidef:=rttidef;
  1022. n.rttitype:=rttitype;
  1023. result:=n;
  1024. end;
  1025. function trttinode.pass_typecheck:tnode;
  1026. begin
  1027. { rtti information will be returned as a void pointer }
  1028. result:=nil;
  1029. resultdef:=voidpointertype;
  1030. end;
  1031. function trttinode.pass_1 : tnode;
  1032. begin
  1033. result:=nil;
  1034. expectloc:=LOC_CREFERENCE;
  1035. end;
  1036. function trttinode.docompare(p: tnode): boolean;
  1037. begin
  1038. docompare :=
  1039. inherited docompare(p) and
  1040. (rttidef = trttinode(p).rttidef) and
  1041. (rttitype = trttinode(p).rttitype);
  1042. end;
  1043. begin
  1044. cloadnode:=tloadnode;
  1045. cassignmentnode:=tassignmentnode;
  1046. carrayconstructorrangenode:=tarrayconstructorrangenode;
  1047. carrayconstructornode:=tarrayconstructornode;
  1048. ctypenode:=ttypenode;
  1049. crttinode:=trttinode;
  1050. end.