diff options
Diffstat (limited to 'src/c_type.c')
| -rw-r--r-- | src/c_type.c | 68 |
1 files changed, 67 insertions, 1 deletions
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) { |