]> git.sur5r.net Git - cc65/blob - src/cc65/typecmp.c
8025f4efeaa972883a9f09bcd90a055cb934116a
[cc65] / src / cc65 / typecmp.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 typecmp.c                                 */
4 /*                                                                           */
5 /*               Type compare function for the cc65 C compiler               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2015, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37
38 /* cc65 */
39 #include "funcdesc.h"
40 #include "global.h"
41 #include "symtab.h"
42 #include "typecmp.h"
43
44
45
46 /*****************************************************************************/
47 /*                                   Code                                    */
48 /*****************************************************************************/
49
50
51
52 static void SetResult (typecmp_t* Result, typecmp_t Val)
53 /* Set a new result value if it is less than the existing one */
54 {
55     if (Val < *Result) {
56         /* printf ("SetResult = %d\n", Val); */
57         *Result = Val;
58     }
59 }
60
61
62
63 static int ParamsHaveDefaultPromotions (const FuncDesc* F)
64 /* Check if any of the parameters of function F has a default promotion. In
65 ** this case, the function is not compatible with an empty parameter name list
66 ** declaration.
67 */
68 {
69     /* Get the symbol table */
70     const SymTable* Tab = F->SymTab;
71
72     /* Get the first parameter in the list */
73     const SymEntry* Sym = Tab->SymHead;
74
75     /* Walk over all parameters */
76     while (Sym && (Sym->Flags & SC_PARAM)) {
77
78         /* If this is an integer type, check if the promoted type is equal
79         ** to the original type. If not, we have a default promotion.
80         */
81         if (IsClassInt (Sym->Type)) {
82             if (IntPromotion (Sym->Type) != Sym->Type) {
83                 return 1;
84             }
85         }
86
87         /* Get the pointer to the next param */
88         Sym = Sym->NextSym;
89     }
90
91     /* No default promotions in the parameter list */
92     return 0;
93 }
94
95
96
97 static int EqualFuncParams (const FuncDesc* F1, const FuncDesc* F2)
98 /* Compare two function symbol tables regarding function parameters. Return 1
99 ** if they are equal and 0 otherwise.
100 */
101 {
102     /* Get the symbol tables */
103     const SymTable* Tab1 = F1->SymTab;
104     const SymTable* Tab2 = F2->SymTab;
105
106     /* Compare the parameter lists */
107     const SymEntry* Sym1 = Tab1->SymHead;
108     const SymEntry* Sym2 = Tab2->SymHead;
109
110     /* Compare the fields */
111     while (Sym1 && (Sym1->Flags & SC_PARAM) && Sym2 && (Sym2->Flags & SC_PARAM)) {
112
113         /* Get the symbol types */
114         Type* Type1 = Sym1->Type;
115         Type* Type2 = Sym2->Type;
116
117         /* If either of both functions is old style, apply the default
118         ** promotions to the parameter type.
119         */
120         if (F1->Flags & FD_OLDSTYLE) {
121             if (IsClassInt (Type1)) {
122                 Type1 = IntPromotion (Type1);
123             }
124         }
125         if (F2->Flags & FD_OLDSTYLE) {
126             if (IsClassInt (Type2)) {
127                 Type2 = IntPromotion (Type2);
128             }
129         }
130
131         /* Compare this field */
132         if (TypeCmp (Type1, Type2) < TC_EQUAL) {
133             /* Field types not equal */
134             return 0;
135         }
136
137         /* Get the pointers to the next fields */
138         Sym1 = Sym1->NextSym;
139         Sym2 = Sym2->NextSym;
140     }
141
142     /* Check both pointers against NULL or a non parameter to compare the
143     ** field count
144     */
145     return (Sym1 == 0 || (Sym1->Flags & SC_PARAM) == 0) &&
146            (Sym2 == 0 || (Sym2->Flags & SC_PARAM) == 0);
147 }
148
149
150
151 static int EqualSymTables (SymTable* Tab1, SymTable* Tab2)
152 /* Compare two symbol tables. Return 1 if they are equal and 0 otherwise */
153 {
154     /* Compare the parameter lists */
155     SymEntry* Sym1 = Tab1->SymHead;
156     SymEntry* Sym2 = Tab2->SymHead;
157
158     /* Compare the fields */
159     while (Sym1 && Sym2) {
160
161         /* Compare the names of this field */
162         if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
163             if (strcmp (Sym1->Name, Sym2->Name) != 0) {
164                 /* Names are not identical */
165                 return 0;
166             }
167         }
168
169         /* Compare the types of this field */
170         if (TypeCmp (Sym1->Type, Sym2->Type) < TC_EQUAL) {
171             /* Field types not equal */
172             return 0;
173         }
174
175         /* Get the pointers to the next fields */
176         Sym1 = Sym1->NextSym;
177         Sym2 = Sym2->NextSym;
178     }
179
180     /* Check both pointers against NULL to compare the field count */
181     return (Sym1 == 0 && Sym2 == 0);
182 }
183
184
185
186 static void DoCompare (const Type* lhs, const Type* rhs, typecmp_t* Result)
187 /* Recursively compare two types. */
188 {
189     unsigned    Indirections;
190     unsigned    ElementCount;
191     SymEntry*   Sym1;
192     SymEntry*   Sym2;
193     SymTable*   Tab1;
194     SymTable*   Tab2;
195     FuncDesc*   F1;
196     FuncDesc*   F2;
197
198
199     /* Initialize stuff */
200     Indirections = 0;
201     ElementCount = 0;
202
203     /* Compare two types. Determine, where they differ */
204     while (lhs->C != T_END) {
205
206         TypeCode LeftType, RightType;
207         TypeCode LeftSign, RightSign;
208         TypeCode LeftQual, RightQual;
209         long LeftCount, RightCount;
210
211         /* Check if the end of the type string is reached */
212         if (rhs->C == T_END) {
213             /* End of comparison reached */
214             return;
215         }
216
217         /* Get the raw left and right types, signs and qualifiers */
218         LeftType  = GetType (lhs);
219         RightType = GetType (rhs);
220         LeftSign  = GetSignedness (lhs);
221         RightSign = GetSignedness (rhs);
222         LeftQual  = GetQualifier (lhs);
223         RightQual = GetQualifier (rhs);
224
225         /* If the left type is a pointer and the right is an array, both
226         ** are compatible.
227         */
228         if (LeftType == T_TYPE_PTR && RightType == T_TYPE_ARRAY) {
229             RightType = T_TYPE_PTR;
230         }
231
232         /* If the raw types are not identical, the types are incompatible */
233         if (LeftType != RightType) {
234             SetResult (Result, TC_INCOMPATIBLE);
235             return;
236         }
237
238         /* On indirection level zero, a qualifier or sign difference is
239         ** accepted. The types are no longer equal, but compatible.
240         */
241         if (LeftSign != RightSign) {
242             if (ElementCount == 0) {
243                 SetResult (Result, TC_SIGN_DIFF);
244             } else {
245                 SetResult (Result, TC_INCOMPATIBLE);
246                 return;
247             }
248         }
249         if (LeftQual != RightQual) {
250             /* On the first indirection level, different qualifiers mean
251             ** that the types still are compatible. On the second level,
252             ** that is a (maybe minor) error. We create a special return-code
253             ** if a qualifier is dropped from a pointer. But, different calling
254             ** conventions are incompatible. Starting from the next level,
255             ** the types are incompatible if the qualifiers differ.
256             */
257             /* (Debugging statement) */
258             /* printf ("Ind = %d    %06X != %06X\n", Indirections, LeftQual, RightQual); */
259             switch (Indirections) {
260                 case 0:
261                     SetResult (Result, TC_STRICT_COMPATIBLE);
262                     break;
263
264                 case 1:
265                     /* A non-const value on the right is compatible to a
266                     ** const one to the left, same for volatile.
267                     */
268                     if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
269                         (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
270                         SetResult (Result, TC_QUAL_DIFF);
271                     } else {
272                         SetResult (Result, TC_STRICT_COMPATIBLE);
273                     }
274
275                     if (LeftType != T_TYPE_FUNC) {
276                         break;
277                     }
278
279                     /* If a calling convention wasn't set explicitly,
280                     ** then assume the default one.
281                     */
282                     LeftQual &= T_QUAL_CCONV;
283                     if (LeftQual == T_QUAL_NONE) {
284                         LeftQual = (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
285                     }
286                     RightQual &= T_QUAL_CCONV;
287                     if (RightQual == T_QUAL_NONE) {
288                         RightQual = (AutoCDecl || IsVariadicFunc (rhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
289                     }
290
291                     if (LeftQual == RightQual) {
292                         break;
293                     }
294                     /* else fall through */
295
296                 default:
297                     SetResult (Result, TC_INCOMPATIBLE);
298                     return;
299             }
300         }
301
302         /* Check for special type elements */
303         switch (LeftType) {
304             case T_TYPE_PTR:
305                 ++Indirections;
306                 break;
307
308             case T_TYPE_FUNC:
309                 /* Compare the function descriptors */
310                 F1 = GetFuncDesc (lhs);
311                 F2 = GetFuncDesc (rhs);
312
313                 /* If one of both functions has an empty parameter list (which
314                 ** does also mean, it is not a function definition, because the
315                 ** flag is reset in this case), it is considered equal to any
316                 ** other definition, provided that the other has no default
317                 ** promotions in the parameter list. If none of both parameter
318                 ** lists is empty, we have to check the parameter lists and
319                 ** other attributes.
320                 */
321                 if (F1->Flags & FD_EMPTY) {
322                     if ((F2->Flags & FD_EMPTY) == 0) {
323                         if (ParamsHaveDefaultPromotions (F2)) {
324                             /* Flags differ */
325                             SetResult (Result, TC_INCOMPATIBLE);
326                             return;
327                         }
328                     }
329                 } else if (F2->Flags & FD_EMPTY) {
330                     if (ParamsHaveDefaultPromotions (F1)) {
331                         /* Flags differ */
332                         SetResult (Result, TC_INCOMPATIBLE);
333                         return;
334                     }
335                 } else {
336
337                     /* Check the remaining flags */
338                     if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) {
339                         /* Flags differ */
340                         SetResult (Result, TC_INCOMPATIBLE);
341                         return;
342                     }
343
344                     /* Compare the parameter lists */
345                     if (EqualFuncParams (F1, F2) == 0) {
346                         /* Parameter list is not identical */
347                         SetResult (Result, TC_INCOMPATIBLE);
348                         return;
349                     }
350                 }
351
352                 /* Keep on and compare the return type */
353                 break;
354
355             case T_TYPE_ARRAY:
356                 /* Check member count */
357                 LeftCount  = GetElementCount (lhs);
358                 RightCount = GetElementCount (rhs);
359                 if (LeftCount  != UNSPECIFIED &&
360                     RightCount != UNSPECIFIED &&
361                     LeftCount  != RightCount) {
362                     /* Member count given but different */
363                     SetResult (Result, TC_INCOMPATIBLE);
364                     return;
365                 }
366                 break;
367
368             case T_TYPE_STRUCT:
369             case T_TYPE_UNION:
370                 /* Compare the fields recursively. To do that, we fetch the
371                 ** pointer to the struct definition from the type, and compare
372                 ** the fields.
373                 */
374                 Sym1 = GetSymEntry (lhs);
375                 Sym2 = GetSymEntry (rhs);
376
377                 /* If one symbol has a name, the names must be identical */
378                 if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
379                     if (strcmp (Sym1->Name, Sym2->Name) != 0) {
380                         /* Names are not identical */
381                         SetResult (Result, TC_INCOMPATIBLE);
382                         return;
383                     }
384                 }
385
386                 /* Get the field tables from the struct entry */
387                 Tab1 = Sym1->V.S.SymTab;
388                 Tab2 = Sym2->V.S.SymTab;
389
390                 /* One or both structs may be forward definitions. In this case,
391                 ** the symbol tables are both non existant. Assume that the
392                 ** structs are equal in this case.
393                 */
394                 if (Tab1 != 0 && Tab2 != 0) {
395
396                     if (EqualSymTables (Tab1, Tab2) == 0) {
397                         /* Field lists are not equal */
398                         SetResult (Result, TC_INCOMPATIBLE);
399                         return;
400                     }
401
402                 }
403
404                 /* Structs are equal */
405                 break;
406         }
407
408         /* Next type string element */
409         ++lhs;
410         ++rhs;
411         ++ElementCount;
412     }
413
414     /* Check if end of rhs reached */
415     if (rhs->C == T_END) {
416         SetResult (Result, TC_EQUAL);
417     } else {
418         SetResult (Result, TC_INCOMPATIBLE);
419     }
420 }
421
422
423
424 typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
425 /* Compare two types and return the result */
426 {
427     /* Assume the types are identical */
428     typecmp_t   Result = TC_IDENTICAL;
429
430 #if 0
431     printf ("Left : "); PrintRawType (stdout, lhs);
432     printf ("Right: "); PrintRawType (stdout, rhs);
433 #endif
434
435     /* Recursively compare the types if they aren't identical */
436     if (rhs != lhs) {
437         DoCompare (lhs, rhs, &Result);
438     }
439
440     /* Return the result */
441     return Result;
442 }