#include <stdarg.h>
#include <stdbool.h>
+#include "adt/strutil.h"
#include "parser.h"
#include "diagnostic.h"
#include "format_check.h"
#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"
static statement_t *current_loop = NULL;
static statement_t *current_parent = NULL;
static ms_try_statement_t *current_try = NULL;
-static linkage_kind_t current_linkage = LINKAGE_INVALID;
+static linkage_kind_t current_linkage;
static goto_statement_t *goto_first = NULL;
static goto_statement_t **goto_anchor = NULL;
static label_statement_t *label_first = NULL;
static size_t get_statement_struct_size(statement_kind_t kind)
{
static const size_t sizes[] = {
- [STATEMENT_INVALID] = sizeof(invalid_statement_t),
- [STATEMENT_EMPTY] = sizeof(empty_statement_t),
- [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
- [STATEMENT_RETURN] = sizeof(return_statement_t),
- [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
- [STATEMENT_IF] = sizeof(if_statement_t),
- [STATEMENT_SWITCH] = sizeof(switch_statement_t),
- [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
- [STATEMENT_CONTINUE] = sizeof(statement_base_t),
- [STATEMENT_BREAK] = sizeof(statement_base_t),
- [STATEMENT_GOTO] = sizeof(goto_statement_t),
- [STATEMENT_LABEL] = sizeof(label_statement_t),
- [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
- [STATEMENT_WHILE] = sizeof(while_statement_t),
- [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
- [STATEMENT_FOR] = sizeof(for_statement_t),
- [STATEMENT_ASM] = sizeof(asm_statement_t),
- [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
- [STATEMENT_LEAVE] = sizeof(leave_statement_t)
+ [STATEMENT_ERROR] = sizeof(statement_base_t),
+ [STATEMENT_EMPTY] = sizeof(statement_base_t),
+ [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
+ [STATEMENT_RETURN] = sizeof(return_statement_t),
+ [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
+ [STATEMENT_IF] = sizeof(if_statement_t),
+ [STATEMENT_SWITCH] = sizeof(switch_statement_t),
+ [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
+ [STATEMENT_CONTINUE] = sizeof(statement_base_t),
+ [STATEMENT_BREAK] = sizeof(statement_base_t),
+ [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t),
+ [STATEMENT_GOTO] = sizeof(goto_statement_t),
+ [STATEMENT_LABEL] = sizeof(label_statement_t),
+ [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
+ [STATEMENT_WHILE] = sizeof(while_statement_t),
+ [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
+ [STATEMENT_FOR] = sizeof(for_statement_t),
+ [STATEMENT_ASM] = sizeof(asm_statement_t),
+ [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
+ [STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
static size_t get_expression_struct_size(expression_kind_t kind)
{
static const size_t sizes[] = {
- [EXPR_INVALID] = sizeof(expression_base_t),
+ [EXPR_ERROR] = sizeof(expression_base_t),
[EXPR_REFERENCE] = sizeof(reference_expression_t),
- [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t),
+ [EXPR_ENUM_CONSTANT] = 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),
* Creates a new invalid expression at the source position
* of the current token.
*/
-static expression_t *create_invalid_expression(void)
+static expression_t *create_error_expression(void)
{
- return allocate_expression_zero(EXPR_INVALID);
+ expression_t *expression = allocate_expression_zero(EXPR_ERROR);
+ expression->base.type = type_error_type;
+ return expression;
}
/**
* Creates a new invalid statement.
*/
-static statement_t *create_invalid_statement(void)
+static statement_t *create_error_statement(void)
{
- return allocate_statement_zero(STATEMENT_INVALID);
+ return allocate_statement_zero(STATEMENT_ERROR);
}
/**
static entity_t *get_entity(const symbol_t *const symbol,
namespace_tag_t namespc)
{
- assert(namespc != NAMESPACE_INVALID);
entity_t *entity = symbol->entity;
for (; entity != NULL; entity = entity->base.symbol_next) {
if ((namespace_tag_t)entity->base.namespc == namespc)
{
symbol_t *symbol = entity->base.symbol;
entity_namespace_t namespc = entity->base.namespc;
- assert(namespc != NAMESPACE_INVALID);
+ assert(namespc != 0);
/* replace/add entity into entity list of the symbol */
entity_t **anchor;
stack_pop_to(&label_stack, new_top);
}
-static int get_akind_rank(atomic_type_kind_t akind)
+static atomic_type_kind_t get_akind(const type_t *type)
{
- return (int) akind;
-}
-
-/**
- * Return the type rank for an atomic type.
- */
-static int get_rank(const type_t *type)
-{
- assert(!is_typeref(type));
- if (type->kind == TYPE_ENUM)
- return get_akind_rank(type->enumt.akind);
-
- assert(type->kind == TYPE_ATOMIC);
- return get_akind_rank(type->atomic.akind);
+ assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
+ || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
+ return type->atomic.akind;
}
/**
*/
static type_t *promote_integer(type_t *type)
{
- if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT))
+ if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
type = type_int;
return type;
points_to_left = get_unqualified_type(points_to_left);
points_to_right = get_unqualified_type(points_to_right);
- if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID))
+ if (is_type_void(points_to_left))
return res;
- if (is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(points_to_right)) {
/* ISO/IEC 14882:1998(E) §C.1.2:6 */
return c_mode & _CXX ? ASSIGN_ERROR_INCOMPATIBLE : res;
}
return result;
}
-/**
- * compare two string, ignoring double underscores on the second.
- */
-static int strcmp_underscore(const char *s1, const char *s2)
-{
- if (s2[0] == '_' && s2[1] == '_') {
- size_t len2 = strlen(s2);
- size_t len1 = strlen(s1);
- if (len1 == len2-4 && s2[len2-2] == '_' && s2[len2-1] == '_') {
- return strncmp(s1, s2+2, len2-4);
- }
- }
-
- return strcmp(s1, s2);
-}
-
static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
{
attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
}
const char *attribute_name = get_attribute_name(kind);
- if (attribute_name != NULL
- && strcmp_underscore(attribute_name, name) == 0)
+ if (attribute_name != NULL && streq_underscore(attribute_name, name))
break;
}
ent = determine_lhs_ent(ref, lhs_ent);
lhs_ent = ent;
} else {
- mark_vars_read(expr->select.compound, lhs_ent);
+ mark_vars_read(ref, lhs_ent);
}
mark_vars_read(expr->array_access.index, lhs_ent);
return ent;
}
case EXPR_SELECT: {
- if (is_type_compound(skip_typeref(expr->base.type))) {
+ mark_vars_read(expr->select.compound, lhs_ent);
+ if (is_type_compound(skip_typeref(expr->base.type)))
return determine_lhs_ent(expr->select.compound, lhs_ent);
- } else {
- mark_vars_read(expr->select.compound, lhs_ent);
- return NULL;
- }
+ return NULL;
}
case EXPR_UNARY_DEREFERENCE: {
return;
case EXPR_ARRAY_ACCESS: {
+ mark_vars_read(expr->array_access.index, lhs_ent);
expression_t *const ref = expr->array_access.array_ref;
+ if (!is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
+ if (lhs_ent == ENT_ANY)
+ lhs_ent = NULL;
+ }
mark_vars_read(ref, lhs_ent);
- lhs_ent = determine_lhs_ent(ref, lhs_ent);
- mark_vars_read(expr->array_access.index, lhs_ent);
return;
}
case EXPR_UNARY_CAST:
/* Special case: Use void cast to mark a variable as "read" */
- if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
+ if (is_type_void(skip_typeref(expr->base.type)))
lhs_ent = NULL;
goto unary;
determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
- EXPR_LITERAL_CASES
- case EXPR_INVALID:
+ case EXPR_LITERAL_CASES:
+ case EXPR_ERROR:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO init?
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
- case EXPR_REFERENCE_ENUM_VALUE:
+ case EXPR_ENUM_CONSTANT:
return;
}
return result;
}
-/**
- * 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_linker_constant(expression) != EXPR_CLASS_VARIABLE;
-}
-
/**
* Parses an scalar initializer.
*
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
- if (must_be_constant && !is_initializer_constant(expression)) {
+ if (must_be_constant && !is_linker_constant(expression)) {
errorf(&expression->base.source_position,
"initialisation expression '%E' is not constant",
expression);
top->type = top_type;
if (is_type_compound(top_type)) {
- compound_t *compound = top_type->compound.compound;
- entity_t *entry = compound->members.entities;
+ compound_t *const compound = top_type->compound.compound;
+ entity_t *const entry = skip_unnamed_bitfields(compound->members.entities);
if (entry != NULL) {
- assert(entry->kind == ENTITY_COMPOUND_MEMBER);
top->v.compound_entry = &entry->declaration;
path->top_type = entry->declaration.type;
} else {
} else if (is_type_struct(type)) {
declaration_t *entry = top->v.compound_entry;
- entity_t *next_entity = entry->base.next;
+ entity_t *const next_entity = skip_unnamed_bitfields(entry->base.next);
if (next_entity != NULL) {
assert(is_declaration(next_entity));
entry = &next_entity->declaration;
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
- if (env->must_be_constant && !is_initializer_constant(expression)) {
+ if (env->must_be_constant && !is_linker_constant(expression)) {
errorf(&expression->base.source_position,
"Initialisation expression '%E' is not constant",
expression);
entity->base.parent_scope = current_scope;
}
- type_t *const type = allocate_type_zero(TYPE_ENUM);
- type->enumt.enume = &entity->enume;
- type->enumt.akind = ATOMIC_TYPE_INT;
+ type_t *const type = allocate_type_zero(TYPE_ENUM);
+ type->enumt.enume = &entity->enume;
+ type->enumt.base.akind = ATOMIC_TYPE_INT;
if (token.kind == '{') {
if (symbol != NULL) {
symbol_t **prop;
symbol_t *symbol = token.identifier.symbol;
- if (strcmp(symbol->string, "put") == 0) {
+ if (streq(symbol->string, "put")) {
prop = &property->put_symbol;
- } else if (strcmp(symbol->string, "get") == 0) {
+ } else if (streq(symbol->string, "get")) {
prop = &property->get_symbol;
} else {
errorf(HERE, "expected put or get in property declspec");
for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST;
++k) {
const char *attribute_name = get_attribute_name(k);
- if (attribute_name != NULL && strcmp(attribute_name, name) == 0) {
+ if (attribute_name != NULL && streq(attribute_name, name)) {
kind = k;
break;
}
}
if (type_specifiers & SPECIFIER_COMPLEX) {
- type = allocate_type_zero(TYPE_COMPLEX);
- type->complex.akind = atomic_type;
+ type = allocate_type_zero(TYPE_COMPLEX);
} else if (type_specifiers & SPECIFIER_IMAGINARY) {
- type = allocate_type_zero(TYPE_IMAGINARY);
- type->imaginary.akind = atomic_type;
+ type = allocate_type_zero(TYPE_IMAGINARY);
} else {
- type = allocate_type_zero(TYPE_ATOMIC);
- type->atomic.akind = atomic_type;
+ type = allocate_type_zero(TYPE_ATOMIC);
}
+ type->atomic.akind = atomic_type;
newtype = true;
} else if (type_specifiers != 0) {
errorf(&specifiers->source_position, "multiple datatypes in declaration");
static bool has_parameters(void)
{
/* func(void) is not a parameter */
+ if (look_ahead(1)->kind != ')')
+ return true;
if (token.kind == T_IDENTIFIER) {
entity_t const *const entity
= get_entity(token.identifier.symbol, NAMESPACE_NORMAL);
return true;
if (entity->kind != ENTITY_TYPEDEF)
return true;
- if (skip_typeref(entity->typedefe.type) != type_void)
+ type_t const *const type = skip_typeref(entity->typedefe.type);
+ if (!is_type_void(type))
return true;
+ if (c_mode & _CXX) {
+ /* ISO/IEC 14882:1998(E) §8.3.5:2 It must be literally (void). A typedef
+ * is not allowed. */
+ errorf(HERE, "empty parameter list defined with a typedef of 'void' not allowed in C++");
+ } else if (type->base.qualifiers != TYPE_QUALIFIER_NONE) {
+ /* §6.7.5.3:10 Qualification is not allowed here. */
+ errorf(HERE, "'void' as parameter must not have type qualifiers");
+ }
} else if (token.kind != T_void) {
return true;
}
- if (look_ahead(1)->kind != ')')
- return true;
next_token();
return false;
}
}
typedef enum construct_type_kind_t {
- CONSTRUCT_INVALID,
- CONSTRUCT_POINTER,
+ CONSTRUCT_POINTER = 1,
CONSTRUCT_REFERENCE,
CONSTRUCT_FUNCTION,
CONSTRUCT_ARRAY
for (; iter != NULL; iter = iter->base.next) {
source_position_t const* const pos = &iter->base.pos;
switch (iter->kind) {
- case CONSTRUCT_INVALID:
- break;
case CONSTRUCT_FUNCTION: {
construct_function_type_t *function = &iter->function;
type_t *function_type = function->function_type;
errorf(pos, "function returning array is not allowed");
} else {
if (skipped_return_type->base.qualifiers != 0) {
- warningf(WARN_OTHER, pos, "type qualifiers in return type of function type are meaningless");
+ warningf(WARN_IGNORED_QUALIFIERS, pos, "type qualifiers in return type of function type are meaningless");
}
}
handle_entity_attributes(attributes, entity);
}
+ if (entity->kind == ENTITY_FUNCTION && !freestanding) {
+ adapt_special_functions(&entity->function);
+ }
+
return entity;
}
*/
static bool is_sym_main(const symbol_t *const sym)
{
- return strcmp(sym->string, "main") == 0;
+ return streq(sym->string, "main");
}
static void error_redefined_as_different_kind(const source_position_t *pos,
goto finish;
}
if (previous_entity->kind == ENTITY_TYPEDEF) {
- /* TODO: C++ allows this for exactly the same type */
- errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos);
+ type_t *const type = skip_typeref(entity->typedefe.type);
+ type_t *const prev_type
+ = skip_typeref(previous_entity->typedefe.type);
+ if (c_mode & _CXX) {
+ /* C++ allows double typedef if they are identical
+ * (after skipping typedefs) */
+ if (type == prev_type)
+ goto finish;
+ } else {
+ /* GCC extension: redef in system headers is allowed */
+ if ((pos->is_system_header || ppos->is_system_header) &&
+ types_compatible(type, prev_type))
+ goto finish;
+ }
+ errorf(pos, "redefinition of '%N' (declared %P)",
+ entity, ppos);
goto finish;
}
merge_in_attributes(decl, prev_decl->attributes);
} else if (!is_definition &&
is_type_valid(prev_type) &&
- strcmp(ppos->input_name, "<builtin>") != 0) {
+ !pos->is_system_header) {
warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos);
}
} else if (current_function == NULL) {
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;
-
label_t *label = goto_statement->label;
if (label->base.source_position.input_name == NULL) {
print_in_function();
switch (expr->kind) {
case EXPR_CALL: {
expression_t const *const func = expr->call.function;
- if (func->kind == EXPR_REFERENCE) {
- entity_t *entity = func->reference.entity;
- if (entity->kind == ENTITY_FUNCTION
- && entity->declaration.modifiers & DM_NORETURN)
+ type_t const *const type = skip_typeref(func->base.type);
+ if (type->kind == TYPE_POINTER) {
+ type_t const *const points_to
+ = skip_typeref(type->pointer.points_to);
+ if (points_to->kind == TYPE_FUNCTION
+ && points_to->function.modifiers & DM_NORETURN)
return false;
}
}
case EXPR_REFERENCE:
- case EXPR_REFERENCE_ENUM_VALUE:
- EXPR_LITERAL_CASES
+ case EXPR_ENUM_CONSTANT:
+ case EXPR_LITERAL_CASES:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
case EXPR_BUILTIN_CONSTANT_P:
case EXPR_BUILTIN_TYPES_COMPATIBLE_P:
case EXPR_OFFSETOF:
- case EXPR_INVALID:
+ case EXPR_ERROR:
return true;
case EXPR_STATEMENT: {
case EXPR_VA_COPY:
return expression_returns(expr->va_copye.src);
- EXPR_UNARY_CASES_MANDATORY
+ case EXPR_UNARY_CASES_MANDATORY:
return expression_returns(expr->unary.value);
case EXPR_UNARY_THROW:
return false;
- EXPR_BINARY_CASES
+ case EXPR_BINARY_CASES:
// TODO handle constant lhs of && and ||
return
expression_returns(expr->binary.left) &&
statement_t *last = stmt;
statement_t *next;
switch (stmt->kind) {
- case STATEMENT_INVALID:
+ case STATEMENT_ERROR:
case STATEMENT_EMPTY:
case STATEMENT_ASM:
next = stmt->base.next;
found_break_parent:
break;
- case STATEMENT_GOTO:
- if (stmt->gotos.expression) {
- if (!expression_returns(stmt->gotos.expression))
- return;
+ case STATEMENT_COMPUTED_GOTO: {
+ if (!expression_returns(stmt->computed_goto.expression))
+ return;
- statement_t *parent = stmt->base.parent;
- if (parent == NULL) /* top level goto */
- return;
- next = parent;
- } else {
- next = stmt->gotos.label->statement;
- if (next == NULL) /* missing label */
- return;
- }
+ statement_t *parent = stmt->base.parent;
+ if (parent == NULL) /* top level goto */
+ return;
+ next = parent;
+ break;
+ }
+
+ case STATEMENT_GOTO:
+ next = stmt->gotos.label->statement;
+ if (next == NULL) /* missing label */
+ return;
break;
case STATEMENT_LABEL:
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 (!is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
- is_type_valid(ret) &&
+ if (!is_type_void(ret) &&
+ is_type_valid(ret) &&
!is_sym_main(current_function->base.base.symbol)) {
source_position_t const *const pos = &stmt->base.source_position;
warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
}
switch (next->kind) {
- case STATEMENT_INVALID:
+ case STATEMENT_ERROR:
case STATEMENT_EMPTY:
case STATEMENT_DECLARATION:
case STATEMENT_EXPRESSION:
case STATEMENT_RETURN:
case STATEMENT_CONTINUE:
case STATEMENT_BREAK:
+ case STATEMENT_COMPUTED_GOTO:
case STATEMENT_GOTO:
case STATEMENT_LEAVE:
panic("invalid control flow in function");
}
}
+static bool is_main(entity_t *entity)
+{
+ static symbol_t *sym_main = NULL;
+ if (sym_main == NULL) {
+ sym_main = symbol_table_insert("main");
+ }
+
+ if (entity->base.symbol != sym_main)
+ return false;
+ /* must be in outermost scope */
+ if (entity->base.parent_scope != file_scope)
+ return false;
+
+ return true;
+}
+
static void parse_external_declaration(void)
{
/* function-definitions and declarations both start with declaration
}
}
+ if (is_main(entity) && enable_main_collect2_hack)
+ prepare_main_collect2(entity);
+
POP_PARENT();
assert(current_function == function);
assert(current_entity == entity);
token.kind != ';' ||
look_ahead(1)->kind != '}') {
errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+ } else if (compound->members.entities == NULL) {
+ errorf(pos, "flexible array member in otherwise empty struct");
}
}
}
}
next_token();
- return create_invalid_expression();
+ return create_error_expression();
}
static type_t *get_string_type(void)
if (entity == NULL) {
if (!strict_mode && token.kind == '(') {
/* an implicitly declared function */
- warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &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);
expression_kind_t kind = EXPR_REFERENCE;
if (entity->kind == ENTITY_ENUM_VALUE)
- kind = EXPR_REFERENCE_ENUM_VALUE;
+ kind = EXPR_ENUM_CONSTANT;
expression_t *expression = allocate_expression_zero(kind);
expression->base.source_position = pos;
source_position_t const *pos = &cast->base.source_position;
/* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
- if (dst_type == type_void)
+ if (is_type_void(dst_type))
return true;
/* only integer and pointer can be casted to pointer */
return cast;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
descend_into_subtype(&path);
if (!walk_designator(&path, designator, true)) {
- return create_invalid_expression();
+ return create_error_expression();
}
DEL_ARR_F(path.path);
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
}
expect(')', end_error);
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
expression->base.type = type_void;
return expression;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
eat(T_ANDAND);
if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
- return create_invalid_expression();
+ return create_error_expression();
}
label_t *const label = get_label();
if (token.kind != ')') do {
(void)parse_assignment_expression();
} while (next_if(','));
+
+ rem_anchor_token(',');
+ rem_anchor_token(')');
}
- rem_anchor_token(',');
- rem_anchor_token(')');
expect(')', end_error);
end_error:
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();
+ return create_error_expression();
}
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
eat_until_anchor();
- return create_invalid_expression();
+ return create_error_expression();
}
static expression_t *parse_array_expression(expression_t *left)
type_t const* const type = skip_typeref(orig_type);
char const* wrong_type = NULL;
if (is_type_incomplete(type)) {
- if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+ if (!is_type_void(type) || !GNU_MODE)
wrong_type = "incomplete";
} else if (type->kind == TYPE_FUNCTION) {
if (GNU_MODE) {
if (token.kind != T_IDENTIFIER) {
parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
- return create_invalid_expression();
+ return create_error_expression();
}
symbol_t *symbol = token.identifier.symbol;
next_token();
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
- return create_invalid_expression();
+ return create_error_expression();
}
compound_t *compound = type_left->compound.compound;
if (!compound->complete) {
errorf(&pos, "request for member '%Y' in incomplete type '%T'",
symbol, type_left);
- return create_invalid_expression();
+ return create_error_expression();
}
type_qualifiers_t qualifiers = type_left->base.qualifiers;
if (result == NULL) {
errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
- return create_invalid_expression();
+ return create_error_expression();
}
return result;
/**
* Handle the semantic restrictions of builtin calls
*/
-static void handle_builtin_argument_restrictions(call_expression_t *call) {
- switch (call->function->reference.entity->function.btk) {
- case bk_gnu_builtin_return_address:
- case bk_gnu_builtin_frame_address: {
+static void handle_builtin_argument_restrictions(call_expression_t *call)
+{
+ entity_t *entity = call->function->reference.entity;
+ switch (entity->function.btk) {
+ case BUILTIN_FIRM:
+ switch (entity->function.b.firm_builtin_kind) {
+ case ir_bk_return_address:
+ case ir_bk_frame_address: {
/* argument must be constant */
call_argument_t *argument = call->arguments;
if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
- }
- break;
- }
- case bk_gnu_builtin_object_size:
- if (call->arguments == NULL)
- break;
-
- call_argument_t *arg = call->arguments->next;
- if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
- errorf(&call->base.source_position,
- "second argument of '%Y' must be a constant expression",
+ "argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
break;
- case bk_gnu_builtin_prefetch:
+ }
+ case ir_bk_prefetch:
/* second and third argument must be constant if existent */
if (call->arguments == NULL)
break;
if (rw != NULL) {
if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "second argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
}
locality = rw->next;
}
if (locality != NULL) {
if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
errorf(&call->base.source_position,
- "third argument of '%Y' must be a constant expression",
- call->function->reference.entity->base.symbol);
+ "third argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
}
locality = rw->next;
}
break;
default:
break;
+ }
+
+ case BUILTIN_OBJECT_SIZE:
+ if (call->arguments == NULL)
+ break;
+
+ call_argument_t *arg = call->arguments->next;
+ if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
+ errorf(&call->base.source_position,
+ "second argument of '%Y' must be a constant expression",
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ default:
+ break;
}
}
if (expression->kind == EXPR_REFERENCE) {
reference_expression_t *reference = &expression->reference;
if (reference->entity->kind == ENTITY_FUNCTION &&
- reference->entity->function.btk != bk_none)
+ reference->entity->function.btk != BUILTIN_NONE)
handle_builtin_argument_restrictions(call);
}
/* 6.5.15.3 */
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)) {
+ if (is_type_void(true_type) || is_type_void(false_type)) {
/* ISO/IEC 14882:1998(E) §5.16:2 */
if (true_expression->kind == EXPR_UNARY_THROW) {
result_type = false_type;
} else if (false_expression->kind == EXPR_UNARY_THROW) {
result_type = true_type;
} else {
- if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
- !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ if (!is_type_void(true_type) || !is_type_void(false_type)) {
warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side");
}
result_type = type_void;
type_t *to2 = skip_typeref(other_type->pointer.points_to);
type_t *to;
- if (is_type_atomic(to1, ATOMIC_TYPE_VOID) ||
- is_type_atomic(to2, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(to1) || is_type_void(to2)) {
to = type_void;
} else if (types_compatible(get_unqualified_type(to1),
get_unqualified_type(to2))) {
return result;
end_error:
- return create_invalid_expression();
+ return create_error_expression();
}
/**
errorf(&value->base.source_position,
"operand of delete must have pointer type");
}
- } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) {
+ } else if (is_type_void(skip_typeref(type->pointer.points_to))) {
source_position_t const *const pos = &value->base.source_position;
warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
}
"cannot throw object of incomplete type '%T'", orig_type);
} else if (is_type_pointer(type)) {
type_t *const points_to = skip_typeref(type->pointer.points_to);
- if (is_type_incomplete(points_to) &&
- !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+ if (is_type_incomplete(points_to) && !is_type_void(points_to)) {
errorf(&value->base.source_position,
"cannot throw pointer to incomplete type '%T'", orig_type);
}
points_to = skip_typeref(points_to);
if (is_type_incomplete(points_to)) {
- if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+ if (!GNU_MODE || !is_type_void(points_to)) {
errorf(source_position,
"arithmetic with pointer to incomplete type '%T' not allowed",
orig_pointer_type);
expression->base.type = orig_type;
}
+static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
+{
+ type_t *const res_type = promote_integer(type);
+ expr->base.type = res_type;
+ expr->value = create_implicit_cast(expr->value, res_type);
+}
+
static void semantic_unexpr_arithmetic(unary_expression_t *expression)
{
type_t *const orig_type = expression->value->base.type;
"operation needs an arithmetic type");
}
return;
+ } else if (is_type_integer(type)) {
+ promote_unary_int_expr(expression, type);
+ } else {
+ expression->base.type = orig_type;
}
-
- expression->base.type = orig_type;
}
static void semantic_unexpr_plus(unary_expression_t *expression)
return;
}
- expression->base.type = orig_type;
+ promote_unary_int_expr(expression, type);
}
static void semantic_dereference(unary_expression_t *expression)
if (type_left == type_right)
return type_left;
- bool const signed_left = is_type_signed(type_left);
- bool const signed_right = is_type_signed(type_right);
- int const rank_left = get_rank(type_left);
- int const rank_right = get_rank(type_right);
+ bool const signed_left = is_type_signed(type_left);
+ bool const signed_right = is_type_signed(type_right);
+ unsigned const rank_left = get_akind_rank(get_akind(type_left));
+ unsigned const rank_right = get_akind_rank(get_akind(type_right));
if (signed_left == signed_right)
return rank_left >= rank_right ? type_left : type_right;
- int s_rank;
- int u_rank;
+ unsigned s_rank;
+ unsigned u_rank;
+ atomic_type_kind_t s_akind;
+ atomic_type_kind_t u_akind;
type_t *s_type;
type_t *u_type;
if (signed_left) {
- s_rank = rank_left;
s_type = type_left;
- u_rank = rank_right;
u_type = type_right;
} else {
- s_rank = rank_right;
s_type = type_right;
- u_rank = rank_left;
u_type = type_left;
}
+ s_akind = get_akind(s_type);
+ u_akind = get_akind(u_type);
+ s_rank = get_akind_rank(s_akind);
+ u_rank = get_akind_rank(u_akind);
if (u_rank >= s_rank)
return u_type;
- /* casting rank to atomic_type_kind is a bit hacky, but makes things
- * easier here... */
- if (get_atomic_type_size((atomic_type_kind_t) s_rank)
- > get_atomic_type_size((atomic_type_kind_t) u_rank))
+ if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
return s_type;
- switch (s_rank) {
- case ATOMIC_TYPE_INT: return type_unsigned_int;
- case ATOMIC_TYPE_LONG: return type_unsigned_long;
- case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+ switch (s_akind) {
+ case ATOMIC_TYPE_INT: return type_unsigned_int;
+ case ATOMIC_TYPE_LONG: return type_unsigned_long;
+ case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
- default: panic("invalid atomic type");
+ default: panic("invalid atomic type");
}
}
"subtracting pointers to incompatible types '%T' and '%T'",
orig_type_left, orig_type_right);
} else if (!is_type_object(unqual_left)) {
- if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
+ if (!is_type_void(unqual_left)) {
errorf(pos, "subtracting pointers to non-object types '%T'",
orig_type_left);
} else {
static bool expression_has_effect(const expression_t *const expr)
{
switch (expr->kind) {
- case EXPR_INVALID: return true; /* do NOT warn */
+ case EXPR_ERROR: return true; /* do NOT warn */
case EXPR_REFERENCE: return false;
- case EXPR_REFERENCE_ENUM_VALUE: return false;
+ case EXPR_ENUM_CONSTANT: return false;
case EXPR_LABEL_ADDRESS: return false;
/* suppress the warning for microsoft __noop operations */
* suppress the warning */
case EXPR_UNARY_CAST: {
type_t *const type = skip_typeref(expr->base.type);
- return is_type_atomic(type, ATOMIC_TYPE_VOID);
+ return is_type_void(type);
}
case EXPR_UNARY_ASSUME: return true;
return statement;
end_error:
- return create_invalid_statement();
+ return create_error_statement();
}
static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
switch (token.kind) {
case '}':
errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
- inner_stmt = create_invalid_statement();
+ inner_stmt = create_error_statement();
break;
case ';':
eat(T_case);
- expression_t *const expression = parse_expression();
+ expression_t *expression = parse_expression();
+ type_t *expression_type = expression->base.type;
+ type_t *skipped = skip_typeref(expression_type);
+ if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+ errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+ expression, expression_type);
+ }
+
+ type_t *type = expression_type;
+ if (current_switch != NULL) {
+ type_t *switch_type = current_switch->expression->base.type;
+ if (is_type_valid(switch_type)) {
+ expression = create_implicit_cast(expression, switch_type);
+ }
+ }
+
statement->case_label.expression = expression;
expression_classification_t const expr_class = is_constant_expression(expression);
if (expr_class != EXPR_CLASS_CONSTANT) {
if (GNU_MODE) {
if (next_if(T_DOTDOTDOT)) {
- expression_t *const end_range = parse_expression();
+ expression_t *end_range = parse_expression();
+ expression_type = expression->base.type;
+ skipped = skip_typeref(expression_type);
+ if (!is_type_integer(skipped) && is_type_valid(skipped)) {
+ errorf(pos, "case expression '%E' must have integer type but has type '%T'",
+ expression, expression_type);
+ }
+
+ end_range = create_implicit_cast(end_range, type);
statement->case_label.end_range = end_range;
expression_classification_t const end_class = is_constant_expression(end_range);
if (end_class != EXPR_CLASS_CONSTANT) {
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_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) {
source_position_t const *const pos = &true_stmt->base.source_position;
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
- if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+ if (get_akind_rank(get_akind(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)) {
return statement;
end_error:
POP_PARENT();
- return create_invalid_statement();
+ return create_error_statement();
}
static statement_t *parse_loop_body(statement_t *const loop)
return statement;
end_error:
POP_PARENT();
- return create_invalid_statement();
+ return create_error_statement();
}
/**
return statement;
end_error:
POP_PARENT();
- return create_invalid_statement();
+ return create_error_statement();
}
/**
/* fallthrough */
end_error1:
- return create_invalid_statement();
+ return create_error_statement();
}
/**
*/
static statement_t *parse_goto(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
- eat(T_goto);
+ statement_t *statement;
+ if (GNU_MODE && look_ahead(1)->kind == '*') {
+ statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO);
+ eat(T_goto);
+ eat('*');
- if (GNU_MODE && next_if('*')) {
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
expression = create_implicit_cast(expression, type_void_ptr);
}
- statement->gotos.expression = expression;
- } else if (token.kind == T_IDENTIFIER) {
- label_t *const label = get_label();
- label->used = true;
- statement->gotos.label = label;
+ statement->computed_goto.expression = expression;
} else {
- if (GNU_MODE)
- parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
- else
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_until_anchor();
- return create_invalid_statement();
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ eat(T_goto);
+ if (token.kind == T_IDENTIFIER) {
+ label_t *const label = get_label();
+ label->used = true;
+ statement->gotos.label = label;
+
+ /* remember the goto's in a list for later checking */
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
+ } else {
+ if (GNU_MODE)
+ parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+ else
+ parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+ eat_until_anchor();
+ return create_error_statement();
+ }
}
- /* remember the goto's in a list for later checking */
- *goto_anchor = &statement->gotos;
- goto_anchor = &statement->gotos.next;
-
expect(';', end_error);
end_error:
return entity;
}
+static void err_or_warn(source_position_t const *const pos, char const *const msg)
+{
+ if (c_mode & _CXX || strict_mode) {
+ errorf(pos, msg);
+ } else {
+ warningf(WARN_OTHER, pos, msg);
+ }
+}
+
/**
* Parse a return statement.
*/
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
- if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
- if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_void(return_type)) {
+ if (!is_type_void(return_value_type)) {
/* ISO/IEC 14882:1998(E) §6.6.3:2 */
/* Only warn in C mode, because GCC does the same */
- if (c_mode & _CXX || strict_mode) {
- errorf(pos,
- "'return' with a value, in function returning 'void'");
- } else {
- warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'");
- }
+ err_or_warn(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 {
- warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'");
- }
+ err_or_warn(pos, "'return' with expression in function returning 'void'");
}
} else {
assign_error_t error = semantic_assign(return_type, return_value);
warningf(WARN_OTHER, pos, "function returns address of local variable");
}
}
- } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ } else if (!is_type_void(return_type)) {
/* 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(WARN_OTHER, pos, "'return' without value, in function returning non-void");
- }
+ err_or_warn(pos, "'return' without value, in function returning non-void");
}
statement->returns.value = return_value;
statement->ms_try.final_statement = parse_compound_statement(false);
} else {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
- return create_invalid_statement();
+ return create_error_statement();
}
return statement;
end_error:
- return create_invalid_statement();
+ return create_error_statement();
}
static statement_t *parse_empty_statement(void)
default:
errorf(HERE, "unexpected token %K while parsing statement", &token);
- statement = create_invalid_statement();
+ statement = create_error_statement();
if (!at_anchor())
next_token();
break;
break;
}
statement_t *sub_statement = intern_parse_statement();
- if (is_invalid_statement(sub_statement)) {
+ if (sub_statement->kind == STATEMENT_ERROR) {
/* an error occurred. if we are at an anchor, return */
if (at_anchor())
goto end_error;
linkage_kind_t old_linkage = current_linkage;
linkage_kind_t new_linkage;
- if (strcmp(linkage, "C") == 0) {
+ if (streq(linkage, "C")) {
new_linkage = LINKAGE_C;
- } else if (strcmp(linkage, "C++") == 0) {
+ } else if (streq(linkage, "C++")) {
new_linkage = LINKAGE_CXX;
} else {
errorf(&pos, "linkage string \"%s\" not recognized", linkage);
- new_linkage = LINKAGE_INVALID;
+ new_linkage = LINKAGE_C;
}
current_linkage = new_linkage;
case ';':
if (!strict_mode) {
- warningf(WARN_OTHER, HERE, "stray ';' outside of function");
+ warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function");
next_token();
return;
}
void prepare_main_collect2(entity_t *entity)
{
+ PUSH_SCOPE(&entity->function.statement->compound.scope);
+
// create call to __main
symbol_t *symbol = symbol_table_insert("__main");
entity_t *subsubmain_ent
expr_statement->base.next = compounds->statements;
compounds->statements = expr_statement;
+
+ POP_SCOPE();
}
void parse(void)