2 * This file is part of cparser.
3 * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
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.
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.
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
23 #include "diagnostic.h"
25 #include "attribute_t.h"
29 static const char *const attribute_names[ATTRIBUTE_LAST+1] = {
30 [ATTRIBUTE_GNU_CONST] = "const",
31 [ATTRIBUTE_GNU_VOLATILE] = "volatile",
32 [ATTRIBUTE_GNU_CDECL] = "cdecl",
33 [ATTRIBUTE_GNU_STDCALL] = "stdcall",
34 [ATTRIBUTE_GNU_FASTCALL] = "fastcall",
35 [ATTRIBUTE_GNU_DEPRECATED] = "deprecated",
36 [ATTRIBUTE_GNU_NOINLINE] = "noinline",
37 [ATTRIBUTE_GNU_RETURNS_TWICE] = "returns_twice",
38 [ATTRIBUTE_GNU_NORETURN] = "noreturn",
39 [ATTRIBUTE_GNU_NAKED] = "naked",
40 [ATTRIBUTE_GNU_PURE] = "pure",
41 [ATTRIBUTE_GNU_ALWAYS_INLINE] = "always_inline",
42 [ATTRIBUTE_GNU_MALLOC] = "malloc",
43 [ATTRIBUTE_GNU_WEAK] = "weak",
44 [ATTRIBUTE_GNU_CONSTRUCTOR] = "constructor",
45 [ATTRIBUTE_GNU_DESTRUCTOR] = "destructor",
46 [ATTRIBUTE_GNU_NOTHROW] = "nothrow",
47 [ATTRIBUTE_GNU_TRANSPARENT_UNION] = "transparent_union",
48 [ATTRIBUTE_GNU_COMMON] = "common",
49 [ATTRIBUTE_GNU_NOCOMMON] = "nocommon",
50 [ATTRIBUTE_GNU_PACKED] = "packed",
51 [ATTRIBUTE_GNU_SHARED] = "shared",
52 [ATTRIBUTE_GNU_NOTSHARED] = "notshared",
53 [ATTRIBUTE_GNU_USED] = "used",
54 [ATTRIBUTE_GNU_UNUSED] = "unused",
55 [ATTRIBUTE_GNU_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
56 [ATTRIBUTE_GNU_WARN_UNUSED_RESULT] = "warn_unused_result",
57 [ATTRIBUTE_GNU_LONGCALL] = "longcall",
58 [ATTRIBUTE_GNU_SHORTCALL] = "shortcall",
59 [ATTRIBUTE_GNU_LONG_CALL] = "long_call",
60 [ATTRIBUTE_GNU_SHORT_CALL] = "short_call",
61 [ATTRIBUTE_GNU_FUNCTION_VECTOR] = "function_vector",
62 [ATTRIBUTE_GNU_INTERRUPT] = "interrupt",
63 [ATTRIBUTE_GNU_INTERRUPT_HANDLER] = "interrupt_handler",
64 [ATTRIBUTE_GNU_NMI_HANDLER] = "nmi_handler",
65 [ATTRIBUTE_GNU_NESTING] = "nesting",
66 [ATTRIBUTE_GNU_NEAR] = "near",
67 [ATTRIBUTE_GNU_FAR] = "far",
68 [ATTRIBUTE_GNU_SIGNAL] = "signal",
69 [ATTRIBUTE_GNU_EIGTHBIT_DATA] = "eightbit_data",
70 [ATTRIBUTE_GNU_TINY_DATA] = "tiny_data",
71 [ATTRIBUTE_GNU_SAVEALL] = "saveall",
72 [ATTRIBUTE_GNU_FLATTEN] = "flatten",
73 [ATTRIBUTE_GNU_SSEREGPARM] = "sseregparm",
74 [ATTRIBUTE_GNU_EXTERNALLY_VISIBLE] = "externally_visible",
75 [ATTRIBUTE_GNU_MAY_ALIAS] = "may_alias",
76 [ATTRIBUTE_GNU_MS_STRUCT] = "ms_struct",
77 [ATTRIBUTE_GNU_GCC_STRUCT] = "gcc_struct",
78 [ATTRIBUTE_GNU_DLLIMPORT] = "dllimport",
79 [ATTRIBUTE_GNU_DLLEXPORT] = "dllexport",
80 [ATTRIBUTE_GNU_ALIGNED] = "aligned",
81 [ATTRIBUTE_GNU_ALIAS] = "alias",
82 [ATTRIBUTE_GNU_SECTION] = "section",
83 [ATTRIBUTE_GNU_FORMAT] = "format",
84 [ATTRIBUTE_GNU_FORMAT_ARG] = "format_arg",
85 [ATTRIBUTE_GNU_WEAKREF] = "weakref",
86 [ATTRIBUTE_GNU_NONNULL] = "nonnull",
87 [ATTRIBUTE_GNU_TLS_MODEL] = "tls_model",
88 [ATTRIBUTE_GNU_VISIBILITY] = "visibility",
89 [ATTRIBUTE_GNU_REGPARM] = "regparm",
90 [ATTRIBUTE_GNU_MODE] = "mode",
91 [ATTRIBUTE_GNU_MODEL] = "model",
92 [ATTRIBUTE_GNU_TRAP_EXIT] = "trap_exit",
93 [ATTRIBUTE_GNU_SP_SWITCH] = "sp_switch",
94 [ATTRIBUTE_GNU_SENTINEL] = "sentinel",
96 [ATTRIBUTE_MS_ALIGN] = "align",
97 [ATTRIBUTE_MS_ALLOCATE] = "allocate",
98 [ATTRIBUTE_MS_DLLIMPORT] = "dllimport",
99 [ATTRIBUTE_MS_DLLEXPORT] = "dllexport",
100 [ATTRIBUTE_MS_NAKED] = "naked",
101 [ATTRIBUTE_MS_NOINLINE] = "noinline",
102 [ATTRIBUTE_MS_RETURNS_TWICE] = "returns_twice",
103 [ATTRIBUTE_MS_NORETURN] = "noreturn",
104 [ATTRIBUTE_MS_NOTHROW] = "nothrow",
105 [ATTRIBUTE_MS_NOVTABLE] = "novtable",
106 [ATTRIBUTE_MS_PROPERTY] = "property",
107 [ATTRIBUTE_MS_SELECTANY] = "selectany",
108 [ATTRIBUTE_MS_THREAD] = "thread",
109 [ATTRIBUTE_MS_UUID] = "uuid",
110 [ATTRIBUTE_MS_DEPRECATED] = "deprecated",
111 [ATTRIBUTE_MS_RESTRICT] = "restrict",
112 [ATTRIBUTE_MS_NOALIAS] = "noalias",
115 const char *get_attribute_name(attribute_kind_t kind)
117 assert(kind <= ATTRIBUTE_LAST);
118 return attribute_names[kind];
122 * compare two string, ignoring double underscores on the second.
124 static int strcmp_underscore(const char *s1, const char *s2)
126 if (s2[0] == '_' && s2[1] == '_') {
127 size_t len2 = strlen(s2);
128 size_t len1 = strlen(s1);
129 if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
130 return strncmp(s1, s2+2, len2-4);
134 return strcmp(s1, s2);
137 type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type)
139 type_t *type = skip_typeref(orig_type);
141 /* at least: byte, word, pointer, list of machine modes
142 * __XXX___ is interpreted as XXX */
144 /* This isn't really correct, the backend should provide a list of machine
145 * specific modes (according to gcc philosophy that is...) */
146 attribute_argument_t *arg = attribute->a.arguments;
147 const char *symbol_str = arg->v.symbol->string;
148 bool sign = is_type_signed(type);
149 atomic_type_kind_t akind;
150 if (strcmp_underscore("QI", symbol_str) == 0 ||
151 strcmp_underscore("byte", symbol_str) == 0) {
152 akind = sign ? ATOMIC_TYPE_CHAR : ATOMIC_TYPE_UCHAR;
153 } else if (strcmp_underscore("HI", symbol_str) == 0) {
154 akind = sign ? ATOMIC_TYPE_SHORT : ATOMIC_TYPE_USHORT;
155 } else if (strcmp_underscore("SI", symbol_str) == 0
156 || strcmp_underscore("word", symbol_str) == 0
157 || strcmp_underscore("pointer", symbol_str) == 0) {
158 akind = sign ? ATOMIC_TYPE_INT : ATOMIC_TYPE_UINT;
159 } else if (strcmp_underscore("DI", symbol_str) == 0) {
160 akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG;
163 warningf(&attribute->source_position, "ignoring unknown mode '%s'",
168 if (type->kind == TYPE_ATOMIC) {
169 type_t *copy = duplicate_type(type);
170 copy->atomic.akind = akind;
171 return identify_new_type(copy);
172 } else if (type->kind == TYPE_ENUM) {
173 type_t *copy = duplicate_type(type);
174 copy->enumt.akind = akind;
175 return identify_new_type(copy);
176 } else if (is_type_pointer(type)) {
177 warningf(&attribute->source_position,
178 "__attribute__((mode)) on pointers not implemented yet (ignored)");
182 errorf(&attribute->source_position,
183 "__attribute__((mode)) only allowed on integer, enum or pointer type");
187 static inline bool is_po2(unsigned x)
189 return (x & (x-1)) == 0;
192 static void handle_attribute_aligned(const attribute_t *attribute,
195 int alignment = 32; /* TODO: fill in maximum useful alignment for
197 if (attribute->a.arguments) {
198 attribute_argument_t *argument = attribute->a.arguments;
199 alignment = fold_constant(argument->v.expression);
202 if (!is_po2(alignment)) {
203 errorf(&attribute->source_position,
204 "alignment must be a power of 2 but is %d\n",
208 if (alignment <= 0) {
209 errorf(&attribute->source_position,
210 "alignment must be bigger than 0 but is %d\n",
215 switch (entity->kind) {
216 DECLARATION_KIND_CASES
217 entity->declaration.alignment = alignment;
219 entity->typedefe.alignment = alignment;
223 if (alignment > entity->compound.alignment) {
224 entity->compound.alignment = alignment;
229 warningf(&attribute->source_position,
230 "alignment attribute specification on '%S' ignored",
231 entity->base.symbol);
237 static void warn_arguments(const attribute_t *attribute)
239 if (attribute->a.arguments == NULL)
243 warningf(&attribute->source_position,
244 "attribute '%s' needs no attributes",
245 get_attribute_name(attribute->kind));
249 static void handle_attribute_packed(const attribute_t *attribute,
252 warn_arguments(attribute);
254 if (entity->kind == ENTITY_STRUCT) {
255 entity->compound.packed = true;
256 } else if (warning.other) {
257 warningf(&attribute->source_position,
258 "packed attribute on %s ignored",
259 get_entity_kind_name(entity->kind));
263 void handle_entity_attributes(const attribute_t *attributes, entity_t *entity)
265 if (entity->kind == ENTITY_TYPEDEF) {
266 type_t *type = entity->typedefe.type;
267 type = handle_type_attributes(attributes, type);
268 entity->typedefe.type = type;
269 } else if (is_declaration(entity)) {
270 type_t *type = entity->declaration.type;
271 type = handle_type_attributes(attributes, type);
272 entity->declaration.type = type;
275 decl_modifiers_t modifiers = 0;
276 const attribute_t *attribute = attributes;
277 for ( ; attribute != NULL; attribute = attribute->next) {
278 switch(attribute->kind) {
279 case ATTRIBUTE_GNU_CONST: modifiers |= DM_CONST; break;
280 case ATTRIBUTE_GNU_DEPRECATED: modifiers |= DM_DEPRECATED; break;
281 case ATTRIBUTE_GNU_NOINLINE: modifiers |= DM_NOINLINE; break;
282 case ATTRIBUTE_GNU_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
283 case ATTRIBUTE_GNU_NORETURN: modifiers |= DM_NORETURN; break;
284 case ATTRIBUTE_GNU_NAKED: modifiers |= DM_NAKED; break;
285 case ATTRIBUTE_GNU_PURE: modifiers |= DM_PURE; break;
286 case ATTRIBUTE_GNU_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; break;
287 case ATTRIBUTE_GNU_MALLOC: modifiers |= DM_MALLOC; break;
288 case ATTRIBUTE_GNU_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; break;
289 case ATTRIBUTE_GNU_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; break;
290 case ATTRIBUTE_GNU_NOTHROW: modifiers |= DM_NOTHROW; break;
291 case ATTRIBUTE_GNU_TRANSPARENT_UNION:
292 modifiers |= DM_TRANSPARENT_UNION;
294 case ATTRIBUTE_GNU_USED: modifiers |= DM_USED; break;
295 case ATTRIBUTE_GNU_UNUSED: modifiers |= DM_UNUSED; break;
296 case ATTRIBUTE_GNU_DLLIMPORT: modifiers |= DM_DLLIMPORT; break;
297 case ATTRIBUTE_GNU_DLLEXPORT: modifiers |= DM_DLLEXPORT; break;
299 case ATTRIBUTE_MS_ALLOCATE: modifiers |= DM_MALLOC; break;
300 case ATTRIBUTE_MS_DLLIMPORT: modifiers |= DM_DLLIMPORT; break;
301 case ATTRIBUTE_MS_DLLEXPORT: modifiers |= DM_DLLEXPORT; break;
302 case ATTRIBUTE_MS_NAKED: modifiers |= DM_NAKED; break;
303 case ATTRIBUTE_MS_NOINLINE: modifiers |= DM_NOINLINE; break;
304 case ATTRIBUTE_MS_RETURNS_TWICE: modifiers |= DM_RETURNS_TWICE; break;
305 case ATTRIBUTE_MS_NORETURN: modifiers |= DM_NORETURN; break;
306 case ATTRIBUTE_MS_NOTHROW: modifiers |= DM_NOTHROW; break;
307 case ATTRIBUTE_MS_THREAD: modifiers |= DM_THREAD; break;
308 case ATTRIBUTE_MS_DEPRECATED: modifiers |= DM_DEPRECATED; break;
309 case ATTRIBUTE_MS_RESTRICT: modifiers |= DM_RESTRICT; break;
310 case ATTRIBUTE_MS_NOALIAS: modifiers |= DM_NOALIAS; break;
312 case ATTRIBUTE_GNU_PACKED:
313 handle_attribute_packed(attribute, entity);
315 case ATTRIBUTE_MS_ALIGN:
316 case ATTRIBUTE_GNU_ALIGNED:
317 handle_attribute_aligned(attribute, entity);
323 if (modifiers != 0) {
324 switch(entity->kind) {
326 entity->typedefe.modifiers |= modifiers;
330 entity->compound.modifiers |= modifiers;
332 case ENTITY_COMPOUND_MEMBER:
333 case ENTITY_VARIABLE:
334 case ENTITY_FUNCTION:
335 entity->declaration.modifiers |= modifiers;
344 static type_t *change_calling_convention(type_t *type, cc_kind_t cconv)
346 if (!is_type_function(type)) {
350 if (type->function.calling_convention == cconv)
353 type_t* new_type = duplicate_type(type);
354 new_type->function.calling_convention = cconv;
355 return identify_new_type(new_type);
358 type_t *handle_type_attributes(const attribute_t *attributes, type_t *type)
360 const attribute_t *attribute = attributes;
361 for ( ; attribute != NULL; attribute = attribute->next) {
362 switch(attribute->kind) {
363 case ATTRIBUTE_GNU_CDECL:
364 case ATTRIBUTE_MS_CDECL:
365 type = change_calling_convention(type, CC_CDECL);
367 case ATTRIBUTE_MS_STDCALL:
368 case ATTRIBUTE_GNU_STDCALL:
369 type = change_calling_convention(type, CC_STDCALL);
371 case ATTRIBUTE_MS_FASTCALL:
372 case ATTRIBUTE_GNU_FASTCALL:
373 type = change_calling_convention(type, CC_FASTCALL);
375 case ATTRIBUTE_MS_THISCALL:
376 type = change_calling_convention(type, CC_THISCALL);
378 case ATTRIBUTE_GNU_MODE:
379 type = handle_attribute_mode(attribute, type);
389 const char *get_deprecated_string(const attribute_t *attribute)
391 for ( ; attribute != NULL; attribute = attribute->next) {
392 if (attribute->kind != ATTRIBUTE_MS_DEPRECATED)
395 attribute_argument_t *argument = attribute->a.arguments;
396 if (argument == NULL)
398 if (argument->kind != ATTRIBUTE_ARGUMENT_EXPRESSION)
400 expression_t *expression = argument->v.expression;
401 if (expression->kind != EXPR_STRING_LITERAL)
403 return expression->string.value.begin;