2
0

nmem.pas 59 KB

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