From: Ben Elliston Date: Mon, 26 Oct 2009 21:58:06 +0000 (+0000) Subject: tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=36c5e70a3aab4f1c25bfe706648aab258e89be1a;p=gcc.git tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. 2009-10-26 Ben Elliston Michael Meissner Ulrich Weigand * doc/tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. * c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is defined, add the named address space keywords. (c_addr_space_name): New function. (complete_array_type): Preserve named address space. (handle_mode_attribute): Use targetm.addr_space.valid_pointer_mode instead of targetm.valid_pointer_mode. * c-common.h (enum rid): Add RID_ADDR_SPACE_0 .. RID_ADDR_SPACE_15, RID_FIRST_ADDR_SPACE and RID_LAST_ADDR_SPACE. (ADDR_SPACE_KEYWORD): New macro. (c_addr_space_name): Add prototype. * c-tree.h (struct c_declspecs): Add address_space member. (declspecs_add_addrspace): Add prototype. * c-pretty-print.c (pp_c_type_qualifier_list): Handle address spaces. * c-parser.c (c_parse_init): Add assertion. (typedef enum c_id_kind): Add C_ID_ADDRSPACE. (c_lex_one_token): Handle address space keywords. (c_token_starts_typename): Likewise. (c_token_starts_declspecs): Likewise. (c_parser_declspecs): Likewise. (c_parser_postfix_expression_after_paren_type): Diagnose compound literal within function qualified with named address space. * c-decl.c (diagnose_mismatched_decls): Diagnose conflicting named address space qualifiers. (shadow_tag_warned): Warn about useless address space qualifiers. (quals_from_declspecs): Handle address space qualifiers. (grokdeclarator): Likewise. (build_null_declspecs): Likewise. (declspecs_add_addrspace): New function. * c-typeck.c (addr_space_superset): New function. (qualify_type): Handle named address spaces. (composite_type): Likewise. (common_pointer_type): Likewise. (comp_target_types): Likewise. (build_conditional_expr): Likewise. (handle_warn_cast_qual): Likewise. (build_c_cast): Likewise. (convert_for_assignment): Likewise. (build_binary_op): Likewise. (pointer_diff): Handle named address spaces. Use intermediate integer type of sufficient size if required. Co-Authored-By: Michael Meissner Co-Authored-By: Ulrich Weigand From-SVN: r153574 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 658274da303..db375c7fb92 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,56 @@ +2009-10-26 Ben Elliston + Michael Meissner + Ulrich Weigand + + * doc/tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. + + * c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is + defined, add the named address space keywords. + (c_addr_space_name): New function. + (complete_array_type): Preserve named address space. + (handle_mode_attribute): Use targetm.addr_space.valid_pointer_mode + instead of targetm.valid_pointer_mode. + + * c-common.h (enum rid): Add RID_ADDR_SPACE_0 .. RID_ADDR_SPACE_15, + RID_FIRST_ADDR_SPACE and RID_LAST_ADDR_SPACE. + (ADDR_SPACE_KEYWORD): New macro. + (c_addr_space_name): Add prototype. + + * c-tree.h (struct c_declspecs): Add address_space member. + (declspecs_add_addrspace): Add prototype. + + * c-pretty-print.c (pp_c_type_qualifier_list): Handle address spaces. + + * c-parser.c (c_parse_init): Add assertion. + (typedef enum c_id_kind): Add C_ID_ADDRSPACE. + (c_lex_one_token): Handle address space keywords. + (c_token_starts_typename): Likewise. + (c_token_starts_declspecs): Likewise. + (c_parser_declspecs): Likewise. + (c_parser_postfix_expression_after_paren_type): Diagnose compound + literal within function qualified with named address space. + + * c-decl.c (diagnose_mismatched_decls): Diagnose conflicting named + address space qualifiers. + (shadow_tag_warned): Warn about useless address space qualifiers. + (quals_from_declspecs): Handle address space qualifiers. + (grokdeclarator): Likewise. + (build_null_declspecs): Likewise. + (declspecs_add_addrspace): New function. + + * c-typeck.c (addr_space_superset): New function. + (qualify_type): Handle named address spaces. + (composite_type): Likewise. + (common_pointer_type): Likewise. + (comp_target_types): Likewise. + (build_conditional_expr): Likewise. + (handle_warn_cast_qual): Likewise. + (build_c_cast): Likewise. + (convert_for_assignment): Likewise. + (build_binary_op): Likewise. + (pointer_diff): Handle named address spaces. Use intermediate + integer type of sufficient size if required. + 2009-10-26 Ben Elliston Michael Meissner Ulrich Weigand diff --git a/gcc/c-common.c b/gcc/c-common.c index 8a6d15b9d9b..1f30d06f4c7 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -710,6 +710,11 @@ const struct c_common_resword c_common_reswords[] = { "inout", RID_INOUT, D_OBJC }, { "oneway", RID_ONEWAY, D_OBJC }, { "out", RID_OUT, D_OBJC }, + +#ifdef TARGET_ADDR_SPACE_KEYWORDS + /* Any address space keywords recognized by the target. */ + TARGET_ADDR_SPACE_KEYWORDS, +#endif }; const unsigned int num_c_common_reswords = @@ -840,6 +845,19 @@ const struct attribute_spec c_common_format_attribute_table[] = { NULL, 0, 0, false, false, false, NULL } }; +/* Return identifier for address space AS. */ +const char * +c_addr_space_name (addr_space_t as) +{ + unsigned int i; + + for (i = 0; i < num_c_common_reswords; i++) + if (c_common_reswords[i].rid == RID_FIRST_ADDR_SPACE + as) + return c_common_reswords[i].word; + + gcc_unreachable (); +} + /* Push current bindings for the function name VAR_DECLS. */ void @@ -6459,9 +6477,10 @@ handle_mode_attribute (tree *node, tree name, tree args, if (POINTER_TYPE_P (type)) { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); tree (*fn)(tree, enum machine_mode, bool); - if (!targetm.valid_pointer_mode (mode)) + if (!targetm.addr_space.valid_pointer_mode (mode, as)) { error ("invalid pointer mode %qs", p); return NULL_TREE; @@ -8511,7 +8530,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) if (quals == 0) unqual_elt = elt; else - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals)); /* Using build_distinct_type_copy and modifying things afterward instead of using build_array_type to create a new type preserves all of the diff --git a/gcc/c-common.h b/gcc/c-common.h index 61d52c870fb..d91546ff239 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -126,6 +126,30 @@ enum rid RID_AT_INTERFACE, RID_AT_IMPLEMENTATION, + /* Named address support, mapping the keyword to a particular named address + number. Named address space 0 is reserved for the generic address. If + there are more than 254 named addresses, the addr_space_t type will need + to be grown from an unsigned char to unsigned short. */ + RID_ADDR_SPACE_0, /* generic address */ + RID_ADDR_SPACE_1, + RID_ADDR_SPACE_2, + RID_ADDR_SPACE_3, + RID_ADDR_SPACE_4, + RID_ADDR_SPACE_5, + RID_ADDR_SPACE_6, + RID_ADDR_SPACE_7, + RID_ADDR_SPACE_8, + RID_ADDR_SPACE_9, + RID_ADDR_SPACE_10, + RID_ADDR_SPACE_11, + RID_ADDR_SPACE_12, + RID_ADDR_SPACE_13, + RID_ADDR_SPACE_14, + RID_ADDR_SPACE_15, + + RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0, + RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15, + RID_MAX, RID_FIRST_MODIFIER = RID_STATIC, @@ -263,6 +287,10 @@ struct c_common_resword #define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */ #define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */ +/* Macro for backends to define named address keywords. */ +#define ADDR_SPACE_KEYWORD(STRING, VALUE) \ + { STRING, RID_FIRST_ADDR_SPACE + (VALUE), D_CONLY | D_EXT } + /* The reserved keyword table. */ extern const struct c_common_resword c_common_reswords[]; @@ -760,6 +788,7 @@ extern const struct attribute_spec c_common_format_attribute_table[]; extern tree (*make_fname_decl) (location_t, tree, int); +extern const char *c_addr_space_name (addr_space_t as); extern tree identifier_global_value (tree); extern void record_builtin_type (enum rid, const char *, tree); extern tree build_void_list_node (void); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index e237332f174..492d2e673b7 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1746,8 +1746,35 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } else { - if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype)) - error ("conflicting type qualifiers for %q+D", newdecl); + int new_quals = TYPE_QUALS (newtype); + int old_quals = TYPE_QUALS (oldtype); + + if (new_quals != old_quals) + { + addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); + addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); + if (new_addr != old_addr) + { + if (ADDR_SPACE_GENERIC_P (new_addr)) + error ("conflicting named address spaces (generic vs %s) " + "for %q+D", + c_addr_space_name (old_addr), newdecl); + else if (ADDR_SPACE_GENERIC_P (old_addr)) + error ("conflicting named address spaces (%s vs generic) " + "for %q+D", + c_addr_space_name (new_addr), newdecl); + else + error ("conflicting named address spaces (%s vs %s) " + "for %q+D", + c_addr_space_name (new_addr), + c_addr_space_name (old_addr), + newdecl); + } + + if (CLEAR_QUAL_ADDR_SPACE (new_quals) + != CLEAR_QUAL_ADDR_SPACE (old_quals)) + error ("conflicting type qualifiers for %q+D", newdecl); + } else error ("conflicting types for %q+D", newdecl); diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); @@ -3605,7 +3632,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) else if (!declspecs->tag_defined_p && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { if (warned != 1) pedwarn (input_location, 0, @@ -3676,7 +3704,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) if (!warned && !in_system_header && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { warning (0, "useless type qualifier in empty declaration"); warned = 2; @@ -3699,7 +3728,8 @@ quals_from_declspecs (const struct c_declspecs *specs) { int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) - | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)); + | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) + | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); gcc_assert (!specs->type && !specs->decl_attr && specs->typespec_word == cts_none @@ -4750,6 +4780,7 @@ grokdeclarator (const struct c_declarator *declarator, bool bitfield = width != NULL; tree element_type; struct c_arg_info *arg_info = 0; + addr_space_t as1, as2, address_space; location_t loc = UNKNOWN_LOCATION; const char *errmsg; tree expr_dummy; @@ -4880,6 +4911,10 @@ grokdeclarator (const struct c_declarator *declarator, constp = declspecs->const_p + TYPE_READONLY (element_type); restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + as1 = declspecs->address_space; + as2 = TYPE_ADDR_SPACE (element_type); + address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; + if (pedantic && !flag_isoc99) { if (constp > 1) @@ -4889,11 +4924,17 @@ grokdeclarator (const struct c_declarator *declarator, if (volatilep > 1) pedwarn (loc, OPT_pedantic, "duplicate %"); } + + if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) + error_at (loc, "conflicting named address spaces (%s vs %s)", + c_addr_space_name (as1), c_addr_space_name (as2)); + if (!flag_gen_aux_info && (TYPE_QUALS (element_type))) type = TYPE_MAIN_VARIANT (type); type_quals = ((constp ? TYPE_QUAL_CONST : 0) | (restrictp ? TYPE_QUAL_RESTRICT : 0) - | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + | (volatilep ? TYPE_QUAL_VOLATILE : 0) + | ENCODE_QUAL_ADDR_SPACE (address_space)); /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ @@ -5309,7 +5350,14 @@ grokdeclarator (const struct c_declarator *declarator, it, but here we want to make sure we don't ever modify the shared type, so we gcc_assert (itype) below. */ - type = build_array_type (type, itype); + { + addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) + type = build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + + type = build_array_type (type, itype); + } if (type != error_mark_node) { @@ -5515,6 +5563,59 @@ grokdeclarator (const struct c_declarator *declarator, /* Now TYPE has the actual type, apart from any qualifiers in TYPE_QUALS. */ + /* Warn about address space used for things other than static memory or + pointers. */ + address_space = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (address_space)) + { + if (decl_context == NORMAL) + { + switch (storage_class) + { + case csc_auto: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_register: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_none: + if (current_function_scope) + { + error ("%qs specified for auto variable %qE", + c_addr_space_name (address_space), name); + break; + } + break; + case csc_static: + case csc_extern: + case csc_typedef: + break; + default: + gcc_unreachable (); + } + } + else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) + { + if (name) + error ("%qs specified for parameter %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for unnamed parameter", + c_addr_space_name (address_space)); + } + else if (decl_context == FIELD) + { + if (name) + error ("%qs specified for structure field %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for structure field", + c_addr_space_name (address_space)); + } + } + /* Check the type and width of a bit-field. */ if (bitfield) check_bitfield_type_and_width (&type, width, name); @@ -8297,9 +8398,29 @@ build_null_declspecs (void) ret->volatile_p = false; ret->restrict_p = false; ret->saturating_p = false; + ret->address_space = ADDR_SPACE_GENERIC; return ret; } +/* Add the address space ADDRSPACE to the declaration specifiers + SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) +{ + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + + if (!ADDR_SPACE_GENERIC_P (specs->address_space) + && specs->address_space != as) + error ("incompatible address space qualifiers %qs and %qs", + c_addr_space_name (as), + c_addr_space_name (specs->address_space)); + else + specs->address_space = as; + return specs; +} + /* Add the type qualifier QUAL to the declaration specifiers SPECS, returning SPECS. */ diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 767d97fbe58..1a6012e9128 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -72,6 +72,10 @@ c_parse_init (void) tree id; int mask = 0; + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + mask |= D_CXXONLY; if (!flag_isoc99) mask |= D_C99; @@ -132,6 +136,8 @@ typedef enum c_id_kind { C_ID_TYPENAME, /* An identifier declared as an Objective-C class name. */ C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, /* Not an identifier. */ C_ID_NONE } c_id_kind; @@ -226,6 +232,13 @@ c_lex_one_token (c_parser *parser, c_token *token) "identifier %qE conflicts with C++ keyword", token->value); } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } else if (c_dialect_objc ()) { if (!objc_is_reserved_word (token->value) @@ -352,6 +365,8 @@ c_token_starts_typename (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -422,6 +437,8 @@ c_token_starts_declspecs (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -1411,6 +1428,7 @@ c_parser_asm_definition (c_parser *parser) const restrict volatile + address-space-qualifier (restrict is new in C99.) @@ -1419,6 +1437,12 @@ c_parser_asm_definition (c_parser *parser) declaration-specifiers: attributes declaration-specifiers[opt] + type-qualifier: + address-space + + address-space: + identifier recognized by the target + storage-class-specifier: __thread @@ -1459,6 +1483,17 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, { tree value = c_parser_peek_token (parser)->value; c_id_kind kind = c_parser_peek_token (parser)->id_kind; + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + /* This finishes the specifiers unless a type name is OK, it is declared as a type name and a type name hasn't yet been seen. */ @@ -5775,6 +5810,14 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, finish_init (); maybe_warn_string_init (type, init); + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + if (!flag_isoc99) pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals"); non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) diff --git a/gcc/c-pretty-print.c b/gcc/c-pretty-print.c index c4e6e96c296..01770014c21 100644 --- a/gcc/c-pretty-print.c +++ b/gcc/c-pretty-print.c @@ -225,7 +225,11 @@ pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) const restrict -- C99 __restrict__ -- GNU C - volatile */ + address-space-qualifier -- GNU C + volatile + + address-space-qualifier: + identifier -- GNU C */ void pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) @@ -245,6 +249,12 @@ pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) pp_c_cv_qualifier (pp, "volatile"); if (qualifiers & TYPE_QUAL_RESTRICT) pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__"); + + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t))) + { + const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t)); + pp_c_identifier (pp, as); + } } /* pointer: diff --git a/gcc/c-tree.h b/gcc/c-tree.h index c7490e461a3..e71771ae840 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -277,6 +277,8 @@ struct c_declspecs { BOOL_BITFIELD restrict_p : 1; /* Whether "_Sat" was specified. */ BOOL_BITFIELD saturating_p : 1; + /* The address space that the declaration belongs to. */ + addr_space_t address_space; }; /* The various kinds of declarators in C. */ @@ -476,6 +478,8 @@ extern struct c_declspecs *declspecs_add_type (location_t, struct c_typespec); extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree); extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *, + addr_space_t); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); /* in c-objc-common.c */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 3274e0730ec..c7d2bc8da22 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) @@ -3063,11 +3129,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 % used in subtraction"); @@ -3125,8 +3223,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 +3233,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 @@ -3956,12 +4057,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) @@ -3982,10 +4093,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) @@ -4144,7 +4258,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) @@ -4170,9 +4285,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); @@ -4321,6 +4438,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 @@ -4915,7 +5062,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 " @@ -4929,7 +5077,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"), @@ -4962,6 +5111,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); @@ -4982,6 +5133,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 @@ -5045,7 +5226,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 @@ -5085,7 +5267,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 " @@ -9193,24 +9376,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 % 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 % with function pointer"); } @@ -9221,7 +9414,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)) { @@ -9265,6 +9462,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); @@ -9276,9 +9477,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"); } diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 26b5a14a3d7..8df014dad99 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -9855,6 +9855,18 @@ Internally, address spaces are represented as a small integer in the range 0 to 15 with address space 0 being reserved for the generic address space. +@defmac TARGET_ADDR_SPACE_KEYWORDS +A list of @code{ADDR_SPACE_KEYWORD} macros to define each named +address keyword. The @code{ADDR_SPACE_KEYWORD} macro takes two +arguments, the keyword string and the number of the named address +space. For example, the SPU port uses the following to declare +@code{__ea} as the keyword for named address space #1: +@smallexample +#define ADDR_SPACE_EA 1 +#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA) +@end smallexample +@end defmac + @deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space}) Define this to return the machine mode to use for pointers to @var{address_space} if the target supports named address spaces.