2 * This file is part of cparser.
3 * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
9 #include "adt/bitfiddle.h"
10 #include "adt/strutil.h"
12 #include "diagnostic.h"
14 #include "attribute_t.h"
16 #include "adt/error.h"
18 #include "symbol_table.h"
21 static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
22 [ATTRIBUTE_GNU_ALIAS] = "alias",
23 [ATTRIBUTE_GNU_ALIGNED] = "aligned",
24 [ATTRIBUTE_GNU_ALWAYS_INLINE] = "always_inline",
25 [ATTRIBUTE_GNU_CDECL] = "cdecl",
26 [ATTRIBUTE_GNU_COMMON] = "common",
27 [ATTRIBUTE_GNU_CONST] = "const",
28 [ATTRIBUTE_GNU_CONSTRUCTOR] = "constructor",
29 [ATTRIBUTE_GNU_DEPRECATED] = "deprecated",
30 [ATTRIBUTE_GNU_DESTRUCTOR] = "destructor",
31 [ATTRIBUTE_GNU_DLLEXPORT] = "dllexport",
32 [ATTRIBUTE_GNU_DLLIMPORT] = "dllimport",
33 [ATTRIBUTE_GNU_EIGTHBIT_DATA] = "eightbit_data",
34 [ATTRIBUTE_GNU_EXTERNALLY_VISIBLE] = "externally_visible",
35 [ATTRIBUTE_GNU_FAR] = "far",
36 [ATTRIBUTE_GNU_FASTCALL] = "fastcall",
37 [ATTRIBUTE_GNU_FLATTEN] = "flatten",
38 [ATTRIBUTE_GNU_FORMAT_ARG] = "format_arg",
39 [ATTRIBUTE_GNU_FORMAT] = "format",
40 [ATTRIBUTE_GNU_FUNCTION_VECTOR] = "function_vector",
41 [ATTRIBUTE_GNU_GCC_STRUCT] = "gcc_struct",
42 [ATTRIBUTE_GNU_INTERRUPT_HANDLER] = "interrupt_handler",
43 [ATTRIBUTE_GNU_INTERRUPT] = "interrupt",
44 [ATTRIBUTE_GNU_LEAF] = "leaf",
45 [ATTRIBUTE_GNU_LONGCALL] = "longcall",
46 [ATTRIBUTE_GNU_LONG_CALL] = "long_call",
47 [ATTRIBUTE_GNU_MALLOC] = "malloc",
48 [ATTRIBUTE_GNU_MAY_ALIAS] = "may_alias",
49 [ATTRIBUTE_GNU_MODEL] = "model",
50 [ATTRIBUTE_GNU_MODE] = "mode",
51 [ATTRIBUTE_GNU_MS_STRUCT] = "ms_struct",
52 [ATTRIBUTE_GNU_NAKED] = "naked",
53 [ATTRIBUTE_GNU_NEAR] = "near",
54 [ATTRIBUTE_GNU_NESTING] = "nesting",
55 [ATTRIBUTE_GNU_NMI_HANDLER] = "nmi_handler",
56 [ATTRIBUTE_GNU_NOCOMMON] = "nocommon",
57 [ATTRIBUTE_GNU_NOINLINE] = "noinline",
58 [ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
59 [ATTRIBUTE_GNU_NONNULL] = "nonnull",
60 [ATTRIBUTE_GNU_NORETURN] = "noreturn",
61 [ATTRIBUTE_GNU_NOTHROW] = "nothrow",
62 [ATTRIBUTE_GNU_NOTSHARED] = "notshared",
63 [ATTRIBUTE_GNU_PACKED] = "packed",
64 [ATTRIBUTE_GNU_PURE] = "pure",
65 [ATTRIBUTE_GNU_REGPARM] = "regparm",
66 [ATTRIBUTE_GNU_RETURNS_TWICE] = "returns_twice",
67 [ATTRIBUTE_GNU_SAVEALL] = "saveall",
68 [ATTRIBUTE_GNU_SECTION] = "section",
69 [ATTRIBUTE_GNU_SENTINEL] = "sentinel",
70 [ATTRIBUTE_GNU_SHARED] = "shared",
71 [ATTRIBUTE_GNU_SHORTCALL] = "shortcall",
72 [ATTRIBUTE_GNU_SHORT_CALL] = "short_call",
73 [ATTRIBUTE_GNU_SIGNAL] = "signal",
74 [ATTRIBUTE_GNU_SP_SWITCH] = "sp_switch",
75 [ATTRIBUTE_GNU_SSEREGPARM] = "sseregparm",
76 [ATTRIBUTE_GNU_STDCALL] = "stdcall",
77 [ATTRIBUTE_GNU_TINY_DATA] = "tiny_data",
78 [ATTRIBUTE_GNU_TLS_MODEL] = "tls_model",
79 [ATTRIBUTE_GNU_TRANSPARENT_UNION] = "transparent_union",
80 [ATTRIBUTE_GNU_TRAP_EXIT] = "trap_exit",
81 [ATTRIBUTE_GNU_UNUSED] = "unused",
82 [ATTRIBUTE_GNU_USED] = "used",
83 [ATTRIBUTE_GNU_VISIBILITY] = "visibility",
84 [ATTRIBUTE_GNU_VOLATILE] = "volatile",
85 [ATTRIBUTE_GNU_WARN_UNUSED_RESULT] = "warn_unused_result",
86 [ATTRIBUTE_GNU_WEAKREF] = "weakref",
87 [ATTRIBUTE_GNU_WEAK] = "weak",
89 [ATTRIBUTE_MS_ALIGN] = "align",
90 [ATTRIBUTE_MS_ALLOCATE] = "allocate",
91 [ATTRIBUTE_MS_DEPRECATED] = "deprecated",
92 [ATTRIBUTE_MS_DLLEXPORT] = "dllexport",
93 [ATTRIBUTE_MS_DLLIMPORT] = "dllimport",
94 [ATTRIBUTE_MS_NAKED] = "naked",
95 [ATTRIBUTE_MS_NOALIAS] = "noalias",
96 [ATTRIBUTE_MS_NOINLINE] = "noinline",
97 [ATTRIBUTE_MS_NORETURN] = "noreturn",
98 [ATTRIBUTE_MS_NOTHROW] = "nothrow",
99 [ATTRIBUTE_MS_NOVTABLE] = "novtable",
100 [ATTRIBUTE_MS_PROPERTY] = "property",
101 [ATTRIBUTE_MS_RESTRICT] = "restrict",
102 [ATTRIBUTE_MS_RETURNS_TWICE] = "returns_twice",
103 [ATTRIBUTE_MS_SELECTANY] = "selectany",
104 [ATTRIBUTE_MS_THREAD] = "thread",
105 [ATTRIBUTE_MS_UUID] = "uuid",
108 const char *get_attribute_name(attribute_kind_t kind)
110 assert(kind <= ATTRIBUTE_LAST);
111 return attribute_names[kind];
114 type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type)
116 type_t *type = skip_typeref(orig_type);
118 /* at least: byte, word, pointer, list of machine modes
119 * __XXX___ is interpreted as XXX */
121 /* This isn't really correct, the backend should provide a list of machine
122 * specific modes (according to gcc philosophy that is...) */
123 attribute_argument_t *arg = attribute->a.arguments;
125 errorf(&attribute->pos, "__attribute__((mode(X))) misses argument");
129 const char *symbol_str = arg->v.symbol->string;
130 bool sign = is_type_signed(type);
131 atomic_type_kind_t akind;
132 if (streq_underscore("QI", symbol_str) ||
133 streq_underscore("byte", symbol_str)) {
134 akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
135 } else if (streq_underscore("HI", symbol_str)) {
136 akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
137 } else if (streq_underscore("SI", symbol_str)
138 || streq_underscore("word", symbol_str)
139 || streq_underscore("pointer", symbol_str)) {
140 akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
141 } else if (streq_underscore("DI", symbol_str)) {
142 akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
144 warningf(WARN_OTHER, &attribute->pos, "ignoring unknown mode '%s'",
149 if (type->kind == TYPE_ATOMIC || type->kind == TYPE_ENUM) {
150 type_t *copy = duplicate_type(type);
151 copy->atomic.akind = akind;
152 return identify_new_type(copy);
153 } else if (is_type_pointer(type)) {
154 warningf(WARN_OTHER, &attribute->pos, "__attribute__((mode)) on pointers not implemented yet (ignored)");
158 errorf(&attribute->pos,
159 "__attribute__((mode)) only allowed on integer, enum or pointer type");
163 static void handle_attribute_aligned(const attribute_t *attribute,
166 int alignment = 32; /* TODO: fill in maximum useful alignment for
168 if (attribute->a.arguments) {
169 attribute_argument_t *argument = attribute->a.arguments;
170 alignment = fold_constant_to_int(argument->v.expression);
173 if (!is_po2(alignment)) {
174 errorf(&attribute->pos, "alignment must be a power of 2 but is %d", alignment);
177 if (alignment <= 0) {
178 errorf(&attribute->pos, "alignment must be bigger than 0 but is %d", alignment);
182 switch (entity->kind) {
183 case DECLARATION_KIND_CASES:
184 entity->declaration.alignment = alignment;
186 entity->typedefe.alignment = alignment;
190 entity->compound.alignment = MAX(entity->compound.alignment, (il_alignment_t)alignment);
194 warningf(WARN_OTHER, &attribute->pos, "alignment attribute specification on '%N' ignored", entity);
199 static const char *get_argument_string(const attribute_argument_t *argument)
201 if (argument == NULL)
203 if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
205 expression_t *expression = argument->v.expression;
206 if (expression->kind != EXPR_STRING_LITERAL)
208 return expression->string_literal.value.begin;
211 static void handle_attribute_visibility(const attribute_t *attribute,
214 /* This isn't really correct, the backend should provide a list of machine
215 * specific modes (according to gcc philosophy that is...) */
216 attribute_argument_t *arg = attribute->a.arguments;
218 errorf(&attribute->pos,
219 "__attribute__((visibility(X))) misses argument");
222 const char *string = get_argument_string(arg);
223 if (string == NULL) {
224 errorf(&attribute->pos,
225 "__attribute__((visibility(X))) argument is not a string");
228 elf_visibility_tag_t visibility = get_elf_visibility_from_string(string);
229 if (visibility == ELF_VISIBILITY_ERROR) {
230 errorf(&attribute->pos,
231 "unknown visibility type '%s'", string);
235 switch (entity->kind) {
236 case ENTITY_VARIABLE:
237 entity->variable.elf_visibility = visibility;
239 case ENTITY_FUNCTION:
240 entity->function.elf_visibility = visibility;
244 warningf(WARN_OTHER, &attribute->pos, "visibility attribute specification on '%N' ignored", entity);
249 static void warn_arguments(const attribute_t *attribute)
251 if (attribute->a.arguments == NULL)
254 position_t const *const pos = &attribute->pos;
255 char const *const what = get_attribute_name(attribute->kind);
256 warningf(WARN_OTHER, pos, "attribute '%s' needs no arguments", what);
259 static void handle_attribute_packed_e(const attribute_t *attribute,
263 if (entity->kind != ENTITY_STRUCT) {
264 warningf(WARN_OTHER, &attribute->pos, "packed attribute on '%N' ignored", entity);
269 warn_arguments(attribute);
270 entity->compound.packed = true;
273 static void handle_attribute_packed(const attribute_t *attribute, type_t *type)
275 if (type->kind != TYPE_COMPOUND_STRUCT) {
276 position_t const *const pos = &attribute->pos;
277 warningf(WARN_OTHER, pos, "packed attribute on type '%T' ignored", type);
281 handle_attribute_packed_e(attribute, (entity_t*) type->compound.compound);
284 static void handle_attribute_asm(const attribute_t *attribute,
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->pos, "Invalid asm attribute expression");
292 symbol_t *sym = symbol_table_insert(expression->string_literal.value.begin);
293 entity->function.actual_name = sym;
294 assert(argument->next == NULL);
298 static void handle_attribute_alias(const attribute_t *attribute,
301 // TODO: return if not at function_scope
302 attribute_argument_t *arg = attribute->a.arguments;
304 errorf(&attribute->pos,
305 "__attribute__((alias(X))) misses argument");
308 const char *string = get_argument_string(arg);
309 if (string == NULL) {
310 errorf(&attribute->pos,
311 "__attribute__((alias(X))) argument is not a string");
314 symbol_t *symbol = symbol_table_insert(string);
316 switch (entity->kind) {
317 case ENTITY_VARIABLE:
318 entity->variable.alias = symbol;
320 case ENTITY_FUNCTION:
321 entity->function.alias = symbol;
324 warningf(WARN_OTHER, &attribute->pos, "alias attribute on '%N' ignored", entity);
330 void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
332 if (entity->kind == ENTITY_TYPEDEF) {
333 type_t *type = entity->typedefe.type;
334 type = handle_type_attributes(attributes, type);
335 entity->typedefe.type = type;
336 } else if (is_declaration(entity)) {
337 type_t *type = entity->declaration.type;
338 type = handle_type_attributes(attributes, type);
339 entity->declaration.type = type;
342 decl_modifiers_t modifiers = 0;
343 const attribute_t *attribute = attributes;
344 for ( ; attribute != NULL; attribute = attribute->next) {
345 switch (attribute->kind) {
346 case ATTRIBUTE_GNU_CONST: modifiers |= DM_CONST; break;
347 case ATTRIBUTE_GNU_DEPRECATED: modifiers |= DM_DEPRECATED; break;
348 case ATTRIBUTE_GNU_NOINLINE: modifiers |= DM_NOINLINE; break;
349 case ATTRIBUTE_GNU_NAKED: modifiers |= DM_NAKED; break;
350 case ATTRIBUTE_GNU_PURE: modifiers |= DM_PURE; break;
351 case ATTRIBUTE_GNU_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; break;
352 case ATTRIBUTE_GNU_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; break;
353 case ATTRIBUTE_GNU_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; break;
354 case ATTRIBUTE_GNU_TRANSPARENT_UNION:
355 modifiers |= DM_TRANSPARENT_UNION;
357 case ATTRIBUTE_GNU_USED: modifiers |= DM_USED; break;
358 case ATTRIBUTE_GNU_UNUSED: modifiers |= DM_UNUSED; break;
359 case ATTRIBUTE_GNU_DLLIMPORT: modifiers |= DM_DLLIMPORT; break;
360 case ATTRIBUTE_GNU_DLLEXPORT: modifiers |= DM_DLLEXPORT; break;
361 case ATTRIBUTE_GNU_WEAK: modifiers |= DM_WEAK; break;
362 case ATTRIBUTE_GNU_LEAF: modifiers |= DM_LEAF; break;
364 case ATTRIBUTE_MS_DLLIMPORT: modifiers |= DM_DLLIMPORT; break;
365 case ATTRIBUTE_MS_DLLEXPORT: modifiers |= DM_DLLEXPORT; break;
366 case ATTRIBUTE_MS_NAKED: modifiers |= DM_NAKED; break;
367 case ATTRIBUTE_MS_NOINLINE: modifiers |= DM_NOINLINE; break;
368 case ATTRIBUTE_MS_THREAD: modifiers |= DM_THREAD; break;
369 case ATTRIBUTE_MS_DEPRECATED: modifiers |= DM_DEPRECATED; break;
370 case ATTRIBUTE_MS_RESTRICT: modifiers |= DM_RESTRICT; break;
371 case ATTRIBUTE_MS_NOALIAS: modifiers |= DM_NOALIAS; break;
373 case ATTRIBUTE_GNU_ALIAS:
374 handle_attribute_alias(attribute, entity);
377 case ATTRIBUTE_GNU_PACKED:
378 handle_attribute_packed_e(attribute, entity);
381 case ATTRIBUTE_GNU_ASM:
382 handle_attribute_asm(attribute, entity);
385 case ATTRIBUTE_GNU_VISIBILITY:
386 handle_attribute_visibility(attribute, entity);
389 case ATTRIBUTE_MS_ALIGN:
390 case ATTRIBUTE_GNU_ALIGNED:
391 handle_attribute_aligned(attribute, entity);
397 if (modifiers != 0) {
398 switch (entity->kind) {
400 entity->typedefe.modifiers |= modifiers;
404 entity->compound.modifiers |= modifiers;
406 case ENTITY_COMPOUND_MEMBER:
407 case ENTITY_VARIABLE:
408 case ENTITY_FUNCTION:
409 entity->declaration.modifiers |= modifiers;
418 static type_t *change_calling_convention(type_t *type, cc_kind_t cconv)
420 if (is_typeref(type) || !is_type_function(type)) {
424 if (type->function.calling_convention == cconv)
427 type_t* new_type = duplicate_type(type);
428 new_type->function.calling_convention = cconv;
429 return identify_new_type(new_type);
432 static type_t *add_modifiers(type_t *type, decl_modifiers_t modifiers)
434 if (is_typeref(type) || !is_type_function(type)) {
438 if ((type->function.modifiers & modifiers) == modifiers)
441 type_t* new_type = duplicate_type(type);
442 new_type->function.modifiers |= modifiers;
443 return identify_new_type(new_type);
446 type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
448 const attribute_t *attribute = attributes;
449 for ( ; attribute != NULL; attribute = attribute->next) {
450 switch (attribute->kind) {
451 case ATTRIBUTE_GNU_PACKED:
452 handle_attribute_packed(attribute, type);
454 case ATTRIBUTE_GNU_CDECL:
455 case ATTRIBUTE_MS_CDECL:
456 type = change_calling_convention(type, CC_CDECL);
458 case ATTRIBUTE_MS_STDCALL:
459 case ATTRIBUTE_GNU_STDCALL:
460 type = change_calling_convention(type, CC_STDCALL);
462 case ATTRIBUTE_MS_FASTCALL:
463 case ATTRIBUTE_GNU_FASTCALL:
464 type = change_calling_convention(type, CC_FASTCALL);
466 case ATTRIBUTE_MS_THISCALL:
467 type = change_calling_convention(type, CC_THISCALL);
469 case ATTRIBUTE_GNU_RETURNS_TWICE:
470 case ATTRIBUTE_MS_RETURNS_TWICE:
471 type = add_modifiers(type, DM_RETURNS_TWICE);
473 case ATTRIBUTE_GNU_NORETURN:
474 case ATTRIBUTE_MS_NORETURN:
475 type = add_modifiers(type, DM_NORETURN);
477 case ATTRIBUTE_GNU_MALLOC:
478 case ATTRIBUTE_MS_ALLOCATE:
479 type = add_modifiers(type, DM_MALLOC);
481 case ATTRIBUTE_GNU_NOTHROW:
482 case ATTRIBUTE_MS_NOTHROW:
483 type = add_modifiers(type, DM_NOTHROW);
485 case ATTRIBUTE_GNU_MODE:
486 type = handle_attribute_mode(attribute, type);
496 const char *get_deprecated_string(const attribute_t *attribute)
498 for ( ; attribute != NULL; attribute = attribute->next) {
499 if (attribute->kind != ATTRIBUTE_MS_DEPRECATED)
502 attribute_argument_t *argument = attribute->a.arguments;
503 return get_argument_string(argument);
508 static bool property_attribute_equal(const attribute_property_argument_t *prop1,
509 const attribute_property_argument_t *prop2)
511 return prop1->put_symbol == prop2->put_symbol
512 && prop1->get_symbol == prop2->get_symbol;
515 static bool attribute_argument_equal(const attribute_argument_t *arg1,
516 const attribute_argument_t *arg2)
518 if (arg1->kind != arg2->kind)
521 switch (arg1->kind) {
522 case ATTRIBUTE_ARGUMENT_SYMBOL:
523 return arg1->v.symbol == arg2->v.symbol;
524 case ATTRIBUTE_ARGUMENT_EXPRESSION:
528 panic("unknown argument type");
531 static bool attribute_arguments_equal(const attribute_argument_t *args1,
532 const attribute_argument_t *args2)
534 for ( ; args1 != NULL && args2 != NULL;
535 args1 = args1->next, args2 = args2->next) {
536 if (!attribute_argument_equal(args1, args2))
539 /* both should be NULL now */
540 return args1 == args2;
543 bool attributes_equal(const attribute_t *attr1, const attribute_t *attr2)
545 if (attr1->kind != attr2->kind)
548 switch (attr1->kind) {
549 case ATTRIBUTE_MS_PROPERTY:
550 return property_attribute_equal(attr1->a.property, attr2->a.property);
552 return attribute_arguments_equal(attr1->a.arguments,