NetBSD/usr.bin/xlint/lint1/decl.c
christos 5c2e510661 Prevent lint1 from coredumping on invalid c code such as:
foo((sockaddr *(void *))0);

This fix is imperfect, because right now we just check the subtype
chains for NULL and we return to the caller when the loop ends, leaving
the upper layers to cope with the syntax error. Ideally we should:

	a.) return an error to the upper layer, or
	b.) not call the type analysis routines in the presence of a syntax
	    error.

That would require a significant re-write which would take much more time
than I have...
2000-07-05 22:50:59 +00:00

3171 lines
69 KiB
C

/* $NetBSD: decl.c,v 1.18 2000/07/05 22:50:59 christos Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
* Copyright (c) 1994, 1995 Jochen Pohl
* All Rights Reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Jochen Pohl for
* The NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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.
*/
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD");
#endif
#include <sys/param.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "lint1.h"
const char *unnamed = "<unnamed>";
/* contains various information and classification on types */
ttab_t ttab[NTSPEC];
/* shared type structures for arithmtic types and void */
static type_t *typetab;
/* value of next enumerator during declaration of enum types */
int enumval;
/*
* pointer to top element of a stack which contains informations local
* to nested declarations
*/
dinfo_t *dcs;
static type_t *tdeferr __P((type_t *, tspec_t));
static void settdsym __P((type_t *, sym_t *));
static tspec_t mrgtspec __P((tspec_t, tspec_t));
static void align __P((int, int));
static sym_t *newtag __P((sym_t *, scl_t, int, int));
static int eqargs __P((type_t *, type_t *, int *));
static int mnoarg __P((type_t *, int *));
static int chkosdef __P((sym_t *, sym_t *));
static int chkptdecl __P((sym_t *, sym_t *));
static sym_t *nsfunc __P((sym_t *, sym_t *));
static void osfunc __P((sym_t *, sym_t *));
static void ledecl __P((sym_t *));
static int chkinit __P((sym_t *));
static void chkausg __P((int, sym_t *));
static void chkvusg __P((int, sym_t *));
static void chklusg __P((sym_t *));
static void chktusg __P((sym_t *));
static void chkglvar __P((sym_t *));
static void glchksz __P((sym_t *));
/*
* initializes all global vars used in declarations
*/
void
initdecl()
{
int i;
static struct {
tspec_t it_tspec;
ttab_t it_ttab;
} ittab[] = {
{ SIGNED, { 0, 0,
SIGNED, UNSIGN,
0, 0, 0, 0, 0, "signed" } },
{ UNSIGN, { 0, 0,
SIGNED, UNSIGN,
0, 0, 0, 0, 0, "unsigned" } },
{ CHAR, { CHAR_BIT, CHAR_BIT,
SCHAR, UCHAR,
1, 0, 0, 1, 1, "char" } },
{ SCHAR, { CHAR_BIT, CHAR_BIT,
SCHAR, UCHAR,
1, 0, 0, 1, 1, "signed char" } },
{ UCHAR, { CHAR_BIT, CHAR_BIT,
SCHAR, UCHAR,
1, 1, 0, 1, 1, "unsigned char" } },
{ SHORT, { sizeof (short) * CHAR_BIT, 2 * CHAR_BIT,
SHORT, USHORT,
1, 0, 0, 1, 1, "short" } },
{ USHORT, { sizeof (u_short) * CHAR_BIT, 2 * CHAR_BIT,
SHORT, USHORT,
1, 1, 0, 1, 1, "unsigned short" } },
{ INT, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
INT, UINT,
1, 0, 0, 1, 1, "int" } },
{ UINT, { sizeof (u_int) * CHAR_BIT, 3 * CHAR_BIT,
INT, UINT,
1, 1, 0, 1, 1, "unsigned int" } },
{ LONG, { sizeof (long) * CHAR_BIT, 4 * CHAR_BIT,
LONG, ULONG,
1, 0, 0, 1, 1, "long" } },
{ ULONG, { sizeof (u_long) * CHAR_BIT, 4 * CHAR_BIT,
LONG, ULONG,
1, 1, 0, 1, 1, "unsigned long" } },
{ QUAD, { sizeof (quad_t) * CHAR_BIT, 8 * CHAR_BIT,
QUAD, UQUAD,
1, 0, 0, 1, 1, "long long" } },
{ UQUAD, { sizeof (u_quad_t) * CHAR_BIT, 8 * CHAR_BIT,
QUAD, UQUAD,
1, 1, 0, 1, 1, "unsigned long long" } },
{ FLOAT, { sizeof (float) * CHAR_BIT, 4 * CHAR_BIT,
FLOAT, FLOAT,
0, 0, 1, 1, 1, "float" } },
{ DOUBLE, { sizeof (double) * CHAR_BIT, 8 * CHAR_BIT,
DOUBLE, DOUBLE,
0, 0, 1, 1, 1, "double" } },
{ LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT,
LDOUBLE, LDOUBLE,
0, 0, 1, 1, 1, "long double" } },
{ VOID, { -1, -1,
VOID, VOID,
0, 0, 0, 0, 0, "void" } },
{ STRUCT, { -1, -1,
STRUCT, STRUCT,
0, 0, 0, 0, 0, "struct" } },
{ UNION, { -1, -1,
UNION, UNION,
0, 0, 0, 0, 0, "union" } },
{ ENUM, { sizeof (int) * CHAR_BIT, 3 * CHAR_BIT,
ENUM, ENUM,
1, 0, 0, 1, 1, "enum" } },
{ PTR, { sizeof (void *) * CHAR_BIT, 4 * CHAR_BIT,
PTR, PTR,
0, 1, 0, 0, 1, "pointer" } },
{ ARRAY, { -1, -1,
ARRAY, ARRAY,
0, 0, 0, 0, 0, "array" } },
{ FUNC, { -1, -1,
FUNC, FUNC,
0, 0, 0, 0, 0, "function" } },
};
/* declaration stack */
dcs = xcalloc(1, sizeof (dinfo_t));
dcs->d_ctx = EXTERN;
dcs->d_ldlsym = &dcs->d_dlsyms;
/* type information and classification */
for (i = 0; i < sizeof (ittab) / sizeof (ittab[0]); i++)
STRUCT_ASSIGN(ttab[ittab[i].it_tspec], ittab[i].it_ttab);
if (!pflag) {
for (i = 0; i < NTSPEC; i++)
ttab[i].tt_psz = ttab[i].tt_sz;
}
/* shared type structures */
typetab = xcalloc(NTSPEC, sizeof (type_t));
for (i = 0; i < NTSPEC; i++)
typetab[i].t_tspec = NOTSPEC;
typetab[CHAR].t_tspec = CHAR;
typetab[SCHAR].t_tspec = SCHAR;
typetab[UCHAR].t_tspec = UCHAR;
typetab[SHORT].t_tspec = SHORT;
typetab[USHORT].t_tspec = USHORT;
typetab[INT].t_tspec = INT;
typetab[UINT].t_tspec = UINT;
typetab[LONG].t_tspec = LONG;
typetab[ULONG].t_tspec = ULONG;
typetab[QUAD].t_tspec = QUAD;
typetab[UQUAD].t_tspec = UQUAD;
typetab[FLOAT].t_tspec = FLOAT;
typetab[DOUBLE].t_tspec = DOUBLE;
typetab[LDOUBLE].t_tspec = LDOUBLE;
typetab[VOID].t_tspec = VOID;
/*
* Next two are not real types. They are only used by the parser
* to return keywords "signed" and "unsigned"
*/
typetab[SIGNED].t_tspec = SIGNED;
typetab[UNSIGN].t_tspec = UNSIGN;
}
/*
* Returns a shared type structure vor arithmetic types and void.
*
* It's important do duplicate this structure (using duptyp() or tdupdyp())
* if it is to be modified (adding qualifiers or anything else).
*/
type_t *
gettyp(t)
tspec_t t;
{
return (&typetab[t]);
}
type_t *
duptyp(tp)
const type_t *tp;
{
type_t *ntp;
ntp = getblk(sizeof (type_t));
STRUCT_ASSIGN(*ntp, *tp);
return (ntp);
}
/*
* Use tduptyp() instead of duptyp() inside expressions (if the
* allocated memory should be freed after the expr).
*/
type_t *
tduptyp(tp)
const type_t *tp;
{
type_t *ntp;
ntp = tgetblk(sizeof (type_t));
STRUCT_ASSIGN(*ntp, *tp);
return (ntp);
}
/*
* Returns 1 if the argument is void or an incomplete array,
* struct, union or enum type.
*/
int
incompl(tp)
type_t *tp;
{
tspec_t t;
if ((t = tp->t_tspec) == VOID) {
return (1);
} else if (t == ARRAY) {
return (tp->t_aincompl);
} else if (t == STRUCT || t == UNION) {
return (tp->t_str->sincompl);
} else if (t == ENUM) {
return (tp->t_enum->eincompl);
}
return (0);
}
/*
* Set the flag for (in)complete array, struct, union or enum
* types.
*/
void
setcompl(tp, ic)
type_t *tp;
int ic;
{
tspec_t t;
if ((t = tp->t_tspec) == ARRAY) {
tp->t_aincompl = ic;
} else if (t == STRUCT || t == UNION) {
tp->t_str->sincompl = ic;
} else {
if (t != ENUM)
lerror("setcompl() 1");
tp->t_enum->eincompl = ic;
}
}
/*
* Remember the storage class of the current declaration in dcs->d_scl
* (the top element of the declaration stack) and detect multiple
* storage classes.
*/
void
addscl(sc)
scl_t sc;
{
if (sc == INLINE) {
if (dcs->d_inline)
/* duplicate '%s' */
warning(10, "inline");
dcs->d_inline = 1;
return;
}
if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
dcs->d_smod != NOTSPEC || dcs->d_lmod != NOTSPEC) {
/* storage class after type is obsolescent */
warning(83);
}
if (dcs->d_scl == NOSCL) {
dcs->d_scl = sc;
} else {
/*
* multiple storage classes. An error will be reported in
* deftyp().
*/
dcs->d_mscl = 1;
}
}
/*
* Remember the type, modifier or typedef name returned by the parser
* in *dcs (top element of decl stack). This information is used in
* deftyp() to build the type used for all declarators in this
* declaration.
*
* Is tp->t_typedef 1, the type comes from a previously defined typename.
* Otherwise it comes from a type specifier (int, long, ...) or a
* struct/union/enum tag.
*/
void
addtype(tp)
type_t *tp;
{
tspec_t t;
if (tp->t_typedef) {
if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
/*
* something like "typedef int a; int a b;"
* This should not happen with current grammar.
*/
lerror("addtype()");
}
dcs->d_type = tp;
return;
}
t = tp->t_tspec;
if (t == STRUCT || t == UNION || t == ENUM) {
/*
* something like "int struct a ..."
* struct/union/enum with anything else is not allowed
*/
if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC ||
dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) {
/*
* remember that an error must be reported in
* deftyp().
*/
dcs->d_terr = 1;
dcs->d_atyp = dcs->d_lmod = dcs->d_smod = NOTSPEC;
}
dcs->d_type = tp;
return;
}
if (dcs->d_type != NULL && !dcs->d_type->t_typedef) {
/*
* something like "struct a int"
* struct/union/enum with anything else is not allowed
*/
dcs->d_terr = 1;
return;
}
if (t == LONG && dcs->d_lmod == LONG) {
/* "long long" or "long ... long" */
t = QUAD;
dcs->d_lmod = NOTSPEC;
if (!quadflg)
/* %s C does not support 'long long' */
(void)gnuism(265, tflag ? "traditional" : "ANSI");
}
if (dcs->d_type != NULL && dcs->d_type->t_typedef) {
/* something like "typedef int a; a long ..." */
dcs->d_type = tdeferr(dcs->d_type, t);
return;
}
/* now it can be only a combination of arithmetic types and void */
if (t == SIGNED || t == UNSIGN) {
/* remeber specifiers "signed" and "unsigned" in dcs->d_smod */
if (dcs->d_smod != NOTSPEC)
/*
* more then one "signed" and/or "unsigned"; print
* an error in deftyp()
*/
dcs->d_terr = 1;
dcs->d_smod = t;
} else if (t == SHORT || t == LONG || t == QUAD) {
/*
* remember specifiers "short", "long" and "long long" in
* dcs->d_lmod
*/
if (dcs->d_lmod != NOTSPEC)
/* more than one, print error in deftyp() */
dcs->d_terr = 1;
dcs->d_lmod = t;
} else {
/*
* remember specifiers "void", "char", "int", "float" or
* "double" int dcs->d_atyp
*/
if (dcs->d_atyp != NOTSPEC)
/* more than one, print error in deftyp() */
dcs->d_terr = 1;
dcs->d_atyp = t;
}
}
/*
* called if a list of declaration specifiers contains a typedef name
* and other specifiers (except struct, union, enum, typedef name)
*/
static type_t *
tdeferr(td, t)
type_t *td;
tspec_t t;
{
tspec_t t2;
t2 = td->t_tspec;
switch (t) {
case SIGNED:
case UNSIGN:
if (t2 == CHAR || t2 == SHORT || t2 == INT || t2 == LONG ||
t2 == QUAD) {
if (!tflag)
/* modifying typedef with ... */
warning(5, ttab[t].tt_name);
td = duptyp(gettyp(mrgtspec(t2, t)));
td->t_typedef = 1;
return (td);
}
break;
case SHORT:
if (t2 == INT || t2 == UINT) {
/* modifying typedef with ... */
warning(5, "short");
td = duptyp(gettyp(t2 == INT ? SHORT : USHORT));
td->t_typedef = 1;
return (td);
}
break;
case LONG:
if (t2 == INT || t2 == UINT || t2 == LONG || t2 == ULONG ||
t2 == FLOAT || t2 == DOUBLE) {
/* modifying typedef with ... */
warning(5, "long");
if (t2 == INT) {
td = gettyp(LONG);
} else if (t2 == UINT) {
td = gettyp(ULONG);
} else if (t2 == LONG) {
td = gettyp(QUAD);
} else if (t2 == ULONG) {
td = gettyp(UQUAD);
} else if (t2 == FLOAT) {
td = gettyp(DOUBLE);
} else if (t2 == DOUBLE) {
td = gettyp(LDOUBLE);
}
td = duptyp(td);
td->t_typedef = 1;
return (td);
}
break;
/* LINTED (enumeration values not handled in switch) */
case NOTSPEC:
case USHORT:
case UCHAR:
case SCHAR:
case CHAR:
case FUNC:
case ARRAY:
case PTR:
case ENUM:
case UNION:
case STRUCT:
case VOID:
case LDOUBLE:
case DOUBLE:
case FLOAT:
case UQUAD:
case QUAD:
case ULONG:
case UINT:
case INT:
break;
}
/* Anything other is not accepted. */
dcs->d_terr = 1;
return (td);
}
/*
* Remember the symbol of a typedef name (2nd arg) in a struct, union
* or enum tag if the typedef name is the first defined for this tag.
*
* If the tag is unnamed, the typdef name is used for identification
* of this tag in lint2. Although its possible that more then one typedef
* name is defined for one tag, the first name defined should be unique
* if the tag is unnamed.
*/
static void
settdsym(tp, sym)
type_t *tp;
sym_t *sym;
{
tspec_t t;
if ((t = tp->t_tspec) == STRUCT || t == UNION) {
if (tp->t_str->stdef == NULL)
tp->t_str->stdef = sym;
} else if (t == ENUM) {
if (tp->t_enum->etdef == NULL)
tp->t_enum->etdef = sym;
}
}
/*
* Remember a qualifier which is part of the declaration specifiers
* (and not the declarator) in the top element of the declaration stack.
* Also detect multiple qualifiers of the same kind.
* The rememberd qualifier is used by deftyp() to construct the type
* for all declarators.
*/
void
addqual(q)
tqual_t q;
{
if (q == CONST) {
if (dcs->d_const) {
/* duplicate "%s" */
warning(10, "const");
}
dcs->d_const = 1;
} else {
if (q != VOLATILE)
lerror("addqual() 1");
if (dcs->d_volatile) {
/* duplicate "%s" */
warning(10, "volatile");
}
dcs->d_volatile = 1;
}
}
/*
* Go to the next declaration level (structs, nested structs, blocks,
* argument declaration lists ...)
*/
void
pushdecl(sc)
scl_t sc;
{
dinfo_t *di;
if (dflag)
(void)printf("pushdecl(%d)\n", (int)sc);
/* put a new element on the declaration stack */
di = xcalloc(1, sizeof (dinfo_t));
di->d_nxt = dcs;
dcs = di;
di->d_ctx = sc;
di->d_ldlsym = &di->d_dlsyms;
}
/*
* Go back to previous declaration level
*/
void
popdecl()
{
dinfo_t *di;
if (dflag)
(void)printf("popdecl(%d)\n", (int)dcs->d_ctx);
if (dcs->d_nxt == NULL)
lerror("popdecl() 1");
di = dcs;
dcs = di->d_nxt;
switch (di->d_ctx) {
case EXTERN:
/* there is nothing after external declarations */
lerror("popdecl() 2");
/* NOTREACHED */
case MOS:
case MOU:
case ENUMCON:
/*
* Symbols declared in (nested) structs or enums are
* part of the next level (they are removed from the
* symbol table if the symbols of the outher level are
* removed)
*/
if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
dcs->d_ldlsym = di->d_ldlsym;
break;
case ARG:
/*
* All symbols in dcs->d_dlsyms are introduced in old style
* argument declarations (it's not clean, but possible).
* They are appended to the list of symbols declared in
* an old style argument identifier list or a new style
* parameter type list.
*/
if (di->d_dlsyms != NULL) {
*di->d_ldlsym = dcs->d_fpsyms;
dcs->d_fpsyms = di->d_dlsyms;
}
break;
case ABSTRACT:
/*
* casts and sizeof
* Append all symbols declared in the abstract declaration
* to the list of symbols declared in the surounding decl.
* or block.
* XXX I'm not sure whether they should be removed from the
* symbol table now or later.
*/
if ((*dcs->d_ldlsym = di->d_dlsyms) != NULL)
dcs->d_ldlsym = di->d_ldlsym;
break;
case AUTO:
/* check usage of local vars */
chkusage(di);
/* FALLTHROUGH */
case PARG:
/* usage of arguments will be checked by funcend() */
rmsyms(di->d_dlsyms);
break;
default:
lerror("popdecl() 3");
}
free(di);
}
/*
* Set flag d_asm in all declaration stack elements up to the
* outermost one.
*
* This is used to mark compound statements which have, possibly in
* nested compound statements, asm statements. For these compound
* statements no warnings about unused or unitialized variables are
* printed.
*
* There is no need to clear d_asm in dinfo structs with context AUTO,
* because these structs are freed at the end of the compound statement.
* But it must be cleard in the outermost dinfo struct, which has
* context EXTERN. This could be done in clrtyp() and would work for
* C, but not for C++ (due to mixed statements and declarations). Thus
* we clear it in glclup(), which is used to do some cleanup after
* global declarations/definitions.
*/
void
setasm()
{
dinfo_t *di;
for (di = dcs; di != NULL; di = di->d_nxt)
di->d_asm = 1;
}
/*
* Clean all elements of the top element of declaration stack which
* will be used by the next declaration
*/
void
clrtyp()
{
dcs->d_atyp = dcs->d_smod = dcs->d_lmod = NOTSPEC;
dcs->d_scl = NOSCL;
dcs->d_type = NULL;
dcs->d_const = dcs->d_volatile = 0;
dcs->d_inline = 0;
dcs->d_mscl = dcs->d_terr = 0;
dcs->d_nedecl = 0;
dcs->d_notyp = 0;
}
/*
* Create a type structure from the informations gathered in
* the declaration stack.
* Complain about storage classes which are not possible in current
* context.
*/
void
deftyp()
{
tspec_t t, s, l;
type_t *tp;
scl_t scl;
t = dcs->d_atyp; /* CHAR, INT, FLOAT, DOUBLE, VOID */
s = dcs->d_smod; /* SIGNED, UNSIGNED */
l = dcs->d_lmod; /* SHORT, LONG, QUAD */
tp = dcs->d_type;
scl = dcs->d_scl;
if (t == NOTSPEC && s == NOTSPEC && l == NOTSPEC && tp == NULL)
dcs->d_notyp = 1;
if (tp != NULL && (t != NOTSPEC || s != NOTSPEC || l != NOTSPEC)) {
/* should never happen */
lerror("deftyp() 1");
}
if (tp == NULL) {
switch (t) {
case NOTSPEC:
t = INT;
/* FALLTHROUGH */
case INT:
if (s == NOTSPEC)
s = SIGNED;
break;
case CHAR:
if (l != NOTSPEC) {
dcs->d_terr = 1;
l = NOTSPEC;
}
break;
case FLOAT:
if (l == LONG) {
l = NOTSPEC;
t = DOUBLE;
if (!tflag)
/* use 'double' instead of ... */
warning(6);
}
break;
case DOUBLE:
if (l == LONG) {
l = NOTSPEC;
t = LDOUBLE;
if (tflag)
/* 'long double' is illegal in ... */
warning(266);
}
break;
case VOID:
break;
default:
lerror("deftyp() 2");
}
if (t != INT && t != CHAR && (s != NOTSPEC || l != NOTSPEC)) {
dcs->d_terr = 1;
l = s = NOTSPEC;
}
if (l != NOTSPEC)
t = l;
dcs->d_type = gettyp(mrgtspec(t, s));
}
if (dcs->d_mscl) {
/* only one storage class allowed */
error(7);
}
if (dcs->d_terr) {
/* illegal type combination */
error(4);
}
if (dcs->d_ctx == EXTERN) {
if (scl == REG || scl == AUTO) {
/* illegal storage class */
error(8);
scl = NOSCL;
}
} else if (dcs->d_ctx == ARG || dcs->d_ctx == PARG) {
if (scl != NOSCL && scl != REG) {
/* only "register" valid ... */
error(9);
scl = NOSCL;
}
}
dcs->d_scl = scl;
if (dcs->d_const && dcs->d_type->t_const) {
if (!dcs->d_type->t_typedef)
lerror("deftyp() 3");
/* typedef already qualified with "%s" */
warning(68, "const");
}
if (dcs->d_volatile && dcs->d_type->t_volatile) {
if (!dcs->d_type->t_typedef)
lerror("deftyp() 4");
/* typedef already qualified with "%s" */
warning(68, "volatile");
}
if (dcs->d_const || dcs->d_volatile) {
dcs->d_type = duptyp(dcs->d_type);
dcs->d_type->t_const |= dcs->d_const;
dcs->d_type->t_volatile |= dcs->d_volatile;
}
}
/*
* Merge type specifiers (char, ..., long long, signed, unsigned).
*/
static tspec_t
mrgtspec(t, s)
tspec_t t, s;
{
if (s == SIGNED || s == UNSIGN) {
if (t == CHAR) {
t = s == SIGNED ? SCHAR : UCHAR;
} else if (t == SHORT) {
t = s == SIGNED ? SHORT : USHORT;
} else if (t == INT) {
t = s == SIGNED ? INT : UINT;
} else if (t == LONG) {
t = s == SIGNED ? LONG : ULONG;
} else if (t == QUAD) {
t = s == SIGNED ? QUAD : UQUAD;
}
}
return (t);
}
/*
* Return the length of a type in bit.
*
* Printing a message if the outhermost dimension of an array is 0 must
* be done by the caller. All other problems are reported by length()
* if name is not NULL.
*/
int
length(tp, name)
type_t *tp;
const char *name;
{
int elem, elsz;
elem = 1;
while (tp && tp->t_tspec == ARRAY) {
elem *= tp->t_dim;
tp = tp->t_subt;
}
if (tp == NULL)
return -1;
switch (tp->t_tspec) {
case FUNC:
/* compiler takes size of function */
lerror(msgs[12]);
/* NOTREACHED */
case STRUCT:
case UNION:
if (incompl(tp) && name != NULL) {
/* incomplete structure or union %s: %s */
error(31, tp->t_str->stag->s_name, name);
}
elsz = tp->t_str->size;
break;
case ENUM:
if (incompl(tp) && name != NULL) {
/* incomplete enum type: %s */
warning(13, name);
}
/* FALLTHROUGH */
default:
elsz = size(tp->t_tspec);
if (elsz <= 0)
lerror("length()");
break;
}
return (elem * elsz);
}
/*
* Get the alignment of the given Type in bits.
*/
int
getbound(tp)
type_t *tp;
{
int a;
tspec_t t;
while (tp && tp->t_tspec == ARRAY)
tp = tp->t_subt;
if (tp == NULL)
return -1;
if ((t = tp->t_tspec) == STRUCT || t == UNION) {
a = tp->t_str->align;
} else if (t == FUNC) {
/* compiler takes alignment of function */
error(14);
a = ALIGN(1) * CHAR_BIT;
} else {
if ((a = size(t)) == 0) {
a = CHAR_BIT;
} else if (a > ALIGN(1) * CHAR_BIT) {
a = ALIGN(1) * CHAR_BIT;
}
}
if (a < CHAR_BIT || a > ALIGN(1) * CHAR_BIT)
lerror("getbound() 1");
return (a);
}
/*
* Concatenate two lists of symbols by s_nxt. Used by declarations of
* struct/union/enum elements and parameters.
*/
sym_t *
lnklst(l1, l2)
sym_t *l1, *l2;
{
sym_t *l;
if ((l = l1) == NULL)
return (l2);
while (l1->s_nxt != NULL)
l1 = l1->s_nxt;
l1->s_nxt = l2;
return (l);
}
/*
* Check if the type of the given symbol is valid and print an error
* message if it is not.
*
* Invalid types are:
* - arrays of incomlete types or functions
* - functions returning arrays or functions
* - void types other than type of function or pointer
*/
void
chktyp(sym)
sym_t *sym;
{
tspec_t to, t;
type_t **tpp, *tp;
tpp = &sym->s_type;
to = NOTSPEC;
while ((tp = *tpp) != NULL) {
t = tp->t_tspec;
/*
* If this is the type of an old style function definition,
* a better warning is printed in funcdef().
*/
if (t == FUNC && !tp->t_proto &&
!(to == NOTSPEC && sym->s_osdef)) {
if (sflag && hflag)
/* function declaration is not a prototype */
warning(287);
}
if (to == FUNC) {
if (t == FUNC || t == ARRAY) {
/* function returns illegal type */
error(15);
if (t == FUNC) {
*tpp = incref(*tpp, PTR);
} else {
*tpp = incref((*tpp)->t_subt, PTR);
}
return;
} else if (tp->t_const || tp->t_volatile) {
if (sflag) { /* XXX oder better !tflag ? */
/* function cannot return const... */
warning(228);
}
}
} if (to == ARRAY) {
if (t == FUNC) {
/* array of function is illegal */
error(16);
*tpp = gettyp(INT);
return;
} else if (t == ARRAY && tp->t_dim == 0) {
/* null dimension */
error(17);
return;
} else if (t == VOID) {
/* illegal use of void */
error(18);
*tpp = gettyp(INT);
#if 0 /* errors are produced by length() */
} else if (incompl(tp)) {
/* array of incomplete type */
if (sflag) {
error(301);
} else {
warning(301);
}
#endif
}
} else if (to == NOTSPEC && t == VOID) {
if (dcs->d_ctx == PARG) {
if (sym->s_scl != ABSTRACT) {
if (sym->s_name == unnamed)
lerror("chktyp()");
/* void param cannot have name: %s */
error(61, sym->s_name);
*tpp = gettyp(INT);
}
} else if (dcs->d_ctx == ABSTRACT) {
/* ok */
} else if (sym->s_scl != TYPEDEF) {
/* void type for %s */
error(19, sym->s_name);
*tpp = gettyp(INT);
}
}
if (t == VOID && to != PTR) {
if (tp->t_const || tp->t_volatile) {
/* inappropriate qualifiers with "void" */
warning(69);
tp->t_const = tp->t_volatile = 0;
}
}
tpp = &tp->t_subt;
to = t;
}
}
/*
* Process the declarator of a struct/union element.
*/
sym_t *
decl1str(dsym)
sym_t *dsym;
{
type_t *tp;
tspec_t t;
int sz, len;
int o = 0; /* Appease gcc */
scl_t sc;
if ((sc = dsym->s_scl) != MOS && sc != MOU)
lerror("decl1str() 1");
if (dcs->d_rdcsym != NULL) {
if ((sc = dcs->d_rdcsym->s_scl) != MOS && sc != MOU)
/* should be ensured by storesym() */
lerror("decl1str() 2");
if (dsym->s_styp == dcs->d_rdcsym->s_styp) {
/* duplicate member name: %s */
error(33, dsym->s_name);
rmsym(dcs->d_rdcsym);
}
}
chktyp(dsym);
t = (tp = dsym->s_type)->t_tspec;
if (dsym->s_field) {
/*
* bit field
*
* only unsigned und signed int are protable bit-field types
*(at least in ANSI C, in traditional C only unsigned int)
*/
if (t == CHAR || t == UCHAR || t == SCHAR ||
t == SHORT || t == USHORT || t == ENUM) {
if (sflag) {
/* bit-field type '%s' invalid in ANSI C */
warning(273, tyname(tp));
} else if (pflag) {
/* nonportable bit-field type */
warning(34);
}
} else if (t == INT && dcs->d_smod == NOTSPEC) {
if (pflag) {
/* nonportable bit-field type */
warning(34);
}
} else if (t != INT && t != UINT) {
/* illegal bit-field type */
error(35);
sz = tp->t_flen;
dsym->s_type = tp = duptyp(gettyp(t = INT));
if ((tp->t_flen = sz) > size(t))
tp->t_flen = size(t);
}
if ((len = tp->t_flen) < 0 || len > size(t)) {
/* illegal bit-field size */
error(36);
tp->t_flen = size(t);
} else if (len == 0 && dsym->s_name != unnamed) {
/* zero size bit-field */
error(37);
tp->t_flen = size(t);
}
if (dsym->s_scl == MOU) {
/* illegal use of bit-field */
error(41);
dsym->s_type->t_isfield = 0;
dsym->s_field = 0;
}
} else if (t == FUNC) {
/* function illegal in structure or union */
error(38);
dsym->s_type = tp = incref(tp, t = PTR);
}
/*
* bit-fields of length 0 are not warned about because length()
* does not return the length of the bit-field but the length
* of the type the bit-field is packed in (its ok)
*/
if ((sz = length(dsym->s_type, dsym->s_name)) == 0) {
if (t == ARRAY && dsym->s_type->t_dim == 0) {
/* illegal zero sized structure member: %s */
warning(39, dsym->s_name);
}
}
if (dcs->d_ctx == MOU) {
o = dcs->d_offset;
dcs->d_offset = 0;
}
if (dsym->s_field) {
align(getbound(tp), tp->t_flen);
dsym->s_value.v_quad = (dcs->d_offset / size(t)) * size(t);
tp->t_foffs = dcs->d_offset - (int)dsym->s_value.v_quad;
dcs->d_offset += tp->t_flen;
} else {
align(getbound(tp), 0);
dsym->s_value.v_quad = dcs->d_offset;
dcs->d_offset += sz;
}
if (dcs->d_ctx == MOU) {
if (o > dcs->d_offset)
dcs->d_offset = o;
}
chkfdef(dsym, 0);
return (dsym);
}
/*
* Aligns next structure element as required.
*
* al contains the required alignment, len the length of a bit-field.
*/
static void
align(al, len)
int al, len;
{
int no;
/*
* The alignment of the current element becomes the alignment of
* the struct/union if it is larger than the current alignment
* of the struct/union.
*/
if (al > dcs->d_stralign)
dcs->d_stralign = al;
no = (dcs->d_offset + (al - 1)) & ~(al - 1);
if (len == 0 || dcs->d_offset + len > no)
dcs->d_offset = no;
}
/*
* Remember the width of the field in its type structure.
*/
sym_t *
bitfield(dsym, len)
sym_t *dsym;
int len;
{
if (dsym == NULL) {
dsym = getblk(sizeof (sym_t));
dsym->s_name = unnamed;
dsym->s_kind = FMOS;
dsym->s_scl = MOS;
dsym->s_type = gettyp(INT);
dsym->s_blklev = -1;
}
dsym->s_type = duptyp(dsym->s_type);
dsym->s_type->t_isfield = 1;
dsym->s_type->t_flen = len;
dsym->s_field = 1;
return (dsym);
}
/*
* Collect informations about a sequence of asterisks and qualifiers
* in a list of type pqinf_t.
* Qualifiers refer always to the left asterisk. The rightmost asterisk
* will be at the top of the list.
*/
pqinf_t *
mergepq(p1, p2)
pqinf_t *p1, *p2;
{
pqinf_t *p;
if (p2->p_pcnt != 0) {
/* left '*' at the end of the list */
for (p = p2; p->p_nxt != NULL; p = p->p_nxt) ;
p->p_nxt = p1;
return (p2);
} else {
if (p2->p_const) {
if (p1->p_const) {
/* duplicate %s */
warning(10, "const");
}
p1->p_const = 1;
}
if (p2->p_volatile) {
if (p1->p_volatile) {
/* duplicate %s */
warning(10, "volatile");
}
p1->p_volatile = 1;
}
free(p2);
return (p1);
}
}
/*
* Followint 3 functions extend the type of a declarator with
* pointer, function and array types.
*
* The current type is the Type built by deftyp() (dcs->d_type) and
* pointer, function and array types already added for this
* declarator. The new type extension is inserted between both.
*/
sym_t *
addptr(decl, pi)
sym_t *decl;
pqinf_t *pi;
{
type_t **tpp, *tp;
pqinf_t *npi;
tpp = &decl->s_type;
while (*tpp && *tpp != dcs->d_type)
tpp = &(*tpp)->t_subt;
if (*tpp == NULL)
return decl;
while (pi != NULL) {
*tpp = tp = getblk(sizeof (type_t));
tp->t_tspec = PTR;
tp->t_const = pi->p_const;
tp->t_volatile = pi->p_volatile;
*(tpp = &tp->t_subt) = dcs->d_type;
npi = pi->p_nxt;
free(pi);
pi = npi;
}
return (decl);
}
/*
* If a dimension was specified, dim is 1, otherwise 0
* n is the specified dimension
*/
sym_t *
addarray(decl, dim, n)
sym_t *decl;
int dim, n;
{
type_t **tpp, *tp;
tpp = &decl->s_type;
while (*tpp && *tpp != dcs->d_type)
tpp = &(*tpp)->t_subt;
if (*tpp == NULL)
return decl;
*tpp = tp = getblk(sizeof (type_t));
tp->t_tspec = ARRAY;
tp->t_subt = dcs->d_type;
tp->t_dim = n;
if (n < 0) {
/* zero or negative array dimension */
error(20);
n = 0;
} else if (n == 0 && dim) {
/* zero or negative array dimension */
warning(20);
} else if (n == 0 && !dim) {
/* is incomplete type */
setcompl(tp, 1);
}
return (decl);
}
sym_t *
addfunc(decl, args)
sym_t *decl, *args;
{
type_t **tpp, *tp;
if (dcs->d_proto) {
if (tflag)
/* function prototypes are illegal in traditional C */
warning(270);
args = nsfunc(decl, args);
} else {
osfunc(decl, args);
}
/*
* The symbols are removed from the symbol table by popdecl() after
* addfunc(). To be able to restore them if this is a function
* definition, a pointer to the list of all symbols is stored in
* dcs->d_nxt->d_fpsyms. Also a list of the arguments (concatenated
* by s_nxt) is stored in dcs->d_nxt->d_fargs.
* (dcs->d_nxt must be used because *dcs is the declaration stack
* element created for the list of params and is removed after
* addfunc())
*/
if (dcs->d_nxt->d_ctx == EXTERN &&
decl->s_type == dcs->d_nxt->d_type) {
dcs->d_nxt->d_fpsyms = dcs->d_dlsyms;
dcs->d_nxt->d_fargs = args;
}
tpp = &decl->s_type;
while (*tpp && *tpp != dcs->d_nxt->d_type)
tpp = &(*tpp)->t_subt;
if (*tpp == NULL)
return decl;
*tpp = tp = getblk(sizeof (type_t));
tp->t_tspec = FUNC;
tp->t_subt = dcs->d_nxt->d_type;
if ((tp->t_proto = dcs->d_proto) != 0)
tp->t_args = args;
tp->t_vararg = dcs->d_vararg;
return (decl);
}
/*
* Called for new style function declarations.
*/
/* ARGSUSED */
static sym_t *
nsfunc(decl, args)
sym_t *decl, *args;
{
sym_t *arg, *sym;
scl_t sc;
int n;
/*
* Declarations of structs/unions/enums in param lists are legal,
* but senseless.
*/
for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
sc = sym->s_scl;
if (sc == STRTAG || sc == UNIONTAG || sc == ENUMTAG) {
/* dubious tag declaration: %s %s */
warning(85, scltoa(sc), sym->s_name);
}
}
n = 1;
for (arg = args; arg != NULL; arg = arg->s_nxt) {
if (arg->s_type->t_tspec == VOID) {
if (n > 1 || arg->s_nxt != NULL) {
/* "void" must be sole parameter */
error(60);
arg->s_type = gettyp(INT);
}
}
n++;
}
/* return NULL if first param is VOID */
return (args != NULL && args->s_type->t_tspec != VOID ? args : NULL);
}
/*
* Called for old style function declarations.
*/
static void
osfunc(decl, args)
sym_t *decl, *args;
{
/*
* Remember list of params only if this is really seams to be
* a function definition.
*/
if (dcs->d_nxt->d_ctx == EXTERN &&
decl->s_type == dcs->d_nxt->d_type) {
/*
* We assume that this becomes a function definition. If
* we are wrong, its corrected in chkfdef().
*/
if (args != NULL) {
decl->s_osdef = 1;
decl->s_args = args;
}
} else {
if (args != NULL)
/* function prototype parameters must have types */
warning(62);
}
}
/*
* Lists of Identifiers in functions declarations are allowed only if
* its also a function definition. If this is not the case, print a
* error message.
*/
void
chkfdef(sym, msg)
sym_t *sym;
int msg;
{
if (sym->s_osdef) {
if (msg) {
/* incomplete or misplaced function definition */
error(22);
}
sym->s_osdef = 0;
sym->s_args = NULL;
}
}
/*
* Process the name in a declarator.
* If the symbol does already exists, a new one is created.
* The symbol becomes one of the storage classes EXTERN, STATIC, AUTO or
* TYPEDEF.
* s_def and s_reg are valid after dname().
*/
sym_t *
dname(sym)
sym_t *sym;
{
scl_t sc = NOSCL;
if (sym->s_scl == NOSCL) {
dcs->d_rdcsym = NULL;
} else if (sym->s_defarg) {
sym->s_defarg = 0;
dcs->d_rdcsym = NULL;
} else {
dcs->d_rdcsym = sym;
sym = pushdown(sym);
}
switch (dcs->d_ctx) {
case MOS:
case MOU:
/* Parent setzen */
sym->s_styp = dcs->d_tagtyp->t_str;
sym->s_def = DEF;
sym->s_value.v_tspec = INT;
sc = dcs->d_ctx;
break;
case EXTERN:
/*
* static and external symbols without "extern" are
* considered to be tentative defined, external
* symbols with "extern" are declared, and typedef names
* are defined. Tentative defined and declared symbols
* may become defined if an initializer is present or
* this is a function definition.
*/
if ((sc = dcs->d_scl) == NOSCL) {
sc = EXTERN;
sym->s_def = TDEF;
} else if (sc == STATIC) {
sym->s_def = TDEF;
} else if (sc == TYPEDEF) {
sym->s_def = DEF;
} else if (sc == EXTERN) {
sym->s_def = DECL;
} else {
lerror("dname() 1");
}
break;
case PARG:
sym->s_arg = 1;
/* FALLTHROUGH */
case ARG:
if ((sc = dcs->d_scl) == NOSCL) {
sc = AUTO;
} else if (sc == REG) {
sym->s_reg = 1;
sc = AUTO;
} else {
lerror("dname() 2");
}
sym->s_def = DEF;
break;
case AUTO:
if ((sc = dcs->d_scl) == NOSCL) {
/*
* XXX somewhat ugly because we dont know whether
* this is AUTO or EXTERN (functions). If we are
* wrong it must be corrected in decl1loc(), where
* we have the neccessary type information.
*/
sc = AUTO;
sym->s_def = DEF;
} else if (sc == AUTO || sc == STATIC || sc == TYPEDEF) {
sym->s_def = DEF;
} else if (sc == REG) {
sym->s_reg = 1;
sc = AUTO;
sym->s_def = DEF;
} else if (sc == EXTERN) {
sym->s_def = DECL;
} else {
lerror("dname() 3");
}
break;
default:
lerror("dname() 4");
}
sym->s_scl = sc;
sym->s_type = dcs->d_type;
dcs->d_fpsyms = NULL;
return (sym);
}
/*
* Process a name in the list of formal params in an old style function
* definition.
*/
sym_t *
iname(sym)
sym_t *sym;
{
if (sym->s_scl != NOSCL) {
if (blklev == sym->s_blklev) {
/* redeclaration of formal parameter %s */
error(21, sym->s_name);
if (!sym->s_defarg)
lerror("iname()");
}
sym = pushdown(sym);
}
sym->s_type = gettyp(INT);
sym->s_scl = AUTO;
sym->s_def = DEF;
sym->s_defarg = sym->s_arg = 1;
return (sym);
}
/*
* Create the type of a tag.
*
* tag points to the symbol table entry of the tag
* kind is the kind of the tag (STRUCT/UNION/ENUM)
* decl is 1 if the type of the tag will be completed in this declaration
* (the following token is T_LBRACE)
* semi is 1 if the following token is T_SEMI
*/
type_t *
mktag(tag, kind, decl, semi)
sym_t *tag;
tspec_t kind;
int decl, semi;
{
scl_t scl = NOSCL;
type_t *tp;
if (kind == STRUCT) {
scl = STRTAG;
} else if (kind == UNION) {
scl = UNIONTAG;
} else if (kind == ENUM) {
scl = ENUMTAG;
} else {
lerror("mktag()");
}
if (tag != NULL) {
if (tag->s_scl != NOSCL) {
tag = newtag(tag, scl, decl, semi);
} else {
/* a new tag, no empty declaration */
dcs->d_nxt->d_nedecl = 1;
if (scl == ENUMTAG && !decl) {
if (!tflag && (sflag || pflag))
/* forward reference to enum type */
warning(42);
}
}
if (tag->s_scl == NOSCL) {
tag->s_scl = scl;
tag->s_type = tp = getblk(sizeof (type_t));
} else {
tp = tag->s_type;
}
} else {
tag = getblk(sizeof (sym_t));
tag->s_name = unnamed;
UNIQUE_CURR_POS(tag->s_dpos);
tag->s_kind = FTAG;
tag->s_scl = scl;
tag->s_blklev = -1;
tag->s_type = tp = getblk(sizeof (type_t));
dcs->d_nxt->d_nedecl = 1;
}
if (tp->t_tspec == NOTSPEC) {
tp->t_tspec = kind;
if (kind != ENUM) {
tp->t_str = getblk(sizeof (str_t));
tp->t_str->align = CHAR_BIT;
tp->t_str->stag = tag;
} else {
tp->t_isenum = 1;
tp->t_enum = getblk(sizeof (enum_t));
tp->t_enum->etag = tag;
}
/* ist unvollstaendiger Typ */
setcompl(tp, 1);
}
return (tp);
}
/*
* Checks all possible cases of tag redeclarations.
* decl is 1 if T_LBRACE follows
* semi is 1 if T_SEMI follows
*/
static sym_t *
newtag(tag, scl, decl, semi)
sym_t *tag;
scl_t scl;
int decl, semi;
{
if (tag->s_blklev < blklev) {
if (semi) {
/* "struct a;" */
if (!tflag) {
if (!sflag)
/* decl. introduces new type ... */
warning(44, scltoa(scl), tag->s_name);
tag = pushdown(tag);
} else if (tag->s_scl != scl) {
/* base type is really "%s %s" */
warning(45, scltoa(tag->s_scl), tag->s_name);
}
dcs->d_nxt->d_nedecl = 1;
} else if (decl) {
/* "struct a { ..." */
if (hflag)
/* redefinition hides earlier one: %s */
warning(43, tag->s_name);
tag = pushdown(tag);
dcs->d_nxt->d_nedecl = 1;
} else if (tag->s_scl != scl) {
/* base type is really "%s %s" */
warning(45, scltoa(tag->s_scl), tag->s_name);
/* declaration introduces new type in ANSI C: %s %s */
if (!sflag)
warning(44, scltoa(scl), tag->s_name);
tag = pushdown(tag);
dcs->d_nxt->d_nedecl = 1;
}
} else {
if (tag->s_scl != scl) {
/* (%s) tag redeclared */
error(46, scltoa(tag->s_scl));
prevdecl(-1, tag);
tag = pushdown(tag);
dcs->d_nxt->d_nedecl = 1;
} else if (decl && !incompl(tag->s_type)) {
/* (%s) tag redeclared */
error(46, scltoa(tag->s_scl));
prevdecl(-1, tag);
tag = pushdown(tag);
dcs->d_nxt->d_nedecl = 1;
} else if (semi || decl) {
dcs->d_nxt->d_nedecl = 1;
}
}
return (tag);
}
const char *
scltoa(sc)
scl_t sc;
{
const char *s;
switch (sc) {
case EXTERN: s = "extern"; break;
case STATIC: s = "static"; break;
case AUTO: s = "auto"; break;
case REG: s = "register"; break;
case TYPEDEF: s = "typedef"; break;
case STRTAG: s = "struct"; break;
case UNIONTAG: s = "union"; break;
case ENUMTAG: s = "enum"; break;
default: lerror("tagttoa()");
}
return (s);
}
/*
* Completes the type of a tag in a struct/union/enum declaration.
* tp points to the type of the, tag, fmem to the list of members/enums.
*/
type_t *
compltag(tp, fmem)
type_t *tp;
sym_t *fmem;
{
tspec_t t;
str_t *sp;
int n;
sym_t *mem;
/* from now a complete type */
setcompl(tp, 0);
if ((t = tp->t_tspec) != ENUM) {
align(dcs->d_stralign, 0);
sp = tp->t_str;
sp->align = dcs->d_stralign;
sp->size = dcs->d_offset;
sp->memb = fmem;
if (sp->size == 0) {
/* zero sized %s */
(void)gnuism(47, ttab[t].tt_name);
} else {
n = 0;
for (mem = fmem; mem != NULL; mem = mem->s_nxt) {
if (mem->s_name != unnamed)
n++;
}
if (n == 0) {
/* %s has no named members */
warning(65,
t == STRUCT ? "structure" : "union");
}
}
} else {
tp->t_enum->elem = fmem;
}
return (tp);
}
/*
* Processes the name of an enumerator in en enum declaration.
*
* sym points to the enumerator
* val is the value of the enumerator
* impl is 1 if the value of the enumerator was not explicit specified.
*/
sym_t *
ename(sym, val, impl)
sym_t *sym;
int val, impl;
{
if (sym->s_scl) {
if (sym->s_blklev == blklev) {
/* no hflag, because this is illegal!!! */
if (sym->s_arg) {
/* enumeration constant hides parameter: %s */
warning(57, sym->s_name);
} else {
/* redeclaration of %s */
error(27, sym->s_name);
/*
* inside blocks it should not too complicated
* to find the position of the previous
* declaration
*/
if (blklev == 0)
prevdecl(-1, sym);
}
} else {
if (hflag)
/* redefinition hides earlier one: %s */
warning(43, sym->s_name);
}
sym = pushdown(sym);
}
sym->s_scl = ENUMCON;
sym->s_type = dcs->d_tagtyp;
sym->s_value.v_tspec = INT;
sym->s_value.v_quad = val;
if (impl && val - 1 == INT_MAX) {
/* overflow in enumeration values: %s */
warning(48, sym->s_name);
}
enumval = val + 1;
return (sym);
}
/*
* Process a single external declarator.
*/
void
decl1ext(dsym, initflg)
sym_t *dsym;
int initflg;
{
int warn, rval, redec;
sym_t *rdsym;
chkfdef(dsym, 1);
chktyp(dsym);
if (initflg && !(initerr = chkinit(dsym)))
dsym->s_def = DEF;
/*
* Declarations of functions are marked as "tentative" in dname().
* This is wrong because there are no tentative function
* definitions.
*/
if (dsym->s_type->t_tspec == FUNC && dsym->s_def == TDEF)
dsym->s_def = DECL;
if (dcs->d_inline) {
if (dsym->s_type->t_tspec == FUNC) {
dsym->s_inline = 1;
} else {
/* variable declared inline: %s */
warning(268, dsym->s_name);
}
}
/* Write the declaration into the output file */
if (plibflg && llibflg &&
dsym->s_type->t_tspec == FUNC && dsym->s_type->t_proto) {
/*
* With both LINTLIBRARY and PROTOLIB the prototyp is
* written as a function definition to the output file.
*/
rval = dsym->s_type->t_subt->t_tspec != VOID;
outfdef(dsym, &dsym->s_dpos, rval, 0, NULL);
} else {
outsym(dsym, dsym->s_scl, dsym->s_def);
}
if ((rdsym = dcs->d_rdcsym) != NULL) {
/*
* If the old symbol stems from a old style function definition
* we have remembered the params in rdsmy->s_args and compare
* them with the params of the prototype.
*/
if (rdsym->s_osdef && dsym->s_type->t_proto) {
redec = chkosdef(rdsym, dsym);
} else {
redec = 0;
}
if (!redec && !isredec(dsym, (warn = 0, &warn))) {
if (warn) {
/* redeclaration of %s */
(*(sflag ? error : warning))(27, dsym->s_name);
prevdecl(-1, rdsym);
}
/*
* Overtake the rememberd params if the new symbol
* is not a prototype.
*/
if (rdsym->s_osdef && !dsym->s_type->t_proto) {
dsym->s_osdef = rdsym->s_osdef;
dsym->s_args = rdsym->s_args;
STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
}
/*
* Remember the position of the declaration if the
* old symbol was a prototype and the new is not.
* Also remember the position if the old symbol
* was defined and the new is not.
*/
if (rdsym->s_type->t_proto && !dsym->s_type->t_proto) {
STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
} else if (rdsym->s_def == DEF && dsym->s_def != DEF) {
STRUCT_ASSIGN(dsym->s_dpos, rdsym->s_dpos);
}
/*
* Copy informations about usage of the name into
* the new symbol.
*/
cpuinfo(dsym, rdsym);
/* Once a name is defined, it remains defined. */
if (rdsym->s_def == DEF)
dsym->s_def = DEF;
/* once a function is inline, it remains inline */
if (rdsym->s_inline)
dsym->s_inline = 1;
compltyp(dsym, rdsym);
}
rmsym(rdsym);
}
if (dsym->s_scl == TYPEDEF) {
dsym->s_type = duptyp(dsym->s_type);
dsym->s_type->t_typedef = 1;
settdsym(dsym->s_type, dsym);
}
}
/*
* Copies informations about usage into a new symbol table entry of
* the same symbol.
*/
void
cpuinfo(sym, rdsym)
sym_t *sym, *rdsym;
{
sym->s_spos = rdsym->s_spos;
sym->s_upos = rdsym->s_upos;
sym->s_set = rdsym->s_set;
sym->s_used = rdsym->s_used;
}
/*
* Prints an error and returns 1 if a symbol is redeclared/redefined.
* Otherwise returns 0 and, in some cases of minor problems, prints
* a warning.
*/
int
isredec(dsym, warn)
sym_t *dsym;
int *warn;
{
sym_t *rsym;
if ((rsym = dcs->d_rdcsym)->s_scl == ENUMCON) {
/* redeclaration of %s */
error(27, dsym->s_name);
prevdecl(-1, rsym);
return (1);
}
if (rsym->s_scl == TYPEDEF) {
/* typedef redeclared: %s */
error(89, dsym->s_name);
prevdecl(-1, rsym);
return (1);
}
if (dsym->s_scl == TYPEDEF) {
/* redeclaration of %s */
error(27, dsym->s_name);
prevdecl(-1, rsym);
return (1);
}
if (rsym->s_def == DEF && dsym->s_def == DEF) {
/* redefinition of %s */
error(28, dsym->s_name);
prevdecl(-1, rsym);
return(1);
}
if (!eqtype(rsym->s_type, dsym->s_type, 0, 0, warn)) {
/* redeclaration of %s */
error(27, dsym->s_name);
prevdecl(-1, rsym);
return(1);
}
if (rsym->s_scl == EXTERN && dsym->s_scl == EXTERN)
return(0);
if (rsym->s_scl == STATIC && dsym->s_scl == STATIC)
return(0);
if (rsym->s_scl == STATIC && dsym->s_def == DECL)
return(0);
if (rsym->s_scl == EXTERN && rsym->s_def == DEF) {
/*
* All cases except "int a = 1; static int a;" are catched
* above with or without a warning
*/
/* redeclaration of %s */
error(27, dsym->s_name);
prevdecl(-1, rsym);
return(1);
}
if (rsym->s_scl == EXTERN) {
/* previously declared extern, becomes static: %s */
warning(29, dsym->s_name);
prevdecl(-1, rsym);
return(0);
}
/*
* Now its on of:
* "static a; int a;", "static a; int a = 1;", "static a = 1; int a;"
*/
/* redeclaration of %s; ANSI C requires "static" */
if (sflag) {
warning(30, dsym->s_name);
prevdecl(-1, rsym);
}
dsym->s_scl = STATIC;
return (0);
}
/*
* Checks if two types are compatible. Returns 0 if not, otherwise 1.
*
* ignqual ignore qualifiers of type; used for function params
* promot promote left type; used for comparison of params of
* old style function definitions with params of prototypes.
* *warn set to 1 if an old style function declaration is not
* compatible with a prototype
*/
int
eqtype(tp1, tp2, ignqual, promot, warn)
type_t *tp1, *tp2;
int ignqual, promot, *warn;
{
tspec_t t;
while (tp1 != NULL && tp2 != NULL) {
t = tp1->t_tspec;
if (promot) {
if (t == FLOAT) {
t = DOUBLE;
} else if (t == CHAR || t == SCHAR) {
t = INT;
} else if (t == UCHAR) {
t = tflag ? UINT : INT;
} else if (t == SHORT) {
t = INT;
} else if (t == USHORT) {
/* CONSTCOND */
t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
}
}
if (t != tp2->t_tspec)
return (0);
if (tp1->t_const != tp2->t_const && !ignqual && !tflag)
return (0);
if (tp1->t_volatile != tp2->t_volatile && !ignqual && !tflag)
return (0);
if (t == STRUCT || t == UNION)
return (tp1->t_str == tp2->t_str);
if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
if (tp1->t_dim != 0 && tp2->t_dim != 0)
return (0);
}
/* dont check prototypes for traditional */
if (t == FUNC && !tflag) {
if (tp1->t_proto && tp2->t_proto) {
if (!eqargs(tp1, tp2, warn))
return (0);
} else if (tp1->t_proto) {
if (!mnoarg(tp1, warn))
return (0);
} else if (tp2->t_proto) {
if (!mnoarg(tp2, warn))
return (0);
}
}
tp1 = tp1->t_subt;
tp2 = tp2->t_subt;
ignqual = promot = 0;
}
return (tp1 == tp2);
}
/*
* Compares the parameter types of two prototypes.
*/
static int
eqargs(tp1, tp2, warn)
type_t *tp1, *tp2;
int *warn;
{
sym_t *a1, *a2;
if (tp1->t_vararg != tp2->t_vararg)
return (0);
a1 = tp1->t_args;
a2 = tp2->t_args;
while (a1 != NULL && a2 != NULL) {
if (eqtype(a1->s_type, a2->s_type, 1, 0, warn) == 0)
return (0);
a1 = a1->s_nxt;
a2 = a2->s_nxt;
}
return (a1 == a2);
}
/*
* mnoarg() (matches functions with no argument type information)
* returns 1 if all parameters of a prototype are compatible with
* and old style function declaration.
* This is the case if following conditions are met:
* 1. the prototype must have a fixed number of parameters
* 2. no parameter is of type float
* 3. no parameter is converted to another type if integer promotion
* is applied on it
*/
static int
mnoarg(tp, warn)
type_t *tp;
int *warn;
{
sym_t *arg;
tspec_t t;
if (tp->t_vararg) {
if (warn != NULL)
*warn = 1;
}
for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) {
if ((t = arg->s_type->t_tspec) == FLOAT ||
t == CHAR || t == SCHAR || t == UCHAR ||
t == SHORT || t == USHORT) {
if (warn != NULL)
*warn = 1;
}
}
return (1);
}
/*
* Compares a prototype declaration with the remembered arguments of
* a previous old style function definition.
*/
static int
chkosdef(rdsym, dsym)
sym_t *rdsym, *dsym;
{
sym_t *args, *pargs, *arg, *parg;
int narg, nparg, n;
int warn, msg;
args = rdsym->s_args;
pargs = dsym->s_type->t_args;
msg = 0;
narg = nparg = 0;
for (arg = args; arg != NULL; arg = arg->s_nxt)
narg++;
for (parg = pargs; parg != NULL; parg = parg->s_nxt)
nparg++;
if (narg != nparg) {
/* prototype does not match old-style definition */
error(63);
msg = 1;
goto end;
}
arg = args;
parg = pargs;
n = 1;
while (narg--) {
warn = 0;
/*
* If it does not match due to promotion and sflag is
* not set we print only a warning.
*/
if (!eqtype(arg->s_type, parg->s_type, 1, 1, &warn) || warn) {
/* prototype does not match old-style def., arg #%d */
error(299, n);
msg = 1;
}
arg = arg->s_nxt;
parg = parg->s_nxt;
n++;
}
end:
if (msg)
/* old style definition */
prevdecl(300, rdsym);
return (msg);
}
/*
* Complets a type by copying the dimension and prototype information
* from a second compatible type.
*
* Following lines are legal:
* "typedef a[]; a b; a b[10]; a c; a c[20];"
* "typedef ft(); ft f; f(int); ft g; g(long);"
* This means that, if a type is completed, the type structure must
* be duplicated.
*/
void
compltyp(dsym, ssym)
sym_t *dsym, *ssym;
{
type_t **dstp, *src;
type_t *dst;
dstp = &dsym->s_type;
src = ssym->s_type;
while ((dst = *dstp) != NULL) {
if (src == NULL || dst->t_tspec != src->t_tspec)
lerror("compltyp() 1");
if (dst->t_tspec == ARRAY) {
if (dst->t_dim == 0 && src->t_dim != 0) {
*dstp = dst = duptyp(dst);
dst->t_dim = src->t_dim;
/* now a complete Typ */
setcompl(dst, 0);
}
} else if (dst->t_tspec == FUNC) {
if (!dst->t_proto && src->t_proto) {
*dstp = dst = duptyp(dst);
dst->t_proto = 1;
dst->t_args = src->t_args;
}
}
dstp = &dst->t_subt;
src = src->t_subt;
}
}
/*
* Completes the declaration of a single argument.
*/
sym_t *
decl1arg(sym, initflg)
sym_t *sym;
int initflg;
{
tspec_t t;
chkfdef(sym, 1);
chktyp(sym);
if (dcs->d_rdcsym != NULL && dcs->d_rdcsym->s_blklev == blklev) {
/* redeclaration of formal parameter %s */
error(237, sym->s_name);
rmsym(dcs->d_rdcsym);
sym->s_arg = 1;
}
if (!sym->s_arg) {
/* declared argument %s is missing */
error(53, sym->s_name);
sym->s_arg = 1;
}
if (initflg) {
/* cannot initialize parameter: %s */
error(52, sym->s_name);
initerr = 1;
}
if ((t = sym->s_type->t_tspec) == ARRAY) {
sym->s_type = incref(sym->s_type->t_subt, PTR);
} else if (t == FUNC) {
if (tflag)
/* a function is declared as an argument: %s */
warning(50, sym->s_name);
sym->s_type = incref(sym->s_type, PTR);
} else if (t == FLOAT) {
if (tflag)
sym->s_type = gettyp(DOUBLE);
}
if (dcs->d_inline)
/* argument declared inline: %s */
warning(269, sym->s_name);
/*
* Arguments must have complete types. lengths() prints the needed
* error messages (null dimension is impossible because arrays are
* converted to pointers).
*/
if (sym->s_type->t_tspec != VOID)
(void)length(sym->s_type, sym->s_name);
setsflg(sym);
return (sym);
}
/*
* Does some checks for lint directives which apply to functions.
* Processes arguments in old style function definitions which default
* to int.
* Checks compatiblility of old style function definition with previous
* prototype.
*/
void
cluparg()
{
sym_t *args, *arg, *pargs, *parg;
int narg, nparg, n, msg;
tspec_t t;
args = funcsym->s_args;
pargs = funcsym->s_type->t_args;
/* check for illegal combinations of lint directives */
if (prflstrg != -1 && scflstrg != -1) {
/* can't be used together: ** PRINTFLIKE ** ** SCANFLIKE ** */
warning(289);
prflstrg = scflstrg = -1;
}
if (nvararg != -1 && (prflstrg != -1 || scflstrg != -1)) {
/* dubious use of ** VARARGS ** with ** %s ** */
warning(288, prflstrg != -1 ? "PRINTFLIKE" : "SCANFLIKE");
nvararg = -1;
}
/*
* check if the argument of a lint directive is compatible with the
* number of arguments.
*/
narg = 0;
for (arg = dcs->d_fargs; arg != NULL; arg = arg->s_nxt)
narg++;
if (nargusg > narg) {
/* argument number mismatch with directive: ** %s ** */
warning(283, "ARGSUSED");
nargusg = 0;
}
if (nvararg > narg) {
/* argument number mismatch with directive: ** %s ** */
warning(283, "VARARGS");
nvararg = 0;
}
if (prflstrg > narg) {
/* argument number mismatch with directive: ** %s ** */
warning(283, "PRINTFLIKE");
prflstrg = -1;
} else if (prflstrg == 0) {
prflstrg = -1;
}
if (scflstrg > narg) {
/* argument number mismatch with directive: ** %s ** */
warning(283, "SCANFLIKE");
scflstrg = -1;
} else if (scflstrg == 0) {
scflstrg = -1;
}
if (prflstrg != -1 || scflstrg != -1) {
narg = prflstrg != -1 ? prflstrg : scflstrg;
arg = dcs->d_fargs;
for (n = 1; n < narg; n++)
arg = arg->s_nxt;
if (arg->s_type->t_tspec != PTR ||
((t = arg->s_type->t_subt->t_tspec) != CHAR &&
t != UCHAR && t != SCHAR)) {
/* arg. %d must be 'char *' for PRINTFLIKE/SCANFLIKE */
warning(293, narg);
prflstrg = scflstrg = -1;
}
}
/*
* print a warning for each argument off an old style function
* definition which defaults to int
*/
for (arg = args; arg != NULL; arg = arg->s_nxt) {
if (arg->s_defarg) {
/* argument type defaults to int: %s */
warning(32, arg->s_name);
arg->s_defarg = 0;
setsflg(arg);
}
}
/*
* If this is an old style function definition and a prototyp
* exists, compare the types of arguments.
*/
if (funcsym->s_osdef && funcsym->s_type->t_proto) {
/*
* If the number of arguments does not macht, we need not
* continue.
*/
narg = nparg = 0;
msg = 0;
for (parg = pargs; parg != NULL; parg = parg->s_nxt)
nparg++;
for (arg = args; arg != NULL; arg = arg->s_nxt)
narg++;
if (narg != nparg) {
/* parameter mismatch: %d declared, %d defined */
error(51, nparg, narg);
msg = 1;
} else {
parg = pargs;
arg = args;
while (narg--) {
msg |= chkptdecl(arg, parg);
parg = parg->s_nxt;
arg = arg->s_nxt;
}
}
if (msg)
/* prototype declaration */
prevdecl(285, dcs->d_rdcsym);
/* from now the prototype is valid */
funcsym->s_osdef = 0;
funcsym->s_args = NULL;
}
}
/*
* Checks compatibility of an old style function definition with a previous
* prototype declaration.
* Returns 1 if the position of the previous declaration should be reported.
*/
static int
chkptdecl(arg, parg)
sym_t *arg, *parg;
{
type_t *tp, *ptp;
int warn, msg;
tp = arg->s_type;
ptp = parg->s_type;
msg = 0;
warn = 0;
if (!eqtype(tp, ptp, 1, 1, &warn)) {
if (eqtype(tp, ptp, 1, 0, &warn)) {
/* type does not match prototype: %s */
msg = gnuism(58, arg->s_name);
} else {
/* type does not match prototype: %s */
error(58, arg->s_name);
msg = 1;
}
} else if (warn) {
/* type does not match prototype: %s */
(*(sflag ? error : warning))(58, arg->s_name);
msg = 1;
}
return (msg);
}
/*
* Completes a single local declaration/definition.
*/
void
decl1loc(dsym, initflg)
sym_t *dsym;
int initflg;
{
/* Correct a mistake done in dname(). */
if (dsym->s_type->t_tspec == FUNC) {
dsym->s_def = DECL;
if (dcs->d_scl == NOSCL)
dsym->s_scl = EXTERN;
}
if (dsym->s_type->t_tspec == FUNC) {
if (dsym->s_scl == STATIC) {
/* dubious static function at block level: %s */
warning(93, dsym->s_name);
dsym->s_scl = EXTERN;
} else if (dsym->s_scl != EXTERN && dsym->s_scl != TYPEDEF) {
/* function has illegal storage class: %s */
error(94, dsym->s_name);
dsym->s_scl = EXTERN;
}
}
/*
* functions may be declared inline at local scope, although
* this has no effect for a later definition of the same
* function.
* XXX it should have an effect if tflag is set. this would
* also be the way gcc behaves.
*/
if (dcs->d_inline) {
if (dsym->s_type->t_tspec == FUNC) {
dsym->s_inline = 1;
} else {
/* variable declared inline: %s */
warning(268, dsym->s_name);
}
}
chkfdef(dsym, 1);
chktyp(dsym);
if (dcs->d_rdcsym != NULL && dsym->s_scl == EXTERN)
ledecl(dsym);
if (dsym->s_scl == EXTERN) {
/*
* XXX wenn die statische Variable auf Ebene 0 erst
* spaeter definiert wird, haben wir die Brille auf.
*/
if (dsym->s_xsym == NULL) {
outsym(dsym, EXTERN, dsym->s_def);
} else {
outsym(dsym, dsym->s_xsym->s_scl, dsym->s_def);
}
}
if (dcs->d_rdcsym != NULL) {
if (dcs->d_rdcsym->s_blklev == 0) {
switch (dsym->s_scl) {
case AUTO:
/* automatic hides external declaration: %s */
if (hflag)
warning(86, dsym->s_name);
break;
case STATIC:
/* static hides external declaration: %s */
if (hflag)
warning(87, dsym->s_name);
break;
case TYPEDEF:
/* typedef hides external declaration: %s */
if (hflag)
warning(88, dsym->s_name);
break;
case EXTERN:
/*
* Warnings and errors are printed in ledecl()
*/
break;
default:
lerror("decl1loc() 1");
}
} else if (dcs->d_rdcsym->s_blklev == blklev) {
/* no hflag, because its illegal! */
if (dcs->d_rdcsym->s_arg) {
/*
* if !tflag, a "redeclaration of %s" error
* is produced below
*/
if (tflag) {
if (hflag)
/* decl. hides parameter: %s */
warning(91, dsym->s_name);
rmsym(dcs->d_rdcsym);
}
}
} else if (dcs->d_rdcsym->s_blklev < blklev) {
if (hflag)
/* declaration hides earlier one: %s */
warning(95, dsym->s_name);
}
if (dcs->d_rdcsym->s_blklev == blklev) {
/* redeclaration of %s */
error(27, dsym->s_name);
rmsym(dcs->d_rdcsym);
}
}
if (initflg && !(initerr = chkinit(dsym))) {
dsym->s_def = DEF;
setsflg(dsym);
}
if (dsym->s_scl == TYPEDEF) {
dsym->s_type = duptyp(dsym->s_type);
dsym->s_type->t_typedef = 1;
settdsym(dsym->s_type, dsym);
}
/*
* Before we can check the size we must wait for a initialisation
* which may follow.
*/
}
/*
* Processes (re)declarations of external Symbols inside blocks.
*/
static void
ledecl(dsym)
sym_t *dsym;
{
int eqt, warn;
sym_t *esym;
/* look for a symbol with the same name */
esym = dcs->d_rdcsym;
while (esym != NULL && esym->s_blklev != 0) {
while ((esym = esym->s_link) != NULL) {
if (esym->s_kind != FVFT)
continue;
if (strcmp(dsym->s_name, esym->s_name) == 0)
break;
}
}
if (esym == NULL)
return;
if (esym->s_scl != EXTERN && esym->s_scl != STATIC) {
/* gcc accepts this without a warning, pcc prints an error. */
/* redeclaration of %s */
warning(27, dsym->s_name);
prevdecl(-1, esym);
return;
}
warn = 0;
eqt = eqtype(esym->s_type, dsym->s_type, 0, 0, &warn);
if (!eqt || warn) {
if (esym->s_scl == EXTERN) {
/* inconsistent redeclaration of extern: %s */
warning(90, dsym->s_name);
prevdecl(-1, esym);
} else {
/* inconsistent redeclaration of static: %s */
warning(92, dsym->s_name);
prevdecl(-1, esym);
}
}
if (eqt) {
/*
* Remember the external symbol so we can update usage
* information at the end of the block.
*/
dsym->s_xsym = esym;
}
}
/*
* Print an error or a warning if the symbol cant be initialized due
* to type/storage class. Returnvalue is 1 if an error has been
* detected.
*/
static int
chkinit(sym)
sym_t *sym;
{
int err;
err = 0;
if (sym->s_type->t_tspec == FUNC) {
/* cannot initialize function: %s */
error(24, sym->s_name);
err = 1;
} else if (sym->s_scl == TYPEDEF) {
/* cannot initialize typedef: %s */
error(25, sym->s_name);
err = 1;
} else if (sym->s_scl == EXTERN && sym->s_def == DECL) {
/* cannot initialize "extern" declaration: %s */
if (dcs->d_ctx == EXTERN) {
warning(26, sym->s_name);
} else {
error(26, sym->s_name);
err = 1;
}
}
return (err);
}
/*
* Create a symbole for an abstract declaration.
*/
sym_t *
aname()
{
sym_t *sym;
if (dcs->d_ctx != ABSTRACT && dcs->d_ctx != PARG)
lerror("aname()");
sym = getblk(sizeof (sym_t));
sym->s_name = unnamed;
sym->s_def = DEF;
sym->s_scl = ABSTRACT;
sym->s_blklev = -1;
if (dcs->d_ctx == PARG)
sym->s_arg = 1;
sym->s_type = dcs->d_type;
dcs->d_rdcsym = NULL;
dcs->d_vararg = 0;
return (sym);
}
/*
* Removes anything which has nothing to do on global level.
*/
void
globclup()
{
while (dcs->d_nxt != NULL)
popdecl();
cleanup();
blklev = 0;
mblklev = 0;
/*
* remove all informations about pending lint directives without
* warnings.
*/
glclup(1);
}
/*
* Process an abstract type declaration
*/
sym_t *
decl1abs(sym)
sym_t *sym;
{
chkfdef(sym, 1);
chktyp(sym);
return (sym);
}
/*
* Checks size after declarations of variables and their initialisation.
*/
void
chksz(dsym)
sym_t *dsym;
{
/*
* check size only for symbols which are defined and no function and
* not typedef name
*/
if (dsym->s_def != DEF)
return;
if (dsym->s_scl == TYPEDEF)
return;
if (dsym->s_type->t_tspec == FUNC)
return;
if (length(dsym->s_type, dsym->s_name) == 0 &&
dsym->s_type->t_tspec == ARRAY && dsym->s_type->t_dim == 0) {
/* empty array declaration: %s */
if (tflag) {
warning(190, dsym->s_name);
} else {
error(190, dsym->s_name);
}
}
}
/*
* Mark an object as set if it is not already
*/
void
setsflg(sym)
sym_t *sym;
{
if (!sym->s_set) {
sym->s_set = 1;
UNIQUE_CURR_POS(sym->s_spos);
}
}
/*
* Mark an object as used if it is not already
*/
void
setuflg(sym, fcall, szof)
sym_t *sym;
int fcall, szof;
{
if (!sym->s_used) {
sym->s_used = 1;
UNIQUE_CURR_POS(sym->s_upos);
}
/*
* for function calls another record is written
*
* XXX Should symbols used in sizeof() treated as used or not?
* Probably not, because there is no sense to declare an
* external variable only to get their size.
*/
if (!fcall && !szof && sym->s_kind == FVFT && sym->s_scl == EXTERN)
outusg(sym);
}
/*
* Prints warnings for a list of variables and labels (concatenated
* with s_dlnxt) if these are not used or only set.
*/
void
chkusage(di)
dinfo_t *di;
{
sym_t *sym;
int mknowarn;
/* for this warnings LINTED has no effect */
mknowarn = nowarn;
nowarn = 0;
for (sym = di->d_dlsyms; sym != NULL; sym = sym->s_dlnxt)
chkusg1(di->d_asm, sym);
nowarn = mknowarn;
}
/*
* Prints a warning for a single variable or label if it is not used or
* only set.
*/
void
chkusg1(novar, sym)
int novar;
sym_t *sym;
{
pos_t cpos;
if (sym->s_blklev == -1)
return;
STRUCT_ASSIGN(cpos, curr_pos);
if (sym->s_kind == FVFT) {
if (sym->s_arg) {
chkausg(novar, sym);
} else {
chkvusg(novar, sym);
}
} else if (sym->s_kind == FLAB) {
chklusg(sym);
} else if (sym->s_kind == FTAG) {
chktusg(sym);
}
STRUCT_ASSIGN(curr_pos, cpos);
}
static void
chkausg(novar, arg)
int novar;
sym_t *arg;
{
if (!arg->s_set)
lerror("chkausg() 1");
if (novar)
return;
if (!arg->s_used && vflag) {
STRUCT_ASSIGN(curr_pos, arg->s_dpos);
/* argument %s unused in function %s */
warning(231, arg->s_name, funcsym->s_name);
}
}
static void
chkvusg(novar, sym)
int novar;
sym_t *sym;
{
scl_t sc;
sym_t *xsym;
if (blklev == 0 || sym->s_blklev == 0)
lerror("chkvusg() 1");
/* errors in expressions easily cause lots of these warnings */
if (nerr != 0)
return;
/*
* XXX Only variables are checkd, although types should
* probably also be checked
*/
if ((sc = sym->s_scl) != EXTERN && sc != STATIC &&
sc != AUTO && sc != REG) {
return;
}
if (novar)
return;
if (sc == EXTERN) {
if (!sym->s_used && !sym->s_set) {
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
/* %s unused in function %s */
warning(192, sym->s_name, funcsym->s_name);
}
} else {
if (sym->s_set && !sym->s_used) {
STRUCT_ASSIGN(curr_pos, sym->s_spos);
/* %s set but not used in function %s */
warning(191, sym->s_name, funcsym->s_name);
} else if (!sym->s_used) {
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
/* %s unused in function %s */
warning(192, sym->s_name, funcsym->s_name);
}
}
if (sc == EXTERN) {
/*
* information about usage is taken over into the symbol
* tabel entry at level 0 if the symbol was locally declared
* as an external symbol.
*
* XXX This is wrong for symbols declared static at level 0
* if the usage information stems from sizeof(). This is
* because symbols at level 0 only used in sizeof() are
* considered to not be used.
*/
if ((xsym = sym->s_xsym) != NULL) {
if (sym->s_used && !xsym->s_used) {
xsym->s_used = 1;
STRUCT_ASSIGN(xsym->s_upos, sym->s_upos);
}
if (sym->s_set && !xsym->s_set) {
xsym->s_set = 1;
STRUCT_ASSIGN(xsym->s_spos, sym->s_spos);
}
}
}
}
static void
chklusg(lab)
sym_t *lab;
{
if (blklev != 1 || lab->s_blklev != 1)
lerror("chklusg() 1");
if (lab->s_set && !lab->s_used) {
STRUCT_ASSIGN(curr_pos, lab->s_spos);
/* label %s unused in function %s */
warning(192, lab->s_name, funcsym->s_name);
} else if (!lab->s_set) {
STRUCT_ASSIGN(curr_pos, lab->s_upos);
/* undefined label %s */
warning(23, lab->s_name);
}
}
static void
chktusg(sym)
sym_t *sym;
{
if (!incompl(sym->s_type))
return;
/* complain alwasy about incomplet tags declared inside blocks */
if (!zflag || dcs->d_ctx != EXTERN)
return;
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
switch (sym->s_type->t_tspec) {
case STRUCT:
/* struct %s never defined */
warning(233, sym->s_name);
break;
case UNION:
/* union %s never defined */
warning(234, sym->s_name);
break;
case ENUM:
/* enum %s never defined */
warning(235, sym->s_name);
break;
default:
lerror("chktusg() 1");
}
}
/*
* Called after the entire translation unit has been parsed.
* Changes tentative definitions in definitions.
* Performs some tests on global Symbols. Detected Problems are:
* - defined variables of incomplete type
* - constant variables which are not initialized
* - static symbols which are never used
*/
void
chkglsyms()
{
sym_t *sym;
pos_t cpos;
if (blklev != 0 || dcs->d_nxt != NULL)
norecover();
STRUCT_ASSIGN(cpos, curr_pos);
for (sym = dcs->d_dlsyms; sym != NULL; sym = sym->s_dlnxt) {
if (sym->s_blklev == -1)
continue;
if (sym->s_kind == FVFT) {
chkglvar(sym);
} else if (sym->s_kind == FTAG) {
chktusg(sym);
} else {
if (sym->s_kind != FMOS)
lerror("chkglsyms() 1");
}
}
STRUCT_ASSIGN(curr_pos, cpos);
}
static void
chkglvar(sym)
sym_t *sym;
{
if (sym->s_scl == TYPEDEF || sym->s_scl == ENUMCON)
return;
if (sym->s_scl != EXTERN && sym->s_scl != STATIC)
lerror("chkglvar() 1");
glchksz(sym);
if (sym->s_scl == STATIC) {
if (sym->s_type->t_tspec == FUNC) {
if (sym->s_used && sym->s_def != DEF) {
STRUCT_ASSIGN(curr_pos, sym->s_upos);
/* static func. called but not def.. */
error(225, sym->s_name);
}
}
if (!sym->s_used) {
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
if (sym->s_type->t_tspec == FUNC) {
if (sym->s_def == DEF) {
if (!sym->s_inline)
/* static function %s unused */
warning(236, sym->s_name);
} else {
/* static function %s decl. but ... */
warning(290, sym->s_name);
}
} else if (!sym->s_set) {
/* static variable %s unused */
warning(226, sym->s_name);
} else {
/* static variable %s set but not used */
warning(307, sym->s_name);
}
}
if (!tflag && sym->s_def == TDEF && sym->s_type->t_const) {
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
/* const object %s should have initializer */
warning(227, sym->s_name);
}
}
}
static void
glchksz(sym)
sym_t *sym;
{
if (sym->s_def == TDEF) {
if (sym->s_type->t_tspec == FUNC)
/*
* this can happen if an syntax error occured
* after a function declaration
*/
return;
STRUCT_ASSIGN(curr_pos, sym->s_dpos);
if (length(sym->s_type, sym->s_name) == 0 &&
sym->s_type->t_tspec == ARRAY && sym->s_type->t_dim == 0) {
/* empty array declaration: %s */
if (tflag || (sym->s_scl == EXTERN && !sflag)) {
warning(190, sym->s_name);
} else {
error(190, sym->s_name);
}
}
}
}
/*
* Prints information about location of previous definition/declaration.
*/
void
prevdecl(msg, psym)
int msg;
sym_t *psym;
{
pos_t cpos;
if (!rflag)
return;
STRUCT_ASSIGN(cpos, curr_pos);
STRUCT_ASSIGN(curr_pos, psym->s_dpos);
if (msg != -1) {
message(msg, psym->s_name);
} else if (psym->s_def == DEF || psym->s_def == TDEF) {
/* previous definition of %s */
message(261, psym->s_name);
} else {
/* previous declaration of %s */
message(260, psym->s_name);
}
STRUCT_ASSIGN(curr_pos, cpos);
}