pparautl.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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. type
  29. // flags of handle_calling_convention routine
  30. thccflag=(
  31. hcc_check, // perform checks and outup errors if found
  32. hcc_insert_hidden_paras // insert hidden parameters
  33. );
  34. thccflags=set of thccflag;
  35. const
  36. hcc_all=[hcc_check,hcc_insert_hidden_paras];
  37. procedure handle_calling_convention(pd:tabstractprocdef;flags:thccflags=hcc_all);
  38. implementation
  39. uses
  40. globals,globtype,verbose,systems,
  41. symconst,symtype,symbase,symsym,symtable,symcreat,defutil,blockutl,
  42. pbase,paramgr;
  43. procedure insert_funcret_para(pd:tabstractprocdef);
  44. var
  45. storepos : tfileposinfo;
  46. vs : tparavarsym;
  47. paranr : word;
  48. begin
  49. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  50. not is_void(pd.returndef) and
  51. not (df_generic in pd.defoptions) and
  52. paramanager.ret_in_param(pd.returndef,pd) then
  53. begin
  54. storepos:=current_tokenpos;
  55. if pd.typ=procdef then
  56. current_tokenpos:=tprocdef(pd).fileinfo;
  57. {$if defined(i386)}
  58. { For left to right add it at the end to be delphi compatible.
  59. In the case of safecalls with safecal-exceptions support the
  60. funcret-para is (from the 'c'-point of view) a normal parameter
  61. which has to be added to the end of the parameter-list }
  62. if (pd.proccalloption in (pushleftright_pocalls)) or
  63. ((tf_safecall_exceptions in target_info.flags) and
  64. (pd.proccalloption=pocall_safecall)) then
  65. paranr:=paranr_result_leftright
  66. else
  67. {$elseif defined(SUPPORT_SAFECALL)}
  68. if (tf_safecall_exceptions in target_info.flags) and
  69. (pd.proccalloption = pocall_safecall) then
  70. paranr:=paranr_result_leftright
  71. else
  72. {$endif}
  73. paranr:=paranr_result;
  74. { Generate result variable accessing function result }
  75. vs:=cparavarsym.create('$result',paranr,vs_var,pd.returndef,[vo_is_funcret,vo_is_hidden_para]);
  76. pd.parast.insert(vs);
  77. { Store this symbol as funcretsym for procedures }
  78. if pd.typ=procdef then
  79. tprocdef(pd).funcretsym:=vs;
  80. current_tokenpos:=storepos;
  81. end;
  82. end;
  83. procedure insert_parentfp_para(pd:tabstractprocdef);
  84. var
  85. storepos : tfileposinfo;
  86. vs : tparavarsym;
  87. paranr : longint;
  88. begin
  89. if pd.parast.symtablelevel>normal_function_level then
  90. begin
  91. storepos:=current_tokenpos;
  92. if pd.typ=procdef then
  93. current_tokenpos:=tprocdef(pd).fileinfo;
  94. { if no support for nested procvars is activated, use the old
  95. calling convention to pass the parent frame pointer for backwards
  96. compatibility }
  97. if not(m_nested_procvars in current_settings.modeswitches) then
  98. paranr:=paranr_parentfp
  99. { nested procvars require Delphi-style parentfp passing, see
  100. po_delphi_nested_cc declaration for more info }
  101. {$if defined(i386) or defined(i8086)}
  102. else if (pd.proccalloption in pushleftright_pocalls) then
  103. paranr:=paranr_parentfp_delphi_cc_leftright
  104. {$endif i386 or i8086}
  105. else
  106. paranr:=paranr_parentfp_delphi_cc;
  107. { Generate frame pointer. It can't be put in a register since it
  108. must be accessable from nested routines }
  109. if not(target_info.system in systems_fpnestedstruct) or
  110. { in case of errors or declared procvardef types, prevent invalid
  111. type cast and possible nil pointer dereference }
  112. not assigned(pd.owner.defowner) or
  113. (pd.owner.defowner.typ<>procdef) then
  114. begin
  115. vs:=cparavarsym.create('$parentfp',paranr,vs_value
  116. ,parentfpvoidpointertype,[vo_is_parentfp,vo_is_hidden_para]);
  117. vs.varregable:=vr_none;
  118. end
  119. else
  120. begin
  121. if not assigned(tprocdef(pd.owner.defowner).parentfpstruct) then
  122. build_parentfpstruct(tprocdef(pd.owner.defowner));
  123. vs:=cparavarsym.create('$parentfp',paranr,vs_value
  124. ,tprocdef(pd.owner.defowner).parentfpstructptrtype,[vo_is_parentfp,vo_is_hidden_para]);
  125. end;
  126. pd.parast.insert(vs);
  127. current_tokenpos:=storepos;
  128. end;
  129. end;
  130. procedure insert_self_and_vmt_para(pd:tabstractprocdef);
  131. var
  132. storepos : tfileposinfo;
  133. vs : tparavarsym;
  134. hdef : tdef;
  135. selfdef : tdef;
  136. vsp : tvarspez;
  137. aliasvs : tabsolutevarsym;
  138. sl : tpropaccesslist;
  139. begin
  140. if (pd.typ=procdef) and
  141. is_objc_class_or_protocol(tprocdef(pd).struct) and
  142. (pd.parast.symtablelevel=normal_function_level) then
  143. begin
  144. { insert Objective-C self and selector parameters }
  145. vs:=cparavarsym.create('$_cmd',paranr_objc_cmd,vs_value,objc_seltype,[vo_is_msgsel,vo_is_hidden_para]);
  146. pd.parast.insert(vs);
  147. { make accessible to code }
  148. sl:=tpropaccesslist.create;
  149. sl.addsym(sl_load,vs);
  150. aliasvs:=cabsolutevarsym.create_ref('_CMD',objc_seltype,sl);
  151. include(aliasvs.varoptions,vo_is_msgsel);
  152. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  153. if (po_classmethod in pd.procoptions) then
  154. { compatible with what gcc does }
  155. hdef:=objc_idtype
  156. else
  157. hdef:=tprocdef(pd).struct;
  158. vs:=cparavarsym.create('$self',paranr_objc_self,vs_value,hdef,[vo_is_self,vo_is_hidden_para]);
  159. pd.parast.insert(vs);
  160. end
  161. else if (pd.typ=procvardef) and
  162. pd.is_methodpointer then
  163. begin
  164. { Generate self variable }
  165. vs:=cparavarsym.create('$self',paranr_self,vs_value,voidpointertype,[vo_is_self,vo_is_hidden_para]);
  166. pd.parast.insert(vs);
  167. end
  168. { while only procvardefs of this type can be declared in Pascal code,
  169. internally we also generate procdefs of this type when creating
  170. block wrappers }
  171. else if (po_is_block in pd.procoptions) then
  172. begin
  173. { generate the first hidden parameter, which is a so-called "block
  174. literal" describing the block and containing its invocation
  175. procedure }
  176. hdef:=cpointerdef.getreusable(get_block_literal_type_for_proc(pd));
  177. { mark as vo_is_parentfp so that proc2procvar comparisons will
  178. succeed when assigning arbitrary routines to the block }
  179. vs:=cparavarsym.create('$_block_literal',paranr_blockselfpara,vs_value,
  180. hdef,[vo_is_hidden_para,vo_is_parentfp]
  181. );
  182. pd.parast.insert(vs);
  183. if pd.typ=procdef then
  184. begin
  185. { make accessible to code }
  186. sl:=tpropaccesslist.create;
  187. sl.addsym(sl_load,vs);
  188. aliasvs:=cabsolutevarsym.create_ref('FPC_BLOCK_SELF',hdef,sl);
  189. include(aliasvs.varoptions,vo_is_parentfp);
  190. tlocalsymtable(tprocdef(pd).localst).insert(aliasvs);
  191. end;
  192. end
  193. else
  194. begin
  195. if (pd.typ=procdef) and
  196. assigned(tprocdef(pd).struct) and
  197. (pd.parast.symtablelevel=normal_function_level) then
  198. begin
  199. { static class methods have no hidden self/vmt pointer }
  200. if pd.no_self_node then
  201. exit;
  202. storepos:=current_tokenpos;
  203. current_tokenpos:=tprocdef(pd).fileinfo;
  204. { Generate VMT variable for constructor/destructor }
  205. if (pd.proctypeoption in [potype_constructor,potype_destructor]) and
  206. not(is_cppclass(tprocdef(pd).struct) or
  207. is_record(tprocdef(pd).struct) or
  208. is_javaclass(tprocdef(pd).struct) or
  209. (
  210. { no vmt for record/type helper constructors }
  211. is_objectpascal_helper(tprocdef(pd).struct) and
  212. (tobjectdef(tprocdef(pd).struct).extendeddef.typ<>objectdef)
  213. )) then
  214. begin
  215. vs:=cparavarsym.create('$vmt',paranr_vmt,vs_value,cclassrefdef.create(tprocdef(pd).struct),[vo_is_vmt,vo_is_hidden_para]);
  216. pd.parast.insert(vs);
  217. end;
  218. { for helpers the type of Self is equivalent to the extended
  219. type or equal to an instance of it }
  220. if is_objectpascal_helper(tprocdef(pd).struct) then
  221. selfdef:=tobjectdef(tprocdef(pd).struct).extendeddef
  222. else if is_objccategory(tprocdef(pd).struct) then
  223. selfdef:=tobjectdef(tprocdef(pd).struct).childof
  224. else
  225. selfdef:=tprocdef(pd).struct;
  226. { Generate self variable, for classes we need
  227. to use the generic voidpointer to be compatible with
  228. methodpointers }
  229. vsp:=vs_value;
  230. if (po_staticmethod in pd.procoptions) or
  231. (po_classmethod in pd.procoptions) then
  232. hdef:=cclassrefdef.create(selfdef)
  233. else
  234. begin
  235. if is_object(selfdef) or (selfdef.typ<>objectdef) then
  236. vsp:=vs_var;
  237. hdef:=selfdef;
  238. end;
  239. vs:=cparavarsym.create('$self',paranr_self,vsp,hdef,[vo_is_self,vo_is_hidden_para]);
  240. pd.parast.insert(vs);
  241. current_tokenpos:=storepos;
  242. end;
  243. end;
  244. end;
  245. procedure insert_funcret_local(pd:tprocdef);
  246. var
  247. storepos : tfileposinfo;
  248. vs : tlocalvarsym;
  249. aliasvs : tabsolutevarsym;
  250. sl : tpropaccesslist;
  251. hs : string;
  252. begin
  253. { The result from constructors and destructors can't be accessed directly }
  254. if not(pd.proctypeoption in [potype_constructor,potype_destructor]) and
  255. not is_void(pd.returndef) and
  256. (not(po_assembler in pd.procoptions) or paramanager.asm_result_var(pd.returndef,pd)) then
  257. begin
  258. storepos:=current_tokenpos;
  259. current_tokenpos:=pd.fileinfo;
  260. { We need to insert a varsym for the result in the localst
  261. when it is returning in a register }
  262. { we also need to do this for a generic procdef as we didn't allow
  263. the creation of a result symbol in insert_funcret_para, but we need
  264. a valid funcretsym }
  265. if (df_generic in pd.defoptions) or
  266. not paramanager.ret_in_param(pd.returndef,pd) then
  267. begin
  268. vs:=clocalvarsym.create('$result',vs_value,pd.returndef,[vo_is_funcret],true);
  269. pd.localst.insert(vs);
  270. pd.funcretsym:=vs;
  271. end;
  272. { insert the name of the procedure as alias for the function result,
  273. we can't use realname because that will not work for compilerprocs
  274. as the name is lowercase and unreachable from the code }
  275. if (pd.proctypeoption<>potype_operator) or assigned(pd.resultname) then
  276. begin
  277. if assigned(pd.resultname) then
  278. hs:=pd.resultname^
  279. else
  280. hs:=pd.procsym.name;
  281. sl:=tpropaccesslist.create;
  282. sl.addsym(sl_load,pd.funcretsym);
  283. aliasvs:=cabsolutevarsym.create_ref(hs,pd.returndef,sl);
  284. include(aliasvs.varoptions,vo_is_funcret);
  285. tlocalsymtable(pd.localst).insert(aliasvs);
  286. end;
  287. { insert result also if support is on }
  288. if (m_result in current_settings.modeswitches) then
  289. begin
  290. sl:=tpropaccesslist.create;
  291. sl.addsym(sl_load,pd.funcretsym);
  292. aliasvs:=cabsolutevarsym.create_ref('RESULT',pd.returndef,sl);
  293. include(aliasvs.varoptions,vo_is_funcret);
  294. include(aliasvs.varoptions,vo_is_result);
  295. tlocalsymtable(pd.localst).insert(aliasvs);
  296. end;
  297. current_tokenpos:=storepos;
  298. end;
  299. end;
  300. procedure insert_hidden_para(p:TObject;arg:pointer);
  301. var
  302. hvs : tparavarsym;
  303. pd : tabstractprocdef absolute arg;
  304. begin
  305. if (tsym(p).typ<>paravarsym) then
  306. exit;
  307. with tparavarsym(p) do
  308. begin
  309. { We need a local copy for a value parameter when only the
  310. address is pushed. Open arrays and Array of Const are
  311. an exception because they are allocated at runtime and the
  312. address that is pushed is patched.
  313. Arrays passed to cdecl routines are special: they are pointers in
  314. C and hence must be passed as such. Due to historical reasons, if
  315. a cdecl routine is implemented in Pascal, we still make a copy on
  316. the callee side. Do this the same on platforms that normally must
  317. make a copy on the caller side, as otherwise the behaviour will
  318. be different (and less perfomant) for routines implemented in C }
  319. if (varspez=vs_value) and
  320. paramanager.push_addr_param(varspez,vardef,pd.proccalloption) and
  321. not(is_open_array(vardef) or
  322. is_array_of_const(vardef)) and
  323. (not(target_info.system in systems_caller_copy_addr_value_para) or
  324. ((pd.proccalloption in cdecl_pocalls) and
  325. (vardef.typ=arraydef))) then
  326. include(varoptions,vo_has_local_copy);
  327. { needs high parameter ? }
  328. if paramanager.push_high_param(varspez,vardef,pd.proccalloption) then
  329. begin
  330. hvs:=cparavarsym.create('$high'+name,paranr+1,vs_const,sizesinttype,[vo_is_high_para,vo_is_hidden_para]);
  331. hvs.symoptions:=[];
  332. owner.insert(hvs);
  333. { don't place to register if it will be accessed from implicit finally block }
  334. if (varspez=vs_value) and
  335. is_open_array(vardef) and
  336. is_managed_type(vardef) then
  337. hvs.varregable:=vr_none;
  338. end
  339. else
  340. begin
  341. { Give a warning that cdecl routines does not include high()
  342. support }
  343. if (pd.proccalloption in cdecl_pocalls) and
  344. paramanager.push_high_param(varspez,vardef,pocall_default) then
  345. begin
  346. if is_open_string(vardef) then
  347. MessagePos(fileinfo,parser_w_cdecl_no_openstring);
  348. if not(po_external in pd.procoptions) and
  349. (pd.typ<>procvardef) and
  350. not is_objc_class_or_protocol(tprocdef(pd).struct) then
  351. if is_array_of_const(vardef) then
  352. MessagePos(fileinfo,parser_e_varargs_need_cdecl_and_external)
  353. else
  354. MessagePos(fileinfo,parser_w_cdecl_has_no_high);
  355. end;
  356. if (vardef.typ=formaldef) and (Tformaldef(vardef).typed) then
  357. begin
  358. hvs:=cparavarsym.create('$typinfo'+name,paranr+1,vs_const,voidpointertype,
  359. [vo_is_typinfo_para,vo_is_hidden_para]);
  360. owner.insert(hvs);
  361. end;
  362. end;
  363. end;
  364. end;
  365. procedure check_c_para(pd:Tabstractprocdef);
  366. var
  367. i,
  368. lastparaidx : longint;
  369. sym : TSym;
  370. begin
  371. lastparaidx:=pd.parast.SymList.Count-1;
  372. for i:=0 to pd.parast.SymList.Count-1 do
  373. begin
  374. sym:=tsym(pd.parast.SymList[i]);
  375. if (sym.typ=paravarsym) and
  376. (tparavarsym(sym).vardef.typ=arraydef) then
  377. begin
  378. if not is_variant_array(tparavarsym(sym).vardef) and
  379. not is_array_of_const(tparavarsym(sym).vardef) and
  380. (tparavarsym(sym).varspez<>vs_var) then
  381. MessagePos(tparavarsym(sym).fileinfo,parser_h_c_arrays_are_references);
  382. if is_array_of_const(tparavarsym(sym).vardef) and
  383. (i<lastparaidx) and
  384. (tsym(pd.parast.SymList[i+1]).typ=paravarsym) and
  385. not(vo_is_high_para in tparavarsym(pd.parast.SymList[i+1]).varoptions) then
  386. MessagePos(tparavarsym(sym).fileinfo,parser_e_C_array_of_const_must_be_last);
  387. end;
  388. end;
  389. end;
  390. procedure set_addr_param_regable(p:TObject;arg:pointer);
  391. begin
  392. if (tsym(p).typ<>paravarsym) then
  393. exit;
  394. with tparavarsym(p) do
  395. begin
  396. if (not needs_finalization) and
  397. paramanager.push_addr_param(varspez,vardef,tprocdef(arg).proccalloption) then
  398. varregable:=vr_addr;
  399. end;
  400. end;
  401. procedure handle_calling_convention(pd:tabstractprocdef;flags:thccflags=hcc_all);
  402. begin
  403. if hcc_check in flags then
  404. begin
  405. { set the default calling convention if none provided }
  406. if (pd.typ=procdef) and
  407. (is_objc_class_or_protocol(tprocdef(pd).struct) or
  408. is_cppclass(tprocdef(pd).struct)) then
  409. begin
  410. { none of the explicit calling conventions should be allowed }
  411. if (po_hascallingconvention in pd.procoptions) then
  412. internalerror(2009032501);
  413. if is_cppclass(tprocdef(pd).struct) then
  414. pd.proccalloption:=pocall_cppdecl
  415. else
  416. pd.proccalloption:=pocall_cdecl;
  417. end
  418. else if not(po_hascallingconvention in pd.procoptions) then
  419. pd.proccalloption:=current_settings.defproccall
  420. else
  421. begin
  422. if pd.proccalloption=pocall_none then
  423. internalerror(200309081);
  424. end;
  425. { handle proccall specific settings }
  426. case pd.proccalloption of
  427. pocall_cdecl,
  428. pocall_cppdecl,
  429. pocall_sysv_abi_cdecl,
  430. pocall_ms_abi_cdecl:
  431. begin
  432. { check C cdecl para types }
  433. check_c_para(pd);
  434. end;
  435. pocall_far16 :
  436. begin
  437. { Temporary stub, must be rewritten to support OS/2 far16 }
  438. Message1(parser_w_proc_directive_ignored,'FAR16');
  439. end;
  440. end;
  441. { Inlining is enabled and supported? }
  442. if (po_inline in pd.procoptions) and
  443. not(cs_do_inline in current_settings.localswitches) then
  444. begin
  445. { Give an error if inline is not supported by the compiler mode,
  446. otherwise only give a hint that this procedure will not be inlined }
  447. if not(m_default_inline in current_settings.modeswitches) then
  448. Message(parser_e_proc_inline_not_supported)
  449. else
  450. Message(parser_h_inlining_disabled);
  451. exclude(pd.procoptions,po_inline);
  452. end;
  453. { For varargs directive also cdecl and external must be defined }
  454. if (po_varargs in pd.procoptions) then
  455. begin
  456. { check first for external in the interface, if available there
  457. then the cdecl must also be there since there is no implementation
  458. available to contain it }
  459. if parse_only then
  460. begin
  461. { if external is available, then cdecl must also be available,
  462. procvars don't need external }
  463. if not((po_external in pd.procoptions) or
  464. (pd.typ=procvardef) or
  465. { for objcclasses this is checked later, because the entire
  466. class may be external. }
  467. is_objc_class_or_protocol(tprocdef(pd).struct)) and
  468. not(pd.proccalloption in (cdecl_pocalls + [pocall_stdcall])) then
  469. Message(parser_e_varargs_need_cdecl_and_external);
  470. end
  471. else
  472. begin
  473. { both must be defined now }
  474. if not((po_external in pd.procoptions) or
  475. (pd.typ=procvardef)) or
  476. not(pd.proccalloption in (cdecl_pocalls + [pocall_stdcall])) then
  477. Message(parser_e_varargs_need_cdecl_and_external);
  478. end;
  479. end;
  480. end;
  481. if hcc_insert_hidden_paras in flags then
  482. begin
  483. { insert hidden high parameters }
  484. pd.parast.SymList.ForEachCall(@insert_hidden_para,pd);
  485. { insert hidden self parameter }
  486. insert_self_and_vmt_para(pd);
  487. { insert funcret parameter if required }
  488. insert_funcret_para(pd);
  489. { Make var parameters regable, this must be done after the calling
  490. convention is set. }
  491. { this must be done before parentfp is insert, because getting all cases
  492. where parentfp must be in a memory location isn't catched properly so
  493. we put parentfp never in a register }
  494. pd.parast.SymList.ForEachCall(@set_addr_param_regable,pd);
  495. { insert parentfp parameter if required }
  496. insert_parentfp_para(pd);
  497. end;
  498. { Calculate parameter tlist }
  499. pd.calcparas;
  500. end;
  501. end.