Warn when a non-static global variable has no prior declaration.
[cparser] / parser.c
index 65748f1..3a3fd39 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -983,19 +983,16 @@ static initializer_t *initializer_from_expression(type_t *type,
 }
 
 static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression,
-                                            type_t *expression_type);
+                                            expression_t *expression);
 
 static initializer_t *parse_sub_initializer_elem(type_t *type)
 {
        if(token.type == '{') {
-               return parse_sub_initializer(type, NULL, NULL);
+               return parse_sub_initializer(type, NULL);
        }
 
-       expression_t *expression      = parse_assignment_expression();
-       type_t       *expression_type = skip_typeref(expression->base.datatype);
-
-       return parse_sub_initializer(type, expression, expression_type);
+       expression_t *expression = parse_assignment_expression();
+       return parse_sub_initializer(type, expression);
 }
 
 static bool had_initializer_brace_warning;
@@ -1019,8 +1016,7 @@ static void skip_designator(void)
 }
 
 static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression,
-                                            type_t *expression_type)
+                                            expression_t *expression)
 {
        if(is_type_scalar(type)) {
                /* there might be extra {} hierarchies */
@@ -1030,7 +1026,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                                warningf(HERE, "braces around scalar initializer");
                                had_initializer_brace_warning = true;
                        }
-                       initializer_t *result = parse_sub_initializer(type, NULL, NULL);
+                       initializer_t *result = parse_sub_initializer(type, NULL);
                        if(token.type == ',') {
                                next_token();
                                /* TODO: warn about excessive elements */
@@ -1076,8 +1072,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                if(expression == NULL) {
                        sub = parse_sub_initializer_elem(element_type);
                } else {
-                       sub = parse_sub_initializer(element_type, expression,
-                                                   expression_type);
+                       sub = parse_sub_initializer(element_type, expression);
                }
 
                /* didn't match the subtypes -> try the parent type */
@@ -1127,7 +1122,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                if(expression == NULL) {
                        sub = parse_sub_initializer_elem(first_type);
                } else {
-                       sub = parse_sub_initializer(first_type, expression,expression_type);
+                       sub = parse_sub_initializer(first_type, expression);
                }
 
                /* didn't match the subtypes -> try our parent type */
@@ -1216,7 +1211,7 @@ static initializer_t *parse_initializer(type_t *const orig_type)
                expect('}');
                return result;
        } else {
-               result = parse_sub_initializer(type, NULL, NULL);
+               result = parse_sub_initializer(type, NULL);
        }
 
        return result;
@@ -2254,6 +2249,11 @@ static declaration_t *append_declaration(declaration_t* const declaration)
        return declaration;
 }
 
+static bool is_sym_main(const symbol_t *const sym)
+{
+       return strcmp(sym->string, "main") == 0;
+}
+
 static declaration_t *internal_record_declaration(
        declaration_t *const declaration,
        const bool is_function_definition)
@@ -2299,7 +2299,8 @@ static declaration_t *internal_record_declaration(
                                                case STORAGE_CLASS_EXTERN:
                                                        if (is_function_definition) {
                                                                if (warning.missing_prototypes &&
-                                                                   prev_type->function.unspecified_parameters) {
+                                                                   prev_type->function.unspecified_parameters &&
+                                                                   !is_sym_main(symbol)) {
                                                                        warningf(declaration->source_position, "no previous prototype for '%#T'", type, symbol);
                                                                }
                                                        } else if (new_storage_class == STORAGE_CLASS_NONE) {
@@ -2344,11 +2345,15 @@ warn_redundant_declaration:
                }
        } else if (is_function_definition &&
                        declaration->storage_class != STORAGE_CLASS_STATIC) {
-               if (warning.missing_prototypes) {
+               if (warning.missing_prototypes && !is_sym_main(symbol)) {
                        warningf(declaration->source_position, "no previous prototype for '%#T'", type, symbol);
-               } else if (warning.missing_declarations) {
+               } else if (warning.missing_declarations && !is_sym_main(symbol)) {
                        warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
                }
+       } else if (warning.missing_declarations &&
+           declaration->storage_class != STORAGE_CLASS_STATIC &&
+           declaration->storage_class != STORAGE_CLASS_TYPEDEF) {
+               warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
        }
 
        assert(declaration->parent_context == NULL);
@@ -3951,6 +3956,7 @@ static void semantic_incdec(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.datatype;
        type_t *const type      = skip_typeref(orig_type);
+       /* TODO !is_type_real && !is_type_pointer */
        if(!is_type_arithmetic(type) && type->kind != TYPE_POINTER) {
                if (is_type_valid(type)) {
                        /* TODO: improve error message */
@@ -4487,8 +4493,6 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_BINARY_BITWISE_AND:        return false;
                case EXPR_BINARY_BITWISE_OR:         return false;
                case EXPR_BINARY_BITWISE_XOR:        return false;
-               case EXPR_BINARY_LOGICAL_AND:        return false;
-               case EXPR_BINARY_LOGICAL_OR:         return false;
                case EXPR_BINARY_SHIFTLEFT:          return false;
                case EXPR_BINARY_SHIFTRIGHT:         return false;
                case EXPR_BINARY_ASSIGN:             return true;
@@ -4502,6 +4506,8 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
                case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
                case EXPR_BINARY_BITWISE_OR_ASSIGN:  return true;
+               case EXPR_BINARY_LOGICAL_AND:
+               case EXPR_BINARY_LOGICAL_OR:
                case EXPR_BINARY_COMMA:
                        return expression_has_effect(expr->binary.right);
 
@@ -5075,6 +5081,10 @@ static statement_t *parse_switch(void)
        statement->body = parse_statement();
        current_switch  = rem;
 
+       if (warning.switch_default && find_default_label(statement) == NULL) {
+               warningf(statement->statement.source_position, "switch has no default case");
+       }
+
        return (statement_t*) statement;
 }
 
@@ -5447,6 +5457,9 @@ static statement_t *parse_statement(void)
                break;
 
        case ';':
+               if (warning.empty_statement) {
+                       warningf(HERE, "statement is empty");
+               }
                next_token();
                statement = NULL;
                break;