#include "entity_t.h"
#include "attribute_t.h"
#include "lang_features.h"
-#include "walk_statements.h"
+#include "walk.h"
#include "warning.h"
#include "printer.h"
#include "adt/bitfiddle.h"
/** 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 statement_t *current_parent = 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) */
-static bool in_type_prop = false;
/** 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) \
- statement_t *const prev_parent = current_parent; \
- ((void)(current_parent = (stmt)))
-#define POP_PARENT ((void)(current_parent = prev_parent))
+static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
+
+
+#define PUSH_PARENT(stmt) \
+ statement_t *const new_parent = (stmt); \
+ statement_t *const old_parent = current_parent; \
+ ((void)(current_parent = new_parent))
+#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent))
+
+#define PUSH_SCOPE(scope) \
+ size_t const top = environment_top(); \
+ scope_t *const new_scope = (scope); \
+ scope_t *const old_scope = scope_push(new_scope)
+#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top))
+
+#define PUSH_EXTENSION() \
+ (void)0; \
+ bool const old_gcc_extension = in_gcc_extension; \
+ while (next_if(T___extension__)) { \
+ in_gcc_extension = true; \
+ } \
+ do {} while (0)
+#define POP_EXTENSION() \
+ ((void)(in_gcc_extension = old_gcc_extension))
/** special symbol used for anonymous entities. */
static symbol_t *sym_anonymous = NULL;
/** The token anchor set */
-static unsigned char token_anchor_set[T_LAST_TOKEN];
+static unsigned short token_anchor_set[T_LAST_TOKEN];
/** The current source position. */
-#define HERE (&token.source_position)
+#define HERE (&token.base.source_position)
/** true if we are in GCC mode. */
#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
TYPE_QUALIFIERS \
TYPE_SPECIFIERS
-#define TYPENAME_START \
- TYPE_QUALIFIERS \
- TYPE_SPECIFIERS
-
#define EXPRESSION_START \
case '!': \
case '&': \
[STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
[STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
[EXPR_INVALID] = sizeof(expression_base_t),
[EXPR_REFERENCE] = sizeof(reference_expression_t),
[EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
+ [EXPR_LITERAL_BOOLEAN] = sizeof(literal_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),
if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) {
return sizes[EXPR_BINARY_FIRST];
}
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
res->base.kind = kind;
res->base.parent = current_parent;
- res->base.source_position = token.source_position;
+ res->base.source_position = token.base.source_position;
return res;
}
res->base.kind = kind;
res->base.type = type_error_type;
- res->base.source_position = token.source_position;
+ res->base.source_position = token.base.source_position;
return res;
}
return allocate_statement_zero(STATEMENT_EMPTY);
}
-static function_parameter_t *allocate_parameter(type_t *const type)
-{
- function_parameter_t *const param
- = obstack_alloc(type_obst, sizeof(*param));
- memset(param, 0, sizeof(*param));
- param->type = type;
- return param;
-}
-
/**
* Returns the size of an initializer node.
*
[INITIALIZER_LIST] = sizeof(initializer_list_t),
[INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t)
};
- assert(kind < lengthof(sizes));
+ assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
return sizes[kind];
}
static inline bool next_if(int const type)
{
- if (token.type == type) {
+ if (token.kind == type) {
next_token();
return true;
} else {
/**
* Adds a token type to the token type anchor set (a multi-set).
*/
-static void add_anchor_token(int token_type)
+static void add_anchor_token(int token_kind)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- ++token_anchor_set[token_type];
+ assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ ++token_anchor_set[token_kind];
}
/**
* 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)
+static int save_and_reset_anchor_state(int token_kind)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- int count = token_anchor_set[token_type];
- token_anchor_set[token_type] = 0;
+ assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ int count = token_anchor_set[token_kind];
+ token_anchor_set[token_kind] = 0;
return count;
}
/**
* Restore the number of token types to the given count.
*/
-static void restore_anchor_state(int token_type, int count)
+static void restore_anchor_state(int token_kind, int count)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- token_anchor_set[token_type] = count;
+ assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ token_anchor_set[token_kind] = count;
}
/**
* Remove a token type from the token type anchor set (a multi-set).
*/
-static void rem_anchor_token(int token_type)
+static void rem_anchor_token(int token_kind)
{
- assert(0 <= token_type && token_type < T_LAST_TOKEN);
- assert(token_anchor_set[token_type] != 0);
- --token_anchor_set[token_type];
+ assert(0 <= token_kind && token_kind < T_LAST_TOKEN);
+ assert(token_anchor_set[token_kind] != 0);
+ --token_anchor_set[token_kind];
}
/**
*/
static bool at_anchor(void)
{
- if (token.type < 0)
+ if (token.kind < 0)
return false;
- return token_anchor_set[token.type];
+ return token_anchor_set[token.kind];
}
/**
unsigned parenthesis_count = 0;
unsigned brace_count = 0;
unsigned bracket_count = 0;
- while (token.type != end_token ||
+ while (token.kind != end_token ||
parenthesis_count != 0 ||
brace_count != 0 ||
bracket_count != 0) {
- switch (token.type) {
+ switch (token.kind) {
case T_EOF: return;
case '(': ++parenthesis_count; break;
case '{': ++brace_count; break;
if (bracket_count > 0)
--bracket_count;
check_stop:
- if (token.type == end_token &&
+ if (token.kind == end_token &&
parenthesis_count == 0 &&
brace_count == 0 &&
bracket_count == 0)
*/
static void eat_until_anchor(void)
{
- while (token_anchor_set[token.type] == 0) {
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ while (token_anchor_set[token.kind] == 0) {
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
}
}
next_if('}');
}
-#define eat(token_type) (assert(token.type == (token_type)), next_token())
+#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
/**
* Report a parse error because an expected token was not found.
*/
#define expect(expected, error_label) \
do { \
- if (UNLIKELY(token.type != (expected))) { \
+ if (UNLIKELY(token.kind != (expected))) { \
parse_error_expected(NULL, (expected), NULL); \
add_anchor_token(expected); \
eat_until_anchor(); \
- next_if((expected)); \
rem_anchor_token(expected); \
- goto error_label; \
+ if (token.kind != (expected)) \
+ goto error_label; \
} \
next_token(); \
} while (0)
assert(namespc != NAMESPACE_INVALID);
entity_t *entity = symbol->entity;
for (; entity != NULL; entity = entity->base.symbol_next) {
- if (entity->base.namespc == namespc)
+ if ((namespace_tag_t)entity->base.namespc == namespc)
return entity;
}
entity_kind_tag_t const kind)
{
entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
- if (entity != NULL && entity->kind != kind) {
+ if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) {
errorf(HERE,
"'%Y' defined as wrong kind of tag (previous definition %P)",
symbol, &entity->base.source_position);
*/
static type_t *promote_integer(type_t *type)
{
- if (type->kind == TYPE_BITFIELD)
- type = type->bitfield.base_type;
-
if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT))
type = type_int;
return type;
}
-/**
- * Create a cast expression.
- *
- * @param expression the expression to cast
- * @param dest_type the destination type
- */
-static expression_t *create_cast_expression(expression_t *expression,
- type_t *dest_type)
-{
- expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST_IMPLICIT);
-
- cast->unary.value = expression;
- cast->base.type = dest_type;
-
- return cast;
-}
-
/**
* Check if a given expression represents a null pointer constant.
*
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) {
+ if (expression->kind == EXPR_UNARY_CAST) {
type_t *const type = skip_typeref(expression->base.type);
if (types_compatible(type, type_void_ptr))
expression = expression->unary.value;
if (source_type == dest_type)
return expression;
- return create_cast_expression(expression, dest_type);
+ expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+ cast->unary.value = expression;
+ cast->base.type = dest_type;
+ cast->base.implicit = true;
+
+ return cast;
}
typedef enum assign_error_t {
ASSIGN_WARNING_INT_FROM_POINTER
} assign_error_t;
-static void report_assign_error(assign_error_t error, type_t *orig_type_left,
- const expression_t *const right,
- const char *context,
- const source_position_t *source_position)
+static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos)
{
type_t *const orig_type_right = right->base.type;
type_t *const type_left = skip_typeref(orig_type_left);
case ASSIGN_SUCCESS:
return;
case ASSIGN_ERROR_INCOMPATIBLE:
- errorf(source_position,
- "destination type '%T' in %s is incompatible with type '%T'",
- orig_type_left, context, orig_type_right);
+ errorf(pos, "destination type '%T' in %s is incompatible with type '%T'", orig_type_left, context, orig_type_right);
return;
case ASSIGN_ERROR_POINTER_QUALIFIER_MISSING: {
- if (warning.other) {
- type_t *points_to_left = skip_typeref(type_left->pointer.points_to);
- type_t *points_to_right = skip_typeref(type_right->pointer.points_to);
+ type_t *points_to_left = skip_typeref(type_left->pointer.points_to);
+ type_t *points_to_right = skip_typeref(type_right->pointer.points_to);
- /* the left type has all qualifiers from the right type */
- unsigned missing_qualifiers
- = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
- warningf(source_position,
- "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type",
- orig_type_left, context, orig_type_right, missing_qualifiers);
- }
+ /* the left type has all qualifiers from the right type */
+ unsigned missing_qualifiers = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
+ warningf(WARN_OTHER, pos, "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type", orig_type_left, context, orig_type_right, missing_qualifiers);
return;
}
case ASSIGN_WARNING_POINTER_INCOMPATIBLE:
- if (warning.other) {
- warningf(source_position,
- "destination type '%T' in %s is incompatible with '%E' of type '%T'",
- orig_type_left, context, right, orig_type_right);
- }
+ warningf(WARN_OTHER, pos, "destination type '%T' in %s is incompatible with '%E' of type '%T'", orig_type_left, context, right, orig_type_right);
return;
case ASSIGN_WARNING_POINTER_FROM_INT:
- if (warning.other) {
- warningf(source_position,
- "%s makes pointer '%T' from integer '%T' without a cast",
- context, orig_type_left, orig_type_right);
- }
+ warningf(WARN_OTHER, pos, "%s makes pointer '%T' from integer '%T' without a cast", context, orig_type_left, orig_type_right);
return;
case ASSIGN_WARNING_INT_FROM_POINTER:
- if (warning.other) {
- warningf(source_position,
- "%s makes integer '%T' from pointer '%T' without a cast",
- context, orig_type_left, orig_type_right);
- }
+ warningf(WARN_OTHER, pos, "%s makes integer '%T' from pointer '%T' without a cast", context, orig_type_left, orig_type_right);
return;
default:
static void warn_string_concat(const source_position_t *pos)
{
- if (warning.traditional) {
- warningf(pos, "traditional C rejects string constant concatenation");
- }
+ warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation");
}
static string_t parse_string_literals(void)
{
- assert(token.type == T_STRING_LITERAL);
- string_t result = token.literal;
+ assert(token.kind == T_STRING_LITERAL);
+ string_t result = token.string.string;
next_token();
- while (token.type == T_STRING_LITERAL) {
- warn_string_concat(&token.source_position);
- result = concat_strings(&result, &token.literal);
+ while (token.kind == T_STRING_LITERAL) {
+ warn_string_concat(&token.base.source_position);
+ result = concat_strings(&result, &token.string.string);
next_token();
}
static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
- attribute->kind = kind;
+ attribute->kind = kind;
+ attribute->source_position = *HERE;
return attribute;
}
{
attribute_argument_t *first = NULL;
attribute_argument_t **anchor = &first;
- if (token.type != ')') do {
+ if (token.kind != ')') 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;
+ if (token.kind == T_IDENTIFIER
+ && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) {
+ symbol_t *symbol = token.identifier.symbol;
argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL;
argument->v.symbol = symbol;
next_token();
static attribute_t *parse_attribute_asm(void)
{
- eat(T_asm);
-
attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM);
+ eat(T_asm);
expect('(', end_error);
attribute->a.arguments = parse_attribute_arguments();
static symbol_t *get_symbol_from_token(void)
{
- switch(token.type) {
+ switch(token.kind) {
case T_IDENTIFIER:
- return token.symbol;
+ return token.identifier.symbol;
case T_auto:
case T_char:
case T_double:
case T_volatile:
case T_inline:
/* maybe we need more tokens ... add them on demand */
- return get_token_symbol(&token);
+ return get_token_kind_symbol(token.kind);
default:
return NULL;
}
return NULL;
}
- const char *name = symbol->string;
- next_token();
+ attribute_kind_t kind;
+ char const *const name = symbol->string;
+ for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) {
+ if (kind > ATTRIBUTE_GNU_LAST) {
+ warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name);
+ /* TODO: we should still save the attribute in the list... */
+ kind = ATTRIBUTE_UNKNOWN;
+ break;
+ }
- attribute_kind_t kind;
- for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) {
const char *attribute_name = get_attribute_name(kind);
if (attribute_name != NULL
&& strcmp_underscore(attribute_name, name) == 0)
break;
}
- if (kind >= ATTRIBUTE_GNU_LAST) {
- if (warning.attribute) {
- warningf(HERE, "unknown attribute '%s' ignored", name);
- }
- /* TODO: we should still save the attribute in the list... */
- kind = ATTRIBUTE_UNKNOWN;
- }
-
attribute_t *attribute = allocate_attribute_zero(kind);
+ next_token();
/* parse arguments */
if (next_if('('))
expect('(', end_error);
expect('(', end_error);
- if (token.type != ')') do {
+ if (token.kind != ')') do {
attribute_t *attribute = parse_attribute_gnu_single();
if (attribute == NULL)
goto end_error;
anchor = &(*anchor)->next;
attribute_t *attribute;
- switch (token.type) {
+ switch (token.kind) {
case T___attribute__:
attribute = parse_attribute_gnu();
if (attribute == NULL)
break;
case T_cdecl:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL);
+ eat(T_cdecl);
break;
case T__fastcall:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL);
+ eat(T__fastcall);
break;
case T__forceinline:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE);
+ eat(T__forceinline);
break;
case T__stdcall:
- next_token();
attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL);
+ eat(T__stdcall);
break;
case T___thiscall:
- next_token();
/* TODO record modifier */
- if (warning.other)
- warningf(HERE, "Ignoring declaration modifier %K", &token);
+ warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token);
attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL);
+ eat(T___thiscall);
break;
default:
case EXPR_UNARY_POSTFIX_DECREMENT:
case EXPR_UNARY_PREFIX_INCREMENT:
case EXPR_UNARY_PREFIX_DECREMENT:
- case EXPR_UNARY_CAST_IMPLICIT:
case EXPR_UNARY_ASSUME:
unary:
mark_vars_read(expr->unary.value, lhs_ent);
return;
EXPR_LITERAL_CASES
- case EXPR_UNKNOWN:
case EXPR_INVALID:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
for (;;) {
designator_t *designator;
- switch (token.type) {
+ switch (token.kind) {
case '[':
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.source_position;
+ designator->source_position = token.base.source_position;
next_token();
add_anchor_token(']');
designator->array_index = parse_constant_expression();
break;
case '.':
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.source_position;
+ designator->source_position = token.base.source_position;
next_token();
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing designator",
T_IDENTIFIER, NULL);
return NULL;
}
- designator->symbol = token.symbol;
+ designator->symbol = token.identifier.symbol;
next_token();
break;
default:
}
/**
- * Checks if a given expression can be used as an constant initializer.
+ * Checks if a given expression can be used as a constant initializer.
*/
static bool is_initializer_constant(const expression_t *expression)
{
- return
- is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
- is_address_constant(expression) != EXPR_CLASS_VARIABLE;
+ return is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+ is_linker_constant(expression) != EXPR_CLASS_VARIABLE;
}
/**
{
/* there might be extra {} hierarchies */
int braces = 0;
- if (next_if('{')) {
- if (warning.other)
- warningf(HERE, "extra curly braces around scalar initializer");
+ if (token.kind == '{') {
+ warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer");
do {
+ eat('{');
++braces;
- } while (next_if('{'));
+ } while (token.kind == '{');
}
expression_t *expression = parse_assignment_expression();
bool additional_warning_displayed = false;
while (braces > 0) {
next_if(',');
- if (token.type != '}') {
- if (!additional_warning_displayed && warning.other) {
- warningf(HERE, "additional elements in scalar initializer");
+ if (token.kind != '}') {
+ if (!additional_warning_displayed) {
+ warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
additional_warning_displayed = true;
}
}
return false;
}
assert(iter->kind == ENTITY_COMPOUND_MEMBER);
- if (used_in_offsetof) {
- type_t *real_type = skip_typeref(iter->declaration.type);
- if (real_type->kind == TYPE_BITFIELD) {
- errorf(&designator->source_position,
- "offsetof designator '%Y' must not specify bitfield",
- symbol);
- return false;
- }
+ if (used_in_offsetof && iter->compound_member.bitfield) {
+ errorf(&designator->source_position,
+ "offsetof designator '%Y' must not specify bitfield",
+ symbol);
+ return false;
}
top->type = orig_type;
{
next_if('{');
- while (token.type != '}') {
- if (token.type == T_EOF)
+ while (token.kind != '}') {
+ if (token.kind == T_EOF)
return;
- if (token.type == '{') {
+ if (token.kind == '{') {
eat_block();
continue;
}
type_t *outer_type, size_t top_path_level,
parse_initializer_env_t *env)
{
- if (token.type == '}') {
+ if (token.kind == '}') {
/* empty initializer */
return create_empty_initializer();
}
while (true) {
designator_t *designator = NULL;
- if (token.type == '.' || token.type == '[') {
+ if (token.kind == '.' || token.kind == '[') {
designator = parse_designation();
goto finish_designator;
- } else if (token.type == T_IDENTIFIER && look_ahead(1)->type == ':') {
+ } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') {
/* GNU-style designator ("identifier: value") */
designator = allocate_ast_zero(sizeof(designator[0]));
- designator->source_position = token.source_position;
- designator->symbol = token.symbol;
+ designator->source_position = token.base.source_position;
+ designator->symbol = token.identifier.symbol;
eat(T_IDENTIFIER);
eat(':');
initializer_t *sub;
- if (token.type == '{') {
+ if (token.kind == '{') {
if (type != NULL && is_type_scalar(type)) {
sub = parse_scalar_initializer(type, env->must_be_constant);
} else {
- eat('{');
if (type == NULL) {
if (env->entity != NULL) {
errorf(HERE,
} else {
errorf(HERE, "extra brace group at end of initializer");
}
- } else
+ eat('{');
+ } else {
+ eat('{');
descend_into_subtype(path);
+ }
add_anchor_token('}');
sub = parse_sub_initializer(path, orig_type, top_path_level+1,
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_skip->compound.compound->complete) {
goto error_parse_next;
}
- goto error_excess;
+
+ source_position_t const* const pos = &expression->base.source_position;
+ if (env->entity != NULL) {
+ warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol);
+ } else {
+ warningf(WARN_OTHER, pos, "excess elements in initializer");
+ }
+ goto error_parse_next;
}
/* handle { "string" } special case */
sub = initializer_from_expression(outer_type, expression);
if (sub != NULL) {
next_if(',');
- if (token.type != '}' && warning.other) {
- warningf(HERE, "excessive elements in initializer for type '%T'",
- orig_type);
+ if (token.kind != '}') {
+ warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type);
}
/* TODO: eat , ... */
return sub;
path->max_index = index;
}
- if (type != NULL) {
- /* append to initializers list */
- ARR_APP1(initializer_t*, initializers, sub);
- } else {
-error_excess:
- if (warning.other) {
- if (env->entity != NULL) {
- warningf(HERE, "excess elements in initializer for '%Y'",
- env->entity->base.symbol);
- } else {
- warningf(HERE, "excess elements in initializer");
- }
- }
- }
+ /* append to initializers list */
+ ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (token.type == '}') {
+ if (token.kind == '}') {
break;
}
expect(',', end_error);
- if (token.type == '}') {
+ if (token.kind == '}') {
break;
}
if (is_type_scalar(type)) {
result = parse_scalar_initializer(type, env->must_be_constant);
- } else if (token.type == '{') {
+ } else if (token.kind == '{') {
eat('{');
type_path_t path;
DEL_ARR_F(path.path);
expect('}', end_error);
+end_error:;
} else {
/* parse_scalar_initializer() also works in this case: we simply
* have an expression without {} around it */
}
return result;
-end_error:
- return NULL;
}
static void append_entity(scope_t *scope, entity_t *entity)
static compound_t *parse_compound_type_specifier(bool is_struct)
{
+ source_position_t const pos = *HERE;
eat(is_struct ? T_struct : T_union);
symbol_t *symbol = NULL;
entity_t *entity = NULL;
attribute_t *attributes = NULL;
- if (token.type == T___attribute__) {
+ if (token.kind == T___attribute__) {
attributes = parse_attributes(NULL);
}
entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION;
- if (token.type == T_IDENTIFIER) {
+ if (token.kind == T_IDENTIFIER) {
/* the compound has a name, check if we have seen it already */
- symbol = token.symbol;
+ symbol = token.identifier.symbol;
+ entity = get_tag(symbol, kind);
next_token();
- entity = get_tag(symbol, kind);
if (entity != NULL) {
if (entity->base.parent_scope != current_scope &&
- (token.type == '{' || token.type == ';')) {
+ (token.kind == '{' || token.kind == ';')) {
/* we're in an inner scope and have a definition. Shadow
* existing definition in outer scope */
entity = NULL;
- } else if (entity->compound.complete && token.type == '{') {
- assert(symbol != NULL);
- errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)",
- is_struct ? "struct" : "union", symbol,
- &entity->base.source_position);
+ } else if (entity->compound.complete && token.kind == '{') {
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
/* clear members in the hope to avoid further errors */
entity->compound.members.entities = NULL;
}
}
- } else if (token.type != '{') {
- if (is_struct) {
- parse_error_expected("while parsing struct type specifier",
- T_IDENTIFIER, '{', NULL);
- } else {
- parse_error_expected("while parsing union type specifier",
- T_IDENTIFIER, '{', NULL);
- }
+ } else if (token.kind != '{') {
+ char const *const msg =
+ is_struct ? "while parsing struct type specifier" :
+ "while parsing union type specifier";
+ parse_error_expected(msg, T_IDENTIFIER, '{', NULL);
return NULL;
}
if (entity == NULL) {
- entity = allocate_entity_zero(kind);
-
+ entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol);
entity->compound.alignment = 1;
- entity->base.namespc = NAMESPACE_TAG;
- entity->base.source_position = token.source_position;
- entity->base.symbol = symbol;
+ entity->base.source_position = pos;
entity->base.parent_scope = current_scope;
if (symbol != NULL) {
environment_push(entity);
append_entity(current_scope, entity);
}
- if (token.type == '{') {
+ if (token.kind == '{') {
parse_compound_type_entries(&entity->compound);
/* ISO/IEC 14882:1998(E) §7.1.3:5 */
{
eat('{');
- if (token.type == '}') {
+ if (token.kind == '}') {
errorf(HERE, "empty enum not allowed");
next_token();
return;
add_anchor_token('}');
do {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL);
eat_block();
rem_anchor_token('}');
return;
}
- entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE);
+ symbol_t *symbol = token.identifier.symbol;
+ entity_t *const entity
+ = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol);
entity->enum_value.enum_type = enum_type;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = token.symbol;
- entity->base.source_position = token.source_position;
+ entity->base.source_position = token.base.source_position;
next_token();
if (next_if('=')) {
}
record_entity(entity, false);
- } while (next_if(',') && token.type != '}');
+ } while (next_if(',') && token.kind != '}');
rem_anchor_token('}');
expect('}', end_error);
static type_t *parse_enum_specifier(void)
{
- entity_t *entity;
- symbol_t *symbol;
+ source_position_t const pos = *HERE;
+ entity_t *entity;
+ symbol_t *symbol;
eat(T_enum);
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
- symbol = token.symbol;
+ symbol = token.identifier.symbol;
+ entity = get_tag(symbol, ENTITY_ENUM);
next_token();
- entity = get_tag(symbol, ENTITY_ENUM);
if (entity != NULL) {
if (entity->base.parent_scope != current_scope &&
- (token.type == '{' || token.type == ';')) {
+ (token.kind == '{' || token.kind == ';')) {
/* we're in an inner scope and have a definition. Shadow
* existing definition in outer scope */
entity = NULL;
- } else if (entity->enume.complete && token.type == '{') {
- errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
- symbol, &entity->base.source_position);
+ } else if (entity->enume.complete && token.kind == '{') {
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
}
}
break;
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_ENUM);
- entity->base.namespc = NAMESPACE_TAG;
- entity->base.source_position = token.source_position;
- entity->base.symbol = symbol;
+ entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol);
+ entity->base.source_position = pos;
entity->base.parent_scope = current_scope;
}
type->enumt.enume = &entity->enume;
type->enumt.akind = ATOMIC_TYPE_INT;
- if (token.type == '{') {
+ if (token.kind == '{') {
if (symbol != NULL) {
environment_push(entity);
}
anonymous_entity = entity;
}
} else if (!entity->enume.complete && !(c_mode & _GNUC)) {
- errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)",
- symbol);
+ errorf(HERE, "'%T' used before definition (incomplete enums are a GNU extension)", type);
}
return type;
expression_t *expression = NULL;
- bool old_type_prop = in_type_prop;
- bool old_gcc_extension = in_gcc_extension;
- in_type_prop = true;
-
- while (next_if(T___extension__)) {
- /* This can be a prefix to a typename or an expression. */
- in_gcc_extension = true;
- }
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(token.symbol)) {
- TYPENAME_START
+ if (is_typedef_symbol(token.identifier.symbol)) {
+ DECLARATION_START
type = parse_typename();
} else {
default:
}
break;
}
- in_type_prop = old_type_prop;
- in_gcc_extension = old_gcc_extension;
rem_anchor_token(')');
expect(')', end_error);
= allocate_ast_zero(sizeof(*property));
do {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing property declspec",
T_IDENTIFIER, NULL);
goto end_error;
}
- bool is_put;
- symbol_t *symbol = token.symbol;
- next_token();
+ symbol_t **prop;
+ symbol_t *symbol = token.identifier.symbol;
if (strcmp(symbol->string, "put") == 0) {
- is_put = true;
+ prop = &property->put_symbol;
} else if (strcmp(symbol->string, "get") == 0) {
- is_put = false;
+ prop = &property->get_symbol;
} else {
errorf(HERE, "expected put or get in property declspec");
- goto end_error;
+ prop = NULL;
}
+ eat(T_IDENTIFIER);
expect('=', end_error);
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != 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;
- }
+ if (prop != NULL)
+ *prop = token.identifier.symbol;
next_token();
} while (next_if(','));
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();
+ } else if (token.kind == T_IDENTIFIER) {
+ const char *name = token.identifier.symbol->string;
for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
++k) {
const char *attribute_name = get_attribute_name(k);
}
}
- if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) {
- warningf(HERE, "unknown __declspec '%s' ignored", name);
+ if (kind == ATTRIBUTE_UNKNOWN) {
+ warningf(WARN_ATTRIBUTE, HERE, "unknown __declspec '%s' ignored", name);
}
} else {
parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL);
}
attribute_t *attribute = allocate_attribute_zero(kind);
+ eat(T_IDENTIFIER);
if (kind == ATTRIBUTE_MS_PROPERTY) {
return parse_attribute_ms_property(attribute);
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
- entity_t *entity = allocate_entity_zero(kind);
- entity->base.namespc = NAMESPACE_NORMAL;
+ entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol);
entity->base.source_position = *HERE;
- entity->base.symbol = symbol;
if (is_declaration(entity)) {
entity->declaration.type = type_error_type;
entity->declaration.implicit = true;
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
- type_t *type = NULL;
- type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
- unsigned type_specifiers = 0;
- bool newtype = false;
- bool saw_error = false;
- bool old_gcc_extension = in_gcc_extension;
+ type_t *type = NULL;
+ type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
+ unsigned type_specifiers = 0;
+ bool newtype = false;
+ bool saw_error = false;
- specifiers->source_position = token.source_position;
+ memset(specifiers, 0, sizeof(*specifiers));
+ specifiers->source_position = token.base.source_position;
while (true) {
specifiers->attributes = parse_attributes(specifiers->attributes);
- switch (token.type) {
+ switch (token.kind) {
/* storage class */
#define MATCH_STORAGE_CLASS(token, class) \
case token: \
MATCH_TYPE_QUALIFIER(T___uptr, TYPE_QUALIFIER_UPTR);
MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR);
- case T___extension__:
- next_token();
- in_gcc_extension = true;
- break;
-
/* type specifiers */
#define MATCH_SPECIFIER(token, specifier, name) \
case token: \
next_token();
break;
-#define CHECK_DOUBLE_TYPE() \
- if ( type != NULL) \
- errorf(HERE, "multiple data types in declaration specifiers");
+#define CHECK_DOUBLE_TYPE() \
+ (type != NULL ? errorf(HERE, "multiple types in declaration specifiers") : (void)0)
case T_struct:
CHECK_DOUBLE_TYPE();
/* Be somewhat resilient to typos like 'unsigned lng* f()' in a
* declaration, so it doesn't generate errors about expecting '(' or
* '{' later on. */
- switch (look_ahead(1)->type) {
+ switch (look_ahead(1)->kind) {
STORAGE_CLASSES
TYPE_SPECIFIERS
case T_const:
}
}
- type_t *const typedef_type = get_typedef_type(token.symbol);
+ type_t *const typedef_type = get_typedef_type(token.identifier.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
* errors later on. */
- token_type_t const la1_type = (token_type_t)look_ahead(1)->type;
+ token_kind_t const la1_type = (token_kind_t)look_ahead(1)->kind;
switch (la1_type) {
DECLARATION_START
case T_IDENTIFIER:
case '*': {
errorf(HERE, "%K does not name a type", &token);
- entity_t *entity =
- create_error_entity(token.symbol, ENTITY_TYPEDEF);
+ symbol_t *symbol = token.identifier.symbol;
+ entity_t *entity
+ = create_error_entity(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)) {
atomic_type_kind_t atomic_type;
| SPECIFIER_INT:
atomic_type = ATOMIC_TYPE_ULONGLONG;
warn_about_long_long:
- if (warning.long_long) {
- warningf(&specifiers->source_position,
- "ISO C90 does not support 'long long'");
- }
+ warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'");
break;
case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
break;
- default:
+ default: {
/* invalid specifier combination, give an error message */
+ source_position_t const* const pos = &specifiers->source_position;
if (type_specifiers == 0) {
- if (saw_error)
- goto end_error;
-
- /* ISO/IEC 14882:1998(E) §C.1.5:4 */
- if (!(c_mode & _CXX) && !strict_mode) {
- if (warning.implicit_int) {
- warningf(HERE, "no type specifiers in declaration, using 'int'");
+ if (!saw_error) {
+ /* ISO/IEC 14882:1998(E) §C.1.5:4 */
+ if (!(c_mode & _CXX) && !strict_mode) {
+ warningf(WARN_IMPLICIT_INT, pos, "no type specifiers in declaration, using 'int'");
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+ } else {
+ errorf(pos, "no type specifiers given in declaration");
}
- atomic_type = ATOMIC_TYPE_INT;
- break;
- } else {
- errorf(HERE, "no type specifiers given in declaration");
}
} else if ((type_specifiers & SPECIFIER_SIGNED) &&
(type_specifiers & SPECIFIER_UNSIGNED)) {
- errorf(HERE, "signed and unsigned specifiers given");
+ errorf(pos, "signed and unsigned specifiers given");
} else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
- errorf(HERE, "only integer types can be signed or unsigned");
+ errorf(pos, "only integer types can be signed or unsigned");
} else {
- errorf(HERE, "multiple datatypes in declaration");
+ errorf(pos, "multiple datatypes in declaration");
}
goto end_error;
}
+ }
if (type_specifiers & SPECIFIER_COMPLEX) {
type = allocate_type_zero(TYPE_COMPLEX);
}
newtype = true;
} else if (type_specifiers != 0) {
- errorf(HERE, "multiple datatypes in declaration");
+ errorf(&specifiers->source_position, "multiple datatypes in declaration");
}
/* FIXME: check type qualifiers here */
type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
while (true) {
- switch (token.type) {
+ switch (token.kind) {
/* type qualifiers */
MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
*/
static void parse_identifier_list(scope_t *scope)
{
+ assert(token.kind == T_IDENTIFIER);
do {
- entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER);
- entity->base.source_position = token.source_position;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = token.symbol;
+ entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol);
+ entity->base.source_position = token.base.source_position;
/* a K&R parameter has no type, yet */
next_token();
if (scope != NULL)
append_entity(scope, entity);
- } while (next_if(',') && token.type == T_IDENTIFIER);
+ } while (next_if(',') && token.kind == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
{
declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
parse_declaration_specifiers(&specifiers);
entity_t *entity = parse_declarator(&specifiers,
* 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);
+ errorf(&entity->base.source_position, "'%N' has incomplete type", entity);
}
}
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 (token.kind == T_IDENTIFIER) {
+ entity_t const *const entity
+ = get_entity(token.identifier.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) {
+ } else if (token.kind != T_void) {
return true;
}
- if (look_ahead(1)->type != ')')
+ if (look_ahead(1)->kind != ')')
return true;
next_token();
return false;
add_anchor_token(')');
int saved_comma_state = save_and_reset_anchor_state(',');
- if (token.type == T_IDENTIFIER &&
- !is_typedef_symbol(token.symbol)) {
- token_type_t la1_type = (token_type_t)look_ahead(1)->type;
+ if (token.kind == T_IDENTIFIER
+ && !is_typedef_symbol(token.identifier.symbol)) {
+ token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
if (la1_type == ',' || la1_type == ')') {
type->kr_style_parameters = true;
parse_identifier_list(scope);
}
}
- if (token.type == ')') {
+ if (token.kind == ')') {
/* ISO/IEC 14882:1998(E) §C.1.6:1 */
if (!(c_mode & _CXX))
type->unspecified_parameters = true;
} else if (has_parameters()) {
function_parameter_t **anchor = &type->parameters;
do {
- switch (token.type) {
+ switch (token.kind) {
case T_DOTDOTDOT:
next_token();
type->variadic = true;
goto parameters_finished;
case T_IDENTIFIER:
- case T___extension__:
DECLARATION_START
{
entity_t *entity = parse_parameter();
array->is_static = is_static;
expression_t *size = NULL;
- if (token.type == '*' && look_ahead(1)->type == ']') {
+ if (token.kind == '*' && look_ahead(1)->kind == ']') {
array->is_variable = true;
next_token();
- } else if (token.type != ']') {
+ } else if (token.kind != ']') {
size = parse_assignment_expression();
/* §6.7.5.2:1 Array size must have integer type */
}
if (is_static && size == NULL)
- errorf(HERE, "static array parameters require a size");
+ errorf(&array->base.pos, "static array parameters require a size");
rem_anchor_token(']');
expect(']', end_error);
for (;;) {
construct_type_t *type;
//variable_t *based = NULL; /* MS __based extension */
- switch (token.type) {
+ switch (token.kind) {
case '&':
type = parse_reference_declarator();
break;
ptr_operator_end: ;
construct_type_t *inner_types = NULL;
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER:
if (env->must_be_abstract) {
errorf(HERE, "no identifier expected in typename");
} else {
- env->symbol = token.symbol;
- env->source_position = token.source_position;
+ env->symbol = token.identifier.symbol;
+ env->source_position = token.base.source_position;
}
next_token();
break;
case '(': {
/* Parenthesized declarator or function declarator? */
token_t const *const la1 = look_ahead(1);
- switch (la1->type) {
+ switch (la1->kind) {
case T_IDENTIFIER:
- if (is_typedef_symbol(la1->symbol)) {
+ if (is_typedef_symbol(la1->identifier.symbol)) {
case ')':
/* §6.7.6:2 footnote 126: Empty parentheses in a type name are
* interpreted as ``function with no parameter specification'', rather
/* Function declarator. */
if (!env->may_be_abstract) {
errorf(HERE, "function declarator must have a name");
- goto error_out;
}
} else {
case '&':
if (env->may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
-error_out:
eat_until_anchor();
return NULL;
}
for (;;) {
construct_type_t *type;
- switch (token.type) {
+ switch (token.kind) {
case '(': {
scope_t *scope = NULL;
if (!env->must_be_abstract) {
} else if (is_type_array(skipped_return_type)) {
errorf(pos, "function returning array is not allowed");
} else {
- if (skipped_return_type->base.qualifiers != 0 && warning.other) {
- warningf(pos, "type qualifiers in return type of function type are meaningless");
+ if (skipped_return_type->base.qualifiers != 0) {
+ warningf(WARN_IGNORED_QUALIFIERS, pos, "type qualifiers in return type of function type are meaningless");
}
}
if (size_expression != NULL) {
switch (is_constant_expression(size_expression)) {
- case EXPR_CLASS_CONSTANT: {
- long const size = fold_constant_to_int(size_expression);
- array_type->array.size = size;
- array_type->array.size_constant = true;
- /* §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");
- }
- }
- break;
+ case EXPR_CLASS_CONSTANT: {
+ long const size = fold_constant_to_int(size_expression);
+ array_type->array.size = size;
+ array_type->array.size_constant = true;
+ /* §6.7.5.2:1 If the expression is a constant expression,
+ * it shall have a value greater than zero. */
+ if (size < 0) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (size == 0 && !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero (zero length arrays are a GCC extension)");
}
+ break;
+ }
- case EXPR_CLASS_VARIABLE:
- array_type->array.is_vla = true;
- break;
+ case EXPR_CLASS_VARIABLE:
+ array_type->array.is_vla = true;
+ break;
- case EXPR_CLASS_ERROR:
- break;
+ case EXPR_CLASS_ERROR:
+ break;
}
}
static type_t *semantic_parameter(const source_position_t *pos,
type_t *type,
const declaration_specifiers_t *specifiers,
- symbol_t *symbol)
+ entity_t const *const param)
{
/* §6.7.5.3:7 A declaration of a parameter as ``array of type''
* shall be adjusted to ``qualified pointer to type'',
type = automatic_type_conversion(type);
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(pos, "parameter '%#T' declared 'inline'", type, symbol);
+ errorf(pos, "'%N' declared 'inline'", param);
}
/* §6.9.1:6 The declarations in the declaration list shall contain
specifiers->storage_class != STORAGE_CLASS_NONE &&
specifiers->storage_class != STORAGE_CLASS_REGISTER)
) {
- errorf(pos, "invalid storage class for parameter '%#T'", type, symbol);
+ errorf(pos, "invalid storage class for '%N'", param);
}
/* delay test for incomplete type, because we might have (void)
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
- entity = allocate_entity_zero(ENTITY_TYPEDEF);
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = env.symbol;
+ entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol);
entity->base.source_position = env.source_position;
entity->typedefe.type = orig_type;
} 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, NAMESPACE_NORMAL, env.symbol);
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
}
}
} else if (flags & DECL_IS_PARAMETER) {
- orig_type = semantic_parameter(&env.source_position, orig_type,
- specifiers, env.symbol);
-
- entity = allocate_entity_zero(ENTITY_PARAMETER);
+ entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol);
+ orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
} else if (is_type_function(type)) {
- entity = allocate_entity_zero(ENTITY_FUNCTION);
-
- entity->function.is_inline = specifiers->is_inline;
- entity->function.parameters = env.parameters;
+ entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol);
+ entity->function.is_inline = specifiers->is_inline;
+ entity->function.elf_visibility = default_visibility;
+ entity->function.parameters = env.parameters;
if (env.symbol != NULL) {
/* this needs fixes for C++ */
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);
+ errorf(&env.source_position, "invalid storage class for '%N'", entity);
}
}
} else {
- entity = allocate_entity_zero(ENTITY_VARIABLE);
-
- entity->variable.thread_local = specifiers->thread_local;
+ entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol);
+ entity->variable.elf_visibility = default_visibility;
+ entity->variable.thread_local = specifiers->thread_local;
if (env.symbol != NULL) {
if (specifiers->is_inline && is_type_valid(type)) {
- errorf(&env.source_position,
- "variable '%Y' declared 'inline'", env.symbol);
+ errorf(&env.source_position, "'%N' declared 'inline'", entity);
}
bool invalid_storage_class = false;
}
}
if (invalid_storage_class) {
- errorf(&env.source_position,
- "invalid storage class for variable '%Y'", env.symbol);
+ errorf(&env.source_position, "invalid storage class for variable '%N'", entity);
}
}
}
- 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->base.source_position = env.symbol != NULL ? env.source_position : specifiers->source_position;
entity->declaration.type = orig_type;
entity->declaration.alignment = get_type_alignment(orig_type);
entity->declaration.modifiers = env.modifiers;
{
const source_position_t *pos = &entity->base.source_position;
if (entity->kind != ENTITY_FUNCTION) {
- warningf(pos, "'main' is not a function");
+ warningf(WARN_MAIN, pos, "'main' is not a function");
return;
}
if (entity->declaration.storage_class == STORAGE_CLASS_STATIC) {
- warningf(pos, "'main' is normally a non-static function");
+ warningf(WARN_MAIN, pos, "'main' is normally a non-static function");
}
type_t *type = skip_typeref(entity->declaration.type);
assert(is_type_function(type));
- function_type_t *func_type = &type->function;
- if (!types_compatible(skip_typeref(func_type->return_type), type_int)) {
- warningf(pos, "return type of 'main' should be 'int', but is '%T'",
- func_type->return_type);
+ function_type_t const *const func_type = &type->function;
+ type_t *const ret_type = func_type->return_type;
+ if (!types_compatible(skip_typeref(ret_type), type_int)) {
+ warningf(WARN_MAIN, pos, "return type of 'main' should be 'int', but is '%T'", ret_type);
}
const function_parameter_t *parm = func_type->parameters;
if (parm != NULL) {
type_t *const first_type = skip_typeref(parm->type);
type_t *const first_type_unqual = get_unqualified_type(first_type);
if (!types_compatible(first_type_unqual, type_int)) {
- warningf(pos,
- "first argument of 'main' should be 'int', but is '%T'",
- parm->type);
+ warningf(WARN_MAIN, pos, "first argument of 'main' should be 'int', but is '%T'", parm->type);
}
parm = parm->next;
if (parm != NULL) {
type_t *const second_type_unqual
= get_unqualified_type(second_type);
if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) {
- warningf(pos, "second argument of 'main' should be 'char**', but is '%T'",
- parm->type);
+ warningf(WARN_MAIN, pos, "second argument of 'main' should be 'char**', but is '%T'", parm->type);
}
parm = parm->next;
if (parm != NULL) {
type_t *const third_type_unqual
= get_unqualified_type(third_type);
if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) {
- warningf(pos, "third argument of 'main' should be 'char**', but is '%T'",
- parm->type);
+ warningf(WARN_MAIN, pos, "third argument of 'main' should be 'char**', but is '%T'", parm->type);
}
parm = parm->next;
if (parm != NULL)
}
} else {
warn_arg_count:
- warningf(pos, "'main' takes only zero, two or three arguments");
+ warningf(WARN_MAIN, pos, "'main' takes only zero, two or three arguments");
}
}
}
static void error_redefined_as_different_kind(const source_position_t *pos,
const entity_t *old, entity_kind_t new_kind)
{
- errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)",
- get_entity_kind_name(old->kind), old->base.symbol,
- get_entity_kind_name(new_kind), &old->base.source_position);
+ char const *const what = get_entity_kind_name(new_kind);
+ source_position_t const *const ppos = &old->base.source_position;
+ errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos);
}
static bool is_entity_valid(entity_t *const ent)
assert(is_type_function(type));
if (type->function.unspecified_parameters &&
- warning.strict_prototypes &&
- previous_entity == NULL) {
- warningf(pos, "function declaration '%#T' is not a prototype",
- orig_type, symbol);
+ previous_entity == NULL &&
+ !entity->declaration.implicit) {
+ warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity);
}
- if (warning.main && current_scope == file_scope
- && is_sym_main(symbol)) {
+ if (current_scope == file_scope && is_sym_main(symbol)) {
check_main(entity);
}
}
- 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 (is_declaration(entity) &&
+ entity->declaration.storage_class == STORAGE_CLASS_EXTERN &&
+ current_scope != file_scope &&
+ !entity->declaration.implicit) {
+ warningf(WARN_NESTED_EXTERNS, pos, "nested extern declaration of '%#N'", entity);
}
if (previous_entity != NULL) {
+ source_position_t const *const ppos = &previous_entity->base.source_position;
+
if (previous_entity->base.parent_scope == ¤t_function->parameters &&
previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
assert(previous_entity->kind == ENTITY_PARAMETER);
- errorf(pos,
- "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
- entity->declaration.type, symbol,
- previous_entity->declaration.type, symbol,
- &previous_entity->base.source_position);
+ errorf(pos, "declaration of '%N' redeclares the '%N' (declared %P)", entity, previous_entity, ppos);
goto finish;
}
goto finish;
}
if (previous_entity->kind == ENTITY_ENUM_VALUE) {
- errorf(pos, "redeclaration of enum entry '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos);
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);
+ errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
goto finish;
}
return previous_entity;
}
- type_t *const orig_type = decl->type;
- assert(orig_type != NULL);
- type_t *const type = skip_typeref(orig_type);
+ type_t *const type = skip_typeref(decl->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);
+ errorf(pos, "declaration '%#N' is incompatible with '%#N' (declared %P)", entity, previous_entity, ppos);
} else {
unsigned old_storage_class = prev_decl->storage_class;
- if (warning.redundant_decls &&
- is_definition &&
+ if (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);
+ warningf(WARN_REDUNDANT_DECLS, ppos, "unnecessary static forward declaration for '%#N'", previous_entity);
}
storage_class_t new_storage_class = decl->storage_class;
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);
+ if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) {
+ warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
}
} else if (new_storage_class == STORAGE_CLASS_NONE) {
new_storage_class = STORAGE_CLASS_EXTERN;
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);
+ strcmp(ppos->input_name, "<builtin>") != 0) {
+ warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
}
} 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);
+ errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos);
} else if (old_storage_class == STORAGE_CLASS_EXTERN) {
prev_decl->storage_class = STORAGE_CLASS_NONE;
prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
} 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);
+ errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos);
} else {
- errorf(pos,
- "redeclaration of '%Y' with different linkage (declared %P)",
- symbol, &previous_entity->base.source_position);
+ errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos);
}
}
}
return previous_entity;
}
- 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);
+ warning_t why;
+ if (is_warn_on(why = WARN_SHADOW) ||
+ (is_warn_on(why = WARN_SHADOW_LOCAL) && previous_entity->base.parent_scope != file_scope)) {
+ char const *const what = get_entity_kind_name(previous_entity->kind);
+ warningf(why, pos, "'%N' shadows %s (declared %P)", entity, what, ppos);
}
}
if (entity->kind == ENTITY_FUNCTION) {
if (is_definition &&
- entity->declaration.storage_class != STORAGE_CLASS_STATIC) {
- if (warning.missing_prototypes && !is_sym_main(symbol)) {
- warningf(pos, "no previous prototype for '%#T'",
- entity->declaration.type, symbol);
- } else if (warning.missing_declarations && !is_sym_main(symbol)) {
- warningf(pos, "no previous declaration for '%#T'",
- entity->declaration.type, symbol);
+ entity->declaration.storage_class != STORAGE_CLASS_STATIC &&
+ !is_sym_main(symbol)) {
+ if (is_warn_on(WARN_MISSING_PROTOTYPES)) {
+ warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity);
+ } else {
+ goto warn_missing_declaration;
}
}
- } 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'",
- declaration->type, symbol);
+ } else if (entity->kind == ENTITY_VARIABLE) {
+ if (current_scope == file_scope &&
+ entity->declaration.storage_class == STORAGE_CLASS_NONE &&
+ !entity->declaration.implicit) {
+warn_missing_declaration:
+ warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity);
}
}
assert(current_scope != NULL);
entity->base.parent_scope = current_scope;
- entity->base.namespc = NAMESPACE_NORMAL;
environment_push(entity);
append_entity(current_scope, entity);
entity->base.symbol, &entity->base.source_position);
}
-static bool is_declaration_specifier(const token_t *token,
- bool only_specifiers_qualifiers)
+static bool is_declaration_specifier(const token_t *token)
{
- switch (token->type) {
- TYPE_SPECIFIERS
- TYPE_QUALIFIERS
+ switch (token->kind) {
+ DECLARATION_START
return true;
case T_IDENTIFIER:
- return is_typedef_symbol(token->symbol);
-
- case T___extension__:
- STORAGE_CLASSES
- return !only_specifiers_qualifiers;
+ return is_typedef_symbol(token->identifier.symbol);
default:
return false;
type_t *orig_type = type_error_type;
if (entity->base.kind == ENTITY_TYPEDEF) {
- errorf(&entity->base.source_position,
- "typedef '%Y' is initialized (use __typeof__ instead)",
- entity->base.symbol);
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity);
} else {
assert(is_declaration(entity));
orig_type = entity->declaration.type;
}
- eat('=');
type_t *type = skip_typeref(orig_type);
&& entity->variable.initializer != NULL) {
parser_error_multiple_definition(entity, HERE);
}
+ eat('=');
declaration_t *const declaration = &entity->declaration;
bool must_be_constant = false;
}
if (is_type_function(type)) {
- errorf(&entity->base.source_position,
- "function '%#T' is initialized like a variable",
- orig_type, entity->base.symbol);
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "'%N' is initialized like a variable", entity);
orig_type = type_error_type;
}
env.type = orig_type;
env.must_be_constant = must_be_constant;
env.entity = entity;
- current_init_decl = entity;
initializer_t *initializer = parse_initializer(&env);
- current_init_decl = NULL;
if (entity->kind == ENTITY_VARIABLE) {
/* §6.7.5:22 array initializers for arrays with unknown size
eat(';');
anonymous_entity = NULL;
- if (warning.other) {
- if (specifiers->storage_class != STORAGE_CLASS_NONE ||
- specifiers->thread_local) {
- warningf(&specifiers->source_position,
- "useless storage class in empty declaration");
- }
+ source_position_t const *const pos = &specifiers->source_position;
+ if (specifiers->storage_class != STORAGE_CLASS_NONE ||
+ specifiers->thread_local) {
+ warningf(WARN_OTHER, pos, "useless storage class in empty declaration");
+ }
- type_t *type = specifiers->type;
- switch (type->kind) {
- case TYPE_COMPOUND_STRUCT:
- case TYPE_COMPOUND_UNION: {
- if (type->compound.compound->base.symbol == NULL) {
- warningf(&specifiers->source_position,
- "unnamed struct/union that defines no instances");
- }
- break;
+ type_t *type = specifiers->type;
+ switch (type->kind) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ if (type->compound.compound->base.symbol == NULL) {
+ warningf(WARN_OTHER, pos, "unnamed struct/union that defines no instances");
}
+ break;
+ }
- case TYPE_ENUM:
- break;
+ case TYPE_ENUM:
+ break;
- default:
- warningf(&specifiers->source_position, "empty declaration");
- break;
- }
+ default:
+ warningf(WARN_OTHER, pos, "empty declaration");
+ break;
}
}
decl->storage_class == STORAGE_CLASS_STATIC)
return;
- type_t *const orig_type = decl->type;
- type_t *const type = skip_typeref(orig_type);
+ type_t *const type = skip_typeref(decl->type);
if (!is_type_incomplete(type))
return;
return;
}
- errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
- orig_type, ent->base.symbol);
+ errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent);
}
add_anchor_token(';');
add_anchor_token(',');
while (true) {
- entity_t *entity = finished_declaration(ndeclaration, token.type == '=');
+ entity_t *entity = finished_declaration(ndeclaration, token.kind == '=');
- if (token.type == '=') {
+ if (token.kind == '=') {
parse_init_declarator_rest(entity);
} else if (entity->kind == ENTITY_VARIABLE) {
/* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted
if (decl->storage_class != STORAGE_CLASS_EXTERN) {
type_t *type = decl->type;
if (is_type_reference(skip_typeref(type))) {
- errorf(&entity->base.source_position,
- "reference '%#T' must be initialized",
- type, entity->base.symbol);
+ source_position_t const *const pos = &entity->base.source_position;
+ errorf(pos, "reference '%#N' must be initialized", entity);
}
}
}
static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
{
symbol_t *symbol = entity->base.symbol;
- if (symbol == NULL) {
- errorf(HERE, "anonymous declaration not valid as function parameter");
+ if (symbol == NULL)
return entity;
- }
assert(entity->base.namespc == NAMESPACE_NORMAL);
entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
if (previous_entity == NULL
|| previous_entity->base.parent_scope != current_scope) {
- errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+ errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
symbol);
return entity;
}
if (is_definition) {
- errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol);
+ errorf(HERE, "'%N' is initialised", entity);
}
return record_entity(entity, false);
static void parse_declaration(parsed_declaration_func finished_declaration,
declarator_flags_t flags)
{
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
add_anchor_token(';');
+ declaration_specifiers_t specifiers;
parse_declaration_specifiers(&specifiers);
rem_anchor_token(';');
- if (token.type == ';') {
+ if (token.kind == ';') {
parse_anonymous_declaration_rest(&specifiers);
} else {
entity_t *entity = parse_declarator(&specifiers, flags);
add_anchor_token('{');
- /* push function parameters */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&entity->function.parameters);
+ PUSH_SCOPE(&entity->function.parameters);
entity_t *parameter = entity->function.parameters.entities;
for ( ; parameter != NULL; parameter = parameter->base.next) {
/* parse declaration list */
for (;;) {
- switch (token.type) {
+ switch (token.kind) {
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. */
}
decl_list_end:
- /* pop function parameters */
- assert(current_scope == &entity->function.parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* update function type */
type_t *new_type = duplicate_type(type);
type_t *parameter_type = parameter->declaration.type;
if (parameter_type == NULL) {
+ source_position_t const* const pos = ¶meter->base.source_position;
if (strict_mode) {
- errorf(HERE, "no type specified for function parameter '%Y'",
- parameter->base.symbol);
+ errorf(pos, "no type specified for function '%N'", parameter);
parameter_type = type_error_type;
} else {
- if (warning.implicit_int) {
- warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
- parameter->base.symbol);
- }
+ warningf(WARN_IMPLICIT_INT, pos, "no type specified for function parameter '%N', using 'int'", parameter);
parameter_type = type_int;
}
parameter->declaration.type = parameter_type;
parameter_type = not_promoted;
}
}
- function_parameter_t *const parameter
+ function_parameter_t *const function_parameter
= allocate_parameter(parameter_type);
- *anchor = parameter;
- anchor = ¶meter->next;
+ *anchor = function_parameter;
+ anchor = &function_parameter->next;
}
new_type->function.parameters = parameters;
new_type = identify_new_type(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);
+ if (need_incompatible_warning) {
+ symbol_t const *const sym = entity->base.symbol;
+ source_position_t const *const pos = &entity->base.source_position;
+ source_position_t const *const ppos = &proto_type->base.source_position;
+ warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos);
}
-
entity->declaration.type = new_type;
rem_anchor_token('{');
{
if (first_err) {
first_err = false;
- diagnosticf("%s: In function '%Y':\n",
- current_function->base.base.source_position.input_name,
- current_function->base.base.symbol);
+ char const *const file = current_function->base.base.source_position.input_name;
+ diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function);
}
}
continue;
label_t *label = goto_statement->label;
-
- label->used = true;
if (label->base.source_position.input_name == NULL) {
print_in_function();
- errorf(&goto_statement->base.source_position,
- "label '%Y' used but not defined", label->base.symbol);
+ source_position_t const *const pos = &goto_statement->base.source_position;
+ errorf(pos, "'%N' used but not defined", (entity_t const*)label);
}
}
- if (warning.unused_label) {
+ if (is_warn_on(WARN_UNUSED_LABEL)) {
for (const label_statement_t *label_statement = label_first;
label_statement != NULL;
label_statement = label_statement->next) {
if (! label->used) {
print_in_function();
- warningf(&label_statement->base.source_position,
- "label '%Y' defined but not used", label->base.symbol);
+ source_position_t const *const pos = &label_statement->base.source_position;
+ warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label);
}
}
}
}
-static void warn_unused_entity(entity_t *entity, entity_t *last)
+static void warn_unused_entity(warning_t const why, entity_t *entity, entity_t *const last)
{
entity_t const *const end = last != NULL ? last->base.next : NULL;
for (; entity != end; entity = entity->base.next) {
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);
+ warningf(why, &entity->base.source_position, "'%N' is unused", entity);
} 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);
+ warningf(why, &entity->base.source_position, "'%N' is never read", entity);
}
}
}
switch (stmt->kind) {
case STATEMENT_DECLARATION: {
declaration_statement_t const *const decls = &stmt->declaration;
- warn_unused_entity(decls->declarations_begin,
- decls->declarations_end);
+ warn_unused_entity(WARN_UNUSED_VARIABLE, decls->declarations_begin, decls->declarations_end);
return;
}
case STATEMENT_FOR:
- warn_unused_entity(stmt->fors.scope.entities, NULL);
+ warn_unused_entity(WARN_UNUSED_VARIABLE, stmt->fors.scope.entities, NULL);
return;
default:
*/
static void check_declarations(void)
{
- if (warning.unused_parameter) {
+ if (is_warn_on(WARN_UNUSED_PARAMETER)) {
const scope_t *scope = ¤t_function->parameters;
/* do not issue unused warnings for main */
if (!is_sym_main(current_function->base.base.symbol)) {
- warn_unused_entity(scope->entities, NULL);
+ warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
}
}
- if (warning.unused_variable) {
+ if (is_warn_on(WARN_UNUSED_VARIABLE)) {
walk_statements(current_function->statement, check_unused_variables,
NULL);
}
return
expression_returns(expr->binary.left) &&
expression_returns(expr->binary.right);
-
- case EXPR_UNKNOWN:
- break;
}
panic("unhandled expression");
case STATEMENT_DECLARATION: {
declaration_statement_t const *const decl = &stmt->declaration;
entity_t const * ent = decl->declarations_begin;
- entity_t const *const last = decl->declarations_end;
+ entity_t const *const last_decl = decl->declarations_end;
if (ent != NULL) {
for (;; ent = ent->base.next) {
if (ent->kind == ENTITY_VARIABLE &&
- ent->variable.initializer != NULL &&
- !initializer_returns(ent->variable.initializer)) {
+ ent->variable.initializer != NULL &&
+ !initializer_returns(ent->variable.initializer)) {
return;
}
- if (ent == last)
+ if (ent == last_decl)
break;
}
}
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 &&
- !is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
+ if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
is_type_valid(ret) &&
!is_sym_main(current_function->base.base.symbol)) {
- warningf(&stmt->base.source_position,
- "control reaches end of non-void function");
+ source_position_t const *const pos = &stmt->base.source_position;
+ warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
}
return;
}
if (!stmt->base.reachable) {
expression_t const *const cond = stmt->do_while.condition;
if (determine_truth(cond) >= 0) {
- warningf(&cond->base.source_position,
- "condition of do-while-loop is unreachable");
+ source_position_t const *const pos = &cond->base.source_position;
+ warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable");
}
}
return;
// if init and step are unreachable, cond is unreachable, too
if (!stmt->base.reachable && !fors->step_reachable) {
- warningf(&stmt->base.source_position, "statement is unreachable");
+ goto warn_unreachable;
} else {
if (!stmt->base.reachable && fors->initialisation != NULL) {
- warningf(&fors->initialisation->base.source_position,
- "initialisation of for-statement is unreachable");
+ source_position_t const *const pos = &fors->initialisation->base.source_position;
+ warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable");
}
if (!fors->condition_reachable && fors->condition != NULL) {
- warningf(&fors->condition->base.source_position,
- "condition of for-statement is unreachable");
+ source_position_t const *const pos = &fors->condition->base.source_position;
+ warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable");
}
if (!fors->step_reachable && fors->step != NULL) {
- warningf(&fors->step->base.source_position,
- "step of for-statement is unreachable");
+ source_position_t const *const pos = &fors->step->base.source_position;
+ warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable");
}
}
return;
default:
warn_unreachable:
- if (!stmt->base.reachable)
- warningf(&stmt->base.source_position, "statement is unreachable");
+ if (!stmt->base.reachable) {
+ source_position_t const *const pos = &stmt->base.source_position;
+ warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable");
+ }
return;
}
}
{
/* function-definitions and declarations both start with declaration
* specifiers */
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
-
add_anchor_token(';');
+ declaration_specifiers_t specifiers;
parse_declaration_specifiers(&specifiers);
rem_anchor_token(';');
/* must be a declaration */
- if (token.type == ';') {
+ if (token.kind == ';') {
parse_anonymous_declaration_rest(&specifiers);
return;
}
rem_anchor_token(',');
/* must be a declaration */
- switch (token.type) {
+ switch (token.kind) {
case ',':
case ';':
case '=':
/* must be a function definition */
parse_kr_declaration_list(ndeclaration);
- if (token.type != '{') {
+ if (token.kind != '{') {
parse_error_expected("while parsing function definition", '{', NULL);
eat_until_matching_token(';');
return;
if (!is_type_function(type)) {
if (is_type_valid(type)) {
- errorf(HERE, "declarator '%#T' has a body but is not a function type",
- type, ndeclaration->base.symbol);
+ errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
}
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 &&
- is_type_compound(skip_typeref(type->function.return_type))) {
- warningf(HERE, "function '%Y' returns an aggregate",
- ndeclaration->base.symbol);
+ source_position_t const *const pos = &ndeclaration->base.source_position;
+ if (is_typeref(orig_type)) {
+ /* §6.9.1:2 */
+ errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
}
- if (warning.traditional && !type->function.unspecified_parameters) {
- warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
- ndeclaration->base.symbol);
+
+ if (is_type_compound(skip_typeref(type->function.return_type))) {
+ warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
}
- if (warning.old_style_definition && type->function.unspecified_parameters) {
- warningf(HERE, "old-style function definition '%Y'",
- ndeclaration->base.symbol);
+ if (type->function.unspecified_parameters) {
+ warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
+ } else {
+ warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
}
/* §6.7.5.3:14 a function definition with () means no
assert(is_declaration(entity));
type = skip_typeref(entity->declaration.type);
- /* push function parameters and switch scope */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&function->parameters);
+ PUSH_SCOPE(&function->parameters);
entity_t *parameter = function->parameters.entities;
for (; parameter != NULL; parameter = parameter->base.next) {
entity_t *old_current_entity = current_entity;
current_function = function;
current_entity = entity;
- current_parent = NULL;
+ PUSH_PARENT(NULL);
goto_first = NULL;
goto_anchor = &goto_first;
first_err = true;
check_labels();
check_declarations();
- if (warning.return_type ||
- warning.unreachable_code ||
- (warning.missing_noreturn
- && !(function->base.modifiers & DM_NORETURN))) {
+ if (is_warn_on(WARN_RETURN_TYPE) ||
+ is_warn_on(WARN_UNREACHABLE_CODE) ||
+ (is_warn_on(WARN_MISSING_NORETURN) && !(function->base.modifiers & DM_NORETURN))) {
noreturn_candidate = true;
check_reachable(body);
- if (warning.unreachable_code)
+ if (is_warn_on(WARN_UNREACHABLE_CODE))
walk_statements(body, check_unreachable, NULL);
- if (warning.missing_noreturn &&
- noreturn_candidate &&
+ if (noreturn_candidate &&
!(function->base.modifiers & DM_NORETURN)) {
- warningf(&body->base.source_position,
- "function '%#T' is candidate for attribute 'noreturn'",
- type, entity->base.symbol);
+ source_position_t const *const pos = &body->base.source_position;
+ warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
}
}
- assert(current_parent == NULL);
+ POP_PARENT();
assert(current_function == function);
assert(current_entity == entity);
current_entity = old_current_entity;
label_pop_to(label_stack_top);
}
- assert(current_scope == &function->parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
-}
-
-static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
- source_position_t *source_position,
- const symbol_t *symbol)
-{
- type_t *type = allocate_type_zero(TYPE_BITFIELD);
-
- type->bitfield.base_type = base_type;
- type->bitfield.size_expression = size;
-
- il_size_t bit_size;
- 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);
- bit_size = 0;
- } else {
- bit_size = get_type_size(base_type) * 8;
- }
-
- if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
- 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'",
- 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",
- user_symbol);
- } else {
- type->bitfield.bit_size = v;
- }
- }
-
- return type;
+ POP_SCOPE();
}
static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
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);
+ source_position_t const *const epos = &entity->base.source_position;
+ char const *const msg = get_deprecated_string(entity->declaration.attributes);
+ if (msg != NULL) {
+ warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg);
} else {
- warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix,
- entity->base.symbol, &entity->base.source_position);
+ warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos);
}
}
type_t *entry_type = entry->declaration.type;
type_t *res_type = get_qualified_type(entry_type, qualifiers);
+ /* bitfields need special treatment */
+ if (entry->compound_member.bitfield) {
+ unsigned bit_size = entry->compound_member.bit_size;
+ /* if fewer bits than an int, convert to int (see §6.3.1.1) */
+ if (bit_size < get_atomic_type_size(ATOMIC_TYPE_INT) * BITS_PER_BYTE) {
+ res_type = type_int;
+ }
+ }
+
/* 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;
}
expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
sub_addr->base.source_position = *pos;
- sub_addr->select.implicit = true;
+ sub_addr->base.implicit = true;
return find_create_select(pos, sub_addr, qualifiers, sub_compound,
symbol);
}
return NULL;
}
+static void parse_bitfield_member(entity_t *entity)
+{
+ eat(':');
+
+ expression_t *size = parse_constant_expression();
+ long size_long;
+
+ assert(entity->kind == ENTITY_COMPOUND_MEMBER);
+ type_t *type = entity->declaration.type;
+ if (!is_type_integer(skip_typeref(type))) {
+ errorf(HERE, "bitfield base type '%T' is not an integer type",
+ type);
+ }
+
+ if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+ /* error already reported by parse_constant_expression */
+ size_long = get_type_size(type) * 8;
+ } else {
+ size_long = fold_constant_to_int(size);
+
+ const symbol_t *symbol = entity->base.symbol;
+ const symbol_t *user_symbol
+ = symbol == NULL ? sym_anonymous : symbol;
+ unsigned bit_size = get_type_size(type) * 8;
+ if (size_long < 0) {
+ errorf(HERE, "negative width in bit-field '%Y'", user_symbol);
+ } else if (size_long == 0 && symbol != NULL) {
+ errorf(HERE, "zero width for bit-field '%Y'", user_symbol);
+ } else if (bit_size > 0 && (unsigned)size_long > bit_size) {
+ errorf(HERE, "width of bitfield '%Y' exceeds its type",
+ user_symbol);
+ } else {
+ /* hope that people don't invent crazy types with more bits
+ * than our struct can hold */
+ assert(size_long <
+ (1 << sizeof(entity->compound_member.bit_size)*8));
+ }
+ }
+
+ entity->compound_member.bitfield = true;
+ entity->compound_member.bit_size = (unsigned char)size_long;
+}
+
static void parse_compound_declarators(compound_t *compound,
const declaration_specifiers_t *specifiers)
{
do {
entity_t *entity;
- if (token.type == ':') {
- source_position_t source_position = *HERE;
- next_token();
-
- type_t *base_type = specifiers->type;
- expression_t *size = parse_constant_expression();
+ if (token.kind == ':') {
+ /* anonymous bitfield */
+ type_t *type = specifiers->type;
+ entity_t *entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER,
+ NAMESPACE_NORMAL, NULL);
+ entity->base.source_position = *HERE;
+ entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
+ entity->declaration.storage_class = STORAGE_CLASS_NONE;
+ entity->declaration.type = type;
- type_t *type = make_bitfield_type(base_type, size,
- &source_position, NULL);
+ parse_bitfield_member(entity);
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.type = type;
- entity->declaration.attributes = attributes;
-
if (attributes != NULL) {
handle_entity_attributes(attributes, entity);
}
+ entity->declaration.attributes = attributes;
+
append_entity(&compound->members, entity);
} else {
entity = parse_declarator(specifiers,
DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+ source_position_t const *const pos = &entity->base.source_position;
if (entity->kind == ENTITY_TYPEDEF) {
- errorf(&entity->base.source_position,
- "typedef not allowed as compound member");
+ errorf(pos, "typedef not allowed as compound member");
} else {
assert(entity->kind == ENTITY_COMPOUND_MEMBER);
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);
+ source_position_t const *const ppos = &prev->base.source_position;
+ errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos);
}
}
- 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);
+ if (token.kind == ':') {
+ parse_bitfield_member(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);
+ errorf(pos, "'%N' must not have function type '%T'", entity, 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);
+ token.kind != ';' ||
+ look_ahead(1)->kind != '}') {
+ errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
}
}
}
eat('{');
add_anchor_token('}');
- while (token.type != '}') {
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- break;
- }
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
- parse_declaration_specifiers(&specifiers);
+ for (;;) {
+ switch (token.kind) {
+ DECLARATION_START
+ case T___extension__:
+ case T_IDENTIFIER: {
+ PUSH_EXTENSION();
+ declaration_specifiers_t specifiers;
+ parse_declaration_specifiers(&specifiers);
+ parse_compound_declarators(compound, &specifiers);
+ POP_EXTENSION();
+ break;
+ }
- parse_compound_declarators(compound, &specifiers);
+ default:
+ rem_anchor_token('}');
+ expect('}', end_error);
+end_error:
+ /* §6.7.2.1:7 */
+ compound->complete = true;
+ return;
+ }
}
- rem_anchor_token('}');
- next_token();
-
- /* §6.7.2.1:7 */
- compound->complete = true;
}
static type_t *parse_typename(void)
{
declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
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 must not have a storage class");
+ errorf(&specifiers.source_position, "typename must not have a storage class");
}
type_t *result = parse_abstract_declarator(specifiers.type);
parse_expression_infix_function infix_parser;
};
-expression_parser_function_t expression_parsers[T_LAST_TOKEN];
+static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
/**
* Prints an error message if an expression was expected but not read
static expression_t *expected_expression_error(void)
{
/* skip the error message if the error token was read */
- if (token.type != T_ERROR) {
+ if (token.kind != T_ERROR) {
errorf(HERE, "expected expression, got token %K", &token);
}
next_token();
static type_t *get_string_type(void)
{
- return warning.write_strings ? type_const_char_ptr : type_char_ptr;
+ return is_warn_on(WARN_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;
+ return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
}
/**
*/
static expression_t *parse_string_literal(void)
{
- source_position_t begin = token.source_position;
- string_t res = token.literal;
- bool is_wide = (token.type == T_WIDE_STRING_LITERAL);
+ source_position_t begin = token.base.source_position;
+ string_t res = token.string.string;
+ bool is_wide = (token.kind == 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);
+ while (token.kind == T_STRING_LITERAL
+ || token.kind == T_WIDE_STRING_LITERAL) {
+ warn_string_concat(&token.base.source_position);
+ res = concat_strings(&res, &token.string.string);
next_token();
- is_wide |= token.type == T_WIDE_STRING_LITERAL;
+ is_wide |= token.kind == T_WIDE_STRING_LITERAL;
}
expression_t *literal;
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;
+ literal->base.type = type_bool;
+ literal->literal.value.begin = value ? "true" : "false";
+ literal->literal.value.size = value ? 4 : 5;
next_token();
return literal;
static void warn_traditional_suffix(void)
{
- if (!warning.traditional)
- return;
- warningf(&token.source_position, "traditional C rejects the '%Y' suffix",
- token.symbol);
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
+ &token.number.suffix);
}
static void check_integer_suffix(void)
{
- symbol_t *suffix = token.symbol;
- if (suffix == NULL)
+ const string_t *suffix = &token.number.suffix;
+ if (suffix->size == 0)
return;
bool not_traditional = false;
- const char *c = suffix->string;
+ const char *c = suffix->begin;
if (*c == 'l' || *c == 'L') {
++c;
if (*c == *(c-1)) {
}
}
if (*c != '\0') {
- errorf(&token.source_position,
- "invalid suffix '%s' on integer constant", suffix->string);
+ errorf(&token.base.source_position,
+ "invalid suffix '%S' on integer constant", suffix);
} else if (not_traditional) {
warn_traditional_suffix();
}
static type_t *check_floatingpoint_suffix(void)
{
- symbol_t *suffix = token.symbol;
- type_t *type = type_double;
- if (suffix == NULL)
+ const string_t *suffix = &token.number.suffix;
+ type_t *type = type_double;
+ if (suffix->size == 0)
return type;
bool not_traditional = false;
- const char *c = suffix->string;
+ const char *c = suffix->begin;
if (*c == 'f' || *c == 'F') {
++c;
type = type_float;
type = type_long_double;
}
if (*c != '\0') {
- errorf(&token.source_position,
- "invalid suffix '%s' on floatingpoint constant", suffix->string);
+ errorf(&token.base.source_position,
+ "invalid suffix '%S' on floatingpoint constant", suffix);
} else if (not_traditional) {
warn_traditional_suffix();
}
expression_kind_t kind;
type_t *type;
- switch (token.type) {
+ switch (token.kind) {
case T_INTEGER:
kind = EXPR_LITERAL_INTEGER;
check_integer_suffix();
}
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;
+ literal->base.type = type;
+ literal->literal.value = token.number.number;
+ literal->literal.suffix = token.number.suffix;
next_token();
/* integer type depends on the size of the number and the size
static expression_t *parse_character_constant(void)
{
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;
+ literal->base.type = c_mode & _CXX ? type_char : type_int;
+ literal->literal.value = token.string.string;
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) {
+ } else {
literal->base.type = type_int;
- warningf(HERE, "multi-character character constant");
+ warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
}
}
static expression_t *parse_wide_character_constant(void)
{
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;
+ literal->base.type = type_int;
+ literal->literal.value = token.string.string;
size_t len = wstrlen(&literal->literal.value);
if (len > 1) {
- warningf(HERE, "multi-character character constant");
+ warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
}
next_token();
ntype->function.linkage = LINKAGE_C;
type_t *type = identify_new_type(ntype);
- entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
+ entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol);
entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.type = type;
entity->declaration.implicit = true;
- entity->base.namespc = NAMESPACE_NORMAL;
- entity->base.symbol = symbol;
entity->base.source_position = *source_position;
- if (current_scope != NULL) {
- bool strict_prototypes_old = warning.strict_prototypes;
- warning.strict_prototypes = false;
+ if (current_scope != NULL)
record_entity(entity, false);
- warning.strict_prototypes = strict_prototypes_old;
- }
return entity;
}
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);
+ return get_qualified_type(type, expression->base.type->base.qualifiers);
}
case EXPR_UNARY_DEREFERENCE: {
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)
+ if (entity->base.symbol == symbol
+ && (namespace_tag_t)entity->base.namespc == namespc)
break;
}
entity_t *entity;
while (true) {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
- symbol = token.symbol;
+ symbol = token.identifier.symbol;
pos = *HERE;
next_token();
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;
+
+ /* skip further qualifications */
+ while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
}
}
if (entity == NULL) {
- if (!strict_mode && token.type == '(') {
+ if (!strict_mode && token.kind == '(') {
/* an implicitly declared function */
- 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);
- }
-
+ warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of function '%Y'", symbol);
entity = create_implicit_function(symbol, &pos);
} else {
errorf(&pos, "unknown identifier '%Y' found.", symbol);
}
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();
+ source_position_t const pos = token.base.source_position;
+ entity_t *const entity = parse_qualified_identifier();
type_t *orig_type;
if (is_declaration(entity)) {
if (entity->kind == ENTITY_ENUM_VALUE)
kind = EXPR_REFERENCE_ENUM_VALUE;
- expression_t *expression = allocate_expression_zero(kind);
- expression->reference.entity = entity;
- expression->base.type = type;
+ expression_t *expression = allocate_expression_zero(kind);
+ expression->base.source_position = pos;
+ expression->base.type = type;
+ expression->reference.entity = entity;
/* this declaration is used */
if (is_declaration(entity)) {
current_function->need_closure = true;
}
- check_deprecated(HERE, entity);
-
- if (warning.init_self && entity == current_init_decl && !in_type_prop
- && entity->kind == ENTITY_VARIABLE) {
- current_init_decl = NULL;
- warningf(HERE, "variable '%#T' is initialized by itself",
- entity->declaration.type, entity->base.symbol);
- }
+ check_deprecated(&pos, entity);
return expression;
}
return false;
}
- if (warning.cast_qual &&
- is_type_pointer(src_type) &&
- is_type_pointer(dst_type)) {
+ if (is_type_pointer(src_type) && is_type_pointer(dst_type)) {
type_t *src = skip_typeref(src_type->pointer.points_to);
type_t *dst = skip_typeref(dst_type->pointer.points_to);
unsigned missing_qualifiers =
src->base.qualifiers & ~dst->base.qualifiers;
if (missing_qualifiers != 0) {
- warningf(pos,
- "cast discards qualifiers '%Q' in pointer target type of '%T'",
- missing_qualifiers, orig_type_right);
+ warningf(WARN_CAST_QUAL, pos, "cast discards qualifiers '%Q' in pointer target type of '%T'", missing_qualifiers, orig_type_right);
}
}
return true;
}
-static expression_t *parse_compound_literal(type_t *type)
+static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
{
expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+ expression->base.source_position = *pos;
parse_initializer_env_t env;
env.type = type;
*/
static expression_t *parse_cast(void)
{
- add_anchor_token(')');
+ source_position_t const pos = *HERE;
- source_position_t source_position = token.source_position;
+ eat('(');
+ add_anchor_token(')');
type_t *type = parse_typename();
rem_anchor_token(')');
expect(')', end_error);
- if (token.type == '{') {
- return parse_compound_literal(type);
+ if (token.kind == '{') {
+ return parse_compound_literal(&pos, type);
}
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
- cast->base.source_position = source_position;
+ cast->base.source_position = pos;
expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
*/
static expression_t *parse_statement_expression(void)
{
- add_anchor_token(')');
-
expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
+ eat('(');
+ add_anchor_token(')');
+
statement_t *statement = parse_compound_statement(true);
statement->compound.stmt_expr = true;
expression->statement.statement = statement;
if (stmt->kind == STATEMENT_EXPRESSION) {
type = stmt->expression.expression->base.type;
}
- } else if (warning.other) {
- warningf(&expression->base.source_position, "empty statement expression ({})");
+ } else {
+ source_position_t const *const pos = &expression->base.source_position;
+ warningf(WARN_OTHER, pos, "empty statement expression ({})");
}
expression->base.type = type;
*/
static expression_t *parse_parenthesized_expression(void)
{
- eat('(');
-
- switch (token.type) {
+ token_t const* const la1 = look_ahead(1);
+ switch (la1->kind) {
case '{':
/* gcc extension: a statement expression */
return parse_statement_expression();
- TYPE_QUALIFIERS
- TYPE_SPECIFIERS
- return parse_cast();
case T_IDENTIFIER:
- if (is_typedef_symbol(token.symbol)) {
+ if (is_typedef_symbol(la1->identifier.symbol)) {
+ DECLARATION_START
return parse_cast();
}
}
+ eat('(');
add_anchor_token(')');
expression_t *result = parse_expression();
result->base.parenthesized = true;
designator_t *result = allocate_ast_zero(sizeof(result[0]));
result->source_position = *HERE;
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing member designator",
T_IDENTIFIER, NULL);
return NULL;
}
- result->symbol = token.symbol;
+ result->symbol = token.identifier.symbol;
next_token();
designator_t *last_designator = result;
while (true) {
if (next_if('.')) {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing member designator",
T_IDENTIFIER, NULL);
return NULL;
}
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
- designator->symbol = token.symbol;
+ designator->symbol = token.identifier.symbol;
next_token();
last_designator->next = designator;
{
expression_t *expression;
- switch (token.type) {
+ switch (token.kind) {
case T___builtin_isgreater:
expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
break;
}
/**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol the symbol of the label
+ * Return the label for the current symbol or create a new one.
*/
-static label_t *get_label(symbol_t *symbol)
+static label_t *get_label(void)
{
- entity_t *label;
+ assert(token.kind == T_IDENTIFIER);
assert(current_function != NULL);
- label = get_entity(symbol, NAMESPACE_LABEL);
- /* if we found a local label, we already created the declaration */
+ entity_t *label = get_entity(token.identifier.symbol, NAMESPACE_LABEL);
+ /* If we find a local label, we already created the declaration. */
if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) {
if (label->base.parent_scope != current_scope) {
assert(label->base.parent_scope->depth < current_scope->depth);
current_function->goto_to_outer = true;
}
- return &label->label;
- }
-
- label = get_entity(symbol, NAMESPACE_LABEL);
- /* if we found a label in the same function, then we already created the
- * declaration */
- if (label != NULL
- && label->base.parent_scope == ¤t_function->parameters) {
- return &label->label;
+ } else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) {
+ /* There is no matching label in the same function, so create a new one. */
+ label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol);
+ label_push(label);
}
- /* otherwise we need to create a new one */
- label = allocate_entity_zero(ENTITY_LABEL);
- label->base.namespc = NAMESPACE_LABEL;
- label->base.symbol = symbol;
-
- label_push(label);
-
+ eat(T_IDENTIFIER);
return &label->label;
}
*/
static expression_t *parse_label_address(void)
{
- source_position_t source_position = token.source_position;
+ source_position_t source_position = token.base.source_position;
eat(T_ANDAND);
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
- goto end_error;
+ return create_invalid_expression();
}
- symbol_t *symbol = token.symbol;
- next_token();
- label_t *label = get_label(symbol);
+ label_t *const label = get_label();
label->used = true;
label->address_taken = true;
expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
expression->base.source_position = source_position;
- /* label address is threaten as a void pointer */
+ /* label address is treated as a void pointer */
expression->base.type = type_void_ptr;
expression->label_address.label = label;
return expression;
-end_error:
- return create_invalid_expression();
}
/**
{
/* the result is a (int)0 */
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;
+ literal->base.type = type_int;
+ literal->literal.value.begin = "__noop";
+ literal->literal.value.size = 6;
eat(T___noop);
- if (token.type == '(') {
+ if (token.kind == '(') {
/* parse arguments */
eat('(');
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') do {
+ if (token.kind != ')') do {
(void)parse_assignment_expression();
} while (next_if(','));
}
*/
static expression_t *parse_primary_expression(void)
{
- switch (token.type) {
+ switch (token.kind) {
case T_false: return parse_boolean_literal(false);
case T_true: return parse_boolean_literal(true);
case T_INTEGER:
case T_COLONCOLON:
return parse_reference();
case T_IDENTIFIER:
- if (!is_typedef_symbol(token.symbol)) {
+ if (!is_typedef_symbol(token.identifier.symbol)) {
return parse_reference();
}
/* FALLTHROUGH */
- TYPENAME_START {
- source_position_t const pos = *HERE;
- type_t const *const type = parse_typename();
+ DECLARATION_START {
+ source_position_t const pos = *HERE;
+ declaration_specifiers_t specifiers;
+ parse_declaration_specifiers(&specifiers);
+ type_t const *const type = parse_abstract_declarator(specifiers.type);
errorf(&pos, "encountered type '%T' while parsing expression", type);
return create_invalid_expression();
}
res_type = type_inside->pointer.points_to;
check_idx:
res_type = automatic_type_conversion(res_type);
- if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR) && warning.char_subscripts) {
- warningf(&idx->base.source_position, "array subscript has char type");
+ if (!is_type_integer(idx_type)) {
+ errorf(&idx->base.source_position, "array subscript must have integer type");
+ } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) {
+ source_position_t const *const pos = &idx->base.source_position;
+ warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
}
} else {
if (is_type_valid(type_left) && is_type_valid(type_inside)) {
- errorf(HERE,
- "array access on object with non-pointer types '%T', '%T'",
- orig_type_left, orig_type_inside);
+ errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
}
res_type = type_error_type;
ref = left;
return expr;
}
+static bool is_bitfield(const expression_t *expression)
+{
+ return expression->kind == EXPR_SELECT
+ && expression->select.compound_entry->compound_member.bitfield;
+}
+
static expression_t *parse_typeprop(expression_kind_t const kind)
{
expression_t *tp_expression = allocate_expression_zero(kind);
eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__);
- /* we only refer to a type property, mark this case */
- bool old = in_type_prop;
- in_type_prop = true;
-
type_t *orig_type;
expression_t *expression;
- if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
+ if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
+ source_position_t const pos = *HERE;
next_token();
add_anchor_token(')');
orig_type = parse_typename();
rem_anchor_token(')');
expect(')', end_error);
- if (token.type == '{') {
+ if (token.kind == '{') {
/* It was not sizeof(type) after all. It is sizeof of an expression
* starting with a compound literal */
- expression = parse_compound_literal(orig_type);
+ expression = parse_compound_literal(&pos, orig_type);
goto typeprop_expression;
}
} else {
expression = parse_subexpression(PREC_UNARY);
typeprop_expression:
+ if (is_bitfield(expression)) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ errorf(&tp_expression->base.source_position,
+ "operand of %s expression must not be a bitfield", what);
+ }
+
tp_expression->typeprop.tp_expression = expression;
orig_type = revert_automatic_type_conversion(expression);
} else if (type->kind == TYPE_FUNCTION) {
if (GNU_MODE) {
/* function types are allowed (and return 1) */
- if (warning.other) {
- char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
- warningf(&tp_expression->base.source_position,
- "%s expression with function argument returns invalid result", what);
- }
+ source_position_t const *const pos = &tp_expression->base.source_position;
+ char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what);
} else {
wrong_type = "function";
}
- } else {
- if (is_type_incomplete(type))
- wrong_type = "incomplete";
}
- if (type->kind == TYPE_BITFIELD)
- wrong_type = "bitfield";
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
}
end_error:
- in_type_prop = old;
return tp_expression;
}
static expression_t *parse_select_expression(expression_t *addr)
{
- assert(token.type == '.' || token.type == T_MINUSGREATER);
- bool select_left_arrow = (token.type == T_MINUSGREATER);
+ assert(token.kind == '.' || token.kind == T_MINUSGREATER);
+ bool select_left_arrow = (token.kind == T_MINUSGREATER);
source_position_t const pos = *HERE;
next_token();
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
return create_invalid_expression();
}
- symbol_t *symbol = token.symbol;
+ symbol_t *symbol = token.identifier.symbol;
next_token();
type_t *const orig_type = addr->base.type;
snprintf(buf, sizeof(buf), "call argument %u", pos);
report_assign_error(error, expected_type, arg_expr, buf,
&arg_expr->base.source_position);
- } else if (warning.traditional || warning.conversion) {
+ } else {
type_t *const promoted_type = get_default_promoted_type(arg_type);
if (!types_compatible(expected_type_skip, promoted_type) &&
!types_compatible(expected_type_skip, type_void_ptr) &&
!types_compatible(type_void_ptr, promoted_type)) {
/* Deliberately show the skipped types in this warning */
- warningf(&arg_expr->base.source_position,
- "passing call argument %u as '%T' rather than '%T' due to prototype",
- pos, expected_type_skip, promoted_type);
+ source_position_t const *const apos = &arg_expr->base.source_position;
+ warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type);
}
}
}
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') {
+ if (token.kind != ')') {
call_argument_t **anchor = &call->arguments;
do {
call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
}
if (parameter != NULL) {
- errorf(HERE, "too few arguments to function '%E'", expression);
+ errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
} else if (argument != NULL && !function_type->variadic) {
- errorf(HERE, "too many arguments to function '%E'", expression);
+ errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
}
}
/* 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))) {
+ type_t *argument_type = argument->expression->base.type;
+ if (!is_type_object(skip_typeref(argument_type))) {
errorf(&argument->expression->base.source_position,
"call argument '%E' must not be void", argument->expression);
}
- type = get_default_promoted_type(type);
+ argument_type = get_default_promoted_type(argument_type);
argument->expression
- = create_implicit_cast(argument->expression, type);
+ = create_implicit_cast(argument->expression, argument_type);
}
- check_format(&result->call);
+ check_format(call);
- if (warning.aggregate_return &&
- is_type_compound(skip_typeref(function_type->return_type))) {
- warningf(&result->base.source_position,
- "function call has aggregate value");
+ if (is_type_compound(skip_typeref(function_type->return_type))) {
+ source_position_t const *const pos = &expression->base.source_position;
+ warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value");
}
- if (call->function->kind == EXPR_REFERENCE) {
- reference_expression_t *reference = &call->function->reference;
+ if (expression->kind == EXPR_REFERENCE) {
+ reference_expression_t *reference = &expression->reference;
if (reference->entity->kind == ENTITY_FUNCTION &&
reference->entity->function.btk != bk_none)
handle_builtin_argument_restrictions(call);
static void warn_reference_address_as_bool(expression_t const* expr)
{
- if (!warning.address)
- return;
-
expr = get_reference_address(expr);
if (expr != NULL) {
- warningf(&expr->base.source_position,
- "the address of '%Y' will always evaluate as 'true'",
- expr->reference.entity->base.symbol);
+ source_position_t const *const pos = &expr->base.source_position;
+ entity_t const *const ent = expr->reference.entity;
+ warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent);
}
}
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");
+ source_position_t const *const pos = &expr->base.source_position;
+ warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value");
}
static void semantic_condition(expression_t const *const expr,
expression_t *true_expression = expression;
bool gnu_cond = false;
- if (GNU_MODE && token.type == ':') {
+ if (GNU_MODE && token.kind == ':') {
gnu_cond = true;
} else {
true_expression = parse_expression();
type_t *const false_type = skip_typeref(orig_false_type);
/* 6.5.15.3 */
- type_t *result_type;
+ source_position_t const *const pos = &conditional->base.source_position;
+ type_t *result_type;
if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
/* ISO/IEC 14882:1998(E) §5.16:2 */
} else if (false_expression->kind == EXPR_UNARY_THROW) {
result_type = true_type;
} else {
- if (warning.other && (
- !is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
- !is_type_atomic(false_type, ATOMIC_TYPE_VOID)
- )) {
- warningf(&conditional->base.source_position,
- "ISO C forbids conditional expression with only one void side");
+ if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
+ !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side");
}
result_type = type_void;
}
get_unqualified_type(to2))) {
to = to1;
} else {
- if (warning.other) {
- warningf(&conditional->base.source_position,
- "pointer types '%T' and '%T' in conditional expression are incompatible",
- true_type, false_type);
- }
+ warningf(WARN_OTHER, pos, "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type);
to = type_void;
}
get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers);
result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE);
} else if (is_type_integer(other_type)) {
- if (warning.other) {
- warningf(&conditional->base.source_position,
- "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
- }
+ warningf(WARN_OTHER, pos, "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
result_type = pointer_type;
} else {
- if (is_type_valid(other_type)) {
- type_error_incompatible("while parsing conditional",
- &expression->base.source_position, true_type, false_type);
- }
- result_type = type_error_type;
+ goto types_incompatible;
}
} else {
+types_incompatible:
if (is_type_valid(true_type) && is_type_valid(false_type)) {
- type_error_incompatible("while parsing conditional",
- &conditional->base.source_position, true_type,
- false_type);
+ type_error_incompatible("while parsing conditional", pos, true_type, false_type);
}
result_type = type_error_type;
}
*/
static expression_t *parse_extension(void)
{
- eat(T___extension__);
-
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
expression_t *expression = parse_subexpression(PREC_UNARY);
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
return expression;
}
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,
- "deleting 'void*' is undefined");
+ } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) {
+ source_position_t const *const pos = &value->base.source_position;
+ warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
}
return result;
eat(T_throw);
expression_t *value = NULL;
- switch (token.type) {
+ switch (token.kind) {
EXPRESSION_START {
value = parse_assignment_expression();
/* ISO/IEC 14882:1998(E) §15.1:3 */
"arithmetic with pointer to incomplete type '%T' not allowed",
orig_pointer_type);
return false;
- } else if (warning.pointer_arith) {
- warningf(source_position,
- "pointer of type '%T' used in arithmetic",
- orig_pointer_type);
+ } else {
+ warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type);
}
} else if (is_type_function(points_to)) {
if (!GNU_MODE) {
"arithmetic with pointer to function type '%T' not allowed",
orig_pointer_type);
return false;
- } else if (warning.pointer_arith) {
- warningf(source_position,
- "pointer to a function '%T' used in arithmetic",
- orig_pointer_type);
+ } else {
+ warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type);
}
}
return true;
static void semantic_unexpr_plus(unary_expression_t *expression)
{
semantic_unexpr_arithmetic(expression);
- if (warning.traditional)
- warningf(&expression->base.source_position,
- "traditional C rejects the unary plus operator");
+ source_position_t const *const pos = &expression->base.source_position;
+ warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator");
}
static void semantic_not(unary_expression_t *expression)
if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
&& !may_be_register) {
- errorf(&expression->base.source_position,
- "address of register %s '%Y' requested",
- get_entity_kind_name(entity->kind), entity->base.symbol);
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "address of register '%N' requested", entity);
}
if (entity->kind == ENTITY_VARIABLE) {
if (!is_lvalue(value)) {
errorf(&expression->base.source_position, "'&' requires an lvalue");
}
- if (type->kind == TYPE_BITFIELD) {
+ if (is_bitfield(value)) {
errorf(&expression->base.source_position,
- "'&' not allowed on object with bitfield type '%T'",
- type);
+ "'&' not allowed on bitfield");
}
set_address_taken(value, false);
expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
}
-#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
+#define CREATE_UNARY_EXPRESSION_PARSER(token_kind, unexpression_type, sfunc) \
static expression_t *parse_##unexpression_type(void) \
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- eat(token_type); \
+ eat(token_kind); \
unary_expression->unary.value = parse_subexpression(PREC_UNARY); \
\
sfunc(&unary_expression->unary); \
CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT,
semantic_incdec)
-#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
+#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_kind, unexpression_type, \
sfunc) \
static expression_t *parse_##unexpression_type(expression_t *left) \
{ \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
- eat(token_type); \
+ eat(token_kind); \
unary_expression->unary.value = left; \
\
sfunc(&unary_expression->unary); \
static void warn_div_by_zero(binary_expression_t const *const expression)
{
- if (!warning.div_by_zero ||
- !is_type_integer(expression->base.type))
+ if (!is_type_integer(expression->base.type))
return;
expression_t const *const right = expression->right;
if (is_type_integer(right->base.type) &&
is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
- warningf(&expression->base.source_position, "division by zero");
+ source_position_t const *const pos = &expression->base.source_position;
+ warningf(WARN_DIV_BY_ZERO, pos, "division by zero");
}
}
default: return;
}
- warningf(&expr->base.source_position,
- "suggest parentheses around '%c' inside shift", op);
+ source_position_t const *const pos = &expr->base.source_position;
+ warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op);
}
static bool semantic_shift(binary_expression_t *expression)
type_left = promote_integer(type_left);
if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
- long count = fold_constant_to_int(right);
+ source_position_t const *const pos = &right->base.source_position;
+ long const count = fold_constant_to_int(right);
if (count < 0) {
- warningf(&right->base.source_position,
- "shift count must be non-negative");
+ warningf(WARN_OTHER, pos, "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");
+ warningf(WARN_OTHER, pos, "shift count must be less than type width");
}
}
if (!semantic_shift(expression))
return;
- if (warning.parentheses) {
- warn_addsub_in_shift(left);
- warn_addsub_in_shift(right);
- }
+ warn_addsub_in_shift(left);
+ warn_addsub_in_shift(right);
type_t *const orig_type_left = left->base.type;
type_t * type_left = skip_typeref(orig_type_left);
if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
errorf(pos, "subtracting pointers to non-object types '%T'",
orig_type_left);
- } else if (warning.other) {
- warningf(pos, "subtracting pointers to void");
+ } else {
+ warningf(WARN_OTHER, pos, "subtracting pointers to void");
}
}
expression->base.type = type_ptrdiff_t;
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;
+ source_position_t const *const pos = &expr->base.source_position;
+ warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
}
}
{
switch (is_constant_expression(expr)) {
case EXPR_CLASS_ERROR: return false;
- case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
default: return true;
}
}
+static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other)
+{
+ warn_string_literal_address(expr);
+
+ expression_t const* const ref = get_reference_address(expr);
+ if (ref != NULL && is_null_pointer_constant(other)) {
+ entity_t const *const ent = ref->reference.entity;
+ warningf(WARN_ADDRESS, pos, "the address of '%N' will never be NULL", ent);
+ }
+
+ if (!expr->base.parenthesized) {
+ 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(WARN_PARENTHESES, pos, "comparisons like 'x <= y < z' do not have their mathematical meaning");
+ break;
+ default:
+ break;
+ }
+ }
+}
+
/**
* Check the semantics of comparison expressions.
*
*/
static void semantic_comparison(binary_expression_t *expression)
{
- expression_t *left = expression->left;
- expression_t *right = expression->right;
-
- if (warning.address) {
- warn_string_literal_address(left);
- warn_string_literal_address(right);
+ source_position_t const *const pos = &expression->base.source_position;
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
- expression_t const* const func_left = get_reference_address(left);
- if (func_left != NULL && is_null_pointer_constant(right)) {
- warningf(&expression->base.source_position,
- "the address of '%Y' will never be NULL",
- func_left->reference.entity->base.symbol);
- }
-
- expression_t const* const func_right = get_reference_address(right);
- if (func_right != NULL && is_null_pointer_constant(right)) {
- warningf(&expression->base.source_position,
- "the address of '%Y' will never be NULL",
- func_right->reference.entity->base.symbol);
- }
- }
-
- if (warning.parentheses) {
- warn_comparison_in_comparison(left);
- warn_comparison_in_comparison(right);
- }
+ warn_comparison(pos, left, right);
+ warn_comparison(pos, right, left);
type_t *orig_type_left = left->base.type;
type_t *orig_type_right = right->base.type;
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
/* test for signed vs unsigned compares */
- if (warning.sign_compare && is_type_integer(arithmetic_type)) {
+ if (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) {
/* 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(WARN_SIGN_COMPARE, pos, "comparison between signed and unsigned");
}
}
}
expression->left = create_implicit_cast(left, arithmetic_type);
expression->right = create_implicit_cast(right, arithmetic_type);
expression->base.type = arithmetic_type;
- if (warning.float_equal &&
- (expression->base.kind == EXPR_BINARY_EQUAL ||
+ if ((expression->base.kind == EXPR_BINARY_EQUAL ||
expression->base.kind == EXPR_BINARY_NOTEQUAL) &&
is_type_float(arithmetic_type)) {
- warningf(&expression->base.source_position,
- "comparing floating point with == or != is unsafe");
+ warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe");
}
} else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
/* TODO check compatibility */
} else if (is_type_pointer(type_right)) {
expression->left = create_implicit_cast(left, type_right);
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
- type_error_incompatible("invalid operands in comparison",
- &expression->base.source_position,
- type_left, type_right);
+ type_error_incompatible("invalid operands in comparison", pos, type_left, type_right);
}
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
type_t *const type_left = skip_typeref(orig_type_left);
if (!is_lvalue(left)) {
- errorf(HERE, "left hand side '%E' of assignment is not an lvalue",
+ errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
left);
return false;
}
if (left->kind == EXPR_REFERENCE
&& left->reference.entity->kind == ENTITY_FUNCTION) {
- errorf(HERE, "cannot assign to function '%E'", left);
+ errorf(&left->base.source_position, "cannot assign to function '%E'", left);
return false;
}
if (is_type_array(type_left)) {
- errorf(HERE, "cannot assign to array '%E'", left);
+ errorf(&left->base.source_position, "cannot assign to array '%E'", left);
return false;
}
if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
- errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+ errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
orig_type_left);
return false;
}
if (is_type_incomplete(type_left)) {
- errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'",
+ errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
left, orig_type_left);
return false;
}
if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
- errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+ errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
left, orig_type_left);
return false;
}
return;
if (expr->base.parenthesized)
return;
- warningf(&expr->base.source_position,
- "suggest parentheses around && within ||");
+ source_position_t const *const pos = &expr->base.source_position;
+ warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||");
}
/**
* §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) {
+ if (expression->base.kind == EXPR_BINARY_LOGICAL_OR) {
warn_logical_and_within_or(expression->left);
warn_logical_and_within_or(expression->right);
}
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;
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;
static void semantic_comma(binary_expression_t *expression)
{
- if (warning.unused_value) {
- const expression_t *const left = expression->left;
- if (!expression_has_effect(left)) {
- warningf(&left->base.source_position,
- "left-hand operand of comma expression has no effect");
- }
+ const expression_t *const left = expression->left;
+ if (!expression_has_effect(left)) {
+ source_position_t const *const pos = &left->base.source_position;
+ warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect");
}
expression->base.type = expression->right->base.type;
}
/**
* @param prec_r precedence of the right operand
*/
-#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \
+#define CREATE_BINEXPR_PARSER(token_kind, binexpression_type, prec_r, sfunc) \
static expression_t *parse_##binexpression_type(expression_t *left) \
{ \
expression_t *binexpr = allocate_expression_zero(binexpression_type); \
binexpr->binary.left = left; \
- eat(token_type); \
+ eat(token_kind); \
\
expression_t *right = parse_subexpression(prec_r); \
\
static expression_t *parse_subexpression(precedence_t precedence)
{
- if (token.type < 0) {
+ if (token.kind < 0) {
return expected_expression_error();
}
expression_parser_function_t *parser
- = &expression_parsers[token.type];
- source_position_t source_position = token.source_position;
+ = &expression_parsers[token.kind];
expression_t *left;
if (parser->parser != NULL) {
left = parse_primary_expression();
}
assert(left != NULL);
- left->base.source_position = source_position;
while (true) {
- if (token.type < 0) {
+ if (token.kind < 0) {
return expected_expression_error();
}
- parser = &expression_parsers[token.type];
+ parser = &expression_parsers[token.kind];
if (parser->infix_parser == NULL)
break;
if (parser->infix_precedence < precedence)
left = parser->infix_parser(left);
assert(left != NULL);
- assert(left->kind != EXPR_UNKNOWN);
- left->base.source_position = source_position;
}
return left;
* Register a parser for a prefix-like operator.
*
* @param parser the parser function
- * @param token_type the token type of the prefix token
+ * @param token_kind the token type of the prefix token
*/
static void register_expression_parser(parse_expression_function parser,
- int token_type)
+ int token_kind)
{
- expression_parser_function_t *entry = &expression_parsers[token_type];
+ expression_parser_function_t *entry = &expression_parsers[token_kind];
if (entry->parser != NULL) {
- diagnosticf("for token '%k'\n", (token_type_t)token_type);
+ diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
panic("trying to register multiple expression parsers for a token");
}
entry->parser = parser;
* Register a parser for an infix operator with given precedence.
*
* @param parser the parser function
- * @param token_type the token type of the infix operator
+ * @param token_kind the token type of the infix operator
* @param precedence the precedence of the operator
*/
static void register_infix_parser(parse_expression_infix_function parser,
- int token_type, precedence_t precedence)
+ int token_kind, precedence_t precedence)
{
- expression_parser_function_t *entry = &expression_parsers[token_type];
+ expression_parser_function_t *entry = &expression_parsers[token_kind];
if (entry->infix_parser != NULL) {
- diagnosticf("for token '%k'\n", (token_type_t)token_type);
+ diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
panic("trying to register multiple infix expression parsers for a "
"token");
}
asm_argument_t *result = NULL;
asm_argument_t **anchor = &result;
- while (token.type == T_STRING_LITERAL || token.type == '[') {
+ while (token.kind == T_STRING_LITERAL || token.kind == '[') {
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
memset(argument, 0, sizeof(argument[0]));
if (next_if('[')) {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing asm argument",
T_IDENTIFIER, NULL);
return NULL;
}
- argument->symbol = token.symbol;
+ argument->symbol = token.identifier.symbol;
expect(']', end_error);
}
size = get_atomic_type_size(akind);
} else {
flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- size = get_atomic_type_size(get_intptr_kind());
+ size = get_type_size(type_void_ptr);
}
do {
value_size = get_atomic_type_size(value_akind);
} else if (value_kind == TYPE_POINTER) {
value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
- value_size = get_atomic_type_size(get_intptr_kind());
+ value_size = get_type_size(type_void_ptr);
} else {
break;
}
asm_clobber_t *result = NULL;
asm_clobber_t **anchor = &result;
- while (token.type == T_STRING_LITERAL) {
+ while (token.kind == T_STRING_LITERAL) {
asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
clobber->clobber = parse_string_literals();
expect('(', end_error);
add_anchor_token(')');
- if (token.type != T_STRING_LITERAL) {
+ if (token.kind != T_STRING_LITERAL) {
parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
goto end_of_asm;
}
static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
{
statement_t *inner_stmt;
- switch (token.type) {
+ switch (token.kind) {
case '}':
errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
inner_stmt = create_invalid_statement();
default:
inner_stmt = parse_statement();
- /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
}
long const val = fold_constant_to_int(end_range);
statement->case_label.last_case = val;
- if (warning.other && val < statement->case_label.first_case) {
+ if (val < statement->case_label.first_case) {
statement->case_label.is_empty_range = true;
- warningf(pos, "empty range specified");
+ warningf(WARN_OTHER, pos, "empty range specified");
}
}
}
statement->case_label.statement = parse_label_inner_statement(statement, "case label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
- errorf(HERE, "multiple default labels in one switch (previous declared %P)",
- &def_label->base.source_position);
+ errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position);
} else {
current_switch->default_label = &statement->case_label;
statement->case_label.statement = parse_label_inner_statement(statement, "default label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
*/
static statement_t *parse_label_statement(void)
{
- assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.symbol;
- label_t *label = get_label(symbol);
-
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
- statement->label.label = label;
-
- next_token();
+ label_t *const label = get_label();
+ statement->label.label = label;
PUSH_PARENT(statement);
/* if statement is already set then the label is defined twice,
* otherwise it was just mentioned in a goto/local label declaration so far
*/
+ source_position_t const* const pos = &statement->base.source_position;
if (label->statement != NULL) {
- errorf(HERE, "duplicate label '%Y' (declared %P)",
- symbol, &label->base.source_position);
+ errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position);
} else {
- label->base.source_position = token.source_position;
+ label->base.source_position = *pos;
label->statement = statement;
}
eat(':');
+ if (token.kind == T___attribute__ && !(c_mode & _CXX)) {
+ parse_attributes(NULL); // TODO process attributes
+ }
+
statement->label.statement = parse_label_inner_statement(statement, "label");
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
label_anchor = &statement->label.next;
- POP_PARENT;
+ POP_PARENT();
return statement;
}
+static statement_t *parse_inner_statement(void)
+{
+ statement_t *const stmt = parse_statement();
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+ errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+ }
+ return stmt;
+}
+
/**
* Parse an if statement.
*/
rem_anchor_token('{');
add_anchor_token(T_else);
- statement_t *const true_stmt = parse_statement();
+ statement_t *const true_stmt = parse_inner_statement();
statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
+ if (true_stmt->kind == STATEMENT_EMPTY) {
+ warningf(WARN_EMPTY_BODY, HERE,
+ "suggest braces around empty body in an ‘if’ statement");
+ }
+
if (next_if(T_else)) {
- statement->ifs.false_statement = parse_statement();
- } else if (warning.parentheses &&
- true_stmt->kind == STATEMENT_IF &&
+ statement->ifs.false_statement = parse_inner_statement();
+
+ if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
+ warningf(WARN_EMPTY_BODY, HERE,
+ "suggest braces around empty body in an ‘if’ statement");
+ }
+ } else if (true_stmt->kind == STATEMENT_IF &&
true_stmt->ifs.false_statement != NULL) {
- warningf(&true_stmt->base.source_position,
- "suggest explicit braces to avoid ambiguous 'else'");
+ source_position_t const *const pos = &true_stmt->base.source_position;
+ warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
}
- POP_PARENT;
+ POP_PARENT();
return statement;
}
*/
static void check_enum_cases(const switch_statement_t *statement)
{
+ if (!is_warn_on(WARN_SWITCH_ENUM))
+ return;
const type_t *type = skip_typeref(statement->expression->base.type);
if (! is_type_enum(type))
return;
break;
}
}
- if (! found) {
- warningf(&statement->base.source_position,
- "enumeration value '%Y' not handled in switch",
- entry->base.symbol);
+ if (!found) {
+ source_position_t const *const pos = &statement->base.source_position;
+ warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
last_value = value;
}
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
- if (warning.traditional) {
- if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
- warningf(&expr->base.source_position,
- "'%T' switch expression not converted to '%T' in ISO C",
- type, type_int);
- }
+ if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+ warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int);
}
} else if (is_type_valid(type)) {
errorf(&expr->base.source_position,
switch_statement_t *rem = current_switch;
current_switch = &statement->switchs;
- statement->switchs.body = parse_statement();
+ statement->switchs.body = parse_inner_statement();
current_switch = rem;
- if (warning.switch_default &&
- statement->switchs.default_label == NULL) {
- warningf(&statement->base.source_position, "switch has no default case");
+ if (statement->switchs.default_label == NULL) {
+ warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case");
}
- if (warning.switch_enum)
- check_enum_cases(&statement->switchs);
+ check_enum_cases(&statement->switchs);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
statement_t *const rem = current_loop;
current_loop = loop;
- statement_t *const body = parse_statement();
+ statement_t *const body = parse_inner_statement();
current_loop = rem;
return body;
statement->whiles.body = parse_loop_body(statement);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
expect(')', end_error);
expect(';', end_error);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
add_anchor_token(')');
PUSH_PARENT(statement);
+ PUSH_SCOPE(&statement->fors.scope);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&statement->fors.scope);
-
- bool old_gcc_extension = in_gcc_extension;
- while (next_if(T___extension__)) {
- in_gcc_extension = true;
- }
+ PUSH_EXTENSION();
if (next_if(';')) {
- } else if (is_declaration_specifier(&token, false)) {
+ } else if (is_declaration_specifier(&token)) {
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, ENT_ANY);
- if (warning.unused_value && !expression_has_effect(init)) {
- warningf(&init->base.source_position,
- "initialisation of 'for'-statement has no effect");
+ if (!expression_has_effect(init)) {
+ warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
expect(';', end_error2);
}
- in_gcc_extension = old_gcc_extension;
- if (token.type != ';') {
+ POP_EXTENSION();
+
+ if (token.kind != ';') {
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
rem_anchor_token(';');
}
expect(';', end_error2);
- if (token.type != ')') {
+ if (token.kind != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
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");
+ if (!expression_has_effect(step)) {
+ warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect");
}
}
expect(')', end_error2);
rem_anchor_token(')');
statement->fors.body = parse_loop_body(statement);
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
-
- POP_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
end_error2:
- POP_PARENT;
+ POP_PARENT();
rem_anchor_token(')');
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* fallthrough */
end_error1:
if (!is_type_pointer(type) && !is_type_integer(type)) {
errorf(&expression->base.source_position,
"cannot convert to a pointer type");
- } else if (warning.other && type != type_void_ptr) {
- warningf(&expression->base.source_position,
- "type of computed goto expression should be 'void*' not '%T'", type);
+ } else if (type != type_void_ptr) {
+ warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type);
}
expression = create_implicit_cast(expression, type_void_ptr);
}
statement->gotos.expression = expression;
- } else if (token.type == T_IDENTIFIER) {
- symbol_t *symbol = token.symbol;
- next_token();
- statement->gotos.label = get_label(symbol);
+ } else if (token.kind == T_IDENTIFIER) {
+ label_t *const label = get_label();
+ label->used = true;
+ statement->gotos.label = label;
} else {
if (GNU_MODE)
parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
*/
static statement_t *parse_return(void)
{
- eat(T_return);
-
statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+ eat(T_return);
expression_t *return_value = NULL;
- if (token.type != ';') {
+ if (token.kind != ';') {
return_value = parse_expression();
mark_vars_read(return_value, NULL);
}
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 {
+ warningf(WARN_OTHER, 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'");
+ } else {
+ warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'");
}
}
} else {
}
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) {
+ if (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(pos, "function returns address of local variable");
+ warningf(WARN_OTHER, pos, "function returns address of local variable");
}
}
- } else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ } else if (!is_type_atomic(return_type, ATOMIC_TYPE_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");
+ warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void");
}
}
statement->returns.value = return_value;
statement->ms_try.try_statement = parse_compound_statement(false);
current_try = rem;
- POP_PARENT;
+ POP_PARENT();
if (next_if(T___except)) {
expect('(', end_error);
static statement_t *parse_empty_statement(void)
{
- if (warning.empty_statement) {
- warningf(HERE, "statement is empty");
- }
+ warningf(WARN_EMPTY_STATEMENT, HERE, "statement is empty");
statement_t *const statement = create_empty_statement();
eat(';');
return statement;
entity_t *end = NULL;
entity_t **anchor = &begin;
do {
- if (token.type != T_IDENTIFIER) {
+ if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing local label declaration",
T_IDENTIFIER, NULL);
goto end_error;
}
- symbol_t *symbol = token.symbol;
+ symbol_t *symbol = token.identifier.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)",
- symbol, &entity->base.source_position);
+ source_position_t const *const ppos = &entity->base.source_position;
+ errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
} else {
- entity = allocate_entity_zero(ENTITY_LOCAL_LABEL);
-
+ entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol);
entity->base.parent_scope = current_scope;
- entity->base.namespc = NAMESPACE_LABEL;
- entity->base.source_position = token.source_position;
- entity->base.symbol = symbol;
+ entity->base.source_position = token.base.source_position;
*anchor = entity;
anchor = &entity->base.next;
entity_t *entity = NULL;
symbol_t *symbol = NULL;
- if (token.type == T_IDENTIFIER) {
- symbol = token.symbol;
+ if (token.kind == T_IDENTIFIER) {
+ symbol = token.identifier.symbol;
next_token();
entity = get_entity(symbol, NAMESPACE_NORMAL);
&& entity->kind != ENTITY_NAMESPACE
&& entity->base.parent_scope == current_scope) {
if (is_entity_valid(entity)) {
- error_redefined_as_different_kind(&token.source_position,
+ error_redefined_as_different_kind(&token.base.source_position,
entity, ENTITY_NAMESPACE);
}
entity = NULL;
}
if (entity == NULL) {
- entity = allocate_entity_zero(ENTITY_NAMESPACE);
- entity->base.symbol = symbol;
- entity->base.source_position = token.source_position;
- entity->base.namespc = NAMESPACE_NORMAL;
+ entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol);
+ entity->base.source_position = token.base.source_position;
entity->base.parent_scope = current_scope;
}
- if (token.type == '=') {
+ if (token.kind == '=') {
/* TODO: parse namespace alias */
panic("namespace alias definition not supported yet");
}
environment_push(entity);
append_entity(current_scope, entity);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&entity->namespacee.members);
+ PUSH_SCOPE(&entity->namespacee.members);
entity_t *old_current_entity = current_entity;
current_entity = entity;
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);
+ POP_SCOPE();
}
/**
/* declaration or statement */
add_anchor_token(';');
- switch (token.type) {
+ switch (token.kind) {
case T_IDENTIFIER: {
- token_type_t la1_type = (token_type_t)look_ahead(1)->type;
+ token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
if (la1_type == ':') {
statement = parse_label_statement();
- } else if (is_typedef_symbol(token.symbol)) {
+ } else if (is_typedef_symbol(token.identifier.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.symbol, NAMESPACE_NORMAL) != NULL) {
+ if (get_entity(token.identifier.symbol, NAMESPACE_NORMAL) != NULL) {
default:
statement = parse_expression_statement();
} else {
break;
}
- case T___extension__:
+ 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. */
- while (next_if(T___extension__)) {}
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
statement = intern_parse_statement();
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
break;
+ }
DECLARATION_START
statement = parse_declaration_statement();
{
statement_t *statement = intern_parse_statement();
- if (statement->kind == STATEMENT_EXPRESSION && warning.unused_value) {
+ if (statement->kind == STATEMENT_EXPRESSION) {
expression_t *expression = statement->expression.expression;
if (!expression_has_effect(expression)) {
- warningf(&expression->base.source_position,
- "statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
}
}
statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
PUSH_PARENT(statement);
+ PUSH_SCOPE(&statement->compound.scope);
eat('{');
add_anchor_token('}');
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);
-
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.type != '}') {
- if (token.type == T_EOF) {
+ while (token.kind != '}') {
+ if (token.kind == T_EOF) {
errorf(&statement->base.source_position,
"EOF while parsing compound statement");
break;
continue;
}
- if (warning.declaration_after_statement) {
- if (sub_statement->kind != STATEMENT_DECLARATION) {
- only_decls_so_far = false;
- } else if (!only_decls_so_far) {
- warningf(&sub_statement->base.source_position,
- "ISO C90 forbids mixed declarations and code");
- }
+ if (sub_statement->kind != STATEMENT_DECLARATION) {
+ only_decls_so_far = false;
+ } else if (!only_decls_so_far) {
+ source_position_t const *const pos = &sub_statement->base.source_position;
+ warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code");
}
*anchor = sub_statement;
next_token();
/* look over all statements again to produce no effect warnings */
- if (warning.unused_value) {
+ if (is_warn_on(WARN_UNUSED_VALUE)) {
statement_t *sub_statement = statement->compound.statements;
for (; sub_statement != NULL; sub_statement = sub_statement->base.next) {
if (sub_statement->kind != STATEMENT_EXPRESSION)
expression_t *expression = sub_statement->expression.expression;
if (!expression_has_effect(expression)) {
- warningf(&expression->base.source_position,
- "statement has no effect");
+ warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
}
}
}
rem_anchor_token('&');
rem_anchor_token('!');
rem_anchor_token('}');
- assert(current_scope == &statement->compound.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
- POP_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
}
*/
static void check_unused_globals(void)
{
- if (!warning.unused_function && !warning.unused_variable)
+ if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE))
return;
for (const entity_t *entity = file_scope->entities; entity != NULL;
declaration->storage_class != STORAGE_CLASS_STATIC)
continue;
- type_t *const type = declaration->type;
- const char *s;
+ warning_t why;
+ char const *s;
if (entity->kind == ENTITY_FUNCTION) {
/* inhibit warning for static inline functions */
if (entity->function.is_inline)
continue;
- s = entity->function.statement != NULL ? "defined" : "declared";
+ why = WARN_UNUSED_FUNCTION;
+ s = entity->function.statement != NULL ? "defined" : "declared";
} else {
- s = "defined";
+ why = WARN_UNUSED_VARIABLE;
+ s = "defined";
}
- warningf(&declaration->base.source_position, "'%#T' %s but not used",
- type, declaration->base.symbol, s);
+ warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s);
}
}
{
eat(T_extern);
- const char *linkage = parse_string_literals().begin;
+ source_position_t const pos = *HERE;
+ char const *const linkage = parse_string_literals().begin;
linkage_kind_t old_linkage = current_linkage;
linkage_kind_t new_linkage;
} else if (strcmp(linkage, "C++") == 0) {
new_linkage = LINKAGE_CXX;
} else {
- errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+ errorf(&pos, "linkage string \"%s\" not recognized", linkage);
new_linkage = LINKAGE_INVALID;
}
current_linkage = new_linkage;
static void parse_external(void)
{
- switch (token.type) {
+ switch (token.kind) {
+ case T_extern:
+ if (look_ahead(1)->kind == T_STRING_LITERAL) {
+ parse_linkage_specification();
+ } else {
DECLARATION_START_NO_EXTERN
case T_IDENTIFIER:
case T___extension__:
/* 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;
-
- case T_extern:
- if (look_ahead(1)->type == T_STRING_LITERAL) {
- parse_linkage_specification();
- } else {
+ case '&': /* & x; -> int& x; (and error later, because C++ has no
+ implicit int) */
+ case '*': /* * x; -> int* x; */
+ case '(': /* (x); -> int (x); */
+ PUSH_EXTENSION();
parse_external_declaration();
+ POP_EXTENSION();
}
return;
case ';':
if (!strict_mode) {
- if (warning.other)
- warningf(HERE, "stray ';' outside of function");
+ warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
next_token();
return;
}
default:
errorf(HERE, "stray %K outside of function", &token);
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
return;
}
#ifndef NDEBUG
/* make a copy of the anchor set, so we can check if it is restored after parsing */
- unsigned char token_anchor_copy[T_LAST_TOKEN];
+ unsigned short token_anchor_copy[T_LAST_TOKEN];
memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
#endif
- while (token.type != T_EOF && token.type != '}') {
+ while (token.kind != T_EOF && token.kind != '}') {
#ifndef NDEBUG
- bool anchor_leak = false;
for (int i = 0; i < T_LAST_TOKEN; ++i) {
- unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
+ unsigned short count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
/* the anchor set and its copy differs */
- errorf(HERE, "Leaked anchor token %k %d times", i, count);
- anchor_leak = true;
+ internal_errorf(HERE, "Leaked anchor token %k %d times", i, count);
}
}
if (in_gcc_extension) {
/* an gcc extension scope was not closed */
- errorf(HERE, "Leaked __extension__");
- anchor_leak = true;
+ internal_errorf(HERE, "Leaked __extension__");
}
-
- if (anchor_leak)
- abort();
#endif
parse_external();
while (true) {
parse_externals();
- if (token.type == T_EOF)
+ if (token.kind == T_EOF)
break;
errorf(HERE, "stray %K outside of function", &token);
- if (token.type == '(' || token.type == '{' || token.type == '[')
- eat_until_matching_token(token.type);
+ if (token.kind == '(' || token.kind == '{' || token.kind == '[')
+ eat_until_matching_token(token.kind);
next_token();
}
}
+void set_default_visibility(elf_visibility_tag_t visibility)
+{
+ default_visibility = visibility;
+}
+
/**
* Parse the input.
*
{
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);
+ declaration_t *const decl = incomplete_arrays[i];
+ type_t *const type = skip_typeref(decl->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);
- }
+ source_position_t const *const pos = &decl->base.source_position;
+ warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl);
type_t *const new_type = duplicate_type(type);
new_type->array.size_constant = true;