nld.pas 42 KB

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