- implemented most cases of -W traditional (preprocessor missing)
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 12 Sep 2008 23:45:34 +0000 (23:45 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 12 Sep 2008 23:45:34 +0000 (23:45 +0000)
- implemented most cases of -Wconversion

[r21918]

lexer.c
parser.c
warning.c
warning.h

diff --git a/lexer.c b/lexer.c
index 5ca734a..779f4b3 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -65,7 +65,7 @@ bool               allow_dollar_in_symbol = true;
  */
 static void parse_error(const char *msg)
 {
-       errorf(&lexer_token.source_position,  "%s", msg);
+       errorf(&lexer_token.source_position, "%s", msg);
 }
 
 /**
@@ -75,7 +75,7 @@ static void parse_error(const char *msg)
  */
 static NORETURN internal_error(const char *msg)
 {
-       internal_errorf(&lexer_token.source_position,  "%s", msg);
+       internal_errorf(&lexer_token.source_position, "%s", msg);
 }
 
 static inline void next_real_char(void)
@@ -304,60 +304,78 @@ end_symbol:
 
 static void parse_integer_suffix(bool is_oct_hex)
 {
-       bool is_unsigned  = false;
-       bool min_long     = false;
-       bool min_longlong = false;
-
-       if(c == 'U' || c == 'u') {
-               is_unsigned = true;
+       bool is_unsigned     = false;
+       bool min_long        = false;
+       bool min_longlong    = false;
+       bool not_traditional = false;
+       int  pos             = 0;
+       char suffix[4];
+
+       if (c == 'U' || c == 'u') {
+               not_traditional = true;
+               suffix[pos++]   = toupper(c);
+               is_unsigned     = true;
                next_char();
-               if(c == 'L' || c == 'l') {
+               if (c == 'L' || c == 'l') {
+                       suffix[pos++] = toupper(c);
                        min_long = true;
                        next_char();
-                       if(c == 'L' || c == 'l') {
+                       if (c == 'L' || c == 'l') {
+                               suffix[pos++] = toupper(c);
                                min_longlong = true;
                                next_char();
                        }
                }
-       } else if(c == 'l' || c == 'L') {
+       } else if (c == 'l' || c == 'L') {
+               suffix[pos++] = toupper(c);
                min_long = true;
                next_char();
-               if(c == 'l' || c == 'L') {
-                       min_longlong = true;
+               if (c == 'l' || c == 'L') {
+                       not_traditional = true;
+                       suffix[pos++]   = toupper(c);
+                       min_longlong    = true;
                        next_char();
-                       if(c == 'u' || c == 'U') {
-                               is_unsigned = true;
+                       if (c == 'u' || c == 'U') {
+                               suffix[pos++] = toupper(c);
+                               is_unsigned   = true;
                                next_char();
                        }
-               } else if(c == 'u' || c == 'U') {
-                       is_unsigned = true;
+               } else if (c == 'u' || c == 'U') {
+                       not_traditional = true;
+                       suffix[pos++]   = toupper(c);
+                       is_unsigned     = true;
                        next_char();
                        lexer_token.datatype = type_unsigned_long;
                }
        }
 
-       if(!is_unsigned) {
+       if (warning.traditional && not_traditional) {
+               suffix[pos] = '\0';
+               warningf(&lexer_token.source_position,
+                       "traditional C rejects the '%s' suffix", suffix);
+       }
+       if (!is_unsigned) {
                long long v = lexer_token.v.intvalue;
-               if(!min_long) {
-                       if(v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
+               if (!min_long) {
+                       if (v >= TARGET_INT_MIN && v <= TARGET_INT_MAX) {
                                lexer_token.datatype = type_int;
                                return;
-                       } else if(is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
+                       } else if (is_oct_hex && v >= 0 && v <= TARGET_UINT_MAX) {
                                lexer_token.datatype = type_unsigned_int;
                                return;
                        }
                }
-               if(!min_longlong) {
-                       if(v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
+               if (!min_longlong) {
+                       if (v >= TARGET_LONG_MIN && v <= TARGET_LONG_MAX) {
                                lexer_token.datatype = type_long;
                                return;
-                       } else if(is_oct_hex && v >= 0 && (unsigned long long)v <= (unsigned long long)TARGET_ULONG_MAX) {
+                       } else if (is_oct_hex && v >= 0 && (unsigned long long)v <= (unsigned long long)TARGET_ULONG_MAX) {
                                lexer_token.datatype = type_unsigned_long;
                                return;
                        }
                }
                unsigned long long uv = (unsigned long long) v;
-               if(is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
+               if (is_oct_hex && uv > (unsigned long long) TARGET_LONGLONG_MAX) {
                        lexer_token.datatype = type_unsigned_long_long;
                        return;
                }
@@ -365,11 +383,11 @@ static void parse_integer_suffix(bool is_oct_hex)
                lexer_token.datatype = type_long_long;
        } else {
                unsigned long long v = (unsigned long long) lexer_token.v.intvalue;
-               if(!min_long && v <= TARGET_UINT_MAX) {
+               if (!min_long && v <= TARGET_UINT_MAX) {
                        lexer_token.datatype = type_unsigned_int;
                        return;
                }
-               if(!min_longlong && v <= TARGET_ULONG_MAX) {
+               if (!min_longlong && v <= TARGET_ULONG_MAX) {
                        lexer_token.datatype = type_unsigned_long;
                        return;
                }
@@ -383,11 +401,19 @@ static void parse_floating_suffix(void)
        /* TODO: do something useful with the suffixes... */
        case 'f':
        case 'F':
+               if (warning.traditional) {
+                       warningf(&lexer_token.source_position,
+                               "traditional C rejects the 'F' suffix");
+               }
                next_char();
                lexer_token.datatype = type_float;
                break;
        case 'l':
        case 'L':
+               if (warning.traditional) {
+                       warningf(&lexer_token.source_position,
+                               "traditional C rejects the 'F' suffix");
+               }
                next_char();
                lexer_token.datatype = type_long_double;
                break;
@@ -840,6 +866,10 @@ string_t concat_strings(const string_t *const s1, const string_t *const s2)
        memcpy(concat, s1->begin, len1);
        memcpy(concat + len1, s2->begin, len2 + 1);
 
+       if (warning.traditional) {
+               warningf(&lexer_token.source_position,
+                       "traditional C rejects string constant concatenation");
+       }
 #if 0 /* TODO hash */
        const char *result = strset_insert(&stringset, concat);
        if(result != concat) {
@@ -866,6 +896,10 @@ wide_string_t concat_string_wide_string(const string_t *const s1, const wide_str
                concat[i] = src[i];
        }
        memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
+       if (warning.traditional) {
+               warningf(&lexer_token.source_position,
+                       "traditional C rejects string constant concatenation");
+       }
 
        return (wide_string_t){ concat, len1 + len2 + 1 };
 }
@@ -881,6 +915,10 @@ wide_string_t concat_wide_strings(const wide_string_t *const s1, const wide_stri
        wchar_rep_t *const concat = obstack_alloc(&symbol_obstack, (len1 + len2 + 1) * sizeof(*concat));
        memcpy(concat,        s1->begin, len1       * sizeof(*concat));
        memcpy(concat + len1, s2->begin, (len2 + 1) * sizeof(*concat));
+       if (warning.traditional) {
+               warningf(&lexer_token.source_position,
+                       "traditional C rejects string constant concatenation");
+       }
 
        return (wide_string_t){ concat, len1 + len2 + 1 };
 }
@@ -899,6 +937,10 @@ wide_string_t concat_wide_string_string(const wide_string_t *const s1, const str
        for (size_t i = 0; i != len2 + 1; ++i) {
                concat[i] = src[i];
        }
+       if (warning.traditional) {
+               warningf(&lexer_token.source_position,
+                       "traditional C rejects string constant concatenation");
+       }
 
        return (wide_string_t){ concat, len1 + len2 + 1 };
 }
index 5f875be..204032d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3606,7 +3606,7 @@ static declaration_t *parse_parameters(function_type_t *type)
 
        if (token.type == T_IDENTIFIER &&
            !is_typedef_symbol(token.v.symbol)) {
-               token_type_t la1_type = look_ahead(1)->type;
+               token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ',' || la1_type == ')') {
                        type->kr_style_parameters = true;
                        declarations = parse_identifier_list();
@@ -5278,6 +5278,10 @@ static void parse_external_declaration(void)
                warningf(HERE, "function '%Y' returns an aggregate",
                         ndeclaration->symbol);
        }
+       if (warning.traditional && !type->function.unspecified_parameters) {
+               warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
+                       ndeclaration->symbol);
+       }
 
        /* ยง 6.7.5.3 (14) a function definition with () means no
         * parameters (and not unspecified parameters) */
@@ -6807,12 +6811,13 @@ create_error_entry:
 }
 
 static void check_call_argument(const function_parameter_t *parameter,
-                                call_argument_t *argument)
+                                call_argument_t *argument, unsigned pos)
 {
        type_t         *expected_type      = parameter->type;
        type_t         *expected_type_skip = skip_typeref(expected_type);
        assign_error_t  error              = ASSIGN_ERROR_INCOMPATIBLE;
        expression_t   *arg_expr           = argument->expression;
+       type_t         *arg_type           = skip_typeref(arg_expr->base.type);
 
        /* handle transparent union gnu extension */
        if (is_type_union(expected_type_skip)
@@ -6845,9 +6850,34 @@ static void check_call_argument(const function_parameter_t *parameter,
        argument->expression = create_implicit_cast(argument->expression,
                                                    expected_type);
 
-       /* TODO report exact scope in error messages (like "in 3rd parameter") */
-       report_assign_error(error, expected_type, arg_expr,     "function call",
-                           &arg_expr->base.source_position);
+       if (error != ASSIGN_SUCCESS) {
+               /* report exact scope in error messages (like "in argument 3") */
+               char buf[64];
+               snprintf(buf, sizeof(buf), "call argument %u", pos);
+               report_assign_error(error, expected_type, arg_expr,     buf,
+                                                       &arg_expr->base.source_position);
+       } else if (warning.traditional | warning.conversion) {
+               if (
+                   /* passing as integer instead of float or complex */
+                   (is_type_integer(expected_type) &&
+                    (is_type_float(arg_type) || is_type_complex(arg_type))) ||
+                   /* passing as complex instead of integer or float */
+                   (is_type_complex(expected_type) &&
+                    (is_type_integer(arg_type) || is_type_float(arg_type))) ||
+                   /* passing as float instead of integer or complex */
+                   (is_type_float(expected_type) &&
+                    (is_type_integer(arg_type) || is_type_complex(arg_type))) ||
+                   /* passing as float instead of double */
+                   (is_type_float(expected_type) && expected_type != type_double &&
+                    is_type_float(arg_type))) {
+                       warningf(&arg_expr->base.source_position,
+                               "passing call argument %u as '%T' rather than '%T' due to prototype",
+                               pos, expected_type, arg_type);
+               }
+               if (is_type_integer(expected_type) && is_type_integer(arg_type)) {
+                       /* TODO check for size HERE */
+               }
+       }
 }
 
 /**
@@ -6890,7 +6920,7 @@ static expression_t *parse_call_expression(unsigned precedence,
        if (token.type != ')') {
                call_argument_t *last_argument = NULL;
 
-               while(true) {
+               while (true) {
                        call_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
 
                        argument->expression = parse_assignment_expression();
@@ -6916,9 +6946,9 @@ static expression_t *parse_call_expression(unsigned precedence,
        function_parameter_t *parameter = function_type->parameters;
        call_argument_t      *argument  = call->arguments;
        if (!function_type->unspecified_parameters) {
-               for; parameter != NULL && argument != NULL;
+               for (unsigned pos = 0; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
-                       check_call_argument(parameter, argument);
+                       check_call_argument(parameter, argument, ++pos);
                }
 
                if (parameter != NULL) {
@@ -7209,7 +7239,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
                if (is_type_valid(type)) {
                        /* TODO: improve error message */
                        errorf(&expression->base.source_position,
-                              "operation needs an arithmetic type");
+                               "operation needs an arithmetic type");
                }
                return;
        }
@@ -7217,6 +7247,14 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
        expression->base.type = orig_type;
 }
 
+static void semantic_unexpr_plus(unary_expression_t *expression)
+{
+       semantic_unexpr_arithmetic(expression);
+       if (warning.traditional)
+               warningf(&expression->base.source_position,
+                       "traditional C rejects the unary plus operator");
+}
+
 static void semantic_not(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7320,7 +7358,7 @@ static expression_t *parse_##unexpression_type(unsigned precedence)            \
 CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
                                semantic_unexpr_arithmetic)
 CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS,
-                               semantic_unexpr_arithmetic)
+                               semantic_unexpr_plus)
 CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT,
                                semantic_not)
 CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE,
@@ -8682,6 +8720,13 @@ static statement_t *parse_switch(void)
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
+               if (warning.traditional) {
+                       if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+                               warningf(&expr->base.source_position,
+                                       "'%T' switch expression not converted to '%T' in ISO C",
+                                       type, type_int);
+                       }
+               }
        } else if (is_type_valid(type)) {
                errorf(&expr->base.source_position,
                       "switch quantity is not an integer, but '%T'", type);
index c14f622..5684886 100644 (file)
--- a/warning.c
+++ b/warning.c
@@ -27,6 +27,7 @@ warning_t warning = {
        .cast_qual                     = false,
        .char_subscripts               = true,
        .comment                       = false,
+       .conversion                    = false,
        .declaration_after_statement   = false,
        .deprecated_declarations       = true,
        .div_by_zero                   = true,
@@ -54,6 +55,7 @@ warning_t warning = {
        .strict_prototypes             = true,
        .switch_default                = false,
        .switch_enum                   = false,
+       .traditional                   = false,
        .unknown_pragmas               = true,
        .unreachable_code              = false,
        .unused_function               = false,
@@ -112,6 +114,7 @@ void set_warning_opt(const char *const opt)
        OPT("cast-qual",                     cast_qual);
        OPT("char-subscripts",               char_subscripts);
        OPT("comment",                       comment);
+       OPT("conversion",                    conversion);
        OPT("declaration-after-statement",   declaration_after_statement);
        OPT("deprecated-declarations",       deprecated_declarations);
        OPT("div_by_zero",                   div_by_zero);
@@ -156,6 +159,7 @@ void set_warning_opt(const char *const opt)
        OPT("strict-prototypes",             strict_prototypes);
        OPT("switch-default",                switch_default);
        OPT("switch-enum",                   switch_enum);
+       OPT("traditional",                   traditional);
        OPT("unknown-pragmas",               unknown_pragmas);
        OPT("unreachable-code",              unreachable_code);
        OPTX("unused") {
index fba6f07..48352e5 100644 (file)
--- a/warning.h
+++ b/warning.h
@@ -34,8 +34,8 @@ typedef struct warning_t {
        bool cast_qual:1;                     /**< Warn whenever a pointer is cast so as to remove a type qualifier from the target type */
        bool char_subscripts:1;               /**< Warn if an array subscript has the type 'char' */
        bool comment:1;                       /**< Warn whenever a comment-start sequence appears in a comment, or whenever a Backslash-Newline appears in a '//' comment. */
-#if 0 // TODO
        bool conversion:1;                    /**< Warn if a prototype causes a type conversion that is different from what would happen to the same argument in the absence of a prototype */
+#if 0 // TODO
        bool cpp_compat:1;                    /**< Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++. */
 #endif
        bool declaration_after_statement:1;   /**< Warn when a declaration is found after a statement in a block */
@@ -94,8 +94,8 @@ typedef struct warning_t {
        bool strict_prototypes:1;             /**< Warn if a function declaration has an unspecified parameter list */
        bool switch_default:1;                /**< Warn whenever a 'switch' statement does not have a 'default' case */
        bool switch_enum:1;                   /**< Warn about 'switch' statements with an enum as index type and missing case labels or case labels outside the enum range TODO has an alias -Wswitch? */
-#if 0 // TODO
        bool traditional:1;                   /**< Warn about certain constructs that behave differently in traditional and ISO C */
+#if 0 // TODO
        bool undef:1;                         /**< Warn if an undefined identifier is evaluated in an '#if' directive */
        bool uninitialized:1;                 /**< Warn if an automatic variable is used without being initialized or if a variable may be clobbered by a 'setjmp' call. */
 #endif