aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-04-18 11:09:17 +0200
committerlemon <lsof@mailbox.org>2026-04-18 11:09:17 +0200
commit970508c5221f930937021203107ecbac5ac9960c (patch)
treec6ec98e89e48331cf20adf5db4742e4155e7686a /src
parente9b132ef171114b0384ef30d6630db22d2b47e5d (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.c24
-rw-r--r--src/c_type.c68
-rw-r--r--src/c_type.h1
3 files changed, 75 insertions, 18 deletions
diff --git a/src/c.c b/src/c.c
index 0715a76..c449129 100644
--- a/src/c.c
+++ b/src/c.c
@@ -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(&param[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);