#include "type_hash.h"
#include "ast_t.h"
#include "entity_t.h"
+#include "attribute_t.h"
#include "lang_features.h"
#include "walk_statements.h"
#include "warning.h"
#include "adt/array.h"
//#define PRINT_TOKENS
-#define MAX_LOOKAHEAD 2
+#define MAX_LOOKAHEAD 1
typedef struct {
entity_t *old_entity;
entity_namespace_t namespc;
} stack_entry_t;
-typedef struct argument_list_t argument_list_t;
-struct argument_list_t {
- long argument;
- argument_list_t *next;
-};
-
-typedef struct gnu_attribute_t gnu_attribute_t;
-struct gnu_attribute_t {
- gnu_attribute_kind_t kind; /**< The kind of the GNU attribute. */
- gnu_attribute_t *next;
- bool invalid; /**< Set if this attribute had argument errors, */
- bool have_arguments; /**< True, if this attribute has arguments. */
- union {
- size_t value;
- string_t string;
- atomic_type_kind_t akind;
- long argument; /**< Single argument. */
- argument_list_t *arguments; /**< List of argument expressions. */
- } u;
-};
-
typedef struct declaration_specifiers_t declaration_specifiers_t;
struct declaration_specifiers_t {
source_position_t source_position;
bool is_inline : 1;
bool thread_local : 1; /**< GCC __thread */
bool deprecated : 1;
- decl_modifiers_t modifiers; /**< declaration modifiers */
- gnu_attribute_t *gnu_attributes; /**< list of GNU attributes */
- const char *deprecated_string; /**< can be set if declaration was marked deprecated. */
- symbol_t *get_property_sym; /**< the name of the get property if set. */
- symbol_t *put_property_sym; /**< the name of the put property if set. */
+ attribute_t *attributes; /**< list of attributes */
type_t *type;
};
bool must_be_constant;
} parse_initializer_env_t;
-/**
- * Capture a MS __base extension.
- */
-typedef struct based_spec_t {
- source_position_t source_position;
- variable_t *base_variable;
-} based_spec_t;
-
typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
/** The current token. */
/** The lookahead ring-buffer. */
static token_t lookahead_buffer[MAX_LOOKAHEAD];
/** Position of the next token in the lookahead buffer. */
-static int lookahead_bufpos;
+static size_t lookahead_bufpos;
static stack_entry_t *environment_stack = NULL;
static stack_entry_t *label_stack = NULL;
static scope_t *file_scope = NULL;
/** special symbol used for anonymous entities. */
static const symbol_t *sym_anonymous = NULL;
-/* symbols for Microsoft extended-decl-modifier */
-static const symbol_t *sym_align = NULL;
-static const symbol_t *sym_allocate = NULL;
-static const symbol_t *sym_dllimport = NULL;
-static const symbol_t *sym_dllexport = NULL;
-static const symbol_t *sym_naked = NULL;
-static const symbol_t *sym_noinline = NULL;
-static const symbol_t *sym_noreturn = NULL;
-static const symbol_t *sym_nothrow = NULL;
-static const symbol_t *sym_novtable = NULL;
-static const symbol_t *sym_property = NULL;
-static const symbol_t *sym_get = NULL;
-static const symbol_t *sym_put = NULL;
-static const symbol_t *sym_selectany = NULL;
-static const symbol_t *sym_thread = NULL;
-static const symbol_t *sym_uuid = NULL;
-static const symbol_t *sym_deprecated = NULL;
-static const symbol_t *sym_restrict = NULL;
-static const symbol_t *sym_noalias = NULL;
-
/** The token anchor set */
static unsigned char token_anchor_set[T_LAST_TOKEN];
/** true if we are in GCC mode. */
#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
-static type_t *type_valist;
-
static statement_t *parse_compound_statement(bool inside_expression_statement);
static statement_t *parse_statement(void);
static void parse_compound_type_entries(compound_t *compound_declaration);
+static void check_call_argument(type_t *expected_type,
+ call_argument_t *argument, unsigned pos);
+
typedef enum declarator_flags_t {
DECL_FLAGS_NONE = 0,
DECL_MAY_BE_ABSTRACT = 1U << 0,
static void semantic_comparison(binary_expression_t *expression);
+static void create_gnu_builtins(void);
+static void create_microsoft_intrinsics(void);
+
#define STORAGE_CLASSES \
STORAGE_CLASSES_NO_EXTERN \
case T_extern:
case T_unsigned: \
case T_void: \
case T_wchar_t: \
+ case T__int8: \
+ case T__int16: \
+ case T__int32: \
+ case T__int64: \
+ case T__int128: \
COMPLEX_SPECIFIERS \
IMAGINARY_SPECIFIERS
case T___FUNCTION__: \
case T___PRETTY_FUNCTION__: \
case T___alignof__: \
- case T___builtin_alloca: \
case T___builtin_classify_type: \
case T___builtin_constant_p: \
- case T___builtin_expect: \
- case T___builtin_huge_val: \
- case T___builtin_inf: \
- case T___builtin_inff: \
- case T___builtin_infl: \
case T___builtin_isgreater: \
case T___builtin_isgreaterequal: \
case T___builtin_isless: \
case T___builtin_islessequal: \
case T___builtin_islessgreater: \
case T___builtin_isunordered: \
- case T___builtin_nan: \
- case T___builtin_nanf: \
- case T___builtin_nanl: \
case T___builtin_offsetof: \
- case T___builtin_prefetch: \
case T___builtin_va_arg: \
- case T___builtin_va_end: \
case T___builtin_va_start: \
+ case T___builtin_va_copy: \
case T___func__: \
case T___noop: \
case T__assume: \
[ENTITY_LOCAL_LABEL] = sizeof(label_t),
[ENTITY_NAMESPACE] = sizeof(namespace_t)
};
- assert(kind < sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
/**
* Allocate an entity of given kind and initialize all
* fields with zero.
+ *
+ * @param kind the kind of the entity to allocate
*/
static entity_t *allocate_entity_zero(entity_kind_t kind)
{
[STATEMENT_COMPOUND] = sizeof(compound_statement_t),
[STATEMENT_RETURN] = sizeof(return_statement_t),
[STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
- [STATEMENT_LOCAL_LABEL] = sizeof(local_label_statement_t),
[STATEMENT_IF] = sizeof(if_statement_t),
[STATEMENT_SWITCH] = sizeof(switch_statement_t),
[STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
[STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
[STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
- assert(kind < sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
static size_t get_expression_struct_size(expression_kind_t kind)
{
static const size_t sizes[] = {
- [EXPR_INVALID] = sizeof(expression_base_t),
- [EXPR_REFERENCE] = sizeof(reference_expression_t),
- [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
- [EXPR_CONST] = sizeof(const_expression_t),
- [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t),
- [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t),
- [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
- [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
- [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
- [EXPR_CALL] = sizeof(call_expression_t),
- [EXPR_UNARY_FIRST] = sizeof(unary_expression_t),
- [EXPR_BINARY_FIRST] = sizeof(binary_expression_t),
- [EXPR_CONDITIONAL] = sizeof(conditional_expression_t),
- [EXPR_SELECT] = sizeof(select_expression_t),
- [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t),
- [EXPR_SIZEOF] = sizeof(typeprop_expression_t),
- [EXPR_ALIGNOF] = sizeof(typeprop_expression_t),
- [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
- [EXPR_FUNCNAME] = sizeof(funcname_expression_t),
- [EXPR_BUILTIN_SYMBOL] = sizeof(builtin_symbol_expression_t),
- [EXPR_BUILTIN_CONSTANT_P] = sizeof(builtin_constant_expression_t),
- [EXPR_BUILTIN_PREFETCH] = sizeof(builtin_prefetch_expression_t),
- [EXPR_OFFSETOF] = sizeof(offsetof_expression_t),
- [EXPR_VA_START] = sizeof(va_start_expression_t),
- [EXPR_VA_ARG] = sizeof(va_arg_expression_t),
- [EXPR_STATEMENT] = sizeof(statement_expression_t),
- [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t),
+ [EXPR_INVALID] = sizeof(expression_base_t),
+ [EXPR_REFERENCE] = sizeof(reference_expression_t),
+ [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
+ [EXPR_CONST] = sizeof(const_expression_t),
+ [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t),
+ [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t),
+ [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
+ [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
+ [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
+ [EXPR_CALL] = sizeof(call_expression_t),
+ [EXPR_UNARY_FIRST] = sizeof(unary_expression_t),
+ [EXPR_BINARY_FIRST] = sizeof(binary_expression_t),
+ [EXPR_CONDITIONAL] = sizeof(conditional_expression_t),
+ [EXPR_SELECT] = sizeof(select_expression_t),
+ [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t),
+ [EXPR_SIZEOF] = sizeof(typeprop_expression_t),
+ [EXPR_ALIGNOF] = sizeof(typeprop_expression_t),
+ [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
+ [EXPR_FUNCNAME] = sizeof(funcname_expression_t),
+ [EXPR_BUILTIN_CONSTANT_P] = sizeof(builtin_constant_expression_t),
+ [EXPR_BUILTIN_TYPES_COMPATIBLE_P] = sizeof(builtin_types_compatible_expression_t),
+ [EXPR_OFFSETOF] = sizeof(offsetof_expression_t),
+ [EXPR_VA_START] = sizeof(va_start_expression_t),
+ [EXPR_VA_ARG] = sizeof(va_arg_expression_t),
+ [EXPR_VA_COPY] = sizeof(va_copy_expression_t),
+ [EXPR_STATEMENT] = sizeof(statement_expression_t),
+ [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t),
};
if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) {
return sizes[EXPR_UNARY_FIRST];
if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
return sizes[EXPR_BINARY_FIRST];
}
- assert(kind < sizeof(sizes) / sizeof(sizes[0]));
+ assert(kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
/**
* Allocate an expression node of given kind and initialize all
* fields with zero.
+ *
+ * @param kind the kind of the expression to allocate
*/
static expression_t *allocate_expression_zero(expression_kind_t kind)
{
[TYPE_TYPEDEF] = sizeof(typedef_type_t),
[TYPE_TYPEOF] = sizeof(typeof_type_t),
};
- assert(sizeof(sizes) / sizeof(sizes[0]) == (int) TYPE_TYPEOF + 1);
+ assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1);
assert(kind <= TYPE_TYPEOF);
assert(sizes[kind] != 0);
return sizes[kind];
return res;
}
+static function_parameter_t *allocate_parameter(type_t *const type)
+{
+ function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param));
+ memset(param, 0, sizeof(*param));
+ param->type = type;
+ return param;
+}
+
/**
* Returns the size of an initializer node.
*
[INITIALIZER_LIST] = sizeof(initializer_list_t),
[INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t)
};
- assert(kind < sizeof(sizes) / sizeof(*sizes));
+ assert(kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
return result;
}
-/**
- * Free a type from the type obstack.
- */
-static void free_type(void *type)
-{
- obstack_free(type_obst, type);
-}
-
/**
* Returns the index of the top element of the environment stack.
*/
lookahead_buffer[lookahead_bufpos] = lexer_token;
lexer_next_token();
- lookahead_bufpos = (lookahead_bufpos+1) % MAX_LOOKAHEAD;
+ lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD;
#ifdef PRINT_TOKENS
print_token(stderr, &token);
/**
* Return the next token with a given lookahead.
*/
-static inline const token_t *look_ahead(int num)
+static inline const token_t *look_ahead(size_t num)
{
- assert(num > 0 && num <= MAX_LOOKAHEAD);
- int pos = (lookahead_bufpos+num-1) % MAX_LOOKAHEAD;
+ assert(0 < num && num <= MAX_LOOKAHEAD);
+ size_t pos = (lookahead_bufpos + num - 1) % MAX_LOOKAHEAD;
return &lookahead_buffer[pos];
}
next_token();
}
-#define eat(token_type) do { assert(token.type == (token_type)); next_token(); } while (0)
+#define eat(token_type) (assert(token.type == (token_type)), next_token())
/**
* Report a parse error because an expected token was not found.
return NULL;
}
+/* §6.2.3:1 24) There is only one name space for tags even though three are
+ * possible. */
+static entity_t *get_tag(symbol_t const *const symbol,
+ entity_kind_tag_t const kind)
+{
+ entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
+ if (entity != NULL && entity->kind != kind) {
+ errorf(HERE,
+ "'%Y' defined as wrong kind of tag (previous definition %P)",
+ symbol, &entity->base.source_position);
+ entity = NULL;
+ }
+ return entity;
+}
+
/**
* pushs an entity on the environment stack and links the corresponding symbol
* it.
static int get_rank(const type_t *type)
{
assert(!is_typeref(type));
- /* The C-standard allows promoting enums to int or unsigned int (see § 7.2.2
- * and esp. footnote 108). However we can't fold constants (yet), so we
- * can't decide whether unsigned int is possible, while int always works.
- * (unsigned int would be preferable when possible... for stuff like
- * struct { enum { ... } bla : 4; } ) */
if (type->kind == TYPE_ENUM)
- return get_akind_rank(ATOMIC_TYPE_INT);
+ return get_akind_rank(type->enumt.akind);
assert(type->kind == TYPE_ATOMIC);
return get_akind_rank(type->atomic.akind);
}
/**
- * Do integer promotion for a given type.
+ * §6.3.1.1:2 Do integer promotion for a given type.
*
* @param type the type to promote
* @return the promoted type
static bool is_null_pointer_constant(const expression_t *expression)
{
/* skip void* cast */
- if (expression->kind == EXPR_UNARY_CAST
- || expression->kind == EXPR_UNARY_CAST_IMPLICIT) {
- expression = expression->unary.value;
+ if (expression->kind == EXPR_UNARY_CAST ||
+ expression->kind == EXPR_UNARY_CAST_IMPLICIT) {
+ type_t *const type = skip_typeref(expression->base.type);
+ if (types_compatible(type, type_void_ptr))
+ expression = expression->unary.value;
}
- /* TODO: not correct yet, should be any constant integer expression
- * which evaluates to 0 */
- if (expression->kind != EXPR_CONST)
- return false;
-
type_t *const type = skip_typeref(expression->base.type);
- if (!is_type_integer(type))
- return false;
-
- return expression->conste.v.int_value == 0;
+ return
+ is_type_integer(type) &&
+ is_constant_expression(expression) &&
+ fold_constant(expression) == 0;
}
/**
}
}
-/** Implements the rules from § 6.5.16.1 */
+/** Implements the rules from §6.5.16.1 */
static assign_error_t semantic_assign(type_t *orig_type_left,
const expression_t *const right)
{
return result;
}
-static const char *const gnu_attribute_names[GNU_AK_LAST] = {
- [GNU_AK_CONST] = "const",
- [GNU_AK_VOLATILE] = "volatile",
- [GNU_AK_CDECL] = "cdecl",
- [GNU_AK_STDCALL] = "stdcall",
- [GNU_AK_FASTCALL] = "fastcall",
- [GNU_AK_DEPRECATED] = "deprecated",
- [GNU_AK_NOINLINE] = "noinline",
- [GNU_AK_NORETURN] = "noreturn",
- [GNU_AK_NAKED] = "naked",
- [GNU_AK_PURE] = "pure",
- [GNU_AK_ALWAYS_INLINE] = "always_inline",
- [GNU_AK_MALLOC] = "malloc",
- [GNU_AK_WEAK] = "weak",
- [GNU_AK_CONSTRUCTOR] = "constructor",
- [GNU_AK_DESTRUCTOR] = "destructor",
- [GNU_AK_NOTHROW] = "nothrow",
- [GNU_AK_TRANSPARENT_UNION] = "transparent_union",
- [GNU_AK_COMMON] = "common",
- [GNU_AK_NOCOMMON] = "nocommon",
- [GNU_AK_PACKED] = "packed",
- [GNU_AK_SHARED] = "shared",
- [GNU_AK_NOTSHARED] = "notshared",
- [GNU_AK_USED] = "used",
- [GNU_AK_UNUSED] = "unused",
- [GNU_AK_NO_INSTRUMENT_FUNCTION] = "no_instrument_function",
- [GNU_AK_WARN_UNUSED_RESULT] = "warn_unused_result",
- [GNU_AK_LONGCALL] = "longcall",
- [GNU_AK_SHORTCALL] = "shortcall",
- [GNU_AK_LONG_CALL] = "long_call",
- [GNU_AK_SHORT_CALL] = "short_call",
- [GNU_AK_FUNCTION_VECTOR] = "function_vector",
- [GNU_AK_INTERRUPT] = "interrupt",
- [GNU_AK_INTERRUPT_HANDLER] = "interrupt_handler",
- [GNU_AK_NMI_HANDLER] = "nmi_handler",
- [GNU_AK_NESTING] = "nesting",
- [GNU_AK_NEAR] = "near",
- [GNU_AK_FAR] = "far",
- [GNU_AK_SIGNAL] = "signal",
- [GNU_AK_EIGTHBIT_DATA] = "eightbit_data",
- [GNU_AK_TINY_DATA] = "tiny_data",
- [GNU_AK_SAVEALL] = "saveall",
- [GNU_AK_FLATTEN] = "flatten",
- [GNU_AK_SSEREGPARM] = "sseregparm",
- [GNU_AK_EXTERNALLY_VISIBLE] = "externally_visible",
- [GNU_AK_RETURN_TWICE] = "return_twice",
- [GNU_AK_MAY_ALIAS] = "may_alias",
- [GNU_AK_MS_STRUCT] = "ms_struct",
- [GNU_AK_GCC_STRUCT] = "gcc_struct",
- [GNU_AK_DLLIMPORT] = "dllimport",
- [GNU_AK_DLLEXPORT] = "dllexport",
- [GNU_AK_ALIGNED] = "aligned",
- [GNU_AK_ALIAS] = "alias",
- [GNU_AK_SECTION] = "section",
- [GNU_AK_FORMAT] = "format",
- [GNU_AK_FORMAT_ARG] = "format_arg",
- [GNU_AK_WEAKREF] = "weakref",
- [GNU_AK_NONNULL] = "nonnull",
- [GNU_AK_TLS_MODEL] = "tls_model",
- [GNU_AK_VISIBILITY] = "visibility",
- [GNU_AK_REGPARM] = "regparm",
- [GNU_AK_MODE] = "mode",
- [GNU_AK_MODEL] = "model",
- [GNU_AK_TRAP_EXIT] = "trap_exit",
- [GNU_AK_SP_SWITCH] = "sp_switch",
- [GNU_AK_SENTINEL] = "sentinel"
-};
-
/**
* compare two string, ignoring double underscores on the second.
*/
return strcmp(s1, s2);
}
-/**
- * Allocate a new gnu temporal attribute of given kind.
- */
-static gnu_attribute_t *allocate_gnu_attribute(gnu_attribute_kind_t kind)
+static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
- gnu_attribute_t *attribute = obstack_alloc(&temp_obst, sizeof(*attribute));
- attribute->kind = kind;
- attribute->next = NULL;
- attribute->invalid = false;
- attribute->have_arguments = false;
-
+ attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
+ attribute->kind = kind;
return attribute;
}
/**
- * Parse one constant expression argument of the given attribute.
+ * Parse (gcc) attribute argument. From gcc comments in gcc source:
+ *
+ * attribute:
+ * __attribute__ ( ( attribute-list ) )
+ *
+ * attribute-list:
+ * attrib
+ * attribute_list , attrib
+ *
+ * attrib:
+ * empty
+ * any-word
+ * any-word ( identifier )
+ * any-word ( identifier , nonempty-expr-list )
+ * any-word ( expr-list )
+ *
+ * where the "identifier" must not be declared as a type, and
+ * "any-word" may be any identifier (including one declared as a
+ * type), a reserved word storage class specifier, type specifier or
+ * type qualifier. ??? This still leaves out most reserved keywords
+ * (following the old parser), shouldn't we include them, and why not
+ * allow identifiers declared as types to start the arguments?
+ *
+ * Matze: this all looks confusing and little systematic, so we're even less
+ * strict and parse any list of things which are identifiers or
+ * (assignment-)expressions.
*/
-static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute)
+static attribute_argument_t *parse_attribute_arguments(void)
{
- expression_t *expression;
- add_anchor_token(')');
- expression = parse_constant_expression();
- rem_anchor_token(')');
- expect(')', end_error);
- attribute->u.argument = fold_constant(expression);
- return;
-end_error:
- attribute->invalid = true;
-}
+ if (token.type == ')')
+ return NULL;
-/**
- * Parse a list of constant expressions arguments of the given attribute.
- */
-static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute)
-{
- argument_list_t **list = &attribute->u.arguments;
- argument_list_t *entry;
- expression_t *expression;
- add_anchor_token(')');
- add_anchor_token(',');
+ attribute_argument_t *first = NULL;
+ attribute_argument_t *last = NULL;
while (true) {
- expression = parse_constant_expression();
- entry = obstack_alloc(&temp_obst, sizeof(entry));
- entry->argument = fold_constant(expression);
- entry->next = NULL;
- *list = entry;
- list = &entry->next;
- if (token.type != ',')
- break;
- next_token();
- }
- rem_anchor_token(',');
- rem_anchor_token(')');
- expect(')', end_error);
- return;
-end_error:
- attribute->invalid = true;
-}
-
-/**
- * Parse one string literal argument of the given attribute.
- */
-static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute,
- string_t *string)
-{
- add_anchor_token('(');
- if (token.type != T_STRING_LITERAL) {
- parse_error_expected("while parsing attribute directive",
- T_STRING_LITERAL, NULL);
- goto end_error;
- }
- *string = parse_string_literals();
- rem_anchor_token('(');
- expect(')', end_error);
- return;
-end_error:
- attribute->invalid = true;
-}
+ attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
+
+ /* is it an identifier */
+ if (token.type == T_IDENTIFIER
+ && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) {
+ symbol_t *symbol = token.v.symbol;
+ argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL;
+ argument->v.symbol = symbol;
+ next_token();
+ } else {
+ /* must be an expression */
+ expression_t *expression = parse_assignment_expression();
-/**
- * Parse one tls model of the given attribute.
- */
-static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
-{
- static const char *const tls_models[] = {
- "global-dynamic",
- "local-dynamic",
- "initial-exec",
- "local-exec"
- };
- string_t string = { NULL, 0 };
- parse_gnu_attribute_string_arg(attribute, &string);
- if (string.begin != NULL) {
- for (size_t i = 0; i < 4; ++i) {
- if (strcmp(tls_models[i], string.begin) == 0) {
- attribute->u.value = i;
- return;
- }
+ argument->kind = ATTRIBUTE_ARGUMENT_EXPRESSION;
+ argument->v.expression = expression;
}
- errorf(HERE, "'%s' is an unrecognized tls model", string.begin);
- }
- attribute->invalid = true;
-}
-/**
- * Parse one tls model of the given attribute.
- */
-static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute)
-{
- static const char *const visibilities[] = {
- "default",
- "protected",
- "hidden",
- "internal"
- };
- string_t string = { NULL, 0 };
- parse_gnu_attribute_string_arg(attribute, &string);
- if (string.begin != NULL) {
- for (size_t i = 0; i < 4; ++i) {
- if (strcmp(visibilities[i], string.begin) == 0) {
- attribute->u.value = i;
- return;
- }
+ /* append argument */
+ if (last == NULL) {
+ first = argument;
+ } else {
+ last->next = argument;
}
- errorf(HERE, "'%s' is an unrecognized visibility", string.begin);
- }
- attribute->invalid = true;
-}
+ last = argument;
-/**
- * Parse one (code) model of the given attribute.
- */
-static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute)
-{
- static const char *const visibilities[] = {
- "small",
- "medium",
- "large"
- };
- string_t string = { NULL, 0 };
- parse_gnu_attribute_string_arg(attribute, &string);
- if (string.begin != NULL) {
- for (int i = 0; i < 3; ++i) {
- if (strcmp(visibilities[i], string.begin) == 0) {
- attribute->u.value = i;
- return;
- }
+ if (token.type == ',') {
+ next_token();
+ continue;
}
- errorf(HERE, "'%s' is an unrecognized model", string.begin);
+ expect(')', end_error);
+ break;
}
- attribute->invalid = true;
+
+ return first;
+
+end_error:
+ /* TODO... */
+ return first;
}
-/**
- * Parse one mode of the given attribute.
- */
-static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_asm(void)
{
- /* TODO: find out what is allowed here... */
+ eat(T_asm);
- /* at least: byte, word, pointer, list of machine modes
- * __XXX___ is interpreted as XXX */
- add_anchor_token(')');
+ attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
- if (token.type != T_IDENTIFIER) {
- expect(T_IDENTIFIER, end_error);
- }
-
- /* This isn't really correct, the backend should provide a list of machine
- * specific modes (according to gcc philosophy that is...) */
- const char *symbol_str = token.v.symbol->string;
- if (strcmp_underscore("QI", symbol_str) == 0 ||
- strcmp_underscore("byte", symbol_str) == 0) {
- attribute->u.akind = ATOMIC_TYPE_CHAR;
- } else if (strcmp_underscore("HI", symbol_str) == 0) {
- attribute->u.akind = ATOMIC_TYPE_SHORT;
- } else if (strcmp_underscore("SI", symbol_str) == 0
- || strcmp_underscore("word", symbol_str) == 0
- || strcmp_underscore("pointer", symbol_str) == 0) {
- attribute->u.akind = ATOMIC_TYPE_INT;
- } else if (strcmp_underscore("DI", symbol_str) == 0) {
- attribute->u.akind = ATOMIC_TYPE_LONGLONG;
- } else {
- if (warning.other)
- warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
- attribute->invalid = true;
- }
- next_token();
+ expect('(', end_error);
+ attribute->a.arguments = parse_attribute_arguments();
+ return attribute;
- rem_anchor_token(')');
- expect(')', end_error);
- return;
end_error:
- attribute->invalid = true;
+ return NULL;
}
-/**
- * Parse one interrupt argument of the given attribute.
- */
-static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
+static symbol_t *get_symbol_from_token(void)
{
- static const char *const interrupts[] = {
- "IRQ",
- "FIQ",
- "SWI",
- "ABORT",
- "UNDEF"
- };
- string_t string = { NULL, 0 };
- parse_gnu_attribute_string_arg(attribute, &string);
- if (string.begin != NULL) {
- for (size_t i = 0; i < 5; ++i) {
- if (strcmp(interrupts[i], string.begin) == 0) {
- attribute->u.value = i;
- return;
- }
- }
- errorf(HERE, "'%s' is not an interrupt", string.begin);
+ switch(token.type) {
+ case T_IDENTIFIER:
+ case T_auto:
+ case T_char:
+ case T_double:
+ case T_enum:
+ case T_extern:
+ case T_float:
+ case T_int:
+ case T_long:
+ case T_register:
+ case T_short:
+ case T_static:
+ case T_struct:
+ case T_union:
+ case T_unsigned:
+ case T_void:
+ case T_bool:
+ case T__Bool:
+ case T_class:
+ case T_explicit:
+ case T_export:
+ case T_wchar_t:
+ case T_const:
+ case T_signed:
+ case T___real__:
+ case T___imag__:
+ case T_restrict:
+ case T_volatile:
+ case T_inline:
+ /* maybe we need more tokens ... add them on demand */
+ return token.v.symbol;
+ default:
+ return NULL;
}
- attribute->invalid = true;
}
-/**
- * Parse ( identifier, const expression, const expression )
- */
-static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_gnu_single(void)
{
- static const char *const format_names[] = {
- "printf",
- "scanf",
- "strftime",
- "strfmon"
- };
- int i;
-
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing format attribute directive", T_IDENTIFIER, NULL);
+ /* parse "any-word" */
+ symbol_t *symbol = get_symbol_from_token();
+ if (symbol == NULL) {
+ parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
goto end_error;
}
- const char *name = token.v.symbol->string;
- for (i = 0; i < 4; ++i) {
- if (strcmp_underscore(format_names[i], name) == 0)
+
+ const char *name = symbol->string;
+ next_token();
+
+ attribute_kind_t kind;
+ for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) {
+ const char *attribute_name = get_attribute_name(kind);
+ if (attribute_name != NULL
+ && strcmp_underscore(attribute_name, name) == 0)
break;
}
- if (i >= 4) {
- if (warning.attribute)
- warningf(HERE, "'%s' is an unrecognized format function type", name);
+
+ if (kind >= ATTRIBUTE_GNU_LAST) {
+ if (warning.attribute) {
+ warningf(HERE, "unknown attribute '%s' ignored", name);
+ }
+ /* TODO: we should still save the attribute in the list... */
+ kind = ATTRIBUTE_UNKNOWN;
}
- next_token();
- expect(',', end_error);
- add_anchor_token(')');
- add_anchor_token(',');
- parse_constant_expression();
- rem_anchor_token(',');
- rem_anchor_token(')');
+ attribute_t *attribute = allocate_attribute_zero(kind);
- expect(',', end_error);
- add_anchor_token(')');
- parse_constant_expression();
- rem_anchor_token(')');
- expect(')', end_error);
- return;
-end_error:
- attribute->u.value = true;
-}
+ /* parse arguments */
+ if (token.type == '(') {
+ next_token();
+ attribute->a.arguments = parse_attribute_arguments();
+ }
-/**
- * Check that a given GNU attribute has no arguments.
- */
-static void check_no_argument(gnu_attribute_t *attribute, const char *name)
-{
- if (!attribute->have_arguments)
- return;
+ return attribute;
- /* should have no arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- eat_until_matching_token('(');
- /* we have already consumed '(', so we stop before ')', eat it */
- eat(')');
- attribute->invalid = true;
+end_error:
+ return NULL;
}
-/**
- * Parse one GNU attribute.
- *
- * Note that attribute names can be specified WITH or WITHOUT
- * double underscores, ie const or __const__.
- *
- * The following attributes are parsed without arguments
- * const
- * volatile
- * cdecl
- * stdcall
- * fastcall
- * deprecated
- * noinline
- * noreturn
- * naked
- * pure
- * always_inline
- * malloc
- * weak
- * constructor
- * destructor
- * nothrow
- * transparent_union
- * common
- * nocommon
- * packed
- * shared
- * notshared
- * used
- * unused
- * no_instrument_function
- * warn_unused_result
- * longcall
- * shortcall
- * long_call
- * short_call
- * function_vector
- * interrupt_handler
- * nmi_handler
- * nesting
- * near
- * far
- * signal
- * eightbit_data
- * tiny_data
- * saveall
- * flatten
- * sseregparm
- * externally_visible
- * return_twice
- * may_alias
- * ms_struct
- * gcc_struct
- * dllimport
- * dllexport
- *
- * The following attributes are parsed with arguments
- * aligned( const expression )
- * alias( string literal )
- * section( string literal )
- * format( identifier, const expression, const expression )
- * format_arg( const expression )
- * tls_model( string literal )
- * visibility( string literal )
- * regparm( const expression )
- * model( string leteral )
- * trap_exit( const expression )
- * sp_switch( string literal )
- *
- * The following attributes might have arguments
- * weak_ref( string literal )
- * non_null( const expression // ',' )
- * interrupt( string literal )
- * sentinel( constant expression )
- */
-static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
+static attribute_t *parse_attribute_gnu(void)
{
- gnu_attribute_t *head = *attributes;
- gnu_attribute_t *last = *attributes;
- decl_modifiers_t modifiers = 0;
- gnu_attribute_t *attribute;
+ attribute_t *first = NULL;
+ attribute_t *last = NULL;
eat(T___attribute__);
expect('(', end_error);
expect('(', end_error);
- if (token.type != ')') {
- /* find the end of the list */
- if (last != NULL) {
- while (last->next != NULL)
- last = last->next;
- }
-
- /* non-empty attribute list */
- while (true) {
- const char *name;
- if (token.type == T_const) {
- name = "const";
- } else if (token.type == T_volatile) {
- name = "volatile";
- } else if (token.type == T_cdecl) {
- /* __attribute__((cdecl)), WITH ms mode */
- name = "cdecl";
- } else if (token.type == T_IDENTIFIER) {
- const symbol_t *sym = token.v.symbol;
- name = sym->string;
- } else {
- parse_error_expected("while parsing GNU attribute", T_IDENTIFIER, NULL);
- break;
- }
-
- next_token();
-
- 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;
+ if (token.type == ')') {
+ next_token();
+ expect(')', end_error);
+ return first;
+ }
- 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;
+ while (true) {
+ attribute_t *attribute = parse_attribute_gnu_single();
+ if (attribute == NULL)
+ goto end_error;
-no_arg:
- check_no_argument(attribute, name);
- }
- }
- if (attribute != NULL) {
- if (last != NULL) {
- last->next = attribute;
- last = attribute;
- } else {
- head = last = attribute;
- }
- }
+ if (last == NULL) {
+ first = attribute;
+ } else {
+ last->next = attribute;
+ }
+ last = attribute;
- if (token.type != ',')
- break;
+ if (token.type == ')') {
next_token();
+ break;
}
+ expect(',', end_error);
}
expect(')', end_error);
- expect(')', end_error);
-end_error:
- *attributes = head;
- return modifiers;
+end_error:
+ return first;
}
-/**
- * Parse GNU attributes.
- */
-static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
+/** Parse attributes. */
+static attribute_t *parse_attributes(attribute_t *first)
{
- decl_modifiers_t modifiers = 0;
-
+ attribute_t *last = first;
while (true) {
+ if (last != NULL) {
+ while (last->next != NULL)
+ last = last->next;
+ }
+
+ attribute_t *attribute;
switch (token.type) {
case T___attribute__:
- modifiers |= parse_gnu_attribute(attributes);
- continue;
+ attribute = parse_attribute_gnu();
+ break;
case T_asm:
+ attribute = parse_attribute_asm();
+ break;
+
+ case T_cdecl:
next_token();
- expect('(', end_error);
- 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(')', end_error);
- continue;
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+ break;
+
+ case T__fastcall:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+ break;
- case T_cdecl: modifiers |= DM_CDECL; break;
- case T__fastcall: modifiers |= DM_FASTCALL; break;
- case T__stdcall: modifiers |= DM_STDCALL; break;
+ case T__forceinline:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+ break;
+
+ case T__stdcall:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+ break;
case T___thiscall:
+ next_token();
/* TODO record modifier */
if (warning.other)
warningf(HERE, "Ignoring declaration modifier %K", &token);
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
break;
-end_error:
- default: return modifiers;
+ default:
+ return first;
}
- next_token();
+ if (last == NULL) {
+ first = attribute;
+ } else {
+ last->next = attribute;
+ }
+ last = attribute;
}
}
mark_vars_read(expr->va_arge.ap, lhs_ent);
return;
+ case EXPR_VA_COPY:
+ mark_vars_read(expr->va_copye.src, lhs_ent);
+ return;
+
case EXPR_UNARY_CAST:
/* Special case: Use void cast to mark a variable as "read" */
if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
case EXPR_CLASSIFY_TYPE:
case EXPR_ALIGNOF:
case EXPR_FUNCNAME:
- case EXPR_BUILTIN_SYMBOL:
case EXPR_BUILTIN_CONSTANT_P:
- case EXPR_BUILTIN_PREFETCH:
+ case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
{
/* TODO check that expression is a constant expression */
- /* § 6.7.8.14/15 char array may be initialized by string literals */
+ /* §6.7.8.14/15 char array may be initialized by string literals */
type_t *type = skip_typeref(orig_type);
type_t *expr_type_orig = expression->base.type;
type_t *expr_type = skip_typeref(expr_type_orig);
return initializer_from_string(array_type,
&expression->string.value);
}
+ break;
case EXPR_WIDE_STRING_LITERAL: {
type_t *bare_wchar_type = skip_typeref(type_wchar_t);
return initializer_from_wide_string(array_type,
&expression->wide_string.value);
}
+ break;
}
default:
/**
* Parses an scalar initializer.
*
- * § 6.7.8.11; eat {} without warning
+ * §6.7.8.11; eat {} without warning
*/
static initializer_t *parse_scalar_initializer(type_t *type,
bool must_be_constant)
}
}
-/**
- * skip until token is found.
- */
-static void skip_until(int type)
-{
- while (token.type != type) {
- if (token.type == T_EOF)
- return;
- next_token();
- }
-}
-
/**
* skip any {...} blocks until a closing bracket is reached.
*/
} else {
/* must be an expression */
expression_t *expression = parse_assignment_expression();
+ mark_vars_read(expression, NULL);
if (env->must_be_constant && !is_initializer_constant(expression)) {
errorf(&expression->base.source_position,
result = parse_scalar_initializer(type, env->must_be_constant);
}
- /* § 6.7.8 (22) array initializers for arrays with unknown size determine
+ /* §6.7.8:22 array initializers for arrays with unknown size determine
* the array type size */
if (is_type_array(type) && type->array.size_expression == NULL
&& result != NULL) {
static compound_t *parse_compound_type_specifier(bool is_struct)
{
- gnu_attribute_t *attributes = NULL;
- decl_modifiers_t modifiers = 0;
if (is_struct) {
eat(T_struct);
} else {
compound_t *compound = NULL;
if (token.type == T___attribute__) {
- modifiers |= parse_attributes(&attributes);
+ parse_attributes(NULL);
}
+ entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
if (token.type == T_IDENTIFIER) {
+ /* the compound has a name, check if we have seen it already */
symbol = token.v.symbol;
next_token();
- namespace_tag_t const namespc =
- is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION;
- entity_t *entity = get_entity(symbol, namespc);
+ entity_t *entity = get_tag(symbol, kind);
if (entity != NULL) {
- assert(entity->kind == (is_struct ? ENTITY_STRUCT : ENTITY_UNION));
compound = &entity->compound;
if (compound->base.parent_scope != current_scope &&
(token.type == '{' || token.type == ';')) {
- /* we're in an inner scope and have a definition. Override
- existing definition in outer scope */
+ /* we're in an inner scope and have a definition. Shadow
+ * existing definition in outer scope */
compound = NULL;
} else if (compound->complete && token.type == '{') {
assert(symbol != NULL);
}
if (compound == NULL) {
- entity_kind_t kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
- entity_t *entity = allocate_entity_zero(kind);
- compound = &entity->compound;
+ entity_t *entity = allocate_entity_zero(kind);
+ compound = &entity->compound;
- compound->base.namespc =
- (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
+ compound->base.namespc = NAMESPACE_TAG;
compound->base.source_position = token.source_position;
compound->base.symbol = symbol;
compound->base.parent_scope = current_scope;
if (token.type == '{') {
parse_compound_type_entries(compound);
- modifiers |= parse_attributes(&attributes);
+ parse_attributes(NULL);
+ /* ISO/IEC 14882:1998(E) §7.1.3:5 */
if (symbol == NULL) {
assert(anonymous_entity == NULL);
anonymous_entity = (entity_t*)compound;
}
}
- compound->modifiers |= modifiers;
return compound;
}
static type_t *parse_enum_specifier(void)
{
- gnu_attribute_t *attributes = NULL;
entity_t *entity;
symbol_t *symbol;
symbol = token.v.symbol;
next_token();
- entity = get_entity(symbol, NAMESPACE_ENUM);
- assert(entity == NULL || entity->kind == ENTITY_ENUM);
+ entity = get_tag(symbol, ENTITY_ENUM);
+ if (entity != NULL) {
+ if (entity->base.parent_scope != current_scope &&
+ (token.type == '{' || token.type == ';')) {
+ /* we're in an inner scope and have a definition. Shadow
+ * existing definition in outer scope */
+ entity = NULL;
+ } else if (entity->enume.complete && token.type == '{') {
+ errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
+ symbol, &entity->base.source_position);
+ }
+ }
} else if (token.type != '{') {
parse_error_expected("while parsing enum type specifier",
T_IDENTIFIER, '{', NULL);
if (entity == NULL) {
entity = allocate_entity_zero(ENTITY_ENUM);
- entity->base.namespc = NAMESPACE_ENUM;
+ entity->base.namespc = NAMESPACE_TAG;
entity->base.source_position = token.source_position;
entity->base.symbol = symbol;
entity->base.parent_scope = current_scope;
type_t *const type = allocate_type_zero(TYPE_ENUM);
type->enumt.enume = &entity->enume;
+ type->enumt.akind = ATOMIC_TYPE_INT;
if (token.type == '{') {
- if (entity->enume.complete) {
- errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
- symbol, &entity->base.source_position);
- }
if (symbol != NULL) {
environment_push(entity);
}
entity->enume.complete = true;
parse_enum_entries(type);
- parse_attributes(&attributes);
+ parse_attributes(NULL);
+ /* ISO/IEC 14882:1998(E) §7.1.3:5 */
if (symbol == NULL) {
assert(anonymous_entity == NULL);
anonymous_entity = entity;
type = parse_typename();
} else {
expression = parse_expression();
- type = expression->base.type;
+ type = revert_automatic_type_conversion(expression);
}
break;
type_t *type = allocate_type_zero(TYPE_BUILTIN);
type->builtin.symbol = symbol;
type->builtin.real_type = real_type;
-
- type_t *result = typehash_insert(type);
- if (type != result) {
- free_type(type);
- }
-
- return result;
+ return identify_new_type(type);
}
static type_t *get_typedef_type(symbol_t *symbol)
return type;
}
-/**
- * check for the allowed MS alignment values.
- */
-static bool check_alignment_value(long long intvalue)
+static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
{
- if (intvalue < 1 || intvalue > 8192) {
- errorf(HERE, "illegal alignment value");
- return false;
- }
- unsigned v = (unsigned)intvalue;
- for (unsigned i = 1; i <= 8192; i += i) {
- if (i == v)
- return true;
+ expect('(', end_error);
+
+ attribute_property_argument_t *property
+ = allocate_ast_zero(sizeof(*property));
+
+ while (true) {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing property declspec",
+ T_IDENTIFIER, NULL);
+ goto end_error;
+ }
+
+ bool is_put;
+ symbol_t *symbol = token.v.symbol;
+ next_token();
+ if (strcmp(symbol->string, "put") == 0) {
+ is_put = true;
+ } else if (strcmp(symbol->string, "get") == 0) {
+ is_put = false;
+ } else {
+ errorf(HERE, "expected put or get in property declspec");
+ goto end_error;
+ }
+ expect('=', end_error);
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing property declspec",
+ T_IDENTIFIER, NULL);
+ goto end_error;
+ }
+ if (is_put) {
+ property->put_symbol = token.v.symbol;
+ } else {
+ property->get_symbol = token.v.symbol;
+ }
+ next_token();
+ if (token.type == ')')
+ break;
+ expect(',', end_error);
}
- errorf(HERE, "alignment must be power of two");
- return false;
+
+ attribute->a.property = property;
+
+ expect(')', end_error);
+
+end_error:
+ return attribute;
}
-#define DET_MOD(name, tag) do { \
- if (*modifiers & tag && warning.other) warningf(HERE, #name " used more than once"); \
- *modifiers |= tag; \
-} while (0)
+static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
+{
+ attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
+ if (token.type == T_restrict) {
+ kind = ATTRIBUTE_MS_RESTRICT;
+ next_token();
+ } else if (token.type == T_IDENTIFIER) {
+ const char *name = token.v.symbol->string;
+ next_token();
+ for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
+ ++k) {
+ const char *attribute_name = get_attribute_name(k);
+ if (attribute_name != NULL && strcmp(attribute_name, name) == 0) {
+ kind = k;
+ break;
+ }
+ }
+
+ if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) {
+ warningf(HERE, "unknown __declspec '%s' ignored", name);
+ }
+ } else {
+ parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
+ return NULL;
+ }
+
+ attribute_t *attribute = allocate_attribute_zero(kind);
+
+ if (kind == ATTRIBUTE_MS_PROPERTY) {
+ return parse_attribute_ms_property(attribute);
+ }
-static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers)
+ /* parse arguments */
+ if (token.type == '(') {
+ next_token();
+ attribute->a.arguments = parse_attribute_arguments();
+ }
+
+ return attribute;
+}
+
+static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
{
- decl_modifiers_t *modifiers = &specifiers->modifiers;
+ eat(T__declspec);
+
+ expect('(', end_error);
+
+ if (token.type == ')') {
+ next_token();
+ return NULL;
+ }
+
+ add_anchor_token(')');
+ attribute_t *last = first;
while (true) {
- if (token.type == T_restrict) {
- next_token();
- DET_MOD(restrict, DM_RESTRICT);
- goto end_loop;
- } else if (token.type != T_IDENTIFIER)
- break;
- symbol_t *symbol = token.v.symbol;
- if (symbol == sym_align) {
- next_token();
- expect('(', end_error);
- if (token.type != T_INTEGER)
- goto end_error;
- if (check_alignment_value(token.v.intvalue)) {
- if (specifiers->alignment != 0 && warning.other)
- warningf(HERE, "align used more than once");
- specifiers->alignment = (unsigned char)token.v.intvalue;
- }
- next_token();
- expect(')', end_error);
- } else if (symbol == sym_allocate) {
- next_token();
- expect('(', end_error);
- if (token.type != T_IDENTIFIER)
- goto end_error;
- (void)token.v.symbol;
- expect(')', end_error);
- } else if (symbol == sym_dllimport) {
- next_token();
- DET_MOD(dllimport, DM_DLLIMPORT);
- } else if (symbol == sym_dllexport) {
- next_token();
- DET_MOD(dllexport, DM_DLLEXPORT);
- } else if (symbol == sym_thread) {
- next_token();
- DET_MOD(thread, DM_THREAD);
- } else if (symbol == sym_naked) {
- next_token();
- DET_MOD(naked, DM_NAKED);
- } else if (symbol == sym_noinline) {
- next_token();
- DET_MOD(noinline, DM_NOINLINE);
- } else if (symbol == sym_noreturn) {
- next_token();
- DET_MOD(noreturn, DM_NORETURN);
- } else if (symbol == sym_nothrow) {
- next_token();
- DET_MOD(nothrow, DM_NOTHROW);
- } else if (symbol == sym_novtable) {
- next_token();
- DET_MOD(novtable, DM_NOVTABLE);
- } else if (symbol == sym_property) {
- next_token();
- expect('(', end_error);
- for (;;) {
- bool is_get = false;
- if (token.type != T_IDENTIFIER)
- goto end_error;
- if (token.v.symbol == sym_get) {
- is_get = true;
- } else if (token.v.symbol == sym_put) {
- } else {
- errorf(HERE, "Bad property name '%Y'", token.v.symbol);
- goto end_error;
- }
- next_token();
- expect('=', end_error);
- if (token.type != T_IDENTIFIER)
- goto end_error;
- if (is_get) {
- if (specifiers->get_property_sym != NULL) {
- errorf(HERE, "get property name already specified");
- } else {
- specifiers->get_property_sym = token.v.symbol;
- }
- } else {
- if (specifiers->put_property_sym != NULL) {
- errorf(HERE, "put property name already specified");
- } else {
- specifiers->put_property_sym = token.v.symbol;
- }
- }
- next_token();
- if (token.type == ',') {
- next_token();
- continue;
- }
- break;
- }
- expect(')', end_error);
- } else if (symbol == sym_selectany) {
- next_token();
- DET_MOD(selectany, DM_SELECTANY);
- } else if (symbol == sym_uuid) {
- next_token();
- expect('(', end_error);
- if (token.type != T_STRING_LITERAL)
- goto end_error;
- next_token();
- expect(')', end_error);
- } else if (symbol == sym_deprecated) {
- next_token();
- if (specifiers->deprecated != 0 && warning.other)
- warningf(HERE, "deprecated used more than once");
- specifiers->deprecated = true;
- if (token.type == '(') {
- next_token();
- if (token.type == T_STRING_LITERAL) {
- specifiers->deprecated_string = token.v.string.begin;
- next_token();
- } else {
- errorf(HERE, "string literal expected");
- }
- expect(')', end_error);
- }
- } else if (symbol == sym_noalias) {
- next_token();
- DET_MOD(noalias, DM_NOALIAS);
+ if (last != NULL) {
+ while (last->next != NULL)
+ last = last->next;
+ }
+
+ attribute_t *attribute
+ = parse_microsoft_extended_decl_modifier_single();
+ if (attribute == NULL)
+ goto end_error;
+
+ if (last == NULL) {
+ first = attribute;
} else {
- if (warning.other)
- warningf(HERE, "Unknown modifier '%Y' ignored", token.v.symbol);
- next_token();
- if (token.type == '(')
- skip_until(')');
+ last->next = attribute;
}
-end_loop:
- if (token.type == ',')
- next_token();
+ last = attribute;
+
+ if (token.type == ')') {
+ break;
+ }
+ expect(',', end_error);
}
+
+ rem_anchor_token(')');
+ expect(')', end_error);
+ return first;
+
end_error:
- return;
+ rem_anchor_token(')');
+ return first;
}
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
entity->typedefe.type = type_error_type;
entity->typedefe.builtin = true;
}
- record_entity(entity, false);
+ if (kind != ENTITY_COMPOUND_MEMBER)
+ record_entity(entity, false);
return entity;
}
-static void parse_microsoft_based(based_spec_t *based_spec)
-{
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
- return;
- }
- symbol_t *symbol = token.v.symbol;
- entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
-
- if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) {
- errorf(HERE, "'%Y' is not a variable name.", symbol);
- entity = create_error_entity(symbol, ENTITY_VARIABLE);
- } else {
- variable_t *variable = &entity->variable;
-
- if (based_spec->base_variable != NULL) {
- errorf(HERE, "__based type qualifier specified more than once");
- }
- based_spec->source_position = token.source_position;
- based_spec->base_variable = variable;
-
- type_t *const type = variable->base.type;
-
- if (is_type_valid(type)) {
- if (! is_type_pointer(skip_typeref(type))) {
- errorf(HERE, "variable in __based modifier must have pointer type instead of '%T'", type);
- }
- if (variable->base.base.parent_scope != file_scope) {
- errorf(HERE, "a nonstatic local variable may not be used in a __based specification");
- }
- }
- }
- next_token();
-}
-
/**
- * Finish the construction of a struct type by calculating
- * its size, offsets, alignment.
+ * Finish the construction of a struct type by calculating its size, offsets,
+ * alignment.
*/
static void finish_struct_type(compound_type_t *type)
{
if (!compound->complete)
return;
- il_size_t size = 0;
+ il_size_t size = 0;
il_size_t offset;
- il_alignment_t alignment = 1;
- bool need_pad = false;
+ il_alignment_t alignment = compound->alignment;
+ bool need_pad = false;
entity_t *entry = compound->members.entities;
for (; entry != NULL; entry = entry->base.next) {
if (entry->kind != ENTITY_COMPOUND_MEMBER)
continue;
- type_t *m_type = skip_typeref(entry->declaration.type);
- if (! is_type_valid(m_type)) {
+ type_t *m_type = entry->declaration.type;
+ if (! is_type_valid(skip_typeref(m_type))) {
/* simply ignore errors here */
continue;
}
- il_alignment_t m_alignment = m_type->base.alignment;
+ il_alignment_t m_alignment = get_type_alignment(m_type);
if (m_alignment > alignment)
alignment = m_alignment;
if (offset > size)
need_pad = true;
entry->compound_member.offset = offset;
- size = offset + m_type->base.size;
- }
- if (type->base.alignment != 0) {
- alignment = type->base.alignment;
+ size = offset + get_type_size(m_type);
}
offset = (size + alignment - 1) & -alignment;
if (need_pad) {
if (warning.padded) {
- warningf(&compound->base.source_position, "'%T' needs padding", type);
- }
- } else {
- if (compound->modifiers & DM_PACKED && warning.packed) {
- warningf(&compound->base.source_position,
- "superfluous packed attribute on '%T'", type);
+ warningf(&compound->base.source_position, "'%T' needs padding",
+ type);
}
+ } else if (compound->packed && warning.packed) {
+ warningf(&compound->base.source_position,
+ "superfluous packed attribute on '%T'", type);
}
- type->base.size = offset;
- type->base.alignment = alignment;
+ compound->size = offset;
+ compound->alignment = alignment;
}
/**
return;
il_size_t size = 0;
- il_alignment_t alignment = 1;
+ il_alignment_t alignment = compound->alignment;
entity_t *entry = compound->members.entities;
for (; entry != NULL; entry = entry->base.next) {
if (entry->kind != ENTITY_COMPOUND_MEMBER)
continue;
- type_t *m_type = skip_typeref(entry->declaration.type);
+ type_t *m_type = entry->declaration.type;
if (! is_type_valid(m_type))
continue;
entry->compound_member.offset = 0;
- if (m_type->base.size > size)
- size = m_type->base.size;
- if (m_type->base.alignment > alignment)
- alignment = m_type->base.alignment;
- }
- if (type->base.alignment != 0) {
- alignment = type->base.alignment;
+ il_size_t m_size = get_type_size(m_type);
+ if (m_size > size)
+ size = m_size;
+ il_alignment_t m_alignment = get_type_alignment(m_type);
+ if (m_alignment > alignment)
+ alignment = m_alignment;
}
size = (size + alignment - 1) & -alignment;
- type->base.size = size;
- type->base.alignment = alignment;
+
+ compound->size = size;
+ compound->alignment = alignment;
}
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
type_t *type = NULL;
type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
- type_modifiers_t modifiers = TYPE_MODIFIER_NONE;
unsigned type_specifiers = 0;
bool newtype = false;
bool saw_error = false;
specifiers->source_position = token.source_position;
while (true) {
- specifiers->modifiers
- |= parse_attributes(&specifiers->gnu_attributes);
- if (specifiers->modifiers & DM_TRANSPARENT_UNION)
- modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
+ specifiers->attributes = parse_attributes(specifiers->attributes);
switch (token.type) {
/* storage class */
MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
case T__declspec:
- next_token();
- expect('(', end_error);
- add_anchor_token(')');
- parse_microsoft_extended_decl_modifier(specifiers);
- rem_anchor_token(')');
- expect(')', end_error);
+ specifiers->attributes
+ = parse_microsoft_extended_decl_modifier(specifiers->attributes);
break;
case T___thread:
MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void");
MATCH_SPECIFIER(T_wchar_t, SPECIFIER_WCHAR_T, "wchar_t");
- case T__forceinline:
- /* only in microsoft mode */
- specifiers->modifiers |= DM_FORCEINLINE;
- /* FALLTHROUGH */
-
case T_inline:
next_token();
specifiers->is_inline = true;
break;
+#if 0
+ case T__forceinline:
+ next_token();
+ specifiers->modifiers |= DM_FORCEINLINE;
+ break;
+#endif
+
case T_long:
if (type_specifiers & SPECIFIER_LONG_LONG) {
errorf(HERE, "multiple type specifiers given");
next_token();
break;
- case T_struct: {
+#define CHECK_DOUBLE_TYPE() \
+ if ( type != NULL) \
+ errorf(HERE, "multiple data types in declaration specifiers");
+
+ case T_struct:
+ CHECK_DOUBLE_TYPE();
type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
type->compound.compound = parse_compound_type_specifier(true);
finish_struct_type(&type->compound);
break;
- }
- case T_union: {
+ case T_union:
+ CHECK_DOUBLE_TYPE();
type = allocate_type_zero(TYPE_COMPOUND_UNION);
type->compound.compound = parse_compound_type_specifier(false);
- if (type->compound.compound->modifiers & DM_TRANSPARENT_UNION)
- modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
finish_union_type(&type->compound);
break;
- }
case T_enum:
+ CHECK_DOUBLE_TYPE();
type = parse_enum_specifier();
break;
case T___typeof__:
+ CHECK_DOUBLE_TYPE();
type = parse_typeof();
break;
case T___builtin_va_list:
+ CHECK_DOUBLE_TYPE();
type = duplicate_type(type_valist);
next_token();
break;
}
finish_specifiers:
+ specifiers->attributes = parse_attributes(specifiers->attributes);
+
in_gcc_extension = old_gcc_extension;
if (type == NULL || (saw_error && type_specifiers != 0)) {
type = allocate_type_zero(TYPE_IMAGINARY);
type->imaginary.akind = atomic_type;
} else {
- type = allocate_type_zero(TYPE_ATOMIC);
- type->atomic.akind = atomic_type;
+ type = allocate_type_zero(TYPE_ATOMIC);
+ type->atomic.akind = atomic_type;
}
newtype = true;
} else if (type_specifiers != 0) {
}
/* FIXME: check type qualifiers here */
-
type->base.qualifiers = qualifiers;
- type->base.modifiers = modifiers;
- type_t *result = typehash_insert(type);
- if (newtype && result != type) {
- free_type(type);
+ if (newtype) {
+ type = identify_new_type(type);
+ } else {
+ type = typehash_insert(type);
}
- specifiers->type = result;
+ if (specifiers->attributes != NULL)
+ type = handle_type_attributes(specifiers->attributes, type);
+ specifiers->type = type;
return;
end_error:
type_t *type = skip_typeref(entity->declaration.type);
if (is_type_incomplete(type)) {
errorf(&entity->base.source_position,
- "parameter '%Y' has incomplete type '%T'", entity->base.symbol,
- entity->declaration.type);
+ "parameter '%#T' has incomplete type",
+ entity->declaration.type, entity->base.symbol);
}
}
+static bool has_parameters(void)
+{
+ /* func(void) is not a parameter */
+ if (token.type == T_IDENTIFIER) {
+ entity_t const *const entity = get_entity(token.v.symbol, NAMESPACE_NORMAL);
+ if (entity == NULL)
+ return true;
+ if (entity->kind != ENTITY_TYPEDEF)
+ return true;
+ if (skip_typeref(entity->typedefe.type) != type_void)
+ return true;
+ } else if (token.type != T_void) {
+ return true;
+ }
+ if (look_ahead(1)->type != ')')
+ return true;
+ next_token();
+ return false;
+}
+
/**
* Parses function type parameters (and optionally creates variable_t entities
* for them in a scope)
goto parameters_finished;
}
- function_parameter_t *parameter;
- function_parameter_t *last_parameter = NULL;
+ if (has_parameters()) {
+ function_parameter_t **anchor = &type->parameters;
+ for (;;) {
+ switch (token.type) {
+ case T_DOTDOTDOT:
+ next_token();
+ type->variadic = true;
+ goto parameters_finished;
- while (true) {
- switch (token.type) {
- case T_DOTDOTDOT:
- next_token();
- type->variadic = true;
- goto parameters_finished;
+ case T_IDENTIFIER:
+ case T___extension__:
+ DECLARATION_START
+ {
+ entity_t *entity = parse_parameter();
+ if (entity->kind == ENTITY_TYPEDEF) {
+ errorf(&entity->base.source_position,
+ "typedef not allowed as function parameter");
+ break;
+ }
+ assert(is_declaration(entity));
- case T_IDENTIFIER:
- case T___extension__:
- DECLARATION_START
- {
- entity_t *entity = parse_parameter();
- if (entity->kind == ENTITY_TYPEDEF) {
- errorf(&entity->base.source_position,
- "typedef not allowed as function parameter");
- break;
- }
- assert(is_declaration(entity));
+ semantic_parameter_incomplete(entity);
- /* func(void) is not a parameter */
- if (last_parameter == NULL
- && token.type == ')'
- && entity->base.symbol == NULL
- && skip_typeref(entity->declaration.type) == type_void) {
- goto parameters_finished;
- }
- semantic_parameter_incomplete(entity);
+ function_parameter_t *const parameter =
+ allocate_parameter(entity->declaration.type);
- parameter = obstack_alloc(type_obst, sizeof(parameter[0]));
- memset(parameter, 0, sizeof(parameter[0]));
- parameter->type = entity->declaration.type;
+ if (scope != NULL) {
+ append_entity(scope, entity);
+ }
- if (scope != NULL) {
- append_entity(scope, entity);
+ *anchor = parameter;
+ anchor = ¶meter->next;
+ break;
}
- if (last_parameter != NULL) {
- last_parameter->next = parameter;
- } else {
- type->parameters = parameter;
+ default:
+ goto parameters_finished;
}
- last_parameter = parameter;
- break;
- }
-
- default:
- goto parameters_finished;
- }
- if (token.type != ',') {
- goto parameters_finished;
+ if (token.type != ',') {
+ goto parameters_finished;
+ }
+ next_token();
}
- next_token();
}
CONSTRUCT_ARRAY
} construct_type_kind_t;
-typedef struct construct_type_t construct_type_t;
-struct construct_type_t {
+typedef union construct_type_t construct_type_t;
+
+typedef struct construct_type_base_t {
construct_type_kind_t kind;
construct_type_t *next;
+} construct_type_base_t;
+
+typedef struct parsed_pointer_t {
+ construct_type_base_t base;
+ type_qualifiers_t type_qualifiers;
+ variable_t *base_variable; /**< MS __based extension. */
+} parsed_pointer_t;
+
+typedef struct parsed_reference_t {
+ construct_type_base_t base;
+} parsed_reference_t;
+
+typedef struct construct_function_type_t {
+ construct_type_base_t base;
+ type_t *function_type;
+} construct_function_type_t;
+
+typedef struct parsed_array_t {
+ construct_type_base_t base;
+ type_qualifiers_t type_qualifiers;
+ bool is_static;
+ bool is_variable;
+ expression_t *size;
+} parsed_array_t;
+
+union construct_type_t {
+ construct_type_kind_t kind;
+ construct_type_base_t base;
+ parsed_pointer_t pointer;
+ parsed_reference_t reference;
+ construct_function_type_t function;
+ parsed_array_t array;
};
-typedef struct parsed_pointer_t parsed_pointer_t;
-struct parsed_pointer_t {
- construct_type_t construct_type;
- type_qualifiers_t type_qualifiers;
- variable_t *base_variable; /**< MS __based extension. */
-};
-
-typedef struct parsed_reference_t parsed_reference_t;
-struct parsed_reference_t {
- construct_type_t construct_type;
-};
-
-typedef struct construct_function_type_t construct_function_type_t;
-struct construct_function_type_t {
- construct_type_t construct_type;
- type_t *function_type;
-};
-
-typedef struct parsed_array_t parsed_array_t;
-struct parsed_array_t {
- construct_type_t construct_type;
- type_qualifiers_t type_qualifiers;
- bool is_static;
- bool is_variable;
- expression_t *size;
-};
-
-typedef struct construct_base_type_t construct_base_type_t;
-struct construct_base_type_t {
- construct_type_t construct_type;
- type_t *type;
-};
-
-static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
+static construct_type_t *parse_pointer_declarator(void)
{
eat('*');
parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
memset(pointer, 0, sizeof(pointer[0]));
- pointer->construct_type.kind = CONSTRUCT_POINTER;
- pointer->type_qualifiers = parse_type_qualifiers();
- pointer->base_variable = base_variable;
+ pointer->base.kind = CONSTRUCT_POINTER;
+ pointer->type_qualifiers = parse_type_qualifiers();
+ //pointer->base_variable = base_variable;
- return &pointer->construct_type;
+ return (construct_type_t*) pointer;
}
static construct_type_t *parse_reference_declarator(void)
{
eat('&');
- parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0]));
- memset(reference, 0, sizeof(reference[0]));
- reference->construct_type.kind = CONSTRUCT_REFERENCE;
+ construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->reference));
+ parsed_reference_t *reference = &cons->reference;
+ memset(reference, 0, sizeof(*reference));
+ cons->kind = CONSTRUCT_REFERENCE;
- return (construct_type_t*)reference;
+ return cons;
}
static construct_type_t *parse_array_declarator(void)
eat('[');
add_anchor_token(']');
- parsed_array_t *array = obstack_alloc(&temp_obst, sizeof(array[0]));
- memset(array, 0, sizeof(array[0]));
- array->construct_type.kind = CONSTRUCT_ARRAY;
+ construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->array));
+ parsed_array_t *array = &cons->array;
+ memset(array, 0, sizeof(*array));
+ cons->kind = CONSTRUCT_ARRAY;
if (token.type == T_static) {
array->is_static = true;
array->is_variable = true;
next_token();
} else if (token.type != ']') {
- array->size = parse_assignment_expression();
+ expression_t *const size = parse_assignment_expression();
+
+ /* §6.7.5.2:1 Array size must have integer type */
+ type_t *const orig_type = size->base.type;
+ type_t *const type = skip_typeref(orig_type);
+ if (!is_type_integer(type) && is_type_valid(type)) {
+ errorf(&size->base.source_position,
+ "array size '%E' must have integer type but has type '%T'",
+ size, orig_type);
+ }
+
+ array->size = size;
+ mark_vars_read(size, NULL);
}
rem_anchor_token(']');
expect(']', end_error);
end_error:
- return &array->construct_type;
+ return cons;
}
-static construct_type_t *parse_function_declarator(scope_t *scope,
- decl_modifiers_t modifiers)
+static construct_type_t *parse_function_declarator(scope_t *scope)
{
type_t *type = allocate_type_zero(TYPE_FUNCTION);
function_type_t *ftype = &type->function;
ftype->linkage = current_linkage;
+#if 0
switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
case DM_NONE: break;
case DM_CDECL: ftype->calling_convention = CC_CDECL; break;
errorf(HERE, "multiple calling conventions in declaration");
break;
}
+#endif
parse_parameters(ftype, scope);
- construct_function_type_t *construct_function_type =
- obstack_alloc(&temp_obst, sizeof(construct_function_type[0]));
- memset(construct_function_type, 0, sizeof(construct_function_type[0]));
- construct_function_type->construct_type.kind = CONSTRUCT_FUNCTION;
- construct_function_type->function_type = type;
+ construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->function));
+ construct_function_type_t *function = &cons->function;
+ memset(function, 0, sizeof(*function));
+ cons->kind = CONSTRUCT_FUNCTION;
+ function->function_type = type;
- return &construct_function_type->construct_type;
+ return cons;
}
typedef struct parse_declarator_env_t {
+ bool may_be_abstract : 1;
+ bool must_be_abstract : 1;
decl_modifiers_t modifiers;
symbol_t *symbol;
source_position_t source_position;
scope_t parameters;
+ attribute_t *attributes;
} parse_declarator_env_t;
-static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
- bool may_be_abstract)
+static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
{
/* construct a single linked list of construct_type_t's which describe
* how to construct the final declarator type */
- construct_type_t *first = NULL;
- construct_type_t *last = NULL;
- gnu_attribute_t *attributes = NULL;
-
- decl_modifiers_t modifiers = parse_attributes(&attributes);
+ construct_type_t *first = NULL;
+ construct_type_t **anchor = &first;
- /* MS __based extension */
- based_spec_t base_spec;
- base_spec.base_variable = NULL;
+ env->attributes = parse_attributes(env->attributes);
for (;;) {
construct_type_t *type;
+ //variable_t *based = NULL; /* MS __based extension */
switch (token.type) {
case '&':
if (!(c_mode & _CXX))
errorf(HERE, "references are only available for C++");
- if (base_spec.base_variable != NULL && warning.other) {
- warningf(&base_spec.source_position,
- "__based does not precede a pointer operator, ignored");
- }
type = parse_reference_declarator();
- /* consumed */
- base_spec.base_variable = NULL;
- break;
-
- case '*':
- type = parse_pointer_declarator(base_spec.base_variable);
- /* consumed */
- base_spec.base_variable = NULL;
break;
- case T__based:
+ case T__based: {
+#if 0
+ source_position_t const pos = *HERE;
next_token();
expect('(', end_error);
add_anchor_token(')');
- parse_microsoft_based(&base_spec);
+ based = parse_microsoft_based();
rem_anchor_token(')');
expect(')', end_error);
- continue;
+ if (token.type != '*') {
+ if (token.type == T__based) {
+ errorf(&pos, "__based type modifier specified more than once");
+ } else if (warning.other) {
+ warningf(&pos,
+ "__based does not precede a pointer declarator, ignored");
+ }
+ continue;
+ }
+#else
+ panic("based currently disabled");
+#endif
+ /* FALLTHROUGH */
+ }
+
+ case '*':
+ type = parse_pointer_declarator();
+ break;
default:
goto ptr_operator_end;
}
- if (last == NULL) {
- first = type;
- last = type;
- } else {
- last->next = type;
- last = type;
- }
+ *anchor = type;
+ anchor = &type->base.next;
/* TODO: find out if this is correct */
- modifiers |= parse_attributes(&attributes);
- }
-ptr_operator_end:
- if (base_spec.base_variable != NULL && warning.other) {
- warningf(&base_spec.source_position,
- "__based does not precede a pointer operator, ignored");
+ env->attributes = parse_attributes(env->attributes);
}
- if (env != NULL) {
- modifiers |= env->modifiers;
- env->modifiers = modifiers;
- }
+ptr_operator_end: ;
+#if 0
+ modifiers |= env->modifiers;
+ env->modifiers = modifiers;
+#endif
construct_type_t *inner_types = NULL;
switch (token.type) {
case T_IDENTIFIER:
- if (env == NULL) {
+ if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
env->symbol = token.v.symbol;
if (look_ahead(1)->type != ')') {
next_token();
add_anchor_token(')');
- inner_types = parse_inner_declarator(env, may_be_abstract);
+ inner_types = parse_inner_declarator(env);
if (inner_types != NULL) {
/* All later declarators only modify the return type */
- env = NULL;
+ env->must_be_abstract = true;
}
rem_anchor_token(')');
expect(')', end_error);
}
break;
default:
- if (may_be_abstract)
+ if (env->may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
eat_until_anchor();
return NULL;
}
- construct_type_t *p = last;
+ construct_type_t **const p = anchor;
- while (true) {
+ for (;;) {
construct_type_t *type;
switch (token.type) {
case '(': {
scope_t *scope = NULL;
- if (env != NULL)
+ if (!env->must_be_abstract) {
scope = &env->parameters;
+ }
- type = parse_function_declarator(scope, modifiers);
+ type = parse_function_declarator(scope);
break;
}
case '[':
goto declarator_finished;
}
- /* insert in the middle of the list (behind p) */
- if (p != NULL) {
- type->next = p->next;
- p->next = type;
- } else {
- type->next = first;
- first = type;
- }
- if (last == p) {
- last = type;
- }
+ /* insert in the middle of the list (at p) */
+ type->base.next = *p;
+ *p = type;
+ if (anchor == p)
+ anchor = &type->base.next;
}
declarator_finished:
- /* append inner_types at the end of the list, we don't to set last anymore
+ /* append inner_types at the end of the list, we don't to set anchor anymore
* as it's not needed anymore */
- if (last == NULL) {
- assert(first == NULL);
- first = inner_types;
- } else {
- last->next = inner_types;
- }
+ *anchor = inner_types;
return first;
end_error:
return NULL;
}
-static void parse_declaration_attributes(entity_t *entity)
-{
- gnu_attribute_t *attributes = NULL;
- decl_modifiers_t modifiers = parse_attributes(&attributes);
-
- if (entity == NULL)
- return;
-
- type_t *type;
- if (entity->kind == ENTITY_TYPEDEF) {
- modifiers |= entity->typedefe.modifiers;
- type = entity->typedefe.type;
- } else {
- assert(is_declaration(entity));
- modifiers |= entity->declaration.modifiers;
- type = entity->declaration.type;
- }
- if (type == NULL)
- return;
-
- /* handle these strange/stupid mode attributes */
- gnu_attribute_t *attribute = attributes;
- for ( ; attribute != NULL; attribute = attribute->next) {
- if (attribute->kind != GNU_AK_MODE || attribute->invalid)
- continue;
-
- 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_modifiers_t type_modifiers = type->base.modifiers;
- if (modifiers & DM_TRANSPARENT_UNION)
- type_modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
-
- if (type->base.modifiers != type_modifiers) {
- type_t *copy = duplicate_type(type);
- copy->base.modifiers = type_modifiers;
-
- type = typehash_insert(copy);
- if (type != copy) {
- obstack_free(type_obst, copy);
- }
- }
-
- if (entity->kind == ENTITY_TYPEDEF) {
- entity->typedefe.type = type;
- entity->typedefe.modifiers = modifiers;
- } else {
- entity->declaration.type = type;
- entity->declaration.modifiers = modifiers;
- }
-}
-
static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
{
construct_type_t *iter = construct_list;
- for (; iter != NULL; iter = iter->next) {
+ for (; iter != NULL; iter = iter->base.next) {
switch (iter->kind) {
case CONSTRUCT_INVALID:
- internal_errorf(HERE, "invalid type construction found");
+ break;
case CONSTRUCT_FUNCTION: {
- construct_function_type_t *construct_function_type
- = (construct_function_type_t*) iter;
-
- type_t *function_type = construct_function_type->function_type;
+ construct_function_type_t *function = &iter->function;
+ type_t *function_type = function->function_type;
function_type->function.return_type = type;
type_t *skipped_return_type = skip_typeref(type);
- /* §6.7.5.3(1) */
+ /* §6.7.5.3:1 */
if (is_type_function(skipped_return_type)) {
errorf(HERE, "function returning function is not allowed");
} else if (is_type_array(skipped_return_type)) {
}
}
- type = function_type;
- break;
+ /* The function type was constructed earlier. Freeing it here will
+ * destroy other types. */
+ type = typehash_insert(function_type);
+ continue;
}
case CONSTRUCT_POINTER: {
if (is_type_reference(skip_typeref(type)))
errorf(HERE, "cannot declare a pointer to reference");
- parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
- type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable);
+ parsed_pointer_t *pointer = &iter->pointer;
+ type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable);
continue;
}
if (is_type_reference(skip_typeref(type)))
errorf(HERE, "cannot declare an array of references");
- parsed_array_t *parsed_array = (parsed_array_t*) iter;
- type_t *array_type = allocate_type_zero(TYPE_ARRAY);
+ parsed_array_t *array = &iter->array;
+ type_t *array_type = allocate_type_zero(TYPE_ARRAY);
- expression_t *size_expression = parsed_array->size;
+ expression_t *size_expression = array->size;
if (size_expression != NULL) {
size_expression
= create_implicit_cast(size_expression, type_size_t);
}
- array_type->base.qualifiers = parsed_array->type_qualifiers;
+ array_type->base.qualifiers = array->type_qualifiers;
array_type->array.element_type = type;
- array_type->array.is_static = parsed_array->is_static;
- array_type->array.is_variable = parsed_array->is_variable;
+ array_type->array.is_static = array->is_static;
+ array_type->array.is_variable = array->is_variable;
array_type->array.size_expression = size_expression;
if (size_expression != NULL) {
if (is_constant_expression(size_expression)) {
+ long const size = fold_constant(size_expression);
+ array_type->array.size = size;
array_type->array.size_constant = true;
- array_type->array.size
- = fold_constant(size_expression);
+ /* §6.7.5.2:1 If the expression is a constant expression, it shall
+ * have a value greater than zero. */
+ if (size <= 0) {
+ if (size < 0 || !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (warning.other) {
+ warningf(&size_expression->base.source_position,
+ "zero length arrays are a GCC extension");
+ }
+ }
} else {
array_type->array.is_vla = true;
}
}
type_t *skipped_type = skip_typeref(type);
- /* §6.7.5.2(1) */
+ /* §6.7.5.2:1 */
if (is_type_incomplete(skipped_type)) {
errorf(HERE, "array of incomplete type '%T' is not allowed", type);
} else if (is_type_function(skipped_type)) {
errorf(HERE, "array of functions is not allowed");
}
- type = array_type;
- break;
- }
+ type = identify_new_type(array_type);
+ continue;
}
-
- type_t *hashed_type = typehash_insert(type);
- if (hashed_type != type) {
- /* the function type was constructed earlier freeing it here will
- * destroy other types... */
- if (iter->kind != CONSTRUCT_FUNCTION) {
- free_type(type);
- }
- type = hashed_type;
}
+ internal_errorf(HERE, "invalid type construction found");
}
return type;
type = automatic_type_conversion(type);
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(pos, "parameter '%Y' declared 'inline'", symbol);
+ errorf(pos, "parameter '%#T' declared 'inline'", type, symbol);
}
/* §6.9.1:6 The declarations in the declaration list shall contain
specifiers->storage_class != STORAGE_CLASS_NONE &&
specifiers->storage_class != STORAGE_CLASS_REGISTER)
) {
- errorf(pos, "invalid storage class for parameter '%Y'", symbol);
+ errorf(pos, "invalid storage class for parameter '%#T'", type, symbol);
}
/* delay test for incomplete type, because we might have (void)
{
parse_declarator_env_t env;
memset(&env, 0, sizeof(env));
- env.modifiers = specifiers->modifiers;
+ env.may_be_abstract = (flags & DECL_MAY_BE_ABSTRACT) != 0;
- construct_type_t *construct_type =
- parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0);
+ construct_type_t *construct_type = parse_inner_declarator(&env);
type_t *orig_type =
construct_declarator_type(construct_type, specifiers->type);
type_t *type = skip_typeref(orig_type);
obstack_free(&temp_obst, construct_type);
}
+ attribute_t *attributes = parse_attributes(env.attributes);
+ /* append (shared) specifier attribute behind attributes of this
+ declarator */
+ if (attributes != NULL) {
+ attribute_t *last = attributes;
+ while (last->next != NULL)
+ last = last->next;
+ last->next = specifiers->attributes;
+ } else {
+ attributes = specifiers->attributes;
+ }
+
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
entity = allocate_entity_zero(ENTITY_TYPEDEF);
if (flags & DECL_CREATE_COMPOUND_MEMBER) {
entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
- if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position,
- "compound member '%Y' declared 'inline'", env.symbol);
- }
+ if (env.symbol != NULL) {
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "compound member '%Y' declared 'inline'", env.symbol);
+ }
- if (specifiers->thread_local ||
- specifiers->storage_class != STORAGE_CLASS_NONE) {
- errorf(&env.source_position,
- "compound member '%Y' must have no storage class",
- env.symbol);
+ if (specifiers->thread_local ||
+ specifiers->storage_class != STORAGE_CLASS_NONE) {
+ errorf(&env.source_position,
+ "compound member '%Y' must have no storage class",
+ env.symbol);
+ }
}
} else if (flags & DECL_IS_PARAMETER) {
orig_type = semantic_parameter(&env.source_position, orig_type,
entity->function.is_inline = specifiers->is_inline;
entity->function.parameters = env.parameters;
- if (specifiers->thread_local || (
- specifiers->storage_class != STORAGE_CLASS_EXTERN &&
- specifiers->storage_class != STORAGE_CLASS_NONE &&
- specifiers->storage_class != STORAGE_CLASS_STATIC)
- ) {
- errorf(&env.source_position,
- "invalid storage class for function '%Y'", env.symbol);
+ if (env.symbol != NULL) {
+ /* this needs fixes for C++ */
+ bool in_function_scope = current_function != NULL;
+
+ if (specifiers->thread_local || (
+ specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+ )) {
+ errorf(&env.source_position,
+ "invalid storage class for function '%Y'", env.symbol);
+ }
}
} else {
entity = allocate_entity_zero(ENTITY_VARIABLE);
- entity->variable.get_property_sym = specifiers->get_property_sym;
- entity->variable.put_property_sym = specifiers->put_property_sym;
- if (specifiers->alignment != 0) {
- /* TODO: add checks here */
- entity->variable.alignment = specifiers->alignment;
- }
-
- if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position,
- "variable '%Y' declared 'inline'", env.symbol);
- }
-
entity->variable.thread_local = specifiers->thread_local;
- bool invalid_storage_class = false;
- if (current_scope == file_scope) {
- if (specifiers->storage_class != STORAGE_CLASS_EXTERN &&
- specifiers->storage_class != STORAGE_CLASS_NONE &&
- specifiers->storage_class != STORAGE_CLASS_STATIC) {
- invalid_storage_class = true;
+ if (env.symbol != NULL) {
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(&env.source_position,
+ "variable '%Y' declared 'inline'", env.symbol);
}
- } else {
- if (specifiers->thread_local &&
- specifiers->storage_class == STORAGE_CLASS_NONE) {
- invalid_storage_class = true;
+
+ bool invalid_storage_class = false;
+ if (current_scope == file_scope) {
+ if (specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_STATIC) {
+ invalid_storage_class = true;
+ }
+ } else {
+ if (specifiers->thread_local &&
+ specifiers->storage_class == STORAGE_CLASS_NONE) {
+ invalid_storage_class = true;
+ }
+ }
+ if (invalid_storage_class) {
+ errorf(&env.source_position,
+ "invalid storage class for variable '%Y'", env.symbol);
}
- }
- if (invalid_storage_class) {
- errorf(&env.source_position,
- "invalid storage class for variable '%Y'", env.symbol);
}
}
- entity->base.source_position = env.source_position;
- entity->base.symbol = env.symbol;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->declaration.type = orig_type;
- entity->declaration.modifiers = env.modifiers;
- entity->declaration.deprecated_string = specifiers->deprecated_string;
+ if (env.symbol != NULL) {
+ entity->base.symbol = env.symbol;
+ entity->base.source_position = env.source_position;
+ } else {
+ entity->base.source_position = specifiers->source_position;
+ }
+ entity->base.namespc = NAMESPACE_NORMAL;
+ entity->declaration.type = orig_type;
+ entity->declaration.alignment = get_type_alignment(orig_type);
+ entity->declaration.modifiers = env.modifiers;
+ entity->declaration.attributes = attributes;
storage_class_t storage_class = specifiers->storage_class;
entity->declaration.declared_storage_class = storage_class;
entity->declaration.storage_class = storage_class;
}
- parse_declaration_attributes(entity);
+ if (attributes != NULL) {
+ handle_entity_attributes(attributes, entity);
+ }
return entity;
}
static type_t *parse_abstract_declarator(type_t *base_type)
{
- construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
+ parse_declarator_env_t env;
+ memset(&env, 0, sizeof(env));
+ env.may_be_abstract = true;
+ env.must_be_abstract = true;
+
+ construct_type_t *construct_type = parse_inner_declarator(&env);
type_t *result = construct_declarator_type(construct_type, base_type);
if (construct_type != NULL) {
obstack_free(&temp_obst, construct_type);
}
+ result = handle_type_attributes(env.attributes, result);
return result;
}
get_entity_kind_name(new_kind), &old->base.source_position);
}
+static bool is_error_entity(entity_t *const ent)
+{
+ if (is_declaration(ent)) {
+ return is_type_valid(skip_typeref(ent->declaration.type));
+ } else if (ent->kind == ENTITY_TYPEDEF) {
+ return is_type_valid(skip_typeref(ent->typedefe.type));
+ }
+ return false;
+}
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
if (symbol == NULL)
return entity;
- entity_t *previous_entity = get_entity(symbol, namespc);
+ entity_t *const previous_entity = get_entity(symbol, namespc);
/* pushing the same entity twice will break the stack structure */
assert(previous_entity != entity);
entity->declaration.type, symbol);
}
- if (previous_entity != NULL &&
- previous_entity->base.parent_scope == ¤t_function->parameters &&
- previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
- assert(previous_entity->kind == ENTITY_PARAMETER);
- errorf(pos,
- "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
- entity->declaration.type, symbol,
- previous_entity->declaration.type, symbol,
- &previous_entity->base.source_position);
- goto finish;
- }
-
- if (previous_entity != NULL &&
- previous_entity->base.parent_scope == current_scope) {
- if (previous_entity->kind != entity->kind) {
- error_redefined_as_different_kind(pos, previous_entity,
- entity->kind);
- goto finish;
- }
- if (previous_entity->kind == ENTITY_ENUM_VALUE) {
- errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- goto finish;
- }
- if (previous_entity->kind == ENTITY_TYPEDEF) {
- /* TODO: C++ allows this for exactly the same type */
- errorf(pos, "redefinition of typedef '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ if (previous_entity != NULL) {
+ if (previous_entity->base.parent_scope == ¤t_function->parameters &&
+ previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
+ assert(previous_entity->kind == ENTITY_PARAMETER);
+ errorf(pos,
+ "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+ entity->declaration.type, symbol,
+ previous_entity->declaration.type, symbol,
+ &previous_entity->base.source_position);
goto finish;
}
- /* at this point we should have only VARIABLES or FUNCTIONS */
- assert(is_declaration(previous_entity) && is_declaration(entity));
-
- declaration_t *const prev_decl = &previous_entity->declaration;
- declaration_t *const decl = &entity->declaration;
+ if (previous_entity->base.parent_scope == current_scope) {
+ if (previous_entity->kind != entity->kind) {
+ if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+ error_redefined_as_different_kind(pos, previous_entity,
+ entity->kind);
+ }
+ goto finish;
+ }
+ if (previous_entity->kind == ENTITY_ENUM_VALUE) {
+ errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ goto finish;
+ }
+ if (previous_entity->kind == ENTITY_TYPEDEF) {
+ /* TODO: C++ allows this for exactly the same type */
+ errorf(pos, "redefinition of typedef '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ goto finish;
+ }
- /* can happen for K&R style declarations */
- if (prev_decl->type == NULL &&
- previous_entity->kind == ENTITY_PARAMETER &&
- entity->kind == ENTITY_PARAMETER) {
- prev_decl->type = decl->type;
- prev_decl->storage_class = decl->storage_class;
- prev_decl->declared_storage_class = decl->declared_storage_class;
- prev_decl->modifiers = decl->modifiers;
- prev_decl->deprecated_string = decl->deprecated_string;
- return previous_entity;
- }
+ /* at this point we should have only VARIABLES or FUNCTIONS */
+ assert(is_declaration(previous_entity) && is_declaration(entity));
- type_t *const orig_type = decl->type;
- assert(orig_type != NULL);
- type_t *const type = skip_typeref(orig_type);
- type_t * prev_type = skip_typeref(prev_decl->type);
+ declaration_t *const prev_decl = &previous_entity->declaration;
+ declaration_t *const decl = &entity->declaration;
- if (!types_compatible(type, prev_type)) {
- errorf(pos,
- "declaration '%#T' is incompatible with '%#T' (declared %P)",
- orig_type, symbol, prev_decl->type, symbol,
- &previous_entity->base.source_position);
- } else {
- unsigned old_storage_class = prev_decl->storage_class;
- if (warning.redundant_decls &&
- is_definition &&
- !prev_decl->used &&
- !(prev_decl->modifiers & DM_USED) &&
- prev_decl->storage_class == STORAGE_CLASS_STATIC) {
- warningf(&previous_entity->base.source_position,
- "unnecessary static forward declaration for '%#T'",
- prev_decl->type, symbol);
+ /* can happen for K&R style declarations */
+ if (prev_decl->type == NULL &&
+ previous_entity->kind == ENTITY_PARAMETER &&
+ entity->kind == ENTITY_PARAMETER) {
+ prev_decl->type = decl->type;
+ prev_decl->storage_class = decl->storage_class;
+ prev_decl->declared_storage_class = decl->declared_storage_class;
+ prev_decl->modifiers = decl->modifiers;
+ return previous_entity;
}
- unsigned new_storage_class = decl->storage_class;
- if (is_type_incomplete(prev_type)) {
- prev_decl->type = type;
- prev_type = type;
- }
+ type_t *const orig_type = decl->type;
+ assert(orig_type != NULL);
+ type_t *const type = skip_typeref(orig_type);
+ type_t *const prev_type = skip_typeref(prev_decl->type);
- /* pretend no storage class means extern for function
- * declarations (except if the previous declaration is neither
- * none nor extern) */
- if (entity->kind == ENTITY_FUNCTION) {
- if (prev_type->function.unspecified_parameters) {
- prev_decl->type = type;
- prev_type = type;
+ if (!types_compatible(type, prev_type)) {
+ errorf(pos,
+ "declaration '%#T' is incompatible with '%#T' (declared %P)",
+ orig_type, symbol, prev_decl->type, symbol,
+ &previous_entity->base.source_position);
+ } else {
+ unsigned old_storage_class = prev_decl->storage_class;
+ if (warning.redundant_decls &&
+ is_definition &&
+ !prev_decl->used &&
+ !(prev_decl->modifiers & DM_USED) &&
+ prev_decl->storage_class == STORAGE_CLASS_STATIC) {
+ warningf(&previous_entity->base.source_position,
+ "unnecessary static forward declaration for '%#T'",
+ prev_decl->type, symbol);
}
- switch (old_storage_class) {
- case STORAGE_CLASS_NONE:
- old_storage_class = STORAGE_CLASS_EXTERN;
- /* FALLTHROUGH */
-
- case STORAGE_CLASS_EXTERN:
- if (is_definition) {
- if (warning.missing_prototypes &&
- prev_type->function.unspecified_parameters &&
- !is_sym_main(symbol)) {
- warningf(pos, "no previous prototype for '%#T'",
- orig_type, symbol);
- }
- } else if (new_storage_class == STORAGE_CLASS_NONE) {
- new_storage_class = STORAGE_CLASS_EXTERN;
- }
- break;
+ storage_class_t new_storage_class = decl->storage_class;
+
+ /* pretend no storage class means extern for function
+ * declarations (except if the previous declaration is neither
+ * none nor extern) */
+ if (entity->kind == ENTITY_FUNCTION) {
+ /* the previous declaration could have unspecified parameters or
+ * be a typedef, so use the new type */
+ if (prev_type->function.unspecified_parameters || is_definition)
+ prev_decl->type = type;
+
+ switch (old_storage_class) {
+ case STORAGE_CLASS_NONE:
+ old_storage_class = STORAGE_CLASS_EXTERN;
+ /* FALLTHROUGH */
+
+ case STORAGE_CLASS_EXTERN:
+ if (is_definition) {
+ if (warning.missing_prototypes &&
+ prev_type->function.unspecified_parameters &&
+ !is_sym_main(symbol)) {
+ warningf(pos, "no previous prototype for '%#T'",
+ orig_type, symbol);
+ }
+ } else if (new_storage_class == STORAGE_CLASS_NONE) {
+ new_storage_class = STORAGE_CLASS_EXTERN;
+ }
+ break;
- default:
- break;
+ default:
+ break;
+ }
+ } else if (is_type_incomplete(prev_type)) {
+ prev_decl->type = type;
}
- }
- if (old_storage_class == STORAGE_CLASS_EXTERN &&
- new_storage_class == STORAGE_CLASS_EXTERN) {
+ if (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
warn_redundant_declaration:
- if (!is_definition &&
- warning.redundant_decls &&
- is_type_valid(prev_type) &&
- strcmp(previous_entity->base.source_position.input_name,
- "<builtin>") != 0) {
- warningf(pos,
- "redundant declaration for '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- }
- } else if (current_function == NULL) {
- if (old_storage_class != STORAGE_CLASS_STATIC &&
- new_storage_class == STORAGE_CLASS_STATIC) {
- errorf(pos,
- "static declaration of '%Y' follows non-static declaration (declared %P)",
- symbol, &previous_entity->base.source_position);
- } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
- prev_decl->storage_class = STORAGE_CLASS_NONE;
- prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
- } else {
- /* ISO/IEC 14882:1998(E) §C.1.2:1 */
- if (c_mode & _CXX)
- goto error_redeclaration;
- goto warn_redundant_declaration;
- }
- } else if (is_type_valid(prev_type)) {
- if (old_storage_class == new_storage_class) {
+ if (!is_definition &&
+ warning.redundant_decls &&
+ is_type_valid(prev_type) &&
+ strcmp(previous_entity->base.source_position.input_name,
+ "<builtin>") != 0) {
+ warningf(pos,
+ "redundant declaration for '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ }
+ } else if (current_function == NULL) {
+ if (old_storage_class != STORAGE_CLASS_STATIC &&
+ new_storage_class == STORAGE_CLASS_STATIC) {
+ errorf(pos,
+ "static declaration of '%Y' follows non-static declaration (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ } else if (old_storage_class == STORAGE_CLASS_EXTERN) {
+ prev_decl->storage_class = STORAGE_CLASS_NONE;
+ prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
+ } else {
+ /* ISO/IEC 14882:1998(E) §C.1.2:1 */
+ if (c_mode & _CXX)
+ goto error_redeclaration;
+ goto warn_redundant_declaration;
+ }
+ } else if (is_type_valid(prev_type)) {
+ if (old_storage_class == new_storage_class) {
error_redeclaration:
- errorf(pos, "redeclaration of '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
- } else {
- errorf(pos,
- "redeclaration of '%Y' with different linkage (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ } else {
+ errorf(pos,
+ "redeclaration of '%Y' with different linkage (declared %P)",
+ symbol, &previous_entity->base.source_position);
+ }
}
}
+
+ prev_decl->modifiers |= decl->modifiers;
+ if (entity->kind == ENTITY_FUNCTION) {
+ previous_entity->function.is_inline |= entity->function.is_inline;
+ }
+ return previous_entity;
}
- prev_decl->modifiers |= decl->modifiers;
- if (entity->kind == ENTITY_FUNCTION) {
- previous_entity->function.is_inline |= entity->function.is_inline;
+ if (warning.shadow) {
+ warningf(pos, "%s '%Y' shadows %s (declared %P)",
+ get_entity_kind_name(entity->kind), symbol,
+ get_entity_kind_name(previous_entity->kind),
+ &previous_entity->base.source_position);
}
- return previous_entity;
}
if (entity->kind == ENTITY_FUNCTION) {
current_init_decl = NULL;
if (entity->kind == ENTITY_VARIABLE) {
- /* § 6.7.5 (22) array initializers for arrays with unknown size
+ /* §6.7.5:22 array initializers for arrays with unknown size
* determine the array type size */
declaration->type = env.type;
entity->variable.initializer = initializer;
/* §6.7:7 If an identifier for an object is declared with no linkage, the
* type for the object shall be complete [...] */
declaration_t *decl = &ent->declaration;
- if (decl->storage_class != STORAGE_CLASS_NONE)
+ if (decl->storage_class == STORAGE_CLASS_EXTERN ||
+ decl->storage_class == STORAGE_CLASS_STATIC)
return;
type_t *const orig_type = decl->type;
if (!is_type_incomplete(type))
return;
- /* GCC allows global arrays without size and assigns them a length of one,
- * if no different declaration follows */
- if (is_type_array(type) &&
- c_mode & _GNUC &&
- ent->base.parent_scope == file_scope) {
+ /* §6.9.2:2 and §6.9.2:5: At the end of the translation incomplete arrays
+ * are given length one. */
+ if (is_type_array(type) && ent->base.parent_scope == file_scope) {
ARR_APP1(declaration_t*, incomplete_arrays, decl);
return;
}
}
}
+/* §6.5.2.2:6 */
static type_t *get_default_promoted_type(type_t *orig_type)
{
type_t *result = orig_type;
type_t *type = skip_typeref(orig_type);
if (is_type_integer(type)) {
result = promote_integer(type);
- } else if (type == type_float) {
+ } else if (is_type_atomic(type, ATOMIC_TYPE_FLOAT)) {
result = type_double;
}
/* update function type */
type_t *new_type = duplicate_type(type);
- function_parameter_t *parameters = NULL;
- function_parameter_t *last_parameter = NULL;
+ function_parameter_t *parameters = NULL;
+ function_parameter_t **anchor = ¶meters;
parameter = entity->function.parameters.entities;
for (; parameter != NULL; parameter = parameter->base.next) {
+ if (parameter->kind != ENTITY_PARAMETER)
+ continue;
+
type_t *parameter_type = parameter->declaration.type;
if (parameter_type == NULL) {
if (strict_mode) {
errorf(HERE, "no type specified for function parameter '%Y'",
parameter->base.symbol);
+ parameter_type = type_error_type;
} else {
if (warning.implicit_int) {
warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
parameter->base.symbol);
}
- parameter_type = type_int;
- parameter->declaration.type = parameter_type;
+ parameter_type = type_int;
}
+ parameter->declaration.type = parameter_type;
}
semantic_parameter_incomplete(parameter);
- parameter_type = parameter->declaration.type;
/*
* we need the default promoted types for the function type
*/
parameter_type = get_default_promoted_type(parameter_type);
- function_parameter_t *function_parameter
- = obstack_alloc(type_obst, sizeof(function_parameter[0]));
- memset(function_parameter, 0, sizeof(function_parameter[0]));
+ function_parameter_t *const parameter =
+ allocate_parameter(parameter_type);
- function_parameter->type = parameter_type;
- if (last_parameter != NULL) {
- last_parameter->next = function_parameter;
- } else {
- parameters = function_parameter;
- }
- last_parameter = function_parameter;
+ *anchor = parameter;
+ anchor = ¶meter->next;
}
- /* § 6.9.1.7: A K&R style parameter list does NOT act as a function
+ /* §6.9.1.7: A K&R style parameter list does NOT act as a function
* prototype */
new_type->function.parameters = parameters;
new_type->function.unspecified_parameters = true;
- type = typehash_insert(new_type);
- if (type != new_type) {
- obstack_free(type_obst, new_type);
- }
+ new_type = identify_new_type(new_type);
- entity->declaration.type = type;
+ entity->declaration.type = new_type;
rem_anchor_token('{');
}
}
}
-static void warn_unused_entity(entity_t *entity, entity_t *end)
+static void warn_unused_entity(entity_t *entity, entity_t *last)
{
- for (; entity != NULL; entity = entity->base.next) {
+ entity_t const *const end = last != NULL ? last->base.next : NULL;
+ for (; entity != end; entity = entity->base.next) {
if (!is_declaration(entity))
continue;
warningf(&entity->base.source_position, "%s '%Y' is never read",
what, entity->base.symbol);
}
-
- if (entity == end)
- break;
}
}
}
static void check_reachable(statement_t *);
+static bool reaches_end;
static bool expression_returns(expression_t const *const expr)
{
case EXPR_SIZEOF: // TODO handle obscure VLA case
case EXPR_ALIGNOF:
case EXPR_FUNCNAME:
- case EXPR_BUILTIN_SYMBOL:
case EXPR_BUILTIN_CONSTANT_P:
- case EXPR_BUILTIN_PREFETCH:
+ case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
case EXPR_OFFSETOF:
case EXPR_INVALID:
return true;
- case EXPR_STATEMENT:
+ case EXPR_STATEMENT: {
+ bool old_reaches_end = reaches_end;
+ reaches_end = false;
check_reachable(expr->statement.statement);
- // TODO check if statement can be left
- return true;
+ bool returns = reaches_end;
+ reaches_end = old_reaches_end;
+ return returns;
+ }
case EXPR_CONDITIONAL:
// TODO handle constant expression
case EXPR_VA_ARG:
return expression_returns(expr->va_arge.ap);
+ case EXPR_VA_COPY:
+ return expression_returns(expr->va_copye.src);
+
EXPR_UNARY_CASES_MANDATORY
return expression_returns(expr->unary.value);
switch (stmt->kind) {
case STATEMENT_INVALID:
case STATEMENT_EMPTY:
- case STATEMENT_LOCAL_LABEL:
case STATEMENT_ASM:
next = stmt->base.next;
break;
case STATEMENT_COMPOUND:
next = stmt->compound.statements;
+ if (next == NULL)
+ next = stmt->base.next;
break;
case STATEMENT_RETURN: {
if (next == NULL) {
noreturn_candidate = false;
- type_t *const type = current_function->base.type;
+ type_t *const type = skip_typeref(current_function->base.type);
assert(is_type_function(type));
type_t *const ret = skip_typeref(type->function.return_type);
if (warning.return_type &&
case STATEMENT_INVALID:
case STATEMENT_EMPTY:
case STATEMENT_DECLARATION:
- case STATEMENT_LOCAL_LABEL:
case STATEMENT_EXPRESSION:
case STATEMENT_ASM:
case STATEMENT_RETURN:
panic("invalid control flow in function");
case STATEMENT_COMPOUND:
+ if (next->compound.stmt_expr) {
+ reaches_end = true;
+ return;
+ }
+ /* FALLTHROUGH */
case STATEMENT_IF:
case STATEMENT_SWITCH:
case STATEMENT_LABEL:
}
assert(is_declaration(ndeclaration));
- type_t *type = skip_typeref(ndeclaration->declaration.type);
+ type_t *const orig_type = ndeclaration->declaration.type;
+ type_t * type = skip_typeref(orig_type);
if (!is_type_function(type)) {
if (is_type_valid(type)) {
}
eat_block();
return;
+ } else if (is_typeref(orig_type)) {
+ /* §6.9.1:2 */
+ errorf(&ndeclaration->base.source_position,
+ "type of function definition '%#T' is a typedef",
+ orig_type, ndeclaration->base.symbol);
}
if (warning.aggregate_return &&
ndeclaration->base.symbol);
}
- /* § 6.7.5.3 (14) a function definition with () means no
+ /* §6.7.5.3:14 a function definition with () means no
* parameters (and not unspecified parameters) */
- if (type->function.unspecified_parameters
- && type->function.parameters == NULL
- && !type->function.kr_style_parameters) {
- type_t *duplicate = duplicate_type(type);
- duplicate->function.unspecified_parameters = false;
+ if (type->function.unspecified_parameters &&
+ type->function.parameters == NULL &&
+ !type->function.kr_style_parameters) {
+ type_t *copy = duplicate_type(type);
+ copy->function.unspecified_parameters = false;
+ type = identify_new_type(copy);
- type = typehash_insert(duplicate);
- if (type != duplicate) {
- obstack_free(type_obst, duplicate);
- }
ndeclaration->declaration.type = type;
}
base_type);
bit_size = 0;
} else {
- bit_size = skipped_type->base.size * 8;
+ bit_size = get_type_size(base_type) * 8;
}
if (is_constant_expression(size)) {
entity->base.source_position = source_position;
entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
entity->declaration.storage_class = STORAGE_CLASS_NONE;
- entity->declaration.modifiers = specifiers->modifiers;
entity->declaration.type = type;
+ append_entity(&compound->members, entity);
} else {
entity = parse_declarator(specifiers,
DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
- assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
- if (token.type == ':') {
- source_position_t source_position = *HERE;
- next_token();
- expression_t *size = parse_constant_expression();
-
- type_t *type = entity->declaration.type;
- type_t *bitfield_type = make_bitfield_type(type, size,
- &source_position, entity->base.symbol);
- entity->declaration.type = bitfield_type;
- }
- }
-
- /* make sure we don't define a symbol multiple times */
- symbol_t *symbol = entity->base.symbol;
- if (symbol != NULL) {
- entity_t *prev = find_compound_entry(compound, symbol);
-
- if (prev != NULL) {
+ if (entity->kind == ENTITY_TYPEDEF) {
errorf(&entity->base.source_position,
- "multiple declarations of symbol '%Y' (declared %P)",
- symbol, &prev->base.source_position);
- }
- }
+ "typedef not allowed as compound member");
+ } else {
+ assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+
+ /* make sure we don't define a symbol multiple times */
+ symbol_t *symbol = entity->base.symbol;
+ if (symbol != NULL) {
+ entity_t *prev = find_compound_entry(compound, symbol);
+ if (prev != NULL) {
+ errorf(&entity->base.source_position,
+ "multiple declarations of symbol '%Y' (declared %P)",
+ symbol, &prev->base.source_position);
+ }
+ }
+
+ if (token.type == ':') {
+ source_position_t source_position = *HERE;
+ next_token();
+ expression_t *size = parse_constant_expression();
- append_entity(&compound->members, entity);
+ type_t *type = entity->declaration.type;
+ type_t *bitfield_type = make_bitfield_type(type, size,
+ &source_position, entity->base.symbol);
+ entity->declaration.type = bitfield_type;
+ } else {
+ type_t *orig_type = entity->declaration.type;
+ type_t *type = skip_typeref(orig_type);
+ if (is_type_function(type)) {
+ errorf(&entity->base.source_position,
+ "compound member '%Y' must not have function type '%T'",
+ entity->base.symbol, orig_type);
+ } else if (is_type_incomplete(type)) {
+ /* §6.7.2.1:16 flexible array member */
+ if (!is_type_array(type) ||
+ token.type != ';' ||
+ look_ahead(1)->type != '}') {
+ errorf(&entity->base.source_position,
+ "compound member '%Y' has incomplete type '%T'",
+ entity->base.symbol, orig_type);
+ }
+ }
+ }
- type_t *orig_type = entity->declaration.type;
- type_t *type = skip_typeref(orig_type);
- if (is_type_function(type)) {
- errorf(&entity->base.source_position,
- "compound member '%Y' must not have function type '%T'",
- entity->base.symbol, orig_type);
- } else if (is_type_incomplete(type)) {
- /* §6.7.2.1:16 flexible array member */
- if (is_type_array(type) &&
- token.type == ';' &&
- look_ahead(1)->type == '}') {
- compound->has_flexible_member = true;
- } else {
- errorf(&entity->base.source_position,
- "compound member '%Y' has incomplete type '%T'",
- entity->base.symbol, orig_type);
+ append_entity(&compound->members, entity);
}
}
typedef struct expression_parser_function_t expression_parser_function_t;
struct expression_parser_function_t {
parse_expression_function parser;
- unsigned infix_precedence;
+ precedence_t infix_precedence;
parse_expression_infix_function infix_parser;
};
ntype->function.return_type = type_int;
ntype->function.unspecified_parameters = true;
ntype->function.linkage = LINKAGE_C;
-
- type_t *type = typehash_insert(ntype);
- if (type != ntype) {
- free_type(ntype);
- }
+ type_t *type = identify_new_type(ntype);
entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
type_t *argument_type2)
{
- function_parameter_t *parameter2
- = obstack_alloc(type_obst, sizeof(parameter2[0]));
- memset(parameter2, 0, sizeof(parameter2[0]));
- parameter2->type = argument_type2;
-
- function_parameter_t *parameter1
- = obstack_alloc(type_obst, sizeof(parameter1[0]));
- memset(parameter1, 0, sizeof(parameter1[0]));
- parameter1->type = argument_type1;
+ function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
+ function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
parameter1->next = parameter2;
type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = parameter1;
- type_t *result = typehash_insert(type);
- if (result != type) {
- free_type(type);
- }
-
- return result;
+ return identify_new_type(type);
}
/**
*/
static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
{
- function_parameter_t *parameter
- = obstack_alloc(type_obst, sizeof(parameter[0]));
- memset(parameter, 0, sizeof(parameter[0]));
- parameter->type = argument_type;
+ function_parameter_t *const parameter = allocate_parameter(argument_type);
type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = parameter;
- type_t *result = typehash_insert(type);
- if (result != type) {
- free_type(type);
- }
+ return identify_new_type(type);
+}
- return result;
+static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
+{
+ type_t *res = make_function_1_type(return_type, argument_type);
+ res->function.variadic = 1;
+ return res;
}
+/**
+ * Creates a return_type (func)(void) function type if not
+ * already exists.
+ *
+ * @param return_type the return type
+ */
static type_t *make_function_0_type(type_t *return_type)
{
type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = NULL;
- type_t *result = typehash_insert(type);
- if (result != type) {
- free_type(type);
- }
-
- return result;
+ return identify_new_type(type);
}
/**
- * Creates a function type for some function like builtins.
+ * Creates a NO_RETURN return_type (func)(void) function type if not
+ * already exists.
*
- * @param symbol the symbol describing the builtin
- */
-static type_t *get_builtin_symbol_type(symbol_t *symbol)
-{
- switch (symbol->ID) {
- case T___builtin_alloca:
- return make_function_1_type(type_void_ptr, type_size_t);
- case T___builtin_huge_val:
- return make_function_0_type(type_double);
- case T___builtin_inf:
- return make_function_0_type(type_double);
- case T___builtin_inff:
- return make_function_0_type(type_float);
- case T___builtin_infl:
- return make_function_0_type(type_long_double);
- case T___builtin_nan:
- return make_function_1_type(type_double, type_char_ptr);
- case T___builtin_nanf:
- return make_function_1_type(type_float, type_char_ptr);
- case T___builtin_nanl:
- return make_function_1_type(type_long_double, type_char_ptr);
- case T___builtin_va_end:
- return make_function_1_type(type_void, type_valist);
- case T___builtin_expect:
- return make_function_2_type(type_long, type_long, type_long);
- default:
- internal_errorf(HERE, "not implemented builtin identifier found");
- }
+ * @param return_type the return type
+ */
+static type_t *make_function_0_type_noreturn(type_t *return_type)
+{
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = NULL;
+ type->function.modifiers |= DM_NORETURN;
+ return identify_new_type(type);
}
/**
- * Performs automatic type cast as described in § 6.3.2.1.
+ * Performs automatic type cast as described in §6.3.2.1.
*
* @param orig_type the original type
*/
/**
* reverts the automatic casts of array to pointer types and function
- * to function-pointer types as defined § 6.3.2.1
+ * to function-pointer types as defined §6.3.2.1
*/
type_t *revert_automatic_type_conversion(const expression_t *expression)
{
assert(is_declaration(entity));
type_t *type = entity->declaration.type;
return get_qualified_type(type,
- expression->base.type->base.qualifiers);
+ expression->base.type->base.qualifiers);
}
case EXPR_UNARY_DEREFERENCE: {
const expression_t *const value = expression->unary.value;
type_t *const type = skip_typeref(value->base.type);
- assert(is_type_pointer(type));
+ if (!is_type_pointer(type))
+ return type_error_type;
return type->pointer.points_to;
}
- case EXPR_BUILTIN_SYMBOL:
- return get_builtin_symbol_type(expression->builtin_symbol.symbol);
-
case EXPR_ARRAY_ACCESS: {
const expression_t *array_ref = expression->array_access.array_ref;
type_t *type_left = skip_typeref(array_ref->base.type);
- if (!is_type_valid(type_left))
- return type_left;
- assert(is_type_pointer(type_left));
+ if (!is_type_pointer(type_left))
+ return type_error_type;
return type_left->pointer.points_to;
}
case EXPR_COMPOUND_LITERAL:
return expression->compound_literal.type;
- default: break;
+ default:
+ return expression->base.type;
}
-
- return expression->base.type;
}
static expression_t *parse_reference(void)
orig_type = entity->declaration.type;
} else if (entity->kind == ENTITY_ENUM_VALUE) {
orig_type = entity->enum_value.enum_type;
- } else if (entity->kind == ENTITY_TYPEDEF) {
- errorf(HERE, "encountered typedef name '%Y' while parsing expression",
- symbol);
- next_token();
- return create_invalid_expression();
} else {
panic("expected declaration or enum value in reference");
}
}
if (entity->base.parent_scope != file_scope
- && entity->base.parent_scope->depth < current_function->parameters.depth
+ && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth)
&& is_type_valid(orig_type) && !is_type_function(orig_type)) {
if (entity->kind == ENTITY_VARIABLE) {
/* access of a variable from an outer function */
if (warning.deprecated_declarations
&& is_declaration(entity)
&& entity->declaration.modifiers & DM_DEPRECATED) {
- declaration_t *declaration = &entity->declaration;
char const *const prefix = entity->kind == ENTITY_FUNCTION ?
"function" : "variable";
-
- if (declaration->deprecated_string != NULL) {
+ const char *deprecated_string
+ = get_deprecated_string(entity->declaration.attributes);
+ if (deprecated_string != NULL) {
warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
prefix, entity->base.symbol, &entity->base.source_position,
- declaration->deprecated_string);
+ deprecated_string);
} else {
warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
entity->base.symbol, &entity->base.source_position);
expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
statement_t *statement = parse_compound_statement(true);
+ statement->compound.stmt_expr = true;
expression->statement.statement = statement;
/* find last statement and use its type */
}
/**
- * Parses a _builtin_va_arg() expression.
+ * Parses a __builtin_va_arg() expression.
*/
static expression_t *parse_va_arg(void)
{
eat(T___builtin_va_arg);
expect('(', end_error);
- expression->va_arge.ap = parse_assignment_expression();
+ call_argument_t ap;
+ ap.expression = parse_assignment_expression();
+ expression->va_arge.ap = ap.expression;
+ check_call_argument(type_valist, &ap, 1);
+
expect(',', end_error);
expression->base.type = parse_typename();
expect(')', end_error);
return create_invalid_expression();
}
-static expression_t *parse_builtin_symbol(void)
+/**
+ * Parses a __builtin_va_copy() expression.
+ */
+static expression_t *parse_va_copy(void)
{
- expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_SYMBOL);
+ expression_t *expression = allocate_expression_zero(EXPR_VA_COPY);
- symbol_t *symbol = token.v.symbol;
+ eat(T___builtin_va_copy);
- expression->builtin_symbol.symbol = symbol;
- next_token();
+ expect('(', end_error);
+ expression_t *dst = parse_assignment_expression();
+ assign_error_t error = semantic_assign(type_valist, dst);
+ report_assign_error(error, type_valist, dst, "call argument 1",
+ &dst->base.source_position);
+ expression->va_copye.dst = dst;
- type_t *type = get_builtin_symbol_type(symbol);
- type = automatic_type_conversion(type);
+ expect(',', end_error);
+
+ call_argument_t src;
+ src.expression = parse_assignment_expression();
+ check_call_argument(type_valist, &src, 2);
+ expression->va_copye.src = src.expression;
+ expect(')', end_error);
- expression->base.type = type;
return expression;
+end_error:
+ return create_invalid_expression();
}
/**
- * Parses a __builtin_constant() expression.
+ * Parses a __builtin_constant_p() expression.
*/
static expression_t *parse_builtin_constant(void)
{
}
/**
- * Parses a __builtin_prefetch() expression.
+ * Parses a __builtin_types_compatible_p() expression.
*/
-static expression_t *parse_builtin_prefetch(void)
+static expression_t *parse_builtin_types_compatible(void)
{
- expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_PREFETCH);
+ expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_TYPES_COMPATIBLE_P);
- eat(T___builtin_prefetch);
+ eat(T___builtin_types_compatible_p);
expect('(', end_error);
add_anchor_token(')');
- expression->builtin_prefetch.adr = parse_assignment_expression();
- if (token.type == ',') {
- next_token();
- expression->builtin_prefetch.rw = parse_assignment_expression();
- }
- if (token.type == ',') {
- next_token();
- expression->builtin_prefetch.locality = parse_assignment_expression();
- }
+ add_anchor_token(',');
+ expression->builtin_types_compatible.left = parse_typename();
+ rem_anchor_token(',');
+ expect(',', end_error);
+ expression->builtin_types_compatible.right = parse_typename();
rem_anchor_token(')');
expect(')', end_error);
- expression->base.type = type_void;
+ expression->base.type = type_int;
return expression;
end_error:
static expression_t *parse_primary_expression(void)
{
switch (token.type) {
- case T_false: return parse_bool_const(false);
- case T_true: return parse_bool_const(true);
- case T_INTEGER: return parse_int_const();
- case T_CHARACTER_CONSTANT: return parse_character_constant();
- case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
- case T_FLOATINGPOINT: return parse_float_const();
+ case T_false: return parse_bool_const(false);
+ case T_true: return parse_bool_const(true);
+ case T_INTEGER: return parse_int_const();
+ case T_CHARACTER_CONSTANT: return parse_character_constant();
+ case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
+ case T_FLOATINGPOINT: return parse_float_const();
case T_STRING_LITERAL:
- case T_WIDE_STRING_LITERAL: return parse_string_const();
- case T_IDENTIFIER: return parse_reference();
+ case T_WIDE_STRING_LITERAL: return parse_string_const();
case T___FUNCTION__:
- case T___func__: return parse_function_keyword();
- case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword();
- case T___FUNCSIG__: return parse_funcsig_keyword();
- case T___FUNCDNAME__: return parse_funcdname_keyword();
- case T___builtin_offsetof: return parse_offsetof();
- case T___builtin_va_start: return parse_va_start();
- case T___builtin_va_arg: return parse_va_arg();
- case T___builtin_expect:
- case T___builtin_alloca:
- case T___builtin_inf:
- case T___builtin_inff:
- case T___builtin_infl:
- case T___builtin_nan:
- case T___builtin_nanf:
- case T___builtin_nanl:
- case T___builtin_huge_val:
- case T___builtin_va_end: return parse_builtin_symbol();
+ case T___func__: return parse_function_keyword();
+ case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword();
+ case T___FUNCSIG__: return parse_funcsig_keyword();
+ case T___FUNCDNAME__: return parse_funcdname_keyword();
+ case T___builtin_offsetof: return parse_offsetof();
+ case T___builtin_va_start: return parse_va_start();
+ case T___builtin_va_arg: return parse_va_arg();
+ case T___builtin_va_copy: return parse_va_copy();
case T___builtin_isgreater:
case T___builtin_isgreaterequal:
case T___builtin_isless:
case T___builtin_islessequal:
case T___builtin_islessgreater:
- case T___builtin_isunordered: return parse_compare_builtin();
- case T___builtin_constant_p: return parse_builtin_constant();
- case T___builtin_prefetch: return parse_builtin_prefetch();
- case T__assume: return parse_assume();
+ case T___builtin_isunordered: return parse_compare_builtin();
+ case T___builtin_constant_p: return parse_builtin_constant();
+ case T___builtin_types_compatible_p: return parse_builtin_types_compatible();
+ case T__assume: return parse_assume();
case T_ANDAND:
if (GNU_MODE)
return parse_label_address();
break;
- case '(': return parse_parenthesized_expression();
- case T___noop: return parse_noop_expression();
+ case '(': return parse_parenthesized_expression();
+ case T___noop: return parse_noop_expression();
+
+ /* Gracefully handle type names while parsing expressions. */
+ case T_IDENTIFIER:
+ if (!is_typedef_symbol(token.v.symbol)) {
+ return parse_reference();
+ }
+ /* FALLTHROUGH */
+ TYPENAME_START {
+ source_position_t const pos = *HERE;
+ type_t const *const type = parse_typename();
+ errorf(&pos, "encountered type '%T' while parsing expression", type);
+ return create_invalid_expression();
+ }
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
return select;
}
-static void check_call_argument(const function_parameter_t *parameter,
+static void check_call_argument(type_t *expected_type,
call_argument_t *argument, unsigned pos)
{
- type_t *expected_type = parameter->type;
type_t *expected_type_skip = skip_typeref(expected_type);
assign_error_t error = ASSIGN_ERROR_INCOMPATIBLE;
expression_t *arg_expr = argument->expression;
/* handle transparent union gnu extension */
if (is_type_union(expected_type_skip)
- && (expected_type_skip->base.modifiers
- & TYPE_MODIFIER_TRANSPARENT_UNION)) {
+ && (get_type_modifiers(expected_type) & DM_TRANSPARENT_UNION)) {
compound_t *union_decl = expected_type_skip->compound.compound;
type_t *best_type = NULL;
entity_t *entry = union_decl->members.entities;
}
error = semantic_assign(expected_type, arg_expr);
- argument->expression = create_implicit_cast(argument->expression,
- expected_type);
+ argument->expression = create_implicit_cast(arg_expr, expected_type);
if (error != ASSIGN_SUCCESS) {
/* report exact scope in error messages (like "in argument 3") */
}
}
+/**
+ * Handle the semantic restrictions of builtin calls
+ */
+static void handle_builtin_argument_restrictions(call_expression_t *call) {
+ switch (call->function->reference.entity->function.btk) {
+ case bk_gnu_builtin_return_address:
+ case bk_gnu_builtin_frame_address: {
+ /* argument must be constant */
+ call_argument_t *argument = call->arguments;
+
+ if (! is_constant_expression(argument->expression)) {
+ errorf(&call->base.source_position,
+ "argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ }
+ case bk_gnu_builtin_prefetch: {
+ /* second and third argument must be constant if existent */
+ call_argument_t *rw = call->arguments->next;
+ call_argument_t *locality = NULL;
+
+ if (rw != NULL) {
+ if (! is_constant_expression(rw->expression)) {
+ errorf(&call->base.source_position,
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ locality = rw->next;
+ }
+ if (locality != NULL) {
+ if (! is_constant_expression(locality->expression)) {
+ errorf(&call->base.source_position,
+ "third argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ locality = rw->next;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
/**
* Parse a call expression, ie. expression '( ... )'.
*
}
if (function_type == NULL && is_type_valid(type)) {
- errorf(HERE, "called object '%E' (type '%T') is not a pointer to a function", expression, orig_type);
+ errorf(HERE,
+ "called object '%E' (type '%T') is not a pointer to a function",
+ expression, orig_type);
}
/* parse arguments */
add_anchor_token(',');
if (token.type != ')') {
- call_argument_t *last_argument = NULL;
-
- while (true) {
- call_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
-
+ call_argument_t **anchor = &call->arguments;
+ for (;;) {
+ call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
argument->expression = parse_assignment_expression();
- if (last_argument == NULL) {
- call->arguments = argument;
- } else {
- last_argument->next = argument;
- }
- last_argument = argument;
+
+ *anchor = argument;
+ anchor = &argument->next;
if (token.type != ',')
break;
if (function_type == NULL)
return result;
+ /* check type and count of call arguments */
function_parameter_t *parameter = function_type->parameters;
call_argument_t *argument = call->arguments;
if (!function_type->unspecified_parameters) {
for (unsigned pos = 0; parameter != NULL && argument != NULL;
parameter = parameter->next, argument = argument->next) {
- check_call_argument(parameter, argument, ++pos);
+ check_call_argument(parameter->type, argument, ++pos);
}
if (parameter != NULL) {
}
}
- /* do default promotion */
+ /* do default promotion for other arguments */
for (; argument != NULL; argument = argument->next) {
type_t *type = argument->expression->base.type;
"function call has aggregate value");
}
+ if (call->function->kind == EXPR_REFERENCE) {
+ reference_expression_t *reference = &call->function->reference;
+ if (reference->entity->kind == ENTITY_FUNCTION &&
+ reference->entity->function.btk != bk_none)
+ handle_builtin_argument_restrictions(call);
+ }
+
end_error:
return result;
}
type_t *const type = skip_typeref(value->base.type);
if (!is_type_pointer(type)) {
- errorf(&value->base.source_position,
- "operand of delete must have pointer type");
+ if (is_type_valid(type)) {
+ errorf(&value->base.source_position,
+ "operand of delete must have pointer type");
+ }
} else if (warning.other &&
is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) {
warningf(&value->base.source_position,
static bool is_lvalue(const expression_t *expression)
{
- /* TODO: doesn't seem to be consistent with §6.3.2.1 (1) */
+ /* TODO: doesn't seem to be consistent with §6.3.2.1:1 */
switch (expression->kind) {
case EXPR_ARRAY_ACCESS:
case EXPR_COMPOUND_LITERAL:
type_left = get_unqualified_type(type_left);
type_right = get_unqualified_type(type_right);
- /* § 6.3.1.8 Usual arithmetic conversions */
+ /* §6.3.1.8 Usual arithmetic conversions */
if (type_left == type_long_double || type_right == type_long_double) {
return type_long_double;
} else if (type_left == type_double || type_right == type_double) {
/**
* Check the semantic restrictions for a div/mod expression.
*/
-static void semantic_divmod_arithmetic(binary_expression_t *expression) {
+static void semantic_divmod_arithmetic(binary_expression_t *expression)
+{
semantic_binexpr_arithmetic(expression);
warn_div_by_zero(expression);
}
static void warn_addsub_in_shift(const expression_t *const expr)
{
+ if (expr->base.parenthesized)
+ return;
+
char op;
switch (expr->kind) {
case EXPR_BINARY_ADD: op = '+'; break;
"suggest parentheses around '%c' inside shift", op);
}
-static void semantic_shift_op(binary_expression_t *expression)
+static bool semantic_shift(binary_expression_t *expression)
{
expression_t *const left = expression->left;
expression_t *const right = expression->right;
errorf(&expression->base.source_position,
"operands of shift operation must have integer types");
}
- return;
+ return false;
}
+ type_left = promote_integer(type_left);
+
+ if (is_constant_expression(right)) {
+ long count = fold_constant(right);
+ if (count < 0) {
+ warningf(&right->base.source_position,
+ "shift count must be non-negative");
+ } else if ((unsigned long)count >=
+ get_atomic_type_size(type_left->atomic.akind) * 8) {
+ warningf(&right->base.source_position,
+ "shift count must be less than type width");
+ }
+ }
+
+ type_right = promote_integer(type_right);
+ expression->right = create_implicit_cast(right, type_right);
+
+ return true;
+}
+
+static void semantic_shift_op(binary_expression_t *expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+
+ if (!semantic_shift(expression))
+ return;
+
if (warning.parentheses) {
warn_addsub_in_shift(left);
warn_addsub_in_shift(right);
}
- type_left = promote_integer(type_left);
- type_right = promote_integer(type_right);
+ type_t *const orig_type_left = left->base.type;
+ type_t * type_left = skip_typeref(orig_type_left);
+ type_left = promote_integer(type_left);
expression->left = create_implicit_cast(left, type_left);
- expression->right = create_implicit_cast(right, type_right);
expression->base.type = type_left;
}
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
- /* § 6.5.6 */
+ /* §6.5.6 */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
expression->left = create_implicit_cast(left, arithmetic_type);
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
- return;
} else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
check_pointer_arithmetic(&expression->base.source_position,
type_left, orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
source_position_t const *const pos = &expression->base.source_position;
- /* § 5.6.5 */
+ /* §5.6.5 */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
expression->left = create_implicit_cast(left, arithmetic_type);
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
- return;
} else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
check_pointer_arithmetic(&expression->base.source_position,
type_left, orig_type_left);
}
}
+static bool maybe_negative(expression_t const *const expr)
+{
+ return
+ !is_constant_expression(expr) ||
+ fold_constant(expr) < 0;
+}
+
/**
* Check the semantics of comparison expressions.
*
/* TODO non-arithmetic types */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
- /* test for signed vs unsigned compares */
- if (warning.sign_compare &&
- (expression->base.kind != EXPR_BINARY_EQUAL &&
- expression->base.kind != EXPR_BINARY_NOTEQUAL) &&
- (is_type_signed(type_left) != is_type_signed(type_right))) {
-
- /* check if 1 of the operands is a constant, in this case we just
- * check wether we can safely represent the resulting constant in
- * the type of the other operand. */
- expression_t *const_expr = NULL;
- expression_t *other_expr = NULL;
-
- if (is_constant_expression(left)) {
- const_expr = left;
- other_expr = right;
- } else if (is_constant_expression(right)) {
- const_expr = right;
- other_expr = left;
- }
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
- if (const_expr != NULL) {
- type_t *other_type = skip_typeref(other_expr->base.type);
- long val = fold_constant(const_expr);
- /* TODO: check if val can be represented by other_type */
- (void) other_type;
- (void) val;
+ /* test for signed vs unsigned compares */
+ if (warning.sign_compare && is_type_integer(arithmetic_type)) {
+ bool const signed_left = is_type_signed(type_left);
+ bool const signed_right = is_type_signed(type_right);
+ if (signed_left != signed_right) {
+ /* FIXME long long needs better const folding magic */
+ /* TODO check whether constant value can be represented by other type */
+ if ((signed_left && maybe_negative(left)) ||
+ (signed_right && maybe_negative(right))) {
+ warningf(&expression->base.source_position,
+ "comparison between signed and unsigned");
+ }
}
- warningf(&expression->base.source_position,
- "comparison between signed and unsigned");
}
- type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+
expression->left = create_implicit_cast(left, arithmetic_type);
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
}
}
+static void semantic_integer_assign(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
+ type_t *orig_type_left = left->base.type;
+ type_t *orig_type_right = right->base.type;
+
+ if (!is_valid_assignment_lhs(left))
+ return;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);
+
+ if (!is_type_integer(type_left) || !is_type_integer(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(&expression->base.source_position,
+ "operation needs integer types");
+ }
+ return;
+ }
+
+ /* combined instructions are tricky. We can't create an implicit cast on
+ * the left side, because we need the uncasted form for the store.
+ * The ast2firm pass has to know that left_type must be right_type
+ * for the arithmetic operation and create a cast by itself */
+ type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+ expression->right = create_implicit_cast(right, arithmetic_type);
+ expression->base.type = type_left;
+}
+
+static void semantic_shift_assign(binary_expression_t *expression)
+{
+ expression_t *left = expression->left;
+
+ if (!is_valid_assignment_lhs(left))
+ return;
+
+ if (!semantic_shift(expression))
+ return;
+
+ expression->base.type = skip_typeref(left->base.type);
+}
+
static void warn_logical_and_within_or(const expression_t *const expr)
{
if (expr->base.kind != EXPR_BINARY_LOGICAL_AND)
static bool expression_has_effect(const expression_t *const expr)
{
switch (expr->kind) {
- case EXPR_UNKNOWN: break;
- case EXPR_INVALID: return true; /* do NOT warn */
- case EXPR_REFERENCE: return false;
- case EXPR_REFERENCE_ENUM_VALUE: return false;
+ case EXPR_UNKNOWN: break;
+ case EXPR_INVALID: return true; /* do NOT warn */
+ case EXPR_REFERENCE: return false;
+ case EXPR_REFERENCE_ENUM_VALUE: return false;
/* suppress the warning for microsoft __noop operations */
- case EXPR_CONST: return expr->conste.is_ms_noop;
- case EXPR_CHARACTER_CONSTANT: return false;
- case EXPR_WIDE_CHARACTER_CONSTANT: return false;
- case EXPR_STRING_LITERAL: return false;
- case EXPR_WIDE_STRING_LITERAL: return false;
- case EXPR_LABEL_ADDRESS: return false;
+ case EXPR_CONST: return expr->conste.is_ms_noop;
+ case EXPR_CHARACTER_CONSTANT: return false;
+ case EXPR_WIDE_CHARACTER_CONSTANT: return false;
+ case EXPR_STRING_LITERAL: return false;
+ case EXPR_WIDE_STRING_LITERAL: return false;
+ case EXPR_LABEL_ADDRESS: return false;
case EXPR_CALL: {
const call_expression_t *const call = &expr->call;
- if (call->function->kind != EXPR_BUILTIN_SYMBOL)
+ if (call->function->kind != EXPR_REFERENCE)
return true;
- switch (call->function->builtin_symbol.symbol->ID) {
- case T___builtin_va_end: return true;
- default: return false;
+ switch (call->function->reference.entity->function.btk) {
+ /* FIXME: which builtins have no effect? */
+ default: return true;
}
}
/* Generate the warning if either the left or right hand side of a
* conditional expression has no effect */
case EXPR_CONDITIONAL: {
- const conditional_expression_t *const cond = &expr->conditional;
+ conditional_expression_t const *const cond = &expr->conditional;
+ expression_t const *const t = cond->true_expression;
return
- expression_has_effect(cond->true_expression) &&
+ (t == NULL || expression_has_effect(t)) &&
expression_has_effect(cond->false_expression);
}
- case EXPR_SELECT: return false;
- case EXPR_ARRAY_ACCESS: return false;
- case EXPR_SIZEOF: return false;
- case EXPR_CLASSIFY_TYPE: return false;
- case EXPR_ALIGNOF: return false;
-
- case EXPR_FUNCNAME: return false;
- case EXPR_BUILTIN_SYMBOL: break; /* handled in EXPR_CALL */
- case EXPR_BUILTIN_CONSTANT_P: return false;
- case EXPR_BUILTIN_PREFETCH: return true;
- case EXPR_OFFSETOF: return false;
- case EXPR_VA_START: return true;
- case EXPR_VA_ARG: return true;
- case EXPR_STATEMENT: return true; // TODO
- case EXPR_COMPOUND_LITERAL: return false;
-
- case EXPR_UNARY_NEGATE: return false;
- case EXPR_UNARY_PLUS: return false;
- case EXPR_UNARY_BITWISE_NEGATE: return false;
- case EXPR_UNARY_NOT: return false;
- case EXPR_UNARY_DEREFERENCE: return false;
- case EXPR_UNARY_TAKE_ADDRESS: return false;
- case EXPR_UNARY_POSTFIX_INCREMENT: return true;
- case EXPR_UNARY_POSTFIX_DECREMENT: return true;
- case EXPR_UNARY_PREFIX_INCREMENT: return true;
- case EXPR_UNARY_PREFIX_DECREMENT: return true;
+ case EXPR_SELECT: return false;
+ case EXPR_ARRAY_ACCESS: return false;
+ case EXPR_SIZEOF: return false;
+ case EXPR_CLASSIFY_TYPE: return false;
+ case EXPR_ALIGNOF: return false;
+
+ case EXPR_FUNCNAME: return false;
+ case EXPR_BUILTIN_CONSTANT_P: return false;
+ case EXPR_BUILTIN_TYPES_COMPATIBLE_P: return false;
+ case EXPR_OFFSETOF: return false;
+ case EXPR_VA_START: return true;
+ case EXPR_VA_ARG: return true;
+ case EXPR_VA_COPY: return true;
+ case EXPR_STATEMENT: return true; // TODO
+ case EXPR_COMPOUND_LITERAL: return false;
+
+ case EXPR_UNARY_NEGATE: return false;
+ case EXPR_UNARY_PLUS: return false;
+ case EXPR_UNARY_BITWISE_NEGATE: return false;
+ case EXPR_UNARY_NOT: return false;
+ case EXPR_UNARY_DEREFERENCE: return false;
+ case EXPR_UNARY_TAKE_ADDRESS: return false;
+ case EXPR_UNARY_POSTFIX_INCREMENT: return true;
+ case EXPR_UNARY_POSTFIX_DECREMENT: return true;
+ case EXPR_UNARY_PREFIX_INCREMENT: return true;
+ case EXPR_UNARY_PREFIX_DECREMENT: return true;
/* Treat void casts as if they have an effect in order to being able to
* suppress the warning */
return is_type_atomic(type, ATOMIC_TYPE_VOID);
}
- case EXPR_UNARY_CAST_IMPLICIT: return true;
- case EXPR_UNARY_ASSUME: return true;
- case EXPR_UNARY_DELETE: return true;
- case EXPR_UNARY_DELETE_ARRAY: return true;
- case EXPR_UNARY_THROW: return true;
-
- case EXPR_BINARY_ADD: return false;
- case EXPR_BINARY_SUB: return false;
- case EXPR_BINARY_MUL: return false;
- case EXPR_BINARY_DIV: return false;
- case EXPR_BINARY_MOD: return false;
- case EXPR_BINARY_EQUAL: return false;
- case EXPR_BINARY_NOTEQUAL: return false;
- case EXPR_BINARY_LESS: return false;
- case EXPR_BINARY_LESSEQUAL: return false;
- case EXPR_BINARY_GREATER: return false;
- case EXPR_BINARY_GREATEREQUAL: return false;
- case EXPR_BINARY_BITWISE_AND: return false;
- case EXPR_BINARY_BITWISE_OR: return false;
- case EXPR_BINARY_BITWISE_XOR: return false;
- case EXPR_BINARY_SHIFTLEFT: return false;
- case EXPR_BINARY_SHIFTRIGHT: return false;
- case EXPR_BINARY_ASSIGN: return true;
- case EXPR_BINARY_MUL_ASSIGN: return true;
- case EXPR_BINARY_DIV_ASSIGN: return true;
- case EXPR_BINARY_MOD_ASSIGN: return true;
- case EXPR_BINARY_ADD_ASSIGN: return true;
- case EXPR_BINARY_SUB_ASSIGN: return true;
- case EXPR_BINARY_SHIFTLEFT_ASSIGN: return true;
- case EXPR_BINARY_SHIFTRIGHT_ASSIGN: return true;
- case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
- case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
- case EXPR_BINARY_BITWISE_OR_ASSIGN: return true;
+ case EXPR_UNARY_CAST_IMPLICIT: return true;
+ case EXPR_UNARY_ASSUME: return true;
+ case EXPR_UNARY_DELETE: return true;
+ case EXPR_UNARY_DELETE_ARRAY: return true;
+ case EXPR_UNARY_THROW: return true;
+
+ case EXPR_BINARY_ADD: return false;
+ case EXPR_BINARY_SUB: return false;
+ case EXPR_BINARY_MUL: return false;
+ case EXPR_BINARY_DIV: return false;
+ case EXPR_BINARY_MOD: return false;
+ case EXPR_BINARY_EQUAL: return false;
+ case EXPR_BINARY_NOTEQUAL: return false;
+ case EXPR_BINARY_LESS: return false;
+ case EXPR_BINARY_LESSEQUAL: return false;
+ case EXPR_BINARY_GREATER: return false;
+ case EXPR_BINARY_GREATEREQUAL: return false;
+ case EXPR_BINARY_BITWISE_AND: return false;
+ case EXPR_BINARY_BITWISE_OR: return false;
+ case EXPR_BINARY_BITWISE_XOR: return false;
+ case EXPR_BINARY_SHIFTLEFT: return false;
+ case EXPR_BINARY_SHIFTRIGHT: return false;
+ case EXPR_BINARY_ASSIGN: return true;
+ case EXPR_BINARY_MUL_ASSIGN: return true;
+ case EXPR_BINARY_DIV_ASSIGN: return true;
+ case EXPR_BINARY_MOD_ASSIGN: return true;
+ case EXPR_BINARY_ADD_ASSIGN: return true;
+ case EXPR_BINARY_SUB_ASSIGN: return true;
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN: return true;
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
+ case EXPR_BINARY_BITWISE_OR_ASSIGN: return true;
/* Only examine the right hand side of && and ||, because the left hand
* side already has the effect of controlling the execution of the right
case EXPR_BINARY_COMMA:
return expression_has_effect(expr->binary.right);
- case EXPR_BINARY_ISGREATER: return false;
- case EXPR_BINARY_ISGREATEREQUAL: return false;
- case EXPR_BINARY_ISLESS: return false;
- case EXPR_BINARY_ISLESSEQUAL: return false;
- case EXPR_BINARY_ISLESSGREATER: return false;
- case EXPR_BINARY_ISUNORDERED: return false;
+ case EXPR_BINARY_ISGREATER: return false;
+ case EXPR_BINARY_ISGREATEREQUAL: return false;
+ case EXPR_BINARY_ISLESS: return false;
+ case EXPR_BINARY_ISLESSEQUAL: return false;
+ case EXPR_BINARY_ISLESSGREATER: return false;
+ case EXPR_BINARY_ISUNORDERED: return false;
}
internal_errorf(HERE, "unexpected expression");
CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
-CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
-CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
-CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
-CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
-CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, PREC_ASSIGNMENT, semantic_shift_assign)
+CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, PREC_ASSIGNMENT, semantic_shift_assign)
+CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, PREC_ASSIGNMENT, semantic_integer_assign)
+CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, PREC_ASSIGNMENT, semantic_integer_assign)
+CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PREC_ASSIGNMENT, semantic_integer_assign)
CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma)
* @param precedence the precedence of the operator
*/
static void register_infix_parser(parse_expression_infix_function parser,
- int token_type, unsigned precedence)
+ int token_type, precedence_t precedence)
{
expression_parser_function_t *entry = &expression_parsers[token_type];
*
* @param statement the switch statement to check
*/
-static void check_enum_cases(const switch_statement_t *statement) {
+static void check_enum_cases(const switch_statement_t *statement)
+{
const type_t *type = skip_typeref(statement->expression->base.type);
if (! is_type_enum(type))
return;
}
statement->gotos.expression = expression;
- } else {
- if (token.type != T_IDENTIFIER) {
- if (GNU_MODE)
- parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
- else
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_until_anchor();
- goto end_error;
- }
+ } else if (token.type == T_IDENTIFIER) {
symbol_t *symbol = token.v.symbol;
next_token();
-
statement->gotos.label = get_label(symbol);
+ } else {
+ if (GNU_MODE)
+ parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+ else
+ parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+ eat_until_anchor();
+ goto end_error;
}
/* remember the goto's in a list for later checking */
/* Only warn in C mode, because GCC does the same */
if (strict_mode) {
errorf(pos,
- "'return' with expression in function return 'void'");
+ "'return' with expression in function returning 'void'");
} else if (warning.other) {
warningf(pos,
- "'return' with expression in function return 'void'");
+ "'return' with expression in function returning 'void'");
}
}
} else {
parse_declaration(record_entity, DECL_FLAGS_NONE);
}
- if (before == NULL) {
- statement->declaration.declarations_begin = current_scope->entities;
- } else {
- statement->declaration.declarations_begin = before->base.next;
- }
- statement->declaration.declarations_end = current_scope->last_entity;
+ declaration_statement_t *const decl = &statement->declaration;
+ entity_t *const begin =
+ before != NULL ? before->base.next : current_scope->entities;
+ decl->declarations_begin = begin;
+ decl->declarations_end = begin != NULL ? current_scope->last_entity : NULL;
return statement;
}
next_token();
entity = get_entity(symbol, NAMESPACE_NORMAL);
- if (entity != NULL && entity->kind != ENTITY_NAMESPACE
- && entity->base.parent_scope == current_scope) {
- error_redefined_as_different_kind(&token.source_position,
- entity, ENTITY_NAMESPACE);
+ if (entity != NULL &&
+ entity->kind != ENTITY_NAMESPACE &&
+ entity->base.parent_scope == current_scope) {
+ if (!is_error_entity(entity)) {
+ error_redefined_as_different_kind(&token.source_position,
+ entity, ENTITY_NAMESPACE);
+ }
entity = NULL;
}
}
assert(current_scope == NULL);
scope_push(&unit->scope);
+
+ create_gnu_builtins();
+ if (c_mode & _MS)
+ create_microsoft_intrinsics();
}
translation_unit_t *finish_parsing(void)
return result;
}
-/* GCC allows global arrays without size and assigns them a length of one,
- * if no different declaration follows */
+/* §6.9.2:2 and §6.9.2:5: At the end of the translation incomplete arrays
+ * are given length one. */
static void complete_incomplete_arrays(void)
{
size_t n = ARR_LEN(incomplete_arrays);
new_type->array.has_implicit_size = true;
new_type->array.size = 1;
- type_t *const result = typehash_insert(new_type);
- if (type != result)
- free_type(type);
+ type_t *const result = identify_new_type(new_type);
decl->type = result;
}
incomplete_arrays = NULL;
}
+/**
+ * create a builtin function.
+ */
+static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
+{
+ symbol_t *symbol = symbol_table_insert(name);
+ entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
+ entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
+ entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
+ entity->declaration.type = function_type;
+ entity->declaration.implicit = true;
+ entity->base.symbol = symbol;
+ entity->base.source_position = builtin_source_position;
+
+ entity->function.btk = kind;
+
+ record_entity(entity, /*is_definition=*/false);
+ return entity;
+}
+
+
+/**
+ * Create predefined gnu builtins.
+ */
+static void create_gnu_builtins(void)
+{
+#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b)
+
+ GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t));
+ GNU_BUILTIN(huge_val, make_function_0_type(type_double));
+ GNU_BUILTIN(inf, make_function_0_type(type_double));
+ GNU_BUILTIN(inff, make_function_0_type(type_float));
+ GNU_BUILTIN(infl, make_function_0_type(type_long_double));
+ GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr));
+ GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr));
+ GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr));
+ GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist));
+ GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long));
+ GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
+ GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int));
+ GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int));
+ GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr));
+ GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void));
+
+#undef GNU_BUILTIN
+}
+
+/**
+ * Create predefined MS intrinsics.
+ */
+static void create_microsoft_intrinsics(void)
+{
+#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b)
+
+ /* intrinsics for all architectures */
+ MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
+ MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
+ MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
+ MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
+ MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short));
+ MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long));
+ MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64));
+
+ MS_BUILTIN(__debugbreak, make_function_0_type(type_void));
+ MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr));
+ MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr));
+ MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int));
+
+ /* x86/x64 only */
+ MS_BUILTIN(_enable, make_function_0_type(type_void));
+ MS_BUILTIN(_disable, make_function_0_type(type_void));
+ MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short));
+ MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short));
+ MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short));
+ MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char));
+ MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short));
+ MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long));
+ MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void));
+ MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
+ MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
+ MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long));
+ MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
+
+ if (machine_size <= 32) {
+ MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int));
+ MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int));
+ } else {
+ MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64));
+ MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64));
+ }
+
+#undef MS_BUILTIN
+}
+
/**
* Initialize the parser.
*/
{
sym_anonymous = symbol_table_insert("<anonymous>");
- if (c_mode & _MS) {
- /* add predefined symbols for extended-decl-modifier */
- sym_align = symbol_table_insert("align");
- sym_allocate = symbol_table_insert("allocate");
- sym_dllimport = symbol_table_insert("dllimport");
- sym_dllexport = symbol_table_insert("dllexport");
- sym_naked = symbol_table_insert("naked");
- sym_noinline = symbol_table_insert("noinline");
- sym_noreturn = symbol_table_insert("noreturn");
- sym_nothrow = symbol_table_insert("nothrow");
- sym_novtable = symbol_table_insert("novtable");
- sym_property = symbol_table_insert("property");
- sym_get = symbol_table_insert("get");
- sym_put = symbol_table_insert("put");
- sym_selectany = symbol_table_insert("selectany");
- sym_thread = symbol_table_insert("thread");
- sym_uuid = symbol_table_insert("uuid");
- sym_deprecated = symbol_table_insert("deprecated");
- sym_restrict = symbol_table_insert("restrict");
- sym_noalias = symbol_table_insert("noalias");
- }
memset(token_anchor_set, 0, sizeof(token_anchor_set));
init_expression_parsers();