type->base.alignment = alignment;
}
+static type_t *handle_mode_attribute(const gnu_attribute_t *attribute,
+ type_t *orig_type)
+{
+ type_t *type = skip_typeref(orig_type);
+ if (type->kind != TYPE_ATOMIC) {
+ errorf(HERE,
+ "__attribute__(mode)) only allowed for atomic types");
+ return orig_type;
+ }
+ atomic_type_kind_t akind = attribute->u.akind;
+ if (!is_type_signed(type)) {
+ switch (akind) {
+ case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_UCHAR; break;
+ case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_USHORT; break;
+ case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_UINT; break;
+ case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_ULONGLONG; break;
+ default:
+ errorf(HERE, "invalid akind in mode attribute");
+ return orig_type;
+ }
+ } else {
+ switch (akind) {
+ case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_SCHAR; break;
+ case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_SHORT; break;
+ case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_INT; break;
+ case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_LONGLONG; break;
+ default:
+ errorf(HERE, "invalid akind in mode attribute");
+ return orig_type;
+ }
+ }
+
+ type_t *copy = duplicate_type(type);
+ copy->atomic.akind = akind;
+
+ type = typehash_insert(copy);
+ if (type != copy) {
+ obstack_free(type_obst, copy);
+ }
+ return type;
+}
+
+static type_t *handle_type_attributes(const gnu_attribute_t *attributes,
+ type_t *type)
+{
+ /* handle these strange/stupid mode attributes */
+ const gnu_attribute_t *attribute = attributes;
+ for ( ; attribute != NULL; attribute = attribute->next) {
+ if (attribute->invalid)
+ continue;
+
+ if (attribute->kind == GNU_AK_MODE) {
+ type = handle_mode_attribute(attribute, type);
+ } else if (attribute->kind == GNU_AK_ALIGNED) {
+ int alignment = 32; /* TODO: fill in maximum usefull alignment for
+ target machine */
+ if (attribute->has_arguments)
+ alignment = attribute->u.argument;
+
+ type_t *copy = duplicate_type(type);
+ copy->base.alignment = attribute->u.argument;
+
+ type = typehash_insert(copy);
+ if (type != copy) {
+ obstack_free(type_obst, copy);
+ }
+ }
+ }
+
+ return type;
+}
+
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
type_t *type = NULL;
while (true) {
specifiers->modifiers
|= parse_attributes(&specifiers->gnu_attributes);
- if (specifiers->modifiers & DM_TRANSPARENT_UNION)
- modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
switch (token.type) {
/* storage class */
}
finish_specifiers:
+ specifiers->modifiers
+ |= parse_attributes(&specifiers->gnu_attributes);
+
in_gcc_extension = old_gcc_extension;
if (type == NULL || (saw_error && type_specifiers != 0)) {
/* FIXME: check type qualifiers here */
+ if (specifiers->modifiers & DM_TRANSPARENT_UNION)
+ modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
type->base.qualifiers = qualifiers;
type->base.modifiers = modifiers;
free_type(type);
}
+ result = handle_type_attributes(specifiers->gnu_attributes, result);
specifiers->type = result;
return;
continue;
if (attribute->kind == GNU_AK_MODE) {
- atomic_type_kind_t akind = attribute->u.akind;
- if (!is_type_signed(type)) {
- switch (akind) {
- case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_UCHAR; break;
- case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_USHORT; break;
- case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_UINT; break;
- case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_ULONGLONG; break;
- default:
- panic("invalid akind in mode attribute");
- }
- } else {
- switch (akind) {
- case ATOMIC_TYPE_CHAR: akind = ATOMIC_TYPE_SCHAR; break;
- case ATOMIC_TYPE_SHORT: akind = ATOMIC_TYPE_SHORT; break;
- case ATOMIC_TYPE_INT: akind = ATOMIC_TYPE_INT; break;
- case ATOMIC_TYPE_LONGLONG: akind = ATOMIC_TYPE_LONGLONG; break;
- default:
- panic("invalid akind in mode attribute");
- }
- }
- type = make_atomic_type(akind, type->base.qualifiers);
+ type = handle_mode_attribute(attribute, type);
} else if (attribute->kind == GNU_AK_ALIGNED) {
int alignment = 32; /* TODO: fill in maximum usefull alignment for target machine */
if (attribute->has_arguments)
{
type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
type_modifiers_t modifiers = TYPE_MODIFIER_NONE;
+ unsigned char alignment = 0;
while (true) {
switch (type->kind) {
case TYPE_TYPEDEF: {
qualifiers |= type->base.qualifiers;
modifiers |= type->base.modifiers;
+ if (type->base.alignment > alignment)
+ alignment = type->base.alignment;
+
const typedef_type_t *typedef_type = &type->typedeft;
if (typedef_type->resolved_type != NULL) {
type = typedef_type->resolved_type;
continue;
}
case TYPE_TYPEOF: {
+ qualifiers |= type->base.qualifiers;
+ modifiers |= type->base.modifiers;
+ if (type->base.alignment > alignment)
+ alignment = type->base.alignment;
+
const typeof_type_t *typeof_type = &type->typeoft;
if (typeof_type->typeof_type != NULL) {
type = typeof_type->typeof_type;
break;
}
- if (qualifiers != TYPE_QUALIFIER_NONE || modifiers != TYPE_MODIFIER_NONE) {
+ if (qualifiers != TYPE_QUALIFIER_NONE || modifiers != TYPE_MODIFIER_NONE
+ || (alignment != 0 && alignment > type->base.alignment)) {
type_t *const copy = duplicate_type(type);
/* for const with typedefed array type the element type has to be
element_type = duplicate_type(element_type);
element_type->base.qualifiers |= qualifiers;
element_type->base.modifiers |= modifiers;
+ element_type->base.alignment = alignment;
copy->array.element_type = element_type;
} else {
copy->base.qualifiers |= qualifiers;
copy->base.modifiers |= modifiers;
+ copy->base.alignment = alignment;
}
type = typehash_insert(copy);