commit f9e48140e72d80782d7962ad7424e3bd5141a008
parent e91b51fe19fc58e4814eed28fda80ed3990078ea
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Wed, 26 Oct 2022 15:12:57 +0200
cc1: Improve k&r function semantic
Combination of k&r function with ansi functions is not easy,
and there are two cases that were not handled in the best way:
- A function definition without parameter list is a definition
of a function with no parameters.
- When function are combined the combinations that produce
runnable code because the call convention is compatible.
Diffstat:
2 files changed, 85 insertions(+), 22 deletions(-)
diff --git a/src/cmd/cc/cc1/decl.c b/src/cmd/cc/cc1/decl.c
@@ -187,21 +187,15 @@ redcl(Symbol *sym, Type *tp, int sclass)
int flags;
char *name = sym->name;
- if (sym->type->op == FTN && tp->op == FTN) {
- Type *ntp = sym->type;
- if (eqtype(ntp->type, tp->type, 1)) {
- if (tp->prop & TK_R)
- tp = ntp;
- if (sym->type->prop & TK_R)
- sym->type = tp;
- }
- }
-
if (!eqtype(sym->type, tp, 1)) {
errorp("conflicting types for '%s'", name);
return sym;
}
+ /* we prefere ansi types over k&r types */
+ if ((sym->type->prop & TK_R) == 0 && (tp->prop & TK_R) != 0)
+ sym->type = tp;
+
if (sym->token == TYPEIDEN && sclass != TYPEDEF ||
sym->token != TYPEIDEN && sclass == TYPEDEF) {
goto redeclaration;
@@ -416,7 +410,6 @@ krfun(struct declarators *dp)
{
int toomany = 0;
-
if (yytoken != ')')
toomany = krpars(dp);
@@ -511,10 +504,10 @@ funbody(Symbol *sym, Symbol *pars[])
if (!sym)
return 0;
+
tp = sym->type;
if (tp->op != FTN)
return 0;
-
if (!isfunbody(yytoken) || sym->ns != NS_IDEN) {
emit(ODECL, sym);
endfundcl(tp, pars);
@@ -533,7 +526,7 @@ funbody(Symbol *sym, Symbol *pars[])
tp->prop |= TFUNDEF;
curfun = sym;
- if (sym->type->prop & TK_R) {
+ if (tp->prop & TK_R) {
while (yytoken != '{') {
dodcl(REP, parameter, NS_IDEN, sym->type);
expect(';');
@@ -562,6 +555,17 @@ funbody(Symbol *sym, Symbol *pars[])
popctx();
flushtypes();
curfun = NULL;
+
+ /*
+ * A function declaration without arguments is a k&r function,
+ * but when it is a definition is a function with 0 arguments
+ */
+ if ((tp->prop & TK_R) && *pars == NULL) {
+ tp = mktype(tp->type, FTN, 0, NULL);
+ tp->prop |= TFUNDEF;
+ sym->type = tp;
+ }
+
return 1;
}
diff --git a/src/cmd/cc/cc1/types.c b/src/cmd/cc/cc1/types.c
@@ -353,11 +353,77 @@ mktype(Type *tp, int op, TINT nelem, Type *pars[])
return bp;
}
+/*
+ * If one type has a parameter type list and the other type is specified by
+ * a function declarator that is not part of a function definition and that
+ * contains an empty identifier list, the parameter list shall not have an
+ * ellipsis terminator and the type of each parameter shall be compatible
+ * with the type that results from the application of the default argument
+ * promotions.
+ */
+static int
+eqfuns(Type *tp1, Type *tp2, int equiv)
+{
+ TINT n;
+ int f1kr, f2kr;
+ Type *krf, *ansi, **pp, *p;
+
+ f1kr = (tp1->prop&TK_R) != 0;
+ f2kr = (tp2->prop&TK_R) != 0;
+
+ /* 1: 2 ansi functions */
+ if (!f1kr && !f2kr) {
+ Type **p1, **p2;
+ if (tp1->n.elem != tp2->n.elem)
+ return 0;
+ p1 = tp1->p.pars, p2 = tp2->p.pars;
+ for (n = tp1->n.elem; n > 0; --n) {
+ if (!eqtype(*p1++, *p2++, equiv))
+ return 0;
+ }
+ goto check_base;
+ }
+
+ /* 2: 2 k&r functions */
+ if (f1kr && f2kr)
+ goto check_base;
+
+ /* 3: 1 k&r function + 1 ansi function */
+ if (!equiv)
+ return 0;
+
+ if (f1kr) {
+ krf = tp1;
+ ansi = tp2;
+ } else {
+ ansi = tp1;
+ krf = tp2;
+ }
+
+ for (pp = ansi->p.pars; p = *pp; ++pp) {
+ switch (p->op) {
+ case ELLIPSIS:
+ return 0;
+ case INT:
+ case ENUM:
+ if (p->n.rank < inttype->n.rank)
+ return 0;
+ break;
+ case FLOAT:
+ if (p == floattype)
+ return 0;
+ break;
+ }
+ }
+
+check_base:
+ return eqtype(tp1->type, tp2->type, equiv);
+}
+
int
eqtype(Type *tp1, Type *tp2, int equiv)
{
TINT n;
- Type **p1, **p2;
Symbol **s1, **s2;
if (tp1 == tp2)
@@ -385,14 +451,7 @@ eqtype(Type *tp1, Type *tp2, int equiv)
}
return 1;
case FTN:
- if (tp1->n.elem != tp2->n.elem)
- return 0;
- p1 = tp1->p.pars, p2 = tp2->p.pars;
- for (n = tp1->n.elem; n > 0; --n) {
- if (!eqtype(*p1++, *p2++, equiv))
- return 0;
- }
- goto check_base;
+ return eqfuns(tp1, tp2, equiv);
case ARY:
if (equiv && (tp1->n.elem == 0 || tp2->n.elem == 0))
goto check_base;