summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-26 21:58:06 +0000
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-26 21:58:06 +0000
commit6d5d708e56103fe5b3909c9782d2ade3a982350a (patch)
tree309434d678721acedb299f20cdc2b4778062b180 /gcc
parent98155838dbd82b97bb7bb16dfcbf98fa2ab27ca9 (diff)
downloadgcc-6d5d708e56103fe5b3909c9782d2ade3a982350a.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@153574 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog53
-rw-r--r--gcc/c-common.c23
-rw-r--r--gcc/c-common.h29
-rw-r--r--gcc/c-decl.c135
-rw-r--r--gcc/c-parser.c43
-rw-r--r--gcc/c-pretty-print.c12
-rw-r--r--gcc/c-tree.h4
-rw-r--r--gcc/c-typeck.c271
-rw-r--r--gcc/doc/tm.texi12
9 files changed, 541 insertions, 41 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 658274da303..db375c7fb92 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -2,6 +2,59 @@
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>
+
* doc/tm.texi (TARGET_ADDR_SPACE_POINTER_MODE): Document.
(TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise.
(TARGET_ADDR_SPACE_VALID_POINTER_MODE): Likewise.
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 %<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. */
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 %<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");
}
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.