Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / cemcom / l_misc.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 /* $Id: l_misc.c,v 3.8 1994/06/24 12:04:47 ceriel Exp $ */
6 /*      Lint miscellaneous routines     */
7
8 #include        "lint.h"
9
10 #ifdef  LINT
11
12 #include        <alloc.h>       /* for st_free */
13 #include        "interface.h"
14 #ifdef ANSI
15 #include        <flt_arith.h>
16 #endif /* ANSI */
17 #include        "arith.h"       /* definition arith */
18 #include        "label.h"       /* definition label */
19 #include        "expr.h"
20 #include        "idf.h"
21 #include        "def.h"
22 #include        "code.h"        /* RVAL etc */
23 #include        "LLlex.h"
24 #include        "Lpars.h"
25 #include        "stack.h"
26 #include        "type.h"
27 #include        "level.h"
28 #include        "l_state.h"
29
30 extern char *symbol2str();
31 extern struct type *func_type;
32
33 PRIVATE lint_enum_arith();
34 PRIVATE lint_conversion();
35 PRIVATE int numsize();
36
37 check_hiding(idf, lvl, sc)
38         struct idf *idf;
39         int lvl;
40         int sc;
41 {
42         /*      Checks if there is already a definition for this non-extern
43                 name on a more global level.
44         */
45         struct def *def = idf->id_def;
46         
47         if (    def && def->df_level < lvl
48         &&      ! (     lvl == L_FORMAL2
49                 ||      def->df_level == L_UNIVERSAL
50                 ||      sc == GLOBAL
51                 ||      sc == EXTERN
52                 )
53         ) {
54                 warning("%s is already defined as a %s",
55                         idf->id_text,
56                         def->df_level == L_GLOBAL ? "global" :
57                         def->df_level == L_FORMAL2 ? "formal" :
58                                 "more global local"
59                 );
60         }
61 }
62
63 lint_new_oper(expr)
64         struct expr *expr;
65 {
66         /*      Does additional checking on a newly constructed expr node
67                 of class Oper.
68
69                 Some code in this routine could be contracted, but since
70                 I am not sure we have covered the entire ground, we'll
71                 leave the contracting for some rainy day.
72         */
73         register struct expr *left = expr->OP_LEFT;
74         register struct expr *right = expr->OP_RIGHT;
75         register int oper = expr->OP_OPER;
76         register int l_fund =
77                 left == 0 ? 0 :                 /* for monadics */
78                 left->ex_type->tp_fund;
79         register int r_fund =
80                 right == 0 ? 0 :                /* for ( without parameters */
81                 right->ex_type->tp_fund;
82
83         /*      In ch7.c, in ch7asgn(), a combined operator/assignment
84                 is hammered into correctness by repeated application of
85                 ch7bin(), which calls new_oper(), which calls lint_new_oper().
86                 These spurious calls understandably cause spurious error
87                 messages, which we don't like.  So we try to suppress these
88                 wierd calls here.  This refers to the code marked
89                         this is really $#@&*%$# !
90                 in ch7asgn().
91         */
92         switch (oper) {
93         case PLUSAB:
94         case MINAB:
95         case TIMESAB:
96         case DIVAB:
97         case MODAB:
98         case LEFTAB:
99         case RIGHTAB:
100         case ANDAB:
101         case XORAB:
102         case ORAB:
103                 /* is the left operand wierd? */
104                 if (    left->ex_class == Value
105                 &&      left->VL_CLASS == Const
106                 &&      left->VL_VALUE == 0
107                 ) {
108                         return;
109                 }
110         }
111
112         switch (oper) {
113         case '=':
114                 lint_conversion(right, l_fund);
115                 break;
116
117         case PLUSAB:
118                 lint_conversion(right, l_fund);
119         case '+':
120                 lint_enum_arith(l_fund, oper, r_fund);
121                 break;
122
123         case MINAB:
124                 lint_conversion(right, l_fund);
125         case '-':
126                 if (left == 0) {
127                         /* unary */
128                         if (r_fund == ENUM)
129                                 warning("negating an enum");
130                 }
131                 else {
132                         /* binary */
133                         if (l_fund == ENUM && r_fund == ENUM) {
134                                 if (left->ex_type != right->ex_type)
135                                         warning("subtracting enums of different type");
136                                 /* update the type, cem does not do it */
137                                 expr->ex_type = int_type;
138                         }
139                         lint_enum_arith(l_fund, oper, r_fund);
140                 }
141                 break;
142
143         case TIMESAB:
144                 lint_conversion(right, l_fund);
145         case '*':
146                 if (left == 0) {
147                         /* unary */
148                 }
149                 else {
150                         /* binary */
151                         if (l_fund == ENUM || r_fund == ENUM)
152                                 warning("multiplying enum");
153                 }
154                 break;
155
156         case DIVAB:
157                 lint_conversion(right, l_fund);
158         case '/':
159                 if (l_fund == ENUM || r_fund == ENUM)
160                         warning("division on enum");
161                 break;
162
163         case MODAB:
164                 lint_conversion(right, l_fund);
165         case '%':
166                 if (l_fund == ENUM || r_fund == ENUM)
167                         warning("modulo on enum");
168                 break;
169
170         case '~':
171                 if (r_fund == ENUM || r_fund == FLOAT || r_fund == DOUBLE)
172                         warning("~ on %s", symbol2str(r_fund));
173                 break;
174
175         case '!':
176                 if (r_fund == ENUM)
177                         warning("! on enum");
178                 break;
179
180         case INT2INT:
181         case INT2FLOAT:
182         case FLOAT2INT:
183         case FLOAT2FLOAT:
184                 lint_conversion(right, l_fund);
185                 break;
186
187         case '<':
188         case '>':
189         case LESSEQ:
190         case GREATEREQ:
191         case EQUAL:
192         case NOTEQUAL:
193                 if (    (l_fund == ENUM || r_fund == ENUM)
194                 &&      left->ex_type != right->ex_type
195                 ) {
196                         warning("comparing enum with non-enum");
197                 }
198                 lint_relop(left, right, oper);
199                 lint_relop(right, left, 
200                         oper == '<' ? '>' :
201                         oper == '>' ? '<' :
202                         oper == LESSEQ ? GREATEREQ :
203                         oper == GREATEREQ ? LESSEQ :
204                         oper
205                 );
206                 break;
207
208         case LEFTAB:
209         case RIGHTAB:
210                 lint_conversion(right, l_fund);
211         case LEFT:
212         case RIGHT:
213                 if (l_fund == ENUM || r_fund == ENUM)
214                         warning("shift on enum");
215                 break;
216
217         case ANDAB:
218         case ORAB:
219         case XORAB:
220                 lint_conversion(right, l_fund);
221         case '&':
222         case '|':
223         case '^':
224                 if (l_fund == ENUM || r_fund == ENUM)
225                         warning("bit operations on enum");
226                 break;
227
228         case ',':
229         case '?':
230         case ':':
231         case AND:
232         case OR:
233         case POSTINCR:
234         case POSTDECR:
235         case PLUSPLUS:
236         case MINMIN:
237         case '(':
238         case '.':
239         case ARROW:
240         default:
241                 /* OK with lint */
242                 break;
243         }
244 }
245
246 PRIVATE
247 lint_enum_arith(l_fund, oper, r_fund)
248         int l_fund, oper, r_fund;
249 {
250         if (    l_fund == ENUM
251         &&      r_fund != CHAR
252         &&      r_fund != SHORT
253         &&      r_fund != INT
254         ) {
255                 warning("%s on enum and %s",
256                         symbol2str(oper), symbol2str(r_fund));
257         }
258         else
259         if (    r_fund == ENUM
260         &&      l_fund != CHAR
261         &&      l_fund != SHORT
262         &&      l_fund != INT
263         ) {
264                 warning("%s on %s and enum",
265                         symbol2str(oper), symbol2str(l_fund));
266         }
267 }
268
269 PRIVATE
270 lint_conversion(from_expr, to_fund)
271         struct expr *from_expr;
272         int to_fund;
273 {
274         register int from_fund = from_expr->ex_type->tp_fund;
275
276         /*      was there an attempt to reduce the type of the from_expr
277                 of the form
278                         expr & 0377
279                 or something like this?
280         */
281         if (from_expr->ex_class == Oper && from_expr->OP_OPER == INT2INT) {
282                 from_expr = from_expr->OP_LEFT;
283         }
284         if (from_expr->ex_class == Oper && from_expr->OP_OPER == '&') {
285                 struct expr *bits =
286                         is_cp_cst(from_expr->OP_LEFT) ? from_expr->OP_LEFT :
287                         is_cp_cst(from_expr->OP_RIGHT) ? from_expr->OP_RIGHT :
288                         0;
289
290                 if (bits) {
291                         arith val = bits->VL_VALUE;
292
293                         if (val < 256)
294                                 from_fund = CHAR;
295                         else if (val < 256)
296                                 from_fund = SHORT;
297                 }
298         }
299         if (numsize(from_fund) > numsize(to_fund)) {
300                 awarning("conversion from %s to %s may lose accuracy",
301                         symbol2str(from_fund), symbol2str(to_fund));
302         }
303 }
304
305 PRIVATE int
306 numsize(fund)
307 {
308         switch (fund) {
309         case CHAR:      return 1;
310         case SHORT:     return 2;
311         case INT:       return 3;
312         case ENUM:      return 3;
313         case LONG:      return 4;
314         case FLOAT:     return 5;
315         case DOUBLE:    return 6;
316         default:        return 0;
317         }
318 }
319
320 lint_ret_conv(from_expr)
321         struct expr *from_expr;
322 {
323         lint_conversion(from_expr, func_type->tp_fund);
324 }
325
326 lint_ptr_conv(from, to)
327         short from, to;
328 {
329 /* X -> X ok                    -- this includes struct -> struct, of any size
330  * X -> CHAR ok
331  * DOUBLE -> X ok
332  * FLOAT -> LONG -> INT -> SHORT  ok
333  */
334         if (from == to)
335                 return;
336
337         if (to == CHAR)
338                 return;
339
340         if (from == DOUBLE)
341                 return;
342
343         switch (from) {
344         case FLOAT:
345                 switch (to) {
346                 case LONG:
347                 case INT:
348                 case SHORT:
349                         return;
350                 }
351                 break;
352         case LONG:
353                 switch (to) {
354                 case INT:
355                 case SHORT:
356                         return;
357                 }
358                 break;
359         case INT:
360                 switch (to) {
361                 case SHORT:
362                         return;
363                 }
364                 break;
365         }
366
367         if (from == VOID) {
368                 /* OK any which way */
369         }
370         else
371         if (from == CHAR) {
372                 hwarning("pointer to char may not align correctly for a %s",
373                         symbol2str(to));
374         }
375         else {
376                 warning("pointer to %s may not align correctly for a %s",
377                         symbol2str(from), symbol2str(to));
378         }
379 }
380
381 lint_relop(left, right, oper)
382         struct expr *left, *right;
383         int oper;       /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
384 {
385         /* left operand may be converted */
386         if (    left->ex_class == Oper
387         &&      left->OP_OPER == INT2INT
388         ) {
389                 left = left->OP_RIGHT;
390         }
391
392         /* <unsigned> <relop> <neg-const|0> is doubtful */
393         if (    left->ex_type->tp_unsigned
394         &&      right->ex_class == Value
395         &&      right->VL_CLASS == Const
396         ) {
397                 if (!right->ex_type->tp_unsigned && right->VL_VALUE < 0) {
398                         warning("unsigned compared to negative constant");
399                 }
400                 if (right->VL_VALUE == 0) {
401                         switch (oper) {
402                         case '<':
403                                 warning("unsigned < 0 will always fail");
404                                 break;
405
406                         case LESSEQ:
407                                 warning("unsigned <= 0 is probably wrong");
408                                 break;
409
410                         case GREATEREQ:
411                                 warning("unsigned >= 0 will always succeed");
412                                 break;
413                         }
414                 }
415         }
416
417         /* <char> <relop> <neg-const> is undefined */
418         if (    left->ex_type->tp_fund == CHAR
419         &&      right->ex_class == Value
420         &&      right->VL_CLASS == Const
421         &&      (right->VL_VALUE < 0 || right->VL_VALUE > 127)
422         ) {
423                 warning("character compared to negative constant");
424         }
425 }
426
427 #endif  /* LINT */