static source_position_t null_position = { NULL, 0 };
+/** special symbol used for anonymous entities. */
+static const symbol_t *sym_anonymous = NULL;
+
/* symbols for Microsoft extended-decl-modifier */
static const symbol_t *sym_align = NULL;
static const symbol_t *sym_allocate = NULL;
case ASSIGN_WARNING_POINTER_FROM_INT:
warningf(source_position,
- "%s makes integer '%T' from pointer '%T' without a cast",
+ "%s makes pointer '%T' from integer '%T' without a cast",
context, orig_type_left, orig_type_right);
return;
type_t *orig_top_type = path->top_type;
type_t *top_type = skip_typeref(orig_top_type);
- assert(is_type_compound(top_type) || is_type_array(top_type));
-
type_path_entry_t *top = append_to_type_path(path);
top->type = top_type;
} else {
path->top_type = NULL;
}
- } else {
- assert(is_type_array(top_type));
-
+ } else if (is_type_array(top_type)) {
top->v.index = 0;
path->top_type = top_type->array.element_type;
+ } else {
+ assert(!is_type_valid(top_type));
}
}
errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
is_struct ? "struct" : "union", symbol,
&declaration->source_position);
- declaration->scope.declarations = NULL;
}
}
} else if (token.type != '{') {
return NULL;
}
- if (declaration == NULL) {
- declaration = allocate_declaration_zero();
- declaration->namespc =
- (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
- declaration->source_position = token.source_position;
- declaration->symbol = symbol;
- declaration->parent_scope = scope;
- if (symbol != NULL) {
- environment_push(declaration);
- }
- append_declaration(declaration);
+ /* always create a new declaration, do NOT modify old one */
+ declaration = allocate_declaration_zero();
+ declaration->namespc =
+ (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_scope = scope;
+ if (symbol != NULL) {
+ environment_push(declaration);
}
+ append_declaration(declaration);
if (token.type == '{') {
declaration->init.complete = true;
;
}
+/**
+ * Parse enum specifier and return the enum type or NULL on error.
+ */
static type_t *parse_enum_specifier(void)
{
- gnu_attribute_t *attributes = NULL;
- declaration_t *declaration;
- symbol_t *symbol;
+ gnu_attribute_t *attributes = NULL;
+ declaration_t *declaration = NULL;
+ symbol_t *symbol = NULL;
eat(T_enum);
if (token.type == T_IDENTIFIER) {
parse_error_expected("while parsing enum type specifier",
T_IDENTIFIER, '{', NULL);
return NULL;
- } else {
- declaration = NULL;
- symbol = NULL;
}
- if (declaration == NULL) {
- declaration = allocate_declaration_zero();
- declaration->namespc = NAMESPACE_ENUM;
- declaration->source_position = token.source_position;
- declaration->symbol = symbol;
- declaration->parent_scope = scope;
+ if (token.type == '{' && declaration != NULL && declaration->init.complete) {
+ errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
+ symbol, &declaration->source_position);
}
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_ENUM;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_scope = scope;
+ if (symbol != NULL) {
+ environment_push(declaration);
+ }
+ append_declaration(declaration);
+
type_t *const type = allocate_type_zero(TYPE_ENUM, &declaration->source_position);
type->enumt.declaration = declaration;
if (token.type == '{') {
if (declaration->init.complete) {
- errorf(HERE, "multiple definitions of enum %Y", symbol);
- }
- if (symbol != NULL) {
- environment_push(declaration);
+ errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
+ symbol, &declaration->source_position);
}
- append_declaration(declaration);
declaration->init.complete = true;
parse_enum_entries(type);
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;
+ il_size_t size = 0;
+ il_size_t offset;
+ 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;
+ type_t *m_type = skip_typeref(entry->type);
+ if (! is_type_valid(m_type)) {
+ /* simply ignore errors here */
+ continue;
+ }
+ il_alignment_t m_alignment = m_type->base.alignment;
if (m_alignment > alignment)
alignment = m_alignment;
- if (new_size > size)
+
+ offset = (size + m_alignment - 1) & -m_alignment;
+
+ if (offset > size)
need_pad = true;
- entry->offset = new_size;
- size = new_size + m_type->base.size;
+ entry->offset = offset;
+ size = offset + m_type->base.size;
}
if (type->base.alignment != 0) {
alignment = type->base.alignment;
}
- new_size = (size + alignment - 1) & -alignment;
- if (new_size > size)
+ offset = (size + alignment - 1) & -alignment;
+ if (offset > size)
need_pad = true;
if (warning.padded && need_pad) {
type, struct_decl->symbol);
}
- type->base.size = new_size;
+ type->base.size = offset;
type->base.alignment = alignment;
}
continue;
type_t *m_type = skip_typeref(entry->type);
+ if (! is_type_valid(m_type))
+ continue;
entry->offset = 0;
if (m_type->base.size > size)
if (old_storage_class == STORAGE_CLASS_EXTERN &&
new_storage_class == STORAGE_CLASS_EXTERN) {
warn_redundant_declaration:
- if (!is_definition &&
- warning.redundant_decls &&
+ if (!is_definition &&
+ warning.redundant_decls &&
+ is_type_valid(prev_type) &&
strcmp(previous_declaration->source_position.input_name, "<builtin>") != 0) {
warningf(&declaration->source_position,
"redundant declaration for '%Y' (declared %P)",
} else {
goto warn_redundant_declaration;
}
- } else if (old_storage_class == new_storage_class) {
- errorf(&declaration->source_position,
- "redeclaration of '%Y' (declared %P)",
- symbol, &previous_declaration->source_position);
- } else {
- errorf(&declaration->source_position,
- "redeclaration of '%Y' with different linkage (declared %P)",
- symbol, &previous_declaration->source_position);
+ } else if (is_type_valid(prev_type)) {
+ if (old_storage_class == new_storage_class) {
+ errorf(&declaration->source_position,
+ "redeclaration of '%Y' (declared %P)",
+ symbol, &previous_declaration->source_position);
+ } else {
+ errorf(&declaration->source_position,
+ "redeclaration of '%Y' with different linkage (declared %P)",
+ symbol, &previous_declaration->source_position);
+ }
}
}
{
eat(';');
+ if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
+ warningf(&specifiers->source_position,
+ "useless storage class in empty declaration");
+ }
+
+#ifdef RECORD_EMPTY_DECLARARTIONS
declaration_t *const declaration = allocate_declaration_zero();
declaration->type = specifiers->type;
declaration->declared_storage_class = specifiers->declared_storage_class;
declaration->source_position = specifiers->source_position;
declaration->modifiers = specifiers->modifiers;
+ declaration->storage_class = STORAGE_CLASS_NONE;
+#endif
- if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
- warningf(&declaration->source_position,
- "useless storage class in empty declaration");
- }
- declaration->storage_class = STORAGE_CLASS_NONE;
-
- type_t *type = declaration->type;
+ type_t *type = specifiers->type;
switch (type->kind) {
case TYPE_COMPOUND_STRUCT:
case TYPE_COMPOUND_UNION: {
if (type->compound.declaration->symbol == NULL) {
- warningf(&declaration->source_position,
+ warningf(&specifiers->source_position,
"unnamed struct/union that defines no instances");
}
break;
break;
default:
- warningf(&declaration->source_position, "empty declaration");
+ warningf(&specifiers->source_position, "empty declaration");
break;
}
+#ifdef RECORD_EMPTY_DECLARARTIONS
append_declaration(declaration);
+#endif
}
static void parse_declaration_rest(declaration_t *ndeclaration,
}
static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
- source_position_t *source_position)
+ 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 = size;
+ 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;
}
type_t *base_type = specifiers->type;
expression_t *size = parse_constant_expression();
- if (!is_type_integer(skip_typeref(base_type))) {
- errorf(HERE, "bitfield base type '%T' is not an integer type",
- base_type);
- }
-
- type_t *type = make_bitfield_type(base_type, size, &source_position);
+ type_t *type = make_bitfield_type(base_type, size,
+ &source_position, sym_anonymous);
declaration = allocate_declaration_zero();
declaration->namespc = NAMESPACE_NORMAL;
next_token();
expression_t *size = parse_constant_expression();
- if (!is_type_integer(type)) {
- errorf(HERE, "bitfield base type '%T' is not an integer type",
- orig_type);
- }
-
- type_t *bitfield_type = make_bitfield_type(orig_type, size, &source_position);
+ type_t *bitfield_type = make_bitfield_type(orig_type, size,
+ &source_position, declaration->symbol);
declaration->type = bitfield_type;
} else {
/* TODO we ignore arrays for now... what is missing is a check
declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
- source_position_t source_position = token.source_position;
- next_token();
-
if (declaration == NULL) {
- if (token.type == '(') {
+ if (!strict_mode && look_ahead(1)->type == '(') {
/* an implicitly declared function */
- if (strict_mode) {
- errorf(HERE, "unknown symbol '%Y' found.", symbol);
- } else if (warning.implicit_function_declaration) {
+ if (warning.implicit_function_declaration) {
warningf(HERE, "implicit declaration of function '%Y'",
symbol);
}
- declaration = create_implicit_function(symbol,
- &source_position);
+ declaration = create_implicit_function(symbol, HERE);
} else {
errorf(HERE, "unknown symbol '%Y' found.", symbol);
declaration = create_error_declaration(symbol, STORAGE_CLASS_NONE);
"function" : "variable";
if (declaration->deprecated_string != NULL) {
- warningf(&source_position,
- "%s '%Y' is deprecated (declared %P): \"%s\"", prefix,
- declaration->symbol, &declaration->source_position,
+ warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
+ prefix, declaration->symbol, &declaration->source_position,
declaration->deprecated_string);
} else {
- warningf(&source_position,
- "%s '%Y' is deprecated (declared %P)", prefix,
+ warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
declaration->symbol, &declaration->source_position);
}
}
if (warning.init_self && declaration == current_init_decl) {
current_init_decl = NULL;
- warningf(&source_position,
- "variable '%#T' is initialized by itself",
+ warningf(HERE, "variable '%#T' is initialized by itself",
declaration->type, declaration->symbol);
}
+ next_token();
return expression;
}
orig_type_left, orig_type_inside);
}
return_type = type_error_type;
- array_access->array_ref = create_invalid_expression();
+ array_access->array_ref = left;
+ array_access->index = inside;
}
+ expression->base.type = automatic_type_conversion(return_type);
+
rem_anchor_token(']');
- if (token.type != ']') {
+ if (token.type == ']') {
+ next_token();
+ } else {
parse_error_expected("Problem while parsing array access", ']', NULL);
- return expression;
}
- next_token();
-
- return_type = automatic_type_conversion(return_type);
- expression->base.type = return_type;
-
return expression;
}
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);
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) {
- if (
- /* passing as integer instead of float or complex */
- (is_type_integer(expected_type) &&
- (is_type_float(arg_type) || is_type_complex(arg_type))) ||
- /* passing as complex instead of integer or float */
- (is_type_complex(expected_type) &&
- (is_type_integer(arg_type) || is_type_float(arg_type))) ||
- /* passing as float instead of integer or complex */
- (is_type_float(expected_type) &&
- (is_type_integer(arg_type) || is_type_complex(arg_type))) ||
- /* passing as float instead of double */
- (is_type_float(expected_type) && expected_type != type_double &&
- is_type_float(arg_type))) {
+ } else if (warning.traditional || warning.conversion) {
+ 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, arg_type);
- }
- if (is_type_integer(expected_type) && is_type_integer(arg_type)) {
- /* TODO check for size HERE */
+ pos, expected_type_skip, promoted_type);
}
}
}
{
/* TODO: handle complex + imaginary types */
+ type_left = get_unqualified_type(type_left);
+ type_right = get_unqualified_type(type_right);
+
/* ยง 6.3.1.8 Usual arithmetic conversions */
if (type_left == type_long_double || type_right == type_long_double) {
return type_long_double;
static void warn_div_by_zero(binary_expression_t const *const expression)
{
- if (warning.div_by_zero &&
- is_type_integer(expression->base.type) &&
- is_constant_expression(expression->right) &&
- fold_constant(expression->right) == 0) {
+ if (!warning.div_by_zero ||
+ !is_type_integer(expression->base.type))
+ return;
+
+ expression_t const *const right = expression->right;
+ /* The type of the right operand can be different for /= */
+ if (is_type_integer(right->base.type) &&
+ is_constant_expression(right) &&
+ fold_constant(right) == 0) {
warningf(&expression->base.source_position, "division by zero");
}
}
source_position_t *const pos = &statement->base.source_position;
*pos = token.source_position;
- statement->case_label.expression = parse_expression();
- if (! is_constant_expression(statement->case_label.expression)) {
- errorf(pos, "case label does not reduce to an integer constant");
+ expression_t *const expression = parse_expression();
+ statement->case_label.expression = expression;
+ if (!is_constant_expression(expression)) {
+ /* This check does not prevent the error message in all cases of an
+ * prior error while parsing the expression. At least it catches the
+ * common case of a mistyped enum entry. */
+ if (is_type_valid(expression->base.type)) {
+ errorf(pos, "case label does not reduce to an integer constant");
+ }
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(statement->case_label.expression);
+ long const val = fold_constant(expression);
statement->case_label.first_case = val;
statement->case_label.last_case = val;
}
if (c_mode & _GNUC) {
if (token.type == T_DOTDOTDOT) {
next_token();
- statement->case_label.end_range = parse_expression();
- if (! is_constant_expression(statement->case_label.end_range)) {
- errorf(pos, "case range does not reduce to an integer constant");
+ expression_t *const end_range = parse_expression();
+ statement->case_label.end_range = end_range;
+ if (!is_constant_expression(end_range)) {
+ /* This check does not prevent the error message in all cases of an
+ * prior error while parsing the expression. At least it catches the
+ * common case of a mistyped enum entry. */
+ if (is_type_valid(end_range->base.type)) {
+ errorf(pos, "case range does not reduce to an integer constant");
+ }
statement->case_label.is_bad = true;
} else {
- long const val = fold_constant(statement->case_label.end_range);
+ long const val = fold_constant(end_range);
statement->case_label.last_case = val;
if (val < statement->case_label.first_case) {
- statement->case_label.is_empty = true;
+ statement->case_label.is_empty_range = true;
warningf(pos, "empty range specified");
}
}
/* Check for duplicate case values */
case_label_statement_t *c = &statement->case_label;
for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) {
- if (l->is_bad || l->is_empty || l->expression == NULL)
+ if (l->is_bad || l->is_empty_range || l->expression == NULL)
continue;
if (c->last_case < l->first_case || c->first_case > l->last_case)
} else if (is_typedef_symbol(token.v.symbol)) {
statement = parse_declaration_statement();
} else switch (la1_type) {
+ case '*':
+ if (get_declaration(token.v.symbol, NAMESPACE_NORMAL) != NULL)
+ goto expression_statment;
+ /* FALLTHROUGH */
+
DECLARATION_START
case T_IDENTIFIER:
- case '*':
statement = parse_declaration_statement();
break;
default:
+expression_statment:
statement = parse_expression_statement();
break;
}
*/
void init_parser(void)
{
+ sym_anonymous = symbol_table_insert("<anonymous>");
+
if (c_mode & _MS) {
/* add predefined symbols for extended-decl-modifier */
sym_align = symbol_table_insert("align");