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;
}
= 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);
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;
}
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)
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;
.aggregate_return = false,
.attribute = true,
.char_subscripts = true,
+ .cast_qual = false,
.declaration_after_statement = false,
.deprecated_declarations = true,
.div_by_zero = true,
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);