Be more consistent, when talking about types in error messages.
[cparser] / parser.c
index 0325add..a6430d2 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -84,7 +84,6 @@ struct declaration_specifiers_t {
        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. */
 };
 
 /**
@@ -98,6 +97,14 @@ typedef struct parse_initializer_env_t {
        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. */
@@ -737,15 +744,6 @@ void parse_error_expected(const char *message, ...)
        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.
  */
@@ -3414,7 +3412,7 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
        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);
@@ -3429,10 +3427,11 @@ static void parse_microsoft_based(declaration_specifiers_t *specifiers)
        } 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;
 
@@ -3591,15 +3590,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        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:
@@ -3733,6 +3723,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                        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();
@@ -3752,6 +3743,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                                switch (la1_type) {
                                        DECLARATION_START
                                        case T_IDENTIFIER:
+                                       case '&':
                                        case '*': {
                                                errorf(HERE, "%K does not name a type", &token);
 
@@ -3763,7 +3755,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 
                                                next_token();
                                                saw_error = true;
-                                               if (la1_type == '*')
+                                               if (la1_type == '&' || la1_type == '*')
                                                        goto finish_specifiers;
                                                continue;
                                        }
@@ -4034,7 +4026,9 @@ static void semantic_parameter(declaration_t *declaration)
        /* 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:
@@ -4047,16 +4041,20 @@ static void semantic_parameter(declaration_t *declaration)
        }
 
        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);
        }
 }
@@ -4169,6 +4167,7 @@ end_error:
 typedef enum construct_type_kind_t {
        CONSTRUCT_INVALID,
        CONSTRUCT_POINTER,
+       CONSTRUCT_REFERENCE,
        CONSTRUCT_FUNCTION,
        CONSTRUCT_ARRAY
 } construct_type_kind_t;
@@ -4183,6 +4182,12 @@ typedef struct parsed_pointer_t parsed_pointer_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;
@@ -4206,7 +4211,7 @@ struct construct_base_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('*');
 
@@ -4214,8 +4219,20 @@ static construct_type_t *parse_pointer_declarator(void)
        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)
@@ -4252,7 +4269,7 @@ 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,
@@ -4304,9 +4321,42 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
 
        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;
@@ -4319,6 +4369,10 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env,
                /* 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;
@@ -4477,8 +4531,7 @@ static void parse_declaration_attributes(entity_t *entity)
        }
 }
 
-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) {
@@ -4511,12 +4564,25 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                }
 
                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);
 
@@ -4578,7 +4644,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        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);
@@ -4655,7 +4721,7 @@ static type_t *parse_abstract_declarator(type_t *base_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);
        }
@@ -5075,6 +5141,7 @@ static void parse_anonymous_declaration_rest(
                const declaration_specifiers_t *specifiers)
 {
        eat(';');
+       anonymous_entity = NULL;
 
        if (warning.other) {
                if (specifiers->storage_class != STORAGE_CLASS_NONE) {
@@ -5103,6 +5170,26 @@ static void parse_anonymous_declaration_rest(
        }
 }
 
+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)
@@ -5116,6 +5203,8 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                        parse_init_declarator_rest(entity);
                }
 
+               check_variable_type_complete(entity);
+
                if (token.type != ',')
                        break;
                eat(',');
@@ -7825,6 +7914,18 @@ static void warn_reference_address_as_bool(expression_t const* expr)
        }
 }
 
+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 ? ... : ...'.
  *
@@ -7837,18 +7938,11 @@ static expression_t *parse_conditional_expression(expression_t *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;
@@ -8179,15 +8273,8 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
 
 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;
 }
 
@@ -8776,25 +8863,10 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
  */
 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;
 }
 
@@ -9569,7 +9641,9 @@ static statement_t *parse_if(void)
        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(')');
@@ -9710,7 +9784,9 @@ static statement_t *parse_while(void)
        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(')');
@@ -9744,7 +9820,9 @@ static statement_t *parse_do(void)
        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(')');
@@ -9774,22 +9852,20 @@ static statement_t *parse_for(void)
        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(';');
        }
 
@@ -9797,7 +9873,9 @@ static statement_t *parse_for(void)
                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(';');
        }
@@ -10267,6 +10345,7 @@ static statement_t *intern_parse_statement(void)
                         * 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;