- -Wcast-qual implemented
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 12 Sep 2008 03:30:36 +0000 (03:30 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Fri, 12 Sep 2008 03:30:36 +0000 (03:30 +0000)
- fixed semantic_assign() error messages
- implemented semantic_cast()

[r21873]

parser.c
parsetest/should_warn/cast_qual.c [new file with mode: 0644]
warning.c
warning.h

index 3b8dcdf..aebb7e8 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -972,7 +972,7 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left,
                unsigned missing_qualifiers
                        = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
                warningf(source_position,
-                        "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointed-to type",
+                        "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type",
                         orig_type_left, context, orig_type_right, missing_qualifiers);
                return;
        }
@@ -1016,12 +1016,13 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                                = skip_typeref(type_left->pointer.points_to);
                        type_t *points_to_right
                                = skip_typeref(type_right->pointer.points_to);
+                       assign_error_t res = ASSIGN_SUCCESS;
 
                        /* the left type has all qualifiers from the right type */
                        unsigned missing_qualifiers
                                = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
                        if (missing_qualifiers != 0) {
-                               return ASSIGN_ERROR_POINTER_QUALIFIER_MISSING;
+                               res = ASSIGN_ERROR_POINTER_QUALIFIER_MISSING;
                        }
 
                        points_to_left  = get_unqualified_type(points_to_left);
@@ -1029,14 +1030,14 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
 
                        if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID) ||
                                        is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) {
-                               return ASSIGN_SUCCESS;
+                               return res;
                        }
 
                        if (!types_compatible(points_to_left, points_to_right)) {
                                return ASSIGN_WARNING_POINTER_INCOMPATIBLE;
                        }
 
-                       return ASSIGN_SUCCESS;
+                       return res;
                } else if (is_type_integer(type_right)) {
                        return ASSIGN_WARNING_POINTER_FROM_INT;
                }
@@ -5900,11 +5901,51 @@ static expression_t *parse_reference(void)
        return expression;
 }
 
-static void check_cast_allowed(expression_t *expression, type_t *dest_type)
+static bool semantic_cast(expression_t *expression, type_t *orig_dest_type)
 {
-       (void) expression;
-       (void) dest_type;
+       type_t *orig_type_right = expression->base.type;
+       const type_t *dest_type = skip_typeref(orig_dest_type);
+       const type_t *orig_type = skip_typeref(orig_type_right);
+
+       if (!is_type_valid(dest_type) || !is_type_valid(orig_type))
+               return true;
+
+       /* ยง6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
+       if (dest_type == type_void)
+               return true;
+
        /* TODO check if explicit cast is allowed and issue warnings/errors */
+       if (is_type_pointer(dest_type)) {
+               /* only integer and pointer can be casted to pointer */
+               if (! is_type_pointer(orig_type) && ! is_type_integer(orig_type)) {
+                       errorf(HERE, "cannot convert type '%T' to a pointer type", orig_type_right);
+                       return false;
+               }
+       }
+       else if (!is_type_scalar(dest_type)) {
+               errorf(HERE, "conversion to non-scalar type '%T' requested", orig_dest_type);
+               return false;
+       }
+       else if (!is_type_scalar(orig_type)) {
+               errorf(HERE, "conversion from non-scalar type '%T' requested", orig_type_right);
+               return false;
+       }
+
+       if (warning.cast_qual) {
+               if (is_type_pointer(orig_type) &&
+                   is_type_pointer(dest_type)) {
+                       type_t *src = skip_typeref(orig_type->pointer.points_to);
+                        type_t *dst = skip_typeref(dest_type->pointer.points_to);
+                       unsigned missing_qualifiers
+                               = src->base.qualifiers & ~dst->base.qualifiers;
+                       if (missing_qualifiers != 0) {
+                               warningf(HERE,
+                                        "cast discards qualifiers '%Q' in pointer target type of '%T'",
+                                        missing_qualifiers, orig_type_right);
+                       }
+               }
+       }
+       return true;
 }
 
 static expression_t *parse_compound_literal(type_t *type)
@@ -5947,7 +5988,8 @@ static expression_t *parse_cast(void)
 
        expression_t *value = parse_sub_expression(20);
 
-       check_cast_allowed(value, type);
+       if (! semantic_cast(value, type))
+               goto end_error;
 
        cast->base.type   = type;
        cast->unary.value = value;
diff --git a/parsetest/should_warn/cast_qual.c b/parsetest/should_warn/cast_qual.c
new file mode 100644 (file)
index 0000000..4d53ed2
--- /dev/null
@@ -0,0 +1,14 @@
+/*$ -Wcast-qual $*/
+void test(const char *p) {
+       char *q = (char *)p;
+       volatile char *r = q;
+       int *i = p;
+
+       (void)p;
+
+       *q = 1;
+}
+
+int main(int argc, char *argv[]) {
+       return 0;
+}
index 2519bf3..c7e78f3 100644 (file)
--- a/warning.c
+++ b/warning.c
@@ -25,6 +25,7 @@ warning_t warning = {
        .aggregate_return              = false,
        .attribute                     = true,
        .char_subscripts               = true,
+       .cast_qual                     = false,
        .declaration_after_statement   = false,
        .deprecated_declarations       = true,
        .div_by_zero                   = true,
@@ -105,6 +106,7 @@ void set_warning_opt(const char *const opt)
        OPT("aggregate-return",              aggregate_return);
        OPT("attribute",                     attribute);
        OPT("char-subscripts",               char_subscripts);
+       OPT("cast-qual",                     cast_qual);
        OPT("declaration-after-statement",   declaration_after_statement);
        OPT("deprecated-declarations",       deprecated_declarations);
        OPT("div_by_zero",                   div_by_zero);
index e141ed8..efe4cac 100644 (file)
--- a/warning.h
+++ b/warning.h
@@ -32,8 +32,11 @@ typedef struct warning_t {
        bool attribute:1;                     /**< Warn if an unexpected `__attribute__' is used or function attributes applied to variables, etc. */
        bool char_subscripts:1;               /**< Warn if an array subscript has the type 'char' */
 #if 0 // TODO
-       bool cast_align:1;                    /**< Warn whenever a pointer is cast such that the required alignment of the target is increased */
+       bool cpp_compat:1;                    /**< Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++. */
+#endif
        bool cast_qual:1;                     /**< Warn whenever a pointer is cast so as to remove a type qualifier from the target type */
+#if 0 // TODO
+       bool cast_align:1;                    /**< Warn whenever a pointer is cast such that the required alignment of the target is increased */
        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 */
 #endif
        bool declaration_after_statement:1;   /**< Warn when a declaration is found after a statement in a block */