nld.pas 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185
  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_proc',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(left,nil));
  662. result:=ccallnode.createintern('fpc_'+tstringdef(right.resultdef).stringtypname+'_to_shortstr',hp);
  663. firstpass(result);
  664. left:=nil;
  665. right:=nil;
  666. exit;
  667. end;
  668. end;
  669. end;
  670. registersint:=left.registersint+right.registersint;
  671. registersfpu:=max(left.registersfpu,right.registersfpu);
  672. {$ifdef SUPPORT_MMX}
  673. registersmmx:=max(left.registersmmx,right.registersmmx);
  674. {$endif SUPPORT_MMX}
  675. end;
  676. function tassignmentnode.docompare(p: tnode): boolean;
  677. begin
  678. docompare :=
  679. inherited docompare(p) and
  680. (assigntype = tassignmentnode(p).assigntype);
  681. end;
  682. {$ifdef state_tracking}
  683. function Tassignmentnode.track_state_pass(exec_known:boolean):boolean;
  684. var se:Tstate_entry;
  685. begin
  686. track_state_pass:=false;
  687. if exec_known then
  688. begin
  689. track_state_pass:=right.track_state_pass(exec_known);
  690. {Force a new resultdef pass.}
  691. right.resultdef:=nil;
  692. do_typecheckpass(right);
  693. typecheckpass(right);
  694. aktstate.store_fact(left.getcopy,right.getcopy);
  695. end
  696. else
  697. aktstate.delete_fact(left);
  698. end;
  699. {$endif}
  700. {*****************************************************************************
  701. TARRAYCONSTRUCTORRANGENODE
  702. *****************************************************************************}
  703. constructor tarrayconstructorrangenode.create(l,r : tnode);
  704. begin
  705. inherited create(arrayconstructorrangen,l,r);
  706. end;
  707. function tarrayconstructorrangenode.pass_typecheck:tnode;
  708. begin
  709. result:=nil;
  710. typecheckpass(left);
  711. typecheckpass(right);
  712. set_varstate(left,vs_read,[vsf_must_be_valid]);
  713. set_varstate(right,vs_read,[vsf_must_be_valid]);
  714. if codegenerror then
  715. exit;
  716. resultdef:=left.resultdef;
  717. end;
  718. function tarrayconstructorrangenode.pass_1 : tnode;
  719. begin
  720. firstpass(left);
  721. firstpass(right);
  722. expectloc:=LOC_CREFERENCE;
  723. calcregisters(self,0,0,0);
  724. result:=nil;
  725. end;
  726. {****************************************************************************
  727. TARRAYCONSTRUCTORNODE
  728. *****************************************************************************}
  729. constructor tarrayconstructornode.create(l,r : tnode);
  730. begin
  731. inherited create(arrayconstructorn,l,r);
  732. end;
  733. function tarrayconstructornode.dogetcopy : tnode;
  734. var
  735. n : tarrayconstructornode;
  736. begin
  737. n:=tarrayconstructornode(inherited dogetcopy);
  738. result:=n;
  739. end;
  740. function tarrayconstructornode.pass_typecheck:tnode;
  741. var
  742. hdef : tdef;
  743. hp : tarrayconstructornode;
  744. len : longint;
  745. varia : boolean;
  746. eq : tequaltype;
  747. hnodetype : tnodetype;
  748. begin
  749. result:=nil;
  750. { are we allowing array constructor? Then convert it to a set.
  751. Do this only if we didn't convert the arrayconstructor yet. This
  752. is needed for the cases where the resultdef is forced for a second
  753. run }
  754. if (not allow_array_constructor) then
  755. begin
  756. hp:=tarrayconstructornode(getcopy);
  757. arrayconstructor_to_set(tnode(hp));
  758. result:=hp;
  759. exit;
  760. end;
  761. { only pass left tree, right tree contains next construct if any }
  762. hdef:=nil;
  763. hnodetype:=errorn;
  764. len:=0;
  765. varia:=false;
  766. if assigned(left) then
  767. begin
  768. hp:=self;
  769. while assigned(hp) do
  770. begin
  771. typecheckpass(hp.left);
  772. set_varstate(hp.left,vs_read,[vsf_must_be_valid]);
  773. if (hdef=nil) then
  774. begin
  775. hdef:=hp.left.resultdef;
  776. hnodetype:=hp.left.nodetype;
  777. end
  778. else
  779. begin
  780. { If we got a niln we don't know the type yet and need to take the
  781. type of the next array element.
  782. This is to handle things like [nil,tclass,tclass], see also tw8371 (PFV) }
  783. if hnodetype=niln then
  784. begin
  785. eq:=compare_defs(hp.left.resultdef,hdef,hnodetype);
  786. if eq>te_incompatible then
  787. begin
  788. hdef:=hp.left.resultdef;
  789. hnodetype:=hp.left.nodetype;
  790. end;
  791. end
  792. else
  793. eq:=compare_defs(hdef,hp.left.resultdef,hp.left.nodetype);
  794. if (not varia) and (eq<te_equal) then
  795. begin
  796. { If both are integers we need to take the type that can hold both
  797. defs }
  798. if is_integer(hdef) and is_integer(hp.left.resultdef) then
  799. begin
  800. if is_in_limit(hdef,hp.left.resultdef) then
  801. hdef:=hp.left.resultdef;
  802. end
  803. else
  804. if (nf_novariaallowed in flags) then
  805. varia:=true;
  806. end;
  807. end;
  808. inc(len);
  809. hp:=tarrayconstructornode(hp.right);
  810. end;
  811. end;
  812. { Set the type of empty or varia arrays to void. Also
  813. do this if the type is array of const/open array
  814. because those can't be used with setelementdef }
  815. if not assigned(hdef) or
  816. varia or
  817. is_array_of_const(hdef) or
  818. is_open_array(hdef) then
  819. hdef:=voidtype;
  820. resultdef:=tarraydef.create(0,len-1,s32inttype);
  821. tarraydef(resultdef).elementdef:=hdef;
  822. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  823. if varia then
  824. include(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  825. end;
  826. procedure tarrayconstructornode.force_type(def:tdef);
  827. var
  828. hp : tarrayconstructornode;
  829. begin
  830. tarraydef(resultdef).elementdef:=def;
  831. include(tarraydef(resultdef).arrayoptions,ado_IsConstructor);
  832. exclude(tarraydef(resultdef).arrayoptions,ado_IsVariant);
  833. if assigned(left) then
  834. begin
  835. hp:=self;
  836. while assigned(hp) do
  837. begin
  838. inserttypeconv(hp.left,def);
  839. hp:=tarrayconstructornode(hp.right);
  840. end;
  841. end;
  842. end;
  843. procedure tarrayconstructornode.insert_typeconvs;
  844. var
  845. hp : tarrayconstructornode;
  846. dovariant : boolean;
  847. begin
  848. dovariant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  849. { only pass left tree, right tree contains next construct if any }
  850. if assigned(left) then
  851. begin
  852. hp:=self;
  853. while assigned(hp) do
  854. begin
  855. typecheckpass(hp.left);
  856. { Insert typeconvs for array of const }
  857. if dovariant then
  858. { at this time C varargs are no longer an arrayconstructornode }
  859. insert_varargstypeconv(hp.left,false);
  860. hp:=tarrayconstructornode(hp.right);
  861. end;
  862. end;
  863. end;
  864. function tarrayconstructornode.pass_1 : tnode;
  865. var
  866. hp : tarrayconstructornode;
  867. do_variant:boolean;
  868. begin
  869. do_variant:=(nf_forcevaria in flags) or (ado_isvariant in tarraydef(resultdef).arrayoptions);
  870. result:=nil;
  871. { Insert required type convs, this must be
  872. done in pass 1, because the call must be
  873. typecheckpassed already }
  874. if assigned(left) then
  875. begin
  876. insert_typeconvs;
  877. { call firstpass for all nodes }
  878. hp:=self;
  879. while assigned(hp) do
  880. begin
  881. if hp.left<>nil then
  882. begin
  883. {This check is pessimistic; a call will happen depending
  884. on the location in which the elements will be found in
  885. pass 2.}
  886. if not do_variant then
  887. include(current_procinfo.flags,pi_do_call);
  888. firstpass(hp.left);
  889. end;
  890. hp:=tarrayconstructornode(hp.right);
  891. end;
  892. end;
  893. expectloc:=LOC_CREFERENCE;
  894. calcregisters(self,0,0,0);
  895. end;
  896. function tarrayconstructornode.docompare(p: tnode): boolean;
  897. begin
  898. docompare:=inherited docompare(p);
  899. end;
  900. {*****************************************************************************
  901. TTYPENODE
  902. *****************************************************************************}
  903. constructor ttypenode.create(def:tdef);
  904. begin
  905. inherited create(typen);
  906. typedef:=def;
  907. allowed:=false;
  908. end;
  909. constructor ttypenode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  910. begin
  911. inherited ppuload(t,ppufile);
  912. ppufile.getderef(typedefderef);
  913. allowed:=boolean(ppufile.getbyte);
  914. end;
  915. procedure ttypenode.ppuwrite(ppufile:tcompilerppufile);
  916. begin
  917. inherited ppuwrite(ppufile);
  918. ppufile.putderef(typedefderef);
  919. ppufile.putbyte(byte(allowed));
  920. end;
  921. procedure ttypenode.buildderefimpl;
  922. begin
  923. inherited buildderefimpl;
  924. typedefderef.build(typedef);
  925. end;
  926. procedure ttypenode.derefimpl;
  927. begin
  928. inherited derefimpl;
  929. typedef:=tdef(typedefderef.resolve);
  930. end;
  931. function ttypenode.pass_typecheck:tnode;
  932. begin
  933. result:=nil;
  934. resultdef:=typedef;
  935. { check if it's valid }
  936. if typedef.typ = errordef then
  937. CGMessage(parser_e_illegal_expression);
  938. end;
  939. function ttypenode.pass_1 : tnode;
  940. begin
  941. result:=nil;
  942. expectloc:=LOC_VOID;
  943. { a typenode can't generate code, so we give here
  944. an error. Else it'll be an abstract error in pass_generate_code.
  945. Only when the allowed flag is set we don't generate
  946. an error }
  947. if not allowed then
  948. Message(parser_e_no_type_not_allowed_here);
  949. end;
  950. function ttypenode.dogetcopy : tnode;
  951. var
  952. n : ttypenode;
  953. begin
  954. n:=ttypenode(inherited dogetcopy);
  955. n.allowed:=allowed;
  956. n.typedef:=typedef;
  957. result:=n;
  958. end;
  959. function ttypenode.docompare(p: tnode): boolean;
  960. begin
  961. docompare :=
  962. inherited docompare(p);
  963. end;
  964. {*****************************************************************************
  965. TRTTINODE
  966. *****************************************************************************}
  967. constructor trttinode.create(def:tstoreddef;rt:trttitype);
  968. begin
  969. inherited create(rttin);
  970. rttidef:=def;
  971. rttitype:=rt;
  972. end;
  973. constructor trttinode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  974. begin
  975. inherited ppuload(t,ppufile);
  976. ppufile.getderef(rttidefderef);
  977. rttitype:=trttitype(ppufile.getbyte);
  978. end;
  979. procedure trttinode.ppuwrite(ppufile:tcompilerppufile);
  980. begin
  981. inherited ppuwrite(ppufile);
  982. ppufile.putderef(rttidefderef);
  983. ppufile.putbyte(byte(rttitype));
  984. end;
  985. procedure trttinode.buildderefimpl;
  986. begin
  987. inherited buildderefimpl;
  988. rttidefderef.build(rttidef);
  989. end;
  990. procedure trttinode.derefimpl;
  991. begin
  992. inherited derefimpl;
  993. rttidef:=tstoreddef(rttidefderef.resolve);
  994. end;
  995. function trttinode.dogetcopy : tnode;
  996. var
  997. n : trttinode;
  998. begin
  999. n:=trttinode(inherited dogetcopy);
  1000. n.rttidef:=rttidef;
  1001. n.rttitype:=rttitype;
  1002. result:=n;
  1003. end;
  1004. function trttinode.pass_typecheck:tnode;
  1005. begin
  1006. { rtti information will be returned as a void pointer }
  1007. result:=nil;
  1008. resultdef:=voidpointertype;
  1009. end;
  1010. function trttinode.pass_1 : tnode;
  1011. begin
  1012. result:=nil;
  1013. expectloc:=LOC_CREFERENCE;
  1014. end;
  1015. function trttinode.docompare(p: tnode): boolean;
  1016. begin
  1017. docompare :=
  1018. inherited docompare(p) and
  1019. (rttidef = trttinode(p).rttidef) and
  1020. (rttitype = trttinode(p).rttitype);
  1021. end;
  1022. begin
  1023. cloadnode:=tloadnode;
  1024. cassignmentnode:=tassignmentnode;
  1025. carrayconstructorrangenode:=tarrayconstructorrangenode;
  1026. carrayconstructornode:=tarrayconstructornode;
  1027. ctypenode:=ttypenode;
  1028. crttinode:=trttinode;
  1029. end.