+ case STATEMENT_MS_TRY: {
+ ms_try_statement_t const *const ms_try = &stmt->ms_try;
+ check_reachable(ms_try->try_statement);
+ next = ms_try->final_statement;
+ break;
+ }
+
+ case STATEMENT_LEAVE: {
+ statement_t *parent = stmt;
+ for (;;) {
+ parent = parent->base.parent;
+ if (parent == NULL) /* __leave not within __try */
+ return;
+
+ if (parent->kind == STATEMENT_MS_TRY) {
+ last = parent;
+ next = parent->ms_try.final_statement;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ while (next == NULL) {
+ next = last->base.parent;
+ if (next == NULL) {
+ noreturn_candidate = false;
+
+ type_t *const type = current_function->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) &&
+ is_type_valid(ret) &&
+ !is_sym_main(current_function->symbol)) {
+ warningf(&stmt->base.source_position,
+ "control reaches end of non-void function");
+ }
+ return;
+ }
+
+ switch (next->kind) {
+ case STATEMENT_INVALID:
+ case STATEMENT_EMPTY:
+ case STATEMENT_DECLARATION:
+ case STATEMENT_EXPRESSION:
+ case STATEMENT_ASM:
+ case STATEMENT_RETURN:
+ case STATEMENT_CONTINUE:
+ case STATEMENT_BREAK:
+ case STATEMENT_GOTO:
+ case STATEMENT_LEAVE:
+ panic("invalid control flow in function");
+
+ case STATEMENT_COMPOUND:
+ case STATEMENT_IF:
+ case STATEMENT_SWITCH:
+ case STATEMENT_LABEL:
+ case STATEMENT_CASE_LABEL:
+ last = next;
+ next = next->base.next;
+ break;
+
+ case STATEMENT_WHILE: {
+continue_while:
+ if (next->base.reachable)
+ return;
+ next->base.reachable = true;
+
+ while_statement_t const *const whiles = &next->whiles;
+ int const val = determine_truth(whiles->condition);
+
+ if (val >= 0)
+ check_reachable(whiles->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_DO_WHILE: {
+continue_do_while:
+ if (next->base.reachable)
+ return;
+ next->base.reachable = true;
+
+ do_while_statement_t const *const dw = &next->do_while;
+ int const val = determine_truth(dw->condition);
+
+ if (val >= 0)
+ check_reachable(dw->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_FOR: {
+continue_for:;
+ for_statement_t *const fors = &next->fors;
+
+ fors->step_reachable = true;
+
+ if (fors->condition_reachable)
+ return;
+ fors->condition_reachable = true;
+
+ expression_t const *const cond = fors->condition;
+ int const val =
+ cond == NULL ? 1 : determine_truth(cond);
+
+ if (val >= 0)
+ check_reachable(fors->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_MS_TRY:
+ last = next;
+ next = next->ms_try.final_statement;
+ break;
+ }
+ }
+
+ if (next == NULL) {
+ next = stmt->base.parent;
+ if (next == NULL) {
+ warningf(&stmt->base.source_position,
+ "control reaches end of non-void function");
+ }
+ }
+
+ check_reachable(next);
+}
+
+static void check_unreachable(statement_t const* const stmt)
+{
+ if (!stmt->base.reachable &&
+ stmt->kind != STATEMENT_DO_WHILE &&
+ stmt->kind != STATEMENT_FOR &&
+ (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) {
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ }
+
+ switch (stmt->kind) {
+ case STATEMENT_INVALID:
+ case STATEMENT_EMPTY:
+ case STATEMENT_RETURN:
+ case STATEMENT_DECLARATION:
+ case STATEMENT_EXPRESSION:
+ case STATEMENT_CONTINUE:
+ case STATEMENT_BREAK:
+ case STATEMENT_GOTO:
+ case STATEMENT_ASM:
+ case STATEMENT_LEAVE:
+ break;
+
+ case STATEMENT_COMPOUND:
+ if (stmt->compound.statements)
+ check_unreachable(stmt->compound.statements);
+ break;
+
+ case STATEMENT_IF:
+ check_unreachable(stmt->ifs.true_statement);
+ if (stmt->ifs.false_statement != NULL)
+ check_unreachable(stmt->ifs.false_statement);
+ break;
+
+ case STATEMENT_SWITCH:
+ check_unreachable(stmt->switchs.body);
+ break;
+
+ case STATEMENT_LABEL:
+ check_unreachable(stmt->label.statement);
+ break;
+
+ case STATEMENT_CASE_LABEL:
+ check_unreachable(stmt->case_label.statement);
+ break;
+
+ case STATEMENT_WHILE:
+ check_unreachable(stmt->whiles.body);
+ break;
+
+ case STATEMENT_DO_WHILE:
+ check_unreachable(stmt->do_while.body);
+ 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");
+ }
+ }
+ break;
+
+ case STATEMENT_FOR: {
+ for_statement_t const* const fors = &stmt->fors;
+
+ // 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");
+ } else {
+ if (!stmt->base.reachable && fors->initialisation != NULL) {
+ warningf(&fors->initialisation->base.source_position,
+ "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");
+ }
+
+ if (!fors->step_reachable && fors->step != NULL) {
+ warningf(&fors->step->base.source_position,
+ "step of for-statement is unreachable");
+ }
+ }
+
+ check_unreachable(fors->body);
+ break;
+ }
+
+ case STATEMENT_MS_TRY: {
+ ms_try_statement_t const *const ms_try = &stmt->ms_try;
+ check_unreachable(ms_try->try_statement);
+ check_unreachable(ms_try->final_statement);
+ }
+ }
+
+ if (stmt->base.next)
+ check_unreachable(stmt->base.next);
+}
+
+static void parse_external_declaration(void)
+{
+ /* function-definitions and declarations both start with declaration
+ * specifiers */
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+
+ add_anchor_token(';');
+ parse_declaration_specifiers(&specifiers);
+ rem_anchor_token(';');
+
+ /* must be a declaration */
+ if (token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers);
+ return;
+ }
+
+ add_anchor_token(',');
+ add_anchor_token('=');
+ add_anchor_token(';');
+ add_anchor_token('{');
+
+ /* declarator is common to both function-definitions and declarations */
+ declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
+
+ rem_anchor_token('{');
+ rem_anchor_token(';');
+ rem_anchor_token('=');
+ rem_anchor_token(',');
+
+ /* must be a declaration */
+ switch (token.type) {
+ case ',':
+ case ';':
+ case '=':
+ parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
+ return;
+ }
+
+ /* must be a function definition */
+ parse_kr_declaration_list(ndeclaration);
+
+ if (token.type != '{') {
+ parse_error_expected("while parsing function definition", '{', NULL);
+ eat_until_matching_token(';');
+ return;
+ }
+
+ type_t *type = ndeclaration->type;
+
+ /* note that we don't skip typerefs: the standard doesn't allow them here
+ * (so we can't use is_type_function here) */
+ if (type->kind != TYPE_FUNCTION) {
+ if (is_type_valid(type)) {
+ errorf(HERE, "declarator '%#T' has a body but is not a function type",
+ type, ndeclaration->symbol);
+ }
+ eat_block();
+ return;
+ }
+
+ if (warning.aggregate_return &&
+ is_type_compound(skip_typeref(type->function.return_type))) {
+ warningf(HERE, "function '%Y' returns an aggregate",
+ ndeclaration->symbol);
+ }
+ if (warning.traditional && !type->function.unspecified_parameters) {
+ warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
+ ndeclaration->symbol);
+ }
+ if (warning.old_style_definition && type->function.unspecified_parameters) {
+ warningf(HERE, "old-style function definition '%Y'",
+ ndeclaration->symbol);
+ }
+
+ /* § 6.7.5.3 (14) a function definition with () means no
+ * parameters (and not unspecified parameters) */
+ if (type->function.unspecified_parameters
+ && type->function.parameters == NULL
+ && !type->function.kr_style_parameters) {
+ type_t *duplicate = duplicate_type(type);
+ duplicate->function.unspecified_parameters = false;
+
+ type = typehash_insert(duplicate);
+ if (type != duplicate) {
+ obstack_free(type_obst, duplicate);
+ }
+ ndeclaration->type = type;
+ }
+
+ declaration_t *const declaration = record_declaration(ndeclaration, true);
+ if (ndeclaration != declaration) {
+ declaration->scope = ndeclaration->scope;
+ }
+ type = skip_typeref(declaration->type);
+
+ /* push function parameters and switch scope */
+ size_t const top = environment_top();
+ scope_push(&declaration->scope);
+
+ declaration_t *parameter = declaration->scope.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ if (parameter->parent_scope == &ndeclaration->scope) {
+ parameter->parent_scope = scope;
+ }
+ assert(parameter->parent_scope == NULL
+ || parameter->parent_scope == scope);
+ parameter->parent_scope = scope;
+ if (parameter->symbol == NULL) {
+ errorf(¶meter->source_position, "parameter name omitted");
+ continue;
+ }
+ environment_push(parameter);
+ }
+
+ if (declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, HERE);
+ eat_block();
+ } else {
+ /* parse function body */
+ int label_stack_top = label_top();
+ declaration_t *old_current_function = current_function;
+ current_function = declaration;
+ current_parent = NULL;
+
+ statement_t *const body = parse_compound_statement(false);
+ declaration->init.statement = body;
+ first_err = true;
+ check_labels();
+ check_declarations();
+ if (warning.return_type ||
+ warning.unreachable_code ||
+ (warning.missing_noreturn && !(declaration->modifiers & DM_NORETURN))) {
+ noreturn_candidate = true;
+ check_reachable(body);
+ if (warning.unreachable_code)
+ check_unreachable(body);
+ if (warning.missing_noreturn &&
+ noreturn_candidate &&
+ !(declaration->modifiers & DM_NORETURN)) {
+ warningf(&body->base.source_position,
+ "function '%#T' is candidate for attribute 'noreturn'",
+ type, declaration->symbol);
+ }
+ }
+
+ assert(current_parent == NULL);
+ assert(current_function == declaration);
+ current_function = old_current_function;
+ label_pop_to(label_stack_top);
+ }
+
+ assert(scope == &declaration->scope);
+ scope_pop();
+ 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, source_position);
+
+ 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 = skipped_type->base.size * 8;
+ }
+
+ if (is_constant_expression(size)) {
+ long v = fold_constant(size);
+
+ if (v < 0) {
+ errorf(source_position, "negative width in bit-field '%Y'",
+ symbol);
+ } else if (v == 0) {
+ errorf(source_position, "zero width for bit-field '%Y'",
+ symbol);
+ } else if (bit_size > 0 && (il_size_t)v > bit_size) {
+ errorf(source_position, "width of '%Y' exceeds its type",
+ symbol);
+ } else {
+ type->bitfield.bit_size = v;
+ }
+ }
+
+ return type;
+}
+
+static declaration_t *find_compound_entry(declaration_t *compound_declaration,
+ symbol_t *symbol)
+{
+ declaration_t *iter = compound_declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if (iter->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ if (iter->symbol == NULL) {
+ type_t *type = skip_typeref(iter->type);
+ if (is_type_compound(type)) {
+ declaration_t *result
+ = find_compound_entry(type->compound.declaration, symbol);
+ if (result != NULL)
+ return result;
+ }
+ continue;
+ }
+
+ if (iter->symbol == symbol) {
+ return iter;
+ }
+ }
+
+ return NULL;
+}
+
+static void parse_compound_declarators(declaration_t *struct_declaration,
+ const declaration_specifiers_t *specifiers)
+{
+ declaration_t *last_declaration = struct_declaration->scope.declarations;
+ if (last_declaration != NULL) {
+ while (last_declaration->next != NULL) {
+ last_declaration = last_declaration->next;
+ }
+ }
+
+ while (true) {
+ declaration_t *declaration;
+
+ if (token.type == ':') {
+ source_position_t source_position = *HERE;
+ next_token();
+
+ type_t *base_type = specifiers->type;
+ expression_t *size = parse_constant_expression();
+
+ type_t *type = make_bitfield_type(base_type, size,
+ &source_position, sym_anonymous);
+
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_NORMAL;