This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
fix various compiler warnings from XS code
[perl5.git] / ext / XS-APItest / APItest.xs
index 0ff2ed1..03bbc92 100644 (file)
@@ -25,10 +25,13 @@ typedef struct {
     int peep_recording;
     AV *peep_recorder;
     AV *rpeep_recorder;
+    AV *xop_record;
 } my_cxt_t;
 
 START_MY_CXT
 
+MGVTBL vtbl_foo, vtbl_bar;
+
 /* indirect functions to test the [pa]MY_CXT macros */
 
 int
@@ -92,8 +95,8 @@ test_freeent(freeent_function *f) {
 #else
     /* Storing then deleting something should ensure that a hash entry is
        available.  */
-    hv_store(test_hash, "", 0, &PL_sv_yes, 0);
-    hv_delete(test_hash, "", 0, 0);
+    (void) hv_store(test_hash, "", 0, &PL_sv_yes, 0);
+    (void) hv_delete(test_hash, "", 0, 0);
 
     /* We need to "inline" new_he here as it's static, and the functions we
        test expect to be able to call del_HE on the HE  */
@@ -121,7 +124,7 @@ test_freeent(freeent_function *f) {
     i = 0;
     do {
        mPUSHu(results[i]);
-    } while (++i < sizeof(results)/sizeof(results[0]));
+    } while (++i < (int)(sizeof(results)/sizeof(results[0])));
 
     /* Goodbye to our extra reference.  */
     SvREFCNT_dec(test_scalar);
@@ -132,6 +135,7 @@ static I32
 bitflip_key(pTHX_ IV action, SV *field) {
     MAGIC *mg = mg_find(field, PERL_MAGIC_uvar);
     SV *keysv;
+    PERL_UNUSED_ARG(action);
     if (mg && (keysv = mg->mg_obj)) {
        STRLEN len;
        const char *p = SvPV(keysv, len);
@@ -167,6 +171,7 @@ static I32
 rot13_key(pTHX_ IV action, SV *field) {
     MAGIC *mg = mg_find(field, PERL_MAGIC_uvar);
     SV *keysv;
+    PERL_UNUSED_ARG(action);
     if (mg && (keysv = mg->mg_obj)) {
        STRLEN len;
        const char *p = SvPV(keysv, len);
@@ -249,6 +254,8 @@ rot13_key(pTHX_ IV action, SV *field) {
 
 STATIC I32
 rmagical_a_dummy(pTHX_ IV idx, SV *sv) {
+    PERL_UNUSED_ARG(idx);
+    PERL_UNUSED_ARG(sv);
     return 0;
 }
 
@@ -260,6 +267,7 @@ blockhook_csc_start(pTHX_ int full)
     dMY_CXT;
     AV *const cur = GvAV(MY_CXT.cscgv);
 
+    PERL_UNUSED_ARG(full);
     SAVEGENERICSV(GvAV(MY_CXT.cscgv));
 
     if (cur) {
@@ -279,6 +287,7 @@ blockhook_csc_pre_end(pTHX_ OP **o)
 {
     dMY_CXT;
 
+    PERL_UNUSED_ARG(o);
     /* if we hit the end of a scope we missed the start of, we need to
      * unconditionally clear @CSC */
     if (GvAV(MY_CXT.cscgv) == MY_CXT.cscav && MY_CXT.cscav) {
@@ -306,6 +315,7 @@ blockhook_test_pre_end(pTHX_ OP **o)
 {
     dMY_CXT;
 
+    PERL_UNUSED_ARG(o);
     if (MY_CXT.bhk_record)
         av_push(MY_CXT.bhkav, newSVpvs("pre_end"));
 }
@@ -315,6 +325,7 @@ blockhook_test_post_end(pTHX_ OP **o)
 {
     dMY_CXT;
 
+    PERL_UNUSED_ARG(o);
     if (MY_CXT.bhk_record)
         av_push(MY_CXT.bhkav, newSVpvs("post_end"));
 }
@@ -378,6 +389,8 @@ my_rpeep (pTHX_ OP *o)
 STATIC OP *
 THX_ck_entersub_args_lists(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
 {
+    PERL_UNUSED_ARG(namegv);
+    PERL_UNUSED_ARG(ckobj);
     return ck_entersub_args_list(entersubop);
 }
 
@@ -385,6 +398,8 @@ STATIC OP *
 THX_ck_entersub_args_scalars(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
 {
     OP *aop = cUNOPx(entersubop)->op_first;
+    PERL_UNUSED_ARG(namegv);
+    PERL_UNUSED_ARG(ckobj);
     if (!aop->op_sibling)
        aop = cUNOPx(aop)->op_first;
     for (aop = aop->op_sibling; aop->op_sibling; aop = aop->op_sibling) {
@@ -398,6 +413,8 @@ THX_ck_entersub_multi_sum(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
 {
     OP *sumop = NULL;
     OP *pushop = cUNOPx(entersubop)->op_first;
+    PERL_UNUSED_ARG(namegv);
+    PERL_UNUSED_ARG(ckobj);
     if (!pushop->op_sibling)
        pushop = cUNOPx(pushop)->op_first;
     while (1) {
@@ -555,6 +572,21 @@ THX_ck_entersub_establish_cleanup(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
     return estop;
 }
 
+STATIC OP *
+THX_ck_entersub_postinc(pTHX_ OP *entersubop, GV *namegv, SV *ckobj)
+{
+    OP *pushop, *argop;
+    ck_entersub_args_proto(entersubop, namegv, ckobj);
+    pushop = cUNOPx(entersubop)->op_first;
+    if(!pushop->op_sibling) pushop = cUNOPx(pushop)->op_first;
+    argop = pushop->op_sibling;
+    pushop->op_sibling = argop->op_sibling;
+    argop->op_sibling = NULL;
+    op_free(entersubop);
+    return newUNOP(OP_POSTINC, 0,
+       op_lvalue(op_contextualize(argop, G_SCALAR), OP_POSTINC));
+}
+
 /** RPN keyword parser **/
 
 #define sv_is_glob(sv) (SvTYPE(sv) == SVt_PVGV)
@@ -568,6 +600,7 @@ static SV *hintkey_swaptwostmts_sv, *hintkey_looprest_sv;
 static SV *hintkey_scopelessblock_sv;
 static SV *hintkey_stmtasexpr_sv, *hintkey_stmtsasexpr_sv;
 static SV *hintkey_loopblock_sv, *hintkey_blockasexpr_sv;
+static SV *hintkey_swaplabel_sv, *hintkey_labelconst_sv;
 static int (*next_keyword_plugin)(pTHX_ char *, STRLEN, OP **);
 
 /* low-level parser helpers */
@@ -741,12 +774,8 @@ static OP *THX_parse_keyword_swaptwostmts(pTHX)
 #define parse_keyword_looprest() THX_parse_keyword_looprest(aTHX)
 static OP *THX_parse_keyword_looprest(pTHX)
 {
-    I32 condline;
-    OP *body;
-    condline = CopLINE(PL_curcop);
-    body = parse_stmtseq(0);
-    return newWHILEOP(0, 1, NULL, condline, newSVOP(OP_CONST, 0, &PL_sv_yes),
-                       body, NULL, 1);
+    return newWHILEOP(0, 1, NULL, newSVOP(OP_CONST, 0, &PL_sv_yes),
+                       parse_stmtseq(0), NULL, 1);
 }
 
 #define parse_keyword_scopelessblock() THX_parse_keyword_scopelessblock(aTHX)
@@ -767,11 +796,10 @@ static OP *THX_parse_keyword_scopelessblock(pTHX)
 #define parse_keyword_stmtasexpr() THX_parse_keyword_stmtasexpr(aTHX)
 static OP *THX_parse_keyword_stmtasexpr(pTHX)
 {
-    OP *o = parse_fullstmt(0);
-    o = op_prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
-    o->op_type = OP_LEAVE;
-    o->op_ppaddr = PL_ppaddr[OP_LEAVE];
-    return o;
+    OP *o = parse_barestmt(0);
+    if (!o) o = newOP(OP_STUB, 0);
+    if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
+    return op_scope(o);
 }
 
 #define parse_keyword_stmtsasexpr() THX_parse_keyword_stmtsasexpr(aTHX)
@@ -785,31 +813,40 @@ static OP *THX_parse_keyword_stmtsasexpr(pTHX)
     lex_read_space(0);
     if(lex_peek_unichar(0) != /*{*/'}') croak("syntax error");
     lex_read_unichar(0);
-    o = op_prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
-    o->op_type = OP_LEAVE;
-    o->op_ppaddr = PL_ppaddr[OP_LEAVE];
-    return o;
+    if (!o) o = newOP(OP_STUB, 0);
+    if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
+    return op_scope(o);
 }
 
 #define parse_keyword_loopblock() THX_parse_keyword_loopblock(aTHX)
 static OP *THX_parse_keyword_loopblock(pTHX)
 {
-    I32 condline;
-    OP *body;
-    condline = CopLINE(PL_curcop);
-    body = parse_block(0);
-    return newWHILEOP(0, 1, NULL, condline, newSVOP(OP_CONST, 0, &PL_sv_yes),
-                       body, NULL, 1);
+    return newWHILEOP(0, 1, NULL, newSVOP(OP_CONST, 0, &PL_sv_yes),
+                       parse_block(0), NULL, 1);
 }
 
 #define parse_keyword_blockasexpr() THX_parse_keyword_blockasexpr(aTHX)
 static OP *THX_parse_keyword_blockasexpr(pTHX)
 {
     OP *o = parse_block(0);
-    o = op_prepend_elem(OP_LINESEQ, newOP(OP_ENTER, 0), o);
-    o->op_type = OP_LEAVE;
-    o->op_ppaddr = PL_ppaddr[OP_LEAVE];
-    return o;
+    if (!o) o = newOP(OP_STUB, 0);
+    if (PL_hints & HINT_BLOCK_SCOPE) o->op_flags |= OPf_PARENS;
+    return op_scope(o);
+}
+
+#define parse_keyword_swaplabel() THX_parse_keyword_swaplabel(aTHX)
+static OP *THX_parse_keyword_swaplabel(pTHX)
+{
+    OP *sop = parse_barestmt(0);
+    SV *label = parse_label(PARSE_OPTIONAL);
+    if (label) sv_2mortal(label);
+    return newSTATEOP(0, label ? savepv(SvPVX(label)) : NULL, sop);
+}
+
+#define parse_keyword_labelconst() THX_parse_keyword_labelconst(aTHX)
+static OP *THX_parse_keyword_labelconst(pTHX)
+{
+    return newSVOP(OP_CONST, 0, parse_label(0));
 }
 
 /* plugin glue */
@@ -868,11 +905,35 @@ static int my_keyword_plugin(pTHX_
                    keyword_active(hintkey_blockasexpr_sv)) {
        *op_ptr = parse_keyword_blockasexpr();
        return KEYWORD_PLUGIN_EXPR;
+    } else if(keyword_len == 9 && strnEQ(keyword_ptr, "swaplabel", 9) &&
+                   keyword_active(hintkey_swaplabel_sv)) {
+       *op_ptr = parse_keyword_swaplabel();
+       return KEYWORD_PLUGIN_STMT;
+    } else if(keyword_len == 10 && strnEQ(keyword_ptr, "labelconst", 10) &&
+                   keyword_active(hintkey_labelconst_sv)) {
+       *op_ptr = parse_keyword_labelconst();
+       return KEYWORD_PLUGIN_EXPR;
     } else {
        return next_keyword_plugin(aTHX_ keyword_ptr, keyword_len, op_ptr);
     }
 }
 
+static XOP my_xop;
+
+static OP *
+pp_xop(pTHX)
+{
+    return PL_op->op_next;
+}
+
+static void
+peep_xop(pTHX_ OP *o, OP *oldop)
+{
+    dMY_CXT;
+    av_push(MY_CXT.xop_record, newSVpvf("peep:%"UVxf, PTR2UV(o)));
+    av_push(MY_CXT.xop_record, newSVpvf("oldop:%"UVxf, PTR2UV(oldop)));
+}
+
 XS(XS_XS__APItest__XSUB_XS_VERSION_undef);
 XS(XS_XS__APItest__XSUB_XS_VERSION_empty);
 XS(XS_XS__APItest__XSUB_XS_APIVERSION_invalid);
@@ -885,6 +946,67 @@ INCLUDE: const-xs.inc
 
 INCLUDE: numeric.xs
 
+MODULE = XS::APItest::utf8     PACKAGE = XS::APItest::utf8
+
+int
+bytes_cmp_utf8(bytes, utf8)
+       SV *bytes
+       SV *utf8
+    PREINIT:
+       const U8 *b;
+       STRLEN blen;
+       const U8 *u;
+       STRLEN ulen;
+    CODE:
+       b = (const U8 *)SvPVbyte(bytes, blen);
+       u = (const U8 *)SvPVbyte(utf8, ulen);
+       RETVAL = bytes_cmp_utf8(b, blen, u, ulen);
+    OUTPUT:
+       RETVAL
+
+MODULE = XS::APItest:Overload  PACKAGE = XS::APItest::Overload
+
+void
+amagic_deref_call(sv, what)
+       SV *sv
+       int what
+    PPCODE:
+       /* The reference is owned by something else.  */
+       PUSHs(amagic_deref_call(sv, what));
+
+# I'd certainly like to discourage the use of this macro, given that we now
+# have amagic_deref_call
+
+void
+tryAMAGICunDEREF_var(sv, what)
+       SV *sv
+       int what
+    PPCODE:
+       {
+           SV **sp = &sv;
+           switch(what) {
+           case to_av_amg:
+               tryAMAGICunDEREF(to_av);
+               break;
+           case to_cv_amg:
+               tryAMAGICunDEREF(to_cv);
+               break;
+           case to_gv_amg:
+               tryAMAGICunDEREF(to_gv);
+               break;
+           case to_hv_amg:
+               tryAMAGICunDEREF(to_hv);
+               break;
+           case to_sv_amg:
+               tryAMAGICunDEREF(to_sv);
+               break;
+           default:
+               croak("Invalid value %d passed to tryAMAGICunDEREF_var", what);
+           }
+       }
+       /* The reference is owned by something else.  */
+       PUSHs(sv);
+
 MODULE = XS::APItest           PACKAGE = XS::APItest::XSUB
 
 BOOT:
@@ -1269,6 +1391,104 @@ MODULE = XS::APItest            PACKAGE = XS::APItest
 
 PROTOTYPES: DISABLE
 
+HV *
+xop_custom_ops ()
+    CODE:
+        RETVAL = PL_custom_ops;
+    OUTPUT:
+        RETVAL
+
+HV *
+xop_custom_op_names ()
+    CODE:
+        PL_custom_op_names = newHV();
+        RETVAL = PL_custom_op_names;
+    OUTPUT:
+        RETVAL
+
+HV *
+xop_custom_op_descs ()
+    CODE:
+        PL_custom_op_descs = newHV();
+        RETVAL = PL_custom_op_descs;
+    OUTPUT:
+        RETVAL
+
+void
+xop_register ()
+    CODE:
+        XopENTRY_set(&my_xop, xop_name, "my_xop");
+        XopENTRY_set(&my_xop, xop_desc, "XOP for testing");
+        XopENTRY_set(&my_xop, xop_class, OA_UNOP);
+        XopENTRY_set(&my_xop, xop_peep, peep_xop);
+        Perl_custom_op_register(aTHX_ pp_xop, &my_xop);
+
+void
+xop_clear ()
+    CODE:
+        XopDISABLE(&my_xop, xop_name);
+        XopDISABLE(&my_xop, xop_desc);
+        XopDISABLE(&my_xop, xop_class);
+        XopDISABLE(&my_xop, xop_peep);
+
+IV
+xop_my_xop ()
+    CODE:
+        RETVAL = PTR2IV(&my_xop);
+    OUTPUT:
+        RETVAL
+
+IV
+xop_ppaddr ()
+    CODE:
+        RETVAL = PTR2IV(pp_xop);
+    OUTPUT:
+        RETVAL
+
+IV
+xop_OA_UNOP ()
+    CODE:
+        RETVAL = OA_UNOP;
+    OUTPUT:
+        RETVAL
+
+AV *
+xop_build_optree ()
+    CODE:
+        dMY_CXT;
+        UNOP *unop;
+        OP *kid;
+
+        MY_CXT.xop_record = newAV();
+
+        kid = newSVOP(OP_CONST, 0, newSViv(42));
+        
+        NewOp(1102, unop, 1, UNOP);
+        unop->op_type       = OP_CUSTOM;
+        unop->op_ppaddr     = pp_xop;
+        unop->op_flags      = OPf_KIDS;
+        unop->op_private    = 0;
+        unop->op_first      = kid;
+        unop->op_next       = NULL;
+        kid->op_next        = (OP*)unop;
+
+        av_push(MY_CXT.xop_record, newSVpvf("unop:%"UVxf, PTR2UV(unop)));
+        av_push(MY_CXT.xop_record, newSVpvf("kid:%"UVxf, PTR2UV(kid)));
+
+        av_push(MY_CXT.xop_record, newSVpvf("NAME:%s", OP_NAME((OP*)unop)));
+        av_push(MY_CXT.xop_record, newSVpvf("DESC:%s", OP_DESC((OP*)unop)));
+        av_push(MY_CXT.xop_record, newSVpvf("CLASS:%d", (int)OP_CLASS((OP*)unop)));
+
+        PL_rpeepp(aTHX_ kid);
+
+        FreeOp(kid);
+        FreeOp(unop);
+
+        RETVAL = MY_CXT.xop_record;
+        MY_CXT.xop_record = NULL;
+    OUTPUT:
+        RETVAL
+
 BOOT:
 {
     MY_CXT_INIT;
@@ -1306,6 +1526,7 @@ void
 CLONE(...)
     CODE:
     MY_CXT_CLONE;
+    PERL_UNUSED_VAR(items);
     MY_CXT.sv = newSVpv("initial_clone",0);
     MY_CXT.cscgv = gv_fetchpvs("XS::APItest::COMPILE_SCOPE_CONTAINER",
         GV_ADDMULTI, SVt_PVAV);
@@ -2037,7 +2258,9 @@ test_cophh()
        check_ph(cophh_fetch_pvs(a, "foo_\xc2\x8c", 0));
        check_iv(cophh_fetch_pvs(a, "foo_\xd9\xa6", COPHH_KEY_UTF8), 666);
        check_ph(cophh_fetch_pvs(a, "foo_\xd9\xa6", 0));
-       cophh_free(a);
+       ENTER;
+       SAVEFREECOPHH(a);
+       LEAVE;
 #undef check_ph
 #undef check_iv
 #undef msvpvs
@@ -2378,6 +2601,36 @@ CODE:
 }
 
 
+SV*
+take_svref(SVREF sv)
+CODE:
+    RETVAL = newRV_inc(sv);
+OUTPUT:
+    RETVAL
+
+SV*
+take_avref(AV* av)
+CODE:
+    RETVAL = newRV_inc((SV*)av);
+OUTPUT:
+    RETVAL
+
+SV*
+take_hvref(HV* hv)
+CODE:
+    RETVAL = newRV_inc((SV*)hv);
+OUTPUT:
+    RETVAL
+
+
+SV*
+take_cvref(CV* cv)
+CODE:
+    RETVAL = newRV_inc((SV*)cv);
+OUTPUT:
+    RETVAL
+
+
 BOOT:
        {
        HV* stash;
@@ -2404,6 +2657,8 @@ BOOT:
     hintkey_stmtsasexpr_sv = newSVpvs_share("XS::APItest/stmtsasexpr");
     hintkey_loopblock_sv = newSVpvs_share("XS::APItest/loopblock");
     hintkey_blockasexpr_sv = newSVpvs_share("XS::APItest/blockasexpr");
+    hintkey_swaplabel_sv = newSVpvs_share("XS::APItest/swaplabel");
+    hintkey_labelconst_sv = newSVpvs_share("XS::APItest/labelconst");
     next_keyword_plugin = PL_keyword_plugin;
     PL_keyword_plugin = my_keyword_plugin;
 }
@@ -2412,6 +2667,7 @@ void
 establish_cleanup(...)
 PROTOTYPE: $
 CODE:
+    PERL_UNUSED_VAR(items);
     croak("establish_cleanup called as a function");
 
 BOOT:
@@ -2419,3 +2675,44 @@ BOOT:
     CV *estcv = get_cv("XS::APItest::establish_cleanup", 0);
     cv_set_call_checker(estcv, THX_ck_entersub_establish_cleanup, (SV*)estcv);
 }
+
+void
+postinc(...)
+PROTOTYPE: $
+CODE:
+    PERL_UNUSED_VAR(items);
+    croak("postinc called as a function");
+
+BOOT:
+{
+    CV *asscv = get_cv("XS::APItest::postinc", 0);
+    cv_set_call_checker(asscv, THX_ck_entersub_postinc, (SV*)asscv);
+}
+
+MODULE = XS::APItest           PACKAGE = XS::APItest::Magic
+
+PROTOTYPES: DISABLE
+
+void
+sv_magic_foo(SV *sv, SV *thingy)
+ALIAS:
+    sv_magic_bar = 1
+CODE:
+    sv_magicext(SvRV(sv), NULL, PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo, (const char *)thingy, 0);
+
+SV *
+mg_find_foo(SV *sv)
+ALIAS:
+    mg_find_bar = 1
+CODE:
+    MAGIC *mg = mg_findext(SvRV(sv), PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo);
+    RETVAL = mg ? SvREFCNT_inc((SV *)mg->mg_ptr) : &PL_sv_undef;
+OUTPUT:
+    RETVAL
+
+void
+sv_unmagic_foo(SV *sv)
+ALIAS:
+    sv_unmagic_bar = 1
+CODE:
+    sv_unmagicext(SvRV(sv), PERL_MAGIC_ext, ix ? &vtbl_bar : &vtbl_foo);