do correct semantic check for pointer arithmetic, support gcc void* arithmetic extension
authorMatthias Braun <matze@braunis.de>
Wed, 30 Jul 2008 14:46:32 +0000 (14:46 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 30 Jul 2008 14:46:32 +0000 (14:46 +0000)
[r20814]

ast2firm.c
parser.c
type.c
type.h

index 1e942ee..7b248a7 100644 (file)
@@ -2073,7 +2073,12 @@ static ir_node *adjust_for_pointer_arithmetic(dbg_info *dbgi,
 {
        pointer_type_t *const pointer_type = &type->pointer;
        type_t         *const points_to    = pointer_type->points_to;
-       const unsigned        elem_size    = get_type_size_const(points_to);
+       unsigned              elem_size    = get_type_size_const(points_to);
+
+       /* gcc extension */
+       if (elem_size == 0 && is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+               elem_size = 1;
+       }
 
        assert(elem_size >= 1);
        if (elem_size == 1)
index 5d566e7..535ae4d 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -6065,19 +6065,35 @@ end_error:
        return create_invalid_expression();
 }
 
+static void check_pointer_arithmetic(const source_position_t *source_position,
+                                     type_t *pointer_type,
+                                     type_t *orig_pointer_type)
+{
+       type_t *points_to = pointer_type->pointer.points_to;
+       if (is_type_incomplete(points_to) &&
+                       (! (c_mode & _GNUC)
+                        || !is_type_atomic(points_to, ATOMIC_TYPE_VOID))) {
+               errorf(source_position,
+                          "arithmetic with pointer to incomplete type '%T' not allowed",
+                          orig_pointer_type);
+       } else if (is_type_function(points_to)) {
+               errorf(source_position,
+                          "arithmetic with pointer to function type '%T' not allowed",
+                          orig_pointer_type);
+       }
+}
+
 static void semantic_incdec(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
        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 */
-                       errorf(HERE, "operation needs an arithmetic or pointer type");
-               }
-               return;
+       if (is_type_pointer(type)) {
+               check_pointer_arithmetic(&expression->base.source_position,
+                                        type, orig_type);
+       } else if (!is_type_real(type) && is_type_valid(type)) {
+               /* TODO: improve error message */
+               errorf(HERE, "operation needs an arithmetic or pointer type");
        }
-
        expression->base.type = orig_type;
 }
 
@@ -6321,19 +6337,25 @@ static void semantic_add(binary_expression_t *expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
-       /* § 5.6.5 */
-       if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+       /* § 6.5.6 */
+       if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
                type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
                expression->left  = create_implicit_cast(left, arithmetic_type);
                expression->right = create_implicit_cast(right, arithmetic_type);
                expression->base.type = arithmetic_type;
                return;
-       } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
+       } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
+               check_pointer_arithmetic(&expression->base.source_position,
+                                        type_left, orig_type_left);
                expression->base.type = type_left;
-       } else if(is_type_pointer(type_right) && is_type_integer(type_left)) {
+       } else if (is_type_pointer(type_right) && is_type_integer(type_left)) {
+               check_pointer_arithmetic(&expression->base.source_position,
+                                        type_right, orig_type_right);
                expression->base.type = type_right;
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
-               errorf(HERE, "invalid operands to binary + ('%T', '%T')", orig_type_left, orig_type_right);
+               errorf(&expression->base.source_position,
+                      "invalid operands to binary + ('%T', '%T')",
+                      orig_type_left, orig_type_right);
        }
 }
 
@@ -6354,6 +6376,8 @@ static void semantic_sub(binary_expression_t *expression)
                expression->base.type =  arithmetic_type;
                return;
        } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
+               check_pointer_arithmetic(&expression->base.source_position,
+                                        type_left, orig_type_left);
                expression->base.type = type_left;
        } else if(is_type_pointer(type_left) && is_type_pointer(type_right)) {
                if(!pointers_compatible(type_left, type_right)) {
@@ -6560,6 +6584,8 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
                expression->right     = create_implicit_cast(right, arithmetic_type);
                expression->base.type = type_left;
        } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
+               check_pointer_arithmetic(&expression->base.source_position,
+                                        type_left, orig_type_left);
                expression->base.type = type_left;
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
                errorf(HERE, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right);
diff --git a/type.c b/type.c
index ac34d3d..d7aaab5 100644 (file)
--- a/type.c
+++ b/type.c
@@ -820,6 +820,13 @@ bool is_type_arithmetic(const type_t *type)
        }
 }
 
+bool is_type_real(const type_t *type)
+{
+       /* 6.2.5.17 */
+       return is_type_integer(type)
+               || (type->kind == TYPE_ATOMIC && is_type_float(type));
+}
+
 /**
  * Returns true if the given type represents a scalar type.
  *
@@ -892,6 +899,11 @@ bool is_type_incomplete(const type_t *type)
        panic("invalid type found");
 }
 
+bool is_type_object(const type_t *type)
+{
+       return !is_type_function(type) && !is_type_incomplete(type);
+}
+
 /**
  * Check if two function types are compatible.
  */
diff --git a/type.h b/type.h
index bbebc33..5ed11cb 100644 (file)
--- a/type.h
+++ b/type.h
@@ -113,6 +113,8 @@ bool is_type_signed(const type_t *type);
  */
 bool is_type_float(const type_t *type);
 
+bool is_type_real(const type_t *type);
+
 /**
  * returns true if the type is valid. A type is valid if it contains no
  * unresolved references anymore and is not of TYPE_INVALID.
@@ -131,6 +133,8 @@ bool is_type_scalar(const type_t *type);
 
 bool is_type_incomplete(const type_t *type);
 
+bool is_type_object(const type_t *type);
+
 bool types_compatible(const type_t *type1, const type_t *type2);
 
 bool pointers_compatible(const type_t *type1, const type_t *type2);