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. */
/** true in we are in a __extension__ context. */
static bool in_gcc_extension = false;
static struct obstack temp_obst;
+static entity_t *anonymous_entity;
#define PUSH_PARENT(stmt) \
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.
*/
eat(T_union);
}
- symbol_t *symbol = NULL;
+ symbol_t *symbol = NULL;
compound_t *compound = NULL;
if (token.type == T___attribute__) {
if (token.type == '{') {
parse_compound_type_entries(compound);
modifiers |= parse_attributes(&attributes);
+
+ if (symbol == NULL) {
+ assert(anonymous_entity == NULL);
+ anonymous_entity = (entity_t*)compound;
+ }
}
compound->modifiers |= modifiers;
eat('{');
if (token.type == '}') {
- next_token();
errorf(HERE, "empty enum not allowed");
+ next_token();
return;
}
parse_enum_entries(type);
parse_attributes(&attributes);
+
+ if (symbol == NULL) {
+ assert(anonymous_entity == NULL);
+ anonymous_entity = entity;
+ }
} else if (!entity->enume.complete && !(c_mode & _GNUC)) {
errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)",
symbol);
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);
}
}
parse_declaration_specifiers(&specifiers);
entity_t *entity = parse_declarator(&specifiers, true, false);
+ anonymous_entity = NULL;
return entity;
}
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);
entity->base.symbol = env.symbol;
entity->base.source_position = env.source_position;
entity->typedefe.type = type;
+
+ if (anonymous_entity != NULL) {
+ if (is_type_compound(type)) {
+ assert(anonymous_entity->compound.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_STRUCT ||
+ anonymous_entity->kind == ENTITY_UNION);
+ anonymous_entity->compound.alias = entity;
+ anonymous_entity = NULL;
+ } else if (is_type_enum(type)) {
+ assert(anonymous_entity->enume.alias == NULL);
+ assert(anonymous_entity->kind == ENTITY_ENUM);
+ anonymous_entity->enume.alias = entity;
+ anonymous_entity = NULL;
+ }
+ }
} else {
if (create_compound_member) {
entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
{
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(',');
expect(';');
end_error:
+ anonymous_entity = NULL;
rem_anchor_token(';');
rem_anchor_token(',');
}
entity_t *prev = find_compound_entry(compound, symbol);
if (prev != NULL) {
- assert(prev->base.symbol == symbol);
errorf(&entity->base.source_position,
"multiple declarations of symbol '%Y' (declared %P)",
symbol, &prev->base.source_position);
expect(';');
end_error:
- ;
+ anonymous_entity = NULL;
}
static void parse_compound_type_entries(compound_t *compound)
}
}
+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;