fix crash when mode attribut misses arguments
[cparser] / attribute.c
1 /*
2  * This file is part of cparser.
3  * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18  * 02111-1307, USA.
19  */
20 #include <config.h>
21
22 #include <assert.h>
23 #include "diagnostic.h"
24 #include "warning.h"
25 #include "attribute_t.h"
26 #include "symbol_t.h"
27 #include "adt/error.h"
28 #include "type_t.h"
29
30 static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
31         [ATTRIBUTE_GNU_CONST]                  = "const",
32         [ATTRIBUTE_GNU_VOLATILE]               = "volatile",
33         [ATTRIBUTE_GNU_CDECL]                  = "cdecl",
34         [ATTRIBUTE_GNU_STDCALL]                = "stdcall",
35         [ATTRIBUTE_GNU_FASTCALL]               = "fastcall",
36         [ATTRIBUTE_GNU_DEPRECATED]             = "deprecated",
37         [ATTRIBUTE_GNU_NOINLINE]               = "noinline",
38         [ATTRIBUTE_GNU_RETURNS_TWICE]          = "returns_twice",
39         [ATTRIBUTE_GNU_NORETURN]               = "noreturn",
40         [ATTRIBUTE_GNU_NAKED]                  = "naked",
41         [ATTRIBUTE_GNU_PURE]                   = "pure",
42         [ATTRIBUTE_GNU_ALWAYS_INLINE]          = "always_inline",
43         [ATTRIBUTE_GNU_MALLOC]                 = "malloc",
44         [ATTRIBUTE_GNU_WEAK]                   = "weak",
45         [ATTRIBUTE_GNU_CONSTRUCTOR]            = "constructor",
46         [ATTRIBUTE_GNU_DESTRUCTOR]             = "destructor",
47         [ATTRIBUTE_GNU_NOTHROW]                = "nothrow",
48         [ATTRIBUTE_GNU_TRANSPARENT_UNION]      = "transparent_union",
49         [ATTRIBUTE_GNU_COMMON]                 = "common",
50         [ATTRIBUTE_GNU_NOCOMMON]               = "nocommon",
51         [ATTRIBUTE_GNU_PACKED]                 = "packed",
52         [ATTRIBUTE_GNU_SHARED]                 = "shared",
53         [ATTRIBUTE_GNU_NOTSHARED]              = "notshared",
54         [ATTRIBUTE_GNU_USED]                   = "used",
55         [ATTRIBUTE_GNU_UNUSED]                 = "unused",
56         [ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
57         [ATTRIBUTE_GNU_WARN_UNUSED_RESULT]     = "warn_unused_result",
58         [ATTRIBUTE_GNU_LONGCALL]               = "longcall",
59         [ATTRIBUTE_GNU_SHORTCALL]              = "shortcall",
60         [ATTRIBUTE_GNU_LONG_CALL]              = "long_call",
61         [ATTRIBUTE_GNU_SHORT_CALL]             = "short_call",
62         [ATTRIBUTE_GNU_FUNCTION_VECTOR]        = "function_vector",
63         [ATTRIBUTE_GNU_INTERRUPT]              = "interrupt",
64         [ATTRIBUTE_GNU_INTERRUPT_HANDLER]      = "interrupt_handler",
65         [ATTRIBUTE_GNU_NMI_HANDLER]            = "nmi_handler",
66         [ATTRIBUTE_GNU_NESTING]                = "nesting",
67         [ATTRIBUTE_GNU_NEAR]                   = "near",
68         [ATTRIBUTE_GNU_FAR]                    = "far",
69         [ATTRIBUTE_GNU_SIGNAL]                 = "signal",
70         [ATTRIBUTE_GNU_EIGTHBIT_DATA]          = "eightbit_data",
71         [ATTRIBUTE_GNU_TINY_DATA]              = "tiny_data",
72         [ATTRIBUTE_GNU_SAVEALL]                = "saveall",
73         [ATTRIBUTE_GNU_FLATTEN]                = "flatten",
74         [ATTRIBUTE_GNU_SSEREGPARM]             = "sseregparm",
75         [ATTRIBUTE_GNU_EXTERNALLY_VISIBLE]     = "externally_visible",
76         [ATTRIBUTE_GNU_MAY_ALIAS]              = "may_alias",
77         [ATTRIBUTE_GNU_MS_STRUCT]              = "ms_struct",
78         [ATTRIBUTE_GNU_GCC_STRUCT]             = "gcc_struct",
79         [ATTRIBUTE_GNU_DLLIMPORT]              = "dllimport",
80         [ATTRIBUTE_GNU_DLLEXPORT]              = "dllexport",
81         [ATTRIBUTE_GNU_ALIGNED]                = "aligned",
82         [ATTRIBUTE_GNU_ALIAS]                  = "alias",
83         [ATTRIBUTE_GNU_SECTION]                = "section",
84         [ATTRIBUTE_GNU_FORMAT]                 = "format",
85         [ATTRIBUTE_GNU_FORMAT_ARG]             = "format_arg",
86         [ATTRIBUTE_GNU_WEAKREF]                = "weakref",
87         [ATTRIBUTE_GNU_NONNULL]                = "nonnull",
88         [ATTRIBUTE_GNU_TLS_MODEL]              = "tls_model",
89         [ATTRIBUTE_GNU_VISIBILITY]             = "visibility",
90         [ATTRIBUTE_GNU_REGPARM]                = "regparm",
91         [ATTRIBUTE_GNU_MODE]                   = "mode",
92         [ATTRIBUTE_GNU_MODEL]                  = "model",
93         [ATTRIBUTE_GNU_TRAP_EXIT]              = "trap_exit",
94         [ATTRIBUTE_GNU_SP_SWITCH]              = "sp_switch",
95         [ATTRIBUTE_GNU_SENTINEL]               = "sentinel",
96
97         [ATTRIBUTE_MS_ALIGN]                   = "align",
98         [ATTRIBUTE_MS_ALLOCATE]                = "allocate",
99         [ATTRIBUTE_MS_DLLIMPORT]               = "dllimport",
100         [ATTRIBUTE_MS_DLLEXPORT]               = "dllexport",
101         [ATTRIBUTE_MS_NAKED]                   = "naked",
102         [ATTRIBUTE_MS_NOINLINE]                = "noinline",
103         [ATTRIBUTE_MS_RETURNS_TWICE]           = "returns_twice",
104         [ATTRIBUTE_MS_NORETURN]                = "noreturn",
105         [ATTRIBUTE_MS_NOTHROW]                 = "nothrow",
106         [ATTRIBUTE_MS_NOVTABLE]                = "novtable",
107         [ATTRIBUTE_MS_PROPERTY]                = "property",
108         [ATTRIBUTE_MS_SELECTANY]               = "selectany",
109         [ATTRIBUTE_MS_THREAD]                  = "thread",
110         [ATTRIBUTE_MS_UUID]                    = "uuid",
111         [ATTRIBUTE_MS_DEPRECATED]              = "deprecated",
112         [ATTRIBUTE_MS_RESTRICT]                = "restrict",
113         [ATTRIBUTE_MS_NOALIAS]                 = "noalias",
114 };
115
116 const char *get_attribute_name(attribute_kind_t kind)
117 {
118         assert(kind <= ATTRIBUTE_LAST);
119         return attribute_names[kind];
120 }
121
122 /**
123  * compare two string, ignoring double underscores on the second.
124  */
125 static int strcmp_underscore(const char *s1, const char *s2)
126 {
127         if (s2[0] == '_' && s2[1] == '_') {
128                 size_t len2 = strlen(s2);
129                 size_t len1 = strlen(s1);
130                 if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
131                         return strncmp(s1, s2+2, len2-4);
132                 }
133         }
134
135         return strcmp(s1, s2);
136 }
137
138 type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type)
139 {
140         type_t *type = skip_typeref(orig_type);
141
142         /* at least: byte, word, pointer, list of machine modes
143          * __XXX___ is interpreted as XXX */
144
145         /* This isn't really correct, the backend should provide a list of machine
146          * specific modes (according to gcc philosophy that is...) */
147         attribute_argument_t *arg = attribute->a.arguments;
148         if (arg == NULL) {
149                 errorf(&attribute->source_position,
150                        "__attribute__((mode(X))) misses argument");
151                 return orig_type;
152         }
153
154         const char         *symbol_str = arg->v.symbol->string;
155         bool                sign       = is_type_signed(type);
156         atomic_type_kind_t  akind;
157         if (strcmp_underscore("QI",   symbol_str) == 0 ||
158             strcmp_underscore("byte", symbol_str) == 0) {
159                 akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
160         } else if (strcmp_underscore("HI", symbol_str) == 0) {
161                 akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
162         } else if (strcmp_underscore("SI",      symbol_str) == 0
163                 || strcmp_underscore("word",    symbol_str) == 0
164                 || strcmp_underscore("pointer", symbol_str) == 0) {
165                 akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
166         } else if (strcmp_underscore("DI", symbol_str) == 0) {
167                 akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
168         } else {
169                 if (warning.other)
170                         warningf(&attribute->source_position, "ignoring unknown mode '%s'",
171                                  symbol_str);
172                 return orig_type;
173         }
174
175         if (type->kind == TYPE_ATOMIC) {
176                 type_t *copy       = duplicate_type(type);
177                 copy->atomic.akind = akind;
178                 return identify_new_type(copy);
179         } else if (type->kind == TYPE_ENUM) {
180                 type_t *copy      = duplicate_type(type);
181                 copy->enumt.akind = akind;
182                 return identify_new_type(copy);
183         } else if (is_type_pointer(type)) {
184                 warningf(&attribute->source_position,
185                          "__attribute__((mode)) on pointers not implemented yet (ignored)");
186                 return type;
187         }
188
189         errorf(&attribute->source_position,
190                "__attribute__((mode)) only allowed on integer, enum or pointer type");
191         return orig_type;
192 }
193
194 static inline bool is_po2(unsigned x)
195 {
196         return (x & (x-1)) == 0;
197 }
198
199 static void handle_attribute_aligned(const attribute_t *attribute,
200                                      entity_t *entity)
201 {
202         int alignment = 32; /* TODO: fill in maximum useful alignment for
203                                                    target machine */
204         if (attribute->a.arguments) {
205                 attribute_argument_t *argument = attribute->a.arguments;
206                 alignment = fold_constant_to_int(argument->v.expression);
207         }
208
209         if (!is_po2(alignment)) {
210                 errorf(&attribute->source_position,
211                            "alignment must be a power of 2 but is %d\n",
212                            alignment);
213                 return;
214         }
215         if (alignment <= 0) {
216                 errorf(&attribute->source_position,
217                            "alignment must be bigger than 0 but is %d\n",
218                            alignment);
219                 return;
220         }
221
222         switch (entity->kind) {
223         DECLARATION_KIND_CASES
224                 entity->declaration.alignment = alignment;
225         case ENTITY_TYPEDEF:
226                 entity->typedefe.alignment = alignment;
227                 break;
228         case ENTITY_STRUCT:
229         case ENTITY_UNION:
230                 if (alignment > entity->compound.alignment) {
231                         entity->compound.alignment = alignment;
232                 }
233                 break;
234         default:
235                 if (warning.other) {
236                         warningf(&attribute->source_position,
237                                          "alignment attribute specification on '%S' ignored",
238                                          entity->base.symbol);
239                 }
240                 break;
241         }
242 }
243
244 static void warn_arguments(const attribute_t *attribute)
245 {
246         if (attribute->a.arguments == NULL)
247                 return;
248
249         if (warning.other) {
250                 warningf(&attribute->source_position,
251                                  "attribute '%s' needs no arguments",
252                                  get_attribute_name(attribute->kind));
253         }
254 }
255
256 static void handle_attribute_packed_e(const attribute_t *attribute,
257                                       entity_t *entity)
258 {
259 #if 0
260         if (entity->kind != ENTITY_STRUCT) {
261                 warningf(&attribute->source_position,
262                          "packed attribute on %s '%s' ignored",
263                                  get_entity_kind_name(entity->kind),
264                                  entity->base.symbol->string);
265                 return;
266         }
267 #endif
268
269         warn_arguments(attribute);
270         entity->compound.packed = true;
271 }
272
273 static void handle_attribute_packed(const attribute_t *attribute, type_t *type)
274 {
275         if (type->kind != TYPE_COMPOUND_STRUCT) {
276                 warningf(&attribute->source_position,
277                          "packed attribute on type '%T' ignored", type);
278                 return;
279         }
280
281         handle_attribute_packed_e(attribute, (entity_t*) type->compound.compound);
282 }
283
284 static void handle_attribute_asm(const attribute_t *attribute,
285                                       entity_t *entity)
286 {
287         attribute_argument_t *argument = attribute->a.arguments;
288         assert (argument->kind == ATTRIBUTE_ARGUMENT_EXPRESSION);
289         expression_t *expression = argument->v.expression;
290         if (expression->kind != EXPR_STRING_LITERAL)
291                 errorf(&attribute->source_position,
292                        "Invalid asm attribute expression");
293         symbol_t *sym = symbol_table_insert(expression->string_literal.value.begin);
294         entity->function.actual_name = sym;
295         assert(argument->next == NULL);
296         return;
297 }
298
299 void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
300 {
301         if (entity->kind == ENTITY_TYPEDEF) {
302                 type_t *type = entity->typedefe.type;
303                 type = handle_type_attributes(attributes, type);
304                 entity->typedefe.type = type;
305         } else if (is_declaration(entity)) {
306                 type_t *type = entity->declaration.type;
307                 type = handle_type_attributes(attributes, type);
308                 entity->declaration.type = type;
309         }
310
311         decl_modifiers_t modifiers = 0;
312         const attribute_t *attribute = attributes;
313         for ( ; attribute != NULL; attribute = attribute->next) {
314                 switch(attribute->kind) {
315                 case ATTRIBUTE_GNU_CONST:         modifiers |= DM_CONST; break;
316                 case ATTRIBUTE_GNU_DEPRECATED:    modifiers |= DM_DEPRECATED; break;
317                 case ATTRIBUTE_GNU_NOINLINE:      modifiers |= DM_NOINLINE; break;
318                 case ATTRIBUTE_GNU_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
319                 case ATTRIBUTE_GNU_NORETURN:      modifiers |= DM_NORETURN; break;
320                 case ATTRIBUTE_GNU_NAKED:         modifiers |= DM_NAKED; break;
321                 case ATTRIBUTE_GNU_PURE:          modifiers |= DM_PURE; break;
322                 case ATTRIBUTE_GNU_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; break;
323                 case ATTRIBUTE_GNU_MALLOC:        modifiers |= DM_MALLOC; break;
324                 case ATTRIBUTE_GNU_CONSTRUCTOR:   modifiers |= DM_CONSTRUCTOR; break;
325                 case ATTRIBUTE_GNU_DESTRUCTOR:    modifiers |= DM_DESTRUCTOR; break;
326                 case ATTRIBUTE_GNU_NOTHROW:       modifiers |= DM_NOTHROW; break;
327                 case ATTRIBUTE_GNU_TRANSPARENT_UNION:
328                                                                                   modifiers |= DM_TRANSPARENT_UNION;
329                                                                                   break;
330                 case ATTRIBUTE_GNU_USED:          modifiers |= DM_USED; break;
331                 case ATTRIBUTE_GNU_UNUSED:        modifiers |= DM_UNUSED; break;
332                 case ATTRIBUTE_GNU_DLLIMPORT:     modifiers |= DM_DLLIMPORT; break;
333                 case ATTRIBUTE_GNU_DLLEXPORT:     modifiers |= DM_DLLEXPORT; break;
334                 case ATTRIBUTE_GNU_WEAK:          modifiers |= DM_WEAK; break;
335
336                 case ATTRIBUTE_MS_ALLOCATE:      modifiers |= DM_MALLOC; break;
337                 case ATTRIBUTE_MS_DLLIMPORT:     modifiers |= DM_DLLIMPORT; break;
338                 case ATTRIBUTE_MS_DLLEXPORT:     modifiers |= DM_DLLEXPORT; break;
339                 case ATTRIBUTE_MS_NAKED:         modifiers |= DM_NAKED; break;
340                 case ATTRIBUTE_MS_NOINLINE:      modifiers |= DM_NOINLINE; break;
341                 case ATTRIBUTE_MS_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
342                 case ATTRIBUTE_MS_NORETURN:      modifiers |= DM_NORETURN; break;
343                 case ATTRIBUTE_MS_NOTHROW:       modifiers |= DM_NOTHROW; break;
344                 case ATTRIBUTE_MS_THREAD:        modifiers |= DM_THREAD; break;
345                 case ATTRIBUTE_MS_DEPRECATED:    modifiers |= DM_DEPRECATED; break;
346                 case ATTRIBUTE_MS_RESTRICT:      modifiers |= DM_RESTRICT; break;
347                 case ATTRIBUTE_MS_NOALIAS:       modifiers |= DM_NOALIAS; break;
348
349                 case ATTRIBUTE_GNU_PACKED:
350                         handle_attribute_packed_e(attribute, entity);
351                         break;
352
353                 case ATTRIBUTE_GNU_ASM:
354                         handle_attribute_asm(attribute, entity);
355                         break;
356
357                 case ATTRIBUTE_MS_ALIGN:
358                 case ATTRIBUTE_GNU_ALIGNED:
359                         handle_attribute_aligned(attribute, entity);
360                         break;
361                 default: break;
362                 }
363         }
364
365         if (modifiers != 0) {
366                 switch(entity->kind) {
367                 case ENTITY_TYPEDEF:
368                         entity->typedefe.modifiers |= modifiers;
369                         break;
370                 case ENTITY_UNION:
371                 case ENTITY_STRUCT:
372                         entity->compound.modifiers |= modifiers;
373                         break;
374                 case ENTITY_COMPOUND_MEMBER:
375                 case ENTITY_VARIABLE:
376                 case ENTITY_FUNCTION:
377                         entity->declaration.modifiers |= modifiers;
378                         break;
379                 default:
380                         /* TODO: warning */
381                         break;
382                 }
383         }
384 }
385
386 static type_t *change_calling_convention(type_t *type, cc_kind_t cconv)
387 {
388         if (is_typeref(type) || !is_type_function(type)) {
389                 return type;
390         }
391
392         if (type->function.calling_convention == cconv)
393                 return type;
394
395         type_t* new_type = duplicate_type(type);
396         new_type->function.calling_convention = cconv;
397         return identify_new_type(new_type);
398 }
399
400 type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
401 {
402         const attribute_t *attribute = attributes;
403         for ( ; attribute != NULL; attribute = attribute->next) {
404                 switch(attribute->kind) {
405                 case ATTRIBUTE_GNU_PACKED:
406                         handle_attribute_packed(attribute, type);
407                         break;
408                 case ATTRIBUTE_GNU_CDECL:
409                 case ATTRIBUTE_MS_CDECL:
410                         type = change_calling_convention(type, CC_CDECL);
411                         break;
412                 case ATTRIBUTE_MS_STDCALL:
413                 case ATTRIBUTE_GNU_STDCALL:
414                         type = change_calling_convention(type, CC_STDCALL);
415                         break;
416                 case ATTRIBUTE_MS_FASTCALL:
417                 case ATTRIBUTE_GNU_FASTCALL:
418                         type = change_calling_convention(type, CC_FASTCALL);
419                         break;
420                 case ATTRIBUTE_MS_THISCALL:
421                         type = change_calling_convention(type, CC_THISCALL);
422                         break;
423                 case ATTRIBUTE_GNU_MODE:
424                         type = handle_attribute_mode(attribute, type);
425                         break;
426                 default:
427                         break;
428                 }
429         }
430
431         return type;
432 }
433
434 const char *get_deprecated_string(const attribute_t *attribute)
435 {
436         for ( ; attribute != NULL; attribute = attribute->next) {
437                 if (attribute->kind != ATTRIBUTE_MS_DEPRECATED)
438                         continue;
439
440                 attribute_argument_t *argument = attribute->a.arguments;
441                 if (argument == NULL)
442                         return NULL;
443                 if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
444                         return NULL;
445                 expression_t *expression = argument->v.expression;
446                 if (expression->kind != EXPR_STRING_LITERAL)
447                         return NULL;
448                 return expression->literal.value.begin;
449         }
450         return NULL;
451 }
452
453 static bool property_attribute_equal(const attribute_property_argument_t *prop1,
454                                      const attribute_property_argument_t *prop2)
455 {
456         return prop1->put_symbol == prop2->put_symbol
457                 && prop1->get_symbol == prop2->get_symbol;
458 }
459
460 static bool attribute_argument_equal(const attribute_argument_t *arg1,
461                                      const attribute_argument_t *arg2)
462 {
463         if (arg1->kind != arg2->kind)
464                 return false;
465
466         switch (arg1->kind) {
467         case ATTRIBUTE_ARGUMENT_SYMBOL:
468                 return arg1->v.symbol == arg2->v.symbol;
469         case ATTRIBUTE_ARGUMENT_EXPRESSION:
470                 /* TODO */
471                 return false;
472         }
473         panic("Unknown argument type found");
474 }
475
476 static bool attribute_arguments_equal(const attribute_argument_t *args1,
477                                       const attribute_argument_t *args2)
478 {
479         for ( ; args1 != NULL && args2 != NULL;
480              args1 = args1->next, args2 = args2->next) {
481                 if (!attribute_argument_equal(args1, args2))
482                         return false;
483         }
484         /* both should be NULL now */
485         return args1 == args2;
486 }
487
488 bool attributes_equal(const attribute_t *attr1, const attribute_t *attr2)
489 {
490         if (attr1->kind != attr2->kind)
491                 return false;
492
493         switch (attr1->kind) {
494         case ATTRIBUTE_MS_PROPERTY:
495                 return property_attribute_equal(attr1->a.property, attr2->a.property);
496         default:
497                 return attribute_arguments_equal(attr1->a.arguments,
498                                                  attr2->a.arguments);
499         }
500 }