nmem.pas 56 KB

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