X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=format_check.c;h=37ffe48fd2b90577a4abea46c0d4329433ac5756;hb=e0f732b71af9ec2c31e9faad9f4341dbc700e50b;hp=63f2e382684d2e8170f52d1ec8e9bbcebf5784a1;hpb=ab16d355c444f215cda89055c05606585c32a49f;p=cparser diff --git a/format_check.c b/format_check.c index 63f2e38..37ffe48 100644 --- a/format_check.c +++ b/format_check.c @@ -4,6 +4,7 @@ #include "diagnostic.h" #include "format_check.h" #include "types.h" +#include "type_t.h" typedef enum format_flag_t { @@ -31,9 +32,7 @@ typedef enum format_length_modifier_t { FMT_MOD_q } format_length_modifier_t; -static void warn_invalid_length_modifier(const source_position_t pos, - const format_length_modifier_t mod, - const char conversion) +static const char* get_length_modifier_name(const format_length_modifier_t mod) { static const char* const names[] = { [FMT_MOD_NONE] = "", @@ -48,10 +47,16 @@ static void warn_invalid_length_modifier(const source_position_t pos, [FMT_MOD_q] = "q" }; assert(mod < sizeof(names) / sizeof(*names)); + return names[mod]; +} - parse_warning_posf(pos, +static void warn_invalid_length_modifier(const source_position_t pos, + const format_length_modifier_t mod, + const wchar_rep_t conversion) +{ + warningf(pos, "invalid length modifier '%s' for conversion specifier '%%%c'", - names[mod], conversion + get_length_modifier_name(mod), conversion ); } @@ -108,14 +113,14 @@ static void check_format_arguments(const call_argument_t *const fmt_arg, const c case ' ': if (fmt_flags & FMT_FLAG_PLUS) { - parse_warning_pos(pos, "' ' is overridden by prior '+' in conversion specification"); + warningf(pos, "' ' is overridden by prior '+' in conversion specification"); } flag = FMT_FLAG_SPACE; break; case '+': if (fmt_flags & FMT_FLAG_SPACE) { - parse_warning_pos(pos, "'+' overrides prior ' ' in conversion specification"); + warningf(pos, "'+' overrides prior ' ' in conversion specification"); } flag = FMT_FLAG_PLUS; break; @@ -123,7 +128,7 @@ static void check_format_arguments(const call_argument_t *const fmt_arg, const c default: goto break_fmt_flags; } if (fmt_flags & flag) { - parse_warning_posf(pos, "repeated flag '%c' in conversion specification", (char)*fmt); + warningf(pos, "repeated flag '%c' in conversion specification", (char)*fmt); } fmt_flags |= flag; ++fmt; @@ -133,14 +138,12 @@ break_fmt_flags: /* minimum field width */ if (*fmt == '*') { if (arg == NULL) { - parse_warning_pos(pos, "missing argument for '*' field width in conversion specification"); + warningf(pos, "missing argument for '*' field width in conversion specification"); return; } const type_t *const arg_type = arg->expression->base.datatype; if (arg_type != type_int) { - parse_warning_pos(pos, "argument for '*' field width in conversion specification is not an 'int', but an '"); - print_type(arg_type); - fputc('\'', stderr); + warningf(pos, "argument for '*' field width in conversion specification is not an 'int', but an '%T'", arg_type); } arg = arg->next; } else { @@ -155,14 +158,12 @@ break_fmt_flags: ++fmt; if (*fmt == '*') { if (arg == NULL) { - parse_warning_pos(pos, "missing argument for '*' precision in conversion specification"); + warningf(pos, "missing argument for '*' precision in conversion specification"); return; } const type_t *const arg_type = arg->expression->base.datatype; if (arg_type != type_int) { - parse_warning_pos(pos, "argument for '*' precision in conversion specification is not an 'int', but an '"); - print_type(arg_type); - fputc('\'', stderr); + warningf(pos, "argument for '*' precision in conversion specification is not an 'int', but an '%T'", arg_type); } arg = arg->next; } else { @@ -205,11 +206,11 @@ break_fmt_flags: } if (*fmt == '\0') { - parse_warning_pos(pos, "dangling % in format string"); + warningf(pos, "dangling %% in format string"); break; } - const type_t *expected_type; + const type_t *expected_type = NULL; format_flags_t allowed_flags; switch (*fmt) { case 'd': @@ -228,7 +229,7 @@ break_fmt_flags: warn_invalid_length_modifier(pos, fmt_mod, *fmt); break; } - allowed_flags = FMT_FLAG_MINUS | FMT_FLAG_PLUS | FMT_FLAG_ZERO; + allowed_flags = FMT_FLAG_MINUS | FMT_FLAG_SPACE | FMT_FLAG_PLUS | FMT_FLAG_ZERO; break; case 'o': @@ -274,7 +275,7 @@ eval_fmt_mod_unsigned: warn_invalid_length_modifier(pos, fmt_mod, *fmt); break; } - allowed_flags = FMT_FLAG_MINUS | FMT_FLAG_PLUS | FMT_FLAG_HASH | FMT_FLAG_ZERO; + allowed_flags = FMT_FLAG_MINUS | FMT_FLAG_SPACE | FMT_FLAG_PLUS | FMT_FLAG_HASH | FMT_FLAG_ZERO; break; case 'C': @@ -345,36 +346,48 @@ eval_fmt_mod_unsigned: break; default: - parse_warning_posf(pos, "encountered unknown conversion specifier '%%%C'", (wint_t)*fmt); + warningf(pos, "encountered unknown conversion specifier '%%%C'", (wint_t)*fmt); arg = arg->next; continue; } if ((fmt_flags & ~allowed_flags) != 0) { /* TODO better warning message text */ - parse_warning_pos(pos, "invalid format flags in conversion specification"); + warningf(pos, "invalid format flags in conversion specification"); } if (arg == NULL) { - parse_warning_pos(pos, "too few arguments for format string"); + warningf(pos, "too few arguments for format string"); return; } - const type_t *const arg_type = arg->expression->base.datatype; - if (arg_type != expected_type) { - parser_print_warning_prefix_pos(pos); - fputs("argument type '", stderr); - print_type(arg_type); - fprintf(stderr, "' does not match conversion specifier '%%%c'\n", (char)*fmt); + type_t *const arg_type = arg->expression->base.datatype; + if (is_type_pointer(expected_type)) { + type_t *const arg_skip = skip_typeref(arg_type); + if (is_type_pointer(arg_skip)) { + type_t *const exp_to = skip_typeref(expected_type->pointer.points_to); + type_t *const arg_to = skip_typeref(arg_skip->pointer.points_to); + if (arg_to == exp_to) { + goto arg_type_ok; + } + } + } else { + if (get_unqualified_type(skip_typeref(arg_type)) == expected_type) { + goto arg_type_ok; + } } + warningf(pos, + "argument type '%T' does not match conversion specifier '%%%s%c'\n", + arg_type, get_length_modifier_name(fmt_mod), (char)*fmt); +arg_type_ok: arg = arg->next; } if (fmt + 1 != wstring->begin + wstring->size) { - parse_warning_pos(pos, "format string contains NUL"); + warningf(pos, "format string contains NUL"); } if (arg != NULL) { - parse_warning_pos(pos, "too many arguments for format string"); + warningf(pos, "too many arguments for format string"); } }