static statement_t *parse_compound_statement(bool inside_expression_statement);
static statement_t *parse_statement(void);
-static expression_t *parse_sub_expression(precedence_t);
+static expression_t *parse_subexpression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
static void parse_externals(void);
/**
* Expect the current token is the expected token.
* If not, generate an error, eat the current statement,
- * and goto the end_error label.
+ * and goto the error_label label.
*/
#define expect(expected, error_label) \
do { \
}
}
- ARR_SHRINKLEN(*stack_ptr, (int) new_top);
+ ARR_SHRINKLEN(*stack_ptr, new_top);
}
/**
}
type_t *const type = skip_typeref(expression->base.type);
- return
- is_type_integer(type) &&
- is_constant_expression(expression) &&
- !fold_constant_to_bool(expression);
+ if (!is_type_integer(type))
+ return false;
+ switch (is_constant_expression(expression)) {
+ case EXPR_CLASS_ERROR: return true;
+ case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
+ default: return false;
+ }
}
/**
return ASSIGN_WARNING_POINTER_FROM_INT;
}
} else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
- (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
- && is_type_pointer(type_right))) {
+ (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+ && is_type_pointer(type_right))) {
return ASSIGN_SUCCESS;
} else if ((is_type_compound(type_left) && is_type_compound(type_right))
|| (is_type_builtin(type_left) && is_type_builtin(type_right))) {
static expression_t *parse_constant_expression(void)
{
- expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
+ expression_t *result = parse_subexpression(PREC_CONDITIONAL);
- if (!is_constant_expression(result)) {
+ if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
errorf(&result->base.source_position,
"expression '%E' is not constant", result);
}
static expression_t *parse_assignment_expression(void)
{
- return parse_sub_expression(PREC_ASSIGNMENT);
+ return parse_subexpression(PREC_ASSIGNMENT);
}
static void warn_string_concat(const source_position_t *pos)
symbol_t *symbol = get_symbol_from_token();
if (symbol == NULL) {
parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
- goto end_error;
+ return NULL;
}
const char *name = symbol->string;
attribute->a.arguments = parse_attribute_arguments();
return attribute;
-
-end_error:
- return NULL;
}
static attribute_t *parse_attribute_gnu(void)
*/
static bool is_initializer_constant(const expression_t *expression)
{
- return is_constant_expression(expression)
- || is_address_constant(expression);
+ return
+ is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+ is_address_constant(expression) != EXPR_CLASS_VARIABLE;
}
/**
long array_size = type->array.size;
if (index >= array_size) {
errorf(&designator->source_position,
- "designator [%E] (%d) exceeds array size %d",
- array_index, index, array_size);
+ "designator [%E] (%d) exceeds array size %d",
+ array_index, index, array_size);
}
}
}
break;
char const* wrong;
- case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_stoarge_class;
- case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
- case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_stoarge_class;
-wrong_thread_stoarge_class:
+ case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_storage_class;
+ case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
+ case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_storage_class;
+wrong_thread_storage_class:
errorf(HERE, "'__thread' used with '%s'", wrong);
break;
}
parsed_array_t array;
};
+static construct_type_t *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size)
+{
+ construct_type_t *const cons = obstack_alloc(&temp_obst, size);
+ memset(cons, 0, size);
+ cons->kind = kind;
+ return cons;
+}
+
/* §6.7.5.1 */
static construct_type_t *parse_pointer_declarator(void)
{
eat('*');
- parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
- memset(pointer, 0, sizeof(pointer[0]));
- pointer->base.kind = CONSTRUCT_POINTER;
- pointer->type_qualifiers = parse_type_qualifiers();
- //pointer->base_variable = base_variable;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+ cons->pointer.type_qualifiers = parse_type_qualifiers();
+ //cons->pointer.base_variable = base_variable;
- return (construct_type_t*) pointer;
+ return cons;
}
/* ISO/IEC 14882:1998(E) §8.3.2 */
if (!(c_mode & _CXX))
errorf(HERE, "references are only available for C++");
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->reference));
- parsed_reference_t *reference = &cons->reference;
- memset(reference, 0, sizeof(*reference));
- cons->kind = CONSTRUCT_REFERENCE;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
return cons;
}
eat('[');
add_anchor_token(']');
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->array));
- parsed_array_t *array = &cons->array;
- memset(array, 0, sizeof(*array));
- cons->kind = CONSTRUCT_ARRAY;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
+ parsed_array_t *const array = &cons->array;
- if (next_if(T_static))
- array->is_static = true;
+ bool is_static = next_if(T_static);
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
- if (type_qualifiers != 0 && next_if(T_static))
- array->is_static = true;
+
+ if (!is_static)
+ is_static = next_if(T_static);
+
array->type_qualifiers = type_qualifiers;
+ array->is_static = is_static;
+ expression_t *size = NULL;
if (token.type == '*' && look_ahead(1)->type == ']') {
array->is_variable = true;
next_token();
} else if (token.type != ']') {
- expression_t *const size = parse_assignment_expression();
+ size = parse_assignment_expression();
/* §6.7.5.2:1 Array size must have integer type */
type_t *const orig_type = size->base.type;
mark_vars_read(size, NULL);
}
+ if (is_static && size == NULL)
+ errorf(HERE, "static array parameters require a size");
+
rem_anchor_token(']');
expect(']', end_error);
parse_parameters(ftype, scope);
- construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->function));
- construct_function_type_t *function = &cons->function;
- memset(function, 0, sizeof(*function));
- cons->kind = CONSTRUCT_FUNCTION;
- function->function_type = type;
+ construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+ cons->function.function_type = type;
return cons;
}
}
rem_anchor_token(')');
expect(')', end_error);
+ } else if (!env->may_be_abstract) {
+ errorf(HERE, "declarator must have a name");
+ goto error_out;
}
break;
default:
if (env->may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
+error_out:
eat_until_anchor();
return NULL;
}
array_type->array.size_expression = size_expression;
if (size_expression != NULL) {
- if (is_constant_expression(size_expression)) {
- long const size
- = fold_constant_to_int(size_expression);
- array_type->array.size = size;
- array_type->array.size_constant = true;
- /* §6.7.5.2:1 If the expression is a constant expression, it shall
- * have a value greater than zero. */
- if (size <= 0) {
- if (size < 0 || !GNU_MODE) {
- errorf(&size_expression->base.source_position,
- "size of array must be greater than zero");
- } else if (warning.other) {
- warningf(&size_expression->base.source_position,
- "zero length arrays are a GCC extension");
+ switch (is_constant_expression(size_expression)) {
+ case EXPR_CLASS_CONSTANT: {
+ long const size = fold_constant_to_int(size_expression);
+ array_type->array.size = size;
+ array_type->array.size_constant = true;
+ /* §6.7.5.2:1 If the expression is a constant expression, it shall
+ * have a value greater than zero. */
+ if (size <= 0) {
+ if (size < 0 || !GNU_MODE) {
+ errorf(&size_expression->base.source_position,
+ "size of array must be greater than zero");
+ } else if (warning.other) {
+ warningf(&size_expression->base.source_position,
+ "zero length arrays are a GCC extension");
+ }
}
+ break;
}
- } else {
- array_type->array.is_vla = true;
+
+ case EXPR_CLASS_VARIABLE:
+ array_type->array.is_vla = true;
+ break;
+
+ case EXPR_CLASS_ERROR:
+ break;
}
}
bool in_function_scope = current_function != NULL;
if (specifiers->thread_local || (
- specifiers->storage_class != STORAGE_CLASS_EXTERN &&
- specifiers->storage_class != STORAGE_CLASS_NONE &&
- (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
- )) {
+ specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+ specifiers->storage_class != STORAGE_CLASS_NONE &&
+ (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+ )) {
errorf(&env.source_position,
"invalid storage class for function '%Y'", env.symbol);
}
static int determine_truth(expression_t const* const cond)
{
return
- !is_constant_expression(cond) ? 0 :
- fold_constant_to_bool(cond) ? 1 :
+ is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+ fold_constant_to_bool(cond) ? 1 :
-1;
}
if (!expression_returns(expr))
return;
- if (is_constant_expression(expr)) {
+ if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
long const val = fold_constant_to_int(expr);
case_label_statement_t * defaults = NULL;
for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
bit_size = get_type_size(base_type) * 8;
}
- if (is_constant_expression(size)) {
+ if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
long v = fold_constant_to_int(size);
const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
cast->base.source_position = source_position;
- expression_t *value = parse_sub_expression(PREC_CAST);
+ expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
cast->unary.value = value;
}
errorf(HERE, "unexpected token %K, expected an expression", &token);
+ eat_until_anchor();
return create_invalid_expression();
}
goto typeprop_expression;
}
} else {
- expression = parse_sub_expression(PREC_UNARY);
+ expression = parse_subexpression(PREC_UNARY);
typeprop_expression:
tp_expression->typeprop.tp_expression = expression;
/* argument must be constant */
call_argument_t *argument = call->arguments;
- if (! is_constant_expression(argument->expression)) {
+ 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_prefetch: {
+ 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",
+ call->function->reference.entity->base.symbol);
+ }
+ break;
+ case bk_gnu_builtin_prefetch:
/* second and third argument must be constant if existent */
+ if (call->arguments == NULL)
+ break;
call_argument_t *rw = call->arguments->next;
call_argument_t *locality = NULL;
if (rw != NULL) {
- if (! is_constant_expression(rw->expression)) {
+ 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);
locality = rw->next;
}
if (locality != NULL) {
- if (! is_constant_expression(locality->expression)) {
+ 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);
locality = rw->next;
}
break;
- }
default:
break;
}
/* do default promotion for other arguments */
for (; argument != NULL; argument = argument->next) {
type_t *type = argument->expression->base.type;
+ if (!is_type_object(skip_typeref(type))) {
+ errorf(&argument->expression->base.source_position,
+ "call argument '%E' must not be void", argument->expression);
+ }
type = get_default_promoted_type(type);
expect(':', end_error);
end_error:;
expression_t *false_expression =
- parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
+ parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
type_t *const orig_true_type = true_expression->base.type;
type_t *const orig_false_type = false_expression->base.type;
} else if (is_type_arithmetic(true_type)
&& is_type_arithmetic(false_type)) {
result_type = semantic_arithmetic(true_type, false_type);
-
- true_expression = create_implicit_cast(true_expression, result_type);
- false_expression = create_implicit_cast(false_expression, result_type);
-
- conditional->true_expression = true_expression;
- conditional->false_expression = false_expression;
- conditional->base.type = result_type;
} else if (same_compound_type(true_type, false_type)) {
/* just take 1 of the 2 types */
result_type = true_type;
result_type = pointer_type;
} else {
if (is_type_valid(other_type)) {
- type_error_incompatible("while parsing conditional",
+ type_error_incompatible("while parsing conditional",
&expression->base.source_position, true_type, false_type);
}
result_type = type_error_type;
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- expression_t *expression = parse_sub_expression(PREC_UNARY);
+ expression_t *expression = parse_subexpression(PREC_UNARY);
in_gcc_extension = old_gcc_extension;
return expression;
}
end_error:;
}
- expression_t *const value = parse_sub_expression(PREC_CAST);
+ expression_t *const value = parse_subexpression(PREC_CAST);
result->unary.value = value;
type_t *const type = skip_typeref(value->base.type);
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
eat(token_type); \
- unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
+ unary_expression->unary.value = parse_subexpression(PREC_UNARY); \
\
sfunc(&unary_expression->unary); \
\
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) &&
+ if (is_type_integer(right->base.type) &&
+ is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
!fold_constant_to_bool(right)) {
warningf(&expression->base.source_position, "division by zero");
}
type_left = promote_integer(type_left);
- if (is_constant_expression(right)) {
+ if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
long count = fold_constant_to_int(right);
if (count < 0) {
warningf(&right->base.source_position,
static bool maybe_negative(expression_t const *const expr)
{
- return
- !is_constant_expression(expr) ||
- fold_constant_to_int(expr) < 0;
+ switch (is_constant_expression(expr)) {
+ case EXPR_CLASS_ERROR: return false;
+ case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+ default: return true;
+ }
}
/**
binexpr->binary.left = left; \
eat(token_type); \
\
- expression_t *right = parse_sub_expression(prec_r); \
+ expression_t *right = parse_subexpression(prec_r); \
\
binexpr->binary.right = right; \
sfunc(&binexpr->binary); \
CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma)
-static expression_t *parse_sub_expression(precedence_t precedence)
+static expression_t *parse_subexpression(precedence_t precedence)
{
if (token.type < 0) {
return expected_expression_error();
*/
static expression_t *parse_expression(void)
{
- return parse_sub_expression(PREC_EXPRESSION);
+ return parse_subexpression(PREC_EXPRESSION);
}
/**
expect('(', end_error);
add_anchor_token(')');
- add_anchor_token(':');
+ if (token.type != T_STRING_LITERAL) {
+ parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
+ goto end_of_asm;
+ }
asm_statement->asm_text = parse_string_literals();
+ add_anchor_token(':');
if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
return create_invalid_statement();
}
+static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+{
+ statement_t *inner_stmt;
+ switch (token.type) {
+ case '}':
+ errorf(HERE, "%s at end of compound statement", label);
+ inner_stmt = create_invalid_statement();
+ break;
+
+ case ';':
+ if (eat_empty_stmt) {
+ /* 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. */
+ inner_stmt = create_empty_statement();
+ next_token();
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ inner_stmt = parse_statement();
+ if (inner_stmt->kind == STATEMENT_DECLARATION) {
+ errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+ }
+ break;
+ }
+ return inner_stmt;
+}
+
/**
* Parse a case statement.
*/
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(skip_typeref(expression->base.type))) {
+ expression_classification_t const expr_class = is_constant_expression(expression);
+ if (expr_class != EXPR_CLASS_CONSTANT) {
+ if (expr_class != EXPR_CLASS_ERROR) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
if (next_if(T_DOTDOTDOT)) {
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(skip_typeref(end_range->base.type))) {
+ expression_classification_t const end_class = is_constant_expression(end_range);
+ if (end_class != EXPR_CLASS_CONSTANT) {
+ if (end_class != EXPR_CLASS_ERROR) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
errorf(pos, "case label not within a switch statement");
}
- statement_t *const inner_stmt = parse_statement();
- statement->case_label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after case label");
- }
+ statement->case_label.statement = parse_label_inner_statement("case label", false);
POP_PARENT;
return statement;
PUSH_PARENT(statement);
expect(':', end_error);
+end_error:
+
if (current_switch != NULL) {
const case_label_statement_t *def_label = current_switch->default_label;
if (def_label != NULL) {
"'default' label not within a switch statement");
}
- statement_t *const inner_stmt = parse_statement();
- statement->case_label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after default label");
- }
+ statement->case_label.statement = parse_label_inner_statement("default label", false);
POP_PARENT;
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
eat(':');
- if (token.type == '}') {
- errorf(HERE, "label at end of compound statement");
- statement->label.statement = create_invalid_statement();
- } else if (token.type == ';') {
- /* 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. */
- statement->label.statement = create_empty_statement();
- next_token();
- } else {
- statement_t *const inner_stmt = parse_statement();
- statement->label.statement = inner_stmt;
- if (inner_stmt->kind == STATEMENT_DECLARATION) {
- errorf(&inner_stmt->base.source_position, "declaration after label");
- }
- }
+ statement->label.statement = parse_label_inner_statement("label", true);
/* remember the labels in a list for later checking */
*label_anchor = &statement->label;
else
parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
eat_until_anchor();
- goto end_error;
+ return create_invalid_statement();
}
/* remember the goto's in a list for later checking */
expect(';', end_error);
- return statement;
end_error:
- return create_invalid_statement();
+ return statement;
}
/**
eat(T___label__);
- entity_t *begin = NULL, *end = NULL;
-
+ entity_t *begin = NULL;
+ entity_t *end = NULL;
+ entity_t **anchor = &begin;
do {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing local label declaration",
entity->base.source_position = token.source_position;
entity->base.symbol = symbol;
- if (end != NULL)
- end->base.next = entity;
- end = entity;
- if (begin == NULL)
- begin = entity;
+ *anchor = entity;
+ anchor = &entity->base.next;
+ end = entity;
environment_push(entity);
}
next_token();
} while (next_if(','));
- eat(';');
+ expect(';', end_error);
end_error:
statement->declaration.declarations_begin = begin;
statement->declaration.declarations_end = end;
switch (la1_type) {
case '&':
case '*':
- if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL)
- goto expression_statment;
- /* FALLTHROUGH */
-
+ if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+ default:
+ statement = parse_expression_statement();
+ } else {
DECLARATION_START
case T_IDENTIFIER:
- statement = parse_declaration_statement();
- break;
-
- default:
-expression_statment:
- statement = parse_expression_statement();
+ statement = parse_declaration_statement();
+ }
break;
}
}