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 | |
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 | |
421 | typecmp_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 | |