nld.pas 44 KB

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