pparautl.pas 15 KB

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