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