#include <stdarg.h>
#include <stdbool.h>
+#include "adt/strutil.h"
#include "parser.h"
#include "diagnostic.h"
#include "format_check.h"
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;
}
determine_lhs_ent(expr->va_starte.ap, lhs_ent);
return;
- EXPR_LITERAL_CASES
+ case EXPR_LITERAL_CASES:
case EXPR_ERROR:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
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);
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;
}
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) {
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_LITERAL_CASES:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
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) &&
}
}
+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");
}
}
}
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);
/**
* 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);
}
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) {
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);
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)