nld.pas 44 KB

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