pparautl.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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,
  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. if pd.retisweak then
  67. include(vs.varoptions,vo_is_weakref);
  68. pd.parast.insert(vs);
  69. { Store this symbol as funcretsym for procedures }
  70. if pd.typ=procdef then
  71. tprocdef(pd).funcretsym:=vs;
  72. current_tokenpos:=storepos;
  73. end;
  74. end;
  75. procedure insert_parentfp_para(pd:tabstractprocdef);
  76. var
  77. storepos : tfileposinfo;
  78. vs : tparavarsym;
  79. paranr : longint;
  80. begin
  81. if pd.parast.symtablelevel>normal_function_level then
  82. begin
  83. storepos:=current_tokenpos;
  84. if pd.typ=procdef then
  85. current_tokenpos:=tprocdef(pd).fileinfo;
  86. { if no support for nested procvars is activated, use the old
  87. calling convention to pass the parent frame pointer for backwards
  88. compatibility }
  89. if not(m_nested_procvars in current_settings.modeswitches) then
  90. paranr:=paranr_parentfp
  91. { nested procvars require Delphi-style parentfp passing, see
  92. po_delphi_nested_cc declaration for more info }
  93. {$if defined(i386) or defined(i8086)}
  94. else if (pd.proccalloption in pushleftright_pocalls) then
  95. paranr:=paranr_parentfp_delphi_cc_leftright
  96. {$endif i386 or i8086}
  97. else
  98. paranr:=paranr_parentfp_delphi_cc;
  99. { Generate frame pointer. It can't be put in a register since it
  100. must be accessable from nested routines }
  101. if not(target_info.system in systems_fpnestedstruct) or
  102. { in case of errors, prevent invalid type cast }
  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. vopts : tvaroptions;
  130. begin
  131. if (pd.typ=procdef) and
  132. is_objc_class_or_protocol(tprocdef(pd).struct) and
  133. (pd.parast.symtablelevel=normal_function_level) then
  134. begin
  135. { insert Objective-C self and selector parameters }
  136. vs:=cparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
  137. pd.parast.insert(vs);
  138. { make accessible to code }
  139. sl:=tpropaccesslist.create;
  140. sl.addsym(sl_load,vs);
  141. aliasvs:=cabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
  142. include(aliasvs.varoptions,vo_is_msgsel);
  143. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  144. if (po_classmethod in pd.procoptions) then
  145. { compatible with what gcc does }
  146. hdef:=objc_idtype
  147. else
  148. hdef:=tprocdef(pd).struct;
  149. vs:=cparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
  150. pd.parast.insert(vs);
  151. end
  152. else if (pd.typ=procvardef) and
  153. pd.is_methodpointer then
  154. begin
  155. { Generate self variable }
  156. vs:=cparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para,vo_is_weakref]);
  157. pd.parast.insert(vs);
  158. end
  159. else
  160. begin
  161. if (pd.typ=procdef) and
  162. assigned(tprocdef(pd).struct) and
  163. (pd.parast.symtablelevel=normal_function_level) then
  164. begin
  165. { static class methods have no hidden self/vmt pointer }
  166. if pd.no_self_node then
  167. exit;
  168. storepos:=current_tokenpos;
  169. current_tokenpos:=tprocdef(pd).fileinfo;
  170. { Generate VMT variable for constructor/destructor }
  171. if (pd.proctypeoption in [potype_constructor,potype_destructor]) and
  172. not(is_cppclass(tprocdef(pd).struct) or
  173. is_record(tprocdef(pd).struct) or
  174. is_javaclass(tprocdef(pd).struct) or
  175. (
  176. { no vmt for record/type helper constructors }
  177. is_objectpascal_helper(tprocdef(pd).struct) and
  178. (tobjectdef(tprocdef(pd).struct).extendeddef.typ<>objectdef)
  179. )) then
  180. begin
  181. { can't use classrefdef as type because inheriting
  182. will then always file because of a type mismatch }
  183. vs:=cparavarsym.create('$vmt',paranr_vmt,vs_value,voidpointertype,[vo_is_vmt,vo_is_hidden_para]);
  184. pd.parast.insert(vs);
  185. end;
  186. { for helpers the type of Self is equivalent to the extended
  187. type or equal to an instance of it }
  188. if is_objectpascal_helper(tprocdef(pd).struct) then
  189. selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
  190. else
  191. selfdef:=tprocdef(pd).struct;
  192. { Generate self variable, for classes we need
  193. to use the generic voidpointer to be compatible with
  194. methodpointers }
  195. vsp:=vs_value;
  196. vopts:=[vo_is_self,vo_is_hidden_para];
  197. if (po_staticmethod in pd.procoptions) or
  198. (po_classmethod in pd.procoptions) then
  199. hdef:=cclassrefdef.create(selfdef)
  200. else
  201. begin
  202. if is_object(selfdef) or (selfdef.typ<>objectdef) then
  203. vsp:=vs_var;
  204. if is_class(selfdef) then
  205. include(vopts,vo_is_weakref);
  206. hdef:=selfdef;
  207. end;
  208. vs:=cparavarsym.create('$self',paranr_self,vsp,hdef,vopts);
  209. pd.parast.insert(vs);
  210. current_tokenpos:=storepos;
  211. end;
  212. end;
  213. end;
  214. procedure insert_funcret_local(pd:tprocdef);
  215. var
  216. storepos : tfileposinfo;
  217. vs : tlocalvarsym;
  218. aliasvs : tabsolutevarsym;
  219. sl : tpropaccesslist;
  220. hs : string;
  221. begin
  222. { The result from constructors and destructors can't be accessed directly }
  223. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  224. not is_void(pd.returndef) then
  225. begin
  226. storepos:=current_tokenpos;
  227. current_tokenpos:=pd.fileinfo;
  228. { We need to insert a varsym for the result in the localst
  229. when it is returning in a register }
  230. { we also need to do this for a generic procdef as we didn't allow
  231. the creation of a result symbol in insert_funcret_para, but we need
  232. a valid funcretsym }
  233. if (df_generic in pd.defoptions) or
  234. not paramanager.ret_in_param(pd.returndef,pd) then
  235. begin
  236. vs:=clocalvarsym.create('$result',vs_value,pd.returndef,[vo_is_funcret]);
  237. if pd.retisweak then
  238. include(vs.varoptions,vo_is_weakref);
  239. pd.localst.insert(vs);
  240. pd.funcretsym:=vs;
  241. end;
  242. { insert the name of the procedure as alias for the function result,
  243. we can't use realname because that will not work for compilerprocs
  244. as the name is lowercase and unreachable from the code }
  245. if (pd.proctypeoption<>potype_operator) or assigned(pd.resultname) then
  246. begin
  247. if assigned(pd.resultname) then
  248. hs:=pd.resultname^
  249. else
  250. hs:=pd.procsym.name;
  251. sl:=tpropaccesslist.create;
  252. sl.addsym(sl_load,pd.funcretsym);
  253. aliasvs:=cabsolutevarsym.create_ref(hs,pd.returndef,sl);
  254. include(aliasvs.varoptions,vo_is_funcret);
  255. tlocalsymtable(pd.localst).insert(aliasvs);
  256. end;
  257. { insert result also if support is on }
  258. if (m_result in current_settings.modeswitches) then
  259. begin
  260. sl:=tpropaccesslist.create;
  261. sl.addsym(sl_load,pd.funcretsym);
  262. aliasvs:=cabsolutevarsym.create_ref('RESULT',pd.returndef,sl);
  263. include(aliasvs.varoptions,vo_is_funcret);
  264. include(aliasvs.varoptions,vo_is_result);
  265. tlocalsymtable(pd.localst).insert(aliasvs);
  266. end;
  267. current_tokenpos:=storepos;
  268. end;
  269. end;
  270. procedure insert_hidden_para(p:TObject;arg:pointer);
  271. var
  272. hvs : tparavarsym;
  273. pd : tabstractprocdef absolute arg;
  274. begin
  275. if (tsym(p).typ<>paravarsym) then
  276. exit;
  277. with tparavarsym(p) do
  278. begin
  279. { We need a local copy for a value parameter when only the
  280. address is pushed. Open arrays and Array of Const are
  281. an exception because they are allocated at runtime and the
  282. address that is pushed is patched }
  283. if (varspez=vs_value) and
  284. paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
  285. not(is_open_array(vardef) or
  286. is_array_of_const(vardef)) then
  287. include(varoptions,vo_has_local_copy);
  288. { needs high parameter ? }
  289. if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
  290. begin
  291. hvs:=cparavarsym.create('$high'+name,paranr+1,vs_const,sinttype,[vo_is_high_para,vo_is_hidden_para]);
  292. hvs.symoptions:=[];
  293. owner.insert(hvs);
  294. { don't place to register if it will be accessed from implicit finally block }
  295. if (varspez=vs_value) and
  296. is_open_array(vardef) and
  297. is_managed_type(vardef) then
  298. hvs.varregable:=vr_none;
  299. end
  300. else
  301. begin
  302. { Give a warning that cdecl routines does not include high()
  303. support }
  304. if (pd.proccalloption in cdecl_pocalls) and
  305. paramanager.push_high_param(varspez,vardef,pocall_default) then
  306. begin
  307. if is_open_string(vardef) then
  308. MessagePos(fileinfo,parser_w_cdecl_no_openstring);
  309. if not(po_external in pd.procoptions) and
  310. (pd.typ<>procvardef) and
  311. not is_objc_class_or_protocol(tprocdef(pd).struct) then
  312. if is_array_of_const(vardef) then
  313. MessagePos(fileinfo,parser_e_varargs_need_cdecl_and_external)
  314. else
  315. MessagePos(fileinfo,parser_w_cdecl_has_no_high);
  316. end;
  317. if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
  318. begin
  319. hvs:=cparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
  320. [vo_is_typinfo_para,vo_is_hidden_para]);
  321. owner.insert(hvs);
  322. end;
  323. end;
  324. end;
  325. end;
  326. procedure check_c_para(pd:Tabstractprocdef);
  327. var
  328. i,
  329. lastparaidx : longint;
  330. sym : TSym;
  331. begin
  332. lastparaidx:=pd.parast.SymList.Count-1;
  333. for i:=0 to pd.parast.SymList.Count-1 do
  334. begin
  335. sym:=tsym(pd.parast.SymList[i]);
  336. if (sym.typ=paravarsym) and
  337. (tparavarsym(sym).vardef.typ=arraydef) then
  338. begin
  339. if not is_variant_array(tparavarsym(sym).vardef) and
  340. not is_array_of_const(tparavarsym(sym).vardef) and
  341. (tparavarsym(sym).varspez<>vs_var) then
  342. MessagePos(tparavarsym(sym).fileinfo,parser_h_c_arrays_are_references);
  343. if is_array_of_const(tparavarsym(sym).vardef) and
  344. (i<lastparaidx) and
  345. (tsym(pd.parast.SymList[i+1]).typ=paravarsym) and
  346. not(vo_is_high_para in tparavarsym(pd.parast.SymList[i+1]).varoptions) then
  347. MessagePos(tparavarsym(sym).fileinfo,parser_e_C_array_of_const_must_be_last);
  348. end;
  349. end;
  350. end;
  351. end.