/*
* This file is part of cparser.
- * Copyright (C) 2007-2008 Matthias Braun <matze@braunis.de>
+ * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#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 "printer.h"
#include "adt/bitfiddle.h"
#include "adt/error.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;
unsigned char alignment; /**< Alignment, 0 if not set. */
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;
static scope_t *current_scope = NULL;
/** Point to the current function declaration if inside a function. */
static function_t *current_function = NULL;
+static entity_t *current_entity = NULL;
static entity_t *current_init_decl = NULL;
static switch_statement_t *current_switch = NULL;
static statement_t *current_loop = NULL;
static label_statement_t **label_anchor = NULL;
/** current translation unit. */
static translation_unit_t *unit = NULL;
-/** true if we are in a type property context (evaluation only for type. */
+/** true if we are in a type property context (evaluation only for type) */
static bool in_type_prop = false;
-/** true in we are in a __extension__ context. */
+/** true if we are in an __extension__ context. */
static bool in_gcc_extension = false;
static struct obstack temp_obst;
static entity_t *anonymous_entity;
+static declaration_t **incomplete_arrays;
#define PUSH_PARENT(stmt) \
#define POP_PARENT ((void)(current_parent = prev_parent))
/** 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;
+static symbol_t *sym_anonymous = 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 expression_t *parse_sub_expression(precedence_t);
+static expression_t *parse_subexpression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
static void parse_externals(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 entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
declarator_flags_t flags);
-static entity_t *record_entity(entity_t *entity, bool is_definition);
-
static void semantic_comparison(binary_expression_t *expression);
#define STORAGE_CLASSES \
case T_union: \
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
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
-#define EXPRESSION_START \
- case '!': \
- case '&': \
- case '(': \
- case '*': \
- case '+': \
- case '-': \
- case '~': \
- case T_ANDAND: \
- case T_CHARACTER_CONSTANT: \
- case T_FLOATINGPOINT: \
- case T_INTEGER: \
- case T_MINUSMINUS: \
- case T_PLUSPLUS: \
- case T_STRING_LITERAL: \
- case T_WIDE_CHARACTER_CONSTANT: \
- case T_WIDE_STRING_LITERAL: \
- case T___FUNCDNAME__: \
- case T___FUNCSIG__: \
- 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___func__: \
- case T___noop: \
- case T__assume: \
- case T_delete: \
- case T_false: \
- case T_sizeof: \
- case T_throw: \
+#define EXPRESSION_START \
+ case '!': \
+ case '&': \
+ case '(': \
+ case '*': \
+ case '+': \
+ case '-': \
+ case '~': \
+ case T_ANDAND: \
+ case T_CHARACTER_CONSTANT: \
+ case T_FLOATINGPOINT: \
+ case T_FLOATINGPOINT_HEXADECIMAL: \
+ case T_INTEGER: \
+ case T_INTEGER_HEXADECIMAL: \
+ case T_INTEGER_OCTAL: \
+ case T_MINUSMINUS: \
+ case T_PLUSPLUS: \
+ case T_STRING_LITERAL: \
+ case T_WIDE_CHARACTER_CONSTANT: \
+ case T_WIDE_STRING_LITERAL: \
+ case T___FUNCDNAME__: \
+ case T___FUNCSIG__: \
+ case T___FUNCTION__: \
+ case T___PRETTY_FUNCTION__: \
+ case T___alignof__: \
+ case T___builtin_classify_type: \
+ case T___builtin_constant_p: \
+ 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_offsetof: \
+ case T___builtin_va_arg: \
+ case T___builtin_va_copy: \
+ case T___builtin_va_start: \
+ case T___func__: \
+ case T___noop: \
+ case T__assume: \
+ case T_delete: \
+ case T_false: \
+ case T_sizeof: \
+ case T_throw: \
case T_true:
-/**
- * Allocate an AST node with given size and
- * initialize all fields with zero.
- */
-static void *allocate_ast_zero(size_t size)
-{
- void *res = allocate_ast(size);
- memset(res, 0, size);
- return res;
-}
-
-static size_t get_entity_struct_size(entity_kind_t kind)
-{
- static const size_t sizes[] = {
- [ENTITY_VARIABLE] = sizeof(variable_t),
- [ENTITY_COMPOUND_MEMBER] = sizeof(variable_t),
- [ENTITY_FUNCTION] = sizeof(function_t),
- [ENTITY_TYPEDEF] = sizeof(typedef_t),
- [ENTITY_STRUCT] = sizeof(compound_t),
- [ENTITY_UNION] = sizeof(compound_t),
- [ENTITY_ENUM] = sizeof(enum_t),
- [ENTITY_ENUM_VALUE] = sizeof(enum_value_t),
- [ENTITY_LABEL] = sizeof(label_t),
- [ENTITY_LOCAL_LABEL] = sizeof(label_t),
- [ENTITY_NAMESPACE] = sizeof(namespace_t)
- };
- assert(kind < sizeof(sizes) / sizeof(sizes[0]));
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-static entity_t *allocate_entity_zero(entity_kind_t kind)
-{
- size_t size = get_entity_struct_size(kind);
- entity_t *entity = allocate_ast_zero(size);
- entity->kind = kind;
- return entity;
-}
-
/**
* Returns the size of a statement node.
*
[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_LITERAL_INTEGER] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t),
+ [EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_CHARACTER] = sizeof(literal_expression_t),
+ [EXPR_LITERAL_WIDE_CHARACTER] = sizeof(literal_expression_t),
+ [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
+ [EXPR_WIDE_STRING_LITERAL] = sizeof(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 a statement node of given kind and initialize all
- * fields with zero.
+ * fields with zero. Sets its source position to the position
+ * of the current token.
*/
static statement_t *allocate_statement_zero(statement_kind_t 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)
{
}
/**
- * Creates a new invalid expression.
+ * Creates a new invalid expression at the source position
+ * of the current token.
*/
static expression_t *create_invalid_expression(void)
{
return allocate_statement_zero(STATEMENT_EMPTY);
}
-/**
- * Returns the size of a type node.
- *
- * @param kind the type kind
- */
-static size_t get_type_struct_size(type_kind_t kind)
-{
- static const size_t sizes[] = {
- [TYPE_ATOMIC] = sizeof(atomic_type_t),
- [TYPE_COMPLEX] = sizeof(complex_type_t),
- [TYPE_IMAGINARY] = sizeof(imaginary_type_t),
- [TYPE_BITFIELD] = sizeof(bitfield_type_t),
- [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
- [TYPE_COMPOUND_UNION] = sizeof(compound_type_t),
- [TYPE_ENUM] = sizeof(enum_type_t),
- [TYPE_FUNCTION] = sizeof(function_type_t),
- [TYPE_POINTER] = sizeof(pointer_type_t),
- [TYPE_ARRAY] = sizeof(array_type_t),
- [TYPE_BUILTIN] = sizeof(builtin_type_t),
- [TYPE_TYPEDEF] = sizeof(typedef_type_t),
- [TYPE_TYPEOF] = sizeof(typeof_type_t),
- };
- assert(sizeof(sizes) / sizeof(sizes[0]) == (int) TYPE_TYPEOF + 1);
- assert(kind <= TYPE_TYPEOF);
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-/**
- * Allocate a type node of given kind and initialize all
- * fields with zero.
- *
- * @param kind type kind to allocate
- */
-static type_t *allocate_type_zero(type_kind_t kind)
+static function_parameter_t *allocate_parameter(type_t *const type)
{
- size_t size = get_type_struct_size(kind);
- type_t *res = obstack_alloc(type_obst, size);
- memset(res, 0, size);
- res->base.kind = kind;
-
- return res;
+ function_parameter_t *const param
+ = obstack_alloc(type_obst, sizeof(*param));
+ memset(param, 0, sizeof(*param));
+ param->type = type;
+ return param;
}
/**
[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);
#endif
}
+static inline bool next_if(int const type)
+{
+ if (token.type == type) {
+ next_token();
+ return true;
+ } else {
+ return false;
+ }
+}
+
/**
* 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];
}
/**
- * Adds a token to the token anchor set (a multi-set).
+ * Adds a token type to the token type anchor set (a multi-set).
*/
static void add_anchor_token(int token_type)
{
++token_anchor_set[token_type];
}
+/**
+ * Set the number of tokens types of the given type
+ * to zero and return the old count.
+ */
static int save_and_reset_anchor_state(int token_type)
{
assert(0 <= token_type && token_type < T_LAST_TOKEN);
return count;
}
+/**
+ * Restore the number of token types to the given count.
+ */
static void restore_anchor_state(int token_type, int count)
{
assert(0 <= token_type && token_type < T_LAST_TOKEN);
}
/**
- * Remove a token from the token anchor set (a multi-set).
+ * Remove a token type from the token type anchor set (a multi-set).
*/
static void rem_anchor_token(int token_type)
{
--token_anchor_set[token_type];
}
+/**
+ * Return true if the token type of the current token is
+ * in the anchor set.
+ */
static bool at_anchor(void)
{
if (token.type < 0)
}
/**
- * Eat tokens until a matching token is found.
+ * Eat tokens until a matching token type is found.
*/
static void eat_until_matching_token(int type)
{
}
}
+/**
+ * Eat a whole block from input tokens.
+ */
static void eat_block(void)
{
eat_until_matching_token('{');
- if (token.type == '}')
- next_token();
+ next_if('}');
}
-#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.
}
/**
- * Expect the the current token is the expected token.
+ * Expect the current token is the expected token.
* If not, generate an error, eat the current statement,
* and goto the end_error label.
*/
-#define expect(expected) \
+#define expect(expected, error_label) \
do { \
if (UNLIKELY(token.type != (expected))) { \
parse_error_expected(NULL, (expected), NULL); \
add_anchor_token(expected); \
eat_until_anchor(); \
- if (token.type == expected) \
- next_token(); \
+ next_if((expected)); \
rem_anchor_token(expected); \
- goto end_error; \
+ goto error_label; \
} \
next_token(); \
} while (0)
+/**
+ * Push a given scope on the scope stack and make it the
+ * current scope
+ */
static scope_t *scope_push(scope_t *new_scope)
{
if (current_scope != NULL) {
return old_scope;
}
+/**
+ * Pop the current scope from the scope stack.
+ */
static void scope_pop(scope_t *old_scope)
{
current_scope = old_scope;
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.
return (int) akind;
}
+/**
+ * Return the type rank for an atomic type.
+ */
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);
}
+/**
+ * §6.3.1.1:2 Do integer promotion for a given type.
+ *
+ * @param type the type to promote
+ * @return the promoted type
+ */
static type_t *promote_integer(type_t *type)
{
if (type->kind == TYPE_BITFIELD)
}
/**
- * Check if a given expression represents the 0 pointer constant.
+ * Check if a given expression represents a null pointer constant.
+ *
+ * @param expression the expression to check
*/
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_to_bool(expression);
}
/**
}
}
-/** 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)
{
static expression_t *parse_constant_expression(void)
{
- expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
+ expression_t *result = parse_subexpression(PREC_CONDITIONAL);
if (!is_constant_expression(result)) {
errorf(&result->base.source_position,
- "expression '%E' is not constant\n", result);
+ "expression '%E' is not constant", result);
}
return result;
static expression_t *parse_assignment_expression(void)
{
- return parse_sub_expression(PREC_ASSIGNMENT);
+ return parse_subexpression(PREC_ASSIGNMENT);
+}
+
+static void warn_string_concat(const source_position_t *pos)
+{
+ if (warning.traditional) {
+ warningf(pos, "traditional C rejects string constant concatenation");
+ }
}
static string_t parse_string_literals(void)
{
assert(token.type == T_STRING_LITERAL);
- string_t result = token.v.string;
+ string_t result = token.literal;
next_token();
while (token.type == T_STRING_LITERAL) {
- result = concat_strings(&result, &token.v.string);
+ warn_string_concat(&token.source_position);
+ result = concat_strings(&result, &token.literal);
next_token();
}
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.
- */
-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.
- */
-static void parse_gnu_attribute_const_arg(gnu_attribute_t *attribute)
-{
- expression_t *expression;
- add_anchor_token(')');
- expression = parse_constant_expression();
- rem_anchor_token(')');
- expect(')');
- attribute->u.argument = fold_constant(expression);
- return;
+ * 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 attribute_argument_t *parse_attribute_arguments(void)
+{
+ attribute_argument_t *first = NULL;
+ attribute_argument_t **anchor = &first;
+ if (token.type != ')') do {
+ 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.symbol;
+ argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL;
+ argument->v.symbol = symbol;
+ next_token();
+ } else {
+ /* must be an expression */
+ expression_t *expression = parse_assignment_expression();
+
+ argument->kind = ATTRIBUTE_ARGUMENT_EXPRESSION;
+ argument->v.expression = expression;
+ }
+
+ /* append argument */
+ *anchor = argument;
+ anchor = &argument->next;
+ } while (next_if(','));
+ expect(')', end_error);
+
+ return first;
+
end_error:
- attribute->invalid = true;
+ /* TODO... */
+ return first;
}
-/**
- * parse a list of constant expressions arguments.
- */
-static void parse_gnu_attribute_const_arg_list(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_asm(void)
{
- argument_list_t **list = &attribute->u.arguments;
- argument_list_t *entry;
- expression_t *expression;
- add_anchor_token(')');
- add_anchor_token(',');
- 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(')');
- return;
+ eat(T_asm);
+
+ attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
+
+ expect('(', end_error);
+ attribute->a.arguments = parse_attribute_arguments();
+ return attribute;
+
end_error:
- attribute->invalid = true;
+ return NULL;
}
-/**
- * parse one string literal argument.
- */
-static void parse_gnu_attribute_string_arg(gnu_attribute_t *attribute,
- string_t *string)
+static symbol_t *get_symbol_from_token(void)
{
- add_anchor_token('(');
- if (token.type != T_STRING_LITERAL) {
- parse_error_expected("while parsing attribute directive",
- T_STRING_LITERAL, NULL);
- goto end_error;
+ switch(token.type) {
+ case T_IDENTIFIER:
+ return token.symbol;
+ 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 get_token_symbol(&token);
+ default:
+ return NULL;
}
- *string = parse_string_literals();
- rem_anchor_token('(');
- expect(')');
- return;
-end_error:
- attribute->invalid = true;
}
-/**
- * parse one tls model.
- */
-static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_gnu_single(void)
{
- 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;
- }
- }
- errorf(HERE, "'%s' is an unrecognized tls model", string.begin);
+ /* 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;
}
- attribute->invalid = true;
-}
-/**
- * parse one tls model.
- */
-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;
- }
- }
- errorf(HERE, "'%s' is an unrecognized visibility", string.begin);
+ 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;
}
- attribute->invalid = true;
-}
-/**
- * parse one (code) model.
- */
-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 (kind >= ATTRIBUTE_GNU_LAST) {
+ if (warning.attribute) {
+ warningf(HERE, "unknown attribute '%s' ignored", name);
}
- errorf(HERE, "'%s' is an unrecognized model", string.begin);
+ /* TODO: we should still save the attribute in the list... */
+ kind = ATTRIBUTE_UNKNOWN;
}
- attribute->invalid = true;
-}
-static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute)
-{
- /* TODO: find out what is allowed here... */
+ attribute_t *attribute = allocate_attribute_zero(kind);
- /* at least: byte, word, pointer, list of machine modes
- * __XXX___ is interpreted as XXX */
- add_anchor_token(')');
+ /* parse arguments */
+ if (next_if('('))
+ attribute->a.arguments = parse_attribute_arguments();
- if (token.type != T_IDENTIFIER) {
- expect(T_IDENTIFIER);
- }
-
- /* 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();
+ return attribute;
- rem_anchor_token(')');
- expect(')');
- return;
end_error:
- attribute->invalid = true;
+ return NULL;
}
-/**
- * parse one interrupt argument.
- */
-static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute)
+static attribute_t *parse_attribute_gnu(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);
- }
- attribute->invalid = true;
-}
+ attribute_t *first = NULL;
+ attribute_t **anchor = &first;
-/**
- * parse ( identifier, const expression, const expression )
- */
-static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
-{
- static const char *const format_names[] = {
- "printf",
- "scanf",
- "strftime",
- "strfmon"
- };
- int i;
+ eat(T___attribute__);
+ expect('(', end_error);
+ expect('(', end_error);
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing format attribute directive", 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)
- break;
- }
- if (i >= 4) {
- if (warning.attribute)
- warningf(HERE, "'%s' is an unrecognized format function type", name);
- }
- next_token();
+ if (token.type != ')') do {
+ attribute_t *attribute = parse_attribute_gnu_single();
+ if (attribute == NULL)
+ goto end_error;
- expect(',');
- add_anchor_token(')');
- add_anchor_token(',');
- parse_constant_expression();
- rem_anchor_token(',');
- rem_anchor_token(')');
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
+ expect(')', end_error);
+ expect(')', end_error);
- expect(',');
- add_anchor_token(')');
- parse_constant_expression();
- rem_anchor_token(')');
- expect(')');
- return;
end_error:
- attribute->u.value = true;
+ return first;
}
-static void check_no_argument(gnu_attribute_t *attribute, const char *name)
+/** Parse attributes. */
+static attribute_t *parse_attributes(attribute_t *first)
{
- if (!attribute->have_arguments)
- return;
+ attribute_t **anchor = &first;
+ for (;;) {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
- /* 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;
-}
+ attribute_t *attribute;
+ switch (token.type) {
+ case T___attribute__:
+ attribute = parse_attribute_gnu();
+ break;
-/**
- * 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)
-{
- gnu_attribute_t *head = *attributes;
- gnu_attribute_t *last = *attributes;
- decl_modifiers_t modifiers = 0;
- gnu_attribute_t *attribute;
+ case T_asm:
+ attribute = parse_attribute_asm();
+ break;
- eat(T___attribute__);
- expect('(');
- expect('(');
+ case T_cdecl:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+ break;
- 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;
- }
+ case T__fastcall:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+ break;
+ case T__forceinline:
next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+ break;
- 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;
+ case T__stdcall:
+ next_token();
+ attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+ break;
- attribute = NULL;
- if (kind == GNU_AK_LAST) {
- if (warning.attribute)
- warningf(HERE, "'%s' attribute directive ignored", name);
+ 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;
- /* skip possible arguments */
- if (token.type == '(') {
- eat_until_matching_token(')');
- }
- } else {
- /* check for arguments */
- attribute = allocate_gnu_attribute(kind);
- if (token.type == '(') {
- next_token();
- if (token.type == ')') {
- /* empty args are allowed */
- next_token();
- } else
- attribute->have_arguments = true;
- }
-
- switch (kind) {
- case GNU_AK_VOLATILE:
- case GNU_AK_NAKED:
- case GNU_AK_MALLOC:
- case GNU_AK_WEAK:
- case GNU_AK_COMMON:
- case GNU_AK_NOCOMMON:
- case GNU_AK_SHARED:
- case GNU_AK_NOTSHARED:
- case GNU_AK_NO_INSTRUMENT_FUNCTION:
- case GNU_AK_WARN_UNUSED_RESULT:
- case GNU_AK_LONGCALL:
- case GNU_AK_SHORTCALL:
- case GNU_AK_LONG_CALL:
- case GNU_AK_SHORT_CALL:
- case GNU_AK_FUNCTION_VECTOR:
- case GNU_AK_INTERRUPT_HANDLER:
- case GNU_AK_NMI_HANDLER:
- case GNU_AK_NESTING:
- case GNU_AK_NEAR:
- case GNU_AK_FAR:
- case GNU_AK_SIGNAL:
- case GNU_AK_EIGTHBIT_DATA:
- case GNU_AK_TINY_DATA:
- case GNU_AK_SAVEALL:
- case GNU_AK_FLATTEN:
- case GNU_AK_SSEREGPARM:
- case GNU_AK_EXTERNALLY_VISIBLE:
- case GNU_AK_RETURN_TWICE:
- case GNU_AK_MAY_ALIAS:
- case GNU_AK_MS_STRUCT:
- case GNU_AK_GCC_STRUCT:
- goto no_arg;
-
- case GNU_AK_CDECL: modifiers |= DM_CDECL; goto no_arg;
- case GNU_AK_FASTCALL: modifiers |= DM_FASTCALL; goto no_arg;
- case GNU_AK_STDCALL: modifiers |= DM_STDCALL; goto no_arg;
- case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg;
- case GNU_AK_USED: modifiers |= DM_USED; goto no_arg;
- case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg;
- case GNU_AK_CONST: modifiers |= DM_CONST; goto no_arg;
- case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg;
- case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg;
- case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg;
- case GNU_AK_PACKED: modifiers |= DM_PACKED; goto no_arg;
- case GNU_AK_NOINLINE: modifiers |= DM_NOINLINE; goto no_arg;
- case GNU_AK_NORETURN: modifiers |= DM_NORETURN; goto no_arg;
- case GNU_AK_NOTHROW: modifiers |= DM_NOTHROW; goto no_arg;
- case GNU_AK_TRANSPARENT_UNION: modifiers |= DM_TRANSPARENT_UNION; goto no_arg;
- case GNU_AK_CONSTRUCTOR: modifiers |= DM_CONSTRUCTOR; goto no_arg;
- case GNU_AK_DESTRUCTOR: modifiers |= DM_DESTRUCTOR; goto no_arg;
- case GNU_AK_DEPRECATED: modifiers |= DM_DEPRECATED; goto no_arg;
-
- case GNU_AK_ALIGNED:
- /* __align__ may be used without an argument */
- if (attribute->have_arguments) {
- parse_gnu_attribute_const_arg(attribute);
- }
- break;
-
- case GNU_AK_FORMAT_ARG:
- case GNU_AK_REGPARM:
- case GNU_AK_TRAP_EXIT:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_const_arg(attribute);
- break;
- case GNU_AK_ALIAS:
- case GNU_AK_SECTION:
- case GNU_AK_SP_SWITCH:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
- break;
- case GNU_AK_FORMAT:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- attribute->invalid = true;
- } else
- parse_gnu_attribute_format_args(attribute);
- break;
- case GNU_AK_WEAKREF:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_string_arg(attribute, &attribute->u.string);
- break;
- case GNU_AK_NONNULL:
- if (attribute->have_arguments)
- parse_gnu_attribute_const_arg_list(attribute);
- break;
- case GNU_AK_TLS_MODEL:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else
- parse_gnu_attribute_tls_model_arg(attribute);
- break;
- case GNU_AK_VISIBILITY:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else
- parse_gnu_attribute_visibility_arg(attribute);
- break;
- case GNU_AK_MODEL:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else {
- parse_gnu_attribute_model_arg(attribute);
- }
- break;
- case GNU_AK_MODE:
- if (!attribute->have_arguments) {
- /* should have arguments */
- errorf(HERE, "wrong number of arguments specified for '%s' attribute", name);
- } else {
- parse_gnu_attribute_mode_arg(attribute);
- }
- break;
- case GNU_AK_INTERRUPT:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_interrupt_arg(attribute);
- break;
- case GNU_AK_SENTINEL:
- /* may have one string argument */
- if (attribute->have_arguments)
- parse_gnu_attribute_const_arg(attribute);
- break;
- case GNU_AK_LAST:
- /* already handled */
- break;
-
-no_arg:
- check_no_argument(attribute, name);
- }
- }
- if (attribute != NULL) {
- if (last != NULL) {
- last->next = attribute;
- last = attribute;
- } else {
- head = last = attribute;
- }
- }
-
- if (token.type != ',')
- break;
- next_token();
- }
- }
- expect(')');
- expect(')');
-end_error:
- *attributes = head;
-
- return modifiers;
-}
-
-/**
- * Parse GNU attributes.
- */
-static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes)
-{
- decl_modifiers_t modifiers = 0;
-
- while (true) {
- switch (token.type) {
- case T___attribute__:
- modifiers |= parse_gnu_attribute(attributes);
- continue;
-
- case T_asm:
- next_token();
- expect('(');
- if (token.type != T_STRING_LITERAL) {
- parse_error_expected("while parsing assembler attribute",
- T_STRING_LITERAL, NULL);
- eat_until_matching_token('(');
- break;
- } else {
- parse_string_literals();
- }
- expect(')');
- continue;
-
- case T_cdecl: modifiers |= DM_CDECL; break;
- case T__fastcall: modifiers |= DM_FASTCALL; break;
- case T__stdcall: modifiers |= DM_STDCALL; break;
-
- case T___thiscall:
- /* TODO record modifier */
- if (warning.other)
- warningf(HERE, "Ignoring declaration modifier %K", &token);
- break;
-
-end_error:
- default: return modifiers;
+ default:
+ return first;
}
- next_token();
+ *anchor = attribute;
+ anchor = &attribute->next;
}
}
-static void mark_vars_read(expression_t *expr, variable_t *lhs_var);
+static void mark_vars_read(expression_t *expr, entity_t *lhs_ent);
-static variable_t *determine_lhs_var(expression_t *const expr,
- variable_t *lhs_var)
+static entity_t *determine_lhs_ent(expression_t *const expr,
+ entity_t *lhs_ent)
{
switch (expr->kind) {
case EXPR_REFERENCE: {
entity_t *const entity = expr->reference.entity;
- /* we should only find variables as lavlues... */
- if (entity->base.kind != ENTITY_VARIABLE)
+ /* we should only find variables as lvalues... */
+ if (entity->base.kind != ENTITY_VARIABLE
+ && entity->base.kind != ENTITY_PARAMETER)
return NULL;
- return &entity->variable;
+ return entity;
}
case EXPR_ARRAY_ACCESS: {
- expression_t *const ref = expr->array_access.array_ref;
- variable_t * var = NULL;
+ expression_t *const ref = expr->array_access.array_ref;
+ entity_t * ent = NULL;
if (is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
- var = determine_lhs_var(ref, lhs_var);
- lhs_var = var;
+ ent = determine_lhs_ent(ref, lhs_ent);
+ lhs_ent = ent;
} else {
- mark_vars_read(expr->select.compound, lhs_var);
+ mark_vars_read(expr->select.compound, lhs_ent);
}
- mark_vars_read(expr->array_access.index, lhs_var);
- return var;
+ mark_vars_read(expr->array_access.index, lhs_ent);
+ return ent;
}
case EXPR_SELECT: {
if (is_type_compound(skip_typeref(expr->base.type))) {
- return determine_lhs_var(expr->select.compound, lhs_var);
+ return determine_lhs_ent(expr->select.compound, lhs_ent);
} else {
- mark_vars_read(expr->select.compound, lhs_var);
+ mark_vars_read(expr->select.compound, lhs_ent);
return NULL;
}
}
expression_t *const val = expr->unary.value;
if (val->kind == EXPR_UNARY_TAKE_ADDRESS) {
/* *&x is a NOP */
- return determine_lhs_var(val->unary.value, lhs_var);
+ return determine_lhs_ent(val->unary.value, lhs_ent);
} else {
mark_vars_read(val, NULL);
return NULL;
}
}
-#define VAR_ANY ((variable_t*)-1)
+#define ENT_ANY ((entity_t*)-1)
/**
- * Mark declarations, which are read. This is used to deted variables, which
+ * Mark declarations, which are read. This is used to detect variables, which
* are never read.
* Example:
* x = x + 1;
* x and y are not detected as "not read", because multiple variables are
* involved.
*/
-static void mark_vars_read(expression_t *const expr, variable_t *lhs_var)
+static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
{
switch (expr->kind) {
case EXPR_REFERENCE: {
entity_t *const entity = expr->reference.entity;
- if (entity->kind != ENTITY_VARIABLE)
+ if (entity->kind != ENTITY_VARIABLE
+ && entity->kind != ENTITY_PARAMETER)
return;
- variable_t *variable = &entity->variable;
- if (lhs_var != variable && lhs_var != VAR_ANY) {
- variable->read = true;
+ if (lhs_ent != entity && lhs_ent != ENT_ANY) {
+ if (entity->kind == ENTITY_VARIABLE) {
+ entity->variable.read = true;
+ } else {
+ entity->parameter.read = true;
+ }
}
return;
}
// TODO lhs_decl should depend on whether true/false have an effect
mark_vars_read(expr->conditional.condition, NULL);
if (expr->conditional.true_expression != NULL)
- mark_vars_read(expr->conditional.true_expression, lhs_var);
- mark_vars_read(expr->conditional.false_expression, lhs_var);
+ mark_vars_read(expr->conditional.true_expression, lhs_ent);
+ mark_vars_read(expr->conditional.false_expression, lhs_ent);
return;
case EXPR_SELECT:
- if (lhs_var == VAR_ANY && !is_type_compound(skip_typeref(expr->base.type)))
- lhs_var = NULL;
- mark_vars_read(expr->select.compound, lhs_var);
+ if (lhs_ent == ENT_ANY
+ && !is_type_compound(skip_typeref(expr->base.type)))
+ lhs_ent = NULL;
+ mark_vars_read(expr->select.compound, lhs_ent);
return;
case EXPR_ARRAY_ACCESS: {
expression_t *const ref = expr->array_access.array_ref;
- mark_vars_read(ref, lhs_var);
- lhs_var = determine_lhs_var(ref, lhs_var);
- mark_vars_read(expr->array_access.index, lhs_var);
+ mark_vars_read(ref, lhs_ent);
+ lhs_ent = determine_lhs_ent(ref, lhs_ent);
+ mark_vars_read(expr->array_access.index, lhs_ent);
return;
}
case EXPR_VA_ARG:
- mark_vars_read(expr->va_arge.ap, lhs_var);
+ 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))
- lhs_var = NULL;
+ lhs_ent = NULL;
goto unary;
case EXPR_UNARY_DEREFERENCE:
case EXPR_UNARY_DELETE:
case EXPR_UNARY_DELETE_ARRAY:
- if (lhs_var == VAR_ANY)
- lhs_var = NULL;
+ if (lhs_ent == ENT_ANY)
+ lhs_ent = NULL;
goto unary;
case EXPR_UNARY_NEGATE:
case EXPR_UNARY_CAST_IMPLICIT:
case EXPR_UNARY_ASSUME:
unary:
- mark_vars_read(expr->unary.value, lhs_var);
+ mark_vars_read(expr->unary.value, lhs_ent);
return;
case EXPR_BINARY_ADD:
case EXPR_BINARY_ISLESSEQUAL:
case EXPR_BINARY_ISLESSGREATER:
case EXPR_BINARY_ISUNORDERED:
- mark_vars_read(expr->binary.left, lhs_var);
- mark_vars_read(expr->binary.right, lhs_var);
+ mark_vars_read(expr->binary.left, lhs_ent);
+ mark_vars_read(expr->binary.right, lhs_ent);
return;
case EXPR_BINARY_ASSIGN:
case EXPR_BINARY_BITWISE_AND_ASSIGN:
case EXPR_BINARY_BITWISE_XOR_ASSIGN:
case EXPR_BINARY_BITWISE_OR_ASSIGN: {
- if (lhs_var == VAR_ANY)
- lhs_var = NULL;
- lhs_var = determine_lhs_var(expr->binary.left, lhs_var);
- mark_vars_read(expr->binary.right, lhs_var);
+ if (lhs_ent == ENT_ANY)
+ lhs_ent = NULL;
+ lhs_ent = determine_lhs_ent(expr->binary.left, lhs_ent);
+ mark_vars_read(expr->binary.right, lhs_ent);
return;
}
case EXPR_VA_START:
- determine_lhs_var(expr->va_starte.ap, lhs_var);
+ determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
+ EXPR_LITERAL_CASES
case EXPR_UNKNOWN:
case EXPR_INVALID:
- case EXPR_CONST:
- case EXPR_CHARACTER_CONSTANT:
- case EXPR_WIDE_CHARACTER_CONSTANT:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO init?
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:
- case EXPR_BINARY_BUILTIN_EXPECT:
case EXPR_REFERENCE_ENUM_VALUE:
return;
}
static designator_t *parse_designation(void)
{
- designator_t *result = NULL;
- designator_t *last = NULL;
+ designator_t *result = NULL;
+ designator_t **anchor = &result;
- while (true) {
+ for (;;) {
designator_t *designator;
switch (token.type) {
case '[':
add_anchor_token(']');
designator->array_index = parse_constant_expression();
rem_anchor_token(']');
- expect(']');
+ expect(']', end_error);
break;
case '.':
designator = allocate_ast_zero(sizeof(designator[0]));
T_IDENTIFIER, NULL);
return NULL;
}
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
next_token();
break;
default:
- expect('=');
+ expect('=', end_error);
return result;
}
assert(designator != NULL);
- if (last != NULL) {
- last->next = designator;
- } else {
- result = designator;
- }
- last = designator;
+ *anchor = designator;
+ anchor = &designator->next;
}
end_error:
return NULL;
}
-static initializer_t *initializer_from_string(array_type_t *type,
+static initializer_t *initializer_from_string(array_type_t *const type,
const string_t *const string)
{
/* TODO: check len vs. size of array type */
}
static initializer_t *initializer_from_wide_string(array_type_t *const type,
- wide_string_t *const string)
+ const string_t *const string)
{
/* TODO: check len vs. size of array type */
(void) type;
{
/* 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);
+
if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
if (element_type->kind == TYPE_ATOMIC) {
atomic_type_kind_t akind = element_type->atomic.akind;
switch (expression->kind) {
- case EXPR_STRING_LITERAL:
- if (akind == ATOMIC_TYPE_CHAR
- || akind == ATOMIC_TYPE_SCHAR
- || akind == ATOMIC_TYPE_UCHAR) {
- return initializer_from_string(array_type,
- &expression->string.value);
- }
+ case EXPR_STRING_LITERAL:
+ if (akind == ATOMIC_TYPE_CHAR
+ || akind == ATOMIC_TYPE_SCHAR
+ || akind == ATOMIC_TYPE_UCHAR) {
+ return initializer_from_string(array_type,
+ &expression->string_literal.value);
+ }
+ break;
- case EXPR_WIDE_STRING_LITERAL: {
- type_t *bare_wchar_type = skip_typeref(type_wchar_t);
- if (get_unqualified_type(element_type) == bare_wchar_type) {
- return initializer_from_wide_string(array_type,
- &expression->wide_string.value);
- }
+ case EXPR_WIDE_STRING_LITERAL: {
+ type_t *bare_wchar_type = skip_typeref(type_wchar_t);
+ if (get_unqualified_type(element_type) == bare_wchar_type) {
+ return initializer_from_wide_string(array_type,
+ &expression->string_literal.value);
}
+ break;
+ }
- default:
- break;
+ default:
+ break;
}
}
}
&expression->base.source_position);
initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
-#if 0
- if (type->kind == TYPE_BITFIELD) {
- type = type->bitfield.base_type;
- }
-#endif
result->value.value = create_implicit_cast(expression, type);
return result;
/**
* 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)
{
/* there might be extra {} hierarchies */
int braces = 0;
- if (token.type == '{') {
+ if (next_if('{')) {
if (warning.other)
warningf(HERE, "extra curly braces around scalar initializer");
do {
++braces;
- next_token();
- } while (token.type == '{');
+ } while (next_if('{'));
}
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
if (must_be_constant && !is_initializer_constant(expression)) {
errorf(&expression->base.source_position,
- "Initialisation expression '%E' is not constant\n",
+ "initialisation expression '%E' is not constant",
expression);
}
bool additional_warning_displayed = false;
while (braces > 0) {
- if (token.type == ',') {
- next_token();
- }
+ next_if(',');
if (token.type != '}') {
if (!additional_warning_displayed && warning.other) {
warningf(HERE, "additional elements in scalar initializer");
type_t *real_type = skip_typeref(iter->declaration.type);
if (real_type->kind == TYPE_BITFIELD) {
errorf(&designator->source_position,
- "offsetof designator '%Y' may not specify bitfield",
+ "offsetof designator '%Y' must not specify bitfield",
symbol);
goto failed;
}
goto failed;
}
- long index = fold_constant(array_index);
+ long index = fold_constant_to_int(array_index);
if (!used_in_offsetof) {
if (index < 0) {
errorf(&designator->source_position,
}
}
-/**
- * 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.
*/
static void skip_initializers(void)
{
- if (token.type == '{')
- next_token();
+ next_if('{');
while (token.type != '}') {
if (token.type == T_EOF)
/* GNU-style designator ("identifier: value") */
designator = allocate_ast_zero(sizeof(designator[0]));
designator->source_position = token.source_position;
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
eat(T_IDENTIFIER);
eat(':');
if (type != NULL) {
ascend_from_subtype(path);
- expect('}');
+ expect('}', end_error);
} else {
- expect('}');
+ expect('}', end_error);
goto error_parse_next;
}
}
} 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,
- "Initialisation expression '%E' is not constant\n",
+ "Initialisation expression '%E' is not constant",
expression);
}
if (type == NULL) {
/* we are already outside, ... */
+ if (outer_type == NULL)
+ goto error_parse_next;
type_t *const outer_type_skip = skip_typeref(outer_type);
if (is_type_compound(outer_type_skip) &&
!outer_type_skip->compound.compound->complete) {
&& outer_type != NULL) {
sub = initializer_from_expression(outer_type, expression);
if (sub != NULL) {
- if (token.type == ',') {
- next_token();
- }
+ next_if(',');
if (token.type != '}' && warning.other) {
warningf(HERE, "excessive elements in initializer for type '%T'",
orig_type);
error_excess:
if (warning.other) {
if (env->entity != NULL) {
- warningf(HERE, "excess elements in struct initializer for '%Y'",
- env->entity->base.symbol);
+ warningf(HERE, "excess elements in initializer for '%Y'",
+ env->entity->base.symbol);
} else {
- warningf(HERE, "excess elements in struct initializer");
+ warningf(HERE, "excess elements in initializer");
}
}
}
if (token.type == '}') {
break;
}
- expect(',');
+ expect(',', end_error);
if (token.type == '}') {
break;
}
return NULL;
}
+static expression_t *make_size_literal(size_t value)
+{
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_INTEGER);
+ literal->base.type = type_size_t;
+
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%u", (unsigned) value);
+ literal->literal.value = make_string(buf);
+
+ return literal;
+}
+
/**
* Parses an initializer. Parsers either a compound literal
* (env->declaration == NULL) or an initializer of a declaration.
*/
static initializer_t *parse_initializer(parse_initializer_env_t *env)
{
- type_t *type = skip_typeref(env->type);
- initializer_t *result = NULL;
- size_t max_index;
+ type_t *type = skip_typeref(env->type);
+ size_t max_index = 0;
+ initializer_t *result;
if (is_type_scalar(type)) {
result = parse_scalar_initializer(type, env->must_be_constant);
max_index = path.max_index;
DEL_ARR_F(path.path);
- expect('}');
+ expect('}', end_error);
} else {
/* parse_scalar_initializer() also works in this case: we simply
* have an expression without {} around it */
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) {
size_t size;
switch (result->kind) {
case INITIALIZER_LIST:
+ assert(max_index != 0xdeadbeaf);
size = max_index + 1;
break;
internal_errorf(HERE, "invalid initializer type");
}
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_size_t;
- cnst->conste.v.int_value = size;
-
type_t *new_type = duplicate_type(type);
- new_type->array.size_expression = cnst;
+ new_type->array.size_expression = make_size_literal(size);
new_type->array.size_constant = true;
new_type->array.has_implicit_size = true;
new_type->array.size = size;
} else {
scope->entities = entity;
}
- scope->last_entity = entity;
+ entity->base.parent_entity = current_entity;
+ scope->last_entity = entity;
}
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 {
- eat(T_union);
- }
+ eat(is_struct ? T_struct : T_union);
- symbol_t *symbol = NULL;
- compound_t *compound = NULL;
+ symbol_t *symbol = NULL;
+ compound_t *compound = NULL;
+ attribute_t *attributes = NULL;
if (token.type == T___attribute__) {
- modifiers |= parse_attributes(&attributes);
+ attributes = parse_attributes(NULL);
}
+ entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
if (token.type == T_IDENTIFIER) {
- symbol = token.v.symbol;
+ /* the compound has a name, check if we have seen it already */
+ symbol = token.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->alignment = 1;
+ 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);
+ /* ISO/IEC 14882:1998(E) §7.1.3:5 */
if (symbol == NULL) {
assert(anonymous_entity == NULL);
anonymous_entity = (entity_t*)compound;
}
}
- compound->modifiers |= modifiers;
+ if (attributes != NULL) {
+ handle_entity_attributes(attributes, (entity_t*) compound);
+ }
+
return compound;
}
entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE);
entity->enum_value.enum_type = enum_type;
- entity->base.symbol = token.v.symbol;
+ entity->base.symbol = token.symbol;
entity->base.source_position = token.source_position;
next_token();
- if (token.type == '=') {
- next_token();
+ if (next_if('=')) {
expression_t *value = parse_constant_expression();
value = create_implicit_cast(value, enum_type);
}
record_entity(entity, false);
-
- if (token.type != ',')
- break;
- next_token();
- } while (token.type != '}');
+ } while (next_if(',') && token.type != '}');
rem_anchor_token('}');
- expect('}');
+ expect('}', end_error);
end_error:
;
static type_t *parse_enum_specifier(void)
{
- gnu_attribute_t *attributes = NULL;
- entity_t *entity;
- symbol_t *symbol;
+ entity_t *entity;
+ symbol_t *symbol;
eat(T_enum);
- if (token.type == T_IDENTIFIER) {
- symbol = token.v.symbol;
- next_token();
+ switch (token.type) {
+ case T_IDENTIFIER:
+ symbol = token.symbol;
+ next_token();
- entity = get_entity(symbol, NAMESPACE_ENUM);
- assert(entity == NULL || entity->kind == ENTITY_ENUM);
- } else if (token.type != '{') {
- parse_error_expected("while parsing enum type specifier",
- T_IDENTIFIER, '{', NULL);
- return NULL;
- } else {
- entity = NULL;
- symbol = NULL;
+ 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);
+ }
+ }
+ break;
+
+ case '{':
+ entity = NULL;
+ symbol = NULL;
+ break;
+
+ default:
+ parse_error_expected("while parsing enum type specifier",
+ T_IDENTIFIER, '{', NULL);
+ return 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;
}
} else if (!entity->enume.complete && !(c_mode & _GNUC)) {
- errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)",
+ errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)",
symbol);
}
type_t *type;
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *expression = NULL;
bool old_gcc_extension = in_gcc_extension;
in_type_prop = true;
- while (token.type == T___extension__) {
+ while (next_if(T___extension__)) {
/* This can be a prefix to a typename or an expression. */
- next_token();
in_gcc_extension = true;
}
switch (token.type) {
case T_IDENTIFIER:
- if (is_typedef_symbol(token.v.symbol)) {
+ if (is_typedef_symbol(token.symbol)) {
+ TYPENAME_START
type = parse_typename();
} else {
+ default:
expression = parse_expression();
- type = expression->base.type;
+ type = revert_automatic_type_conversion(expression);
}
break;
-
- TYPENAME_START
- type = parse_typename();
- break;
-
- default:
- expression = parse_expression();
- type = expression->base.type;
- break;
}
in_type_prop = old_type_prop;
in_gcc_extension = old_gcc_extension;
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF);
typeof_type->typeoft.expression = expression;
SPECIFIER_INT = 1 << 3,
SPECIFIER_DOUBLE = 1 << 4,
SPECIFIER_CHAR = 1 << 5,
- SPECIFIER_SHORT = 1 << 6,
- SPECIFIER_LONG_LONG = 1 << 7,
- SPECIFIER_FLOAT = 1 << 8,
- SPECIFIER_BOOL = 1 << 9,
- SPECIFIER_VOID = 1 << 10,
- SPECIFIER_INT8 = 1 << 11,
- SPECIFIER_INT16 = 1 << 12,
- SPECIFIER_INT32 = 1 << 13,
- SPECIFIER_INT64 = 1 << 14,
- SPECIFIER_INT128 = 1 << 15,
- SPECIFIER_COMPLEX = 1 << 16,
- SPECIFIER_IMAGINARY = 1 << 17,
+ SPECIFIER_WCHAR_T = 1 << 6,
+ SPECIFIER_SHORT = 1 << 7,
+ SPECIFIER_LONG_LONG = 1 << 8,
+ SPECIFIER_FLOAT = 1 << 9,
+ SPECIFIER_BOOL = 1 << 10,
+ SPECIFIER_VOID = 1 << 11,
+ SPECIFIER_INT8 = 1 << 12,
+ SPECIFIER_INT16 = 1 << 13,
+ SPECIFIER_INT32 = 1 << 14,
+ SPECIFIER_INT64 = 1 << 15,
+ SPECIFIER_INT128 = 1 << 16,
+ SPECIFIER_COMPLEX = 1 << 17,
+ SPECIFIER_IMAGINARY = 1 << 18,
} specifiers_t;
static type_t *create_builtin_type(symbol_t *const symbol,
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;
- }
- errorf(HERE, "alignment must be power of two");
- return false;
-}
+ expect('(', end_error);
-#define DET_MOD(name, tag) do { \
- if (*modifiers & tag && warning.other) warningf(HERE, #name " used more than once"); \
- *modifiers |= tag; \
-} while (0)
+ attribute_property_argument_t *property
+ = allocate_ast_zero(sizeof(*property));
-static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *specifiers)
-{
- decl_modifiers_t *modifiers = &specifiers->modifiers;
+ do {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing property declspec",
+ T_IDENTIFIER, NULL);
+ goto end_error;
+ }
- 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('(');
- 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(')');
- } else if (symbol == sym_allocate) {
- next_token();
- expect('(');
- if (token.type != T_IDENTIFIER)
- goto end_error;
- (void)token.v.symbol;
- expect(')');
- } 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('(');
- 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('=');
- 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(')');
- } else if (symbol == sym_selectany) {
- next_token();
- DET_MOD(selectany, DM_SELECTANY);
- } else if (symbol == sym_uuid) {
- next_token();
- expect('(');
- if (token.type != T_STRING_LITERAL)
- goto end_error;
- next_token();
- expect(')');
- } 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(')');
- }
- } else if (symbol == sym_noalias) {
- next_token();
- DET_MOD(noalias, DM_NOALIAS);
+ bool is_put;
+ symbol_t *symbol = token.symbol;
+ next_token();
+ if (strcmp(symbol->string, "put") == 0) {
+ is_put = true;
+ } else if (strcmp(symbol->string, "get") == 0) {
+ is_put = false;
} else {
- if (warning.other)
- warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol);
- next_token();
- if (token.type == '(')
- skip_until(')');
+ errorf(HERE, "expected put or get in property declspec");
+ goto end_error;
}
-end_loop:
- if (token.type == ',')
- next_token();
- }
+ 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.symbol;
+ } else {
+ property->get_symbol = token.symbol;
+ }
+ next_token();
+ } while (next_if(','));
+
+ attribute->a.property = property;
+
+ expect(')', end_error);
+
end_error:
- return;
+ return attribute;
}
-static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
+static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
{
- entity_t *entity = allocate_entity_zero(kind);
- entity->base.source_position = *HERE;
- entity->base.symbol = symbol;
- if (is_declaration(entity)) {
- entity->declaration.type = type_error_type;
- entity->declaration.implicit = true;
- } else if (kind == ENTITY_TYPEDEF) {
- entity->typedefe.type = type_error_type;
- }
- record_entity(entity, false);
- return entity;
-}
+ attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
+ if (next_if(T_restrict)) {
+ kind = ATTRIBUTE_MS_RESTRICT;
+ } else if (token.type == T_IDENTIFIER) {
+ const char *name = token.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;
+ }
+ }
-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;
+ 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;
}
- 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;
+ attribute_t *attribute = allocate_attribute_zero(kind);
- 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;
+ if (kind == ATTRIBUTE_MS_PROPERTY) {
+ return parse_attribute_ms_property(attribute);
+ }
- type_t *const type = variable->base.type;
+ /* parse arguments */
+ if (next_if('('))
+ attribute->a.arguments = parse_attribute_arguments();
- 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();
+ return attribute;
}
-/**
- * Finish the construction of a struct type by calculating
- * its size, offsets, alignment.
- */
-static void finish_struct_type(compound_type_t *type)
+static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
{
- assert(type->compound != NULL);
-
- compound_t *compound = type->compound;
- if (!compound->complete)
- return;
+ eat(T__declspec);
- il_size_t size = 0;
- il_size_t offset;
- il_alignment_t alignment = 1;
- bool need_pad = false;
+ expect('(', end_error);
- entity_t *entry = compound->members.entities;
- for (; entry != NULL; entry = entry->base.next) {
- if (entry->kind != ENTITY_COMPOUND_MEMBER)
- continue;
+ if (next_if(')'))
+ return NULL;
- type_t *m_type = skip_typeref(entry->declaration.type);
- if (! is_type_valid(m_type)) {
- /* simply ignore errors here */
- continue;
- }
- il_alignment_t m_alignment = m_type->base.alignment;
- if (m_alignment > alignment)
- alignment = m_alignment;
+ add_anchor_token(')');
- offset = (size + m_alignment - 1) & -m_alignment;
+ attribute_t **anchor = &first;
+ do {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
- 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;
- }
+ attribute_t *attribute
+ = parse_microsoft_extended_decl_modifier_single();
+ if (attribute == NULL)
+ goto end_error;
- offset = (size + alignment - 1) & -alignment;
- if (offset > size)
- need_pad = true;
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
- if (warning.padded && need_pad) {
- warningf(&compound->base.source_position,
- "'%#T' needs padding", type, compound->base.symbol);
- }
- if (warning.packed && !need_pad) {
- warningf(&compound->base.source_position,
- "superfluous packed attribute on '%#T'",
- type, compound->base.symbol);
- }
+ rem_anchor_token(')');
+ expect(')', end_error);
+ return first;
- type->base.size = offset;
- type->base.alignment = alignment;
+end_error:
+ rem_anchor_token(')');
+ return first;
}
-/**
- * Finish the construction of an union type by calculating
- * its size and alignment.
- */
-static void finish_union_type(compound_type_t *type)
+static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
- assert(type->compound != NULL);
-
- compound_t *compound = type->compound;
- if (! compound->complete)
- return;
-
- il_size_t size = 0;
- il_alignment_t alignment = 1;
-
- 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))
- 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;
+ entity_t *entity = allocate_entity_zero(kind);
+ entity->base.source_position = *HERE;
+ entity->base.symbol = symbol;
+ if (is_declaration(entity)) {
+ entity->declaration.type = type_error_type;
+ entity->declaration.implicit = true;
+ } else if (kind == ENTITY_TYPEDEF) {
+ entity->typedefe.type = type_error_type;
+ entity->typedefe.builtin = true;
}
- size = (size + alignment - 1) & -alignment;
- type->base.size = size;
- type->base.alignment = alignment;
+ if (kind != ENTITY_COMPOUND_MEMBER)
+ record_entity(entity, false);
+ return entity;
}
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('(');
- add_anchor_token(')');
- parse_microsoft_extended_decl_modifier(specifiers);
- rem_anchor_token(')');
- expect(')');
+ specifiers->attributes
+ = parse_microsoft_extended_decl_modifier(specifiers->attributes);
break;
case T___thread:
MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed");
MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned");
MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void");
-
- case T__forceinline:
- /* only in microsoft mode */
- specifiers->modifiers |= DM_FORCEINLINE;
- /* FALLTHROUGH */
+ MATCH_SPECIFIER(T_wchar_t, SPECIFIER_WCHAR_T, "wchar_t");
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;
}
}
- type_t *const typedef_type = get_typedef_type(token.v.symbol);
+ type_t *const typedef_type = get_typedef_type(token.symbol);
if (typedef_type == NULL) {
/* Be somewhat resilient to typos like 'vodi f()' at the beginning of a
* declaration, so it doesn't generate 'implicit int' followed by more
errorf(HERE, "%K does not name a type", &token);
entity_t *entity =
- create_error_entity(token.v.symbol, ENTITY_TYPEDEF);
+ create_error_entity(token.symbol, ENTITY_TYPEDEF);
type = allocate_type_zero(TYPE_TYPEDEF);
type->typedeft.typedefe = &entity->typedefe;
}
finish_specifiers:
+ specifiers->attributes = parse_attributes(specifiers->attributes);
+
in_gcc_extension = old_gcc_extension;
if (type == NULL || (saw_error && type_specifiers != 0)) {
case SPECIFIER_VOID:
atomic_type = ATOMIC_TYPE_VOID;
break;
+ case SPECIFIER_WCHAR_T:
+ atomic_type = ATOMIC_TYPE_WCHAR_T;
+ break;
case SPECIFIER_CHAR:
atomic_type = ATOMIC_TYPE_CHAR;
break;
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:
specifiers->type = type_error_type;
- return;
}
static type_qualifiers_t parse_type_qualifiers(void)
static void parse_identifier_list(scope_t *scope)
{
do {
- entity_t *entity = allocate_entity_zero(ENTITY_VARIABLE);
+ entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
entity->base.source_position = token.source_position;
entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = token.v.symbol;
+ entity->base.symbol = token.symbol;
/* a K&R parameter has no type, yet */
next_token();
- append_entity(scope, entity);
-
- if (token.type != ',') {
- break;
- }
- next_token();
- } while (token.type == T_IDENTIFIER);
-}
-
-static void semantic_parameter(declaration_t *declaration)
-{
- /* TODO: improve error messages */
- source_position_t const* const pos = &declaration->base.source_position;
-
- /* §6.9.1:6 The declarations in the declaration list shall contain no
- * storage-class specifier other than register and no
- * initializations. */
- switch (declaration->declared_storage_class) {
- /* Allowed storage classes */
- case STORAGE_CLASS_NONE:
- case STORAGE_CLASS_REGISTER:
- break;
-
- default:
- errorf(pos, "parameter may only have none or register storage class");
- break;
- }
-
- /* §6.7.5.3:4 After adjustment, the parameters in a parameter type list in
- * a function declarator that is part of a definition of that
- * function shall not have incomplete type. */
- type_t *type = declaration->type;
- if (is_type_incomplete(skip_typeref(type))) {
- errorf(pos, "parameter '%#T' has incomplete type",
- type, declaration->base.symbol);
- }
+ if (scope != NULL)
+ append_entity(scope, entity);
+ } while (next_if(',') && token.type == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
return entity;
}
+static void semantic_parameter_incomplete(const entity_t *entity)
+{
+ assert(entity->kind == ENTITY_PARAMETER);
+
+ /* §6.7.5.3:4 After adjustment, the parameters in a parameter type
+ * list in a function declarator that is part of a
+ * definition of that function shall not have
+ * incomplete type. */
+ type_t *type = skip_typeref(entity->declaration.type);
+ if (is_type_incomplete(type)) {
+ errorf(&entity->base.source_position,
+ "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.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)
int saved_comma_state = save_and_reset_anchor_state(',');
if (token.type == T_IDENTIFIER &&
- !is_typedef_symbol(token.v.symbol)) {
+ !is_typedef_symbol(token.symbol)) {
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ',' || la1_type == ')') {
type->kr_style_parameters = true;
goto parameters_finished;
}
- function_parameter_t *parameter;
- function_parameter_t *last_parameter = NULL;
+ if (has_parameters()) {
+ function_parameter_t **anchor = &type->parameters;
+ do {
+ 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(&entity->declaration);
+ 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;
- }
- next_token();
+ } while (next_if(','));
}
parameters_finished:
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
end_error:
restore_anchor_state(',', saved_comma_state);
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 *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size)
+{
+ construct_type_t *const cons = obstack_alloc(&temp_obst, size);
+ memset(cons, 0, size);
+ cons->kind = kind;
+ return cons;
+}
-static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
+/* §6.7.5.1 */
+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;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+ cons->pointer.type_qualifiers = parse_type_qualifiers();
+ //cons->pointer.base_variable = base_variable;
- return &pointer->construct_type;
+ return cons;
}
+/* ISO/IEC 14882:1998(E) §8.3.2 */
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;
+ if (!(c_mode & _CXX))
+ errorf(HERE, "references are only available for C++");
- return (construct_type_t*)reference;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
+
+ return cons;
}
+/* §6.7.5.2 */
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 *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
+ parsed_array_t *const array = &cons->array;
- if (token.type == T_static) {
- array->is_static = true;
- next_token();
- }
+ bool is_static = next_if(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
- if (type_qualifiers != 0) {
- if (token.type == T_static) {
- array->is_static = true;
- next_token();
- }
- }
+
+ if (!is_static)
+ is_static = next_if(T_static);
+
array->type_qualifiers = type_qualifiers;
+ array->is_static = is_static;
+ expression_t *size = NULL;
if (token.type == '*' && look_ahead(1)->type == ']') {
array->is_variable = true;
next_token();
} else if (token.type != ']') {
- array->size = parse_assignment_expression();
+ 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);
}
+ if (is_static && size == NULL)
+ errorf(HERE, "static array parameters require a size");
+
rem_anchor_token(']');
- expect(']');
+ 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)
+/* §6.7.5.3 */
+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;
-
- switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) {
- case DM_NONE: break;
- case DM_CDECL: ftype->calling_convention = CC_CDECL; break;
- case DM_STDCALL: ftype->calling_convention = CC_STDCALL; break;
- case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break;
- case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break;
-
- default:
- errorf(HERE, "multiple calling conventions in declaration");
- break;
- }
+ ftype->linkage = current_linkage;
+ ftype->calling_convention = CC_DEFAULT;
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 *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+ cons->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)
+/* §6.7.5 */
+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 T__based: {
+ panic("based not supported anymore");
+ /* FALLTHROUGH */
+ }
+
case '*':
- type = parse_pointer_declarator(base_spec.base_variable);
- /* consumed */
- base_spec.base_variable = NULL;
+ type = parse_pointer_declarator();
break;
- case T__based:
- next_token();
- expect('(');
- add_anchor_token(')');
- parse_microsoft_based(&base_spec);
- rem_anchor_token(')');
- expect(')');
- continue;
-
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");
- }
-
- if (env != NULL) {
- modifiers |= env->modifiers;
- env->modifiers = modifiers;
+ env->attributes = parse_attributes(env->attributes);
}
+ptr_operator_end: ;
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;
+ env->symbol = token.symbol;
env->source_position = token.source_position;
}
next_token();
break;
case '(':
- next_token();
- add_anchor_token(')');
- inner_types = parse_inner_declarator(env, may_be_abstract);
- if (inner_types != NULL) {
- /* All later declarators only modify the return type */
- env = NULL;
+ /* §6.7.6:2 footnote 126: Empty parentheses in a type name are
+ * interpreted as ``function with no parameter specification'', rather
+ * than redundant parentheses around the omitted identifier. */
+ if (look_ahead(1)->type != ')') {
+ next_token();
+ add_anchor_token(')');
+ inner_types = parse_inner_declarator(env);
+ if (inner_types != NULL) {
+ /* All later declarators only modify the return type */
+ env->must_be_abstract = true;
+ }
+ rem_anchor_token(')');
+ expect(')', end_error);
}
- rem_anchor_token(')');
- expect(')');
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;
- }
-
- 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)
- 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;
- }
+ *anchor = inner_types;
+
+ return first;
+end_error:
+ return NULL;
}
-static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
+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_to_int(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;
static type_t *automatic_type_conversion(type_t *orig_type);
+static type_t *semantic_parameter(const source_position_t *pos,
+ type_t *type,
+ const declaration_specifiers_t *specifiers,
+ symbol_t *symbol)
+{
+ /* §6.7.5.3:7 A declaration of a parameter as ``array of type''
+ * shall be adjusted to ``qualified pointer to type'',
+ * [...]
+ * §6.7.5.3:8 A declaration of a parameter as ``function returning
+ * type'' shall be adjusted to ``pointer to function
+ * returning type'', as in 6.3.2.1. */
+ type = automatic_type_conversion(type);
+
+ if (specifiers->is_inline && is_type_valid(type)) {
+ errorf(pos, "parameter '%#T' declared 'inline'", type, symbol);
+ }
+
+ /* §6.9.1:6 The declarations in the declaration list shall contain
+ * no storage-class specifier other than register and no
+ * initializations. */
+ if (specifiers->thread_local || (
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ specifiers->storage_class != STORAGE_CLASS_REGISTER)
+ ) {
+ errorf(pos, "invalid storage class for parameter '%#T'", type, symbol);
+ }
+
+ /* delay test for incomplete type, because we might have (void)
+ * which is legal but incomplete... */
+
+ return type;
+}
+
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
declarator_flags_t flags)
{
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 */
+ attribute_t **anchor = &attributes;
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
+ *anchor = specifiers->attributes;
+
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
entity = allocate_entity_zero(ENTITY_TYPEDEF);
}
}
} else {
+ /* create a declaration type entity */
if (flags & DECL_CREATE_COMPOUND_MEMBER) {
- entity = allocate_entity_zero(ENTITY_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) {
- /* §6.7.5.3:7 A declaration of a parameter as ``array of type''
- * shall be adjusted to ``qualified pointer to type'',
- * [...]
- * §6.7.5.3:8 A declaration of a parameter as ``function returning
- * type'' shall be adjusted to ``pointer to function
- * returning type'', as in 6.3.2.1. */
- orig_type = automatic_type_conversion(type);
- goto create_variable;
+ orig_type = semantic_parameter(&env.source_position, orig_type,
+ specifiers, env.symbol);
+
+ entity = allocate_entity_zero(ENTITY_PARAMETER);
} else if (is_type_function(type)) {
entity = allocate_entity_zero(ENTITY_FUNCTION);
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 {
-create_variable:
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;
- if (storage_class == STORAGE_CLASS_NONE
- && current_scope != file_scope) {
+ if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
storage_class = STORAGE_CLASS_AUTO;
- }
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;
}
* @param decl the declaration to check
* @param type the function type of the declaration
*/
-static void check_type_of_main(const entity_t *entity)
+static void check_main(const entity_t *entity)
{
const source_position_t *pos = &entity->base.source_position;
if (entity->kind != ENTITY_FUNCTION) {
return strcmp(sym->string, "main") == 0;
}
-static const char *get_entity_kind_name(entity_kind_t kind)
-{
- switch ((entity_kind_tag_t) kind) {
- case ENTITY_FUNCTION: return "function";
- case ENTITY_VARIABLE: return "variable";
- case ENTITY_COMPOUND_MEMBER: return "compound type member";
- case ENTITY_STRUCT: return "struct";
- case ENTITY_UNION: return "union";
- case ENTITY_ENUM: return "enum";
- case ENTITY_ENUM_VALUE: return "enum value";
- case ENTITY_LABEL: return "label";
- case ENTITY_LOCAL_LABEL: return "local label";
- case ENTITY_TYPEDEF: return "typedef";
- case ENTITY_NAMESPACE: return "namespace";
- case ENTITY_INVALID: break;
- }
-
- panic("Invalid entity kind encountered in get_entity_kind_name");
-}
-
static void error_redefined_as_different_kind(const source_position_t *pos,
const entity_t *old, entity_kind_t new_kind)
{
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;
+}
+
+static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
+{
+ for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) {
+ if (attributes_equal(tattr, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * test wether new_list contains any attributes not included in old_list
+ */
+static bool has_new_attributes(const attribute_t *old_list,
+ const attribute_t *new_list)
+{
+ for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) {
+ if (!contains_attribute(old_list, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Merge in attributes from an attribute list (probably from a previous
+ * declaration with the same name). Warning: destroys the old structure
+ * of the attribute list - don't reuse attributes after this call.
+ */
+static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
+{
+ attribute_t *next;
+ for (attribute_t *attr = attributes; attr != NULL; attr = next) {
+ next = attr->next;
+ if (contains_attribute(decl->attributes, attr))
+ continue;
+
+ /* move attribute to new declarations attributes list */
+ attr->next = decl->attributes;
+ decl->attributes = attr;
+ }
+}
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
*/
-static entity_t *record_entity(entity_t *entity, const bool is_definition)
+entity_t *record_entity(entity_t *entity, const bool is_definition)
{
const symbol_t *const symbol = entity->base.symbol;
const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
const source_position_t *pos = &entity->base.source_position;
- assert(symbol != NULL);
- entity_t *previous_entity = get_entity(symbol, namespc);
+ /* can happen in error cases */
+ if (symbol == NULL)
+ return entity;
+
+ entity_t *const previous_entity = get_entity(symbol, namespc);
/* pushing the same entity twice will break the stack structure */
assert(previous_entity != entity);
if (warning.main && current_scope == file_scope
&& is_sym_main(symbol)) {
- check_type_of_main(entity);
- }
- }
-
- if (is_declaration(entity)) {
- if (warning.nested_externs
- && entity->declaration.storage_class == STORAGE_CLASS_EXTERN
- && current_scope != file_scope) {
- warningf(pos, "nested extern declaration of '%#T'",
- entity->declaration.type, symbol);
+ check_main(entity);
}
}
- if (previous_entity != NULL
- && previous_entity->base.parent_scope == ¤t_function->parameters
- && current_scope->depth == previous_entity->base.parent_scope->depth+1){
-
- assert(previous_entity->kind == ENTITY_VARIABLE);
- 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 (is_declaration(entity) &&
+ warning.nested_externs &&
+ entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
+ current_scope != file_scope) {
+ warningf(pos, "nested extern declaration of '%#T'",
+ entity->declaration.type, symbol);
}
- 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 */
+ 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,
- "redefinition of typedef '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ "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));
-
- /* can happen for K&R style declarations */
- if (previous_entity->kind == ENTITY_VARIABLE
- && previous_entity->declaration.type == NULL
- && entity->kind == ENTITY_VARIABLE) {
- previous_entity->declaration.type = entity->declaration.type;
- previous_entity->declaration.storage_class
- = entity->declaration.storage_class;
- previous_entity->declaration.declared_storage_class
- = entity->declaration.declared_storage_class;
- previous_entity->declaration.modifiers
- = entity->declaration.modifiers;
- previous_entity->declaration.deprecated_string
- = entity->declaration.deprecated_string;
- }
- assert(entity->declaration.type != NULL);
-
- declaration_t *const previous_declaration
- = &previous_entity->declaration;
- declaration_t *const declaration = &entity->declaration;
- type_t *const orig_type = entity->declaration.type;
- type_t *const type = skip_typeref(orig_type);
+ 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;
+ }
- type_t *prev_type = skip_typeref(previous_declaration->type);
+ /* at this point we should have only VARIABLES or FUNCTIONS */
+ assert(is_declaration(previous_entity) && is_declaration(entity));
- if (!types_compatible(type, prev_type)) {
- errorf(pos,
- "declaration '%#T' is incompatible with '%#T' (declared %P)",
- orig_type, symbol, previous_declaration->type, symbol,
- &previous_entity->base.source_position);
- } else {
- unsigned old_storage_class = previous_declaration->storage_class;
- if (warning.redundant_decls && is_definition
- && previous_declaration->storage_class == STORAGE_CLASS_STATIC
- && !(previous_declaration->modifiers & DM_USED)
- && !previous_declaration->used) {
- warningf(&previous_entity->base.source_position,
- "unnecessary static forward declaration for '%#T'",
- previous_declaration->type, symbol);
- }
+ declaration_t *const prev_decl = &previous_entity->declaration;
+ declaration_t *const decl = &entity->declaration;
- unsigned new_storage_class = declaration->storage_class;
- if (is_type_incomplete(prev_type)) {
- previous_declaration->type = type;
- prev_type = type;
+ /* 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;
}
- /* 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) {
- previous_declaration->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);
+
+ 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) {
-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) {
- previous_declaration->storage_class = STORAGE_CLASS_NONE;
- previous_declaration->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 (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
+
+warn_redundant_declaration: ;
+ bool has_new_attrs
+ = has_new_attributes(prev_decl->attributes,
+ decl->attributes);
+ if (has_new_attrs) {
+ merge_in_attributes(decl, prev_decl->attributes);
+ } else 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;
}
- previous_declaration->modifiers |= declaration->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) {
entity->declaration.type, symbol);
}
}
- } else if (warning.missing_declarations
- && entity->kind == ENTITY_VARIABLE
- && current_scope == file_scope) {
+ } else if (warning.missing_declarations &&
+ entity->kind == ENTITY_VARIABLE &&
+ current_scope == file_scope) {
declaration_t *declaration = &entity->declaration;
if (declaration->storage_class == STORAGE_CLASS_NONE) {
warningf(pos, "no previous declaration for '%#T'",
static void parser_error_multiple_definition(entity_t *entity,
const source_position_t *source_position)
{
- errorf(source_position, "multiple definition of symbol '%Y' (declared %P)",
+ errorf(source_position, "multiple definition of '%Y' (declared %P)",
entity->base.symbol, &entity->base.source_position);
}
TYPE_QUALIFIERS
return true;
case T_IDENTIFIER:
- return is_typedef_symbol(token->v.symbol);
+ return is_typedef_symbol(token->symbol);
case T___extension__:
STORAGE_CLASSES
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;
+ type_t *const type = skip_typeref(orig_type);
+ if (!is_type_incomplete(type))
return;
- type_t *type = decl->type;
- if (!is_type_incomplete(skip_typeref(type)))
+ /* §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;
+ }
errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
- type, ent->base.symbol);
+ orig_type, ent->base.symbol);
}
check_variable_type_complete(entity);
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
add_anchor_token('=');
ndeclaration = parse_declarator(specifiers, flags);
rem_anchor_token('=');
}
- expect(';');
+ expect(';', end_error);
end_error:
anonymous_entity = NULL;
}
if (is_definition) {
- errorf(HERE, "parameter %Y is initialised", entity->base.symbol);
+ errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol);
}
return record_entity(entity, false);
}
}
+/* §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;
}
if (!type->function.kr_style_parameters)
return;
-
add_anchor_token('{');
/* push function parameters */
}
/* parse declaration list */
- while (is_declaration_specifier(&token, false)) {
- parse_declaration(finished_kr_declaration, DECL_IS_PARAMETER);
+ for (;;) {
+ switch (token.type) {
+ DECLARATION_START
+ case T___extension__:
+ /* This covers symbols, which are no type, too, and results in
+ * better error messages. The typical cases are misspelled type
+ * names and missing includes. */
+ case T_IDENTIFIER:
+ parse_declaration(finished_kr_declaration, DECL_IS_PARAMETER);
+ break;
+ default:
+ goto decl_list_end;
+ }
}
+decl_list_end:
/* pop function parameters */
assert(current_scope == &entity->function.parameters);
/* 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;
+
+ /* did we have an earlier prototype? */
+ entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL);
+ if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION)
+ proto_type = NULL;
+
+ function_parameter_t *proto_parameter = NULL;
+ if (proto_type != NULL) {
+ type_t *proto_type_type = proto_type->declaration.type;
+ proto_parameter = proto_type_type->function.parameters;
+ /* If a K&R function definition has a variadic prototype earlier, then
+ * make the function definition variadic, too. This should conform to
+ * §6.7.5.3:15 and §6.9.1:8. */
+ new_type->function.variadic = proto_type_type->function.variadic;
+ } else {
+ /* §6.9.1.7: A K&R style parameter list does NOT act as a function
+ * prototype */
+ new_type->function.unspecified_parameters = true;
+ }
+
+ bool need_incompatible_warning = false;
+ parameter = entity->function.parameters.entities;
+ for (; parameter != NULL; parameter = parameter->base.next,
+ proto_parameter =
+ proto_parameter == NULL ? NULL : proto_parameter->next) {
+ if (parameter->kind != ENTITY_PARAMETER)
+ continue;
- entity_t *parameter_declaration = entity->function.parameters.entities;
- for (; parameter_declaration != NULL;
- parameter_declaration = parameter_declaration->base.next) {
- type_t *parameter_type = parameter_declaration->declaration.type;
+ type_t *parameter_type = parameter->declaration.type;
if (parameter_type == NULL) {
if (strict_mode) {
errorf(HERE, "no type specified for function parameter '%Y'",
- parameter_declaration->base.symbol);
+ 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_declaration->base.symbol);
+ parameter->base.symbol);
}
- parameter_type = type_int;
- parameter_declaration->declaration.type = parameter_type;
+ parameter_type = type_int;
}
+ parameter->declaration.type = parameter_type;
}
- semantic_parameter(¶meter_declaration->declaration);
- parameter_type = parameter_declaration->declaration.type;
-
- /*
- * we need the default promoted types for the function type
- */
- parameter_type = get_default_promoted_type(parameter_type);
+ semantic_parameter_incomplete(parameter);
- function_parameter_t *function_parameter
- = obstack_alloc(type_obst, sizeof(function_parameter[0]));
- memset(function_parameter, 0, sizeof(function_parameter[0]));
+ /* we need the default promoted types for the function type */
+ type_t *not_promoted = parameter_type;
+ parameter_type = get_default_promoted_type(parameter_type);
- function_parameter->type = parameter_type;
- if (last_parameter != NULL) {
- last_parameter->next = function_parameter;
- } else {
- parameters = function_parameter;
+ /* gcc special: if the type of the prototype matches the unpromoted
+ * type don't promote */
+ if (!strict_mode && proto_parameter != NULL) {
+ type_t *proto_p_type = skip_typeref(proto_parameter->type);
+ type_t *promo_skip = skip_typeref(parameter_type);
+ type_t *param_skip = skip_typeref(not_promoted);
+ if (!types_compatible(proto_p_type, promo_skip)
+ && types_compatible(proto_p_type, param_skip)) {
+ /* don't promote */
+ need_incompatible_warning = true;
+ parameter_type = not_promoted;
+ }
}
- last_parameter = function_parameter;
+ function_parameter_t *const parameter
+ = allocate_parameter(parameter_type);
+
+ *anchor = parameter;
+ anchor = ¶meter->next;
}
- /* § 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;
+ new_type->function.parameters = parameters;
+ new_type = identify_new_type(new_type);
- type = typehash_insert(new_type);
- if (type != new_type) {
- obstack_free(type_obst, new_type);
+ if (warning.other && need_incompatible_warning) {
+ type_t *proto_type_type = proto_type->declaration.type;
+ warningf(HERE,
+ "declaration '%#T' is incompatible with '%#T' (declared %P)",
+ proto_type_type, proto_type->base.symbol,
+ new_type, entity->base.symbol,
+ &proto_type->base.source_position);
}
- entity->declaration.type = type;
+ entity->declaration.type = new_type;
rem_anchor_token('{');
}
}
}
-static void warn_unused_decl(entity_t *entity, entity_t *end,
- char const *const what)
+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;
if (!declaration->used) {
print_in_function();
+ const char *what = get_entity_kind_name(entity->kind);
warningf(&entity->base.source_position, "%s '%Y' is unused",
what, entity->base.symbol);
} else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
print_in_function();
+ const char *what = get_entity_kind_name(entity->kind);
warningf(&entity->base.source_position, "%s '%Y' is never read",
what, entity->base.symbol);
}
-
- if (entity == end)
- break;
}
}
switch (stmt->kind) {
case STATEMENT_DECLARATION: {
declaration_statement_t const *const decls = &stmt->declaration;
- warn_unused_decl(decls->declarations_begin, decls->declarations_end,
- "variable");
+ warn_unused_entity(decls->declarations_begin,
+ decls->declarations_end);
return;
}
case STATEMENT_FOR:
- warn_unused_decl(stmt->fors.scope.entities, NULL, "variable");
+ warn_unused_entity(stmt->fors.scope.entities, NULL);
return;
default:
/* do not issue unused warnings for main */
if (!is_sym_main(current_function->base.base.symbol)) {
- warn_unused_decl(scope->entities, NULL, "parameter");
+ warn_unused_entity(scope->entities, NULL);
}
}
if (warning.unused_variable) {
{
return
!is_constant_expression(cond) ? 0 :
- fold_constant(cond) != 0 ? 1 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
static void check_reachable(statement_t *);
+static bool reaches_end;
static bool expression_returns(expression_t const *const expr)
{
case EXPR_REFERENCE:
case EXPR_REFERENCE_ENUM_VALUE:
- case EXPR_CONST:
- case EXPR_CHARACTER_CONSTANT:
- case EXPR_WIDE_CHARACTER_CONSTANT:
+ EXPR_LITERAL_CASES
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
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
- return
- expression_returns(expr->conditional.condition) && (
- expression_returns(expr->conditional.true_expression) ||
- expression_returns(expr->conditional.false_expression)
- );
+
+ if (!expression_returns(expr->conditional.condition))
+ return false;
+
+ if (expr->conditional.true_expression != NULL
+ && expression_returns(expr->conditional.true_expression))
+ return true;
+
+ return expression_returns(expr->conditional.false_expression);
case EXPR_SELECT:
return expression_returns(expr->select.compound);
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;
declaration_statement_t const *const decl = &stmt->declaration;
entity_t const * ent = decl->declarations_begin;
entity_t const *const last = decl->declarations_end;
- for (;; ent = ent->base.next) {
- if (ent->kind == ENTITY_VARIABLE &&
- ent->variable.initializer != NULL &&
- !initializer_returns(ent->variable.initializer)) {
- return;
+ if (ent != NULL) {
+ for (;; ent = ent->base.next) {
+ if (ent->kind == ENTITY_VARIABLE &&
+ ent->variable.initializer != NULL &&
+ !initializer_returns(ent->variable.initializer)) {
+ return;
+ }
+ if (ent == last)
+ break;
}
- if (ent == last)
- break;
}
next = stmt->base.next;
break;
case STATEMENT_COMPOUND:
next = stmt->compound.statements;
+ if (next == NULL)
+ next = stmt->base.next;
break;
case STATEMENT_RETURN: {
return;
if (is_constant_expression(expr)) {
- long const val = fold_constant(expr);
+ long const val = fold_constant_to_int(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
if (i->expression == NULL) {
break;
}
- case STATEMENT_CONTINUE: {
- statement_t *parent = stmt;
- for (;;) {
+ case STATEMENT_CONTINUE:
+ for (statement_t *parent = stmt;;) {
parent = parent->base.parent;
if (parent == NULL) /* continue not within loop */
return;
default: break;
}
}
- }
- case STATEMENT_BREAK: {
- statement_t *parent = stmt;
- for (;;) {
+ case STATEMENT_BREAK:
+ for (statement_t *parent = stmt;;) {
parent = parent->base.parent;
if (parent == NULL) /* break not within loop/switch */
return;
}
found_break_parent:
break;
- }
case STATEMENT_GOTO:
if (stmt->gotos.expression) {
}
break;
}
+
+ default:
+ panic("invalid statement kind");
}
while (next == NULL) {
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:
declaration_statement_t const *const decl = &stmt->declaration;
entity_t const * ent = decl->declarations_begin;
entity_t const *const last = decl->declarations_end;
- for (;; ent = ent->base.next) {
- if (ent->kind == ENTITY_VARIABLE &&
- ent->variable.initializer != NULL) {
- goto warn_unreachable;
+ if (ent != NULL) {
+ for (;; ent = ent->base.next) {
+ if (ent->kind == ENTITY_VARIABLE &&
+ ent->variable.initializer != NULL) {
+ goto warn_unreachable;
+ }
+ if (ent == last)
+ return;
}
- if (ent == last)
- return;
}
}
}
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_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;
}
/* parse function body */
int label_stack_top = label_top();
function_t *old_current_function = current_function;
+ entity_t *old_current_entity = current_entity;
current_function = function;
+ current_entity = (entity_t*) function;
current_parent = NULL;
goto_first = NULL;
assert(current_parent == NULL);
assert(current_function == function);
+ assert(current_entity == (entity_t*) function);
+ current_entity = old_current_entity;
current_function = old_current_function;
label_pop_to(label_stack_top);
}
type_t *skipped_type = skip_typeref(base_type);
if (!is_type_integer(skipped_type)) {
errorf(HERE, "bitfield base type '%T' is not an integer type",
- base_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)) {
- long v = fold_constant(size);
+ long v = fold_constant_to_int(size);
+ const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
if (v < 0) {
- errorf(source_position, "negative width in bit-field '%Y'", symbol);
- } else if (v == 0) {
- errorf(source_position, "zero width for bit-field '%Y'", symbol);
+ errorf(source_position, "negative width in bit-field '%Y'",
+ user_symbol);
+ } else if (v == 0 && symbol != NULL) {
+ errorf(source_position, "zero width for bit-field '%Y'",
+ user_symbol);
} else if (bit_size > 0 && (il_size_t)v > bit_size) {
- errorf(source_position, "width of '%Y' exceeds its type", symbol);
+ errorf(source_position, "width of '%Y' exceeds its type",
+ user_symbol);
} else {
type->bitfield.bit_size = v;
}
if (iter->base.symbol == symbol) {
return iter;
} else if (iter->base.symbol == NULL) {
+ /* search in anonymous structs and unions */
type_t *type = skip_typeref(iter->declaration.type);
if (is_type_compound(type)) {
- entity_t *result
- = find_compound_entry(type->compound.compound, symbol);
- if (result != NULL)
- return result;
+ if (find_compound_entry(type->compound.compound, symbol)
+ != NULL)
+ return iter;
}
continue;
}
return NULL;
}
+static void check_deprecated(const source_position_t *source_position,
+ const entity_t *entity)
+{
+ if (!warning.deprecated_declarations)
+ return;
+ if (!is_declaration(entity))
+ return;
+ if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
+ return;
+
+ char const *const prefix = get_entity_kind_name(entity->kind);
+ const char *deprecated_string
+ = get_deprecated_string(entity->declaration.attributes);
+ if (deprecated_string != NULL) {
+ warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"",
+ prefix, entity->base.symbol, &entity->base.source_position,
+ deprecated_string);
+ } else {
+ warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
+ entity->base.symbol, &entity->base.source_position);
+ }
+}
+
+
+static expression_t *create_select(const source_position_t *pos,
+ expression_t *addr,
+ type_qualifiers_t qualifiers,
+ entity_t *entry)
+{
+ assert(entry->kind == ENTITY_COMPOUND_MEMBER);
+
+ check_deprecated(pos, entry);
+
+ expression_t *select = allocate_expression_zero(EXPR_SELECT);
+ select->select.compound = addr;
+ select->select.compound_entry = entry;
+
+ type_t *entry_type = entry->declaration.type;
+ type_t *res_type = get_qualified_type(entry_type, qualifiers);
+
+ /* we always do the auto-type conversions; the & and sizeof parser contains
+ * code to revert this! */
+ select->base.type = automatic_type_conversion(res_type);
+ if (res_type->kind == TYPE_BITFIELD) {
+ select->base.type = res_type->bitfield.base_type;
+ }
+
+ return select;
+}
+
+/**
+ * Find entry with symbol in compound. Search anonymous structs and unions and
+ * creates implicit select expressions for them.
+ * Returns the adress for the innermost compound.
+ */
+static expression_t *find_create_select(const source_position_t *pos,
+ expression_t *addr,
+ type_qualifiers_t qualifiers,
+ compound_t *compound, symbol_t *symbol)
+{
+ entity_t *iter = compound->members.entities;
+ for (; iter != NULL; iter = iter->base.next) {
+ if (iter->kind != ENTITY_COMPOUND_MEMBER)
+ continue;
+
+ symbol_t *iter_symbol = iter->base.symbol;
+ if (iter_symbol == NULL) {
+ type_t *type = iter->declaration.type;
+ if (type->kind != TYPE_COMPOUND_STRUCT
+ && type->kind != TYPE_COMPOUND_UNION)
+ continue;
+
+ compound_t *sub_compound = type->compound.compound;
+
+ if (find_compound_entry(sub_compound, symbol) == NULL)
+ continue;
+
+ expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
+ sub_addr->base.source_position = *pos;
+ sub_addr->select.implicit = true;
+ return find_create_select(pos, sub_addr, qualifiers, sub_compound,
+ symbol);
+ }
+
+ if (iter_symbol == symbol) {
+ return create_select(pos, addr, qualifiers, iter);
+ }
+ }
+
+ return NULL;
+}
+
static void parse_compound_declarators(compound_t *compound,
const declaration_specifiers_t *specifiers)
{
- while (true) {
+ do {
entity_t *entity;
if (token.type == ':') {
expression_t *size = parse_constant_expression();
type_t *type = make_bitfield_type(base_type, size,
- &source_position, sym_anonymous);
+ &source_position, NULL);
+
+ attribute_t *attributes = parse_attributes(NULL);
+ attribute_t **anchor = &attributes;
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
+ *anchor = specifiers->attributes;
entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
entity->base.namespc = NAMESPACE_NORMAL;
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;
+ entity->declaration.attributes = attributes;
+
+ if (attributes != NULL) {
+ handle_entity_attributes(attributes, entity);
+ }
+ 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;
- }
- }
+ if (entity->kind == ENTITY_TYPEDEF) {
+ errorf(&entity->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);
+ }
+ }
- /* 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 (token.type == ':') {
+ source_position_t source_position = *HERE;
+ next_token();
+ expression_t *size = parse_constant_expression();
- if (prev != NULL) {
- errorf(&entity->base.source_position,
- "multiple declarations of symbol '%Y' (declared %P)",
- symbol, &prev->base.source_position);
- }
- }
+ type_t *type = entity->declaration.type;
+ type_t *bitfield_type = make_bitfield_type(type, size,
+ &source_position, entity->base.symbol);
- append_entity(&compound->members, entity);
+ attribute_t *attributes = parse_attributes(NULL);
+ entity->declaration.type = bitfield_type;
+ handle_entity_attributes(attributes, entity);
+ } 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);
}
}
-
- if (token.type != ',')
- break;
- next_token();
- }
- expect(';');
+ } while (next_if(','));
+ expect(';', end_error);
end_error:
anonymous_entity = NULL;
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
- if (specifiers.storage_class != STORAGE_CLASS_NONE ||
- specifiers.thread_local) {
+ if (specifiers.storage_class != STORAGE_CLASS_NONE
+ || specifiers.thread_local) {
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
- errorf(HERE, "typename may not have a storage class");
+ errorf(HERE, "typename must not have a storage class");
}
type_t *result = parse_abstract_declarator(specifiers.type);
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;
};
{
/* skip the error message if the error token was read */
if (token.type != T_ERROR) {
- errorf(HERE, "expected expression, got token '%K'", &token);
+ errorf(HERE, "expected expression, got token %K", &token);
}
next_token();
return create_invalid_expression();
}
+static type_t *get_string_type(void)
+{
+ return warning.write_strings ? type_const_char_ptr : type_char_ptr;
+}
+
+static type_t *get_wide_string_type(void)
+{
+ return warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+}
+
/**
* Parse a string constant.
*/
-static expression_t *parse_string_const(void)
+static expression_t *parse_string_literal(void)
{
- wide_string_t wres;
- if (token.type == T_STRING_LITERAL) {
- string_t res = token.v.string;
+ source_position_t begin = token.source_position;
+ string_t res = token.literal;
+ bool is_wide = (token.type == T_WIDE_STRING_LITERAL);
+
+ next_token();
+ while (token.type == T_STRING_LITERAL
+ || token.type == T_WIDE_STRING_LITERAL) {
+ warn_string_concat(&token.source_position);
+ res = concat_strings(&res, &token.literal);
next_token();
- while (token.type == T_STRING_LITERAL) {
- res = concat_strings(&res, &token.v.string);
- next_token();
- }
- if (token.type != T_WIDE_STRING_LITERAL) {
- expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
- /* note: that we use type_char_ptr here, which is already the
- * automatic converted type. revert_automatic_type_conversion
- * will construct the array type */
- cnst->base.type = warning.write_strings ? type_const_char_ptr : type_char_ptr;
- cnst->string.value = res;
- return cnst;
- }
+ is_wide |= token.type == T_WIDE_STRING_LITERAL;
+ }
- wres = concat_string_wide_string(&res, &token.v.wide_string);
+ expression_t *literal;
+ if (is_wide) {
+ literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
+ literal->base.type = get_wide_string_type();
} else {
- wres = token.v.wide_string;
+ literal = allocate_expression_zero(EXPR_STRING_LITERAL);
+ literal->base.type = get_string_type();
}
+ literal->base.source_position = begin;
+ literal->literal.value = res;
+
+ return literal;
+}
+
+/**
+ * Parse a boolean constant.
+ */
+static expression_t *parse_boolean_literal(bool value)
+{
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN);
+ literal->base.source_position = token.source_position;
+ literal->base.type = type_bool;
+ literal->literal.value.begin = value ? "true" : "false";
+ literal->literal.value.size = value ? 4 : 5;
+
next_token();
+ return literal;
+}
- for (;;) {
- switch (token.type) {
- case T_WIDE_STRING_LITERAL:
- wres = concat_wide_strings(&wres, &token.v.wide_string);
- break;
+static void warn_traditional_suffix(void)
+{
+ if (!warning.traditional)
+ return;
+ warningf(&token.source_position, "traditional C rejects the '%Y' suffix",
+ token.symbol);
+}
- case T_STRING_LITERAL:
- wres = concat_wide_string_string(&wres, &token.v.string);
- break;
+static void check_integer_suffix(void)
+{
+ symbol_t *suffix = token.symbol;
+ if (suffix == NULL)
+ return;
- default: {
- expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
- cnst->base.type = warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr;
- cnst->wide_string.value = wres;
- return cnst;
+ bool not_traditional = false;
+ const char *c = suffix->string;
+ if (*c == 'l' || *c == 'L') {
+ ++c;
+ if (*c == *(c-1)) {
+ not_traditional = true;
+ ++c;
+ if (*c == 'u' || *c == 'U') {
+ ++c;
+ }
+ } else if (*c == 'u' || *c == 'U') {
+ not_traditional = true;
+ ++c;
+ }
+ } else if (*c == 'u' || *c == 'U') {
+ not_traditional = true;
+ ++c;
+ if (*c == 'l' || *c == 'L') {
+ ++c;
+ if (*c == *(c-1)) {
+ ++c;
}
}
- next_token();
+ }
+ if (*c != '\0') {
+ errorf(&token.source_position,
+ "invalid suffix '%s' on integer constant", suffix->string);
+ } else if (not_traditional) {
+ warn_traditional_suffix();
}
}
-/**
- * Parse a boolean constant.
- */
-static expression_t *parse_bool_const(bool value)
+static type_t *check_floatingpoint_suffix(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_bool;
- cnst->conste.v.int_value = value;
+ symbol_t *suffix = token.symbol;
+ type_t *type = type_double;
+ if (suffix == NULL)
+ return type;
- next_token();
+ bool not_traditional = false;
+ const char *c = suffix->string;
+ if (*c == 'f' || *c == 'F') {
+ ++c;
+ type = type_float;
+ } else if (*c == 'l' || *c == 'L') {
+ ++c;
+ type = type_long_double;
+ }
+ if (*c != '\0') {
+ errorf(&token.source_position,
+ "invalid suffix '%s' on floatingpoint constant", suffix->string);
+ } else if (not_traditional) {
+ warn_traditional_suffix();
+ }
- return cnst;
+ return type;
}
/**
* Parse an integer constant.
*/
-static expression_t *parse_int_const(void)
+static expression_t *parse_number_literal(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = token.datatype;
- cnst->conste.v.int_value = token.v.intvalue;
+ expression_kind_t kind;
+ type_t *type;
+
+ switch (token.type) {
+ case T_INTEGER:
+ kind = EXPR_LITERAL_INTEGER;
+ check_integer_suffix();
+ type = type_int;
+ break;
+ case T_INTEGER_OCTAL:
+ kind = EXPR_LITERAL_INTEGER_OCTAL;
+ check_integer_suffix();
+ type = type_int;
+ break;
+ case T_INTEGER_HEXADECIMAL:
+ kind = EXPR_LITERAL_INTEGER_HEXADECIMAL;
+ check_integer_suffix();
+ type = type_int;
+ break;
+ case T_FLOATINGPOINT:
+ kind = EXPR_LITERAL_FLOATINGPOINT;
+ type = check_floatingpoint_suffix();
+ break;
+ case T_FLOATINGPOINT_HEXADECIMAL:
+ kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL;
+ type = check_floatingpoint_suffix();
+ break;
+ default:
+ panic("unexpected token type in parse_number_literal");
+ }
+ expression_t *literal = allocate_expression_zero(kind);
+ literal->base.source_position = token.source_position;
+ literal->base.type = type;
+ literal->literal.value = token.literal;
+ literal->literal.suffix = token.symbol;
next_token();
- return cnst;
+ /* integer type depends on the size of the number and the size
+ * representable by the types. The backend/codegeneration has to determine
+ * that
+ */
+ determine_literal_type(&literal->literal);
+ return literal;
}
/**
*/
static expression_t *parse_character_constant(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT);
- cnst->base.type = token.datatype;
- cnst->conste.v.character = token.v.string;
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+ literal->base.source_position = token.source_position;
+ literal->base.type = c_mode & _CXX ? type_char : type_int;
+ literal->literal.value = token.literal;
- if (cnst->conste.v.character.size != 1) {
- if (!GNU_MODE) {
+ size_t len = literal->literal.value.size;
+ if (len != 1) {
+ if (!GNU_MODE && !(c_mode & _C99)) {
errorf(HERE, "more than 1 character in character constant");
} else if (warning.multichar) {
+ literal->base.type = type_int;
warningf(HERE, "multi-character character constant");
}
}
- next_token();
- return cnst;
+ next_token();
+ return literal;
}
/**
*/
static expression_t *parse_wide_character_constant(void)
{
- expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT);
- cnst->base.type = token.datatype;
- cnst->conste.v.wide_character = token.v.wide_string;
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
+ literal->base.source_position = token.source_position;
+ literal->base.type = type_int;
+ literal->literal.value = token.literal;
- if (cnst->conste.v.wide_character.size != 1) {
- if (!GNU_MODE) {
- errorf(HERE, "more than 1 character in character constant");
- } else if (warning.multichar) {
- warningf(HERE, "multi-character character constant");
- }
+ size_t len = wstrlen(&literal->literal.value);
+ if (len != 1) {
+ warningf(HERE, "multi-character character constant");
}
- next_token();
-
- return cnst;
-}
-
-/**
- * Parse a float constant.
- */
-static expression_t *parse_float_const(void)
-{
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = token.datatype;
- cnst->conste.v.float_value = token.v.floatvalue;
next_token();
-
- return cnst;
+ return literal;
}
static entity_t *create_implicit_function(symbol_t *symbol,
type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
ntype->function.return_type = type_int;
ntype->function.unspecified_parameters = true;
-
- type_t *type = typehash_insert(ntype);
- if (type != ntype) {
- free_type(ntype);
- }
+ ntype->function.linkage = LINKAGE_C;
+ type_t *type = identify_new_type(ntype);
entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
entity->base.symbol = symbol;
entity->base.source_position = *source_position;
- bool strict_prototypes_old = warning.strict_prototypes;
- warning.strict_prototypes = false;
- record_entity(entity, false);
- warning.strict_prototypes = strict_prototypes_old;
-
- return entity;
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- */
-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;
- 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;
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- *
- * @param return_type the return type
- * @param argument_type the argument 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;
-
- 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 result;
-}
-
-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);
+ if (current_scope != NULL) {
+ bool strict_prototypes_old = warning.strict_prototypes;
+ warning.strict_prototypes = false;
+ record_entity(entity, false);
+ warning.strict_prototypes = strict_prototypes_old;
}
- return result;
-}
-
-/**
- * Creates a function type for some function like builtins.
- *
- * @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 symbol found");
- }
+ return entity;
}
/**
- * 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)
{
switch (expression->kind) {
- case EXPR_REFERENCE: {
- entity_t *entity = expression->reference.entity;
- if (is_declaration(entity)) {
- return entity->declaration.type;
- } else if (entity->kind == ENTITY_ENUM_VALUE) {
- return entity->enum_value.enum_type;
- } else {
- panic("no declaration or enum in reference");
- }
+ case EXPR_REFERENCE: {
+ entity_t *entity = expression->reference.entity;
+ if (is_declaration(entity)) {
+ return entity->declaration.type;
+ } else if (entity->kind == ENTITY_ENUM_VALUE) {
+ return entity->enum_value.enum_type;
+ } else {
+ panic("no declaration or enum in reference");
}
+ }
- case EXPR_SELECT: {
- entity_t *entity = expression->select.compound_entry;
- assert(is_declaration(entity));
- type_t *type = entity->declaration.type;
- return get_qualified_type(type,
- expression->base.type->base.qualifiers);
- }
+ case EXPR_SELECT: {
+ entity_t *entity = expression->select.compound_entry;
+ assert(is_declaration(entity));
+ type_t *type = entity->declaration.type;
+ return get_qualified_type(type,
+ 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));
- return type->pointer.points_to;
- }
+ case EXPR_UNARY_DEREFERENCE: {
+ const expression_t *const value = expression->unary.value;
+ type_t *const type = skip_typeref(value->base.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_pointer(type_left))
+ return type_error_type;
+ return type_left->pointer.points_to;
+ }
- 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));
- return type_left->pointer.points_to;
- }
+ case EXPR_STRING_LITERAL: {
+ size_t size = expression->string_literal.value.size;
+ return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
+ }
- case EXPR_STRING_LITERAL: {
- size_t size = expression->string.value.size;
- return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
- }
+ case EXPR_WIDE_STRING_LITERAL: {
+ size_t size = wstrlen(&expression->string_literal.value);
+ return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+ }
- case EXPR_WIDE_STRING_LITERAL: {
- size_t size = expression->wide_string.value.size;
- return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
- }
+ case EXPR_COMPOUND_LITERAL:
+ return expression->compound_literal.type;
+
+ default:
+ break;
+ }
+ return expression->base.type;
+}
- case EXPR_COMPOUND_LITERAL:
- return expression->compound_literal.type;
+/**
+ * Find an entity matching a symbol in a scope.
+ * Uses current scope if scope is NULL
+ */
+static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
+ namespace_tag_t namespc)
+{
+ if (scope == NULL) {
+ return get_entity(symbol, namespc);
+ }
- default: break;
+ /* we should optimize here, if scope grows above a certain size we should
+ construct a hashmap here... */
+ entity_t *entity = scope->entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ if (entity->base.symbol == symbol && entity->base.namespc == namespc)
+ break;
}
- return expression->base.type;
+ return entity;
}
-static expression_t *parse_reference(void)
+static entity_t *parse_qualified_identifier(void)
{
- symbol_t *const symbol = token.v.symbol;
+ /* namespace containing the symbol */
+ symbol_t *symbol;
+ source_position_t pos;
+ const scope_t *lookup_scope = NULL;
- entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+ if (next_if(T_COLONCOLON))
+ lookup_scope = &unit->scope;
+
+ entity_t *entity;
+ while (true) {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+ }
+ symbol = token.symbol;
+ pos = *HERE;
+ next_token();
+
+ /* lookup entity */
+ entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
+
+ if (!next_if(T_COLONCOLON))
+ break;
+
+ switch (entity->kind) {
+ case ENTITY_NAMESPACE:
+ lookup_scope = &entity->namespacee.members;
+ break;
+ case ENTITY_STRUCT:
+ case ENTITY_UNION:
+ case ENTITY_CLASS:
+ lookup_scope = &entity->compound.members;
+ break;
+ default:
+ errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)",
+ symbol, get_entity_kind_name(entity->kind));
+ goto end_error;
+ }
+ }
if (entity == NULL) {
- if (!strict_mode && look_ahead(1)->type == '(') {
+ if (!strict_mode && token.type == '(') {
/* an implicitly declared function */
- if (warning.implicit_function_declaration) {
- warningf(HERE, "implicit declaration of function '%Y'",
- symbol);
+ if (warning.error_implicit_function_declaration) {
+ errorf(&pos, "implicit declaration of function '%Y'", symbol);
+ } else if (warning.implicit_function_declaration) {
+ warningf(&pos, "implicit declaration of function '%Y'", symbol);
}
- entity = create_implicit_function(symbol, HERE);
+ entity = create_implicit_function(symbol, &pos);
} else {
- errorf(HERE, "unknown symbol '%Y' found.", symbol);
+ errorf(&pos, "unknown identifier '%Y' found.", symbol);
entity = create_error_entity(symbol, ENTITY_VARIABLE);
}
}
- type_t *orig_type;
+ return entity;
+
+end_error:
+ /* skip further qualifications */
+ while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+}
+
+static expression_t *parse_reference(void)
+{
+ entity_t *entity = parse_qualified_identifier();
+ type_t *orig_type;
if (is_declaration(entity)) {
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
- && is_type_valid(orig_type) && !is_type_function(orig_type)) {
+ && (current_function != NULL
+ && entity->base.parent_scope->depth < current_function->parameters.depth)
+ && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
if (entity->kind == ENTITY_VARIABLE) {
/* access of a variable from an outer function */
entity->variable.address_taken = true;
+ } else if (entity->kind == ENTITY_PARAMETER) {
+ entity->parameter.address_taken = true;
}
current_function->need_closure = true;
}
- /* check for deprecated functions */
- 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) {
- warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
- prefix, entity->base.symbol, &entity->base.source_position,
- declaration->deprecated_string);
- } else {
- warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
- entity->base.symbol, &entity->base.source_position);
- }
- }
+ check_deprecated(HERE, entity);
if (warning.init_self && entity == current_init_decl && !in_type_prop
&& entity->kind == ENTITY_VARIABLE) {
entity->declaration.type, entity->base.symbol);
}
- next_token();
return expression;
}
type_t *type = parse_typename();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
if (token.type == '{') {
return parse_compound_literal(type);
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
cast->base.source_position = source_position;
- expression_t *value = parse_sub_expression(PREC_CAST);
+ expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
cast->unary.value = value;
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 */
expression->base.type = type;
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
end_error:
return expression;
TYPE_SPECIFIERS
return parse_cast();
case T_IDENTIFIER:
- if (is_typedef_symbol(token.v.symbol)) {
+ if (is_typedef_symbol(token.symbol)) {
return parse_cast();
}
}
add_anchor_token(')');
expression_t *result = parse_expression();
+ result->base.parenthesized = true;
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
end_error:
return result;
T_IDENTIFIER, NULL);
return NULL;
}
- result->symbol = token.v.symbol;
+ result->symbol = token.symbol;
next_token();
designator_t *last_designator = result;
while (true) {
- if (token.type == '.') {
- next_token();
+ if (next_if('.')) {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing member designator",
T_IDENTIFIER, NULL);
}
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
- designator->symbol = token.v.symbol;
+ designator->symbol = token.symbol;
next_token();
last_designator->next = designator;
last_designator = designator;
continue;
}
- if (token.type == '[') {
- next_token();
+ if (next_if('[')) {
add_anchor_token(']');
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
designator->array_index = parse_expression();
rem_anchor_token(']');
- expect(']');
+ expect(']', end_error);
if (designator->array_index == NULL) {
return NULL;
}
eat(T___builtin_offsetof);
- expect('(');
+ expect('(', end_error);
add_anchor_token(',');
type_t *type = parse_typename();
rem_anchor_token(',');
- expect(',');
+ expect(',', end_error);
add_anchor_token(')');
designator_t *designator = parse_designator();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
expression->offsetofe.type = type;
expression->offsetofe.designator = designator;
eat(T___builtin_va_start);
- expect('(');
+ expect('(', end_error);
add_anchor_token(',');
expression->va_starte.ap = parse_assignment_expression();
rem_anchor_token(',');
- expect(',');
+ expect(',', end_error);
expression_t *const expr = parse_assignment_expression();
if (expr->kind == EXPR_REFERENCE) {
entity_t *const entity = expr->reference.entity;
- if (entity->base.parent_scope != ¤t_function->parameters
- || entity->base.next != NULL
- || entity->kind != ENTITY_VARIABLE) {
+ if (!current_function->base.type->function.variadic) {
+ errorf(&expr->base.source_position,
+ "'va_start' used in non-variadic function");
+ } else if (entity->base.parent_scope != ¤t_function->parameters ||
+ entity->base.next != NULL ||
+ entity->kind != ENTITY_PARAMETER) {
errorf(&expr->base.source_position,
"second argument of 'va_start' must be last parameter of the current function");
} else {
expression->va_starte.parameter = &entity->variable;
}
- expect(')');
+ expect(')', end_error);
return expression;
}
- expect(')');
+ expect(')', end_error);
end_error:
return create_invalid_expression();
}
/**
- * 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('(');
- expression->va_arge.ap = parse_assignment_expression();
- expect(',');
+ expect('(', end_error);
+ 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(')');
+ expect(')', end_error);
return expression;
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)
{
eat(T___builtin_constant_p);
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression->builtin_constant.value = parse_assignment_expression();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
expression->base.type = type_int;
return expression;
}
/**
- * 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('(');
+ 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(')');
- expression->base.type = type_void;
+ expect(')', end_error);
+ expression->base.type = type_int;
return expression;
end_error:
expression->base.source_position = *HERE;
next_token();
- expect('(');
+ expect('(', end_error);
expression->binary.left = parse_assignment_expression();
- expect(',');
+ expect(',', end_error);
expression->binary.right = parse_assignment_expression();
- expect(')');
+ expect(')', end_error);
type_t *const orig_type_left = expression->binary.left->base.type;
type_t *const orig_type_right = expression->binary.right->base.type;
return create_invalid_expression();
}
-#if 0
-/**
- * Parses a __builtin_expect() expression.
- */
-static expression_t *parse_builtin_expect(void)
-{
- expression_t *expression
- = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
-
- eat(T___builtin_expect);
-
- expect('(');
- expression->binary.left = parse_assignment_expression();
- expect(',');
- expression->binary.right = parse_constant_expression();
- expect(')');
-
- expression->base.type = expression->binary.left->base.type;
-
- return expression;
-end_error:
- return create_invalid_expression();
-}
-#endif
-
/**
* Parses a MS assume() expression.
*/
eat(T__assume);
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression->unary.value = parse_assignment_expression();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
expression->base.type = type_void;
return expression;
parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
goto end_error;
}
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
label_t *label = get_label(symbol);
static expression_t *parse_noop_expression(void)
{
/* the result is a (int)0 */
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
- cnst->base.type = type_int;
- cnst->conste.v.int_value = 0;
- cnst->conste.is_ms_noop = true;
+ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP);
+ literal->base.type = type_int;
+ literal->base.source_position = token.source_position;
+ literal->literal.value.begin = "__noop";
+ literal->literal.value.size = 6;
eat(T___noop);
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') {
- while (true) {
- (void)parse_assignment_expression();
- if (token.type != ',')
- break;
- next_token();
- }
- }
+ if (token.type != ')') do {
+ (void)parse_assignment_expression();
+ } while (next_if(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
end_error:
- return cnst;
+ return literal;
}
/**
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_STRING_LITERAL:
- case T_WIDE_STRING_LITERAL: return parse_string_const();
- case T_IDENTIFIER: return parse_reference();
- 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___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_ANDAND:
- if (GNU_MODE)
- return parse_label_address();
- break;
+ case T_false: return parse_boolean_literal(false);
+ case T_true: return parse_boolean_literal(true);
+ case T_INTEGER:
+ case T_INTEGER_OCTAL:
+ case T_INTEGER_HEXADECIMAL:
+ case T_FLOATINGPOINT:
+ case T_FLOATINGPOINT_HEXADECIMAL: return parse_number_literal();
+ case T_CHARACTER_CONSTANT: return parse_character_constant();
+ case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant();
+ case T_STRING_LITERAL:
+ case T_WIDE_STRING_LITERAL: return parse_string_literal();
+ 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_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_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_COLONCOLON:
+ return parse_reference();
+ case T_IDENTIFIER:
+ if (!is_typedef_symbol(token.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);
expression->base.type = automatic_type_conversion(return_type);
rem_anchor_token(']');
- expect(']');
+ expect(']', end_error);
end_error:
return expression;
}
add_anchor_token(')');
orig_type = parse_typename();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
if (token.type == '{') {
/* It was not sizeof(type) after all. It is sizeof of an expression
goto typeprop_expression;
}
} else {
- expression = parse_sub_expression(PREC_UNARY);
+ expression = parse_subexpression(PREC_UNARY);
typeprop_expression:
tp_expression->typeprop.tp_expression = expression;
tp_expression->typeprop.type = orig_type;
type_t const* const type = skip_typeref(orig_type);
char const* const wrong_type =
- is_type_incomplete(type) ? "incomplete" :
- type->kind == TYPE_FUNCTION ? "function designator" :
- type->kind == TYPE_BITFIELD ? "bitfield" :
+ GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL :
+ is_type_incomplete(type) ? "incomplete" :
+ type->kind == TYPE_FUNCTION ? "function designator" :
+ type->kind == TYPE_BITFIELD ? "bitfield" :
NULL;
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
return parse_typeprop(EXPR_ALIGNOF);
}
-static expression_t *parse_select_expression(expression_t *compound)
+static expression_t *parse_select_expression(expression_t *addr)
{
- expression_t *select = allocate_expression_zero(EXPR_SELECT);
- select->select.compound = compound;
-
assert(token.type == '.' || token.type == T_MINUSGREATER);
- bool is_pointer = (token.type == T_MINUSGREATER);
+ bool select_left_arrow = (token.type == T_MINUSGREATER);
next_token();
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
- return select;
+ return create_invalid_expression();
}
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
next_token();
- type_t *const orig_type = compound->base.type;
+ type_t *const orig_type = addr->base.type;
type_t *const type = skip_typeref(orig_type);
type_t *type_left;
bool saw_error = false;
if (is_type_pointer(type)) {
- if (!is_pointer) {
+ if (!select_left_arrow) {
errorf(HERE,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, orig_type);
}
type_left = skip_typeref(type->pointer.points_to);
} else {
- if (is_pointer && is_type_valid(type)) {
+ if (select_left_arrow && is_type_valid(type)) {
errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
}
- entity_t *entry;
- if (type_left->kind == TYPE_COMPOUND_STRUCT ||
- type_left->kind == TYPE_COMPOUND_UNION) {
- compound_t *compound = type_left->compound.compound;
-
- if (!compound->complete) {
- errorf(HERE, "request for member '%Y' of incomplete type '%T'",
- symbol, type_left);
- goto create_error_entry;
- }
+ if (type_left->kind != TYPE_COMPOUND_STRUCT &&
+ type_left->kind != TYPE_COMPOUND_UNION) {
- entry = find_compound_entry(compound, symbol);
- if (entry == NULL) {
- errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
- goto create_error_entry;
- }
- } else {
if (is_type_valid(type_left) && !saw_error) {
errorf(HERE,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
-create_error_entry:
return create_invalid_expression();
}
- assert(is_declaration(entry));
- select->select.compound_entry = entry;
-
- type_t *entry_type = entry->declaration.type;
- type_t *res_type
- = get_qualified_type(entry_type, type_left->base.qualifiers);
+ compound_t *compound = type_left->compound.compound;
+ if (!compound->complete) {
+ errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+ symbol, type_left);
+ return create_invalid_expression();
+ }
- /* we always do the auto-type conversions; the & and sizeof parser contains
- * code to revert this! */
- select->base.type = automatic_type_conversion(res_type);
+ type_qualifiers_t qualifiers = type_left->base.qualifiers;
+ expression_t *result
+ = find_create_select(HERE, addr, qualifiers, compound, symbol);
- type_t *skipped = skip_typeref(res_type);
- if (skipped->kind == TYPE_BITFIELD) {
- select->base.type = skipped->bitfield.base_type;
+ if (result == NULL) {
+ errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+ return create_invalid_expression();
}
- return select;
+ return result;
}
-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_object_size:
+ if (call->arguments == NULL)
+ break;
+
+ call_argument_t *arg = call->arguments->next;
+ if (arg != NULL && ! is_constant_expression(arg->expression)) {
+ errorf(&call->base.source_position,
+ "second 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 */
+ if (call->arguments == NULL)
+ break;
+ 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;
+ do {
+ 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;
- if (token.type != ',')
- break;
- next_token();
- }
+ *anchor = argument;
+ anchor = &argument->next;
+ } while (next_if(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
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;
+ if (!is_type_object(skip_typeref(type))) {
+ errorf(&argument->expression->base.source_position,
+ "call argument '%E' must not be void", argument->expression);
+ }
type = get_default_promoted_type(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;
}
}
}
+static void warn_assignment_in_condition(const expression_t *const expr)
+{
+ if (!warning.parentheses)
+ return;
+ if (expr->base.kind != EXPR_BINARY_ASSIGN)
+ return;
+ if (expr->base.parenthesized)
+ return;
+ warningf(&expr->base.source_position,
+ "suggest parentheses around assignment used as truth value");
+}
+
static void semantic_condition(expression_t const *const expr,
char const *const context)
{
type_t *const type = skip_typeref(expr->base.type);
if (is_type_scalar(type)) {
warn_reference_address_as_bool(expr);
+ warn_assignment_in_condition(expr);
} else if (is_type_valid(type)) {
errorf(&expr->base.source_position,
"%s must have scalar type", context);
true_expression = parse_expression();
}
rem_anchor_token(':');
- expect(':');
+ expect(':', end_error);
+end_error:;
expression_t *false_expression =
- parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
+ parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
type_t *const orig_true_type = true_expression->base.type;
type_t *const orig_false_type = false_expression->base.type;
= create_implicit_cast(false_expression, result_type);
conditional->base.type = result_type;
return result;
-end_error:
- return create_invalid_expression();
}
/**
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- expression_t *expression = parse_sub_expression(PREC_UNARY);
+ expression_t *expression = parse_subexpression(PREC_UNARY);
in_gcc_extension = old_gcc_extension;
return expression;
}
eat(T___builtin_classify_type);
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *expression = parse_expression();
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
result->classify_type.type_expression = expression;
return result;
eat(T_delete);
- if (token.type == '[') {
- next_token();
+ if (next_if('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
- expect(']');
+ expect(']', end_error);
end_error:;
}
- expression_t *const value = parse_sub_expression(PREC_CAST);
+ expression_t *const value = parse_subexpression(PREC_CAST);
result->unary.value = value;
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_REFERENCE:
case EXPR_ARRAY_ACCESS:
+ case EXPR_COMPOUND_LITERAL:
+ case EXPR_REFERENCE:
case EXPR_SELECT:
case EXPR_UNARY_DEREFERENCE:
return true;
default: {
- type_t *type = skip_typeref(expression->base.type);
- return
- /* ISO/IEC 14882:1998(E) §3.10:3 */
- is_type_reference(type) ||
- /* Claim it is an lvalue, if the type is invalid. There was a parse
- * error before, which maybe prevented properly recognizing it as
- * lvalue. */
- !is_type_valid(type);
+ type_t *type = skip_typeref(expression->base.type);
+ return
+ /* ISO/IEC 14882:1998(E) §3.10:3 */
+ is_type_reference(type) ||
+ /* Claim it is an lvalue, if the type is invalid. There was a parse
+ * error before, which maybe prevented properly recognizing it as
+ * lvalue. */
+ !is_type_valid(type);
}
}
}
entity_t *const entity = expression->reference.entity;
- if (entity->kind != ENTITY_VARIABLE)
+ if (entity->kind != ENTITY_VARIABLE && entity->kind != ENTITY_PARAMETER)
return;
if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
&& !may_be_register) {
errorf(&expression->base.source_position,
- "address of register variable '%Y' requested",
- entity->base.symbol);
+ "address of register %s '%Y' requested",
+ get_entity_kind_name(entity->kind), entity->base.symbol);
}
- entity->variable.address_taken = true;
+ if (entity->kind == ENTITY_VARIABLE) {
+ entity->variable.address_taken = true;
+ } else {
+ assert(entity->kind == ENTITY_PARAMETER);
+ entity->parameter.address_taken = true;
+ }
}
/**
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
eat(token_type); \
- unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
+ unary_expression->unary.value = parse_subexpression(PREC_UNARY); \
\
sfunc(&unary_expression->unary); \
\
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) {
/* The type of the right operand can be different for /= */
if (is_type_integer(right->base.type) &&
is_constant_expression(right) &&
- fold_constant(right) == 0) {
+ !fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
}
/**
* 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 semantic_shift_op(binary_expression_t *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;
+ case EXPR_BINARY_SUB: op = '-'; break;
+ default: return;
+ }
+
+ warningf(&expr->base.source_position,
+ "suggest parentheses around '%c' inside shift", op);
+}
+
+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 false;
+ }
+
+ type_left = promote_integer(type_left);
+
+ if (is_constant_expression(right)) {
+ long count = fold_constant_to_int(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);
expr = expr->unary.value;
}
- if (expr->kind == EXPR_STRING_LITERAL ||
- expr->kind == EXPR_WIDE_STRING_LITERAL) {
+ if (expr->kind == EXPR_STRING_LITERAL
+ || expr->kind == EXPR_WIDE_STRING_LITERAL) {
warningf(&expr->base.source_position,
"comparison with string literal results in unspecified behaviour");
}
}
+static void warn_comparison_in_comparison(const expression_t *const expr)
+{
+ if (expr->base.parenthesized)
+ return;
+ switch (expr->base.kind) {
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_BINARY_EQUAL:
+ warningf(&expr->base.source_position,
+ "comparisons like 'x <= y < z' do not have their mathematical meaning");
+ break;
+ default:
+ break;
+ }
+}
+
+static bool maybe_negative(expression_t const *const expr)
+{
+ return
+ !is_constant_expression(expr) ||
+ fold_constant_to_int(expr) < 0;
+}
+
/**
* Check the semantics of comparison expressions.
*
}
}
+ if (warning.parentheses) {
+ warn_comparison_in_comparison(left);
+ warn_comparison_in_comparison(right);
+ }
+
type_t *orig_type_left = left->base.type;
type_t *orig_type_right = right->base.type;
type_t *type_left = skip_typeref(orig_type_left);
/* 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;
return false;
}
+ if (left->kind == EXPR_REFERENCE
+ && left->reference.entity->kind == ENTITY_FUNCTION) {
+ errorf(HERE, "cannot assign to function '%E'", left);
+ return false;
+ }
+
if (is_type_array(type_left)) {
- errorf(HERE, "cannot assign to arrays ('%E')", left);
+ errorf(HERE, "cannot assign to array '%E'", left);
return false;
}
if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
}
}
+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)
+ return;
+ if (expr->base.parenthesized)
+ return;
+ warningf(&expr->base.source_position,
+ "suggest parentheses around && within ||");
+}
+
/**
* Check the semantic restrictions of a logical expression.
*/
* §6.5.14:2 Each of the operands shall have scalar type. */
semantic_condition(expression->left, "left operand of logical operator");
semantic_condition(expression->right, "right operand of logical operator");
+ if (expression->base.kind == EXPR_BINARY_LOGICAL_OR &&
+ warning.parentheses) {
+ warn_logical_and_within_or(expression->left);
+ warn_logical_and_within_or(expression->right);
+ }
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
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;
+ case EXPR_LABEL_ADDRESS: 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_LITERAL_MS_NOOP: return true;
+ case EXPR_LITERAL_BOOLEAN:
+ case EXPR_LITERAL_CHARACTER:
+ case EXPR_LITERAL_WIDE_CHARACTER:
+ case EXPR_LITERAL_INTEGER:
+ case EXPR_LITERAL_INTEGER_OCTAL:
+ case EXPR_LITERAL_INTEGER_HEXADECIMAL:
+ case EXPR_LITERAL_FLOATINGPOINT:
+ case EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL: return false;
+ case EXPR_STRING_LITERAL: return false;
+ case EXPR_WIDE_STRING_LITERAL: 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_BUILTIN_EXPECT: return true;
- 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");
binexpr->binary.left = left; \
eat(token_type); \
\
- expression_t *right = parse_sub_expression(prec_r); \
+ expression_t *right = parse_subexpression(prec_r); \
\
binexpr->binary.right = right; \
sfunc(&binexpr->binary); \
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)
-static expression_t *parse_sub_expression(precedence_t precedence)
+static expression_t *parse_subexpression(precedence_t precedence)
{
if (token.type < 0) {
return expected_expression_error();
*/
static expression_t *parse_expression(void)
{
- return parse_sub_expression(PREC_EXPRESSION);
+ return parse_subexpression(PREC_EXPRESSION);
}
/**
* @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];
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
memset(argument, 0, sizeof(argument[0]));
- if (token.type == '[') {
- eat('[');
+ if (next_if('[')) {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing asm argument",
T_IDENTIFIER, NULL);
return NULL;
}
- argument->symbol = token.v.symbol;
+ argument->symbol = token.symbol;
- expect(']');
+ expect(']', end_error);
}
argument->constraints = parse_string_literals();
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *expression = parse_expression();
rem_anchor_token(')');
"asm output argument is not an lvalue");
}
- if (argument->constraints.begin[0] == '+')
+ if (argument->constraints.begin[0] == '=')
+ determine_lhs_ent(expression, NULL);
+ else
mark_vars_read(expression, NULL);
} else {
mark_vars_read(expression, NULL);
}
argument->expression = expression;
- expect(')');
+ expect(')', end_error);
set_address_taken(expression, true);
*anchor = argument;
anchor = &argument->next;
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
}
return result;
*/
static asm_clobber_t *parse_asm_clobbers(void)
{
- asm_clobber_t *result = NULL;
- asm_clobber_t *last = NULL;
+ asm_clobber_t *result = NULL;
+ asm_clobber_t **anchor = &result;
while (token.type == T_STRING_LITERAL) {
asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
clobber->clobber = parse_string_literals();
- if (last != NULL) {
- last->next = clobber;
- } else {
- result = clobber;
- }
- last = clobber;
+ *anchor = clobber;
+ anchor = &clobber->next;
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
}
return result;
eat(T_asm);
- if (token.type == T_volatile) {
- next_token();
+ if (next_if(T_volatile))
asm_statement->is_volatile = true;
- }
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
- add_anchor_token(':');
+ if (token.type != T_STRING_LITERAL) {
+ parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
+ goto end_of_asm;
+ }
asm_statement->asm_text = parse_string_literals();
- if (token.type != ':') {
+ add_anchor_token(':');
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
- eat(':');
asm_statement->outputs = parse_asm_arguments(true);
- if (token.type != ':') {
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
- eat(':');
asm_statement->inputs = parse_asm_arguments(false);
- if (token.type != ':') {
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
rem_anchor_token(':');
- eat(':');
asm_statement->clobbers = parse_asm_clobbers();
end_of_asm:
rem_anchor_token(')');
- expect(')');
- expect(';');
+ expect(')', end_error);
+ expect(';', end_error);
if (asm_statement->outputs == NULL) {
/* GCC: An 'asm' instruction without any output operands will be treated
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(expression);
+ long const val = fold_constant_to_int(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
if (GNU_MODE) {
- if (token.type == T_DOTDOTDOT) {
- next_token();
+ if (next_if(T_DOTDOTDOT)) {
expression_t *const end_range = parse_expression();
statement->case_label.end_range = end_range;
if (!is_constant_expression(end_range)) {
}
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(end_range);
+ long const val = fold_constant_to_int(end_range);
statement->case_label.last_case = val;
if (warning.other && val < statement->case_label.first_case) {
PUSH_PARENT(statement);
- expect(':');
+ expect(':', end_error);
+end_error:
if (current_switch != NULL) {
if (! statement->case_label.is_bad) {
POP_PARENT;
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
PUSH_PARENT(statement);
- expect(':');
+ expect(':', end_error);
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
static statement_t *parse_label_statement(void)
{
assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
label_t *label = get_label(symbol);
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
eat(':');
if (token.type == '}') {
- /* TODO only warn? */
- if (warning.other && false) {
- warningf(HERE, "label at end of compound statement");
- statement->label.statement = create_empty_statement();
- } else {
- errorf(HERE, "label at end of compound statement");
- statement->label.statement = create_invalid_statement();
- }
+ errorf(HERE, "label at end of compound statement");
+ statement->label.statement = create_invalid_statement();
} else if (token.type == ';') {
/* Eat an empty statement here, to avoid the warning about an empty
* statement after a label. label:; is commonly used to have a label
add_anchor_token('{');
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *const expr = parse_expression();
statement->ifs.condition = expr;
semantic_condition(expr, "condition of 'if'-statment");
mark_vars_read(expr, NULL);
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
end_error:
rem_anchor_token('{');
add_anchor_token(T_else);
- statement->ifs.true_statement = parse_statement();
+ statement_t *const true_stmt = parse_statement();
+ statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
- if (token.type == T_else) {
- next_token();
+ if (next_if(T_else)) {
statement->ifs.false_statement = parse_statement();
+ } else if (warning.parentheses &&
+ true_stmt->kind == STATEMENT_IF &&
+ true_stmt->ifs.false_statement != NULL) {
+ warningf(&true_stmt->base.source_position,
+ "suggest explicit braces to avoid ambiguous 'else'");
}
POP_PARENT;
*
* @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;
for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
entry = entry->base.next) {
const expression_t *expression = entry->enum_value.value;
- long value = expression != NULL ? fold_constant(expression) : last_value + 1;
+ long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
bool found = false;
for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
if (l->expression == NULL)
PUSH_PARENT(statement);
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *const expr = parse_expression();
mark_vars_read(expr, NULL);
type = type_error_type;
}
statement->switchs.expression = create_implicit_cast(expr, type);
- expect(')');
+ expect(')', end_error);
rem_anchor_token(')');
switch_statement_t *rem = current_switch;
PUSH_PARENT(statement);
- expect('(');
+ expect('(', end_error);
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->whiles.condition = cond;
semantic_condition(cond, "condition of 'while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
statement->whiles.body = parse_loop_body(statement);
statement->do_while.body = parse_loop_body(statement);
rem_anchor_token(T_while);
- expect(T_while);
- expect('(');
+ expect(T_while, end_error);
+ expect('(', end_error);
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->do_while.condition = cond;
semantic_condition(cond, "condition of 'do-while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
- expect(')');
- expect(';');
+ expect(')', end_error);
+ expect(';', end_error);
POP_PARENT;
return statement;
eat(T_for);
+ expect('(', end_error1);
+ add_anchor_token(')');
+
PUSH_PARENT(statement);
size_t const top = environment_top();
scope_t *old_scope = scope_push(&statement->fors.scope);
- expect('(');
- add_anchor_token(')');
+ bool old_gcc_extension = in_gcc_extension;
+ while (next_if(T___extension__)) {
+ in_gcc_extension = true;
+ }
- if (token.type == ';') {
- next_token();
+ if (next_if(';')) {
} else if (is_declaration_specifier(&token, false)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
add_anchor_token(';');
expression_t *const init = parse_expression();
statement->fors.initialisation = init;
- mark_vars_read(init, VAR_ANY);
+ mark_vars_read(init, ENT_ANY);
if (warning.unused_value && !expression_has_effect(init)) {
warningf(&init->base.source_position,
"initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
- expect(';');
+ expect(';', end_error2);
}
+ in_gcc_extension = old_gcc_extension;
if (token.type != ';') {
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
- /* §6.8.5:2 The controlling expression of an iteration statement shall
- * have scalar type. */
+ /* §6.8.5:2 The controlling expression of an iteration statement
+ * shall have scalar type. */
semantic_condition(cond, "condition of 'for'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
- expect(';');
+ expect(';', end_error2);
if (token.type != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
- mark_vars_read(step, VAR_ANY);
+ mark_vars_read(step, ENT_ANY);
if (warning.unused_value && !expression_has_effect(step)) {
warningf(&step->base.source_position,
"step of 'for'-statement has no effect");
}
}
- expect(')');
+ expect(')', end_error2);
rem_anchor_token(')');
statement->fors.body = parse_loop_body(statement);
POP_PARENT;
return statement;
-end_error:
+end_error2:
POP_PARENT;
rem_anchor_token(')');
assert(current_scope == &statement->fors.scope);
scope_pop(old_scope);
environment_pop_to(top);
+ /* fallthrough */
+end_error1:
return create_invalid_statement();
}
statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
eat(T_goto);
- if (GNU_MODE && token.type == '*') {
- next_token();
+ if (GNU_MODE && next_if('*')) {
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
}
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;
- }
- symbol_t *symbol = token.v.symbol;
+ } else if (token.type == T_IDENTIFIER) {
+ symbol_t *symbol = token.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 */
*goto_anchor = &statement->gotos;
goto_anchor = &statement->gotos.next;
- expect(';');
+ expect(';', end_error);
return statement;
end_error:
statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
eat(T_continue);
- expect(';');
+ expect(';', end_error);
end_error:
return statement;
statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
eat(T_break);
- expect(';');
+ expect(';', end_error);
end_error:
return statement;
statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
eat(T___leave);
- expect(';');
+ expect(';', end_error);
end_error:
return statement;
assert(is_type_function(func_type));
type_t *const return_type = skip_typeref(func_type->function.return_type);
+ source_position_t const *const pos = &statement->base.source_position;
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
- if (is_type_atomic(return_type, ATOMIC_TYPE_VOID) &&
- !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
- if (warning.other) {
- warningf(&statement->base.source_position,
- "'return' with a value, in function returning void");
+ if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+ /* ISO/IEC 14882:1998(E) §6.6.3:2 */
+ /* Only warn in C mode, because GCC does the same */
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos,
+ "'return' with a value, in function returning 'void'");
+ } else if (warning.other) {
+ warningf(pos,
+ "'return' with a value, in function returning 'void'");
+ }
+ } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */
+ /* Only warn in C mode, because GCC does the same */
+ if (strict_mode) {
+ errorf(pos,
+ "'return' with expression in function returning 'void'");
+ } else if (warning.other) {
+ warningf(pos,
+ "'return' with expression in function returning 'void'");
+ }
}
- return_value = NULL;
} else {
assign_error_t error = semantic_assign(return_type, return_value);
report_assign_error(error, return_type, return_value, "'return'",
- &statement->base.source_position);
- return_value = create_implicit_cast(return_value, return_type);
+ pos);
}
+ return_value = create_implicit_cast(return_value, return_type);
/* check for returning address of a local var */
if (warning.other && return_value != NULL
&& return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
const expression_t *expression = return_value->unary.value;
if (expression_is_local_variable(expression)) {
- warningf(&statement->base.source_position,
- "function returns address of local variable");
+ warningf(pos, "function returns address of local variable");
}
}
} else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
- warningf(&statement->base.source_position,
- "'return' without value, in function returning non-void");
+ /* ISO/IEC 14882:1998(E) §6.6.3:3 */
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos,
+ "'return' without value, in function returning non-void");
+ } else {
+ warningf(pos,
+ "'return' without value, in function returning non-void");
+ }
}
statement->returns.value = return_value;
- expect(';');
+ expect(';', end_error);
end_error:
return statement;
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;
}
expression_t *const expr = parse_expression();
statement->expression.expression = expr;
- mark_vars_read(expr, VAR_ANY);
+ mark_vars_read(expr, ENT_ANY);
- expect(';');
+ expect(';', end_error);
end_error:
return statement;
POP_PARENT;
- if (token.type == T___except) {
- eat(T___except);
- expect('(');
+ if (next_if(T___except)) {
+ expect('(', end_error);
add_anchor_token(')');
expression_t *const expr = parse_expression();
mark_vars_read(expr, NULL);
}
statement->ms_try.except_expression = create_implicit_cast(expr, type);
rem_anchor_token(')');
- expect(')');
+ expect(')', end_error);
statement->ms_try.final_statement = parse_compound_statement(false);
- } else if (token.type == T__finally) {
- eat(T___finally);
+ } else if (next_if(T__finally)) {
statement->ms_try.final_statement = parse_compound_statement(false);
} else {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
entity_t *begin = NULL, *end = NULL;
- while (true) {
+ do {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing local label declaration",
T_IDENTIFIER, NULL);
goto end_error;
}
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.symbol;
entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
if (entity != NULL && entity->base.parent_scope == current_scope) {
errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)",
environment_push(entity);
}
next_token();
-
- if (token.type != ',')
- break;
- next_token();
- }
+ } while (next_if(','));
eat(';');
end_error:
statement->declaration.declarations_begin = begin;
symbol_t *symbol = NULL;
if (token.type == T_IDENTIFIER) {
- symbol = token.v.symbol;
+ symbol = token.symbol;
next_token();
entity = get_entity(symbol, NAMESPACE_NORMAL);
- if (entity != NULL && entity->kind != ENTITY_NAMESPACE
+ 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 (!is_error_entity(entity)) {
+ error_redefined_as_different_kind(&token.source_position,
+ entity, ENTITY_NAMESPACE);
+ }
entity = NULL;
}
}
size_t const top = environment_top();
scope_t *old_scope = scope_push(&entity->namespacee.members);
- expect('{');
+ entity_t *old_current_entity = current_entity;
+ current_entity = entity;
+
+ expect('{', end_error);
parse_externals();
- expect('}');
+ expect('}', end_error);
end_error:
assert(current_scope == &entity->namespacee.members);
+ assert(current_entity == entity);
+ current_entity = old_current_entity;
scope_pop(old_scope);
environment_pop_to(top);
}
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ':') {
statement = parse_label_statement();
- } else if (is_typedef_symbol(token.v.symbol)) {
+ } else if (is_typedef_symbol(token.symbol)) {
statement = parse_declaration_statement();
} else {
/* it's an identifier, the grammar says this must be an
switch (la1_type) {
case '&':
case '*':
- if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL)
+ if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL)
goto expression_statment;
/* FALLTHROUGH */
case T___extension__:
/* This can be a prefix to a declaration or an expression statement.
* We simply eat it now and parse the rest with tail recursion. */
- do {
- next_token();
- } while (token.type == T___extension__);
+ while (next_if(T___extension__)) {}
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
statement = intern_parse_statement();
eat('{');
add_anchor_token('}');
+ /* tokens, which can start a statement */
+ /* TODO MS, __builtin_FOO */
+ add_anchor_token('!');
+ add_anchor_token('&');
+ add_anchor_token('(');
+ add_anchor_token('*');
+ add_anchor_token('+');
+ add_anchor_token('-');
+ add_anchor_token('{');
+ add_anchor_token('~');
+ add_anchor_token(T_CHARACTER_CONSTANT);
+ add_anchor_token(T_COLONCOLON);
+ add_anchor_token(T_FLOATINGPOINT);
+ add_anchor_token(T_IDENTIFIER);
+ add_anchor_token(T_INTEGER);
+ add_anchor_token(T_MINUSMINUS);
+ add_anchor_token(T_PLUSPLUS);
+ add_anchor_token(T_STRING_LITERAL);
+ add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
+ add_anchor_token(T_WIDE_STRING_LITERAL);
+ add_anchor_token(T__Bool);
+ add_anchor_token(T__Complex);
+ add_anchor_token(T__Imaginary);
+ add_anchor_token(T___FUNCTION__);
+ add_anchor_token(T___PRETTY_FUNCTION__);
+ add_anchor_token(T___alignof__);
+ add_anchor_token(T___attribute__);
+ add_anchor_token(T___builtin_va_start);
+ add_anchor_token(T___extension__);
+ add_anchor_token(T___func__);
+ add_anchor_token(T___imag__);
+ add_anchor_token(T___label__);
+ add_anchor_token(T___real__);
+ add_anchor_token(T___thread);
+ add_anchor_token(T_asm);
+ add_anchor_token(T_auto);
+ add_anchor_token(T_bool);
+ add_anchor_token(T_break);
+ add_anchor_token(T_case);
+ add_anchor_token(T_char);
+ add_anchor_token(T_class);
+ add_anchor_token(T_const);
+ add_anchor_token(T_const_cast);
+ add_anchor_token(T_continue);
+ add_anchor_token(T_default);
+ add_anchor_token(T_delete);
+ add_anchor_token(T_double);
+ add_anchor_token(T_do);
+ add_anchor_token(T_dynamic_cast);
+ add_anchor_token(T_enum);
+ add_anchor_token(T_extern);
+ add_anchor_token(T_false);
+ add_anchor_token(T_float);
+ add_anchor_token(T_for);
+ add_anchor_token(T_goto);
+ add_anchor_token(T_if);
+ add_anchor_token(T_inline);
+ add_anchor_token(T_int);
+ add_anchor_token(T_long);
+ add_anchor_token(T_new);
+ add_anchor_token(T_operator);
+ add_anchor_token(T_register);
+ add_anchor_token(T_reinterpret_cast);
+ add_anchor_token(T_restrict);
+ add_anchor_token(T_return);
+ add_anchor_token(T_short);
+ add_anchor_token(T_signed);
+ add_anchor_token(T_sizeof);
+ add_anchor_token(T_static);
+ add_anchor_token(T_static_cast);
+ add_anchor_token(T_struct);
+ add_anchor_token(T_switch);
+ add_anchor_token(T_template);
+ add_anchor_token(T_this);
+ add_anchor_token(T_throw);
+ add_anchor_token(T_true);
+ add_anchor_token(T_try);
+ add_anchor_token(T_typedef);
+ add_anchor_token(T_typeid);
+ add_anchor_token(T_typename);
+ add_anchor_token(T_typeof);
+ add_anchor_token(T_union);
+ add_anchor_token(T_unsigned);
+ add_anchor_token(T_using);
+ add_anchor_token(T_void);
+ add_anchor_token(T_volatile);
+ add_anchor_token(T_wchar_t);
+ add_anchor_token(T_while);
size_t const top = environment_top();
scope_t *old_scope = scope_push(&statement->compound.scope);
}
end_error:
+ rem_anchor_token(T_while);
+ rem_anchor_token(T_wchar_t);
+ rem_anchor_token(T_volatile);
+ rem_anchor_token(T_void);
+ rem_anchor_token(T_using);
+ rem_anchor_token(T_unsigned);
+ rem_anchor_token(T_union);
+ rem_anchor_token(T_typeof);
+ rem_anchor_token(T_typename);
+ rem_anchor_token(T_typeid);
+ rem_anchor_token(T_typedef);
+ rem_anchor_token(T_try);
+ rem_anchor_token(T_true);
+ rem_anchor_token(T_throw);
+ rem_anchor_token(T_this);
+ rem_anchor_token(T_template);
+ rem_anchor_token(T_switch);
+ rem_anchor_token(T_struct);
+ rem_anchor_token(T_static_cast);
+ rem_anchor_token(T_static);
+ rem_anchor_token(T_sizeof);
+ rem_anchor_token(T_signed);
+ rem_anchor_token(T_short);
+ rem_anchor_token(T_return);
+ rem_anchor_token(T_restrict);
+ rem_anchor_token(T_reinterpret_cast);
+ rem_anchor_token(T_register);
+ rem_anchor_token(T_operator);
+ rem_anchor_token(T_new);
+ rem_anchor_token(T_long);
+ rem_anchor_token(T_int);
+ rem_anchor_token(T_inline);
+ rem_anchor_token(T_if);
+ rem_anchor_token(T_goto);
+ rem_anchor_token(T_for);
+ rem_anchor_token(T_float);
+ rem_anchor_token(T_false);
+ rem_anchor_token(T_extern);
+ rem_anchor_token(T_enum);
+ rem_anchor_token(T_dynamic_cast);
+ rem_anchor_token(T_do);
+ rem_anchor_token(T_double);
+ rem_anchor_token(T_delete);
+ rem_anchor_token(T_default);
+ rem_anchor_token(T_continue);
+ rem_anchor_token(T_const_cast);
+ rem_anchor_token(T_const);
+ rem_anchor_token(T_class);
+ rem_anchor_token(T_char);
+ rem_anchor_token(T_case);
+ rem_anchor_token(T_break);
+ rem_anchor_token(T_bool);
+ rem_anchor_token(T_auto);
+ rem_anchor_token(T_asm);
+ rem_anchor_token(T___thread);
+ rem_anchor_token(T___real__);
+ rem_anchor_token(T___label__);
+ rem_anchor_token(T___imag__);
+ rem_anchor_token(T___func__);
+ rem_anchor_token(T___extension__);
+ rem_anchor_token(T___builtin_va_start);
+ rem_anchor_token(T___attribute__);
+ rem_anchor_token(T___alignof__);
+ rem_anchor_token(T___PRETTY_FUNCTION__);
+ rem_anchor_token(T___FUNCTION__);
+ rem_anchor_token(T__Imaginary);
+ rem_anchor_token(T__Complex);
+ rem_anchor_token(T__Bool);
+ rem_anchor_token(T_WIDE_STRING_LITERAL);
+ rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
+ rem_anchor_token(T_STRING_LITERAL);
+ rem_anchor_token(T_PLUSPLUS);
+ rem_anchor_token(T_MINUSMINUS);
+ rem_anchor_token(T_INTEGER);
+ rem_anchor_token(T_IDENTIFIER);
+ rem_anchor_token(T_FLOATINGPOINT);
+ rem_anchor_token(T_COLONCOLON);
+ rem_anchor_token(T_CHARACTER_CONSTANT);
+ rem_anchor_token('~');
+ rem_anchor_token('{');
+ rem_anchor_token('-');
+ rem_anchor_token('+');
+ rem_anchor_token('*');
+ rem_anchor_token('(');
+ rem_anchor_token('&');
+ rem_anchor_token('!');
rem_anchor_token('}');
assert(current_scope == &statement->compound.scope);
scope_pop(old_scope);
statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
eat(T_asm);
- expect('(');
+ expect('(', end_error);
statement->asms.asm_text = parse_string_literals();
statement->base.next = unit->global_asm;
unit->global_asm = statement;
- expect(')');
- expect(';');
+ expect(')', end_error);
+ expect(';', end_error);
end_error:;
}
}
current_linkage = new_linkage;
- if (token.type == '{') {
- next_token();
+ if (next_if('{')) {
parse_externals();
- expect('}');
+ expect('}', end_error);
} else {
parse_external();
}
DECLARATION_START_NO_EXTERN
case T_IDENTIFIER:
case T___extension__:
- case '(': /* for function declarations with implicit return type and
- * parenthesized declarator, i.e. (f)(void); */
+ /* tokens below are for implicit int */
+ case '&': /* & x; -> int& x; (and error later, because C++ has no
+ implicit int) */
+ case '*': /* * x; -> int* x; */
+ case '(': /* (x); -> int (x); */
parse_external_declaration();
return;
error_count = 0;
warning_count = 0;
- type_set_output(stderr);
- ast_set_output(stderr);
+ print_to_file(stderr);
assert(unit == NULL);
unit = allocate_ast_zero(sizeof(unit[0]));
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;
}
+/* §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);
+ for (size_t i = 0; i != n; ++i) {
+ declaration_t *const decl = incomplete_arrays[i];
+ type_t *const orig_type = decl->type;
+ type_t *const type = skip_typeref(orig_type);
+
+ if (!is_type_incomplete(type))
+ continue;
+
+ if (warning.other) {
+ warningf(&decl->base.source_position,
+ "array '%#T' assumed to have one element",
+ orig_type, decl->base.symbol);
+ }
+
+ type_t *const new_type = duplicate_type(type);
+ new_type->array.size_constant = true;
+ new_type->array.has_implicit_size = true;
+ new_type->array.size = 1;
+
+ type_t *const result = identify_new_type(new_type);
+
+ decl->type = result;
+ }
+}
+
+void prepare_main_collect2(entity_t *entity)
+{
+ // create call to __main
+ symbol_t *symbol = symbol_table_insert("__main");
+ entity_t *subsubmain_ent
+ = create_implicit_function(symbol, &builtin_source_position);
+
+ expression_t *ref = allocate_expression_zero(EXPR_REFERENCE);
+ type_t *ftype = subsubmain_ent->declaration.type;
+ ref->base.source_position = builtin_source_position;
+ ref->base.type = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
+ ref->reference.entity = subsubmain_ent;
+
+ expression_t *call = allocate_expression_zero(EXPR_CALL);
+ call->base.source_position = builtin_source_position;
+ call->base.type = type_void;
+ call->call.function = ref;
+
+ statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION);
+ expr_statement->base.source_position = builtin_source_position;
+ expr_statement->expression.expression = call;
+
+ statement_t *statement = entity->function.statement;
+ assert(statement->kind == STATEMENT_COMPOUND);
+ compound_statement_t *compounds = &statement->compound;
+
+ expr_statement->base.next = compounds->statements;
+ compounds->statements = expr_statement;
+}
+
void parse(void)
{
lookahead_bufpos = 0;
for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
next_token();
}
- current_linkage = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C;
+ current_linkage = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C;
+ incomplete_arrays = NEW_ARR_F(declaration_t*, 0);
parse_translation_unit();
+ complete_incomplete_arrays();
+ DEL_ARR_F(incomplete_arrays);
+ incomplete_arrays = NULL;
}
/**
{
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();