]> git.sur5r.net Git - cc65/blob - src/cc65/typeconv.c
cf3c9a3ef4bbb1b8f7a21bc6bd5c47384f8c56f8
[cc65] / src / cc65 / typeconv.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                typeconv.c                                 */
4 /*                                                                           */
5 /*                          Handle type conversions                          */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2002-2004 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 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 /* common */
37 #include "shift.h"
38
39 /* cc65 */
40 #include "codegen.h"
41 #include "datatype.h"
42 #include "declare.h"
43 #include "error.h"
44 #include "expr.h"
45 #include "loadexpr.h"
46 #include "scanner.h"
47 #include "typecmp.h"
48 #include "typeconv.h"
49
50
51
52 /*****************************************************************************/
53 /*                                   Code                                    */
54 /*****************************************************************************/
55
56
57
58 static void DoPtrConversions (ExprDesc* Expr)
59 /* If the expression is a function, convert it to pointer to function.
60  * If the expression is an array, convert it to pointer to first element.
61  */
62 {
63     if (IsTypeFunc (Expr->Type)) {
64         Expr->Type = PointerTo (Expr->Type);
65     } else if (IsTypeArray (Expr->Type)) {
66         Expr->Type = ArrayToPtr (Expr->Type);
67     }
68 }
69
70
71
72 static void DoConversion (ExprDesc* Expr, const type* NewType)
73 /* Emit code to convert the given expression to a new type. */
74 {
75     type*    OldType;
76     unsigned OldSize;
77     unsigned NewSize;
78
79
80     /* Remember the old type */
81     OldType = Expr->Type;
82
83     /* If we're converting to void, we're done. Note: This does also cover a
84      * conversion void -> void.
85      */
86     if (IsTypeVoid (NewType)) {
87         ED_MakeRVal (Expr);     /* Never an lvalue */
88         goto ExitPoint;
89     }
90
91     /* Don't allow casts from void to something else. */
92     if (IsTypeVoid (OldType)) {
93         Error ("Cannot convert from `void' to something else");
94         goto ExitPoint;
95     }
96
97     /* Get the sizes of the types. Since we've excluded void types, checking
98      * for known sizes makes sense here.
99      */
100     OldSize = CheckedSizeOf (OldType);
101     NewSize = CheckedSizeOf (NewType);
102
103     /* lvalue? */
104     if (ED_IsLVal (Expr)) {
105
106         /* We have an lvalue. If the new size is smaller than the new one,
107          * we don't need to do anything. The compiler will generate code
108          * to load only the portion of the value that is actually needed.
109          * This works only on a little endian architecture, but that's
110          * what we support.
111          * If both sizes are equal, do also leave the value alone.
112          * If the new size is larger, we must convert the value.
113          */
114         if (NewSize > OldSize) {
115             /* Load the value into the primary */
116             LoadExpr (CF_NONE, Expr);
117
118             /* Emit typecast code */
119             g_typecast (TypeOf (NewType), TypeOf (OldType));
120
121             /* Value is now in primary and an rvalue */
122             ED_MakeRValExpr (Expr);
123         }
124
125     } else if (ED_IsLocAbs (Expr)) {
126
127         /* A cast of a constant numeric value to another type. Be sure
128          * to handle sign extension correctly.
129          */
130
131         /* Get the current and new size of the value */
132         unsigned OldBits = OldSize * 8;
133         unsigned NewBits = NewSize * 8;
134
135         /* Check if the new datatype will have a smaller range. If it
136          * has a larger range, things are ok, since the value is
137          * internally already represented by a long.
138          */
139         if (NewBits <= OldBits) {
140
141             /* Cut the value to the new size */
142             Expr->IVal &= (0xFFFFFFFFUL >> (32 - NewBits));
143
144             /* If the new type is signed, sign extend the value */
145             if (!IsSignUnsigned (NewType)) {
146                 if (Expr->IVal & (0x01UL << (NewBits-1))) {
147                     /* Beware: Use the safe shift routine here. */
148                     Expr->IVal |= shl_l (~0UL, NewBits);
149                 }
150             }
151         }
152
153     } else {
154
155         /* The value is not a constant. If the sizes of the types are
156          * not equal, add conversion code. Be sure to convert chars
157          * correctly.
158          */
159         if (OldSize != NewSize) {
160
161             /* Load the value into the primary */
162             LoadExpr (CF_NONE, Expr);
163
164             /* Emit typecast code. */
165             g_typecast (TypeOf (NewType) | CF_FORCECHAR, TypeOf (OldType));
166
167             /* Value is now a rvalue in the primary */
168             ED_MakeRValExpr (Expr);
169         }
170     }
171
172 ExitPoint:
173     /* The expression has always the new type */
174     ReplaceType (Expr, NewType);
175 }
176
177
178
179 void TypeConversion (ExprDesc* Expr, type* NewType)
180 /* Do an automatic conversion of the given expression to the new type. Output
181  * warnings or errors where this automatic conversion is suspicious or
182  * impossible.
183  */
184 {
185     /* Get the type of the right hand side. Treat function types as
186      * pointer-to-function
187      */
188     DoPtrConversions (Expr);
189
190     /* First, do some type checking */
191     if (IsTypeVoid (NewType) || IsTypeVoid (Expr->Type)) {
192         /* If one of the sides are of type void, output a more apropriate
193          * error message.
194          */
195         Error ("Illegal type");
196     }
197
198     /* If both types are equal, no conversion is needed */
199     if (TypeCmp (Expr->Type, NewType) >= TC_EQUAL) {
200         /* We're already done */
201         return;
202     }
203
204     /* Check for conversion problems */
205     if (IsClassInt (NewType)) {
206
207         /* Handle conversions to int type */
208         if (IsClassPtr (Expr->Type)) {
209             /* Pointer -> int conversion */
210             Warning ("Converting pointer to integer without a cast");
211         } else if (!IsClassInt (Expr->Type) && !IsClassFloat (Expr->Type)) {
212             Error ("Incompatible types");
213         }
214
215     } else if (IsClassFloat (NewType)) {
216
217         if (!IsClassFloat (Expr->Type) && !IsClassInt (Expr->Type)) {
218             Error ("Incompatible types");
219         }
220
221     } else if (IsClassPtr (NewType)) {
222
223         /* Handle conversions to pointer type */
224         if (IsClassPtr (Expr->Type)) {
225             /* Pointer to pointer assignment is valid, if:
226              *   - both point to the same types, or
227              *   - the rhs pointer is a void pointer, or
228              *   - the lhs pointer is a void pointer.
229              */
230             if (!IsTypeVoid (Indirect (NewType)) && !IsTypeVoid (Indirect (Expr->Type))) {
231                 /* Compare the types */
232                 switch (TypeCmp (NewType, Expr->Type)) {
233
234                     case TC_INCOMPATIBLE:
235                         Error ("Incompatible pointer types");
236                         break;
237
238                     case TC_QUAL_DIFF:
239                         Error ("Pointer types differ in type qualifiers");
240                         break;
241
242                     default:
243                         /* Ok */
244                         break;
245                 }
246             }
247         } else if (IsClassInt (Expr->Type)) {
248             /* Int to pointer assignment is valid only for constant zero */
249             if (!ED_IsConstAbsInt (Expr) || Expr->IVal != 0) {
250                 Warning ("Converting integer to pointer without a cast");
251             }
252         } else if (IsTypeFuncPtr (NewType) && IsTypeFunc(Expr->Type)) {
253             /* Assignment of function to function pointer is allowed, provided
254              * that both functions have the same parameter list.
255              */
256             if (TypeCmp (Indirect (NewType), Expr->Type) < TC_EQUAL) {
257                 Error ("Incompatible types");
258             }
259         } else {
260             Error ("Incompatible types");
261         }
262
263     } else {
264
265         /* Invalid automatic conversion */
266         Error ("Incompatible types");
267
268     }
269
270     /* Do the actual conversion */
271     DoConversion (Expr, NewType);
272 }
273
274
275
276 void TypeCast (ExprDesc* Expr)
277 /* Handle an explicit cast. The function returns true if the resulting
278  * expression is an lvalue and false if not.
279  */
280 {
281     type    NewType[MAXTYPELEN];
282
283     /* Skip the left paren */
284     NextToken ();
285
286     /* Read the type */
287     ParseType (NewType);
288
289     /* Closing paren */
290     ConsumeRParen ();
291
292     /* Read the expression we have to cast */
293     hie10 (Expr);
294
295     /* Convert functions and arrays to "pointer to" object */
296     DoPtrConversions (Expr);
297
298     /* Convert the value. */
299     DoConversion (Expr, NewType);
300 }
301
302
303
304