diff options
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r-- | gcc/c-typeck.c | 311 |
1 files changed, 254 insertions, 57 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 4c55e587de3..9b1f09c4593 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -284,14 +284,55 @@ c_type_promotes_to (tree type) return type; } +/* Return true if between two named address spaces, whether there is a superset + named address space that encompasses both address spaces. If there is a + superset, return which address space is the superset. */ + +static bool +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) +{ + if (as1 == as2) + { + *common = as1; + return true; + } + else if (targetm.addr_space.subset_p (as1, as2)) + { + *common = as2; + return true; + } + else if (targetm.addr_space.subset_p (as2, as1)) + { + *common = as1; + return true; + } + else + return false; +} + /* Return a variant of TYPE which has all the type qualifiers of LIKE as well as those of TYPE. */ static tree qualify_type (tree type, tree like) { + addr_space_t as_type = TYPE_ADDR_SPACE (type); + addr_space_t as_like = TYPE_ADDR_SPACE (like); + addr_space_t as_common; + + /* If the two named address spaces are different, determine the common + superset address space. If there isn't one, raise an error. */ + if (!addr_space_superset (as_type, as_like, &as_common)) + { + as_common = as_type; + error ("%qT and %qT are in disjoint named address spaces", + type, like); + } + return c_build_qualified_type (type, - TYPE_QUALS (type) | TYPE_QUALS (like)); + TYPE_QUALS_NO_ADDR_SPACE (type) + | TYPE_QUALS_NO_ADDR_SPACE (like) + | ENCODE_QUAL_ADDR_SPACE (as_common)); } /* Return true iff the given tree T is a variable length array. */ @@ -371,7 +412,8 @@ composite_type (tree t1, tree t2) bool t1_complete, t2_complete; /* We should not have any type quals on arrays at all. */ - gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2)); + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) + && !TYPE_QUALS_NO_ADDR_SPACE (t2)); t1_complete = COMPLETE_TYPE_P (t1); t2_complete = COMPLETE_TYPE_P (t2); @@ -585,6 +627,8 @@ common_pointer_type (tree t1, tree t2) tree pointed_to_2, mv2; tree target; unsigned target_quals; + addr_space_t as1, as2, as_common; + int quals1, quals2; /* Save time if the two types are the same. */ @@ -616,10 +660,24 @@ common_pointer_type (tree t1, tree t2) /* For function types do not merge const qualifiers, but drop them if used inconsistently. The middle-end uses these to mark const and noreturn functions. */ + quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1); + quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2); + if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) - target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2); + target_quals = (quals1 & quals2); else - target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2); + target_quals = (quals1 | quals2); + + /* If the two named address spaces are different, determine the common + superset address space. This is guaranteed to exist due to the + assumption that comp_target_type returned non-zero. */ + as1 = TYPE_ADDR_SPACE (pointed_to_1); + as2 = TYPE_ADDR_SPACE (pointed_to_2); + if (!addr_space_superset (as1, as2, &as_common)) + gcc_unreachable (); + + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); + t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); return build_type_attribute_variant (t1, attributes); } @@ -1103,20 +1161,28 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p) return attrval == 2 && val == 1 ? 2 : val; } -/* Return 1 if TTL and TTR are pointers to types that are equivalent, - ignoring their qualifiers. */ +/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring + their qualifiers, except for named address spaces. If the pointers point to + different named addresses, then we must determine if one address space is a + subset of the other. */ static int comp_target_types (location_t location, tree ttl, tree ttr) { int val; - tree mvl, mvr; + tree mvl = TREE_TYPE (ttl); + tree mvr = TREE_TYPE (ttr); + addr_space_t asl = TYPE_ADDR_SPACE (mvl); + addr_space_t asr = TYPE_ADDR_SPACE (mvr); + addr_space_t as_common; bool enum_and_int_p; + /* Fail if pointers point to incompatible address spaces. */ + if (!addr_space_superset (asl, asr, &as_common)) + return 0; + /* Do not lose qualifiers on element types of array types that are pointer targets by taking their TYPE_MAIN_VARIANT. */ - mvl = TREE_TYPE (ttl); - mvr = TREE_TYPE (ttr); if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); if (TREE_CODE (mvr) != ARRAY_TYPE) @@ -2673,6 +2739,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, { tree typetail, val; unsigned int parmnum; + bool error_args = false; const bool type_generic = fundecl && lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl))); bool type_generic_remove_excess_precision = false; @@ -2942,6 +3009,8 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, parmval = default_conversion (val); VEC_replace (tree, values, parmnum, parmval); + if (parmval == error_mark_node) + error_args = true; if (typetail) typetail = TREE_CHAIN (typetail); @@ -2955,7 +3024,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, return -1; } - return parmnum; + return error_args ? -1 : (int) parmnum; } /* This is the entry point used by the parser to build unary operators @@ -3063,11 +3132,43 @@ static tree pointer_diff (location_t loc, tree op0, tree op1) { tree restype = ptrdiff_type_node; + tree result, inttype; + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0))); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1))); tree target_type = TREE_TYPE (TREE_TYPE (op0)); tree con0, con1, lit0, lit1; tree orig_op1 = op1; + /* If the operands point into different address spaces, we need to + explicitly convert them to pointers into the common address space + before we can subtract the numerical address values. */ + if (as0 != as1) + { + addr_space_t as_common; + tree common_type; + + /* Determine the common superset address space. This is guaranteed + to exist because the caller verified that comp_target_types + returned non-zero. */ + if (!addr_space_superset (as0, as1, &as_common)) + gcc_unreachable (); + + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + op0 = convert (common_type, op0); + op1 = convert (common_type, op1); + } + + /* Determine integer type to perform computations in. This will usually + be the same as the result type (ptrdiff_t), but may need to be a wider + type if pointers for the address space are wider than ptrdiff_t. */ + if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0))) + inttype = lang_hooks.types.type_for_size + (TYPE_PRECISION (TREE_TYPE (op0)), 0); + else + inttype = restype; + + if (TREE_CODE (target_type) == VOID_TYPE) pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, "pointer of type %<void *%> used in subtraction"); @@ -3125,8 +3226,8 @@ pointer_diff (location_t loc, tree op0, tree op1) in case restype is a short type. */ op0 = build_binary_op (loc, - MINUS_EXPR, convert (restype, op0), - convert (restype, op1), 0); + MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), 0); /* This generates an error if op1 is pointer to incomplete type. */ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) error_at (loc, "arithmetic on pointer to an incomplete type"); @@ -3135,8 +3236,11 @@ pointer_diff (location_t loc, tree op0, tree op1) op1 = c_size_in_bytes (target_type); /* Divide by the size, in easiest possible way. */ - return fold_build2_loc (loc, EXACT_DIV_EXPR, restype, - op0, convert (restype, op1)); + result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, + op0, convert (inttype, op1)); + + /* Convert to final result type if necessary. */ + return convert (restype, result); } /* Construct and perhaps optimize a tree representation @@ -3940,17 +4044,9 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, "conditional expression")); } if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - { - op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1), - NULL, op1); - C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const; - } + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST) - { - op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2), - NULL, op2); - C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const; - } + op2 = c_wrap_maybe_const (op2, !op2_maybe_const); } } } @@ -3964,12 +4060,22 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) { + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); + addr_space_t as_common; + if (comp_target_types (colon_loc, type1, type2)) result_type = common_pointer_type (type1, type2); else if (null_pointer_constant_p (orig_op1)) - result_type = qualify_type (type2, type1); + result_type = type2; else if (null_pointer_constant_p (orig_op2)) - result_type = qualify_type (type1, type2); + result_type = type1; + else if (!addr_space_superset (as1, as2, &as_common)) + { + error_at (colon_loc, "pointers to disjoint address spaces " + "used in conditional expression"); + return error_mark_node; + } else if (VOID_TYPE_P (TREE_TYPE (type1))) { if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) @@ -3990,10 +4096,13 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + if (!objc_ok) pedwarn (colon_loc, 0, "pointer type mismatch in conditional expression"); - result_type = build_pointer_type (void_type_node); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); } } else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) @@ -4152,7 +4261,8 @@ build_compound_expr (location_t loc, tree expr1, tree expr2) /* Issue -Wcast-qual warnings when appropriate. TYPE is the type to which we are casting. OTYPE is the type of the expression being cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared - on the command line. */ + on the command line. Named address space qualifiers are not handled + here, because they result in different warnings. */ static void handle_warn_cast_qual (tree type, tree otype) @@ -4178,9 +4288,11 @@ handle_warn_cast_qual (tree type, tree otype) taken away. */ if (TREE_CODE (in_otype) == FUNCTION_TYPE && TREE_CODE (in_type) == FUNCTION_TYPE) - added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype)); + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); else - discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type)); + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); } while (TREE_CODE (in_type) == POINTER_TYPE && TREE_CODE (in_otype) == POINTER_TYPE); @@ -4329,6 +4441,36 @@ build_c_cast (location_t loc, tree type, tree expr) && TREE_CODE (otype) == POINTER_TYPE) handle_warn_cast_qual (type, otype); + /* Warn about conversions between pointers to disjoint + address spaces. */ + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !null_pointer_constant_p (value)) + { + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); + addr_space_t as_common; + + if (!addr_space_superset (as_to, as_from, &as_common)) + { + if (ADDR_SPACE_GENERIC_P (as_from)) + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint generic address space pointer", + c_addr_space_name (as_to)); + + else if (ADDR_SPACE_GENERIC_P (as_to)) + warning_at (loc, 0, "cast to generic address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_from)); + + else + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_to), + c_addr_space_name (as_from)); + } + } + /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && TREE_CODE (type) == POINTER_TYPE @@ -4923,7 +5065,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE " "makes qualified function " @@ -4937,7 +5080,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, G_("return makes qualified function " "pointer from unqualified")); } - else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE discards " "qualifiers from pointer target type"), @@ -4970,6 +5114,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, tree mvr = ttr; bool is_opaque_pointer; int target_cmp = 0; /* Cache comp_target_types () result. */ + addr_space_t asl; + addr_space_t asr; if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); @@ -4990,6 +5136,36 @@ convert_for_assignment (location_t location, tree type, tree rhs, "request for implicit conversion " "from %qT to %qT not permitted in C++", rhstype, type); + /* See if the pointers point to incompatible address spaces. */ + asl = TYPE_ADDR_SPACE (ttl); + asr = TYPE_ADDR_SPACE (ttr); + if (!null_pointer_constant_p (rhs) + && asr != asl && !targetm.addr_space.subset_p (asr, asl)) + { + switch (errtype) + { + case ic_argpass: + error_at (location, "passing argument %d of %qE from pointer to " + "non-enclosed address space", parmnum, rname); + break; + case ic_assign: + error_at (location, "assignment from pointer to " + "non-enclosed address space"); + break; + case ic_init: + error_at (location, "initialization from pointer to " + "non-enclosed address space"); + break; + case ic_return: + error_at (location, "return from pointer to " + "non-enclosed address space"); + break; + default: + gcc_unreachable (); + } + return error_mark_node; + } + /* Check if the right-hand side has a format attribute but the left-hand side doesn't. */ if (warn_missing_format_attribute @@ -5053,7 +5229,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, else if (TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttl) != FUNCTION_TYPE) { - if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) { /* Types differing only by the presence of the 'volatile' qualifier are acceptable if the 'volatile' has been added @@ -5093,7 +5270,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, 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_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE makes " "qualified function pointer " @@ -8661,16 +8839,17 @@ c_finish_stmt_expr (location_t loc, tree body) goto continue_searching; } + if (last == error_mark_node) + return last; + /* In the case that the BIND_EXPR is not necessary, return the expression out from inside it. */ - if (last == error_mark_node - || (last == BIND_EXPR_BODY (body) - && BIND_EXPR_VARS (body) == NULL)) + if (last == BIND_EXPR_BODY (body) + && BIND_EXPR_VARS (body) == NULL) { /* Even if this looks constant, do not allow it in a constant expression. */ - last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last); - C_MAYBE_CONST_EXPR_NON_CONST (last) = 1; + last = c_wrap_maybe_const (last, true); /* Do not warn if the return value of a statement expression is unused. */ TREE_NO_WARNING (last) = 1; @@ -9200,24 +9379,34 @@ build_binary_op (location_t location, enum tree_code code, { tree tt0 = TREE_TYPE (type0); tree tt1 = TREE_TYPE (type1); + addr_space_t as0 = TYPE_ADDR_SPACE (tt0); + addr_space_t as1 = TYPE_ADDR_SPACE (tt1); + addr_space_t as_common = ADDR_SPACE_GENERIC; + /* Anything compares with void *. void * compares with anything. Otherwise, the targets must be compatible and both must be object or both incomplete. */ if (comp_target_types (location, type0, type1)) result_type = common_pointer_type (type0, type1); + else if (null_pointer_constant_p (orig_op0)) + result_type = type1; + else if (null_pointer_constant_p (orig_op1)) + result_type = type0; + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else if (VOID_TYPE_P (tt0)) { - /* op0 != orig_op0 detects the case of something - whose value is 0 but which isn't a valid null ptr const. */ - if (pedantic && !null_pointer_constant_p (orig_op0) - && TREE_CODE (tt1) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } else if (VOID_TYPE_P (tt1)) { - if (pedantic && !null_pointer_constant_p (orig_op1) - && TREE_CODE (tt0) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of %<void *%> with function pointer"); } @@ -9228,7 +9417,11 @@ build_binary_op (location_t location, enum tree_code code, "comparison of distinct pointer types lacks a cast"); if (result_type == NULL_TREE) - result_type = ptr_type_node; + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } } else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) { @@ -9272,6 +9465,10 @@ build_binary_op (location_t location, enum tree_code code, short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as_common; + if (comp_target_types (location, type0, type1)) { result_type = common_pointer_type (type0, type1); @@ -9283,9 +9480,17 @@ build_binary_op (location_t location, enum tree_code code, pedwarn (location, OPT_pedantic, "ISO C forbids " "ordered comparisons of pointers to functions"); } + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else { - result_type = ptr_type_node; + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); pedwarn (location, 0, "comparison of distinct pointer types lacks a cast"); } @@ -9545,17 +9750,9 @@ build_binary_op (location_t location, enum tree_code code, if (!in_late_binary_op) { if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST) - { - op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0), - NULL, op0); - C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const; - } + op0 = c_wrap_maybe_const (op0, !op0_maybe_const); if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - { - op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1), - NULL, op1); - C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const; - } + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); } } } |