void check_return(expression e) { type ret = current_return_type(); if (type_void(ret)) { if (pedantic || !type_void(e->type)) warning("`return' with a value, in function returning void"); } else { check_assignment(ret, default_conversion_for_assignment(e), e, "return", NULL, NULL, 0); /* XXX: Missing warning about returning address of local var */ } }
static void check_dereference(expression result, type dereferenced, const char *errorstring) { if (type_pointer(dereferenced)) { type t = type_points_to(dereferenced); result->type = t; #if 0 if (TYPE_SIZE (t) == 0 && TREE_CODE (t) != ARRAY_TYPE) { error ("dereferencing pointer to incomplete type"); return error_mark_node; } #endif if (type_void(t) && unevaluated_expression == 0) warning("dereferencing `void *' pointer"); result->side_effects |= type_volatile(t) || flag_volatile; } else { result->type = error_type; if (dereferenced != error_type) error("invalid type argument of `%s'", errorstring); } result->lvalue = TRUE; }
void check_void_return(void) { type ret = current_return_type(); if (warn_return_type && ret != error_type && !type_void(ret)) warning("`return' with no value, in function returning non-void"); }
static void incomplete_type_error(expression e, type t) { /* Avoid duplicate error message. */ if (t == error_type) return; if (e && is_identifier(e)) error("`%s' has an incomplete type", CAST(identifier, e)->cstring.data); else { while (type_array(t) && type_array_size(t)) t = type_array_of(t); if (type_struct(t)) error("invalid use of undefined type `struct %s'", type_tag(t)->name); else if (type_union(t)) error("invalid use of undefined type `union %s'", type_tag(t)->name); else if (type_enum(t)) error("invalid use of undefined type `enum %s'", type_tag(t)->name); else if (type_void(t)) error("invalid use of void expression"); else if (type_array(t)) error("invalid use of array with unspecified bounds"); else assert(0); /* XXX: Missing special message for typedef's */ } }
value type_num(value f) { if (f->N == 0) { num_free(get_num(f)); return 0; } return type_void(f); }
value type_var(value f) { if (f->N == 0) { drop(get_var(f)); return 0; } return type_void(f); }
static void ptrconversion_warnings(type ttl, type ttr, expression rhs, const char *context, const char *funname, int parmnum, bool pedantic) { if (pedantic && ((type_void(ttl) && type_function(ttr)) || (type_function(ttl) && type_void(ttr) && !(rhs && definite_null(rhs))))) warn_for_assignment("ANSI forbids %s between function pointer and `void *'", context, funname, parmnum); /* Const and volatile mean something different for function types, so the usual warnings are not appropriate. */ else if (type_function(ttl) && type_function(ttr)) { /* Because const and volatile on functions are restrictions that say the function will not do certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ if (type_const(ttl) && !type_const(ttr)) warn_for_assignment("%s makes `const *' function pointer from non-const", context, funname, parmnum); if (type_volatile(ttl) && !type_volatile(ttr)) warn_for_assignment("%s makes `volatile *' function pointer from non-volatile", context, funname, parmnum); } else if (!type_function(ttl) && !type_function(ttr)) { if (!type_const(ttl) && type_const(ttr)) warn_for_assignment("%s discards `const' from pointer target type", context, funname, parmnum); if (!type_volatile(ttl) && type_volatile(ttr)) warn_for_assignment("%s discards `volatile' from pointer target type", context, funname, parmnum); /* If this is not a case of ignoring a mismatch in signedness, no warning. */ if (!assignable_pointer_targets(ttl, ttr, FALSE) && pedantic) warn_for_assignment("pointer targets in %s differ in signedness", context, funname, parmnum); } }
bool valid_compare(type t1, type t2, expression e1) { if (type_void(type_points_to(t1))) { if (pedantic && type_function(type_points_to(t2)) && !definite_null(e1)) pedwarn("ANSI C forbids comparison of `void *' with function pointer"); return TRUE; } return FALSE; }
static bool voidstar_conditional(type t1, type t2) { if (type_void(t1)) { if (pedantic && type_function(t2)) pedwarn("ANSI C forbids conditional expr between `void *' and function pointer"); return TRUE; } return FALSE; }
type default_conversion(expression e) { type from = e->type; if (type_enum(from)) from = type_tag(from)->reptype; if (type_smallerthanint(from)) { /* Traditionally, unsignedness is preserved in default promotions. */ if (flag_traditional && type_unsigned(from)) return unsigned_int_type; else return int_type; } if (flag_traditional && !flag_allow_single_precision && type_float(from)) return double_type; if (type_void(from)) { error("void value not ignored as it ought to be"); return error_type; } if (type_function(from)) { assert(!e->cst); e->cst = e->static_address; return make_pointer_type(from); } if (type_array(from)) { if (!e->lvalue) { error("invalid use of non-lvalue array"); return error_type; } assert(!e->cst); e->cst = e->static_address; /* It's being used as a pointer, so is not an lvalue */ e->lvalue = FALSE; return make_pointer_type(type_array_of(from)); } return from; }
void check_sizeof(expression result, type stype) { if (type_function(stype)) { if (pedantic || warn_pointer_arith) pedwarn("sizeof applied to a function type"); } else if (type_void(stype)) { if (pedantic || warn_pointer_arith) pedwarn("sizeof applied to a void type"); } else if (type_incomplete(stype)) error("sizeof applied to an incomplete type"); result->type = size_t_type; result->cst = fold_sizeof(result, stype); }
type pointer_int_sum(type ptype, type itype) { type pointed = type_points_to(ptype); if (type_void(pointed)) { if (pedantic || warn_pointer_arith) pedwarn("pointer of type `void *' used in arithmetic"); } else if (type_function(pointed)) { if (pedantic || warn_pointer_arith) pedwarn("pointer to a function used in arithmetic"); } else if (type_incomplete(pointed)) error("arithmetic on pointer to an incomplete type"); return ptype; }
value type_file(value f) { if (f->N == 0) return 0; return type_void(f); }
expression make_cast(location loc, asttype t, expression e) { expression result = CAST(expression, new_cast(parse_region, loc, e, t)); type castto = t->type; if (castto == error_type || type_void(castto)) ; /* Do nothing */ else if (type_array(castto)) { error("cast specifies array type"); castto = error_type; } else if (type_function(castto)) { error("cast specifies function type"); castto = error_type; } else if (type_equal_unqualified(castto, e->type)) { if (pedantic && type_aggregate(castto)) pedwarn("ANSI C forbids casting nonscalar to the same type"); } else { type etype = e->type; /* Convert functions and arrays to pointers, but don't convert any other types. */ if (type_function(etype) || type_array(etype)) etype = default_conversion(e); if (type_union(castto)) { tag_declaration utag = type_tag(castto); field_declaration ufield; /* Look for etype as a field of the union */ for (ufield = utag->fieldlist; ufield; ufield = ufield->next) if (ufield->name && type_equal_unqualified(ufield->type, etype)) { if (pedantic) pedwarn("ANSI C forbids casts to union type"); break; } if (!ufield) error("cast to union type from type not present in union"); } else { /* Optionally warn about potentially worrisome casts. */ if (warn_cast_qual && type_pointer(etype) && type_pointer(castto)) { type ep = type_points_to(etype), cp = type_points_to(castto); if (type_volatile(ep) && !type_volatile(cp)) pedwarn("cast discards `volatile' from pointer target type"); if (type_const(ep) && !type_const(cp)) pedwarn("cast discards `const' from pointer target type"); } /* This warning is weird */ if (warn_bad_function_cast && is_function_call(e) && !type_equal_unqualified(castto, etype)) warning ("cast does not match function type"); #if 0 /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && warn_cast_align && TREE_CODE (type) == POINTER_TYPE && TREE_CODE (otype) == POINTER_TYPE && TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE && TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE /* Don't warn about opaque types, where the actual alignment restriction is unknown. */ && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE) && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode) && TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype))) warning ("cast increases required alignment of target type"); if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (otype) == POINTER_TYPE && TYPE_PRECISION (type) != TYPE_PRECISION (otype) && !TREE_CONSTANT (value)) warning ("cast from pointer to integer of different size"); if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (otype) == INTEGER_TYPE && TYPE_PRECISION (type) != TYPE_PRECISION (otype) #if 0 /* Don't warn about converting 0 to pointer, provided the 0 was explicit--not cast or made by folding. */ && !(TREE_CODE (value) == INTEGER_CST && integer_zerop (value)) #endif /* Don't warn about converting any constant. */ && !TREE_CONSTANT (value)) warning ("cast to pointer from integer of different size"); #endif check_conversion(castto, etype); } } result->lvalue = !pedantic && e->lvalue; result->isregister = e->isregister; result->bitfield = e->bitfield; result->static_address = e->static_address; result->type = castto; result->cst = fold_cast(result); return result; }
/* Return TRUE if no error and lhstype and rhstype are not error_type */ bool check_assignment(type lhstype, type rhstype, expression rhs, const char *context, data_declaration fundecl, const char *funname, int parmnum) { bool zerorhs = rhs && definite_zero(rhs); if (lhstype == error_type || rhstype == error_type) return FALSE; if (type_void(rhstype)) { error("void value not ignored as it ought to be"); return FALSE; } if (type_equal_unqualified(lhstype, rhstype)) return TRUE; if (type_arithmetic(lhstype) && type_arithmetic(rhstype)) { if (rhs) constant_overflow_warning(rhs->cst); return check_conversion(lhstype, rhstype); } if (parmnum && (type_qualifiers(lhstype) & transparent_qualifier)) { /* See if we can match any field of lhstype */ tag_declaration tag = type_tag(lhstype); field_declaration fields, marginal_field = NULL; /* I blame gcc for this horrible mess (and it's minor inconsistencies with the regular rules) */ /* pedantic warnings are skipped in here because we're already issuing a warning for the use of this construct */ for (fields = tag->fieldlist; fields; fields = fields->next) { type ft = fields->type; if (type_compatible(ft, rhstype)) break; if (!type_pointer(ft)) continue; if (type_pointer(rhstype)) { type ttl = type_points_to(ft), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, FALSE); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch) { /* If this type won't generate any warnings, use it. */ if ((type_function(ttr) && type_function(ttl)) ? (((!type_const(ttl)) | type_const(ttr)) & ((!type_volatile(ttl)) | type_volatile(ttr))) : (((type_const(ttl)) | (!type_const(ttr))) & (type_volatile(ttl) | (!type_volatile(ttr))))) break; /* Keep looking for a better type, but remember this one. */ if (!marginal_field) marginal_field = fields; } } /* Can convert integer zero to any pointer type. */ /* Note that this allows passing *any* null pointer (gcc bug?) */ if (zerorhs) break; } if (fields || marginal_field) { if (!fields) { /* We have only a marginally acceptable member type; it needs a warning. */ type ttl = type_points_to(marginal_field->type), ttr = type_points_to(rhstype); ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, FALSE); } if (pedantic && !(fundecl && fundecl->in_system_header)) pedwarn("ANSI C prohibits argument conversion to union type"); return TRUE; } } if (type_pointer(lhstype) && type_pointer(rhstype)) { type ttl = type_points_to(lhstype), ttr = type_points_to(rhstype); bool goodmatch = assignable_pointer_targets(ttl, ttr, pedantic); /* Any non-function converts to a [const][volatile] void * and vice versa; otherwise, targets must be the same. Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if (goodmatch || (type_equal_unqualified(make_unsigned_type(ttl), make_unsigned_type(ttr)))) ptrconversion_warnings(ttl, ttr, rhs, context, funname, parmnum, pedantic); else warn_for_assignment("%s from incompatible pointer type", context, funname, parmnum); return check_conversion(lhstype, rhstype); } /* enum = ptr and ptr = enum counts as an error, so use type_integral */ else if (type_pointer(lhstype) && type_integral(rhstype)) { if (!zerorhs) warn_for_assignment("%s makes pointer from integer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } else if (type_integral(lhstype) && type_pointer(rhstype)) { warn_for_assignment("%s makes integer from pointer without a cast", context, funname, parmnum); return check_conversion(lhstype, rhstype); } if (!context) if (funname) error("incompatible type for argument %d of `%s'", parmnum, funname); else error("incompatible type for argument %d of indirect function call", parmnum); else error("incompatible types in %s", context); return FALSE; }
static bool assignable_pointer_targets(type tt1, type tt2, bool pedantic) { return type_void(tt1) || type_void(tt2) || compatible_pointer_targets(tt1, tt2, pedantic); }
bool check_conversion(type to, type from) { if (type_equal_unqualified(to, from)) return TRUE; if (to == error_type || from == error_type) return FALSE; if (type_void(from)) { error("void value not ignored as it ought to be"); return FALSE; } if (type_void(to)) return TRUE; if (type_integer(to)) { if (!type_scalar(from)) { error("aggregate value used where an integer was expected"); return FALSE; } } else if (type_pointer(to)) { if (!(type_integer(from) || type_pointer(from))) { error("cannot convert to a pointer type"); return FALSE; } } else if (type_floating(to)) { if (type_pointer(from)) { error("pointer value used where a floating point value was expected"); return FALSE; } else if (!type_arithmetic(from)) { error("aggregate value used where a float was expected"); return FALSE; } } else if (type_complex(to)) { if (type_pointer(from)) { error("pointer value used where a complex was expected"); return FALSE; } else if (!type_arithmetic(from)) { error("aggregate value used where a complex was expected"); return FALSE; } } else { error("conversion to non-scalar type requested"); return FALSE; } return TRUE; }