From: phk Date: Sat, 31 Mar 2007 08:36:31 +0000 (+0000) Subject: Overhaul cross reference checks in vcc compiler X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a5e3ec2337a3f2f5f91610ad925d99d82138d503;p=varnish Overhaul cross reference checks in vcc compiler Move and isolate cross reference stuff to it's own source file (vcc_xref.c) and use vcc_ prefix as originally intended. Also warn about multiple definitions of objects. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1291 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/lib/libvcl/Makefile.am b/varnish-cache/lib/libvcl/Makefile.am index a8184b6a..c5afed45 100644 --- a/varnish-cache/lib/libvcl/Makefile.am +++ b/varnish-cache/lib/libvcl/Makefile.am @@ -14,6 +14,7 @@ libvcl_la_SOURCES = \ vcc_parse.c \ vcc_fixed_token.c \ vcc_obj.c \ - vcc_token.c + vcc_token.c \ + vcc_xref.c libvcl_la_CFLAGS = -include config.h diff --git a/varnish-cache/lib/libvcl/flint.lnt b/varnish-cache/lib/libvcl/flint.lnt index d04ad898..94b2c7b2 100644 --- a/varnish-cache/lib/libvcl/flint.lnt +++ b/varnish-cache/lib/libvcl/flint.lnt @@ -18,7 +18,7 @@ -e763 // Redundant declaration for symbol '...' previously declared --e737 // Loss of sign in promotion from int to unsigned int +-e737 // Loss of sign in promotion from int to unsigned int -e715 // Symbol 'arg' (line 43) not referenced -e818 // Pointer parameter '...' could be declared as pointing to const diff --git a/varnish-cache/lib/libvcl/vcc_acl.c b/varnish-cache/lib/libvcl/vcc_acl.c index 33e98ad5..c2c7c528 100644 --- a/varnish-cache/lib/libvcl/vcc_acl.c +++ b/varnish-cache/lib/libvcl/vcc_acl.c @@ -60,7 +60,7 @@ vcc_Cond_Ip(struct var *vp, struct tokenlist *tl) case '~': vcc_NextToken(tl); ExpectErr(tl, ID); - AddRef(tl, tl->t, R_ACL); + vcc_AddRef(tl, tl->t, R_ACL); Fc(tl, 1, "VRT_acl_match(sp, \"%.*s\", acl_%.*s)\n", PF(tl->t), PF(tl->t)); vcc_NextToken(tl); @@ -87,7 +87,7 @@ vcc_Acl(struct tokenlist *tl) an = tl->t; vcc_NextToken(tl); - AddDef(tl, an, R_ACL); + vcc_AddDef(tl, an, R_ACL); Fh(tl, 0, "static struct vrt_acl acl_%.*s[];\n", PF(an)); Fc(tl, 1, "static struct vrt_acl acl_%.*s[] = {\n", PF(an)); diff --git a/varnish-cache/lib/libvcl/vcc_compile.c b/varnish-cache/lib/libvcl/vcc_compile.c index 6adc8723..425b1257 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.c +++ b/varnish-cache/lib/libvcl/vcc_compile.c @@ -85,7 +85,7 @@ #include "vrt.h" #include "libvcl.h" -static struct method method_tab[] = { +struct method method_tab[] = { #define VCL_RET_MAC(l,U,b,n) #define VCL_MET_MAC(l,U,m) { "vcl_"#l, m }, #include "vcl_returns.h" @@ -237,46 +237,6 @@ EncToken(struct vsb *sb, struct token *t) EncString(sb, t->dec, NULL, 0); } -/*-------------------------------------------------------------------- - * Keep track of definitions and references - */ - -static struct ref * -FindRef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - struct ref *r; - - TAILQ_FOREACH(r, &tl->refs, list) { - if (r->type != type) - continue; - if (vcc_Teq(r->name, t)) - return (r); - } - r = TlAlloc(tl, sizeof *r); - assert(r != NULL); - r->name = t; - r->type = type; - TAILQ_INSERT_TAIL(&tl->refs, r, list); - return (r); -} - -void -AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - - FindRef(tl, t, type)->refcnt++; -} - -void -AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) -{ - struct ref *r; - - r = FindRef(tl, t, type); - r->defcnt++; - r->name = t; -} - /*--------------------------------------------------------------------*/ static struct var * @@ -333,182 +293,6 @@ FindVar(struct tokenlist *tl, struct token *t, struct var *vl) return (NULL); } -/*-------------------------------------------------------------------- - * Consistency check - */ - -struct proc * -AddProc(struct tokenlist *tl, struct token *t, int def) -{ - struct proc *p; - - TAILQ_FOREACH(p, &tl->procs, list) { - if (!vcc_Teq(p->name, t)) - continue; - if (def) - p->name = t; - return (p); - } - p = TlAlloc(tl, sizeof *p); - assert(p != NULL); - p->name = t; - TAILQ_INIT(&p->calls); - TAILQ_INSERT_TAIL(&tl->procs, p, list); - return (p); -} - -void -AddCall(struct tokenlist *tl, struct token *t) -{ - struct proccall *pc; - struct proc *p; - - p = AddProc(tl, t, 0); - TAILQ_FOREACH(pc, &tl->curproc->calls, list) { - if (pc->p == p) - return; - } - pc = TlAlloc(tl, sizeof *pc); - assert(pc != NULL); - pc->p = p; - pc->t = t; - TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list); -} - -static int -Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns) -{ - unsigned u; - struct proccall *pc; - - if (!p->exists) { - vsb_printf(tl->sb, "Function %.*s does not exist\n", - PF(p->name)); - return (1); - } - if (p->active) { - vsb_printf(tl->sb, "Function recurses on\n"); - vcc_ErrWhere(tl, p->name); - return (1); - } - u = p->returns & ~returns; - if (u) { -#define VCL_RET_MAC(a, b, c, d) \ - if (u & VCL_RET_##b) { \ - vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \ - vcc_ErrWhere(tl, p->returnt[d]); \ - } -#include "vcl_returns.h" -#undef VCL_RET_MAC - vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name)); - vcc_ErrWhere(tl, p->name); - return (1); - } - p->active = 1; - TAILQ_FOREACH(pc, &p->calls, list) { - if (Consist_Decend(tl, pc->p, returns)) { - vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", - PF(p->name)); - vcc_ErrWhere(tl, pc->t); - return (1); - } - } - p->active = 0; - p->called++; - return (0); -} - -static int -Consistency(struct tokenlist *tl) -{ - struct proc *p; - struct method *m; - - TAILQ_FOREACH(p, &tl->procs, list) { - for(m = method_tab; m->name != NULL; m++) { - if (vcc_IdIs(p->name, m->name)) - break; - } - if (m->name == NULL) - continue; - if (Consist_Decend(tl, p, m->returns)) { - vsb_printf(tl->sb, - "\n...which is the \"%s\" method\n", m->name); - vsb_printf(tl->sb, "Legal actions are:"); -#define VCL_RET_MAC(a, b, c, d) \ - if (m->returns & c) \ - vsb_printf(tl->sb, " \"%s\"", #a); -#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d) -#include "vcl_returns.h" -#undef VCL_RET_MAC -#undef VCL_RET_MAC_E - vsb_printf(tl->sb, "\n"); - return (1); - } - } - TAILQ_FOREACH(p, &tl->procs, list) { - if (p->called) - continue; - vsb_printf(tl->sb, "Function unused\n"); - vcc_ErrWhere(tl, p->name); - return (1); - } - return (0); -} - -/*--------------------------------------------------------------------*/ - -static int -CheckRefs(struct tokenlist *tl) -{ - struct ref *r; - const char *type; - int nerr = 0; - - TAILQ_FOREACH(r, &tl->refs, list) { - if (r->defcnt != 0 && r->refcnt != 0) - continue; - nerr++; - - switch(r->type) { - case R_FUNC: - type = "function"; - break; - case R_ACL: - type = "acl"; - break; - case R_BACKEND: - type = "backend"; - break; - default: - ErrInternal(tl); - vsb_printf(tl->sb, "Ref "); - vcc_ErrToken(tl, r->name); - vsb_printf(tl->sb, " has unknown type %d\n", - r->type); - continue; - } - if (r->defcnt == 0 && r->name->tok == METHOD) { - vsb_printf(tl->sb, - "No definition for method %.*s\n", PF(r->name)); - continue; - } - - if (r->defcnt == 0) { - vsb_printf(tl->sb, - "Undefined %s %.*s, first reference:\n", - type, PF(r->name)); - vcc_ErrWhere(tl, r->name); - continue; - } - - vsb_printf(tl->sb, "Unused %s %.*s, defined:\n", - type, PF(r->name)); - vcc_ErrWhere(tl, r->name); - } - return (nerr); -} - /*-------------------------------------------------------------------- * Output the location/profiling table. For each counted token, we * record source+line+charpos for the first character in the token. @@ -939,13 +723,13 @@ vcc_CompileSource(struct vsb *sb, struct source *sp) if (tl->err) return (vcc_DestroyTokenList(tl, NULL)); - /* Perform consistency checks */ - Consistency(tl); - if (tl->err) + /* Check for orphans */ + if (vcc_CheckReferences(tl)) return (vcc_DestroyTokenList(tl, NULL)); - /* Check for orphans */ - if (CheckRefs(tl)) + /* Check that all action returns are legal */ + vcc_CheckAction(tl); + if (tl->err) return (vcc_DestroyTokenList(tl, NULL)); Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n"); diff --git a/varnish-cache/lib/libvcl/vcc_compile.h b/varnish-cache/lib/libvcl/vcc_compile.h index af350442..6fcfa985 100644 --- a/varnish-cache/lib/libvcl/vcc_compile.h +++ b/varnish-cache/lib/libvcl/vcc_compile.h @@ -120,26 +120,10 @@ struct var { struct method { const char *name; - unsigned returns; -}; - -struct proccall { - TAILQ_ENTRY(proccall) list; - struct proc *p; - struct token *t; -}; - -struct proc { - TAILQ_ENTRY(proc) list; - TAILQ_HEAD(,proccall) calls; - struct token *name; - unsigned returns; - unsigned exists; - unsigned called; - unsigned active; - struct token *returnt[VCL_RET_MAX]; + unsigned actions; }; +struct proc; /*--------------------------------------------------------------------*/ @@ -149,18 +133,15 @@ void vcc_Acl(struct tokenlist *tl); void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl); /* vcc_compile.c */ +extern struct method method_tab[]; void Fh(struct tokenlist *tl, int indent, const char *fmt, ...); void Fc(struct tokenlist *tl, int indent, const char *fmt, ...); void Fb(struct tokenlist *tl, int indent, const char *fmt, ...); void Fi(struct tokenlist *tl, int indent, const char *fmt, ...); void Ff(struct tokenlist *tl, int indent, const char *fmt, ...); unsigned UintVal(struct tokenlist *tl); -void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); -void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); void EncToken(struct vsb *sb, struct token *t); struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl); -void AddCall(struct tokenlist *tl, struct token *t); -struct proc *AddProc(struct tokenlist *tl, struct token *t, int def); int IsMethod(struct token *t); void *TlAlloc(struct tokenlist *tl, unsigned len); @@ -183,6 +164,16 @@ void vcc__ErrInternal(struct tokenlist *tl, const char *func, unsigned line); void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e); void vcc_FreeToken(struct token *t); +/* vcc_expr.c */ +void vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type); +void vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type); +int vcc_CheckReferences(struct tokenlist *tl); + +void vcc_AddCall(struct tokenlist *tl, struct token *t); +struct proc *vcc_AddProc(struct tokenlist *tl, struct token *t); +void vcc_ProcAction(struct proc *p, unsigned action, struct token *t); +int vcc_CheckAction(struct tokenlist *tl); + #define ERRCHK(tl) do { if ((tl)->err) return; } while (0) #define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__) #define Expect(a, b) vcc__Expect(a, b, __LINE__) diff --git a/varnish-cache/lib/libvcl/vcc_parse.c b/varnish-cache/lib/libvcl/vcc_parse.c index 6bfe344f..9331475e 100644 --- a/varnish-cache/lib/libvcl/vcc_parse.c +++ b/varnish-cache/lib/libvcl/vcc_parse.c @@ -527,8 +527,7 @@ Action(struct tokenlist *tl) return; #define VCL_RET_MAC(a,b,c,d) case T_##b: \ Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \ - tl->curproc->returns |= VCL_RET_##b; \ - tl->curproc->returnt[d] = at; \ + vcc_ProcAction(tl->curproc, d, at); \ return; #include "vcl_returns.h" #undef VCL_RET_MAC @@ -554,8 +553,8 @@ Action(struct tokenlist *tl) return; case T_CALL: ExpectErr(tl, ID); - AddCall(tl, tl->t); - AddRef(tl, tl->t, R_FUNC); + vcc_AddCall(tl, tl->t); + vcc_AddRef(tl, tl->t, R_FUNC); Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t)); Fb(tl, 1, "\treturn (1);\n"); vcc_NextToken(tl); @@ -620,7 +619,7 @@ Action(struct tokenlist *tl) case BACKEND: if (tl->t->tok == '=') { vcc_NextToken(tl); - AddRef(tl, tl->t, R_BACKEND); + vcc_AddRef(tl, tl->t, R_BACKEND); Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t)); vcc_NextToken(tl); Fb(tl, 0, ");\n"); @@ -717,9 +716,9 @@ Backend(struct tokenlist *tl) vcc_NextToken(tl); ExpectErr(tl, ID); t_be = tl->t; - AddDef(tl, tl->t, R_BACKEND); + vcc_AddDef(tl, tl->t, R_BACKEND); if (tl->nbackend == 0) - AddRef(tl, tl->t, R_BACKEND); + vcc_AddRef(tl, tl->t, R_BACKEND); Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n", PF(tl->t), tl->nbackend); Fc(tl, 0, "\n"); @@ -837,17 +836,15 @@ Function(struct tokenlist *tl) assert(m < N_METHODS); tl->fb = tl->fm[m]; if (tl->mprocs[m] == NULL) { - tl->mprocs[m] = AddProc(tl, tl->t, 1); - tl->mprocs[m]->exists++; - AddDef(tl, tl->t, R_FUNC); - AddRef(tl, tl->t, R_FUNC); + tl->mprocs[m] = vcc_AddProc(tl, tl->t); + vcc_AddDef(tl, tl->t, R_FUNC); + vcc_AddRef(tl, tl->t, R_FUNC); } tl->curproc = tl->mprocs[m]; } else { tl->fb = tl->fc; - tl->curproc = AddProc(tl, tl->t, 1); - tl->curproc->exists++; - AddDef(tl, tl->t, R_FUNC); + tl->curproc = vcc_AddProc(tl, tl->t); + vcc_AddDef(tl, tl->t, R_FUNC); Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n", PF(tl->t)); Fc(tl, 1, "static int\n"); diff --git a/varnish-cache/lib/libvcl/vcc_xref.c b/varnish-cache/lib/libvcl/vcc_xref.c new file mode 100644 index 00000000..4cbd151b --- /dev/null +++ b/varnish-cache/lib/libvcl/vcc_xref.c @@ -0,0 +1,307 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + * This fine contains code for two cross-reference or consistency checks. + * + * The first check is simply that all functions, acls and backends are + * both defined and referenced. Complaints about referenced but undefined + * or defined but unreferenced objects will be emitted. + * + * The second check recursively decends through function calls to make + * sure that action actions are correct for the methods through which + * they are called. + */ + +#include +#include + +#include "vsb.h" + +#include "vcc_priv.h" +#include "vcc_compile.h" + +/*--------------------------------------------------------------------*/ + +struct proccall { + TAILQ_ENTRY(proccall) list; + struct proc *p; + struct token *t; +}; + +struct proc { + TAILQ_ENTRY(proc) list; + TAILQ_HEAD(,proccall) calls; + struct token *name; + unsigned actions; + unsigned exists; + unsigned called; + unsigned active; + struct token *action_tok[VCL_RET_MAX]; +}; + +/*--------------------------------------------------------------------*/ + +static const char * +vcc_typename(struct tokenlist *tl, const struct ref *r) +{ + switch (r->type) { + case R_FUNC: return ("function"); + case R_ACL: return ("acl"); + case R_BACKEND: return ("backend"); + default: + ErrInternal(tl); + vsb_printf(tl->sb, "Ref "); + vcc_ErrToken(tl, r->name); + vsb_printf(tl->sb, " has unknown type %d\n", + r->type); + return "???"; + } +} + +/*-------------------------------------------------------------------- + * Keep track of definitions and references + */ + +static struct ref * +vcc_findref(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + struct ref *r; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->type != type) + continue; + if (vcc_Teq(r->name, t)) + return (r); + } + r = TlAlloc(tl, sizeof *r); + assert(r != NULL); + r->name = t; + r->type = type; + TAILQ_INSERT_TAIL(&tl->refs, r, list); + return (r); +} + +void +vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + + vcc_findref(tl, t, type)->refcnt++; +} + +void +vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type) +{ + struct ref *r; + const char *tp; + + r = vcc_findref(tl, t, type); + if (r->defcnt > 0) { + tp = vcc_typename(tl, r); + vsb_printf(tl->sb, "Multiple definitions of %s \"%.*s\"\n", + tp, PF(t)); + vcc_ErrWhere(tl, r->name); + vsb_printf(tl->sb, "...and\n"); + vcc_ErrWhere(tl, t); + } + r->defcnt++; + r->name = t; +} + +/*--------------------------------------------------------------------*/ + +int +vcc_CheckReferences(struct tokenlist *tl) +{ + struct ref *r; + const char *type; + int nerr = 0; + + TAILQ_FOREACH(r, &tl->refs, list) { + if (r->defcnt != 0 && r->refcnt != 0) + continue; + nerr++; + + type = vcc_typename(tl, r); + if (r->defcnt == 0 && r->name->tok == METHOD) { + vsb_printf(tl->sb, + "No definition for method %.*s\n", PF(r->name)); + continue; + } + + if (r->defcnt == 0) { + vsb_printf(tl->sb, + "Undefined %s %.*s, first reference:\n", + type, PF(r->name)); + vcc_ErrWhere(tl, r->name); + continue; + } + + vsb_printf(tl->sb, "Unused %s %.*s, defined:\n", + type, PF(r->name)); + vcc_ErrWhere(tl, r->name); + } + return (nerr); +} + +/*-------------------------------------------------------------------- + * Returned action checks + */ + +static struct proc * +vcc_findproc(struct tokenlist *tl, struct token *t) +{ + struct proc *p; + + TAILQ_FOREACH(p, &tl->procs, list) + if (vcc_Teq(p->name, t)) + return (p); + p = TlAlloc(tl, sizeof *p); + assert(p != NULL); + TAILQ_INIT(&p->calls); + TAILQ_INSERT_TAIL(&tl->procs, p, list); + p->name = t; + return (p); +} + +struct proc * +vcc_AddProc(struct tokenlist *tl, struct token *t) +{ + struct proc *p; + + p = vcc_findproc(tl, t); + p->name = t; /* make sure the name matches the definition */ + p->exists++; + return (p); +} + +void +vcc_AddCall(struct tokenlist *tl, struct token *t) +{ + struct proccall *pc; + struct proc *p; + + p = vcc_findproc(tl, t); + pc = TlAlloc(tl, sizeof *pc); + assert(pc != NULL); + pc->p = p; + pc->t = t; + TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list); +} + +void +vcc_ProcAction(struct proc *p, unsigned action, struct token *t) +{ + + p->actions |= (1 << action); + /* Record the first instance of this action */ + if (p->action_tok[action] == NULL) + p->action_tok[action] = t; +} + +static int +vcc_CheckActionRecurse(struct tokenlist *tl, struct proc *p, unsigned actions) +{ + unsigned u; + struct proccall *pc; + + if (!p->exists) { + vsb_printf(tl->sb, "Function %.*s does not exist\n", + PF(p->name)); + return (1); + } + if (p->active) { + vsb_printf(tl->sb, "Function recurses on\n"); + vcc_ErrWhere(tl, p->name); + return (1); + } + u = p->actions & ~actions; + if (u) { +#define VCL_RET_MAC(a, b, c, d) \ + if (u & VCL_RET_##b) { \ + vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \ + vcc_ErrWhere(tl, p->action_tok[d]); \ + } +#include "vcl_returns.h" +#undef VCL_RET_MAC + vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name)); + vcc_ErrWhere(tl, p->name); + return (1); + } + p->active = 1; + TAILQ_FOREACH(pc, &p->calls, list) { + if (vcc_CheckActionRecurse(tl, pc->p, actions)) { + vsb_printf(tl->sb, "\n...called from \"%.*s\"\n", + PF(p->name)); + vcc_ErrWhere(tl, pc->t); + return (1); + } + } + p->active = 0; + p->called++; + return (0); +} + +int +vcc_CheckAction(struct tokenlist *tl) +{ + struct proc *p; + struct method *m; + int i; + + TAILQ_FOREACH(p, &tl->procs, list) { + i = IsMethod(p->name); + if (i < 0) + continue; + m = method_tab + i; + if (vcc_CheckActionRecurse(tl, p, m->actions)) { + vsb_printf(tl->sb, + "\n...which is the \"%s\" method\n", m->name); + vsb_printf(tl->sb, "Legal actions are:"); +#define VCL_RET_MAC(a, b, c, d) \ + if (m->actions & c) \ + vsb_printf(tl->sb, " \"%s\"", #a); +#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d) +#include "vcl_returns.h" +#undef VCL_RET_MAC +#undef VCL_RET_MAC_E + vsb_printf(tl->sb, "\n"); + return (1); + } + } + TAILQ_FOREACH(p, &tl->procs, list) { + if (p->called) + continue; + vsb_printf(tl->sb, "Function unused\n"); + vcc_ErrWhere(tl, p->name); + return (1); + } + return (0); +} +