2009-10-26 Ben Elliston <bje@au.ibm.com>
authoruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Oct 2009 21:58:06 +0000 (21:58 +0000)
committeruweigand <uweigand@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 26 Oct 2009 21:58:06 +0000 (21:58 +0000)
    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

gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/c-parser.c
gcc/c-pretty-print.c
gcc/c-tree.h
gcc/c-typeck.c
gcc/doc/tm.texi

index 658274d..db375c7 100644 (file)
@@ -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.
index 8a6d15b..1f30d06 100644 (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
index 61d52c8..d91546f 100644 (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);
index e237332..492d2e6 100644 (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.  */
 
index 767d97f..1a6012e 100644 (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)
index c4e6e96..0177001 100644 (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:
index c7490e4..e71771a 100644 (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 */
index 3274e07..c7d2bc8 100644 (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);
 }
 \f
 /* 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");
            }
index 26b5a14..8df014d 100644 (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.