static int lookahead_bufpos;
static stack_entry_t *environment_stack = NULL;
static stack_entry_t *label_stack = NULL;
+static stack_entry_t *local_label_stack = NULL;
static scope_t *global_scope = NULL;
static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
[EXPR_VA_START] = sizeof(va_start_expression_t),
[EXPR_VA_ARG] = sizeof(va_arg_expression_t),
[EXPR_STATEMENT] = sizeof(statement_expression_t),
+ [EXPR_LABEL_ADDRESS] = sizeof(label_address_expression_t),
};
if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) {
return sizes[EXPR_UNARY_FIRST];
}
/**
- * Returns the index of the top element of the label stack.
+ * Returns the index of the top element of the global label stack.
*/
static size_t label_top(void)
{
return ARR_LEN(label_stack);
}
+/**
+ * Returns the index of the top element of the local label stack.
+ */
+static size_t local_label_top(void)
+{
+ return ARR_LEN(local_label_stack);
+}
+
/**
* Return the next token.
*/
ARR_APP1(stack_entry_t, *stack_ptr, entry);
}
+/**
+ * Push a declaration on the environment stack.
+ *
+ * @param declaration the declaration
+ */
static void environment_push(declaration_t *declaration)
{
assert(declaration->source_position.input_name != NULL);
}
/**
- * Push a declaration of the label stack.
+ * Push a declaration on the global label stack.
*
* @param declaration the declaration
*/
stack_push(&label_stack, declaration);
}
+/**
+ * Push a declaration of the local label stack.
+ *
+ * @param declaration the declaration
+ */
+static void local_label_push(declaration_t *declaration)
+{
+ assert(declaration->parent_scope != NULL);
+ stack_push(&local_label_stack, declaration);
+}
+
/**
* pops symbols from the environment stack until @p new_top is the top element
*/
ARR_SHRINKLEN(*stack_ptr, (int) new_top);
}
+/**
+ * Pop all entries from the environment stack until the new_top
+ * is reached.
+ *
+ * @param new_top the new stack top
+ */
static void environment_pop_to(size_t new_top)
{
stack_pop_to(&environment_stack, new_top);
}
/**
- * Pop all entries on the label stack until the new_top
+ * Pop all entries from the global label stack until the new_top
* is reached.
*
* @param new_top the new stack top
stack_pop_to(&label_stack, new_top);
}
+/**
+ * Pop all entries from the local label stack until the new_top
+ * is reached.
+ *
+ * @param new_top the new stack top
+ */
+static void local_label_pop_to(size_t new_top)
+{
+ stack_pop_to(&local_label_stack, new_top);
+}
+
+
static int get_akind_rank(atomic_type_kind_t akind)
{
return (int) akind;
return decl;
}
+/**
+ * Finish the construction of a struct type by calculating
+ * its size, offsets, alignment.
+ */
+static void finish_struct_type(compound_type_t *type) {
+ if (type->declaration == NULL)
+ return;
+ declaration_t *struct_decl = type->declaration;
+ if (! struct_decl->init.complete)
+ return;
+
+ il_size_t size = 0;
+ il_size_t new_size;
+ il_alignment_t alignment = 1;
+ bool need_pad = false;
+
+ declaration_t *entry = struct_decl->scope.declarations;
+ for (; entry != NULL; entry = entry->next) {
+ if (entry->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ type_t *m_type = skip_typeref(entry->type);
+ il_alignment_t m_alignment = m_type->base.alignment;
+
+ new_size = (size + m_alignment - 1) & -m_alignment;
+ if (m_alignment > alignment)
+ alignment = m_alignment;
+ if (new_size > size)
+ need_pad = true;
+ entry->offset = new_size;
+ size = new_size + m_type->base.size;
+ }
+ if (type->base.alignment != 0) {
+ alignment = type->base.alignment;
+ }
+
+ new_size = (size + alignment - 1) & -alignment;
+ if (new_size > size)
+ need_pad = true;
+
+ if (warning.padded && need_pad) {
+ warningf(&struct_decl->source_position,
+ "'%#T' needs padding", type, struct_decl->symbol);
+ }
+ if (warning.packed && !need_pad) {
+ warningf(&struct_decl->source_position,
+ "superfluous packed attribute on '%#T'",
+ type, struct_decl->symbol);
+ }
+
+ type->base.size = new_size;
+ type->base.alignment = alignment;
+}
+
+/**
+ * Finish the construction of an union type by calculating
+ * its size and alignment.
+ */
+static void finish_union_type(compound_type_t *type) {
+ if (type->declaration == NULL)
+ return;
+ declaration_t *union_decl = type->declaration;
+ if (! union_decl->init.complete)
+ return;
+
+ il_size_t size = 0;
+ il_alignment_t alignment = 1;
+
+ declaration_t *entry = union_decl->scope.declarations;
+ for (; entry != NULL; entry = entry->next) {
+ if (entry->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ type_t *m_type = skip_typeref(entry->type);
+
+ entry->offset = 0;
+ if (m_type->base.size > size)
+ size = m_type->base.size;
+ if (m_type->base.alignment > alignment)
+ alignment = m_type->base.alignment;
+ }
+ if (type->base.alignment != 0) {
+ alignment = type->base.alignment;
+ }
+ size = (size + alignment - 1) & -alignment;
+ type->base.size = size;
+ type->base.alignment = alignment;
+}
+
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
type_t *type = NULL;
type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE);
type->compound.declaration = parse_compound_type_specifier(true);
+ finish_struct_type(&type->compound);
break;
}
case T_union: {
if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
break;
+ finish_union_type(&type->compound);
}
case T_enum:
type = parse_enum_specifier();
declaration->type = type;
if (is_type_incomplete(skip_typeref(type))) {
- errorf(pos, "incomplete type '%T' not allowed for parameter '%Y'",
+ errorf(pos, "parameter '%#T' is of incomplete type",
orig_type, declaration->symbol);
}
}
next_token();
add_anchor_token(')');
inner_types = parse_inner_declarator(declaration, may_be_abstract);
- /* All later declarators only modify the return type, not declaration */
- declaration = NULL;
+ if (inner_types != NULL) {
+ /* All later declarators only modify the return type, not declaration */
+ declaration = NULL;
+ }
rem_anchor_token(')');
expect(')');
break;
if (is_type_function(type)) {
errorf(&declaration->source_position,
- "function %#T is initialized like a variable",
+ "function '%#T' is initialized like a variable",
orig_type, declaration->symbol);
orig_type = type_error_type;
}
for (const goto_statement_t *goto_statement = goto_first;
goto_statement != NULL;
goto_statement = goto_statement->next) {
+ /* skip computed gotos */
+ if (goto_statement->expression != NULL)
+ continue;
+
declaration_t *label = goto_statement->label;
label->used = true;
}
case STATEMENT_GOTO:
- next = stmt->gotos.label->init.statement;
- if (next == NULL) /* missing label */
- return;
+ if (stmt->gotos.expression) {
+ statement_t *parent = stmt->base.parent;
+ if (parent == NULL) /* top level goto */
+ return;
+ next = parent;
+ } else {
+ next = stmt->gotos.label->init.statement;
+ if (next == NULL) /* missing label */
+ return;
+ }
break;
case STATEMENT_LABEL:
{
declaration_t *last_declaration = struct_declaration->scope.declarations;
if (last_declaration != NULL) {
- while(last_declaration->next != NULL) {
+ while (last_declaration->next != NULL) {
last_declaration = last_declaration->next;
}
}
- while(1) {
+ while (true) {
declaration_t *declaration;
if (token.type == ':') {
eat('{');
add_anchor_token('}');
- while(token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}' && token.type != T_EOF) {
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
{
switch (expression->kind) {
case EXPR_REFERENCE: return expression->reference.declaration->type;
- case EXPR_SELECT: return expression->select.compound_entry->type;
+
+ case EXPR_SELECT:
+ return get_qualified_type(expression->select.compound_entry->type,
+ expression->base.type->base.qualifiers);
case EXPR_UNARY_DEREFERENCE: {
const expression_t *const value = expression->unary.value;
return create_invalid_expression();
}
+/**
+ * Return the declaration for a given label symbol or create a new one.
+ *
+ * @param symbol the symbol of the label
+ */
+static declaration_t *get_label(symbol_t *symbol)
+{
+ declaration_t *candidate;
+ assert(current_function != NULL);
+
+ candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+ /* if we found a local label, we already created the declaration */
+ if (candidate != NULL) {
+ assert(candidate->parent_scope == scope);
+ return candidate;
+ }
+
+ candidate = get_declaration(symbol, NAMESPACE_LABEL);
+ /* if we found a label in the same function, then we already created the
+ * declaration */
+ if (candidate != NULL
+ && candidate->parent_scope == ¤t_function->scope) {
+ return candidate;
+ }
+
+ /* otherwise we need to create a new one */
+ declaration_t *const declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_LABEL;
+ declaration->symbol = symbol;
+
+ label_push(declaration);
+
+ return declaration;
+}
+
+/**
+ * Parses a GNU && label address expression.
+ */
+static expression_t *parse_label_address(void)
+{
+ source_position_t source_position = token.source_position;
+ eat(T_ANDAND);
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+ goto end_error;
+ }
+ symbol_t *symbol = token.v.symbol;
+ next_token();
+
+ declaration_t *label = get_label(symbol);
+
+ 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 */
+ expression->base.type = type_void_ptr;
+ expression->label_address.declaration = label;
+ return expression;
+end_error:
+ return create_invalid_expression();
+}
+
/**
* Parse a microsoft __noop expression.
*/
case T___builtin_constant_p: return parse_builtin_constant();
case T___builtin_prefetch: return parse_builtin_prefetch();
case T__assume: return parse_assume();
+ case T_ANDAND:
+ if (c_mode & _GNUC)
+ return parse_label_address();
+ break;
case '(': return parse_parenthesized_expression();
case T___noop: return parse_noop_expression();
type_t *const orig_type = compound->base.type;
type_t *const type = skip_typeref(orig_type);
- type_t *type_left = type;
+ type_t *type_left;
bool saw_error = false;
if (is_type_pointer(type)) {
if (!is_pointer) {
errorf(HERE,
"request for member '%Y' in something not a struct or union, but '%T'",
- symbol, type_left);
+ symbol, orig_type);
saw_error = true;
}
- type_left = type->pointer.points_to;
- } else if (is_pointer) {
- if (is_type_valid(type)) {
+ type_left = skip_typeref(type->pointer.points_to);
+ } else {
+ if (is_pointer && is_type_valid(type)) {
errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
}
- type_left = skip_typeref(type_left);
declaration_t *entry;
if (type_left->kind == TYPE_COMPOUND_STRUCT ||
if (!declaration->init.complete) {
errorf(HERE, "request for member '%Y' of incomplete type '%T'",
symbol, type_left);
- return create_invalid_expression();
+ goto create_error_entry;
}
entry = find_compound_entry(declaration, symbol);
}
select->select.compound_entry = entry;
+
+ type_t *const res_type =
+ get_qualified_type(entry->type, type_left->base.qualifiers);
+
/* we always do the auto-type conversions; the & and sizeof parser contains
* code to revert this! */
- select->base.type = automatic_type_conversion(entry->type);
+ select->base.type = automatic_type_conversion(res_type);
- type_t *skipped = skip_typeref(entry->type);
+ type_t *skipped = skip_typeref(res_type);
if (skipped->kind == TYPE_BITFIELD) {
select->base.type = skipped->bitfield.base_type;
}
to = type_void;
}
- type_t *const copy = duplicate_type(to);
- copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers;
-
- type_t *const type = typehash_insert(copy);
- if (type != copy)
- free_type(copy);
-
+ type_t *const type =
+ 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)) {
warningf(&conditional->base.source_position,
if (!is_type_pointer(type)) {
if (is_type_valid(type)) {
errorf(&expression->base.source_position,
- "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type);
+ "Unary '*' needs pointer or array type, but type '%T' given", orig_type);
}
return;
}
expression_t *left = expression->left;
type_t *orig_type_left = left->base.type;
- type_t *type_left = revert_automatic_type_conversion(left);
- type_left = skip_typeref(orig_type_left);
-
if (!is_valid_assignment_lhs(left))
return;
case EXPR_WIDE_CHARACTER_CONSTANT: return false;
case EXPR_STRING_LITERAL: return false;
case EXPR_WIDE_STRING_LITERAL: return false;
+ case EXPR_LABEL_ADDRESS: return false;
case EXPR_CALL: {
const call_expression_t *const call = &expr->call;
return create_invalid_statement();
}
-/**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol the symbol of the label
- */
-static declaration_t *get_label(symbol_t *symbol)
-{
- declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL);
- assert(current_function != NULL);
- /* if we found a label in the same function, then we already created the
- * declaration */
- if (candidate != NULL
- && candidate->parent_scope == ¤t_function->scope) {
- return candidate;
- }
-
- /* otherwise we need to create a new one */
- declaration_t *const declaration = allocate_declaration_zero();
- declaration->namespc = NAMESPACE_LABEL;
- declaration->symbol = symbol;
-
- label_push(declaration);
-
- return declaration;
-}
-
/**
* Parse a label statement.
*/
PUSH_PARENT(statement);
- /* if source position is already set then the label is defined twice,
- * otherwise it was just mentioned in a goto so far */
- if (label->source_position.input_name != NULL) {
+ /* if statement is already set then the label is defined twice,
+ * otherwise it was just mentioned in a goto/local label declaration so far */
+ if (label->init.statement != NULL) {
errorf(HERE, "duplicate label '%Y' (declared %P)",
symbol, &label->source_position);
} else {
*/
static statement_t *parse_goto(void)
{
+ source_position_t source_position = token.source_position;
eat(T_goto);
- if (token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_statement();
- goto end_error;
- }
- symbol_t *symbol = token.v.symbol;
- next_token();
+ statement_t *statement;
+ if (c_mode & _GNUC && token.type == '*') {
+ next_token();
+ expression_t *expression = parse_expression();
- declaration_t *label = get_label(symbol);
+ /* Argh: although documentation say the expression must be of type void *,
+ * gcc excepts anything that can be casted into void * without error */
+ type_t *type = expression->base.type;
- statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
- statement->base.source_position = token.source_position;
+ if (type != type_error_type) {
+ if (!is_type_pointer(type) && !is_type_integer(type)) {
+ errorf(&source_position, "cannot convert to a pointer type");
+ } else if (type != type_void_ptr) {
+ warningf(&source_position,
+ "type of computed goto expression should be 'void*' not '%T'", type);
+ }
+ expression = create_implicit_cast(expression, type_void_ptr);
+ }
- statement->gotos.label = label;
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ statement->base.source_position = source_position;
+ statement->gotos.expression = expression;
+ } else {
+ if (token.type != T_IDENTIFIER) {
+ if (c_mode & _GNUC)
+ parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+ else
+ parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+ eat_statement();
+ goto end_error;
+ }
+ symbol_t *symbol = token.v.symbol;
+ next_token();
+
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ statement->base.source_position = source_position;
+ statement->gotos.label = get_label(symbol);
+ }
/* remember the goto's in a list for later checking */
if (goto_last == NULL) {
/**
* Parse a __leave statement.
*/
-static statement_t *parse_leave(void)
+static statement_t *parse_leave_statement(void)
{
if (current_try == NULL) {
errorf(HERE, "__leave statement not within __try");
return statement;
}
+static statement_t *parse_local_label_declaration(void) {
+ statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
+ statement->base.source_position = token.source_position;
+
+ eat(T___label__);
+
+ declaration_t *begin = NULL, *end = NULL;
+
+ while (true) {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing local label declaration",
+ T_IDENTIFIER, NULL);
+ goto end_error;
+ }
+ symbol_t *symbol = token.v.symbol;
+ declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+ if (declaration != NULL) {
+ errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)",
+ symbol, &declaration->source_position);
+ } else {
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_LOCAL_LABEL;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_scope = scope;
+ declaration->init.statement = NULL;
+
+ if (end != NULL)
+ end->next = declaration;
+ end = declaration;
+ if (begin == NULL)
+ begin = declaration;
+
+ local_label_push(declaration);
+ }
+ next_token();
+
+ if (token.type != ',')
+ break;
+ next_token();
+ }
+ eat(';');
+end_error:
+ statement->declaration.declarations_begin = begin;
+ statement->declaration.declarations_end = end;
+ return statement;
+}
+
/**
* Parse a statement.
* There's also parse_statement() which additionally checks for
statement = parse_declaration_statement();
break;
+ case T___label__:
+ statement = parse_local_label_declaration();
+ break;
+
case ';': statement = parse_empty_statement(); break;
case '{': statement = parse_compound_statement(false); break;
- case T___leave: statement = parse_leave(); break;
+ case T___leave: statement = parse_leave_statement(); break;
case T___try: statement = parse_ms_try_statment(); break;
case T_asm: statement = parse_asm_statement(); break;
case T_break: statement = parse_break(); break;
add_anchor_token('}');
int top = environment_top();
+ int top_local = local_label_top();
scope_t *last_scope = scope;
set_scope(&statement->compound.scope);
assert(scope == &statement->compound.scope);
set_scope(last_scope);
environment_pop_to(top);
+ local_label_pop_to(top_local);
POP_PARENT;
return statement;
{
environment_stack = NEW_ARR_F(stack_entry_t, 0);
label_stack = NEW_ARR_F(stack_entry_t, 0);
+ local_label_stack = NEW_ARR_F(stack_entry_t, 0);
diagnostic_count = 0;
error_count = 0;
warning_count = 0;
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);
+ DEL_ARR_F(local_label_stack);
translation_unit_t *result = unit;
unit = NULL;
void parse(void)
{
lookahead_bufpos = 0;
- for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+ for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
next_token();
}
parse_translation_unit();