pparautl.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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.proccalloption) 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(x86) or defined(arm)}
  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:=tparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
  66. pd.parast.insert(vs);
  67. { Store the 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. {$ifdef i386}
  92. else if (pd.proccalloption in pushleftright_pocalls) then
  93. paranr:=paranr_parentfp_delphi_cc_leftright
  94. {$endif i386}
  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) then
  100. begin
  101. vs:=tparavarsym.create('$parentfp',paranr,vs_value
  102. ,voidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
  103. vs.varregable:=vr_none;
  104. end
  105. else
  106. begin
  107. if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
  108. build_parentfpstruct(tprocdef(pd.owner.defowner));
  109. vs:=tparavarsym.create('$parentfp',paranr,vs_value
  110. ,tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
  111. end;
  112. pd.parast.insert(vs);
  113. current_tokenpos:=storepos;
  114. end;
  115. end;
  116. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  117. var
  118. storepos : tfileposinfo;
  119. vs : tparavarsym;
  120. hdef : tdef;
  121. selfdef : tdef;
  122. vsp : tvarspez;
  123. aliasvs : tabsolutevarsym;
  124. sl : tpropaccesslist;
  125. begin
  126. if (pd.typ=procdef) and
  127. is_objc_class_or_protocol(tprocdef(pd).struct) and
  128. (pd.parast.symtablelevel=normal_function_level) then
  129. begin
  130. { insert Objective-C self and selector parameters }
  131. vs:=tparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
  132. pd.parast.insert(vs);
  133. { make accessible to code }
  134. sl:=tpropaccesslist.create;
  135. sl.addsym(sl_load,vs);
  136. aliasvs:=tabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
  137. include(aliasvs.varoptions,vo_is_msgsel);
  138. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  139. if (po_classmethod in pd.procoptions) then
  140. { compatible with what gcc does }
  141. hdef:=objc_idtype
  142. else
  143. hdef:=tprocdef(pd).struct;
  144. vs:=tparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
  145. pd.parast.insert(vs);
  146. end
  147. else if (pd.typ=procvardef) and
  148. pd.is_methodpointer then
  149. begin
  150. { Generate self variable }
  151. vs:=tparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
  152. pd.parast.insert(vs);
  153. end
  154. else
  155. begin
  156. if (pd.typ=procdef) and
  157. assigned(tprocdef(pd).struct) and
  158. (pd.parast.symtablelevel=normal_function_level) then
  159. begin
  160. { static class methods have no hidden self/vmt pointer }
  161. if pd.no_self_node then
  162. exit;
  163. storepos:=current_tokenpos;
  164. current_tokenpos:=tprocdef(pd).fileinfo;
  165. { Generate VMT variable for constructor/destructor }
  166. if (pd.proctypeoption in [potype_constructor,potype_destructor]) and
  167. not(is_cppclass(tprocdef(pd).struct) or
  168. is_record(tprocdef(pd).struct) or
  169. is_javaclass(tprocdef(pd).struct)) then
  170. begin
  171. { can't use classrefdef as type because inheriting
  172. will then always file because of a type mismatch }
  173. vs:=tparavarsym.create('$vmt',paranr_vmt,vs_value,voidpointertype,[vo_is_vmt,vo_is_hidden_para]);
  174. pd.parast.insert(vs);
  175. end;
  176. { for helpers the type of Self is equivalent to the extended
  177. type or equal to an instance of it }
  178. if is_objectpascal_helper(tprocdef(pd).struct) then
  179. selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
  180. else
  181. selfdef:=tprocdef(pd).struct;
  182. { Generate self variable, for classes we need
  183. to use the generic voidpointer to be compatible with
  184. methodpointers }
  185. vsp:=vs_value;
  186. if (po_staticmethod in pd.procoptions) or
  187. (po_classmethod in pd.procoptions) then
  188. hdef:=tclassrefdef.create(selfdef)
  189. else
  190. begin
  191. if is_object(selfdef) or is_record(selfdef) then
  192. vsp:=vs_var;
  193. hdef:=selfdef;
  194. end;
  195. vs:=tparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
  196. pd.parast.insert(vs);
  197. current_tokenpos:=storepos;
  198. end;
  199. end;
  200. end;
  201. procedure insert_funcret_local(pd:tprocdef);
  202. var
  203. storepos : tfileposinfo;
  204. vs : tlocalvarsym;
  205. aliasvs : tabsolutevarsym;
  206. sl : tpropaccesslist;
  207. hs : string;
  208. begin
  209. { The result from constructors and destructors can't be accessed directly }
  210. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  211. not is_void(pd.returndef) then
  212. begin
  213. storepos:=current_tokenpos;
  214. current_tokenpos:=pd.fileinfo;
  215. { We need to insert a varsym for the result in the localst
  216. when it is returning in a register }
  217. { we also need to do this for a generic procdef as we didn't allow
  218. the creation of a result symbol in insert_funcret_para, but we need
  219. a valid funcretsym }
  220. if (df_generic in pd.defoptions) or
  221. not paramanager.ret_in_param(pd.returndef,pd.proccalloption) then
  222. begin
  223. vs:=tlocalvarsym.create('$result',vs_value,pd.returndef,[vo_is_funcret]);
  224. pd.localst.insert(vs);
  225. pd.funcretsym:=vs;
  226. end;
  227. { insert the name of the procedure as alias for the function result,
  228. we can't use realname because that will not work for compilerprocs
  229. as the name is lowercase and unreachable from the code }
  230. if assigned(pd.resultname) then
  231. hs:=pd.resultname^
  232. else
  233. hs:=pd.procsym.name;
  234. sl:=tpropaccesslist.create;
  235. sl.addsym(sl_load,pd.funcretsym);
  236. aliasvs:=tabsolutevarsym.create_ref(hs,pd.returndef,sl);
  237. include(aliasvs.varoptions,vo_is_funcret);
  238. tlocalsymtable(pd.localst).insert(aliasvs);
  239. { insert result also if support is on }
  240. if (m_result in current_settings.modeswitches) then
  241. begin
  242. sl:=tpropaccesslist.create;
  243. sl.addsym(sl_load,pd.funcretsym);
  244. aliasvs:=tabsolutevarsym.create_ref('RESULT',pd.returndef,sl);
  245. include(aliasvs.varoptions,vo_is_funcret);
  246. include(aliasvs.varoptions,vo_is_result);
  247. tlocalsymtable(pd.localst).insert(aliasvs);
  248. end;
  249. current_tokenpos:=storepos;
  250. end;
  251. end;
  252. procedure insert_hidden_para(p:TObject;arg:pointer);
  253. var
  254. hvs : tparavarsym;
  255. pd : tabstractprocdef absolute arg;
  256. begin
  257. if (tsym(p).typ<>paravarsym) then
  258. exit;
  259. with tparavarsym(p) do
  260. begin
  261. { We need a local copy for a value parameter when only the
  262. address is pushed. Open arrays and Array of Const are
  263. an exception because they are allocated at runtime and the
  264. address that is pushed is patched }
  265. if (varspez=vs_value) and
  266. paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
  267. not(is_open_array(vardef) or
  268. is_array_of_const(vardef)) then
  269. include(varoptions,vo_has_local_copy);
  270. { needs high parameter ? }
  271. if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
  272. begin
  273. hvs:=tparavarsym.create('$high'+name,paranr+1,vs_const,sinttype,[vo_is_high_para,vo_is_hidden_para]);
  274. hvs.symoptions:=[];
  275. owner.insert(hvs);
  276. { don't place to register if it will be accessed from implicit finally block }
  277. if (varspez=vs_value) and
  278. is_open_array(vardef) and
  279. is_managed_type(vardef) then
  280. hvs.varregable:=vr_none;
  281. end
  282. else
  283. begin
  284. { Give a warning that cdecl routines does not include high()
  285. support }
  286. if (pd.proccalloption in cdecl_pocalls) and
  287. paramanager.push_high_param(varspez,vardef,pocall_default) then
  288. begin
  289. if is_open_string(vardef) then
  290. MessagePos(fileinfo,parser_w_cdecl_no_openstring);
  291. if not(po_external in pd.procoptions) and
  292. (pd.typ<>procvardef) and
  293. not is_objc_class_or_protocol(tprocdef(pd).struct) then
  294. if is_array_of_const(vardef) then
  295. MessagePos(fileinfo,parser_e_varargs_need_cdecl_and_external)
  296. else
  297. MessagePos(fileinfo,parser_w_cdecl_has_no_high);
  298. end;
  299. if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
  300. begin
  301. hvs:=tparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
  302. [vo_is_typinfo_para,vo_is_hidden_para]);
  303. owner.insert(hvs);
  304. end;
  305. end;
  306. end;
  307. end;
  308. procedure check_c_para(pd:Tabstractprocdef);
  309. var
  310. i,
  311. lastparaidx : longint;
  312. sym : TSym;
  313. begin
  314. lastparaidx:=pd.parast.SymList.Count-1;
  315. for i:=0 to pd.parast.SymList.Count-1 do
  316. begin
  317. sym:=tsym(pd.parast.SymList[i]);
  318. if (sym.typ=paravarsym) and
  319. (tparavarsym(sym).vardef.typ=arraydef) then
  320. begin
  321. if not is_variant_array(tparavarsym(sym).vardef) and
  322. not is_array_of_const(tparavarsym(sym).vardef) and
  323. (tparavarsym(sym).varspez<>vs_var) then
  324. MessagePos(tparavarsym(sym).fileinfo,parser_h_c_arrays_are_references);
  325. if is_array_of_const(tparavarsym(sym).vardef) and
  326. (i<lastparaidx) and
  327. (tsym(pd.parast.SymList[i+1]).typ=paravarsym) and
  328. not(vo_is_high_para in tparavarsym(pd.parast.SymList[i+1]).varoptions) then
  329. MessagePos(tparavarsym(sym).fileinfo,parser_e_C_array_of_const_must_be_last);
  330. end;
  331. end;
  332. end;
  333. end.