pparautl.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
  3. Helpers for dealing with subroutine parameters during parsing
  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 pparautl;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. symdef;
  22. procedure insert_funcret_para(pd:tabstractprocdef);
  23. procedure insert_parentfp_para(pd:tabstractprocdef);
  24. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  25. procedure insert_funcret_local(pd:tprocdef);
  26. procedure insert_hidden_para(p:TObject;arg:pointer);
  27. procedure check_c_para(pd:Tabstractprocdef);
  28. implementation
  29. uses
  30. globals,globtype,verbose,systems,
  31. symconst,symtype,symbase,symsym,symtable,symcreat,defutil,blockutl,
  32. paramgr;
  33. procedure insert_funcret_para(pd:tabstractprocdef);
  34. var
  35. storepos : tfileposinfo;
  36. vs : tparavarsym;
  37. paranr : word;
  38. begin
  39. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  40. not is_void(pd.returndef) and
  41. not (df_generic in pd.defoptions) and
  42. paramanager.ret_in_param(pd.returndef,pd) then
  43. begin
  44. storepos:=current_tokenpos;
  45. if pd.typ=procdef then
  46. current_tokenpos:=tprocdef(pd).fileinfo;
  47. {$if defined(i386)}
  48. { For left to right add it at the end to be delphi compatible.
  49. In the case of safecalls with safecal-exceptions support the
  50. funcret-para is (from the 'c'-point of view) a normal parameter
  51. which has to be added to the end of the parameter-list }
  52. if (pd.proccalloption in (pushleftright_pocalls)) or
  53. ((tf_safecall_exceptions in target_info.flags) and
  54. (pd.proccalloption=pocall_safecall)) then
  55. paranr:=paranr_result_leftright
  56. else
  57. {$elseif defined(SUPPORT_SAFECALL)}
  58. if (tf_safecall_exceptions in target_info.flags) and
  59. (pd.proccalloption = pocall_safecall) then
  60. paranr:=paranr_result_leftright
  61. else
  62. {$endif}
  63. paranr:=paranr_result;
  64. { Generate result variable accessing function result }
  65. vs:=cparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
  66. pd.parast.insert(vs);
  67. { Store this symbol as funcretsym for procedures }
  68. if pd.typ=procdef then
  69. tprocdef(pd).funcretsym:=vs;
  70. current_tokenpos:=storepos;
  71. end;
  72. end;
  73. procedure insert_parentfp_para(pd:tabstractprocdef);
  74. var
  75. storepos : tfileposinfo;
  76. vs : tparavarsym;
  77. paranr : longint;
  78. begin
  79. if pd.parast.symtablelevel>normal_function_level then
  80. begin
  81. storepos:=current_tokenpos;
  82. if pd.typ=procdef then
  83. current_tokenpos:=tprocdef(pd).fileinfo;
  84. { if no support for nested procvars is activated, use the old
  85. calling convention to pass the parent frame pointer for backwards
  86. compatibility }
  87. if not(m_nested_procvars in current_settings.modeswitches) then
  88. paranr:=paranr_parentfp
  89. { nested procvars require Delphi-style parentfp passing, see
  90. po_delphi_nested_cc declaration for more info }
  91. {$if defined(i386) or defined(i8086)}
  92. else if (pd.proccalloption in pushleftright_pocalls) then
  93. paranr:=paranr_parentfp_delphi_cc_leftright
  94. {$endif i386 or i8086}
  95. else
  96. paranr:=paranr_parentfp_delphi_cc;
  97. { Generate frame pointer. It can't be put in a register since it
  98. must be accessable from nested routines }
  99. if not(target_info.system in systems_fpnestedstruct) or
  100. { in case of errors or declared procvardef types, prevent invalid
  101. type cast and possible nil pointer dereference }
  102. not assigned(pd.owner.defowner) or
  103. (pd.owner.defowner.typ<>procdef) then
  104. begin
  105. vs:=cparavarsym.create('$parentfp',paranr,vs_value
  106. ,parentfpvoidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
  107. vs.varregable:=vr_none;
  108. end
  109. else
  110. begin
  111. if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
  112. build_parentfpstruct(tprocdef(pd.owner.defowner));
  113. vs:=cparavarsym.create('$parentfp',paranr,vs_value
  114. ,tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
  115. end;
  116. pd.parast.insert(vs);
  117. current_tokenpos:=storepos;
  118. end;
  119. end;
  120. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  121. var
  122. storepos : tfileposinfo;
  123. vs : tparavarsym;
  124. hdef : tdef;
  125. selfdef : tdef;
  126. vsp : tvarspez;
  127. aliasvs : tabsolutevarsym;
  128. sl : tpropaccesslist;
  129. begin
  130. if (pd.typ=procdef) and
  131. is_objc_class_or_protocol(tprocdef(pd).struct) and
  132. (pd.parast.symtablelevel=normal_function_level) then
  133. begin
  134. { insert Objective-C self and selector parameters }
  135. vs:=cparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
  136. pd.parast.insert(vs);
  137. { make accessible to code }
  138. sl:=tpropaccesslist.create;
  139. sl.addsym(sl_load,vs);
  140. aliasvs:=cabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
  141. include(aliasvs.varoptions,vo_is_msgsel);
  142. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  143. if (po_classmethod in pd.procoptions) then
  144. { compatible with what gcc does }
  145. hdef:=objc_idtype
  146. else
  147. hdef:=tprocdef(pd).struct;
  148. vs:=cparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
  149. pd.parast.insert(vs);
  150. end
  151. else if (pd.typ=procvardef) and
  152. pd.is_methodpointer then
  153. begin
  154. { Generate self variable }
  155. vs:=cparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
  156. pd.parast.insert(vs);
  157. end
  158. { while only procvardefs of this type can be declared in Pascal code,
  159. internally we also generate procdefs of this type when creating
  160. block wrappers }
  161. else if (po_is_block in pd.procoptions) then
  162. begin
  163. { generate the first hidden parameter, which is a so-called "block
  164. literal" describing the block and containing its invocation
  165. procedure }
  166. hdef:=cpointerdef.getreusable(get_block_literal_type_for_proc(pd));
  167. { mark as vo_is_parentfp so that proc2procvar comparisons will
  168. succeed when assigning arbitrary routines to the block }
  169. vs:=cparavarsym.create('$_block_literal',paranr_blockselfpara,vs_value,
  170. hdef,[vo_is_hidden_para,vo_is_parentfp]
  171. );
  172. pd.parast.insert(vs);
  173. if pd.typ=procdef then
  174. begin
  175. { make accessible to code }
  176. sl:=tpropaccesslist.create;
  177. sl.addsym(sl_load,vs);
  178. aliasvs:=cabsolutevarsym.create_ref('FPC_BLOCK_SELF',hdef,sl);
  179. include(aliasvs.varoptions,vo_is_parentfp);
  180. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  181. end;
  182. end
  183. else
  184. begin
  185. if (pd.typ=procdef) and
  186. assigned(tprocdef(pd).struct) and
  187. (pd.parast.symtablelevel=normal_function_level) then
  188. begin
  189. { static class methods have no hidden self/vmt pointer }
  190. if pd.no_self_node then
  191. exit;
  192. storepos:=current_tokenpos;
  193. current_tokenpos:=tprocdef(pd).fileinfo;
  194. { Generate VMT variable for constructor/destructor }
  195. if (pd.proctypeoption in [potype_constructor,potype_destructor]) and
  196. not(is_cppclass(tprocdef(pd).struct) or
  197. is_record(tprocdef(pd).struct) or
  198. is_javaclass(tprocdef(pd).struct) or
  199. (
  200. { no vmt for record/type helper constructors }
  201. is_objectpascal_helper(tprocdef(pd).struct) and
  202. (tobjectdef(tprocdef(pd).struct).extendeddef.typ<>objectdef)
  203. )) then
  204. begin
  205. vs:=cparavarsym.create('$vmt',paranr_vmt,vs_value,cclassrefdef.create(tprocdef(pd).struct),[vo_is_vmt,vo_is_hidden_para]);
  206. pd.parast.insert(vs);
  207. end;
  208. { for helpers the type of Self is equivalent to the extended
  209. type or equal to an instance of it }
  210. if is_objectpascal_helper(tprocdef(pd).struct) then
  211. selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
  212. else if is_objccategory(tprocdef(pd).struct) then
  213. selfdef:=tobjectdef(tprocdef(pd).struct).childof
  214. else
  215. selfdef:=tprocdef(pd).struct;
  216. { Generate self variable, for classes we need
  217. to use the generic voidpointer to be compatible with
  218. methodpointers }
  219. vsp:=vs_value;
  220. if (po_staticmethod in pd.procoptions) or
  221. (po_classmethod in pd.procoptions) then
  222. hdef:=cclassrefdef.create(selfdef)
  223. else
  224. begin
  225. if is_object(selfdef) or (selfdef.typ<>objectdef) then
  226. vsp:=vs_var;
  227. hdef:=selfdef;
  228. end;
  229. vs:=cparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
  230. pd.parast.insert(vs);
  231. current_tokenpos:=storepos;
  232. end;
  233. end;
  234. end;
  235. procedure insert_funcret_local(pd:tprocdef);
  236. var
  237. storepos : tfileposinfo;
  238. vs : tlocalvarsym;
  239. aliasvs : tabsolutevarsym;
  240. sl : tpropaccesslist;
  241. hs : string;
  242. begin
  243. { The result from constructors and destructors can't be accessed directly }
  244. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  245. not is_void(pd.returndef) and
  246. (not(po_assembler in pd.procoptions) or paramanager.asm_result_var(pd.returndef,pd)) then
  247. begin
  248. storepos:=current_tokenpos;
  249. current_tokenpos:=pd.fileinfo;
  250. { We need to insert a varsym for the result in the localst
  251. when it is returning in a register }
  252. { we also need to do this for a generic procdef as we didn't allow
  253. the creation of a result symbol in insert_funcret_para, but we need
  254. a valid funcretsym }
  255. if (df_generic in pd.defoptions) or
  256. not paramanager.ret_in_param(pd.returndef,pd) then
  257. begin
  258. vs:=clocalvarsym.create('$result',vs_value,pd.returndef,[vo_is_funcret],true);
  259. pd.localst.insert(vs);
  260. pd.funcretsym:=vs;
  261. end;
  262. { insert the name of the procedure as alias for the function result,
  263. we can't use realname because that will not work for compilerprocs
  264. as the name is lowercase and unreachable from the code }
  265. if (pd.proctypeoption<>potype_operator) or assigned(pd.resultname) then
  266. begin
  267. if assigned(pd.resultname) then
  268. hs:=pd.resultname^
  269. else
  270. hs:=pd.procsym.name;
  271. sl:=tpropaccesslist.create;
  272. sl.addsym(sl_load,pd.funcretsym);
  273. aliasvs:=cabsolutevarsym.create_ref(hs,pd.returndef,sl);
  274. include(aliasvs.varoptions,vo_is_funcret);
  275. tlocalsymtable(pd.localst).insert(aliasvs);
  276. end;
  277. { insert result also if support is on }
  278. if (m_result in current_settings.modeswitches) then
  279. begin
  280. sl:=tpropaccesslist.create;
  281. sl.addsym(sl_load,pd.funcretsym);
  282. aliasvs:=cabsolutevarsym.create_ref('RESULT',pd.returndef,sl);
  283. include(aliasvs.varoptions,vo_is_funcret);
  284. include(aliasvs.varoptions,vo_is_result);
  285. tlocalsymtable(pd.localst).insert(aliasvs);
  286. end;
  287. current_tokenpos:=storepos;
  288. end;
  289. end;
  290. procedure insert_hidden_para(p:TObject;arg:pointer);
  291. var
  292. hvs : tparavarsym;
  293. pd : tabstractprocdef absolute arg;
  294. begin
  295. if (tsym(p).typ<>paravarsym) then
  296. exit;
  297. with tparavarsym(p) do
  298. begin
  299. { We need a local copy for a value parameter when only the
  300. address is pushed. Open arrays and Array of Const are
  301. an exception because they are allocated at runtime and the
  302. address that is pushed is patched.
  303. Arrays passed to cdecl routines are special: they are pointers in
  304. C and hence must be passed as such. Due to historical reasons, if
  305. a cdecl routine is implemented in Pascal, we still make a copy on
  306. the callee side. Do this the same on platforms that normally must
  307. make a copy on the caller side, as otherwise the behaviour will
  308. be different (and less perfomant) for routines implemented in C }
  309. if (varspez=vs_value) and
  310. paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
  311. not(is_open_array(vardef) or
  312. is_array_of_const(vardef)) and
  313. (not(target_info.system in systems_caller_copy_addr_value_para) or
  314. ((pd.proccalloption in cdecl_pocalls) and
  315. (vardef.typ=arraydef))) then
  316. include(varoptions,vo_has_local_copy);
  317. { needs high parameter ? }
  318. if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
  319. begin
  320. hvs:=cparavarsym.create('$high'+name,paranr+1,vs_const,sizesinttype,[vo_is_high_para,vo_is_hidden_para]);
  321. hvs.symoptions:=[];
  322. owner.insert(hvs);
  323. { don't place to register if it will be accessed from implicit finally block }
  324. if (varspez=vs_value) and
  325. is_open_array(vardef) and
  326. is_managed_type(vardef) then
  327. hvs.varregable:=vr_none;
  328. end
  329. else
  330. begin
  331. { Give a warning that cdecl routines does not include high()
  332. support }
  333. if (pd.proccalloption in cdecl_pocalls) and
  334. paramanager.push_high_param(varspez,vardef,pocall_default) then
  335. begin
  336. if is_open_string(vardef) then
  337. MessagePos(fileinfo,parser_w_cdecl_no_openstring);
  338. if not(po_external in pd.procoptions) and
  339. (pd.typ<>procvardef) and
  340. not is_objc_class_or_protocol(tprocdef(pd).struct) then
  341. if is_array_of_const(vardef) then
  342. MessagePos(fileinfo,parser_e_varargs_need_cdecl_and_external)
  343. else
  344. MessagePos(fileinfo,parser_w_cdecl_has_no_high);
  345. end;
  346. if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
  347. begin
  348. hvs:=cparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
  349. [vo_is_typinfo_para,vo_is_hidden_para]);
  350. owner.insert(hvs);
  351. end;
  352. end;
  353. end;
  354. end;
  355. procedure check_c_para(pd:Tabstractprocdef);
  356. var
  357. i,
  358. lastparaidx : longint;
  359. sym : TSym;
  360. begin
  361. lastparaidx:=pd.parast.SymList.Count-1;
  362. for i:=0 to pd.parast.SymList.Count-1 do
  363. begin
  364. sym:=tsym(pd.parast.SymList[i]);
  365. if (sym.typ=paravarsym) and
  366. (tparavarsym(sym).vardef.typ=arraydef) then
  367. begin
  368. if not is_variant_array(tparavarsym(sym).vardef) and
  369. not is_array_of_const(tparavarsym(sym).vardef) and
  370. (tparavarsym(sym).varspez<>vs_var) then
  371. MessagePos(tparavarsym(sym).fileinfo,parser_h_c_arrays_are_references);
  372. if is_array_of_const(tparavarsym(sym).vardef) and
  373. (i<lastparaidx) and
  374. (tsym(pd.parast.SymList[i+1]).typ=paravarsym) and
  375. not(vo_is_high_para in tparavarsym(pd.parast.SymList[i+1]).varoptions) then
  376. MessagePos(tparavarsym(sym).fileinfo,parser_e_C_array_of_const_must_be_last);
  377. end;
  378. end;
  379. end;
  380. end.