- int i;
- for(i = 0; i < GNU_AK_LAST; ++i) {
- if (strcmp_underscore(gnu_attribute_names[i], name) == 0)
- break;
- }
- gnu_attribute_kind_t kind = (gnu_attribute_kind_t)i;
-
- attribute = NULL;
- if (kind == GNU_AK_LAST) {
- if (warning.attribute)
- warningf(HERE, "'%s' attribute directive ignored", name);
-
- /* skip possible arguments */
- if (token.type == '(') {
- eat_until_matching_token(')');
- }
- } else {
- /* check for arguments */
- attribute = allocate_gnu_attribute(kind);
- if (token.type == '(') {
- next_token();
- if (token.type == ')') {
- /* empty args are allowed */
- next_token();
- } else
- attribute->have_arguments = true;
- }
-
- switch (kind) {
- case GNU_AK_VOLATILE:
- case GNU_AK_NAKED:
- case GNU_AK_MALLOC:
- case GNU_AK_WEAK:
- case GNU_AK_COMMON:
- case GNU_AK_NOCOMMON:
- case GNU_AK_SHARED:
- case GNU_AK_NOTSHARED:
- case GNU_AK_NO_INSTRUMENT_FUNCTION:
- case GNU_AK_WARN_UNUSED_RESULT:
- case GNU_AK_LONGCALL:
- case GNU_AK_SHORTCALL:
- case GNU_AK_LONG_CALL:
- case GNU_AK_SHORT_CALL:
- case GNU_AK_FUNCTION_VECTOR:
- case GNU_AK_INTERRUPT_HANDLER:
- case GNU_AK_NMI_HANDLER:
- case GNU_AK_NESTING:
- case GNU_AK_NEAR:
- case GNU_AK_FAR:
- case GNU_AK_SIGNAL:
- case GNU_AK_EIGTHBIT_DATA:
- case GNU_AK_TINY_DATA:
- case GNU_AK_SAVEALL:
- case GNU_AK_FLATTEN:
- case GNU_AK_SSEREGPARM:
- case GNU_AK_EXTERNALLY_VISIBLE:
- case GNU_AK_RETURN_TWICE:
- case GNU_AK_MAY_ALIAS:
- case GNU_AK_MS_STRUCT:
- case GNU_AK_GCC_STRUCT:
- goto no_arg;
-
- case GNU_AK_CDECL: modifiers |= DM_CDECL; goto no_arg;
- case GNU_AK_FASTCALL: modifiers |= DM_FASTCALL; goto no_arg;
- case GNU_AK_STDCALL: modifiers |= DM_STDCALL; goto no_arg;
- case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg;
- case GNU_AK_USED: modifiers |= DM_USED; goto no_arg;
- case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg;
- case GNU_AK_CONST: modifiers |= DM_CONST; goto no_arg;
- case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg;
- case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg;
- case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg;
- case GNU_AK_PACKED: modifiers |= DM_PACKED; goto no_arg;
- case GNU_AK_NOINLINE: modifiers |= DM_NOINLINE; goto no_arg;
- case GNU_AK_NORETURN: modifiers |= DM_NORETURN; goto no_arg;
- case GNU_AK_NOTHROW: modifiers |= DM_NOTHROW; goto no_arg;
- case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg;
- case GNU_AK_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; goto no_arg;
- case GNU_AK_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; goto no_arg;
- case GNU_AK_DEPRECATED: modifiers |= DM_DEPRECATED; goto no_arg;
-
- case GNU_AK_ALIGNED:
- /* __align__ may be used without an argument */
- if (attribute->have_arguments) {
- parse_gnu_attribute_const_arg(attribute);
- }
- break;
-
- case GNU_AK_FORMAT_ARG:
- case GNU_AK_REGPARM:
- case GNU_AK_TRAP_EXIT:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_const_arg(attribute);
- break;
- case GNU_AK_ALIAS:
- case GNU_AK_SECTION:
- case GNU_AK_SP_SWITCH:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
- break;
- case GNU_AK_FORMAT:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_format_args(attribute);
- break;
- case GNU_AK_WEAKREF:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
- break;
- case GNU_AK_NONNULL:
- if (attribute->have_arguments)
- parse_gnu_attribute_const_arg_list(attribute);
- break;
- case GNU_AK_TLS_MODEL:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else
- parse_gnu_attribute_tls_model_arg(attribute);
- break;
- case GNU_AK_VISIBILITY:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else
- parse_gnu_attribute_visibility_arg(attribute);
- break;
- case GNU_AK_MODEL:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else {
- parse_gnu_attribute_model_arg(attribute);
- }
- break;
- case GNU_AK_MODE:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else {
- parse_gnu_attribute_mode_arg(attribute);
- }
- break;
- case GNU_AK_INTERRUPT:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_interrupt_arg(attribute);
- break;
- case GNU_AK_SENTINEL:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_const_arg(attribute);
- break;
- case GNU_AK_LAST:
- /* already handled */
- break;
-
-no_arg:
- check_no_argument(attribute, name);
- }
- }
- if (attribute != NULL) {
- if (last != NULL) {
- last->next = attribute;
- last = attribute;
- } else {
- head = last = attribute;
- }
- }
-
- if (token.type != ',')
- break;
- next_token();
- }
- }
- expect(')');
- expect(')');
-end_error:
- *attributes = head;
-
- return modifiers;
-}
-
-/**
- * Parse GNU attributes.
- */
-static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
-{
- decl_modifiers_t modifiers = 0;
-
- while (true) {
- switch (token.type) {
- case T___attribute__:
- modifiers |= parse_gnu_attribute(attributes);
- continue;
-
- case T_asm:
- next_token();
- expect('(');
- if (token.type != T_STRING_LITERAL) {
- parse_error_expected("while parsing assembler attribute",
- T_STRING_LITERAL, NULL);
- eat_until_matching_token('(');
- break;
- } else {
- parse_string_literals();
- }
- expect(')');
- continue;
-
- case T_cdecl: modifiers |= DM_CDECL; break;
- case T__fastcall: modifiers |= DM_FASTCALL; break;
- case T__stdcall: modifiers |= DM_STDCALL; break;