symbol_t *get_property_sym; /**< the name of the get property if set. */
symbol_t *put_property_sym; /**< the name of the put property if set. */
type_t *type;
- variable_t *based_variable; /**< Microsoft __based variable. */
};
/**
bool must_be_constant;
} parse_initializer_env_t;
+/**
+ * Capture a MS __base extension.
+ */
+typedef struct based_spec_t {
+ source_position_t source_position;
+ variable_t *base_variable;
+} based_spec_t;
+
typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
/** The current token. */
va_end(ap);
}
-/**
- * Report a type error.
- */
-static void type_error(const char *msg, const source_position_t *source_position,
- type_t *type)
-{
- errorf(source_position, "%s, but found type '%T'", msg, type);
-}
-
/**
* Report an incompatible type.
*/
return entity;
}
-static void parse_microsoft_based(declaration_specifiers_t *specifiers)
+static void parse_microsoft_based(based_spec_t *based_spec)
{
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing __based", T_IDENTIFIER, NULL);
} else {
variable_t *variable = &entity->variable;
- if (specifiers->based_variable != NULL) {
+ if (based_spec->base_variable != NULL) {
errorf(HERE, "__based type qualifier specified more than once");
}
- specifiers->based_variable = variable;
+ based_spec->source_position = token.source_position;
+ based_spec->base_variable = variable;
type_t *const type = variable->base.type;
expect(')');
break;
- case T__based:
- next_token();
- expect('(');
- add_anchor_token(')');
- parse_microsoft_based(specifiers);
- rem_anchor_token(')');
- expect(')');
- break;
-
case T___thread:
switch (specifiers->storage_class) {
case STORAGE_CLASS_NONE:
case T_inline:
case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */
case T_IDENTIFIER:
+ case '&':
case '*':
errorf(HERE, "discarding stray %K in declaration specifier", &token);
next_token();
switch (la1_type) {
DECLARATION_START
case T_IDENTIFIER:
+ case '&':
case '*': {
errorf(HERE, "%K does not name a type", &token);
next_token();
saw_error = true;
- if (la1_type == '*')
+ if (la1_type == '&' || la1_type == '*')
goto finish_specifiers;
continue;
}
/* TODO: improve error messages */
source_position_t const* const pos = &declaration->base.source_position;
- /* §6.9.1:6 */
+ /* §6.9.1:6 The declarations in the declaration list shall contain no
+ * storage-class specifier other than register and no
+ * initializations. */
switch (declaration->declared_storage_class) {
/* Allowed storage classes */
case STORAGE_CLASS_NONE:
}
type_t *const orig_type = declaration->type;
- /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic
- * sugar. Turn it into a pointer.
- * §6.7.5.3(8): A declaration of a parameter as ``function returning type''
- * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1.
+ /* §6.7.5.3:7 A declaration of a parameter as ``array of type'' shall be
+ * adjusted to ``qualified pointer to type'', [...]
+ * §6.7.5.3:8 A declaration of a parameter as ``function returning type''
+ * shall be adjusted to ``pointer to function returning type'',
+ * as in 6.3.2.1.
*/
type_t *const type = automatic_type_conversion(orig_type);
declaration->type = type;
+ /* §6.7.5.3:4 After adjustment, the parameters in a parameter type list in
+ * a function declarator that is part of a definition of that
+ * function shall not have incomplete type. */
if (is_type_incomplete(skip_typeref(type))) {
- errorf(pos, "parameter '%#T' is of incomplete type",
+ errorf(pos, "parameter '%#T' has incomplete type",
orig_type, declaration->base.symbol);
}
}
typedef enum construct_type_kind_t {
CONSTRUCT_INVALID,
CONSTRUCT_POINTER,
+ CONSTRUCT_REFERENCE,
CONSTRUCT_FUNCTION,
CONSTRUCT_ARRAY
} construct_type_kind_t;
struct parsed_pointer_t {
construct_type_t construct_type;
type_qualifiers_t type_qualifiers;
+ variable_t *base_variable; /**< MS __based extension. */
+};
+
+typedef struct parsed_reference_t parsed_reference_t;
+struct parsed_reference_t {
+ construct_type_t construct_type;
};
typedef struct construct_function_type_t construct_function_type_t;
type_t *type;
};
-static construct_type_t *parse_pointer_declarator(void)
+static construct_type_t *parse_pointer_declarator(variable_t *base_variable)
{
eat('*');
memset(pointer, 0, sizeof(pointer[0]));
pointer->construct_type.kind = CONSTRUCT_POINTER;
pointer->type_qualifiers = parse_type_qualifiers();
+ pointer->base_variable = base_variable;
- return (construct_type_t*) pointer;
+ return &pointer->construct_type;
+}
+
+static construct_type_t *parse_reference_declarator(void)
+{
+ eat('&');
+
+ parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0]));
+ memset(reference, 0, sizeof(reference[0]));
+ reference->construct_type.kind = CONSTRUCT_REFERENCE;
+
+ return (construct_type_t*)reference;
}
static construct_type_t *parse_array_declarator(void)
expect(']');
end_error:
- return (construct_type_t*) array;
+ return &array->construct_type;
}
static construct_type_t *parse_function_declarator(scope_t *scope,
decl_modifiers_t modifiers = parse_attributes(&attributes);
- /* pointers */
- while (token.type == '*') {
- construct_type_t *type = parse_pointer_declarator();
+ /* MS __based extension */
+ based_spec_t base_spec;
+ base_spec.base_variable = NULL;
+
+ for (;;) {
+ construct_type_t *type;
+ switch (token.type) {
+ case '&':
+ if (!(c_mode & _CXX))
+ errorf(HERE, "references are only available for C++");
+ if (base_spec.base_variable != NULL)
+ warningf(&base_spec.source_position,
+ "__based does not precede a pointer operator, ignored");
+ type = parse_reference_declarator();
+ /* consumed */
+ base_spec.base_variable = NULL;
+ break;
+
+ case '*':
+ type = parse_pointer_declarator(base_spec.base_variable);
+ /* consumed */
+ base_spec.base_variable = NULL;
+ break;
+
+ case T__based:
+ next_token();
+ expect('(');
+ add_anchor_token(')');
+ parse_microsoft_based(&base_spec);
+ rem_anchor_token(')');
+ expect(')');
+ continue;
+
+ default:
+ goto ptr_operator_end;
+ }
if (last == NULL) {
first = type;
/* TODO: find out if this is correct */
modifiers |= parse_attributes(&attributes);
}
+ptr_operator_end:
+ if (base_spec.base_variable != NULL)
+ warningf(&base_spec.source_position,
+ "__based does not precede a pointer operator, ignored");
if (env != NULL) {
modifiers |= env->modifiers;
}
}
-static type_t *construct_declarator_type(construct_type_t *construct_list,
- type_t *type, variable_t *variable)
+static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
{
construct_type_t *iter = construct_list;
for (; iter != NULL; iter = iter->next) {
}
case CONSTRUCT_POINTER: {
+ if (is_type_reference(skip_typeref(type)))
+ errorf(HERE, "cannot declare a pointer to reference");
+
parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
- type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, variable);
+ type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable);
continue;
}
+ case CONSTRUCT_REFERENCE:
+ if (is_type_reference(skip_typeref(type)))
+ errorf(HERE, "cannot declare a reference to reference");
+
+ type = make_reference_type(type);
+ continue;
+
case CONSTRUCT_ARRAY: {
+ if (is_type_reference(skip_typeref(type)))
+ errorf(HERE, "cannot declare an array of references");
+
parsed_array_t *parsed_array = (parsed_array_t*) iter;
type_t *array_type = allocate_type_zero(TYPE_ARRAY);
construct_type_t *construct_type
= parse_inner_declarator(&env, may_be_abstract);
- type_t *type = construct_declarator_type(construct_type, specifiers->type, specifiers->based_variable);
+ type_t *type = construct_declarator_type(construct_type, specifiers->type);
if (construct_type != NULL) {
obstack_free(&temp_obst, construct_type);
{
construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
- type_t *result = construct_declarator_type(construct_type, base_type, NULL);
+ type_t *result = construct_declarator_type(construct_type, base_type);
if (construct_type != NULL) {
obstack_free(&temp_obst, construct_type);
}
const declaration_specifiers_t *specifiers)
{
eat(';');
+ anonymous_entity = NULL;
if (warning.other) {
if (specifiers->storage_class != STORAGE_CLASS_NONE) {
}
}
+static void check_variable_type_complete(entity_t *ent)
+{
+ if (ent->kind != ENTITY_VARIABLE)
+ return;
+
+ /* §6.7:7 If an identifier for an object is declared with no linkage, the
+ * type for the object shall be complete [...] */
+ declaration_t *decl = &ent->declaration;
+ if (decl->storage_class != STORAGE_CLASS_NONE)
+ return;
+
+ type_t *type = decl->type;
+ if (!is_type_incomplete(skip_typeref(type)))
+ return;
+
+ errorf(&ent->base.source_position, "variable '%#T' has incomplete type",
+ type, ent->base.symbol);
+}
+
+
static void parse_declaration_rest(entity_t *ndeclaration,
const declaration_specifiers_t *specifiers,
parsed_declaration_func finished_declaration)
parse_init_declarator_rest(entity);
}
+ check_variable_type_complete(entity);
+
if (token.type != ',')
break;
eat(',');
}
}
+static void semantic_condition(expression_t const *const expr,
+ char const *const context)
+{
+ type_t *const type = skip_typeref(expr->base.type);
+ if (is_type_scalar(type)) {
+ warn_reference_address_as_bool(expr);
+ } else if (is_type_valid(type)) {
+ errorf(&expr->base.source_position,
+ "%s must have scalar type", context);
+ }
+}
+
/**
* Parse a conditional expression, ie. 'expression ? ... : ...'.
*
conditional_expression_t *conditional = &result->conditional;
conditional->condition = expression;
- warn_reference_address_as_bool(expression);
-
eat('?');
add_anchor_token(':');
- /* 6.5.15.2 */
- type_t *const condition_type_orig = expression->base.type;
- type_t *const condition_type = skip_typeref(condition_type_orig);
- if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) {
- type_error("expected a scalar type in conditional condition",
- &expression->base.source_position, condition_type_orig);
- }
+ /* §6.5.15:2 The first operand shall have scalar type. */
+ semantic_condition(expression, "condition of conditional operator");
expression_t *true_expression = expression;
bool gnu_cond = false;
static void semantic_not(unary_expression_t *expression)
{
- type_t *const orig_type = expression->value->base.type;
- type_t *const type = skip_typeref(orig_type);
- if (!is_type_scalar(type) && is_type_valid(type)) {
- errorf(&expression->base.source_position,
- "operand of ! must be of scalar type");
- }
-
- warn_reference_address_as_bool(expression->value);
-
+ /* §6.5.3.3:1 The operand [...] of the ! operator, scalar type. */
+ semantic_condition(expression->value, "operand of !");
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
*/
static void semantic_logical_op(binary_expression_t *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);
-
- warn_reference_address_as_bool(left);
- warn_reference_address_as_bool(right);
-
- if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
- /* TODO: improve error message */
- if (is_type_valid(type_left) && is_type_valid(type_right)) {
- errorf(&expression->base.source_position,
- "operation needs scalar types");
- }
- return;
- }
-
+ /* §6.5.13:2 Each of the operands shall have scalar type.
+ * §6.5.14:2 Each of the operands shall have scalar type. */
+ semantic_condition(expression->left, "left operand of logical operator");
+ semantic_condition(expression->right, "right operand of logical operator");
expression->base.type = c_mode & _CXX ? type_bool : type_int;
}
add_anchor_token(')');
expression_t *const expr = parse_expression();
statement->ifs.condition = expr;
- warn_reference_address_as_bool(expr);
+ /* §6.8.4.1:1 The controlling expression of an if statement shall have
+ * scalar type. */
+ semantic_condition(expr, "condition of 'if'-statment");
mark_vars_read(expr, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->whiles.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
add_anchor_token(')');
expression_t *const cond = parse_expression();
statement->do_while.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'do-while'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(')');
expect(')');
expect('(');
add_anchor_token(')');
- if (token.type != ';') {
- if (is_declaration_specifier(&token, false)) {
- parse_declaration(record_entity);
- } else {
- add_anchor_token(';');
- expression_t *const init = parse_expression();
- statement->fors.initialisation = init;
- mark_vars_read(init, VAR_ANY);
- if (warning.unused_value && !expression_has_effect(init)) {
- warningf(&init->base.source_position,
- "initialisation of 'for'-statement has no effect");
- }
- rem_anchor_token(';');
- expect(';');
- }
+ if (token.type == ';') {
+ next_token();
+ } else if (is_declaration_specifier(&token, false)) {
+ parse_declaration(record_entity);
} else {
+ add_anchor_token(';');
+ expression_t *const init = parse_expression();
+ statement->fors.initialisation = init;
+ mark_vars_read(init, VAR_ANY);
+ if (warning.unused_value && !expression_has_effect(init)) {
+ warningf(&init->base.source_position,
+ "initialisation of 'for'-statement has no effect");
+ }
+ rem_anchor_token(';');
expect(';');
}
add_anchor_token(';');
expression_t *const cond = parse_expression();
statement->fors.condition = cond;
- warn_reference_address_as_bool(cond);
+ /* §6.8.5:2 The controlling expression of an iteration statement shall
+ * have scalar type. */
+ semantic_condition(cond, "condition of 'for'-statement");
mark_vars_read(cond, NULL);
rem_anchor_token(';');
}
* declaration types, so we guess a bit here to improve robustness
* for incorrect programs */
switch (la1_type) {
+ case '&':
case '*':
if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL)
goto expression_statment;