nmem.pas 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  1. {
  2. Copyright (c) 2000-2002 by Florian Klaempfl
  3. Type checking and register allocation for memory related 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 nmem;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. node,
  22. symdef,symsym,symtable,symtype;
  23. type
  24. tloadvmtaddrnode = class(tunarynode)
  25. { unless this is for a call, we have to send the "class" message to
  26. the objctype because the type information only gets initialized
  27. after the first message has been sent -> crash if you pass an
  28. uninitialized type to e.g. class_getInstanceSize() or so. No need
  29. to save to/restore from ppu. }
  30. forcall: boolean;
  31. constructor create(l : tnode);virtual;
  32. function pass_1 : tnode;override;
  33. function pass_typecheck:tnode;override;
  34. function docompare(p: tnode): boolean; override;
  35. function dogetcopy: tnode; override;
  36. end;
  37. tloadvmtaddrnodeclass = class of tloadvmtaddrnode;
  38. tloadparentfpkind = (
  39. { as parameter to a nested routine (current routine's frame) }
  40. lpf_forpara,
  41. { to load a local from a parent routine in the current nested routine
  42. (some parent routine's frame) }
  43. lpf_forload
  44. );
  45. tloadparentfpnode = class(tunarynode)
  46. parentpd : tprocdef;
  47. parentpdderef : tderef;
  48. kind: tloadparentfpkind;
  49. constructor create(pd: tprocdef; fpkind: tloadparentfpkind);virtual;
  50. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  51. procedure ppuwrite(ppufile:tcompilerppufile);override;
  52. procedure buildderefimpl;override;
  53. procedure derefimpl;override;
  54. function pass_1 : tnode;override;
  55. function pass_typecheck:tnode;override;
  56. function docompare(p: tnode): boolean; override;
  57. function dogetcopy : tnode;override;
  58. end;
  59. tloadparentfpnodeclass = class of tloadparentfpnode;
  60. taddrnodeflag = (
  61. { generated by the Ofs() internal function }
  62. anf_ofs,
  63. anf_typedaddr
  64. );
  65. taddrnodeflags = set of taddrnodeflag;
  66. taddrnode = class(tunarynode)
  67. getprocvardef : tprocvardef;
  68. getprocvardefderef : tderef;
  69. addrnodeflags : taddrnodeflags;
  70. constructor create(l : tnode);virtual;
  71. constructor create_internal(l : tnode); virtual;
  72. constructor create_internal_nomark(l : tnode); virtual;
  73. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  74. procedure ppuwrite(ppufile:tcompilerppufile);override;
  75. procedure mark_write;override;
  76. procedure buildderefimpl;override;
  77. procedure derefimpl;override;
  78. procedure printnodeinfo(var t: text); override;
  79. {$ifdef DEBUG_NODE_XML}
  80. procedure XMLPrintNodeInfo(var T: Text); override;
  81. {$endif DEBUG_NODE_XML}
  82. function docompare(p: tnode): boolean; override;
  83. function dogetcopy : tnode;override;
  84. function pass_1 : tnode;override;
  85. function pass_typecheck:tnode;override;
  86. function simplify(forinline : boolean) : tnode; override;
  87. protected
  88. mark_read_written: boolean;
  89. procedure set_labelsym_resultdef; virtual;
  90. function typecheck_non_proc(realsource: tnode; out res: tnode): boolean; virtual;
  91. end;
  92. taddrnodeclass = class of taddrnode;
  93. tderefnode = class(tunarynode)
  94. constructor create(l : tnode);virtual;
  95. function pass_1 : tnode;override;
  96. function pass_typecheck:tnode;override;
  97. procedure mark_write;override;
  98. end;
  99. tderefnodeclass = class of tderefnode;
  100. tsubscriptnode = class(tunarynode)
  101. vs : tfieldvarsym;
  102. vsderef : tderef;
  103. constructor create(varsym : tsym;l : tnode);virtual;
  104. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  105. procedure ppuwrite(ppufile:tcompilerppufile);override;
  106. procedure buildderefimpl;override;
  107. procedure derefimpl;override;
  108. function dogetcopy : tnode;override;
  109. function pass_1 : tnode;override;
  110. function docompare(p: tnode): boolean; override;
  111. function pass_typecheck:tnode;override;
  112. procedure mark_write;override;
  113. procedure printnodedata(var T: Text); override;
  114. {$ifdef DEBUG_NODE_XML}
  115. procedure XMLPrintNodeData(var T: Text); override;
  116. {$endif DEBUG_NODE_XML}
  117. end;
  118. tsubscriptnodeclass = class of tsubscriptnode;
  119. TVecNodeFlag = (
  120. vnf_memindex,
  121. vnf_memseg,
  122. vnf_callunique
  123. );
  124. TVecNodeFlags = set of TVecNodeFlag;
  125. tvecnode = class(tbinarynode)
  126. protected
  127. function first_arraydef: tnode; virtual;
  128. function gen_array_rangecheck: tnode; virtual;
  129. public
  130. vecnodeflags: TVecNodeFlags;
  131. constructor create(l,r : tnode);virtual;
  132. constructor ppuload(t:tnodetype;ppufile:tcompilerppufile);override;
  133. procedure ppuwrite(ppufile:tcompilerppufile);override;
  134. function pass_1 : tnode;override;
  135. function pass_typecheck:tnode;override;
  136. function simplify(forinline : boolean) : tnode; override;
  137. function dogetcopy : tnode;override;
  138. procedure mark_write;override;
  139. {$ifdef DEBUG_NODE_XML}
  140. procedure XMLPrintNodeInfo(var T: Text); override;
  141. procedure XMLPrintNodeData(var T: Text); override;
  142. {$endif DEBUG_NODE_XML}
  143. end;
  144. tvecnodeclass = class of tvecnode;
  145. var
  146. cloadvmtaddrnode : tloadvmtaddrnodeclass= tloadvmtaddrnode;
  147. caddrnode : taddrnodeclass= taddrnode;
  148. cderefnode : tderefnodeclass= tderefnode;
  149. csubscriptnode : tsubscriptnodeclass= tsubscriptnode;
  150. cvecnode : tvecnodeclass= tvecnode;
  151. cloadparentfpnode : tloadparentfpnodeclass = tloadparentfpnode;
  152. function is_big_untyped_addrnode(p: tnode): boolean;
  153. implementation
  154. uses
  155. globtype,systems,constexp,
  156. cutils,verbose,globals,ppu,
  157. symconst,defutil,defcmp,
  158. nadd,nbas,nflw,nutils,objcutil,
  159. wpobase,
  160. {$ifdef i8086}
  161. cpuinfo,
  162. {$endif i8086}
  163. htypechk,pass_1,ncal,nld,ncon,ncnv,cgbase,procinfo,widestr
  164. ;
  165. {*****************************************************************************
  166. TLOADVMTADDRNODE
  167. *****************************************************************************}
  168. constructor tloadvmtaddrnode.create(l : tnode);
  169. begin
  170. inherited create(loadvmtaddrn,l);
  171. end;
  172. function tloadvmtaddrnode.pass_typecheck:tnode;
  173. var
  174. defaultresultdef : boolean;
  175. begin
  176. result:=nil;
  177. typecheckpass(left);
  178. if codegenerror then
  179. exit;
  180. case left.resultdef.typ of
  181. classrefdef :
  182. resultdef:=left.resultdef;
  183. recorddef,
  184. objectdef:
  185. begin
  186. if (left.resultdef.typ=objectdef) or
  187. ((target_info.system in systems_jvm) and
  188. (left.resultdef.typ=recorddef)) then
  189. begin
  190. { access to the classtype while specializing? }
  191. if tstoreddef(left.resultdef).is_generic then
  192. begin
  193. defaultresultdef:=true;
  194. if assigned(current_structdef) then
  195. begin
  196. if assigned(current_structdef.genericdef) then
  197. if current_structdef.genericdef=left.resultdef then
  198. begin
  199. resultdef:=cclassrefdef.create(current_structdef);
  200. defaultresultdef:=false;
  201. end
  202. else
  203. CGMessage(parser_e_cant_create_generics_of_this_type);
  204. end
  205. else
  206. message(parser_e_cant_create_generics_of_this_type);
  207. if defaultresultdef then
  208. resultdef:=cclassrefdef.create(left.resultdef);
  209. end
  210. else
  211. resultdef:=cclassrefdef.create(left.resultdef);
  212. end
  213. else
  214. CGMessage(parser_e_pointer_to_class_expected);
  215. end
  216. else
  217. CGMessage(parser_e_pointer_to_class_expected);
  218. end;
  219. end;
  220. function tloadvmtaddrnode.docompare(p: tnode): boolean;
  221. begin
  222. result:=inherited docompare(p);
  223. if result then
  224. result:=forcall=tloadvmtaddrnode(p).forcall;
  225. end;
  226. function tloadvmtaddrnode.dogetcopy: tnode;
  227. begin
  228. result:=inherited dogetcopy;
  229. tloadvmtaddrnode(result).forcall:=forcall;
  230. end;
  231. function tloadvmtaddrnode.pass_1 : tnode;
  232. var
  233. vs: tsym;
  234. begin
  235. result:=nil;
  236. expectloc:=LOC_REGISTER;
  237. if left.nodetype<>typen then
  238. begin
  239. if (is_objc_class_or_protocol(left.resultdef) or
  240. is_objcclassref(left.resultdef)) then
  241. begin
  242. { on non-fragile ABI platforms, the ISA pointer may be opaque
  243. and we must call Object_getClass to obtain the real ISA
  244. pointer }
  245. if target_info.system in systems_objc_nfabi then
  246. begin
  247. result:=ccallnode.createinternfromunit('OBJC','OBJECT_GETCLASS',ccallparanode.create(left,nil));
  248. inserttypeconv_explicit(result,resultdef);
  249. end
  250. else
  251. result:=objcloadbasefield(left,'ISA');
  252. end
  253. else
  254. result:=ctypeconvnode.create_internal(load_vmt_for_self_node(left),resultdef);
  255. { reused }
  256. left:=nil;
  257. end
  258. else if not is_objcclass(left.resultdef) and
  259. not is_objcclassref(left.resultdef) then
  260. begin
  261. if not(nf_ignore_for_wpo in flags) and
  262. wpoinfomanager.symbol_live_in_currentproc(left.resultdef) then
  263. begin
  264. { keep track of which classes might be instantiated via a classrefdef }
  265. if (left.resultdef.typ=classrefdef) then
  266. tobjectdef(tclassrefdef(left.resultdef).pointeddef).register_maybe_created_object_type
  267. else if (left.resultdef.typ=objectdef) then
  268. tobjectdef(left.resultdef).register_maybe_created_object_type
  269. end
  270. end
  271. else if is_objcclass(left.resultdef) and
  272. not(forcall) then
  273. begin
  274. { call "class" method (= "classclass" in FPC), because otherwise
  275. we may use the class information before it has been
  276. initialized }
  277. vs:=search_struct_member(tobjectdef(left.resultdef),'CLASSCLASS');
  278. if not assigned(vs) or
  279. (vs.typ<>procsym) then
  280. internalerror(2011080601);
  281. { can't reuse "self", because it will be freed when we return }
  282. result:=ccallnode.create(nil,tprocsym(vs),vs.owner,self.getcopy,[],nil);
  283. end;
  284. end;
  285. {*****************************************************************************
  286. TLOADPARENTFPNODE
  287. *****************************************************************************}
  288. constructor tloadparentfpnode.create(pd: tprocdef; fpkind: tloadparentfpkind);
  289. begin
  290. inherited create(loadparentfpn,nil);
  291. if not assigned(pd) then
  292. internalerror(200309288);
  293. if (pd.parast.symtablelevel>current_procinfo.procdef.parast.symtablelevel) then
  294. internalerror(200309284);
  295. parentpd:=pd;
  296. kind:=fpkind;
  297. end;
  298. constructor tloadparentfpnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  299. begin
  300. inherited ppuload(t,ppufile);
  301. ppufile.getderef(parentpdderef);
  302. kind:=tloadparentfpkind(ppufile.getbyte);
  303. end;
  304. procedure tloadparentfpnode.ppuwrite(ppufile:tcompilerppufile);
  305. begin
  306. inherited ppuwrite(ppufile);
  307. ppufile.putderef(parentpdderef);
  308. ppufile.putbyte(byte(kind));
  309. end;
  310. procedure tloadparentfpnode.buildderefimpl;
  311. begin
  312. inherited buildderefimpl;
  313. parentpdderef.build(parentpd);
  314. end;
  315. procedure tloadparentfpnode.derefimpl;
  316. begin
  317. inherited derefimpl;
  318. parentpd:=tprocdef(parentpdderef.resolve);
  319. end;
  320. function tloadparentfpnode.docompare(p: tnode): boolean;
  321. begin
  322. result:=
  323. inherited docompare(p) and
  324. (tloadparentfpnode(p).parentpd=parentpd) and
  325. (tloadparentfpnode(p).kind=kind);
  326. end;
  327. function tloadparentfpnode.dogetcopy : tnode;
  328. var
  329. p : tloadparentfpnode;
  330. begin
  331. p:=tloadparentfpnode(inherited dogetcopy);
  332. p.parentpd:=parentpd;
  333. p.kind:=kind;
  334. dogetcopy:=p;
  335. end;
  336. function tloadparentfpnode.pass_typecheck:tnode;
  337. begin
  338. result:=nil;
  339. resultdef:=parentfpvoidpointertype;
  340. end;
  341. function tloadparentfpnode.pass_1 : tnode;
  342. begin
  343. result:=nil;
  344. expectloc:=LOC_REGISTER;
  345. end;
  346. {*****************************************************************************
  347. TADDRNODE
  348. *****************************************************************************}
  349. constructor taddrnode.create(l : tnode);
  350. begin
  351. inherited create(addrn,l);
  352. getprocvardef:=nil;
  353. addrnodeflags:=[];
  354. mark_read_written := true;
  355. end;
  356. constructor taddrnode.create_internal(l : tnode);
  357. begin
  358. self.create(l);
  359. include(flags,nf_internal);
  360. end;
  361. constructor taddrnode.create_internal_nomark(l : tnode);
  362. begin
  363. self.create_internal(l);
  364. mark_read_written := false;
  365. end;
  366. constructor taddrnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  367. begin
  368. inherited ppuload(t,ppufile);
  369. ppufile.getderef(getprocvardefderef);
  370. ppufile.getset(tppuset1(addrnodeflags));
  371. end;
  372. procedure taddrnode.ppuwrite(ppufile:tcompilerppufile);
  373. begin
  374. inherited ppuwrite(ppufile);
  375. ppufile.putderef(getprocvardefderef);
  376. ppufile.putset(tppuset1(addrnodeflags));
  377. end;
  378. procedure Taddrnode.mark_write;
  379. begin
  380. {@procvar:=nil is legal in Delphi mode.}
  381. left.mark_write;
  382. end;
  383. procedure taddrnode.buildderefimpl;
  384. begin
  385. inherited buildderefimpl;
  386. getprocvardefderef.build(getprocvardef);
  387. end;
  388. procedure taddrnode.derefimpl;
  389. begin
  390. inherited derefimpl;
  391. getprocvardef:=tprocvardef(getprocvardefderef.resolve);
  392. end;
  393. procedure taddrnode.printnodeinfo(var t: text);
  394. var
  395. first: Boolean;
  396. i: taddrnodeflag;
  397. begin
  398. inherited printnodeinfo(t);
  399. write(t,', addrnodeflags = [');
  400. first:=true;
  401. for i:=low(taddrnodeflag) to high(taddrnodeflag) do
  402. if i in addrnodeflags then
  403. begin
  404. if not first then
  405. write(t,',')
  406. else
  407. first:=false;
  408. write(t,i);
  409. end;
  410. write(t,']');
  411. end;
  412. {$ifdef DEBUG_NODE_XML}
  413. procedure TAddrNode.XMLPrintNodeInfo(var T: Text);
  414. var
  415. First: Boolean;
  416. i: TAddrNodeFlag;
  417. begin
  418. inherited XMLPrintNodeInfo(t);
  419. First := True;
  420. for i := Low(TAddrNodeFlag) to High(TAddrNodeFlag) do
  421. if i in addrnodeflags then
  422. begin
  423. if First then
  424. begin
  425. Write(T, ' addrnodeflags="', i);
  426. First := False;
  427. end
  428. else
  429. Write(T, ',', i);
  430. end;
  431. if not First then
  432. Write(T, '"');
  433. end;
  434. {$endif DEBUG_NODE_XML}
  435. function taddrnode.docompare(p: tnode): boolean;
  436. begin
  437. result:=
  438. inherited docompare(p) and
  439. (taddrnode(p).getprocvardef=getprocvardef) and
  440. (taddrnode(p).addrnodeflags=addrnodeflags);
  441. end;
  442. function taddrnode.dogetcopy : tnode;
  443. var
  444. p : taddrnode;
  445. begin
  446. p:=taddrnode(inherited dogetcopy);
  447. p.getprocvardef:=getprocvardef;
  448. p.addrnodeflags:=addrnodeflags;
  449. dogetcopy:=p;
  450. end;
  451. function taddrnode.pass_typecheck:tnode;
  452. procedure check_mark_read_written;
  453. begin
  454. if mark_read_written then
  455. begin
  456. { This is actually only "read", but treat it nevertheless as
  457. modified due to the possible use of pointers
  458. To avoid false positives regarding "uninitialised"
  459. warnings when using arrays, perform it in two steps }
  460. set_varstate(left,vs_written,[]);
  461. { vsf_must_be_valid so it doesn't get changed into
  462. vsf_referred_not_inited }
  463. set_varstate(left,vs_read,[vsf_must_be_valid]);
  464. end;
  465. end;
  466. var
  467. hp : tnode;
  468. hsym : tfieldvarsym;
  469. isprocvar,need_conv_to_voidptr: boolean;
  470. procpointertype: tdef;
  471. begin
  472. result:=nil;
  473. typecheckpass(left);
  474. if codegenerror then
  475. exit;
  476. make_not_regable(left,[ra_addr_regable,ra_addr_taken]);
  477. { don't allow constants, for internal use we also
  478. allow taking the address of strings and sets }
  479. if is_constnode(left) and
  480. not(
  481. (nf_internal in flags) and
  482. (left.nodetype in [stringconstn,setconstn])
  483. ) then
  484. begin
  485. CGMessagePos(left.fileinfo,type_e_no_addr_of_constant);
  486. exit;
  487. end;
  488. { Handle @proc special, also @procvar in tp-mode needs
  489. special handling }
  490. if (left.resultdef.typ=procdef) or
  491. (
  492. { in case of nf_internal, follow the normal FPC semantics so that
  493. we can easily get the actual address of a procvar }
  494. not(nf_internal in flags) and
  495. (left.resultdef.typ=procvardef) and
  496. ((m_tp_procvar in current_settings.modeswitches) or
  497. (m_mac_procvar in current_settings.modeswitches))
  498. ) then
  499. begin
  500. isprocvar:=(left.resultdef.typ=procvardef);
  501. need_conv_to_voidptr:=
  502. (m_tp_procvar in current_settings.modeswitches) or
  503. (m_mac_procvar in current_settings.modeswitches);
  504. if not isprocvar then
  505. begin
  506. left:=ctypeconvnode.create_proc_to_procvar(left);
  507. if need_conv_to_voidptr then
  508. include(ttypeconvnode(left).convnodeflags,tcnf_proc_2_procvar_2_voidpointer);
  509. if anf_ofs in addrnodeflags then
  510. include(ttypeconvnode(left).convnodeflags,tcnf_proc_2_procvar_get_offset_only);
  511. left.fileinfo:=fileinfo;
  512. typecheckpass(left);
  513. end;
  514. { In tp procvar mode the result is always a voidpointer. Insert
  515. a typeconversion to voidpointer. For methodpointers we need
  516. to load the proc field }
  517. if need_conv_to_voidptr then
  518. begin
  519. if tabstractprocdef(left.resultdef).is_addressonly then
  520. begin
  521. if anf_ofs in addrnodeflags then
  522. result:=ctypeconvnode.create_internal(left,tabstractprocdef(left.resultdef).ofs_address_type)
  523. else
  524. result:=ctypeconvnode.create_internal(left,voidcodepointertype);
  525. include(result.flags,nf_load_procvar);
  526. left:=nil;
  527. end
  528. else
  529. begin
  530. { For procvars and for nested routines we need to return
  531. the proc field of the methodpointer }
  532. if isprocvar or
  533. is_nested_pd(tabstractprocdef(left.resultdef)) then
  534. begin
  535. if tabstractprocdef(left.resultdef).is_methodpointer then
  536. procpointertype:=methodpointertype
  537. else
  538. procpointertype:=nestedprocpointertype;
  539. { find proc field in methodpointer record }
  540. hsym:=tfieldvarsym(trecorddef(procpointertype).symtable.Find('proc'));
  541. if not assigned(hsym) then
  542. internalerror(200412041);
  543. { Load tmehodpointer(left).proc }
  544. result:=csubscriptnode.create(
  545. hsym,
  546. ctypeconvnode.create_internal(left,procpointertype));
  547. left:=nil;
  548. end
  549. else
  550. CGMessage(type_e_variable_id_expected);
  551. end;
  552. end
  553. else
  554. begin
  555. check_mark_read_written;
  556. { Return the typeconvn only }
  557. result:=left;
  558. left:=nil;
  559. exit;
  560. end;
  561. end
  562. else
  563. begin
  564. hp:=left;
  565. while assigned(hp) and (hp.nodetype in [typeconvn,derefn,subscriptn]) do
  566. hp:=tunarynode(hp).left;
  567. if not assigned(hp) then
  568. internalerror(200412042);
  569. if typecheck_non_proc(hp,result) then
  570. begin
  571. if assigned(result) then
  572. exit;
  573. end
  574. else
  575. CGMessage(type_e_variable_id_expected);
  576. end;
  577. check_mark_read_written;
  578. if not(assigned(result)) then
  579. result:=simplify(false);
  580. end;
  581. function taddrnode.simplify(forinline : boolean) : tnode;
  582. function compatible_with_offsetof(res : tdef) : boolean;
  583. begin
  584. result:=(res.typ in [recorddef,objectdef]) and not (is_implicit_pointer_object_type(res))
  585. or (res.typ=arraydef) and not (ado_IsDynamicArray in tarraydef(res).arrayoptions);
  586. end;
  587. var
  588. hsym : tfieldvarsym;
  589. hp : tnode;
  590. fieldoffset : asizeint;
  591. resdef : tdef;
  592. index : int64;
  593. begin
  594. result:=nil;
  595. hp:=left;
  596. fieldoffset:=0;
  597. { Attempt to turn
  598. @PSomeType(nil)^.field
  599. or
  600. @SomeType(nil^).fieldA.aryA[3].fieldB.aryB[5]
  601. into a compile-time constant, numerically equal to the offset of the target field in 'SomeType' (and usually cast to 'PtrUint' right away). }
  602. repeat
  603. case hp.nodetype of
  604. subscriptn:
  605. begin
  606. { Here and below, 'hp<>left' detects non-first iteration,
  607. as the first iteration handles deepest field whose type can be arbitrary: 'c' in @PType(nil)^.a.b.c. }
  608. if (hp<>left) and not compatible_with_offsetof(tsubscriptnode(hp).resultdef) then
  609. exit;
  610. hsym:=tsubscriptnode(hp).vs;
  611. if tabstractrecordsymtable(hsym.owner).is_packed then
  612. begin
  613. if hsym.fieldoffset mod 8<>0 then
  614. exit;
  615. inc(fieldoffset,hsym.fieldoffset div 8);
  616. end
  617. else
  618. inc(fieldoffset,hsym.fieldoffset);
  619. hp:=tsubscriptnode(hp).left;
  620. end;
  621. vecn:
  622. begin
  623. if (tvecnode(hp).right.nodetype<>ordconstn) or
  624. (hp<>left) and not compatible_with_offsetof(tvecnode(hp).resultdef) then
  625. exit;
  626. resdef:=tvecnode(hp).left.resultdef;
  627. if not ((resdef.typ=arraydef) and not (ado_IsDynamicArray in tarraydef(resdef).arrayoptions)) then
  628. exit;
  629. index:=tordconstnode(tvecnode(hp).right).value.svalue;
  630. if not ((index>=tarraydef(resdef).lowrange) and (index<=tarraydef(resdef).highrange)) then
  631. exit;
  632. index:=index-tarraydef(resdef).lowrange;
  633. if ado_IsBitPacked in tarraydef(resdef).arrayoptions then
  634. begin
  635. if index*tarraydef(resdef).elepackedbitsize mod 8<>0 then
  636. exit;
  637. inc(fieldoffset,index*tarraydef(resdef).elepackedbitsize div 8);
  638. end
  639. else
  640. inc(fieldoffset,index*tarraydef(resdef).elesize);
  641. hp:=tvecnode(hp).left;
  642. end;
  643. derefn:
  644. begin
  645. { @PObjectType(nil)^.fields? }
  646. if tderefnode(hp).left.nodetype=niln then
  647. result:=cpointerconstnode.create(fieldoffset,resultdef);
  648. exit;
  649. end;
  650. typeconvn:
  651. begin
  652. { @ObjectType(nil^).fields? }
  653. if (ttypeconvnode(hp).left.nodetype=derefn) and
  654. (tderefnode(ttypeconvnode(hp).left).left.nodetype=niln) then
  655. result:=cpointerconstnode.create(fieldoffset,resultdef);
  656. exit;
  657. end;
  658. niln:
  659. { @ClassType(nil).fields. }
  660. exit(cpointerconstnode.create(fieldoffset,resultdef));
  661. else
  662. exit;
  663. end;
  664. until false;
  665. end;
  666. procedure taddrnode.set_labelsym_resultdef;
  667. begin
  668. resultdef:=voidcodepointertype;
  669. end;
  670. function taddrnode.typecheck_non_proc(realsource: tnode; out res: tnode): boolean;
  671. var
  672. hp : tnode;
  673. hsym : tfieldvarsym;
  674. offset: asizeint;
  675. begin
  676. result:=false;
  677. res:=nil;
  678. if (realsource.nodetype=loadn) and
  679. (tloadnode(realsource).symtableentry.typ=labelsym) then
  680. begin
  681. set_labelsym_resultdef;
  682. result:=true;
  683. end
  684. else if (realsource.nodetype=loadn) and
  685. (tloadnode(realsource).symtableentry.typ=absolutevarsym) and
  686. (tabsolutevarsym(tloadnode(realsource).symtableentry).abstyp=toaddr) then
  687. begin
  688. offset:=tabsolutevarsym(tloadnode(realsource).symtableentry).addroffset;
  689. hp:=left;
  690. while assigned(hp)and(hp.nodetype=subscriptn) do
  691. begin
  692. hsym:=tsubscriptnode(hp).vs;
  693. if tabstractrecordsymtable(hsym.owner).is_packed then
  694. begin
  695. { can't calculate the address of a non-byte aligned field }
  696. if (hsym.fieldoffset mod 8)<>0 then
  697. begin
  698. CGMessagePos(hp.fileinfo,parser_e_packed_element_no_var_addr);
  699. exit
  700. end;
  701. inc(offset,hsym.fieldoffset div 8)
  702. end
  703. else
  704. inc(offset,hsym.fieldoffset);
  705. hp:=tunarynode(hp).left;
  706. end;
  707. if anf_typedaddr in addrnodeflags then
  708. res:=cpointerconstnode.create(offset,cpointerdef.getreusable(left.resultdef))
  709. else
  710. res:=cpointerconstnode.create(offset,voidpointertype);
  711. result:=true;
  712. end
  713. else if (nf_internal in flags) or
  714. valid_for_addr(left,true) then
  715. begin
  716. if not(anf_typedaddr in addrnodeflags) then
  717. resultdef:=voidpointertype
  718. else
  719. resultdef:=cpointerdef.getreusable(left.resultdef);
  720. result:=true;
  721. end
  722. end;
  723. function taddrnode.pass_1 : tnode;
  724. begin
  725. result:=nil;
  726. firstpass(left);
  727. if codegenerror then
  728. exit;
  729. { is this right for object of methods ?? }
  730. expectloc:=LOC_REGISTER;
  731. end;
  732. {*****************************************************************************
  733. TDEREFNODE
  734. *****************************************************************************}
  735. constructor tderefnode.create(l : tnode);
  736. begin
  737. inherited create(derefn,l);
  738. end;
  739. function tderefnode.pass_typecheck:tnode;
  740. begin
  741. result:=nil;
  742. typecheckpass(left);
  743. set_varstate(left,vs_read,[vsf_must_be_valid]);
  744. if codegenerror then
  745. exit;
  746. { tp procvar support }
  747. maybe_call_procvar(left,true);
  748. if left.resultdef.typ=pointerdef then
  749. resultdef:=tpointerdef(left.resultdef).pointeddef
  750. else if left.resultdef.typ=undefineddef then
  751. resultdef:=cundefineddef.create(true)
  752. else
  753. CGMessage(parser_e_invalid_qualifier);
  754. end;
  755. procedure Tderefnode.mark_write;
  756. begin
  757. include(flags,nf_write);
  758. end;
  759. function tderefnode.pass_1 : tnode;
  760. begin
  761. result:=nil;
  762. firstpass(left);
  763. if codegenerror then
  764. exit;
  765. expectloc:=LOC_REFERENCE;
  766. end;
  767. {*****************************************************************************
  768. TSUBSCRIPTNODE
  769. *****************************************************************************}
  770. constructor tsubscriptnode.create(varsym : tsym;l : tnode);
  771. begin
  772. inherited create(subscriptn,l);
  773. { vs should be changed to tsym! }
  774. vs:=tfieldvarsym(varsym);
  775. end;
  776. constructor tsubscriptnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  777. begin
  778. inherited ppuload(t,ppufile);
  779. ppufile.getderef(vsderef);
  780. end;
  781. procedure tsubscriptnode.ppuwrite(ppufile:tcompilerppufile);
  782. begin
  783. inherited ppuwrite(ppufile);
  784. ppufile.putderef(vsderef);
  785. end;
  786. procedure tsubscriptnode.buildderefimpl;
  787. begin
  788. inherited buildderefimpl;
  789. vsderef.build(vs);
  790. end;
  791. procedure tsubscriptnode.derefimpl;
  792. begin
  793. inherited derefimpl;
  794. vs:=tfieldvarsym(vsderef.resolve);
  795. end;
  796. function tsubscriptnode.dogetcopy : tnode;
  797. var
  798. p : tsubscriptnode;
  799. begin
  800. p:=tsubscriptnode(inherited dogetcopy);
  801. p.vs:=vs;
  802. dogetcopy:=p;
  803. end;
  804. function tsubscriptnode.pass_typecheck:tnode;
  805. begin
  806. result:=nil;
  807. typecheckpass(left);
  808. { tp procvar support }
  809. maybe_call_procvar(left,true);
  810. resultdef:=vs.vardef;
  811. // don't put records from which we load float fields
  812. // in integer registers
  813. if (left.resultdef.typ=recorddef) and
  814. (resultdef.typ=floatdef) then
  815. make_not_regable(left,[ra_addr_regable]);
  816. end;
  817. procedure Tsubscriptnode.mark_write;
  818. begin
  819. include(flags,nf_write);
  820. { if an element of a record is written, then the whole record is changed/it is written to it,
  821. for data types being implicit pointers this does not apply as the object itself does not change }
  822. if not(is_implicit_pointer_object_type(left.resultdef)) then
  823. left.mark_write;
  824. end;
  825. function tsubscriptnode.pass_1 : tnode;
  826. begin
  827. result:=nil;
  828. firstpass(left);
  829. if codegenerror then
  830. exit;
  831. { several object types must be dereferenced implicitly }
  832. if is_implicit_pointer_object_type(left.resultdef) then
  833. expectloc:=LOC_REFERENCE
  834. else
  835. begin
  836. case left.expectloc of
  837. { if a floating point value is casted into a record, it
  838. can happen that we get here an fpu or mm register }
  839. LOC_CMMREGISTER,
  840. LOC_CFPUREGISTER,
  841. LOC_MMREGISTER,
  842. LOC_FPUREGISTER,
  843. LOC_CONSTANT,
  844. LOC_REGISTER,
  845. LOC_SUBSETREG:
  846. // can happen for function results on win32 and darwin/x86
  847. if (left.resultdef.size > sizeof(pint)) then
  848. expectloc:=LOC_REFERENCE
  849. else
  850. expectloc:=LOC_SUBSETREG;
  851. LOC_CREGISTER,
  852. LOC_CSUBSETREG:
  853. expectloc:=LOC_CSUBSETREG;
  854. LOC_REFERENCE,
  855. LOC_CREFERENCE:
  856. expectloc:=left.expectloc;
  857. else internalerror(20060521);
  858. end;
  859. end;
  860. end;
  861. function tsubscriptnode.docompare(p: tnode): boolean;
  862. begin
  863. docompare :=
  864. inherited docompare(p) and
  865. (vs = tsubscriptnode(p).vs);
  866. end;
  867. procedure tsubscriptnode.printnodedata(var T: Text);
  868. begin
  869. inherited printnodedata(T);
  870. writeln(t,printnodeindention,'field = ',vs.name);
  871. end;
  872. {$ifdef DEBUG_NODE_XML}
  873. procedure TSubscriptNode.XMLPrintNodeData(var T: Text);
  874. begin
  875. inherited XMLPrintNodeData(T);
  876. WriteLn(T, PrintNodeIndention, '<field>', vs.Name, '</field>');
  877. end;
  878. {$endif DEBUG_NODE_XML}
  879. {*****************************************************************************
  880. TVECNODE
  881. *****************************************************************************}
  882. constructor tvecnode.create(l,r : tnode);
  883. begin
  884. inherited create(vecn,l,r);
  885. vecnodeflags := [];
  886. end;
  887. constructor tvecnode.ppuload(t:tnodetype;ppufile:tcompilerppufile);
  888. begin
  889. inherited ppuload(t, ppufile);
  890. ppufile.getset(tppuset1(vecnodeflags));
  891. end;
  892. procedure tvecnode.ppuwrite(ppufile:tcompilerppufile);
  893. begin
  894. inherited ppuwrite(ppufile);
  895. ppufile.putset(tppuset1(vecnodeflags));
  896. end;
  897. function tvecnode.pass_typecheck:tnode;
  898. var
  899. htype,elementdef,elementptrdef : tdef;
  900. newordtyp: tordtype;
  901. valid : boolean;
  902. minvalue, maxvalue: Tconstexprint;
  903. begin
  904. result:=nil;
  905. typecheckpass(left);
  906. typecheckpass(right);
  907. { implicitly convert stringconstant to stringdef,
  908. see tbs/tb0476.pp for a test }
  909. if (left.nodetype=stringconstn) and
  910. (tstringconstnode(left).cst_type=cst_conststring) then
  911. begin
  912. if tstringconstnode(left).len>255 then
  913. inserttypeconv(left,getansistringdef)
  914. else
  915. inserttypeconv(left,cshortstringtype);
  916. end;
  917. { In p[1] p is always valid, it is not possible to
  918. declared a shortstring or normal array that has
  919. undefined number of elements. Dynamic array and
  920. ansi/widestring needs to be valid }
  921. valid:=is_dynamic_array(left.resultdef) or
  922. is_ansistring(left.resultdef) or
  923. is_wide_or_unicode_string(left.resultdef) or
  924. { implicit pointer dereference -> pointer is read }
  925. (left.resultdef.typ = pointerdef);
  926. if valid then
  927. set_varstate(left,vs_read,[vsf_must_be_valid]);
  928. {
  929. A vecn is, just like a loadn, always part of an expression with its
  930. own read/write and must_be_valid semantics. Therefore we don't have
  931. to do anything else here, just like for loadn's
  932. }
  933. set_varstate(right,vs_read,[vsf_must_be_valid]);
  934. if codegenerror then
  935. exit;
  936. { maybe type conversion for the index value, but
  937. do not convert range nodes }
  938. if (right.nodetype<>rangen) then
  939. case left.resultdef.typ of
  940. arraydef:
  941. begin
  942. htype:=Tarraydef(left.resultdef).rangedef;
  943. if ado_isvariant in Tarraydef(left.resultdef).arrayoptions then
  944. {Variant arrays are a special array, can have negative indexes and would therefore
  945. need s32bit. However, they should not appear in a vecn, as they are handled in
  946. handle_variantarray in pexpr.pas. Therefore, encountering a variant array is an
  947. internal error... }
  948. internalerror(200707031)
  949. { open array and array constructor range checking is handled
  950. below at the node level, where the validity of the index
  951. will be checked -> use a regular type conversion to either
  952. the signed or unsigned native int type to prevent another
  953. range check from getting inserted here (unless the type is
  954. larger than the int type). Exception: if it's an ordinal
  955. constant, because then this check should be performed at
  956. compile time }
  957. else if is_open_array(left.resultdef) or
  958. is_array_constructor(left.resultdef) then
  959. begin
  960. if is_signed(right.resultdef) and
  961. not is_constnode(right) then
  962. inserttypeconv(right,sizesinttype)
  963. else
  964. inserttypeconv(right,sizeuinttype)
  965. end
  966. else if is_special_array(left.resultdef) then
  967. {Arrays without a high bound (dynamic arrays, open arrays) are zero based,
  968. convert indexes into these arrays to aword.}
  969. inserttypeconv(right,uinttype)
  970. { note: <> rather than </>, because indexing e.g. an array 0..0
  971. must not result in truncating the indexing value from 2/4/8
  972. bytes to 1 byte (with range checking off, the full index
  973. value must be used) }
  974. else if (htype.typ=enumdef) and
  975. (right.resultdef.typ=enumdef) and
  976. (tenumdef(htype).basedef=tenumdef(right.resultdef).basedef) and
  977. ((tarraydef(left.resultdef).lowrange<>tenumdef(htype).min) or
  978. (tarraydef(left.resultdef).highrange<>tenumdef(htype).max) or
  979. { while we could assume that the value might not be out of range,
  980. memory corruption could have resulted in an illegal value,
  981. so do not skip the type conversion in case of range checking
  982. After all, range checking is a safety mean }
  983. (cs_check_range in current_settings.localswitches)) then
  984. {Convert array indexes to low_bound..high_bound.}
  985. inserttypeconv(right,cenumdef.create_subrange(tenumdef(right.resultdef),
  986. asizeint(Tarraydef(left.resultdef).lowrange),
  987. asizeint(Tarraydef(left.resultdef).highrange)
  988. ))
  989. else if (htype.typ=orddef) and
  990. { right can also be a variant or another type with
  991. overloaded assignment }
  992. (right.resultdef.typ=orddef) and
  993. { don't try to create boolean types with custom ranges }
  994. not is_boolean(right.resultdef) and
  995. { ordtype determines the size of the loaded value -> make
  996. sure we don't truncate }
  997. ((Torddef(right.resultdef).ordtype<>torddef(htype).ordtype) or
  998. (tarraydef(left.resultdef).lowrange<>torddef(htype).low) or
  999. (tarraydef(left.resultdef).highrange<>torddef(htype).high)) then
  1000. {Convert array indexes to low_bound..high_bound.}
  1001. begin
  1002. if (right.resultdef.typ=orddef)
  1003. {$ifndef cpu64bitaddr}
  1004. { do truncate 64 bit values on 32 bit cpus, since
  1005. a) the arrays cannot be > 32 bit anyway
  1006. b) their code generators can't directly handle 64 bit
  1007. loads
  1008. }
  1009. and not is_64bit(right.resultdef)
  1010. {$endif not cpu64bitaddr}
  1011. then
  1012. begin
  1013. { in case of an integer type, we need a new type which covers declaration range and index range,
  1014. see tests/webtbs/tw38413.pp
  1015. This matters only if we sign extend, if the type exceeds the sint range, we can fall back only
  1016. to the index type
  1017. }
  1018. if is_integer(right.resultdef) and ((torddef(right.resultdef).low<0) or (TConstExprInt(Tarraydef(left.resultdef).lowrange)<0)) then
  1019. begin
  1020. minvalue:=min(TConstExprInt(Tarraydef(left.resultdef).lowrange),torddef(right.resultdef).low);
  1021. maxvalue:=max(TConstExprInt(Tarraydef(left.resultdef).highrange),torddef(right.resultdef).high);
  1022. if maxvalue>torddef(sinttype).high then
  1023. newordtyp:=Torddef(right.resultdef).ordtype
  1024. else
  1025. newordtyp:=range_to_basetype(minvalue,maxvalue);
  1026. end
  1027. else
  1028. newordtyp:=Torddef(right.resultdef).ordtype;
  1029. end
  1030. else
  1031. newordtyp:=torddef(sizesinttype).ordtype;
  1032. inserttypeconv(right,corddef.create(newordtyp,
  1033. int64(Tarraydef(left.resultdef).lowrange),
  1034. int64(Tarraydef(left.resultdef).highrange),
  1035. true
  1036. ));
  1037. end
  1038. else
  1039. begin
  1040. inserttypeconv(right,htype);
  1041. { insert type conversion so cse can pick it up }
  1042. if (htype.size<ptrsinttype.size) and is_integer(htype) and not(cs_check_range in current_settings.localswitches) then
  1043. inserttypeconv_internal(right,ptrsinttype);
  1044. end;
  1045. end;
  1046. stringdef:
  1047. if is_open_string(left.resultdef) then
  1048. inserttypeconv(right,u8inttype)
  1049. else if is_shortstring(left.resultdef) then
  1050. {Convert shortstring indexes to 0..length.}
  1051. inserttypeconv(right,corddef.create(u8bit,0,int64(Tstringdef(left.resultdef).len),true))
  1052. else
  1053. {Convert indexes into dynamically allocated strings to aword.}
  1054. inserttypeconv(right,uinttype);
  1055. pointerdef:
  1056. inserttypeconv(right,tpointerdef(left.resultdef).pointer_arithmetic_int_type);
  1057. else
  1058. {Others, (are there any?) indexes to aint.}
  1059. inserttypeconv(right,sinttype);
  1060. end;
  1061. { although we never put regular arrays or shortstrings in registers,
  1062. it's possible that another type was typecasted to a small record
  1063. that has a field of one of these types -> in that case the record
  1064. can't be a regvar either }
  1065. if ((left.resultdef.typ=arraydef) and
  1066. not is_special_array(left.resultdef) and
  1067. { arrays with elements equal to the alu size and with a constant index can be kept in register }
  1068. not(is_constnode(right) and (tarraydef(left.resultdef).elementdef.size=alusinttype.size))) or
  1069. ((left.resultdef.typ=stringdef) and
  1070. (tstringdef(left.resultdef).stringtype in [st_shortstring,st_longstring])) then
  1071. make_not_regable(left,[ra_addr_regable]);
  1072. case left.resultdef.typ of
  1073. arraydef :
  1074. begin
  1075. { check type of the index value }
  1076. if (compare_defs(right.resultdef,tarraydef(left.resultdef).rangedef,right.nodetype)=te_incompatible) then
  1077. IncompatibleTypes(right.resultdef,tarraydef(left.resultdef).rangedef);
  1078. if right.nodetype=rangen then
  1079. resultdef:=left.resultdef
  1080. else
  1081. resultdef:=Tarraydef(left.resultdef).elementdef;
  1082. result:=gen_array_rangecheck;
  1083. if assigned(result) then
  1084. exit;
  1085. { in case of a bitpacked array of enums that are size 2 (due to
  1086. packenum 2) but whose values all fit in one byte, the size of
  1087. bitpacked array elements will be 1 byte while the resultdef of
  1088. will currently say it's two bytes) -> create a temp enumdef
  1089. with packenum=1 for the resultdef as subtype of the main
  1090. enumdef }
  1091. if is_enum(resultdef) and
  1092. is_packed_array(left.resultdef) and
  1093. ((tarraydef(left.resultdef).elepackedbitsize div 8) <> resultdef.size) then
  1094. begin
  1095. resultdef:=cenumdef.create_subrange(tenumdef(resultdef),tenumdef(resultdef).min,tenumdef(resultdef).max);
  1096. tenumdef(resultdef).calcsavesize(1);
  1097. end
  1098. end;
  1099. pointerdef :
  1100. begin
  1101. { are we accessing a pointer[], then convert the pointer to
  1102. an array first, in FPC this is allowed for all pointers
  1103. (except voidpointer) in delphi/tp7 it's only allowed for pchars. }
  1104. if not is_voidpointer(left.resultdef) and
  1105. (
  1106. (cs_pointermath in current_settings.localswitches) or
  1107. tpointerdef(left.resultdef).has_pointer_math or
  1108. is_pchar(left.resultdef) or
  1109. is_pwidechar(left.resultdef)
  1110. ) then
  1111. begin
  1112. { convert pointer to array }
  1113. htype:=carraydef.create_from_pointer(tpointerdef(left.resultdef));
  1114. inserttypeconv(left,htype);
  1115. if right.nodetype=rangen then
  1116. resultdef:=htype
  1117. else
  1118. resultdef:=tarraydef(htype).elementdef;
  1119. end
  1120. else
  1121. CGMessage(type_e_array_required);
  1122. end;
  1123. stringdef :
  1124. begin
  1125. case tstringdef(left.resultdef).stringtype of
  1126. st_unicodestring,
  1127. st_widestring :
  1128. begin
  1129. elementdef:=cwidechartype;
  1130. elementptrdef:=widecharpointertype;
  1131. end;
  1132. st_ansistring,
  1133. st_longstring,
  1134. st_shortstring :
  1135. begin
  1136. elementdef:=cansichartype;
  1137. elementptrdef:=charpointertype;
  1138. end;
  1139. end;
  1140. if right.nodetype=rangen then
  1141. begin
  1142. htype:=carraydef.create_from_pointer(tpointerdef(elementptrdef));
  1143. resultdef:=htype;
  1144. end
  1145. else
  1146. begin
  1147. { indexed access to 0 element is only allowed for shortstrings or if
  1148. zero based strings is turned on }
  1149. if (right.nodetype=ordconstn) and
  1150. (Tordconstnode(right).value.svalue=0) and
  1151. not is_shortstring(left.resultdef) and
  1152. not(cs_zerobasedstrings in current_settings.localswitches) then
  1153. CGMessage(cg_e_can_access_element_zero);
  1154. resultdef:=elementdef;
  1155. end;
  1156. end;
  1157. variantdef :
  1158. resultdef:=cvarianttype;
  1159. else
  1160. CGMessage(type_e_array_required);
  1161. end;
  1162. end;
  1163. procedure Tvecnode.mark_write;
  1164. begin
  1165. include(flags,nf_write);
  1166. { see comment in tsubscriptnode.mark_write }
  1167. if not(is_implicit_array_pointer(left.resultdef)) then
  1168. left.mark_write;
  1169. end;
  1170. function tvecnode.pass_1 : tnode;
  1171. begin
  1172. result:=nil;
  1173. firstpass(left);
  1174. firstpass(right);
  1175. if codegenerror then
  1176. exit;
  1177. if (vnf_callunique in vecnodeflags) and
  1178. (is_ansistring(left.resultdef) or
  1179. is_unicodestring(left.resultdef) or
  1180. (is_widestring(left.resultdef) and not(tf_winlikewidestring in target_info.flags))) then
  1181. begin
  1182. left := ctypeconvnode.create_internal(ccallnode.createintern('fpc_'+tstringdef(left.resultdef).stringtypname+'_unique',
  1183. ccallparanode.create(
  1184. ctypeconvnode.create_internal(left,voidpointertype),nil)),
  1185. left.resultdef);
  1186. firstpass(left);
  1187. { double resultdef passes somwhere else may cause this to be }
  1188. { reset though :/ }
  1189. exclude(vecnodeflags,vnf_callunique);
  1190. end
  1191. else if is_widestring(left.resultdef) and (tf_winlikewidestring in target_info.flags) then
  1192. exclude(vecnodeflags,vnf_callunique);
  1193. { a range node as array index can only appear in function calls, and
  1194. those convert the range node into something else in
  1195. tcallnode.gen_high_tree }
  1196. if (right.nodetype=rangen) then
  1197. CGMessagePos(right.fileinfo,parser_e_illegal_expression)
  1198. else if left.resultdef.typ=arraydef then
  1199. result:=first_arraydef
  1200. else
  1201. begin
  1202. if left.expectloc=LOC_CREFERENCE then
  1203. expectloc:=LOC_CREFERENCE
  1204. else
  1205. expectloc:=LOC_REFERENCE
  1206. end;
  1207. end;
  1208. function tvecnode.simplify(forinline : boolean) : tnode;
  1209. begin
  1210. Result := nil;
  1211. { If left is a string constant and right is an ordinal constant, then
  1212. we can replace the entire branch with an ordinal constant
  1213. corresponding to the character
  1214. }
  1215. if
  1216. { If the address of the result is taken, do not optimise, as the
  1217. pointer of the original string constant is in use }
  1218. not (nf_address_taken in flags) and
  1219. (left.nodetype = stringconstn) and
  1220. (right.nodetype = ordconstn) and
  1221. { Ensure the index is in range }
  1222. (TOrdConstNode(right).value > 0) and
  1223. (TOrdConstNode(right).value <= TStringConstNode(left).len) then
  1224. begin
  1225. { The internal fields are zero-based }
  1226. case TStringConstNode(left).cst_type of
  1227. cst_widestring, cst_unicodestring:
  1228. { value_str is of type PCompilerWideString }
  1229. { while the conversion to PtrUInt is not correct when compiling from an 32 bit to a 64 bit platform because
  1230. in theory for a 64 bit target the string could be longer than 2^32,
  1231. it does not matter as a 32 bit host cannot handle such long strings anyways due to memory limitations
  1232. }
  1233. Result := COrdConstNode.create(
  1234. PCompilerWideString(TStringConstNode(left).value_str)^.data[PtrUInt(TOrdConstNode(right).value.uvalue) - 1],
  1235. resultdef,
  1236. False
  1237. );
  1238. else
  1239. { while the conversion to PtrUInt is not correct when compiling from an 32 bit to a 64 bit platform because
  1240. in theory for a 64 bit target the string could be longer than 2^32,
  1241. it does not matter as a 32 bit host cannot handle such long strings anyways due to memory limitations
  1242. }
  1243. Result := COrdConstNode.create(
  1244. Byte(TStringConstNode(left).value_str[PtrUInt(TOrdConstNode(right).value.uvalue) - 1]),
  1245. resultdef,
  1246. False
  1247. );
  1248. end;
  1249. end;
  1250. end;
  1251. function tvecnode.dogetcopy: tnode;
  1252. var
  1253. n: tvecnode;
  1254. begin
  1255. n:=tvecnode(inherited dogetcopy);
  1256. n.vecnodeflags := vecnodeflags;
  1257. result:=n;
  1258. end;
  1259. function tvecnode.first_arraydef: tnode;
  1260. begin
  1261. result:=nil;
  1262. if (not is_packed_array(left.resultdef)) or
  1263. ((tarraydef(left.resultdef).elepackedbitsize mod 8) = 0) then
  1264. if left.expectloc=LOC_CREFERENCE then
  1265. expectloc:=LOC_CREFERENCE
  1266. else
  1267. expectloc:=LOC_REFERENCE
  1268. else
  1269. if left.expectloc=LOC_CREFERENCE then
  1270. expectloc:=LOC_CSUBSETREF
  1271. else
  1272. expectloc:=LOC_SUBSETREF;
  1273. end;
  1274. function tvecnode.gen_array_rangecheck: tnode;
  1275. var
  1276. htype: tdef;
  1277. temp: ttempcreatenode;
  1278. stat: tstatementnode;
  1279. indextree: tnode;
  1280. hightree: tnode;
  1281. begin
  1282. result:=nil;
  1283. { Range checking an array of const/open array/dynamic array is
  1284. more complicated than regular arrays, because the bounds must
  1285. be checked dynamically. Additionally, in case of array of const
  1286. and open array we need the high parameter, which must not be
  1287. made a regvar in case this is a nested rountine relative to the
  1288. array parameter -> generate te check at the node tree level
  1289. rather than in the code generator }
  1290. if (cs_check_range in current_settings.localswitches) and
  1291. (is_open_array(left.resultdef) or
  1292. is_array_of_const(left.resultdef)) and
  1293. (right.nodetype<>rangen) then
  1294. begin
  1295. { expect to find the load node }
  1296. if get_open_const_array(left).nodetype<>loadn then
  1297. internalerror(2014040601);
  1298. { cdecl functions don't have high() so we can not check the range }
  1299. { (can't use current_procdef, since it may be a nested procedure) }
  1300. if not(tprocdef(tparasymtable(tparavarsym(tloadnode(get_open_const_array(left)).symtableentry).owner).defowner).proccalloption in cdecl_pocalls) then
  1301. begin
  1302. temp:=nil;
  1303. result:=internalstatements(stat);
  1304. { can't use node_complexity here, assumes that the code has
  1305. already been firstpassed }
  1306. if not is_const(right) then
  1307. begin
  1308. temp:=ctempcreatenode.create(right.resultdef,right.resultdef.size,tt_persistent,true);
  1309. addstatement(stat,temp);
  1310. { needed so we can typecheck its temprefnodes }
  1311. typecheckpass(tnode(temp));
  1312. addstatement(stat,cassignmentnode.create(
  1313. ctemprefnode.create(temp),right)
  1314. );
  1315. right:=ctemprefnode.create(temp);
  1316. { right.resultdef is used below }
  1317. typecheckpass(right);
  1318. end;
  1319. { range check will be made explicit here }
  1320. exclude(localswitches,cs_check_range);
  1321. hightree:=load_high_value_node(tparavarsym(tloadnode(
  1322. get_open_const_array(left)).symtableentry));
  1323. { make index unsigned so we only need one comparison;
  1324. lower bound is always zero for these arrays, but
  1325. hightree can be -1 in case the array was empty ->
  1326. add 1 before comparing (ignoring overflows) }
  1327. htype:=get_unsigned_inttype(right.resultdef);
  1328. inserttypeconv_explicit(hightree,htype);
  1329. hightree:=caddnode.create(addn,hightree,genintconstnode(1));
  1330. hightree.localswitches:=hightree.localswitches-[cs_check_range,
  1331. cs_check_overflow];
  1332. indextree:=ctypeconvnode.create_explicit(right.getcopy,htype);
  1333. { range error if index >= hightree+1 }
  1334. addstatement(stat,
  1335. cifnode.create_internal(
  1336. caddnode.create_internal(gten,indextree,hightree),
  1337. ccallnode.createintern('fpc_rangeerror',nil),
  1338. nil
  1339. )
  1340. );
  1341. if assigned(temp) then
  1342. addstatement(stat,ctempdeletenode.create_normal_temp(temp));
  1343. addstatement(stat,self.getcopy);
  1344. end;
  1345. end;
  1346. end;
  1347. {$ifdef DEBUG_NODE_XML}
  1348. procedure TVecNode.XMLPrintNodeInfo(var T: Text);
  1349. var
  1350. i: TVecNodeFlag;
  1351. First: Boolean;
  1352. begin
  1353. inherited XMLPrintNodeInfo(T);
  1354. First := True;
  1355. for i in vecnodeflags do
  1356. begin
  1357. if First then
  1358. begin
  1359. Write(T, ' vecnodeflags="', i);
  1360. First := False;
  1361. end
  1362. else
  1363. Write(T, ',', i)
  1364. end;
  1365. if not First then
  1366. Write(T, '"');
  1367. end;
  1368. procedure TVecNode.XMLPrintNodeData(var T: Text);
  1369. begin
  1370. XMLPrintNode(T, Left);
  1371. { The right node is the index }
  1372. WriteLn(T, PrintNodeIndention, '<index>');
  1373. PrintNodeIndent;
  1374. XMLPrintNode(T, Right);
  1375. PrintNodeUnindent;
  1376. WriteLn(T, PrintNodeIndention, '</index>');
  1377. PrintNodeUnindent;
  1378. WriteLn(T, PrintNodeIndention, '</', nodetype2str[nodetype], '>');
  1379. end;
  1380. {$endif DEBUG_NODE_XML}
  1381. function is_big_untyped_addrnode(p: tnode): boolean;
  1382. begin
  1383. is_big_untyped_addrnode:=(p.nodetype=addrn) and
  1384. not (anf_typedaddr in taddrnode(p).addrnodeflags) and
  1385. (taddrnode(p).left.resultdef.size > 1);
  1386. end;
  1387. end.