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
52static 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
63static 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
97static 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
151static 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
186static 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
250 if (LeftType == T_TYPE_FUNC) {
251 /* If a calling convention wasn't set explicitly,
252 ** then assume the default one.
253 */
254 if ((LeftQual & T_QUAL_CCONV) == T_QUAL_NONE) {
255 LeftQual |= (AutoCDecl || IsVariadicFunc (lhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
256 }
257 if ((RightQual & T_QUAL_CCONV) == T_QUAL_NONE) {
258 RightQual |= (AutoCDecl || IsVariadicFunc (rhs)) ? T_QUAL_CDECL : T_QUAL_FASTCALL;
259 }
260 }
261
262 if (LeftQual != RightQual) {
263 /* On the first indirection level, different qualifiers mean
264 ** that the types still are compatible. On the second level,
265 ** that is a (maybe minor) error. We create a special return-code
266 ** if a qualifier is dropped from a pointer. But, different calling
267 ** conventions are incompatible. Starting from the next level,
268 ** the types are incompatible if the qualifiers differ.
269 */
270 /* (Debugging statement) */
271 /* printf ("Ind = %d %06X != %06X\n", Indirections, LeftQual, RightQual); */
272 switch (Indirections) {
273 case 0:
274 SetResult (Result, TC_STRICT_COMPATIBLE);
275 break;
276
277 case 1:
278 /* A non-const value on the right is compatible to a
279 ** const one to the left, same for volatile.
280 */
281 if ((LeftQual & T_QUAL_CONST) < (RightQual & T_QUAL_CONST) ||
282 (LeftQual & T_QUAL_VOLATILE) < (RightQual & T_QUAL_VOLATILE)) {
283 SetResult (Result, TC_QUAL_DIFF);
284 } else {
285 SetResult (Result, TC_STRICT_COMPATIBLE);
286 }
287
288 if (LeftType != T_TYPE_FUNC || (LeftQual & T_QUAL_CCONV) == (RightQual & T_QUAL_CCONV)) {
289 break;
290 }
291 /* else fall through */
292
293 default:
294 SetResult (Result, TC_INCOMPATIBLE);
295 return;
296 }
297 }
298
299 /* Check for special type elements */
300 switch (LeftType) {
301 case T_TYPE_PTR:
302 ++Indirections;
303 break;
304
305 case T_TYPE_FUNC:
306 /* Compare the function descriptors */
307 F1 = GetFuncDesc (lhs);
308 F2 = GetFuncDesc (rhs);
309
310 /* If one of both functions has an empty parameter list (which
311 ** does also mean, it is not a function definition, because the
312 ** flag is reset in this case), it is considered equal to any
313 ** other definition, provided that the other has no default
314 ** promotions in the parameter list. If none of both parameter
315 ** lists is empty, we have to check the parameter lists and
316 ** other attributes.
317 */
318 if (F1->Flags & FD_EMPTY) {
319 if ((F2->Flags & FD_EMPTY) == 0) {
320 if (ParamsHaveDefaultPromotions (F2)) {
321 /* Flags differ */
322 SetResult (Result, TC_INCOMPATIBLE);
323 return;
324 }
325 }
326 } else if (F2->Flags & FD_EMPTY) {
327 if (ParamsHaveDefaultPromotions (F1)) {
328 /* Flags differ */
329 SetResult (Result, TC_INCOMPATIBLE);
330 return;
331 }
332 } else {
333
334 /* Check the remaining flags */
335 if ((F1->Flags & ~FD_IGNORE) != (F2->Flags & ~FD_IGNORE)) {
336 /* Flags differ */
337 SetResult (Result, TC_INCOMPATIBLE);
338 return;
339 }
340
341 /* Compare the parameter lists */
342 if (EqualFuncParams (F1, F2) == 0) {
343 /* Parameter list is not identical */
344 SetResult (Result, TC_INCOMPATIBLE);
345 return;
346 }
347 }
348
349 /* Keep on and compare the return type */
350 break;
351
352 case T_TYPE_ARRAY:
353 /* Check member count */
354 LeftCount = GetElementCount (lhs);
355 RightCount = GetElementCount (rhs);
356 if (LeftCount != UNSPECIFIED &&
357 RightCount != UNSPECIFIED &&
358 LeftCount != RightCount) {
359 /* Member count given but different */
360 SetResult (Result, TC_INCOMPATIBLE);
361 return;
362 }
363 break;
364
365 case T_TYPE_STRUCT:
366 case T_TYPE_UNION:
367 /* Compare the fields recursively. To do that, we fetch the
368 ** pointer to the struct definition from the type, and compare
369 ** the fields.
370 */
371 Sym1 = GetSymEntry (lhs);
372 Sym2 = GetSymEntry (rhs);
373
374 /* If one symbol has a name, the names must be identical */
375 if (!HasAnonName (Sym1) || !HasAnonName (Sym2)) {
376 if (strcmp (Sym1->Name, Sym2->Name) != 0) {
377 /* Names are not identical */
378 SetResult (Result, TC_INCOMPATIBLE);
379 return;
380 }
381 }
382
383 /* Get the field tables from the struct entry */
384 Tab1 = Sym1->V.S.SymTab;
385 Tab2 = Sym2->V.S.SymTab;
386
387 /* One or both structs may be forward definitions. In this case,
388 ** the symbol tables are both non existant. Assume that the
389 ** structs are equal in this case.
390 */
391 if (Tab1 != 0 && Tab2 != 0) {
392
393 if (EqualSymTables (Tab1, Tab2) == 0) {
394 /* Field lists are not equal */
395 SetResult (Result, TC_INCOMPATIBLE);
396 return;
397 }
398
399 }
400
401 /* Structs are equal */
402 break;
403 }
404
405 /* Next type string element */
406 ++lhs;
407 ++rhs;
408 ++ElementCount;
409 }
410
411 /* Check if end of rhs reached */
412 if (rhs->C == T_END) {
413 SetResult (Result, TC_EQUAL);
414 } else {
415 SetResult (Result, TC_INCOMPATIBLE);
416 }
417}
418
419
420
421typecmp_t TypeCmp (const Type* lhs, const Type* rhs)
422/* Compare two types and return the result */
423{
424 /* Assume the types are identical */
425 typecmp_t Result = TC_IDENTICAL;
426
427#if 0
428 printf ("Left : "); PrintRawType (stdout, lhs);
429 printf ("Right: "); PrintRawType (stdout, rhs);
430#endif
431
432 /* Recursively compare the types if they aren't identical */
433 if (rhs != lhs) {
434 DoCompare (lhs, rhs, &Result);
435 }
436
437 /* Return the result */
438 return Result;
439}
440