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 (entity->base.namespc == namespc)
entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE);
entity->enum_value.enum_type = enum_type;
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.symbol = token.symbol;
entity->base.source_position = token.source_position;
next_token();
static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
{
entity_t *entity = allocate_entity_zero(kind);
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.source_position = *HERE;
entity->base.symbol = symbol;
if (is_declaration(entity)) {
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
entity = allocate_entity_zero(ENTITY_TYPEDEF);
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.symbol = env.symbol;
entity->base.source_position = env.source_position;
entity->typedefe.type = orig_type;
storage_class_t storage_class = specifiers->storage_class;
entity->declaration.declared_storage_class = storage_class;
- if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
+ if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
storage_class = STORAGE_CLASS_AUTO;
entity->declaration.storage_class = storage_class;
}
get_entity_kind_name(new_kind), &old->base.source_position);
}
-static bool is_error_entity(entity_t *const ent)
+static bool is_entity_valid(entity_t *const ent)
{
if (is_declaration(ent)) {
return is_type_valid(skip_typeref(ent->declaration.type));
} else if (ent->kind == ENTITY_TYPEDEF) {
return is_type_valid(skip_typeref(ent->typedefe.type));
}
- return false;
+ return true;
}
static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
if (previous_entity->base.parent_scope == current_scope) {
if (previous_entity->kind != entity->kind) {
- if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+ if (is_entity_valid(previous_entity) && is_entity_valid(entity)) {
error_redefined_as_different_kind(pos, previous_entity,
entity->kind);
}
} else {
unsigned old_storage_class = prev_decl->storage_class;
- if (warning.redundant_decls &&
+ if (warning.redundant_decls &&
is_definition &&
!prev_decl->used &&
!(prev_decl->modifiers & DM_USED) &&
static void parse_init_declarator_rest(entity_t *entity)
{
- assert(is_declaration(entity));
- declaration_t *const declaration = &entity->declaration;
+ type_t *orig_type = type_error_type;
+ if (entity->base.kind == ENTITY_TYPEDEF) {
+ errorf(&entity->base.source_position,
+ "typedef '%Y' is initialized (use __typeof__ instead)",
+ entity->base.symbol);
+ } else {
+ assert(is_declaration(entity));
+ orig_type = entity->declaration.type;
+ }
eat('=');
- type_t *orig_type = declaration->type;
- type_t *type = skip_typeref(orig_type);
+ type_t *type = skip_typeref(orig_type);
if (entity->kind == ENTITY_VARIABLE
&& entity->variable.initializer != NULL) {
parser_error_multiple_definition(entity, HERE);
}
+ declaration_t *const declaration = &entity->declaration;
bool must_be_constant = false;
if (declaration->storage_class == STORAGE_CLASS_STATIC ||
entity->base.parent_scope == file_scope) {
entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
entity->declaration.type = type;
entity->declaration.implicit = true;
+ entity->base.namespc = NAMESPACE_NORMAL;
entity->base.symbol = symbol;
entity->base.source_position = *source_position;
tp_expression->typeprop.type = orig_type;
type_t const* const type = skip_typeref(orig_type);
- char const* const wrong_type =
- GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL :
- is_type_incomplete(type) ? "incomplete" :
- type->kind == TYPE_FUNCTION ? "function designator" :
- type->kind == TYPE_BITFIELD ? "bitfield" :
- NULL;
+ char const* wrong_type = NULL;
+ if (is_type_incomplete(type)) {
+ if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+ wrong_type = "incomplete";
+ } else if (type->kind == TYPE_FUNCTION) {
+ if (GNU_MODE) {
+ /* function types are allowed (and return 1) */
+ if (warning.other) {
+ char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ warningf(&tp_expression->base.source_position,
+ "%s expression with function argument returns invalid result", what);
+ }
+ } else {
+ wrong_type = "function";
+ }
+ } else {
+ if (is_type_incomplete(type))
+ wrong_type = "incomplete";
+ }
+ if (type->kind == TYPE_BITFIELD)
+ wrong_type = "bitfield";
+
if (wrong_type != NULL) {
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
errorf(&tp_expression->base.source_position,
{
assert(token.type == '.' || token.type == T_MINUSGREATER);
bool select_left_arrow = (token.type == T_MINUSGREATER);
+ source_position_t const pos = *HERE;
next_token();
if (token.type != T_IDENTIFIER) {
bool saw_error = false;
if (is_type_pointer(type)) {
if (!select_left_arrow) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, orig_type);
saw_error = true;
type_left = skip_typeref(type->pointer.points_to);
} else {
if (select_left_arrow && is_type_valid(type)) {
- errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+ errorf(&pos, "left hand side of '->' is not a pointer, but '%T'", orig_type);
saw_error = true;
}
type_left = type;
type_left->kind != TYPE_COMPOUND_UNION) {
if (is_type_valid(type_left) && !saw_error) {
- errorf(HERE,
+ errorf(&pos,
"request for member '%Y' in something not a struct or union, but '%T'",
symbol, type_left);
}
compound_t *compound = type_left->compound.compound;
if (!compound->complete) {
- errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+ errorf(&pos, "request for member '%Y' in incomplete type '%T'",
symbol, type_left);
return create_invalid_expression();
}
type_qualifiers_t qualifiers = type_left->base.qualifiers;
- expression_t *result
- = find_create_select(HERE, addr, qualifiers, compound, symbol);
+ expression_t *result =
+ find_create_select(&pos, addr, qualifiers, compound, symbol);
if (result == NULL) {
- errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+ errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
return create_invalid_expression();
}
/* report exact scope in error messages (like "in argument 3") */
char buf[64];
snprintf(buf, sizeof(buf), "call argument %u", pos);
- report_assign_error(error, expected_type, arg_expr, buf,
- &arg_expr->base.source_position);
+ report_assign_error(error, expected_type, arg_expr, buf,
+ &arg_expr->base.source_position);
} 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) &&
if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
&& !may_be_register) {
errorf(&expression->base.source_position,
- "address of register %s '%Y' requested",
- get_entity_kind_name(entity->kind), entity->base.symbol);
+ "address of register %s '%Y' requested",
+ get_entity_kind_name(entity->kind), entity->base.symbol);
}
if (entity->kind == ENTITY_VARIABLE) {
expression->base.type = arithmetic_type;
}
+static void semantic_binexpr_integer(binary_expression_t *const expression)
+{
+ expression_t *const left = expression->left;
+ expression_t *const right = expression->right;
+ type_t *const orig_type_left = left->base.type;
+ type_t *const orig_type_right = right->base.type;
+ type_t *const type_left = skip_typeref(orig_type_left);
+ type_t *const type_right = skip_typeref(orig_type_right);
+
+ if (!is_type_integer(type_left) || !is_type_integer(type_right)) {
+ /* TODO: improve error message */
+ if (is_type_valid(type_left) && is_type_valid(type_right)) {
+ errorf(&expression->base.source_position,
+ "operation needs integer types");
+ }
+ return;
+ }
+
+ type_t *const result_type = semantic_arithmetic(type_left, type_right);
+ expression->left = create_implicit_cast(left, result_type);
+ expression->right = create_implicit_cast(right, result_type);
+ expression->base.type = result_type;
+}
+
static void warn_div_by_zero(binary_expression_t const *const expression)
{
if (!warning.div_by_zero ||
CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_comparison)
CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_comparison)
CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_comparison)
-CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_integer)
CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, PREC_OR, semantic_logical_op)
CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, PREC_LOGICAL_AND, semantic_logical_op)
CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, PREC_ASSIGNMENT, semantic_binexpr_assign)
* @param precedence the precedence of the operator
*/
static void register_infix_parser(parse_expression_infix_function parser,
- int token_type, precedence_t precedence)
+ int token_type, precedence_t precedence)
{
expression_parser_function_t *entry = &expression_parsers[token_type];
return create_invalid_statement();
}
-static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
{
statement_t *inner_stmt;
switch (token.type) {
case '}':
- errorf(HERE, "%s at end of compound statement", label);
+ errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
inner_stmt = create_invalid_statement();
break;
case ';':
- if (eat_empty_stmt) {
+ if (label->kind == STATEMENT_LABEL) {
/* Eat an empty statement here, to avoid the warning about an empty
* statement after a label. label:; is commonly used to have a label
* before a closing brace. */
default:
inner_stmt = parse_statement();
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+ errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
}
break;
}
errorf(pos, "case label not within a switch statement");
}
- statement->case_label.statement = parse_label_inner_statement("case label", false);
+ statement->case_label.statement = parse_label_inner_statement(statement, "case label");
POP_PARENT;
return statement;
"'default' label not within a switch statement");
}
- statement->case_label.statement = parse_label_inner_statement("default label", false);
+ statement->case_label.statement = parse_label_inner_statement(statement, "default label");
POP_PARENT;
return statement;
eat(':');
- statement->label.statement = parse_label_inner_statement("label", true);
+ statement->label.statement = parse_label_inner_statement(statement, "label");
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
}
} else {
assign_error_t error = semantic_assign(return_type, return_value);
- report_assign_error(error, return_type, return_value, "'return'",
- pos);
+ report_assign_error(error, return_type, return_value, "'return'",
+ pos);
}
return_value = create_implicit_cast(return_value, return_type);
/* check for returning address of a local var */
if (warning.other && return_value != NULL
- && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+ && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
const expression_t *expression = return_value->unary.value;
if (expression_is_local_variable(expression)) {
warningf(pos, "function returns address of local variable");
/* 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");
+ "'return' without value, in function returning non-void");
} else {
warningf(pos,
- "'return' without value, in function returning non-void");
+ "'return' without value, in function returning non-void");
}
}
statement->returns.value = return_value;
if (entity != NULL
&& entity->kind != ENTITY_NAMESPACE
&& entity->base.parent_scope == current_scope) {
- if (!is_error_entity(entity)) {
+ if (is_entity_valid(entity)) {
error_redefined_as_different_kind(&token.source_position,
entity, ENTITY_NAMESPACE);
}
static void parse_linkage_specification(void)
{
eat(T_extern);
- assert(token.type == T_STRING_LITERAL);
const char *linkage = parse_string_literals().begin;
add_anchor_token(T_EOF);
#ifndef NDEBUG
+ /* make a copy of the anchor set, so we can check if it is restored after parsing */
unsigned char token_anchor_copy[T_LAST_TOKEN];
memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
#endif
while (token.type != T_EOF && token.type != '}') {
#ifndef NDEBUG
bool anchor_leak = false;
- for (int i = 0; i != T_LAST_TOKEN; ++i) {
+ for (int i = 0; i < T_LAST_TOKEN; ++i) {
unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
+ /* the anchor set and its copy differs */
errorf(HERE, "Leaked anchor token %k %d times", i, count);
anchor_leak = true;
}
}
if (in_gcc_extension) {
+ /* an gcc extension scope was not closed */
errorf(HERE, "Leaked __extension__");
anchor_leak = true;
}