More accurate line numbers in messages
Paul Johnson [Thu, 12 Jul 2001 04:14:11 +0000 (06:14 +0200)]
Message-ID: <20010712041411.A3467@pjcj.net>

(With prototyping and multiplicity tweaks.)

p4raw-id: //depot/perl@11305

dump.c
embed.h
embed.pl
t/lib/warnings/util
util.c

diff --git a/dump.c b/dump.c
index f23ac7b..c2f7746 100644 (file)
--- a/dump.c
+++ b/dump.c
@@ -392,7 +392,20 @@ Perl_do_op_dump(pTHX_ I32 level, PerlIO *file, OP *o)
        PerlIO_printf(file, "DONE\n");
     if (o->op_targ) {
        if (o->op_type == OP_NULL)
+       {
            Perl_dump_indent(aTHX_ level, file, "  (was %s)\n", PL_op_name[o->op_targ]);
+           if (o->op_targ == OP_NEXTSTATE)
+           {
+               if (CopLINE(cCOPo))
+                   Perl_dump_indent(aTHX_ level, file, "LINE = %d\n",CopLINE(cCOPo));
+               if (CopSTASHPV(cCOPo))
+                   Perl_dump_indent(aTHX_ level, file, "PACKAGE = \"%s\"\n",
+                                    CopSTASHPV(cCOPo));
+               if (cCOPo->cop_label)
+                   Perl_dump_indent(aTHX_ level, file, "LABEL = \"%s\"\n",
+                                    cCOPo->cop_label);
+           }
+       }
        else
            Perl_dump_indent(aTHX_ level, file, "TARG = %ld\n", (long)o->op_targ);
     }
diff --git a/embed.h b/embed.h
index cb9eb6c..0a12dcd 100644 (file)
--- a/embed.h
+++ b/embed.h
 #define stdize_locale          S_stdize_locale
 #endif
 #if defined(PERL_IN_UTIL_C) || defined(PERL_DECL_PROT)
+#define closest_cop            S_closest_cop
 #define mess_alloc             S_mess_alloc
 #  if defined(LEAKTEST)
 #define xstat                  S_xstat
 #define stdize_locale(a)       S_stdize_locale(aTHX_ a)
 #endif
 #if defined(PERL_IN_UTIL_C) || defined(PERL_DECL_PROT)
+#define closest_cop(a,b)       S_closest_cop(aTHX_ a,b)
 #define mess_alloc()           S_mess_alloc(aTHX)
 #  if defined(LEAKTEST)
 #define xstat(a)               S_xstat(aTHX_ a)
 #define stdize_locale          S_stdize_locale
 #endif
 #if defined(PERL_IN_UTIL_C) || defined(PERL_DECL_PROT)
+#define S_closest_cop          CPerlObj::S_closest_cop
+#define closest_cop            S_closest_cop
 #define S_mess_alloc           CPerlObj::S_mess_alloc
 #define mess_alloc             S_mess_alloc
 #  if defined(LEAKTEST)
index 82ebfd2..ee21f3e 100755 (executable)
--- a/embed.pl
+++ b/embed.pl
@@ -2593,6 +2593,7 @@ s |char*  |stdize_locale  |char* locs
 #endif
 
 #if defined(PERL_IN_UTIL_C) || defined(PERL_DECL_PROT)
+s      |COP*   |closest_cop    |COP *cop|OP *o
 s      |SV*    |mess_alloc
 #  if defined(LEAKTEST)
 s      |void   |xstat          |int
index e82d6a6..4e960c1 100644 (file)
@@ -106,3 +106,53 @@ no warnings 'portable' ;
    $a =  oct "0047777777777" ;
 EXPECT
 Octal number > 037777777777 non-portable at - line 5.
+########
+# util.c
+use warnings;
+$x = 1;
+if ($x) {
+    print $y;
+}
+EXPECT
+Name "main::y" used only once: possible typo at - line 5.
+Use of uninitialized value in print at - line 5.
+########
+# util.c
+use warnings;
+$x = 1;
+if ($x) {
+    $x++;
+    print $y;
+}
+EXPECT
+Name "main::y" used only once: possible typo at - line 6.
+Use of uninitialized value in print at - line 6.
+########
+# util.c
+use warnings;
+$x = 0;
+if ($x) {
+    print "1\n";
+} elsif (!$x) {
+    print $y;
+} else {
+    print "0\n";
+}
+EXPECT
+Name "main::y" used only once: possible typo at - line 7.
+Use of uninitialized value in print at - line 7.
+########
+# util.c
+use warnings;
+$x = 0;
+if ($x) {
+    print "1\n";
+} elsif (!$x) {
+    $x++;
+    print $y;
+} else {
+    print "0\n";
+}
+EXPECT
+Name "main::y" used only once: possible typo at - line 8.
+Use of uninitialized value in print at - line 8.
diff --git a/util.c b/util.c
index b72a8f2..e01e836 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1003,17 +1003,60 @@ Perl_mess(pTHX_ const char *pat, ...)
     return retval;
 }
 
+STATIC COP*
+S_closest_cop(pTHX_ COP *cop, OP *o)
+{
+    /* Look for PL_op starting from o.  cop is the last COP we've seen. */
+
+    if (!o || o == PL_op) return cop;
+
+    if (o->op_flags & OPf_KIDS) {
+       OP *kid;
+       for (kid = cUNOPo->op_first; kid; kid = kid->op_sibling)
+       {
+           COP *new_cop;
+
+           /* If the OP_NEXTSTATE has been optimised away we can still use it
+            * the get the file and line number. */
+
+           if (kid->op_type == OP_NULL && kid->op_targ == OP_NEXTSTATE)
+               cop = (COP *)kid;
+
+           /* Keep searching, and return when we've found something. */
+
+           new_cop = closest_cop(cop, kid);
+           if (new_cop) return new_cop;
+       }
+    }
+
+    /* Nothing found. */
+
+    return 0;
+}
+
 SV *
 Perl_vmess(pTHX_ const char *pat, va_list *args)
 {
     SV *sv = mess_alloc();
     static char dgd[] = " during global destruction.\n";
+    COP *cop;
 
     sv_vsetpvfn(sv, pat, strlen(pat), args, Null(SV**), 0, Null(bool*));
     if (!SvCUR(sv) || *(SvEND(sv) - 1) != '\n') {
-       if (CopLINE(PL_curcop))
+
+       /*
+        * Try and find the file and line for PL_op.  This will usually be
+        * PL_curcop, but it might be a cop that has been optimised away.  We
+        * can try to find such a cop by searching through the optree starting
+        * from the sibling of PL_curcop.
+        */
+
+       cop = closest_cop(PL_curcop, PL_curcop->op_sibling);
+       if (!cop) cop = PL_curcop;
+
+       if (CopLINE(cop))
            Perl_sv_catpvf(aTHX_ sv, " at %s line %"IVdf,
-                          CopFILE(PL_curcop), (IV)CopLINE(PL_curcop));
+                          CopFILE(cop), (IV)CopLINE(cop));
        if (GvIO(PL_last_in_gv) && IoLINES(GvIOp(PL_last_in_gv))) {
            bool line_mode = (RsSIMPLE(PL_rs) &&
                              SvCUR(PL_rs) == 1 && *SvPVX(PL_rs) == '\n');