tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document.

2009-10-26  Ben Elliston  <bje@au.ibm.com>
	    Michael Meissner  <meissner@linux.vnet.ibm.com>
	    Ulrich Weigand  <uweigand@de.ibm.com>

	* 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 <meissner@linux.vnet.ibm.com>
Co-Authored-By: Ulrich Weigand <uweigand@de.ibm.com>

From-SVN: r153574
This commit is contained in:
Ben Elliston 2009-10-26 21:58:06 +00:00 committed by Ulrich Weigand
parent d4ebfa65c9
commit 36c5e70a3a
9 changed files with 541 additions and 41 deletions

View File

@ -1,3 +1,56 @@
2009-10-26 Ben Elliston <bje@au.ibm.com>
Michael Meissner <meissner@linux.vnet.ibm.com>
Ulrich Weigand <uweigand@de.ibm.com>
* 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 <bje@au.ibm.com>
Michael Meissner <meissner@linux.vnet.ibm.com>
Ulrich Weigand <uweigand@de.ibm.com>

View File

@ -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

View File

@ -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);

View File

@ -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 %<volatile%>");
}
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 %<auto%> qualifier for %qE",
c_addr_space_name (address_space), name);
break;
case csc_register:
error ("%qs combined with %<register%> 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. */

View File

@ -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)

View File

@ -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:

View File

@ -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 */

View File

@ -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 %<void *%> 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 %<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");
}
@ -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");
}

View File

@ -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.