What does call_sv() return?
call_sv()の戻り値を正確に把握していないがために、Xslate で厄介なバグを引き起こしてしまった*1。具体的には、call_sv()でG_VOIDを指定すると常に1を返すと思い込んでいた。しかし、それは間違いだった。
検証:
https://github.com/gfx/p5-XS-CallSV
#!perl -w use strict; use Test::More; use B qw(/^G_/); use XS::SvCallTest; sub empty_pp { } sub return_empty_pp { return } sub return2_pp { return(10, 20) } sub fatal { die } note 'G_VOID'; is call_sv(\&empty_pp, G_VOID), 0; is call_sv(\&return_empty_pp, G_VOID), 0; is call_sv(\&return2_pp, G_VOID), 0; is call_sv(\&empty_xs, G_VOID), 0; is call_sv(\&return2_xs, G_VOID), 2; note 'G_SCALAR'; is call_sv(\&empty_pp, G_SCALAR), 1; is call_sv(\&return_empty_pp, G_SCALAR), 1; is call_sv(\&return2_pp, G_SCALAR), 1; is call_sv(\&empty_xs, G_SCALAR), 1; is call_sv(\&return2_xs, G_SCALAR), 1; note 'G_VOID | G_EVAL'; is call_sv(\&fatal, G_VOID | G_EVAL), 1; note 'G_SCALAR | G_EVAL'; is call_sv(\&fatal, G_SCALAR | G_EVAL), 1; done_testing;
このテストはすべてパスする。
興味深いのはG_VOIDで、基本的には0を返すが、1つ以上の値を返すケースではPPサブルーチンとXSUBで結果が変わる。また、G_EVALを指定しているときにサブルーチンが例外を投げると、なぜか1を返す。
G_SCALARについては常に1を返すとみていいようだが、心配なら assert(retval == 1) を仕込んでおくといいかもしれない。
*1:1.0004で修正済み