diff options
| author | 2026-04-18 11:09:17 +0200 | |
|---|---|---|
| committer | 2026-04-18 11:09:17 +0200 | |
| commit | 970508c5221f930937021203107ecbac5ac9960c (patch) | |
| tree | c6ec98e89e48331cf20adf5db4742e4155e7686a /src | |
| parent | e9b132ef171114b0384ef30d6630db22d2b47e5d (diff) | |
c: fix some compatible type declarations
When K&R prototypes are present, definition of compatible types and
composite types becomes recursive. For example
`int f(int (*)())`
should be compatible with
`int f(int (*)(int))`
etc
Diffstat (limited to 'src')
| -rw-r--r-- | src/c.c | 24 | ||||
| -rw-r--r-- | src/c_type.c | 68 | ||||
| -rw-r--r-- | src/c_type.h | 1 |
3 files changed, 75 insertions, 18 deletions
@@ -261,7 +261,7 @@ envitertagged(Tagged **l, Env *env) } static bool -redeclarationok(const Decl *old, const Decl *new) +redeclarationok(const Decl *old, Decl *new) { bool takeoldscls = 0; if (old->scls != new->scls) { @@ -273,18 +273,7 @@ redeclarationok(const Decl *old, const Decl *new) switch (old->scls) { case SCSTATIC: case SCEXTERN: - if (old->ty.bits == new->ty.bits) goto OkFuncs; - if (old->ty.t != new->ty.t) return 0; - if (old->ty.t == TYARRAY /* allow 'int x[]; int x[100];' */ - && typechild(old->ty).bits == typechild(new->ty).bits - && (isincomplete(old->ty) || isincomplete(new->ty))) - { - return 1; - } - if (old->ty.t == TYFUNC /* allow 'int f(); int f(int);' (some K&R) */ - && typedata[old->ty.dat].ret.bits == typedata[new->ty.dat].ret.bits - && (typedata[old->ty.dat].kandr || typedata[new->ty.dat].kandr)) - { OkFuncs: + if (typescompat(&new->ty, old->ty, new->ty)) { if (takeoldscls) ((Decl *)new)->scls = old->scls; return 1; } @@ -296,7 +285,7 @@ redeclarationok(const Decl *old, const Decl *new) } static int -putdecl(CComp *cm, const Decl *decl) +putdecl(CComp *cm, Decl *decl) { for (Env *env = cm->env; env; env = env->up) { Decl *l; @@ -404,14 +393,15 @@ argpromote(Type t) bool assigncheck(Type t, const Expr *src) { - Type srcty = typedecay(src->ty);; + Type srcty = typedecay(src->ty); if (assigncompat(t, srcty)) { if (t.t == TYPTR && srcty.t == TYPTR && (t.flag & TFCHLDQUAL & srcty.flag & TFCHLDQUAL) != (srcty.flag & TFCHLDQUAL)) { warn(&src->span, "usage of '%ty' discards pointer qualifiers", src->ty); } return 1; - } else if (t.t == TYPTR && srcty.t == TYPTR) { + } else if ((t.t == TYPTR && srcty.t == TYPTR) + && !typescompat(NULL, typechild(t), typechild(srcty))) { warn(&src->span, "converting between incompatible pointer types ('%ty' -> '%ty')", srcty, t); return 1; } else if (t.t == TYPTR && iszero(*src)) return 1; @@ -652,7 +642,7 @@ bintypecheck(const Span *span, enum toktag tt, Expr *lhs, Expr *rhs) error(span, "arithmetic on pointer to incomplete type '%ty'", ty); else if (pointee1.t == TYFUNC) error(span, "arithmetic on function pointer '%ty'", lhs->ty); - else if (pointee1.bits != pointee2.bits) { + else if (!typescompat(NULL, pointee1, pointee2)) { error(span, "arithmetic on incompatible pointer types: '%ty', '%ty'", ty, rhs->ty); } diff --git a/src/c_type.c b/src/c_type.c index c34d7df..3aa9126 100644 --- a/src/c_type.c +++ b/src/c_type.c @@ -278,7 +278,7 @@ typedecay(Type t) bool /* 6.5.16.1 Simple assignment Constraints */ assigncompat(Type dst, Type src) { - if (dst.bits == src.bits) return 1; + if (dst.bits == src.bits || typescompat(NULL, dst, src)) return 1; if (isarith(dst) && isarith(src)) return 1; if (dst.t == TYPTR && src.t == TYPTR) { Type ds = typechild(dst), ss = typechild(src); @@ -295,6 +295,72 @@ assigncompat(Type dst, Type src) return 0; } + +bool /* 6.2.7 Compatible type and composite type */ +typescompat(Type *pcompt, Type t1, Type t2) +{ + if (t1.bits == t2.bits) { + if (pcompt) *pcompt = t1; + return 1; + } + if (t1.t != t2.t) return 0; + if (t1.t == TYPTR) { + int qual; + if ((qual = t1.flag & TFCHLDQUAL) != (t2.flag & TFCHLDQUAL)) return 0; + Type chld; + if (!typescompat(&chld, typechild(t1), typechild(t2))) return 0; + if (pcompt) + *pcompt = mkptrtype(chld, qual); + return 1; + } else if (t1.t == TYARRAY) { + int qual; + Type chld; + if ((qual = t1.flag & TFCHLDQUAL) != (t2.flag & TFCHLDQUAL)) return 0; + if (!typescompat(&chld, typechild(t1), typechild(t2))) return 0; + if (pcompt) { + uint len; + if (!(t1.flag & TFUNKNOWN)) { + len = typearrlen(t1); + Sized: + *pcompt = mkarrtype(chld, qual, len); + } else if (!(t2.flag & TFUNKNOWN)) { + len = typearrlen(t2); + goto Sized; + } else { + *pcompt = mkunszarrtype(chld, qual); + } + } + return 1; + } else if (t1.t == TYFUNC) { + Type ret, param[40]; + const TypeData *td1 = &typedata[t1.dat], *td2 = &typedata[t2.dat]; + if (!typescompat(&ret, td1->ret, td2->ret)) return 0; + if (td1->kandr && td2->kandr) { + if (pcompt) *pcompt = mkfntype(ret, 0, NULL, /*kandr=*/1, 0); + return 1; + } else if (td1->kandr || td2->kandr) { + if (pcompt) { + const TypeData *tdgood = td1->kandr ? td2 : td1; + *pcompt = mkfntype(ret, tdgood->nmemb, tdgood->param, + /*kandr=*/0, tdgood->variadic); + } + return 1; + } else if (td1->nmemb != td2->nmemb || td1->variadic != td2->variadic) { + return 0; + } + if (td1->nmemb > countof(param)) return 0; /* meh */ + + for (int i = 0, npar = td1->nmemb; i < npar; ++i) { + if (!typescompat(¶m[i], td1->param[i], td2->param[i])) + return 0; + } + if (pcompt) + *pcompt = mkfntype(ret, td1->nmemb, param, 0, td1->variadic); + return 1; + } + return 0; +} + enum typetag intpromote(enum typetag t) { diff --git a/src/c_type.h b/src/c_type.h index 1347fcc..3b1e022 100644 --- a/src/c_type.h +++ b/src/c_type.h @@ -135,6 +135,7 @@ bool getfield(FieldData *res, Type, internstr); Type completetype(internstr name, int id, TypeData *td); Type typedecay(Type); bool assigncompat(Type dst, Type src); +bool typescompat(Type *pcomposite, Type, Type); enum typetag intpromote(enum typetag); Type cvtarith(Type a, Type b); Type complex2struct(Type); |