Warn about type qualifiers in the return type of function types.
[cparser] / parser.c
index 7bfb77f..119677c 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -134,6 +134,9 @@ static struct obstack      temp_obst;
 
 static source_position_t null_position = { NULL, 0 };
 
+/** special symbol used for anonymous entities. */
+static const symbol_t *sym_anonymous = NULL;
+
 /* symbols for Microsoft extended-decl-modifier */
 static const symbol_t *sym_align      = NULL;
 static const symbol_t *sym_allocate   = NULL;
@@ -552,6 +555,7 @@ static void restore_anchor_state(int token_type, int count)
 static void rem_anchor_token(int token_type)
 {
        assert(0 <= token_type && token_type < T_LAST_TOKEN);
+       assert(token_anchor_set[token_type] != 0);
        --token_anchor_set[token_type];
 }
 
@@ -693,18 +697,18 @@ static void type_error_incompatible(const char *msg,
  * If not, generate an error, eat the current statement,
  * and goto the end_error label.
  */
-#define expect(expected)                              \
-       do {                                              \
-    if (UNLIKELY(token.type != (expected))) {          \
-        parse_error_expected(NULL, (expected), NULL); \
-               add_anchor_token(expected);                   \
-        eat_until_anchor();                           \
-        if (token.type == expected)                   \
-               next_token();                             \
-               rem_anchor_token(expected);                   \
-        goto end_error;                               \
-    }                                                 \
-    next_token();                                     \
+#define expect(expected)                                  \
+       do {                                                  \
+               if (UNLIKELY(token.type != (expected))) {         \
+                       parse_error_expected(NULL, (expected), NULL); \
+                       add_anchor_token(expected);                   \
+                       eat_until_anchor();                           \
+                       if (token.type == expected)                   \
+                               next_token();                             \
+                       rem_anchor_token(expected);                   \
+                       goto end_error;                               \
+               }                                                 \
+               next_token();                                     \
        } while (0)
 
 static void set_scope(scope_t *new_scope)
@@ -1497,12 +1501,12 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute)
        add_anchor_token(',');
        parse_constant_expression();
        rem_anchor_token(',');
-       rem_anchor_token('(');
+       rem_anchor_token(')');
 
        expect(',');
        add_anchor_token(')');
        parse_constant_expression();
-       rem_anchor_token('(');
+       rem_anchor_token(')');
        expect(')');
        return;
 end_error:
@@ -2471,6 +2475,10 @@ finish_designator:
 
                        if (type == NULL) {
                                /* we are already outside, ... */
+                               if (is_type_compound(outer_type) &&
+                                   !outer_type->compound.declaration->init.complete) {
+                                       goto error_parse_next;
+                               }
                                goto error_excess;
                        }
 
@@ -3129,33 +3137,38 @@ static void finish_struct_type(compound_type_t *type) {
        if (! struct_decl->init.complete)
                return;
 
-       il_size_t      size      = 0;
-       il_size_t      new_size;
-       il_alignment_t alignment = 1;
-       bool           need_pad  = false;
+       il_size_t      size           = 0;
+       il_size_t      offset;
+       il_alignment_t alignment      = 1;
+       bool           need_pad       = false;
 
        declaration_t *entry = struct_decl->scope.declarations;
        for (; entry != NULL; entry = entry->next) {
                if (entry->namespc != NAMESPACE_NORMAL)
                        continue;
 
-               type_t         *m_type      = skip_typeref(entry->type);
-               il_alignment_t  m_alignment = m_type->base.alignment;
-
-               new_size = (size + m_alignment - 1) & -m_alignment;
+               type_t *m_type = skip_typeref(entry->type);
+               if (! is_type_valid(m_type)) {
+                       /* simply ignore errors here */
+                       continue;
+               }
+               il_alignment_t m_alignment = m_type->base.alignment;
                if (m_alignment > alignment)
                        alignment = m_alignment;
-               if (new_size > size)
+
+               offset = (size + m_alignment - 1) & -m_alignment;
+
+               if (offset > size)
                        need_pad = true;
-               entry->offset = new_size;
-               size = new_size + m_type->base.size;
+               entry->offset = offset;
+               size = offset + m_type->base.size;
        }
        if (type->base.alignment != 0) {
                alignment = type->base.alignment;
        }
 
-       new_size = (size + alignment - 1) & -alignment;
-       if (new_size > size)
+       offset = (size + alignment - 1) & -alignment;
+       if (offset > size)
                need_pad = true;
 
        if (warning.padded && need_pad) {
@@ -3168,7 +3181,7 @@ static void finish_struct_type(compound_type_t *type) {
                        type, struct_decl->symbol);
        }
 
-       type->base.size      = new_size;
+       type->base.size      = offset;
        type->base.alignment = alignment;
 }
 
@@ -3192,6 +3205,8 @@ static void finish_union_type(compound_type_t *type) {
                        continue;
 
                type_t *m_type = skip_typeref(entry->type);
+               if (! is_type_valid(m_type))
+                       continue;
 
                entry->offset = 0;
                if (m_type->base.size > size)
@@ -3573,10 +3588,8 @@ warn_about_long_long:
                default:
                        /* invalid specifier combination, give an error message */
                        if (type_specifiers == 0) {
-                               if (saw_error) {
-                                       specifiers->type = type_error_type;
-                                       return;
-                               }
+                               if (saw_error)
+                                       goto end_error;
 
                                if (!strict_mode) {
                                        if (warning.implicit_int) {
@@ -3595,15 +3608,13 @@ warn_about_long_long:
                        } else {
                                errorf(HERE, "multiple datatypes in declaration");
                        }
-                       atomic_type = ATOMIC_TYPE_INVALID;
+                       goto end_error;
                }
 
-               if (type_specifiers & SPECIFIER_COMPLEX &&
-                  atomic_type != ATOMIC_TYPE_INVALID) {
+               if (type_specifiers & SPECIFIER_COMPLEX) {
                        type                = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position);
                        type->complex.akind = atomic_type;
-               } else if (type_specifiers & SPECIFIER_IMAGINARY &&
-                         atomic_type != ATOMIC_TYPE_INVALID) {
+               } else if (type_specifiers & SPECIFIER_IMAGINARY) {
                        type                  = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position);
                        type->imaginary.akind = atomic_type;
                } else {
@@ -3626,7 +3637,10 @@ warn_about_long_long:
        }
 
        specifiers->type = result;
+       return;
+
 end_error:
+       specifiers->type = type_error_type;
        return;
 }
 
@@ -4153,6 +4167,10 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                                errorf(HERE, "function returning array is not allowed");
                                type = type_error_type;
                        } else {
+                               if (skipped_return_type->base.qualifiers != 0) {
+                                       warningf(HERE,
+                                               "type qualifiers in return type of function type are meaningless");
+                               }
                                type = function_type;
                        }
                        break;
@@ -4297,7 +4315,7 @@ static void check_type_of_main(const declaration_t *const decl, const function_t
                warningf(&decl->source_position,
                         "'main' is normally a non-static function");
        }
-       if (skip_typeref(func_type->return_type) != type_int) {
+       if (!types_compatible(skip_typeref(func_type->return_type), type_int)) {
                warningf(&decl->source_position,
                         "return type of 'main' should be 'int', but is '%T'",
                         func_type->return_type);
@@ -5373,7 +5391,7 @@ static void parse_external_declaration(void)
 
        add_anchor_token(',');
        add_anchor_token('=');
-       rem_anchor_token(';');
+       add_anchor_token(';');
 
        /* declarator is common to both function-definitions and declarations */
        declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
@@ -5511,12 +5529,40 @@ static void parse_external_declaration(void)
 }
 
 static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
-                                  source_position_t *source_position)
+                                  source_position_t *source_position,
+                                  const symbol_t *symbol)
 {
        type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position);
 
-       type->bitfield.base_type = base_type;
-       type->bitfield.size      = size;
+       type->bitfield.base_type       = base_type;
+       type->bitfield.size_expression = size;
+
+       il_size_t bit_size;
+       type_t *skipped_type = skip_typeref(base_type);
+       if (!is_type_integer(skipped_type)) {
+               errorf(HERE, "bitfield base type '%T' is not an integer type",
+                       base_type);
+               bit_size = 0;
+       } else {
+               bit_size = skipped_type->base.size * 8;
+       }
+
+       if (is_constant_expression(size)) {
+               long v = fold_constant(size);
+
+               if (v < 0) {
+                       errorf(source_position, "negative width in bit-field '%Y'",
+                               symbol);
+               } else if (v == 0) {
+                       errorf(source_position, "zero width for bit-field '%Y'",
+                               symbol);
+               } else if (bit_size > 0 && (il_size_t)v > bit_size) {
+                       errorf(source_position, "width of '%Y' exceeds its type",
+                               symbol);
+               } else {
+                       type->bitfield.bit_size = v;
+               }
+       }
 
        return type;
 }
@@ -5568,12 +5614,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                        type_t *base_type = specifiers->type;
                        expression_t *size = parse_constant_expression();
 
-                       if (!is_type_integer(skip_typeref(base_type))) {
-                               errorf(HERE, "bitfield base type '%T' is not an integer type",
-                                      base_type);
-                       }
-
-                       type_t *type = make_bitfield_type(base_type, size, &source_position);
+                       type_t *type = make_bitfield_type(base_type, size,
+                                       &source_position, sym_anonymous);
 
                        declaration                         = allocate_declaration_zero();
                        declaration->namespc                = NAMESPACE_NORMAL;
@@ -5593,12 +5635,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                                next_token();
                                expression_t *size = parse_constant_expression();
 
-                               if (!is_type_integer(type)) {
-                                       errorf(HERE, "bitfield base type '%T' is not an integer type",
-                                              orig_type);
-                               }
-
-                               type_t *bitfield_type = make_bitfield_type(orig_type, size, &source_position);
+                               type_t *bitfield_type = make_bitfield_type(orig_type, size,
+                                               &source_position, declaration->symbol);
                                declaration->type = bitfield_type;
                        } else {
                                /* TODO we ignore arrays for now... what is missing is a check
@@ -6050,11 +6088,9 @@ static expression_t *parse_reference(void)
        declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
 
        if (declaration == NULL) {
-               if (look_ahead(1)->type == '(') {
+               if (!strict_mode && look_ahead(1)->type == '(') {
                        /* an implicitly declared function */
-                       if (strict_mode) {
-                               errorf(HERE, "unknown symbol '%Y' found.", symbol);
-                       } else if (warning.implicit_function_declaration) {
+                       if (warning.implicit_function_declaration) {
                                warningf(HERE, "implicit declaration of function '%Y'",
                                        symbol);
                        }
@@ -6174,11 +6210,12 @@ static expression_t *parse_compound_literal(type_t *type)
  */
 static expression_t *parse_cast(void)
 {
+       add_anchor_token(')');
+
        source_position_t source_position = token.source_position;
 
        type_t *type  = parse_typename();
 
-       /* matching add_anchor_token() is at call site */
        rem_anchor_token(')');
        expect(')');
 
@@ -6207,6 +6244,8 @@ end_error:
  */
 static expression_t *parse_statement_expression(void)
 {
+       add_anchor_token(')');
+
        expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
 
        statement_t *statement           = parse_compound_statement(true);
@@ -6228,11 +6267,11 @@ static expression_t *parse_statement_expression(void)
        }
        expression->base.type = type;
 
+       rem_anchor_token(')');
        expect(')');
 
-       return expression;
 end_error:
-       return create_invalid_expression();
+       return expression;
 }
 
 /**
@@ -6241,7 +6280,6 @@ end_error:
 static expression_t *parse_parenthesized_expression(void)
 {
        eat('(');
-       add_anchor_token(')');
 
        switch(token.type) {
        case '{':
@@ -6257,13 +6295,13 @@ static expression_t *parse_parenthesized_expression(void)
                }
        }
 
+       add_anchor_token(')');
        expression_t *result = parse_expression();
        rem_anchor_token(')');
        expect(')');
 
-       return result;
 end_error:
-       return create_invalid_expression();
+       return result;
 }
 
 static expression_t *parse_function_keyword(void)
@@ -6440,17 +6478,15 @@ static expression_t *parse_va_start(void)
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                declaration_t *const decl = expr->reference.declaration;
-               if (decl == NULL)
-                       return create_invalid_expression();
-               if (decl->parent_scope == &current_function->scope &&
-                   decl->next == NULL) {
-                       expression->va_starte.parameter = decl;
-                       expect(')');
-                       return expression;
+               if (decl->parent_scope != &current_function->scope || decl->next != NULL) {
+                       errorf(&expr->base.source_position,
+                              "second argument of 'va_start' must be last parameter of the current function");
                }
+               expression->va_starte.parameter = decl;
+               expect(')');
+               return expression;
        }
-       errorf(&expr->base.source_position,
-              "second argument of 'va_start' must be last parameter of the current function");
+       expect(')');
 end_error:
        return create_invalid_expression();
 }
@@ -6919,9 +6955,8 @@ static expression_t *parse_typeprop(expression_kind_t const kind,
                tp_expression->typeprop.tp_expression = expression;
        }
 
-       return tp_expression;
 end_error:
-       return create_invalid_expression();
+       return tp_expression;
 }
 
 static expression_t *parse_sizeof(unsigned precedence)
@@ -7177,9 +7212,8 @@ static expression_t *parse_call_expression(unsigned precedence,
                         "function call has aggregate value");
        }
 
-       return result;
 end_error:
-       return create_invalid_expression();
+       return result;
 }
 
 static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right);
@@ -7597,6 +7631,9 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
 {
        /* TODO: handle complex + imaginary types */
 
+       type_left  = get_unqualified_type(type_left);
+       type_right = get_unqualified_type(type_right);
+
        /* ยง 6.3.1.8 Usual arithmetic conversions */
        if (type_left == type_long_double || type_right == type_long_double) {
                return type_long_double;
@@ -8651,7 +8688,7 @@ static statement_t *parse_case_statement(void)
                                statement->case_label.last_case = val;
 
                                if (val < statement->case_label.first_case) {
-                                       statement->case_label.is_empty = true;
+                                       statement->case_label.is_empty_range = true;
                                        warningf(pos, "empty range specified");
                                }
                        }
@@ -8667,7 +8704,7 @@ static statement_t *parse_case_statement(void)
                        /* Check for duplicate case values */
                        case_label_statement_t *c = &statement->case_label;
                        for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) {
-                               if (l->is_bad || l->is_empty || l->expression == NULL)
+                               if (l->is_bad || l->is_empty_range || l->expression == NULL)
                                        continue;
 
                                if (c->last_case < l->first_case || c->first_case > l->last_case)
@@ -9516,7 +9553,7 @@ expression_statment:
 
        case ';':        statement = parse_empty_statement();         break;
        case '{':        statement = parse_compound_statement(false); break;
-       case T___leave:  statement = parse_leave_statement();                   break;
+       case T___leave:  statement = parse_leave_statement();         break;
        case T___try:    statement = parse_ms_try_statment();         break;
        case T_asm:      statement = parse_asm_statement();           break;
        case T_break:    statement = parse_break();                   break;
@@ -9530,7 +9567,58 @@ expression_statment:
        case T_return:   statement = parse_return();                  break;
        case T_switch:   statement = parse_switch();                  break;
        case T_while:    statement = parse_while();                   break;
-       default:         statement = parse_expression_statement();    break;
+
+       case '!':
+       case '&':
+       case '(':
+       case '*':
+       case '+':
+       case '-':
+       case '~':
+       case T_ANDAND:
+       case T_CHARACTER_CONSTANT:
+       case T_FLOATINGPOINT:
+       case T_INTEGER:
+       case T_MINUSMINUS:
+       case T_PLUSPLUS:
+       case T_STRING_LITERAL:
+       case T_WIDE_CHARACTER_CONSTANT:
+       case T_WIDE_STRING_LITERAL:
+       case T___FUNCDNAME__:
+       case T___FUNCSIG__:
+       case T___FUNCTION__:
+       case T___PRETTY_FUNCTION__:
+       case T___builtin_alloca:
+       case T___builtin_classify_type:
+       case T___builtin_constant_p:
+       case T___builtin_expect:
+       case T___builtin_huge_val:
+       case T___builtin_isgreater:
+       case T___builtin_isgreaterequal:
+       case T___builtin_isless:
+       case T___builtin_islessequal:
+       case T___builtin_islessgreater:
+       case T___builtin_isunordered:
+       case T___builtin_nan:
+       case T___builtin_nand:
+       case T___builtin_nanf:
+       case T___builtin_offsetof:
+       case T___builtin_prefetch:
+       case T___builtin_va_arg:
+       case T___builtin_va_end:
+       case T___builtin_va_start:
+       case T___func__:
+       case T___noop:
+       case T__assume:
+               statement = parse_expression_statement();
+               break;
+
+       default:
+               errorf(HERE, "unexpected token %K while parsing statement", &token);
+               statement = create_invalid_statement();
+               if (!at_anchor())
+                       next_token();
+               break;
        }
        rem_anchor_token(';');
 
@@ -9727,32 +9815,47 @@ end_error:;
  */
 static void parse_translation_unit(void)
 {
-       for (;;) switch (token.type) {
-               DECLARATION_START
-               case T_IDENTIFIER:
-               case T___extension__:
-                       parse_external_declaration();
-                       break;
+       for (;;) {
+#ifndef NDEBUG
+               bool anchor_leak = false;
+               for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) {
+                       unsigned char count = token_anchor_set[i];
+                       if (count != 0) {
+                               errorf(HERE, "Leaked anchor token %k %d times", i, count);
+                               anchor_leak = true;
+                       }
+               }
+               if (anchor_leak)
+                       abort();
+#endif
 
-               case T_asm:
-                       parse_global_asm();
-                       break;
+               switch (token.type) {
+                       DECLARATION_START
+                       case T_IDENTIFIER:
+                       case T___extension__:
+                               parse_external_declaration();
+                               break;
 
-               case T_EOF:
-                       return;
+                       case T_asm:
+                               parse_global_asm();
+                               break;
 
-               case ';':
-                       /* TODO error in strict mode */
-                       warningf(HERE, "stray ';' outside of function");
-                       next_token();
-                       break;
+                       case T_EOF:
+                               return;
 
-               default:
-                       errorf(HERE, "stray %K outside of function", &token);
-                       if (token.type == '(' || token.type == '{' || token.type == '[')
-                               eat_until_matching_token(token.type);
-                       next_token();
-                       break;
+                       case ';':
+                               /* TODO error in strict mode */
+                               warningf(HERE, "stray ';' outside of function");
+                               next_token();
+                               break;
+
+                       default:
+                               errorf(HERE, "stray %K outside of function", &token);
+                               if (token.type == '(' || token.type == '{' || token.type == '[')
+                                       eat_until_matching_token(token.type);
+                               next_token();
+                               break;
+               }
        }
 }
 
@@ -9818,6 +9921,8 @@ void parse(void)
  */
 void init_parser(void)
 {
+       sym_anonymous = symbol_table_insert("<anonymous>");
+
        if (c_mode & _MS) {
                /* add predefined symbols for extended-decl-modifier */
                sym_align      = symbol_table_insert("align");