From: guenther Date: Sat, 24 Jul 2010 22:17:03 +0000 (+0000) Subject: Teach lint about C99's _Bool and _Complex, plus some related gcc X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=5fdc31176191116d769f239419f5cba4f36bda1e;p=openbsd Teach lint about C99's _Bool and _Complex, plus some related gcc extensions: __real__ and __imag__ operators, the use of '~' for complex conjugation, and 'i' or 'j' as a suffix for complex constants. While this doesn't handle folding and overflow detection for complex constants correctly, it's good enough to make it through libm...and found several bugs once it could do so. "no objections" miod@, krw@ --- diff --git a/include/complex.h b/include/complex.h index aa89d70079e..be85c7c0914 100644 --- a/include/complex.h +++ b/include/complex.h @@ -1,4 +1,4 @@ -/* $OpenBSD: complex.h,v 1.2 2008/12/04 03:52:31 ray Exp $ */ +/* $OpenBSD: complex.h,v 1.3 2010/07/24 22:17:03 guenther Exp $ */ /* * Copyright (c) 2008 Martynas Venckus * @@ -28,6 +28,8 @@ #define _Complex __complex__ #endif #define _Complex_I 1.0fi +#elif defined(lint) +#define _Complex_I 1.0fi #endif #define complex _Complex diff --git a/include/stdbool.h b/include/stdbool.h index cc1104c6f85..34304130081 100644 --- a/include/stdbool.h +++ b/include/stdbool.h @@ -1,4 +1,4 @@ -/* $OpenBSD: stdbool.h,v 1.4 2007/10/02 14:06:16 otto Exp $ */ +/* $OpenBSD: stdbool.h,v 1.5 2010/07/24 22:17:03 guenther Exp $ */ /* * Written by Marc Espie, September 25, 1999 @@ -10,7 +10,7 @@ #ifndef __cplusplus -#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__PCC__) +#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__PCC__) || defined(lint) /* Support for _C99: type _Bool is already built-in. */ #define false 0 #define true 1 diff --git a/usr.bin/xlint/lint1/decl.c b/usr.bin/xlint/lint1/decl.c index bd52fdd3c79..3ee6f39670f 100644 --- a/usr.bin/xlint/lint1/decl.c +++ b/usr.bin/xlint/lint1/decl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: decl.c,v 1.24 2007/11/27 16:22:14 martynas Exp $ */ +/* $OpenBSD: decl.c,v 1.25 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: decl.c,v 1.11 1995/10/02 17:34:16 jpo Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: decl.c,v 1.24 2007/11/27 16:22:14 martynas Exp $"; +static char rcsid[] = "$OpenBSD: decl.c,v 1.25 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -97,6 +97,9 @@ initdecl(void) { UNSIGN, { 0, 0, 0, SIGNED, UNSIGN, 0, 0, 0, 0, 0, "unsigned" } }, + { BOOL, { sizeof (_Bool) * CHAR_BIT, CHAR_BIT, 1, + BOOL, BOOL, + 1, 1, 0, 1, 1, "_Bool" } }, { CHAR, { CHAR_BIT, CHAR_BIT, 20, SCHAR, UCHAR, 1, 0, 0, 1, 1, "char" } }, @@ -139,6 +142,32 @@ initdecl(void) { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT, -1, LDOUBLE, LDOUBLE, 0, 0, 1, 1, 1, "long double" } }, + { COMPLEX, { sizeof (float _Complex) * CHAR_BIT, + 8 * CHAR_BIT, -1, + COMPLEX, COMPLEX, + 0, 0, 1, 1, 3, "float _Complex" } }, + { DCOMPLEX, { sizeof (double _Complex) * CHAR_BIT, + 16 * CHAR_BIT, -1, + DCOMPLEX, DCOMPLEX, + 0, 0, 1, 1, 3, "double _Complex" } }, + { LDCOMPLEX,{ sizeof (long double _Complex) * CHAR_BIT, + 20 * CHAR_BIT, -1, + LDCOMPLEX, LDCOMPLEX, + 0, 0, 1, 1, 3, "long double _Complex" } }, +#if 0 + { IMAGINARY,{ sizeof (float _Imaginary) * CHAR_BIT, + 4 * CHAR_BIT, -1, + IMAGINARY, IMAGINARY, + 0, 0, 1, 1, 2, "float _Imaginary" } }, + { DIMAGINARY,{ sizeof (double _Imaginary) * CHAR_BIT, + 8 * CHAR_BIT, -1, + DIMAGINARY, DIMAGINARY, + 0, 0, 1, 1, 2, "double _Imaginary" } }, + { LDIMAGINARY,{ sizeof (long double _Imaginary) * CHAR_BIT, + 10 * CHAR_BIT, -1, + LDIMAGINARY, LDIMAGINARY, + 0, 0, 1, 1, 2, "long double _Imaginary" } }, +#endif { VOID, { -1, -1, -1, VOID, VOID, 0, 0, 0, 0, 0, "void" } }, @@ -179,6 +208,7 @@ initdecl(void) typetab = xcalloc(NTSPEC, sizeof (type_t)); for (i = 0; i < NTSPEC; i++) typetab[i].t_tspec = NOTSPEC; + typetab[BOOL].t_tspec = BOOL; typetab[CHAR].t_tspec = CHAR; typetab[SCHAR].t_tspec = SCHAR; typetab[UCHAR].t_tspec = UCHAR; @@ -193,6 +223,12 @@ initdecl(void) typetab[FLOAT].t_tspec = FLOAT; typetab[DOUBLE].t_tspec = DOUBLE; typetab[LDOUBLE].t_tspec = LDOUBLE; + typetab[COMPLEX].t_tspec = COMPLEX; + typetab[DCOMPLEX].t_tspec = DCOMPLEX; + typetab[LDCOMPLEX].t_tspec = LDCOMPLEX; + typetab[IMAGINARY].t_tspec = IMAGINARY; + typetab[DIMAGINARY].t_tspec = DIMAGINARY; + typetab[LDIMAGINARY].t_tspec = LDIMAGINARY; typetab[VOID].t_tspec = VOID; /* * Next two are not real types. They are only used by the parser @@ -203,7 +239,7 @@ initdecl(void) } /* - * Returns a shared type structure vor arithmetic types and void. + * Returns a shared type structure for arithmetic types and void. * * It's important to duplicate this structure (using duptyp() or tduptyp()) * if it is to be modified (adding qualifiers or anything else). @@ -327,7 +363,8 @@ addtype(type_t *tp) if (tp->t_typedef) { if (dcs->d_type != NULL || dcs->d_atyp != NOTSPEC || - dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC) { + dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC || + dcs->d_dmod != NOTSPEC) { /* * something like "typedef int a; int a b;" * This should not happen with current grammar. @@ -346,13 +383,15 @@ addtype(type_t *tp) * 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) { + dcs->d_lmod != NOTSPEC || dcs->d_smod != NOTSPEC || + dcs->d_dmod != 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_atyp = dcs->d_smod = dcs->d_lmod = + dcs->d_dmod = NOTSPEC; } dcs->d_type = tp; return; @@ -401,6 +440,15 @@ addtype(type_t *tp) /* more than one, print error in deftyp() */ dcs->d_terr = 1; dcs->d_lmod = t; + } else if (t == COMPLEX || t == IMAGINARY) { + /* + * remember specifiers "_Complex" and "_Imaginary" in + * dcs->d_dmod + */ + if (dcs->d_dmod != NOTSPEC) + /* more than one, print error in deftyp() */ + dcs->d_terr = 1; + dcs->d_dmod = t; } else { /* * remember specifiers "void", "char", "int", "float" or @@ -447,7 +495,8 @@ tdeferr(type_t *td, tspec_t t) break; case LONG: if (t2 == INT || t2 == UINT || t2 == LONG || t2 == ULONG || - t2 == FLOAT || t2 == DOUBLE) { + t2 == FLOAT || t2 == DOUBLE || t2 == COMPLEX || + t2 == IMAGINARY) { /* modifying typedef with ... */ warning(5, "long"); if (t2 == INT) { @@ -462,6 +511,14 @@ tdeferr(type_t *td, tspec_t t) td = gettyp(DOUBLE); } else if (t2 == DOUBLE) { td = gettyp(LDOUBLE); + } else if (t2 == COMPLEX) { + td = gettyp(DCOMPLEX); + } else if (t2 == DCOMPLEX) { + td = gettyp(LDCOMPLEX); + } else if (t2 == IMAGINARY) { + td = gettyp(DIMAGINARY); + } else if (t2 == DIMAGINARY) { + td = gettyp(LDIMAGINARY); } td = duptyp(td); td->t_typedef = 1; @@ -657,7 +714,7 @@ setasm(void) void clrtyp(void) { - dcs->d_atyp = dcs->d_smod = dcs->d_lmod = NOTSPEC; + dcs->d_atyp = dcs->d_smod = dcs->d_lmod = dcs->d_dmod = NOTSPEC; dcs->d_scl = NOSCL; dcs->d_type = NULL; dcs->d_const = dcs->d_volatile = 0; @@ -667,6 +724,33 @@ clrtyp(void) dcs->d_notyp = 0; } +/* + * Merge the domain (_Complex or _Imaginary) into a type. Returns non-zero + * if the merge doesn't make sense. e.g., no "int _Complex". + */ +int +mergedomain(tspec_t *tp, tspec_t domain) +{ + if (domain == NOTSPEC) + return (0); + if (domain != COMPLEX && domain != IMAGINARY) + lerror("mergedomain()"); + switch (*tp) { + case FLOAT: + *tp = domain; + break; + case DOUBLE: + *tp = domain == COMPLEX ? DCOMPLEX : DIMAGINARY; + break; + case LDOUBLE: + *tp = domain == COMPLEX ? LDCOMPLEX : LDIMAGINARY; + break; + default: + return (1); + } + return (0); +} + /* * Create a type structure from the informations gathered in * the declaration stack. @@ -676,13 +760,15 @@ clrtyp(void) void deftyp(void) { - tspec_t t, s, l; + tspec_t t, s, l, d; type_t *tp; scl_t scl; - t = dcs->d_atyp; /* CHAR, INT, FLOAT, DOUBLE, VOID */ + t = dcs->d_atyp; /* BOOL, CHAR, INT, FLOAT, + DOUBLE, VOID */ s = dcs->d_smod; /* SIGNED, UNSIGNED */ l = dcs->d_lmod; /* SHORT, LONG, QUAD */ + d = dcs->d_dmod; /* COMPLEX, IMAGINARY */ tp = dcs->d_type; scl = dcs->d_scl; @@ -699,6 +785,8 @@ deftyp(void) case NOTSPEC: t = INT; /* FALLTHROUGH */ + case BOOL: + break; case INT: if (s == NOTSPEC) s = SIGNED; @@ -728,6 +816,8 @@ deftyp(void) default: lerror("deftyp() 2"); } + if (mergedomain(&t, d)) + dcs->d_terr = 1; if (t != INT && t != CHAR && (s != NOTSPEC || l != NOTSPEC)) { dcs->d_terr = 1; l = s = NOTSPEC; @@ -1059,7 +1149,7 @@ decl1str(sym_t *dsym) warning(34); } } else if (t != INT && t != UINT && t != LONG && - t != ULONG && t != QUAD && t != UQUAD) { + t != ULONG && t != QUAD && t != UQUAD && t != BOOL) { /* illegal bit-field type */ error(35); sz = tp->t_flen; @@ -1985,6 +2075,8 @@ eqtype(type_t *tp1, type_t *tp2, int ignqual, int promot, int *warn) if (promot) { if (t == FLOAT) { t = DOUBLE; + } else if (t == BOOL) { + t = INT; } else if (t == CHAR || t == SCHAR) { t = INT; } else if (t == UCHAR) { @@ -1994,6 +2086,10 @@ eqtype(type_t *tp1, type_t *tp2, int ignqual, int promot, int *warn) } else if (t == USHORT) { /* CONSTCOND */ t = INT_MAX < USHRT_MAX ? UINT : INT; + } else if (t == COMPLEX) { + t = DCOMPLEX; + } else if (t == IMAGINARY) { + t = DIMAGINARY; } } @@ -2087,9 +2183,11 @@ mnoarg(type_t *tp, int *warn) *warn = 1; } for (arg = tp->t_args; arg != NULL; arg = arg->s_nxt) { - if ((t = arg->s_type->t_tspec) == FLOAT || + if ((t = arg->s_type->t_tspec) == FLOAT || t == BOOL || t == CHAR || t == SCHAR || t == UCHAR || - t == SHORT || t == USHORT) { + t == SHORT || t == USHORT || t == COMPLEX || + t == DCOMPLEX || t == LDCOMPLEX || t == IMAGINARY || + t == DIMAGINARY || t == LDIMAGINARY) { if (warn != NULL) *warn = 1; } diff --git a/usr.bin/xlint/lint1/emit1.c b/usr.bin/xlint/lint1/emit1.c index 0ee39c3b55a..03f471e8f6e 100644 --- a/usr.bin/xlint/lint1/emit1.c +++ b/usr.bin/xlint/lint1/emit1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: emit1.c,v 1.7 2007/03/21 03:31:19 tedu Exp $ */ +/* $OpenBSD: emit1.c,v 1.8 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: emit1.c,v 1.4 1995/10/02 17:21:28 jpo Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: emit1.c,v 1.7 2007/03/21 03:31:19 tedu Exp $"; +static char rcsid[] = "$OpenBSD: emit1.c,v 1.8 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -48,6 +48,7 @@ static void outfstrg(strg_t *); * The type is written as a sequence of substrings, each of which describes a * node of type type_t * a node is coded as follows: + * _Bool B * char C * signed char s C * unsigned char u C @@ -62,6 +63,12 @@ static void outfstrg(strg_t *); * float s D * double D * long double l D + * float _Complex s X + * double _Complex X + * long double _Complex l X + * float _Imaginary s J + * double _Imaginary J + * long double _Imaginary l J * void V * * P * [n] A n @@ -93,6 +100,7 @@ outtype(type_t *tp) if ((ts = tp->t_tspec) == INT && tp->t_isenum) ts = ENUM; switch (ts) { + case BOOL: t = 'B'; s = '\0'; break; case CHAR: t = 'C'; s = '\0'; break; case SCHAR: t = 'C'; s = 's'; break; case UCHAR: t = 'C'; s = 'u'; break; @@ -107,6 +115,12 @@ outtype(type_t *tp) case FLOAT: t = 'D'; s = 's'; break; case DOUBLE: t = 'D'; s = '\0'; break; case LDOUBLE: t = 'D'; s = 'l'; break; + case COMPLEX: t = 'X'; s = 's'; break; + case DCOMPLEX: t = 'X'; s = '\0'; break; + case LDCOMPLEX: t = 'X'; s = 'l'; break; + case IMAGINARY: t = 'J'; s = 's'; break; + case DIMAGINARY: t = 'J'; s = '\0'; break; + case LDIMAGINARY:t = 'J'; s = 'l'; break; case VOID: t = 'V'; s = '\0'; break; case PTR: t = 'P'; s = '\0'; break; case ARRAY: t = 'A'; s = '\0'; break; diff --git a/usr.bin/xlint/lint1/externs1.h b/usr.bin/xlint/lint1/externs1.h index 437c0d8eb93..d9d19299b16 100644 --- a/usr.bin/xlint/lint1/externs1.h +++ b/usr.bin/xlint/lint1/externs1.h @@ -1,4 +1,4 @@ -/* $OpenBSD: externs1.h,v 1.15 2006/05/29 20:47:22 cloder Exp $ */ +/* $OpenBSD: externs1.h,v 1.16 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: externs1.h,v 1.7 1995/10/02 17:31:39 jpo Exp $ */ /* @@ -138,6 +138,7 @@ extern void pushdecl(scl_t); extern void popdecl(void); extern void setasm(void); extern void clrtyp(void); +extern int mergedomain(tspec_t *, tspec_t); extern void deftyp(void); extern int length(type_t *, const char *); extern int getbound(type_t *); diff --git a/usr.bin/xlint/lint1/lint.h b/usr.bin/xlint/lint1/lint.h index 8ecadbee938..570832e04e5 100644 --- a/usr.bin/xlint/lint1/lint.h +++ b/usr.bin/xlint/lint1/lint.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lint.h,v 1.6 2006/05/29 20:47:22 cloder Exp $ */ +/* $OpenBSD: lint.h,v 1.7 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: lint.h,v 1.2 1995/07/03 21:24:18 cgd Exp $ */ /* @@ -45,6 +45,7 @@ typedef enum { NOTSPEC, SIGNED, /* keyword "signed", only used in the parser */ UNSIGN, /* keyword "unsigned", only used in the parser */ + BOOL, /* _Bool */ CHAR, /* char */ SCHAR, /* signed char */ UCHAR, /* unsigned char */ @@ -59,6 +60,12 @@ typedef enum { FLOAT, /* float */ DOUBLE, /* double */ LDOUBLE, /* long double */ + COMPLEX, /* float _Complex */ + DCOMPLEX, /* double _Complex */ + LDCOMPLEX, /* long double _Complex */ + IMAGINARY, /* float _Imaginary */ + DIMAGINARY, /* double _Imaginary */ + LDIMAGINARY, /* long double _Imaginary */ VOID, /* void */ STRUCT, /* structure tag */ UNION, /* union tag */ @@ -83,7 +90,8 @@ typedef struct { u_int tt_isutyp : 1; /* 1 if unsigned integer type */ u_int tt_isftyp : 1; /* 1 if floating point type */ u_int tt_isatyp : 1; /* 1 if arithmetic type */ - u_int tt_issclt : 1; /* 1 if scalar type */ + u_int tt_domain : 2; /* 0 if non-scalar, 1 if real, + 2 if imaginary, 3 if complex */ char *tt_name; /* type name */ } ttab_t; @@ -96,7 +104,9 @@ typedef struct { #define isutyp(t) (ttab[t].tt_isutyp) #define isftyp(t) (ttab[t].tt_isftyp) #define isatyp(t) (ttab[t].tt_isatyp) -#define issclt(t) (ttab[t].tt_issclt) +#define issclt(t) (ttab[t].tt_domain != 0) +#define iscomplex(t) (ttab[t].tt_domain == 3) +#define isimag(t) (ttab[t].tt_domain == 2) extern ttab_t ttab[]; diff --git a/usr.bin/xlint/lint1/lint1.h b/usr.bin/xlint/lint1/lint1.h index d4d3f8ed9a9..39f24fe9ad7 100644 --- a/usr.bin/xlint/lint1/lint1.h +++ b/usr.bin/xlint/lint1/lint1.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lint1.h,v 1.13 2006/04/18 02:59:40 cloder Exp $ */ +/* $OpenBSD: lint1.h,v 1.14 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: lint1.h,v 1.6 1995/10/02 17:31:41 jpo Exp $ */ /* @@ -224,6 +224,7 @@ typedef struct sym { tqual_t _s_tqu; /* qualifier (only for keywords) */ struct sym *_s_args; /* arguments in old style function definitions */ + op_t _s_op; /* op type (only for operators) */ } u; struct sym *s_link; /* next symbol with same hash value */ struct sym **s_rlink; /* pointer to s_link of prev. symbol */ @@ -236,6 +237,7 @@ typedef struct sym { #define s_etyp u._s_et #define s_tspec u._s_tsp #define s_tqual u._s_tqu +#define s_op u._s_op #define s_args u._s_args /* @@ -294,9 +296,10 @@ typedef struct tnode { * */ typedef struct dinfo { - tspec_t d_atyp; /* VOID, CHAR, INT, FLOAT or DOUBLE */ - tspec_t d_smod; /* SIGNED or UNSIGN */ - tspec_t d_lmod; /* SHORT, LONG or QUAD */ + tspec_t d_atyp; /* NOTSPEC, VOID, CHAR, INT, FLOAT or DOUBLE */ + tspec_t d_smod; /* sign: NOTSPEC, SIGNED or UNSIGN */ + tspec_t d_lmod; /* length: NOTSPEC, SHORT, LONG or QUAD */ + tspec_t d_dmod; /* domain: NOTSPEC, COMPLEX or IMAGINARY */ scl_t d_scl; /* storage class */ type_t *d_type; /* after deftyp() pointer to the type used for all declarators */ diff --git a/usr.bin/xlint/lint1/op.h b/usr.bin/xlint/lint1/op.h index 80d55631795..2198822f8aa 100644 --- a/usr.bin/xlint/lint1/op.h +++ b/usr.bin/xlint/lint1/op.h @@ -1,4 +1,4 @@ -/* $OpenBSD: op.h,v 1.3 2005/11/29 20:09:57 cloder Exp $ */ +/* $OpenBSD: op.h,v 1.4 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: op.h,v 1.2 1995/07/03 21:24:27 cgd Exp $ */ /* @@ -114,6 +114,8 @@ typedef enum { LOAD, PUSH, RETURN, + REAL, /* gcc extension: __real__ */ + IMAG, /* gcc extension: __imag__ */ INIT, /* pseudo op, not used in trees */ CASE, /* pseudo op, not used in trees */ FARG /* pseudo op, not used in trees */ diff --git a/usr.bin/xlint/lint1/scan.l b/usr.bin/xlint/lint1/scan.l index a8cf8d71463..55002fff854 100644 --- a/usr.bin/xlint/lint1/scan.l +++ b/usr.bin/xlint/lint1/scan.l @@ -1,5 +1,5 @@ %{ -/* $OpenBSD: scan.l,v 1.31 2007/09/05 16:32:17 fgsch Exp $ */ +/* $OpenBSD: scan.l,v 1.32 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: scan.l,v 1.8 1995/10/23 13:38:51 jpo Exp $ */ /* @@ -34,7 +34,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: scan.l,v 1.31 2007/09/05 16:32:17 fgsch Exp $"; +static char rcsid[] = "$OpenBSD: scan.l,v 1.32 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -91,6 +91,7 @@ OD [0-7] HD [0-9A-Fa-f] EX ([eE][+-]?[0-9]+) HEX ([pP][+-]?[0-9]+) +FSUFF ([fFlL][iIjJ]?|[iIjJ][fFlL]?)? %% @@ -98,12 +99,12 @@ HEX ([pP][+-]?[0-9]+) 0{OD}*[lLuU]* return (icon(8)); {NZD}{D}*[lLuU]* return (icon(10)); 0[xX]{HD}+[lLuU]* return (icon(16)); -{D}+\.{D}*{EX}?[fFlL]? | -{D}+{EX}[fFlL]? | -\.{D}+{EX}?[fFlL]? return (fcon()); -0[xX]{HD}+\.{HD}*{HEX}[fFlL]? | -0[xX]{HD}+{HEX}[fFlL]? | -0[xX]\.{HD}+{HEX}[fFlL]? return (fhexcon()); +{D}+\.{D}*{EX}?{FSUFF} | +{D}+{EX}{FSUFF} | +\.{D}+{EX}?{FSUFF} return (fcon()); +0[xX]{HD}+\.{HD}*{HEX}{FSUFF} | +0[xX]{HD}+{HEX}{FSUFF} | +0[xX]\.{HD}+{HEX}{FSUFF} return (fhexcon()); "=" return (operator(T_ASSIGN, ASSIGN)); "*=" return (operator(T_OPASS, MULASS)); "/=" return (operator(T_OPASS, DIVASS)); @@ -189,6 +190,7 @@ static struct kwtab { scl_t kw_scl; /* storage class if kw_token T_SCLASS */ tspec_t kw_tspec; /* type spec. if kw_token T_TYPE or T_SOU */ tqual_t kw_tqual; /* type qual. if kw_token T_QUAL */ + op_t kw_op; /* operator if kw_token T_UNOP */ } kw_u; u_int kw_stdc : 1; /* STDC keyword */ u_int kw_gcc : 1; /* GCC keyword */ @@ -198,9 +200,12 @@ static struct kwtab { { "__asm__", T_ASM, { 0 }, 0, 0 }, { "__attribute__", T_ATTRIBUTE, { 0 }, 0, 0 }, { "auto", T_SCLASS, { AUTO }, 0, 0 }, + { "_Bool", T_TYPE, { BOOL }, 1, 0 }, { "break", T_BREAK, { 0 }, 0, 0 }, { "case", T_CASE, { 0 }, 0, 0 }, { "char", T_TYPE, { CHAR }, 0, 0 }, + { "_Complex", T_TYPE, { COMPLEX }, 1, 0 }, + { "__complex__", T_TYPE, { COMPLEX }, 0, 1 }, { "const", T_QUAL, { CONST }, 1, 0 }, { "__const__", T_QUAL, { CONST }, 0, 0 }, { "__const", T_QUAL, { CONST }, 0, 0 }, @@ -215,12 +220,15 @@ static struct kwtab { { "for", T_FOR, { 0 }, 0, 0 }, { "goto", T_GOTO, { 0 }, 0, 0 }, { "if", T_IF, { 0 }, 0, 0 }, + { "__imag__", T_UNOP, { IMAG }, 0, 0 /*1*/ }, +/* { "_Imaginary", T_TYPE, { IMAGINARY }, 1, 0 }, */ { "inline", T_SCLASS, { INLINE }, 1, 0 }, { "__inline__", T_SCLASS, { INLINE }, 0, 0 }, { "__inline", T_SCLASS, { INLINE }, 0, 0 }, { "int", T_TYPE, { INT }, 0, 0 }, { "__lint_equal__", T_LEQUAL, { 0 }, 0, 0 }, { "long", T_TYPE, { LONG }, 0, 0 }, + { "__real__", T_UNOP, { REAL }, 0, 0 /*1*/ }, { "register", T_SCLASS, { REG }, 0, 0 }, { "__restrict", T_QUAL, { RESTRICT }, 0, 0 }, { "__restrict__", T_QUAL, { RESTRICT }, 0, 0 }, @@ -247,6 +255,7 @@ static struct kwtab { #define kw_scl kw_u.kw_scl #define kw_tspec kw_u.kw_tspec #define kw_tqual kw_u.kw_tqual +#define kw_op kw_u.kw_op /* Symbol table */ static sym_t *symtab[HSHSIZ1]; @@ -292,6 +301,8 @@ initscan(void) sym->s_scl = kw->kw_scl; } else if (kw->kw_token == T_QUAL) { sym->s_tqual = kw->kw_tqual; + } else if (kw->kw_token == T_UNOP) { + sym->s_op = kw->kw_op; } h = hash(sym->s_name); if ((sym->s_link = symtab[h]) != NULL) @@ -444,6 +455,8 @@ keyw(sym_t *sym) yylval.y_tspec = sym->s_tspec; } else if (t == T_QUAL) { yylval.y_tqual = sym->s_tqual; + } else if (t == T_UNOP) { + yylval.y_op = sym->s_op; } return (t); } @@ -627,6 +640,7 @@ fcon(void) const char *cp; int len; tspec_t typ; + tspec_t domain = NOTSPEC; char c, *eptr; double d; float f; @@ -634,15 +648,29 @@ fcon(void) cp = yytext; len = yyleng; - if ((c = cp[len - 1]) == 'f' || c == 'F') { + c = cp[len - 1]; + if (c == 'i' || c == 'I' || c == 'j' || c == 'J') { + domain = COMPLEX; /* XXX should be IMAGINARY */ + len--; + c = cp[len - 1]; + } + if (c == 'f' || c == 'F') { typ = FLOAT; len--; + c = cp[len - 1]; } else if (c == 'l' || c == 'L') { typ = LDOUBLE; len--; + c = cp[len - 1]; } else { typ = DOUBLE; } + if (c == 'i' || c == 'I' || c == 'j' || c == 'J') { + if (domain != NOTSPEC) + lerror("fcon() 2"); /* can't happen */ + domain = COMPLEX; /* XXX should be IMAGINARY */ + len--; + } errno = 0; d = strtod(cp, &eptr); @@ -661,12 +689,15 @@ fcon(void) } } - (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ; + yylval.y_val = xcalloc(1, sizeof (val_t)); if (typ == FLOAT) { yylval.y_val->v_ldbl = f; } else { yylval.y_val->v_ldbl = d; } + if (mergedomain(&typ, domain)) + lerror("fcon() 3"); + yylval.y_val->v_tspec = typ; return (T_CON); } @@ -684,6 +715,7 @@ fhexcon(void) const char *cp; int len; tspec_t typ; + tspec_t domain = NOTSPEC; char c; double d; float f; @@ -691,15 +723,29 @@ fhexcon(void) cp = yytext; len = yyleng; - if ((c = cp[len - 1]) == 'f' || c == 'F') { + c = cp[len - 1]; + if (c == 'i' || c == 'I' || c == 'j' || c == 'J') { + domain = COMPLEX; /* XXX should be IMAGINARY */ + len--; + c = cp[len - 1]; + } + if (c == 'f' || c == 'F') { typ = FLOAT; len--; + c = cp[len - 1]; } else if (c == 'l' || c == 'L') { typ = LDOUBLE; len--; + c = cp[len - 1]; } else { typ = DOUBLE; } + if (c == 'i' || c == 'I' || c == 'j' || c == 'J') { + if (domain != NOTSPEC) + lerror("fhexcon() 1"); /* can't happen */ + domain = COMPLEX; /* XXX should be IMAGINARY */ + len--; + } /* arbitrary value, until strtod can cope */ d = 1.0; @@ -708,12 +754,15 @@ fhexcon(void) f = (float)d; } - (yylval.y_val = xcalloc(1, sizeof (val_t)))->v_tspec = typ; + yylval.y_val = xcalloc(1, sizeof (val_t)); if (typ == FLOAT) { yylval.y_val->v_ldbl = f; } else { yylval.y_val->v_ldbl = d; } + if (mergedomain(&typ, domain)) + lerror("fhexcon() 2"); + yylval.y_val->v_tspec = typ; return (T_CON); } diff --git a/usr.bin/xlint/lint1/tree.c b/usr.bin/xlint/lint1/tree.c index c674be2e743..0ed9c24eac4 100644 --- a/usr.bin/xlint/lint1/tree.c +++ b/usr.bin/xlint/lint1/tree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tree.c,v 1.46 2007/10/17 20:10:44 chl Exp $ */ +/* $OpenBSD: tree.c,v 1.47 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: tree.c,v 1.12 1995/10/02 17:37:57 jpo Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: tree.c,v 1.46 2007/10/17 20:10:44 chl Exp $"; +static char rcsid[] = "$OpenBSD: tree.c,v 1.47 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -203,6 +203,10 @@ initmtab(void) "PUSH" } }, { RETURN, { 1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, "RETURN" } }, + { REAL, { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1, + "__real__" } }, + { IMAG, { 0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1, + "__imag__" } }, { INIT, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, "INIT" } }, { FARG, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, @@ -629,6 +633,17 @@ build(op_t op, tnode_t *ln, tnode_t *rn) case QUEST: ntn = mktnode(op, rn->tn_type, ln, rn); break; + case REAL: + case IMAG: + rtp = ln->tn_type; + if (rtp->t_tspec == COMPLEX) + rtp = gettyp(FLOAT); + else if (rtp->t_tspec == DCOMPLEX) + rtp = gettyp(DOUBLE); + else if (rtp->t_tspec == LDCOMPLEX) + rtp = gettyp(LDOUBLE); + ntn = mktnode(op, rtp, ln, rn); + break; default: rtp = mp->m_logop ? gettyp(INT) : ln->tn_type; if (!mp->m_binary && rn != NULL) @@ -747,6 +762,9 @@ typeok(op_t op, farg_t *farg, tnode_t *ln, tnode_t *rn) } if (mp->m_rqint) { + if (op == COMPL && iscomplex(lt)) { + /* use of '~' for complex conjugation is a GNUism */ + } else /* integer types required */ if (!isityp(lt) || (mp->m_binary && !isityp(rt))) { incompat(op, lt, rt); @@ -1434,6 +1452,8 @@ mktnode(op_t op, type_t *type, tnode_t *ln, tnode_t *rn) } else { lerror("mktnode() 2"); } + } else if (op == REAL || op == IMAG) { + ntn->tn_lvalue = ln->tn_lvalue; } return (ntn); @@ -1715,6 +1735,10 @@ iiconv(op_t op, farg_t *farg, tspec_t nt, tspec_t ot, type_t *tp, tnode_t *tn) if (op == CVT) return; + /* logical ops return int, so silently convert int to _Bool */ + if (ot == INT && nt == BOOL) + return; + if (rank(nt) < rank(ot)) { /* coercion from greater to lesser width */ if (op == FARG) { @@ -1842,6 +1866,8 @@ cvtcon(op_t op, farg_t *farg, type_t *tp, val_t *nv, val_t *v) if (ot == FLOAT || ot == DOUBLE || ot == LDOUBLE) { switch (nt) { + case BOOL: + max = 1; min = 0; break; case CHAR: max = CHAR_MAX; min = CHAR_MIN; break; case UCHAR: @@ -1873,11 +1899,21 @@ cvtcon(op_t op, farg_t *farg, type_t *tp, val_t *nv, val_t *v) /* Already an error because of float --> ptr */ case LDOUBLE: max = LDBL_MAX; min = -LDBL_MAX; break; + case COMPLEX: + max = FLT_MAX; min = -FLT_MAX; break; + case DCOMPLEX: + max = DBL_MAX; min = -DBL_MAX; break; + case LDCOMPLEX: + max = LDBL_MAX; min = -LDBL_MAX; break; + case IMAGINARY: + case DIMAGINARY: + case LDIMAGINARY: + max = 0; min = 0; break; default: lerror("cvtcon() 1"); } if (v->v_ldbl > max || v->v_ldbl < min) { - if (nt == LDOUBLE) + if (nt == LDOUBLE || nt == LDCOMPLEX) lerror("cvtcon() 2"); if (op == FARG) { /* %s arg #%d: conv. of %s to %s is out of range */ @@ -1900,15 +1936,18 @@ cvtcon(op_t op, farg_t *farg, type_t *tp, val_t *nv, val_t *v) (u_quad_t)v->v_ldbl : (quad_t)v->v_ldbl; } } else { - if (nt == FLOAT) { + if (nt == FLOAT || nt == COMPLEX) { nv->v_ldbl = (ot == PTR || isutyp(ot)) ? (float)(u_quad_t)v->v_quad : (float)v->v_quad; - } else if (nt == DOUBLE) { + } else if (nt == DOUBLE || nt == DCOMPLEX) { nv->v_ldbl = (ot == PTR || isutyp(ot)) ? (double)(u_quad_t)v->v_quad : (double)v->v_quad; - } else if (nt == LDOUBLE) { + } else if (nt == LDOUBLE || nt == LDCOMPLEX) { nv->v_ldbl = (ot == PTR || isutyp(ot)) ? (ldbl_t)(u_quad_t)v->v_quad : (ldbl_t)v->v_quad; + } else if (nt == IMAGINARY || nt == DIMAGINARY || + nt == LDIMAGINARY) { + nv->v_ldbl = 0; } else { rchk = 1; /* Check for lost precision. */ nv->v_quad = v->v_quad; @@ -2200,6 +2239,7 @@ tyname(type_t *tp) t = ENUM; switch (t) { + case BOOL: s = "_Bool"; break; case CHAR: s = "char"; break; case UCHAR: s = "unsigned char"; break; case SCHAR: s = "signed char"; break; @@ -2214,6 +2254,12 @@ tyname(type_t *tp) case FLOAT: s = "float"; break; case DOUBLE: s = "double"; break; case LDOUBLE: s = "long double"; break; + case COMPLEX: s = "float _Complex"; break; + case DCOMPLEX: s = "double _Complex"; break; + case LDCOMPLEX: s = "long double _Complex"; break; + case IMAGINARY: s = "float _Imaginary"; break; + case DIMAGINARY: s = "double _Imaginary"; break; + case LDIMAGINARY:s = "long double _Imaginary"; break; case PTR: s = "pointer"; break; case ENUM: s = "enum"; break; case STRUCT: s = "struct"; break; @@ -2757,6 +2803,9 @@ fold(tnode_t *tn) case OR: q = utyp ? ul | ur : sl | sr; break; + case REAL: + case IMAG: + q = sl; default: lerror("fold() 5"); } @@ -2897,6 +2946,10 @@ foldflt(tnode_t *tn) case NE: v->v_quad = l != r; break; + case REAL: + case IMAG: + v->v_ldbl = l; + break; default: lerror("foldflt() 4"); } @@ -2933,6 +2986,8 @@ bldszoftrm(tnode_t *tn) case STAR: case NAME: case STRING: + case REAL: + case IMAG: break; default: warning(312, modtab[tn->tn_op].m_name); @@ -3504,6 +3559,8 @@ chkmisc(tnode_t *tn, int vctx, int tctx, int eqwarn, int fcall, int rvdisc, case XORASS: case SHLASS: case SHRASS: + case REAL: + case IMAG: if (ln->tn_op == NAME && (reached || rchflg)) { sc = ln->tn_sym->s_scl; /* diff --git a/usr.bin/xlint/lint2/chk.c b/usr.bin/xlint/lint2/chk.c index 5dddd17b039..5ec065a5995 100644 --- a/usr.bin/xlint/lint2/chk.c +++ b/usr.bin/xlint/lint2/chk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chk.c,v 1.16 2007/05/26 00:36:04 krw Exp $ */ +/* $OpenBSD: chk.c,v 1.17 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: chk.c,v 1.2 1995/07/03 21:24:42 cgd Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: chk.c,v 1.16 2007/05/26 00:36:04 krw Exp $"; +static char rcsid[] = "$OpenBSD: chk.c,v 1.17 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -83,6 +83,9 @@ inittyp(void) { UNSIGN, { 0, 0, 0, SIGNED, UNSIGN, 0, 0, 0, 0, 0, "unsigned" } }, + { BOOL, { sizeof (_Bool) * CHAR_BIT, CHAR_BIT, 1, + BOOL, BOOL, + 1, 1, 0, 1, 1, "_Bool" } }, { CHAR, { CHAR_BIT, CHAR_BIT, 20, SCHAR, UCHAR, 1, 0, 0, 1, 1, "char" } }, @@ -125,6 +128,18 @@ inittyp(void) { LDOUBLE, { sizeof (ldbl_t) * CHAR_BIT, 10 * CHAR_BIT, -1, LDOUBLE, LDOUBLE, 0, 0, 1, 1, 1, "long double" } }, + { COMPLEX, { sizeof (_Complex float) * CHAR_BIT, + 8 * CHAR_BIT, -1, + COMPLEX, COMPLEX, + 0, 0, 1, 1, 1, "float _Complex" } }, + { DCOMPLEX, { sizeof (double _Complex) * CHAR_BIT, + 16 * CHAR_BIT, -1, + DCOMPLEX, DCOMPLEX, + 0, 0, 1, 1, 1, "double _Complex" } }, + { LDCOMPLEX,{ sizeof (long double _Complex) * CHAR_BIT, + 20 * CHAR_BIT, -1, + LDCOMPLEX, LDCOMPLEX, + 0, 0, 1, 1, 1, "long double _Complex" } }, { VOID, { -1, -1, -1, VOID, VOID, 0, 0, 0, 0, 0, "void" } }, diff --git a/usr.bin/xlint/lint2/emit2.c b/usr.bin/xlint/lint2/emit2.c index de032bdb16b..08d796a0fa5 100644 --- a/usr.bin/xlint/lint2/emit2.c +++ b/usr.bin/xlint/lint2/emit2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: emit2.c,v 1.5 2005/11/20 17:09:55 cloder Exp $ */ +/* $OpenBSD: emit2.c,v 1.6 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: emit2.c,v 1.2 1995/07/03 21:24:44 cgd Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: emit2.c,v 1.5 2005/11/20 17:09:55 cloder Exp $"; +static char rcsid[] = "$OpenBSD: emit2.c,v 1.6 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -58,6 +58,7 @@ outtype(type_t *tp) if ((ts = tp->t_tspec) == INT && tp->t_isenum) ts = ENUM; switch (ts) { + case BOOL: t = 'B'; s = '\0'; break; case CHAR: t = 'C'; s = '\0'; break; case SCHAR: t = 'C'; s = 's'; break; case UCHAR: t = 'C'; s = 'u'; break; @@ -72,6 +73,12 @@ outtype(type_t *tp) case FLOAT: t = 'D'; s = 's'; break; case DOUBLE: t = 'D'; s = '\0'; break; case LDOUBLE: t = 'D'; s = 'l'; break; + case COMPLEX: t = 'X'; s = 's'; break; + case DCOMPLEX: t = 'X'; s = '\0'; break; + case LDCOMPLEX: t = 'X'; s = 'l'; break; + case IMAGINARY: t = 'J'; s = 's'; break; + case DIMAGINARY: t = 'J'; s = '\0'; break; + case LDIMAGINARY:t = 'J'; s = 'l'; break; case VOID: t = 'V'; s = '\0'; break; case PTR: t = 'P'; s = '\0'; break; case ARRAY: t = 'A'; s = '\0'; break; diff --git a/usr.bin/xlint/lint2/read.c b/usr.bin/xlint/lint2/read.c index d59bf939d1d..615c6a971c8 100644 --- a/usr.bin/xlint/lint2/read.c +++ b/usr.bin/xlint/lint2/read.c @@ -1,4 +1,4 @@ -/* $OpenBSD: read.c,v 1.9 2005/12/01 05:06:40 cloder Exp $ */ +/* $OpenBSD: read.c,v 1.10 2010/07/24 22:17:03 guenther Exp $ */ /* $NetBSD: read.c,v 1.2 1995/07/03 21:24:59 cgd Exp $ */ /* @@ -33,7 +33,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: read.c,v 1.9 2005/12/01 05:06:40 cloder Exp $"; +static char rcsid[] = "$OpenBSD: read.c,v 1.10 2010/07/24 22:17:03 guenther Exp $"; #endif #include @@ -517,6 +517,9 @@ inptype(const char *cp, const char **epp) } switch (c) { + case 'B': + tp->t_tspec = BOOL; + break; case 'C': tp->t_tspec = s == 's' ? SCHAR : (s == 'u' ? UCHAR : CHAR); break; @@ -535,6 +538,14 @@ inptype(const char *cp, const char **epp) case 'D': tp->t_tspec = s == 's' ? FLOAT : (s == 'l' ? LDOUBLE : DOUBLE); break; + case 'X': + tp->t_tspec = s == 's' ? COMPLEX : (s == 'l' ? + LDCOMPLEX : DCOMPLEX); + break; + case 'J': + tp->t_tspec = s == 's' ? IMAGINARY : (s == 'l' ? + LDIMAGINARY : DIMAGINARY); + break; case 'V': tp->t_tspec = VOID; break; @@ -649,6 +660,9 @@ gettlen(const char *cp, const char **epp) t = NOTSPEC; switch (c) { + case 'B': + t = BOOL; + break; case 'C': if (s == 's') { t = SCHAR; @@ -695,6 +709,24 @@ gettlen(const char *cp, const char **epp) t = DOUBLE; } break; + case 'X': + if (s == 's') { + t = COMPLEX; + } else if (s == 'l') { + t = LDCOMPLEX; + } else if (s == '\0') { + t = DCOMPLEX; + } + break; + case 'J': + if (s == 's') { + t = IMAGINARY; + } else if (s == 'l') { + t = LDIMAGINARY; + } else if (s == '\0') { + t = DIMAGINARY; + } + break; case 'V': if (s == '\0') t = VOID;