public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Paul Iannetta <piannetta@kalrayinc.com>
To: Jason Merrill <jason@redhat.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: [PATCH v4] c++: parser - Support for target address spaces in C++
Date: Thu, 10 Nov 2022 16:42:22 +0100	[thread overview]
Message-ID: <20221110154222.twnrydaj3zhig3tj@ws2202.lin.mbt.kalray.eu> (raw)
In-Reply-To: <a0ae9db0-d540-cbf4-0aff-7d93f0d4264a@redhat.com>

Hi,

It took a bit of time to rework the rough corners.  I tried to be
mirror as much as possible the C front-end, especially when it comes
to implicit conversions, and warnings; and expose the same hooks as
the C front-end does.  The C++ front-end produces as much warnings
that the C front-end, however they are sometimes a bit less
informative (especially so, when passing arguments to functions).

I also address the following points:

  1.  The handling of the register storage class is grouped with the
  other variables with automatic storage.  This incurs a slight
  dis-alignment since you cannot have global register variables do not
  trigger an error, only a warning.

  2. In template unification, I maintain that we don't want any
  changes to address spaces whatsoever during the unification process,
  hence ignoring the strict flag.  Nevertheless, we allow implicit
  conversion, and I have verified that, indeed,


template <class T> void f(T **);
struct A {
   template <class T> operator T*__seg_fs*();
};
int main()
{
   f((void* __seg_fs *)0);           // (1): void*__seg_fs* -> void** should be OK
   void (*p)(void * __seg_fs *) = f; // (2): error
}

works as intended. That is, (1) works if we set __seg_fs as a subspace
of the generic address space, and (2) is always an error.

  3. In template unification, when unifying __as1 T = __as2 U we want
  to unify to the __as1 at most, never to __as2 at most, because the
  function requiring __as1 T may want to mix address space from the
  bigger address space, therefore I think that we want to have the
  smaller address-space to be unified into the bigger of the two.

  4. I left untouched same_type_ignoring_top_level_qualifiers_p, even
  though that was very convenient and often lead to better error
  messages since error were caught earlier.

  5. The handling of conversions is done very late in the calling
  chain, because I absolutely want to fold the conversion and force
  the conversion to appear as an ADDR_SPACE_CONV_EXPR after
  gimplification.

  6.  Currently, I do not handle classes. I see what I can do in a
  further revision and maybe add a target hook to hand down to targets
  the choice of the address space of the vtable.

  7.  This can't be added as a test case, but I checked that:

 // In this test case, __seg_gs is a subset of the generic address
 // space.

 int f (int *);
 int main ()
 {
   int __seg_fs *pa;
   int __seg_gs *pb;
   int *pc;
   pa = (__seg_fs int *) pb; return *pa; // warning: cast to ‘__seg_fs’ address space pointer from disjoint ‘__seg_gs’ address space pointer
   pa = (int __seg_fs *) pc; return *pa; // warning: cast to ‘__seg_fs’ address space pointer from disjoint generic address space pointer
   pa = pb; return *pa; //  error: invalid conversion from ‘__seg_gs int*’ to ‘__seg_fs int*’
   pc = pb; return *pc; // __seg_gs int * -> int * converted through ADDR_SPACE_CONV_EXPR
   pb = pc; return *pb; // error: invalid conversion from ‘int*’ to ‘__seg_gs int*’
   pc = pa; return *pb; //  error: invalid conversion from ‘__seg_fs int*’ to ‘int*’
   return f (pb); // __seg_gs int * -> int * converted through ADDR_SPACE_CONV_EXPR
   // return f (pa); // error: invalid conversion from ‘__seg_fs int*’ to ‘int*’
                     // note:   initializing argument 1 of ‘int f(int*)’
 }

Thanks,
Paul

Rebased on current trunk, bootstrapped and regtested.
# ------------------------ >8 ------------------------
gcc/cp/ChangeLog:

2022-11-09  Paul Iannetta  <piannetta@kalray.eu>

	* call.cc (convert_like_internal): Add support for implicit
	  conversion between compatible address spaces.  This is done
	  here (and not in a higher caller) because we want to force the
	  use of cp_fold_convert, which later enable back-end writers to
	  tune-up the fine details of the conversion.
	* cp-tree.h (enum cp_decl_spec): Add a new decl spec to handle
	  address spaces.
	(struct cp_decl_specifier_seq): Likewise.
	* decl.cc (get_type_quals): Add address space support.
	(check_tag_decl): Likewise.
	(grokdeclarator): Likewise.
	* class.cc (fixed_type_or_null): Add a case for
	  ADDR_SPACE_CONVERT_EXPR.
	* constexpr.cc (cxx_eval_constant_expression): Likewise.
	(potential_constant_expression_1): Likewise.
	* cp-gimplify.cc (cp_fold): Likewise.
	* error.cc (dump_expr): Likewise.
	* expr.cc (mark_use): Likewise.
	* tree.cc (cp_stabilize_reference): Likewise.
	(strip_typedefs_expr): Likewise.
	(cp_tree_equal): Likewise.
	(mark_exp_read): Likewise.
	* mangle.cc (write_CV_qualifiers_for_type): Mangle address
	  spaces using the extended type qualifier scheme.
	* parser.cc (cp_lexer_get_preprocessor_token): Add a call to
	  targetm.addr_space.diagnose_usage when lexing an address space
	  token.
	(cp_parser_postfix_expression): Prevent the use of address
	spaces with compound literals.
	(cp_parser_dot_deref_incomplete): Add a case for
	ADDR_SPACE_CONVERT_EXPR.
	(cp_parser_type_specifier): Add address space support.
	(cp_parser_cv_qualifier_seq_opt): Likewise.
	(set_and_check_decl_spec_loc): Likewise.
	* pt.cc (invalid_tparm_referent_p): Add a case for
	  ADDR_SPACE_CONVERT_EXPR.
	(tsubst_copy): Likewise.
	(tsubst_omp_clauses): Likewise.
	(tsubst_omp_for_iterator): Likewise.
	(check_cv_quals_for_unify): Add address space support.
	(unify): Likewise.
	* typeck.cc (composite_pointer_type_r): Likewise.
	(pointer_diff): Likewise.
	(cp_build_addr_expr_1): Add a case for ADDR_SPACE_CONVERT_EXPR.
	(warn_about_cast_crossing_as_boundaries): New function.
	(build_static_cast): Add address space support.
	(build_reinterpret_cast): Add address space support.
	(build_const_cast): Add address space support.
	(cp_build_c_cast): Add address space support.
	(comp_ptr_ttypes_real): Add address space support.

gcc/c/ChangeLog:

2022-11-09  Paul Iannetta  <piannetta@kalray.eu>

	* c-decl.cc (r_register_addr_space): Remove.
	* c-typeck.cc: (addr_space_superset): Move to gcc/c/c-common.h

gcc/c-family/ChangeLog:

2022-11-09  Paul Iannetta  <piannetta@kalray.eu>

	* c-common.cc (addr_space_superset): Imported from c-decl.cc
	(c_register_addr_space): Imported from gcc/c/c-typeck.cc
	* c-common.h: Remove the FIXME.
	(addr_space_superset): New declaration.

gcc/testsuite/ChangeLog:

2022-11-09  Paul Iannetta  <piannetta@kalray.eu>

	* g++.dg/abi/mangle-addr-space1.C: New test.
	* g++.dg/abi/mangle-addr-space2.C: New test.
	* g++.dg/ext/addr-space-decl.C: New test.
	* g++.dg/ext/addr-space-ops.C: New test.
	* g++.dg/ext/addr-space-ref.C: New test.
	* g++.dg/parse/addr-space.C: New test.
	* g++.dg/parse/addr-space1.C: New test.
	* g++.dg/parse/addr-space2.C: New test.
	* g++.dg/template/addr-space-overload.C: New test.
	* g++.dg/template/addr-space-strip1.C: New test.
	* g++.dg/template/addr-space-strip2.C: New test.
	* g++.dg/template/spec-addr-space.C: New test.

gcc/ChangeLog:

2022-11-09  Paul Iannetta  <piannetta@kalray.eu>

	* doc/.../named-address-spaces.rst: Add C++ support.
	* targhooks.cc (default_addr_space_subset_p):
	* tree.h (ENCODE_QUAL_ADDR_SPACE): Missing parentheses.

# Date:      Sun Oct 9 16:02:22 2022 +0200
#
# ------------------------ >8 ------------------------
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 5890c18bdc3..88351441c0c 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -588,6 +588,33 @@ c_addr_space_name (addr_space_t as)
   return IDENTIFIER_POINTER (ridpointers [rid]);
 }
 
+/* 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.  */
+
+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;
+}
+
 /* Push current bindings for the function name VAR_DECLS.  */
 
 void
@@ -2789,6 +2816,25 @@ c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
   return build_nonstandard_integer_type (width, unsignedp);
 }
 
+/* Register reserved keyword WORD as qualifier for address space AS.  */
+
+void
+c_register_addr_space (const char *word, addr_space_t as)
+{
+  int rid = RID_FIRST_ADDR_SPACE + as;
+  tree id;
+
+  /* Address space qualifiers are only supported
+     in C with GNU extensions enabled.  */
+  if (c_dialect_objc () || flag_no_asm)
+    return;
+
+  id = get_identifier (word);
+  C_SET_RID_CODE (id, rid);
+  TREE_LANG_FLAG_0 (id) = 1;
+  ridpointers[rid] = id;
+}
+
 /* The C version of the register_builtin_type langhook.  */
 
 void
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index f9d0d2945a5..4ffaabd9f50 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -829,12 +829,11 @@ extern const struct attribute_spec c_common_format_attribute_table[];
 
 extern tree (*make_fname_decl) (location_t, tree, int);
 
-/* In c-decl.cc and cp/tree.cc.  FIXME.  */
-extern void c_register_addr_space (const char *str, addr_space_t as);
-
 /* In c-common.cc.  */
 extern bool in_late_binary_op;
 extern const char *c_addr_space_name (addr_space_t as);
+extern const char *c_addr_space_name (addr_space_t as);
+extern bool addr_space_superset (addr_space_t, addr_space_t, addr_space_t *);
 extern tree identifier_global_value (tree);
 extern tree identifier_global_tag (tree);
 extern bool names_builtin_p (const char *);
@@ -951,6 +950,7 @@ extern bool c_common_init (void);
 extern void c_common_finish (void);
 extern void c_common_parse_file (void);
 extern alias_set_type c_common_get_alias_set (tree);
+extern void c_register_addr_space (const char *, addr_space_t);
 extern void c_register_builtin_type (tree, const char*);
 extern bool c_promoting_integer_type_p (const_tree);
 extern bool self_promoting_args_p (const_tree);
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index a99b7456055..cf4076849f7 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -12869,25 +12869,6 @@ c_parse_final_cleanups (void)
   ext_block = NULL;
 }
 
-/* Register reserved keyword WORD as qualifier for address space AS.  */
-
-void
-c_register_addr_space (const char *word, addr_space_t as)
-{
-  int rid = RID_FIRST_ADDR_SPACE + as;
-  tree id;
-
-  /* Address space qualifiers are only supported
-     in C with GNU extensions enabled.  */
-  if (c_dialect_objc () || flag_no_asm)
-    return;
-
-  id = get_identifier (word);
-  C_SET_RID_CODE (id, rid);
-  C_IS_RESERVED_WORD (id) = 1;
-  ridpointers [rid] = id;
-}
-
 /* Return identifier to look up for omp declare reduction.  */
 
 tree
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 636098444b4..98cfc2132fc 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -303,32 +303,6 @@ 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.  */
 
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 492db9b59ad..25ceef04abb 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -8147,7 +8147,32 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
 				 complain);
 	  else if (t->kind == ck_identity)
 	    break;
-	}
+	  else if (t->kind == ck_ptr
+	      && INDIRECT_TYPE_P (TREE_TYPE (expr))
+	      && INDIRECT_TYPE_P (totype))
+	    {
+	      tree from = TREE_TYPE (TREE_TYPE (expr));
+	      tree to = TREE_TYPE (totype);
+
+	      int from_full_quals = cp_type_quals (from);
+	      int to_full_quals = cp_type_quals (to);
+	      int from_quals = CLEAR_QUAL_ADDR_SPACE (from_full_quals);
+	      int to_quals = CLEAR_QUAL_ADDR_SPACE (to_full_quals);
+	      addr_space_t as_from = DECODE_QUAL_ADDR_SPACE (from_full_quals);
+	      addr_space_t as_to = DECODE_QUAL_ADDR_SPACE (to_full_quals);
+	      if (same_type_ignoring_top_level_qualifiers_p (from, to)
+		  && from_quals == to_quals && as_from != as_to)
+		{
+		  addr_space_t as_common;
+
+		  /* If AS_FROM can be converted to AS_TO fold convert to force the
+		     selection of ADDR_SPACE_CONVERT_EXPR instead of NOP_EXPR.  */
+		  if (addr_space_superset (as_from, as_to, &as_common)
+		      && as_common == as_to)
+		    return cp_fold_convert (totype, expr);
+		}
+	    }
+	  }
       if (!complained && expr != error_mark_node)
 	{
 	  range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index aebcb53739e..5addff58214 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -7902,6 +7902,7 @@ fixed_type_or_null (tree instance, int *nonnull, int *cdtorp)
       return NULL_TREE;
 
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
       return RECUR (TREE_OPERAND (instance, 0));
 
     case ADDR_EXPR:
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 15b4f2c4a08..56124960086 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7535,6 +7535,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
       /* FALLTHROUGH.  */
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
     case UNARY_PLUS_EXPR:
       {
 	tree oldop = TREE_OPERAND (t, 0);
@@ -9076,6 +9077,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
       /* FALLTHRU */
     case CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
       /* -- a reinterpret_cast.  FIXME not implemented, and this rule
 	 may change to something more specific to type-punning (DR 1312).  */
       {
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index cc8bfada5af..5a95902e762 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2470,6 +2470,7 @@ cp_fold (tree x)
       /* FALLTHRU */
     case NON_LVALUE_EXPR:
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
 
       if (VOID_TYPE_P (TREE_TYPE (x)))
 	{
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bbc8be21900..6cf2406ce98 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6237,6 +6237,7 @@ enum cp_decl_spec {
   ds_complex,
   ds_constinit,
   ds_consteval,
+  ds_addr_space,
   ds_thread,
   ds_type_spec,
   ds_redefined_builtin_type_spec,
@@ -6273,6 +6274,8 @@ struct cp_decl_specifier_seq {
   cp_storage_class storage_class;
   /* For the __intN declspec, this stores the index into the int_n_* arrays.  */
   int int_n_idx;
+  /* The address space that the declaration belongs to.  */
+  addr_space_t address_space;
   /* True iff TYPE_SPEC defines a class or enum.  */
   BOOL_BITFIELD type_definition_p : 1;
   /* True iff multiple types were (erroneously) specified for this
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 890cfcabd35..e2d97409b05 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -5353,6 +5353,8 @@ get_type_quals (const cp_decl_specifier_seq *declspecs)
     type_quals |= TYPE_QUAL_VOLATILE;
   if (decl_spec_seq_has_spec_p (declspecs, ds_restrict))
     type_quals |= TYPE_QUAL_RESTRICT;
+  if (decl_spec_seq_has_spec_p (declspecs, ds_addr_space))
+    type_quals |= ENCODE_QUAL_ADDR_SPACE (declspecs->address_space);
 
   return type_quals;
 }
@@ -5475,6 +5477,10 @@ check_tag_decl (cp_decl_specifier_seq *declspecs,
 	error_at (declspecs->locations[ds_restrict],
 		  "%<__restrict%> can only be specified for objects and "
 		  "functions");
+      else if (decl_spec_seq_has_spec_p (declspecs, ds_addr_space))
+	error_at (declspecs->locations[ds_addr_space],
+		  "address space can only be specified for objects and "
+		  "functions");
       else if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
 	error_at (declspecs->locations[ds_thread],
 		  "%<__thread%> can only be specified for objects "
@@ -14674,6 +14680,49 @@ grokdeclarator (const cp_declarator *declarator,
     if (!processing_template_decl)
       cp_apply_type_quals_to_decl (type_quals, decl);
 
+    /* Warn about address space used for things other than static memory or
+       pointers.  */
+    addr_space_t address_space = DECODE_QUAL_ADDR_SPACE (type_quals);
+    if (!ADDR_SPACE_GENERIC_P (address_space))
+    {
+      if (VAR_P (decl) && decl_context == NORMAL)
+	{
+	  duration_kind dk = decl_storage_duration (decl);
+	  switch (dk)
+	    {
+	    case dk_auto:
+	      if (! toplevel_bindings_p ())
+		error ("%qs specified for variable %qs with automatic storage",
+		       c_addr_space_name (address_space), name);
+	      break;
+	    case dk_static:
+	    case dk_thread:
+	    case dk_dynamic:
+	      break;
+	    default:
+	      gcc_unreachable ();
+	    }
+	}
+      else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE)
+	{
+	  if (name)
+	    error ("%qs specified for parameter %qs",
+		   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 %qs",
+		   c_addr_space_name (address_space), name);
+	  else
+	    error ("%qs specified for structure field",
+		   c_addr_space_name (address_space));
+	}
+    }
+
     return decl;
   }
 }
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index da8c95c9b43..c02ea67b0e7 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -2633,6 +2633,7 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
     CASE_CONVERT:
     case IMPLICIT_CONV_EXPR:
     case VIEW_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
       {
 	tree op = TREE_OPERAND (t, 0);
 
diff --git a/gcc/cp/expr.cc b/gcc/cp/expr.cc
index f3e155b7ba3..457c2cf5cb4 100644
--- a/gcc/cp/expr.cc
+++ b/gcc/cp/expr.cc
@@ -214,6 +214,7 @@ mark_use (tree expr, bool rvalue_p, bool read_p,
 	}
       gcc_fallthrough();
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
       recurse_op[0] = true;
       break;
 
@@ -373,6 +374,7 @@ mark_exp_read (tree exp)
     case FLOAT_EXPR:
     case NON_DEPENDENT_EXPR:
     case VIEW_CONVERT_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
       mark_exp_read (TREE_OPERAND (exp, 0));
       break;
     case COMPOUND_EXPR:
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index e97428e8f30..31cd35522a5 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2594,6 +2594,14 @@ write_CV_qualifiers_for_type (const tree type)
      array.  */
   cp_cv_quals quals = TYPE_QUALS (type);
 
+  if (addr_space_t as = DECODE_QUAL_ADDR_SPACE (quals))
+    {
+      const char *as_name = c_addr_space_name (as);
+      write_char ('U');
+      write_unsigned_number (strlen (as_name));
+      write_string (as_name);
+      ++num_qualifiers;
+    }
   if (quals & TYPE_QUAL_RESTRICT)
     {
       write_char ('r');
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index e4021835ed5..d9ae1139235 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #define INCLUDE_MEMORY
 #include "system.h"
 #include "coretypes.h"
+#include "target.h"
 #include "cp-tree.h"
 #include "c-family/c-common.h"
 #include "timevar.h"
@@ -962,6 +963,14 @@ cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token)
 	  token->type = CPP_KEYWORD;
 	  /* Record which keyword.  */
 	  token->keyword = C_RID_CODE (token->u.value);
+
+	  if (token->keyword >= RID_FIRST_ADDR_SPACE
+	      && token->keyword <= RID_LAST_ADDR_SPACE)
+		{
+		  addr_space_t as
+		    = (addr_space_t) (token->keyword - RID_FIRST_ADDR_SPACE);
+		  targetm.addr_space.diagnose_usage (as, token->location);
+		}
 	}
       else
 	{
@@ -7707,6 +7716,15 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 		    postfix_expression = error_mark_node;
 		    break;
 		  }
+		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;
+		  }
 		/* Form the representation of the compound-literal.  */
 		postfix_expression
 		  = finish_compound_literal (type, initializer,
@@ -8200,6 +8218,7 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
     case STATIC_CAST_EXPR:
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
+    case ADDR_SPACE_CONVERT_EXPR:
     case VIEW_CONVERT_EXPR:
     case NON_LVALUE_EXPR:
       kind = DK_ERROR;
@@ -19449,6 +19468,14 @@ cp_parser_type_specifier (cp_parser* parser,
       break;
     }
 
+  if (RID_FIRST_ADDR_SPACE <= keyword
+      && keyword <= RID_LAST_ADDR_SPACE)
+    {
+      ds = ds_addr_space;
+      if (is_cv_qualifier)
+	*is_cv_qualifier = true;
+    }
+
   /* Handle simple keywords.  */
   if (ds != ds_last)
     {
@@ -23841,6 +23868,7 @@ cp_parser_ptr_operator (cp_parser* parser,
    GNU Extension:
 
    cv-qualifier:
+     address-space-qualifier
      __restrict__
 
    Returns a bitmask representing the cv-qualifiers.  */
@@ -23877,6 +23905,11 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 	  break;
 	}
 
+      if (RID_FIRST_ADDR_SPACE <= token->keyword
+	  && token->keyword <= RID_LAST_ADDR_SPACE)
+	cv_qualifier
+	  = ENCODE_QUAL_ADDR_SPACE (token->keyword - RID_FIRST_ADDR_SPACE);
+
       if (!cv_qualifier)
 	break;
 
@@ -32898,6 +32931,8 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
       decl_specs->locations[ds] = location;
       if (ds == ds_thread)
 	decl_specs->gnu_thread_keyword_p = token_is__thread (token);
+      else if (ds == ds_addr_space)
+	decl_specs->address_space = token->keyword - RID_FIRST_ADDR_SPACE;
     }
   else
     {
@@ -32930,6 +32965,24 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
 	      error_at (&richloc, "duplicate %qD", token->u.value);
 	    }
 	}
+      else if (ds == ds_addr_space)
+	{
+	  addr_space_t as1 = decl_specs->address_space;
+	  addr_space_t as2 = token->keyword - RID_FIRST_ADDR_SPACE;
+
+	  gcc_rich_location richloc (location);
+	  richloc.add_fixit_remove ();
+	  if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2)
+	      && as1 != as2)
+	    error_at (&richloc,
+		      "incompatible address space qualifiers %qs and %qs",
+		      c_addr_space_name (as1), c_addr_space_name (as2));
+	  if (as1 == as2 && !ADDR_SPACE_GENERIC_P (as1))
+	    error_at (&richloc, "duplicate named address space %qs",
+				  c_addr_space_name (as1));
+
+	  decl_specs->address_space = as2;
+	}
       else
 	{
 	  static const char *const decl_spec_names[] = {
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 57917de321f..bd901b6e0eb 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -7044,6 +7044,7 @@ invalid_tparm_referent_p (tree type, tree expr, tsubst_flags_t complain)
   switch (TREE_CODE (expr))
     {
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
       return invalid_tparm_referent_p (type, TREE_OPERAND (expr, 0),
 				       complain);
 
@@ -17253,6 +17254,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
     case DYNAMIC_CAST_EXPR:
     case IMPLICIT_CONV_EXPR:
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
       {
 	tsubst_flags_t tcomplain = complain;
 	if (code == CAST_EXPR)
@@ -17986,6 +17988,7 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
 		    case MEM_REF:
 		    case INDIRECT_REF:
 		    CASE_CONVERT:
+		    case ADDR_SPACE_CONVERT_EXPR:
 		    case POINTER_PLUS_EXPR:
 		      v = TREE_OPERAND (v, 0);
 		      continue;
@@ -18170,6 +18173,7 @@ tsubst_omp_for_iterator (tree t, int i, tree declv, tree &orig_declv,
 		  case MEM_REF:
 		  case INDIRECT_REF:
 		  CASE_CONVERT:
+		  case ADDR_SPACE_CONVERT_EXPR:
 		  case POINTER_PLUS_EXPR:
 		    v = TREE_OPERAND (v, 0);
 		    continue;
@@ -23706,12 +23710,21 @@ template_decl_level (tree decl)
 static int
 check_cv_quals_for_unify (int strict, tree arg, tree parm)
 {
-  int arg_quals = cp_type_quals (arg);
-  int parm_quals = cp_type_quals (parm);
+  int arg_quals = CLEAR_QUAL_ADDR_SPACE (cp_type_quals (arg));
+  int parm_quals = CLEAR_QUAL_ADDR_SPACE (cp_type_quals (parm));
+
+  /*  Try to unify ARG's address space into PARM's address space.
+      If PARM does not have any address space qualifiers (ie., as_parm is 0),
+      there are no constraints on address spaces for this type.  */
+  addr_space_t as_arg = DECODE_QUAL_ADDR_SPACE (cp_type_quals (arg));
+  addr_space_t as_parm = DECODE_QUAL_ADDR_SPACE (cp_type_quals (parm));
+  addr_space_t as_common;
+  addr_space_superset (as_arg, as_parm, &as_common);
 
   if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
       && !(strict & UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
     {
+
       /*  Although a CVR qualifier is ignored when being applied to a
 	  substituted template parameter ([8.3.2]/1 for example), that
 	  does not allow us to unify "const T" with "int&" because both
@@ -23728,6 +23741,9 @@ check_cv_quals_for_unify (int strict, tree arg, tree parm)
 	return 0;
     }
 
+  if (!(as_parm == as_common || as_parm == 0))
+    return 0;
+
   if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
       && (arg_quals & parm_quals) != parm_quals)
     return 0;
@@ -24343,10 +24359,28 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 					 arg, parm))
 	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
+	  int arg_cv_quals = cp_type_quals (arg);
+	  int parm_cv_quals = cp_type_quals (parm);
+
+	  /* If PARM does not contain any address spaces constraints it can
+	     fully match the address space of ARG.  However, if PARM contains an
+	     address space constraints, it becomes the upper bound.  That is,
+	     AS_ARG may be promoted to AS_PARM but not the converse.  If we
+	     ended up here, it means that `check_cv_quals_for_unify' succeeded
+	     and that either AS_PARM is 0 (ie., no constraints) or AS_COMMON ==
+	     AS_PARM.  */
+	  addr_space_t as_arg = DECODE_QUAL_ADDR_SPACE (arg_cv_quals);
+	  addr_space_t as_parm = DECODE_QUAL_ADDR_SPACE (parm_cv_quals);
+	  addr_space_t as_common = as_parm ? 0 : as_arg;
+
 	  /* Consider the case where ARG is `const volatile int' and
 	     PARM is `const T'.  Then, T should be `volatile int'.  */
 	  arg = cp_build_qualified_type
 	    (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none);
+	  int unified_cv =
+	    (CLEAR_QUAL_ADDR_SPACE (arg_cv_quals & ~parm_cv_quals)
+	    | ENCODE_QUAL_ADDR_SPACE (as_common));
+	  arg = cp_build_qualified_type (arg, unified_cv, tf_none);
 	  if (arg == error_mark_node)
 	    return unify_invalid (explain_p);
 
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 954c6de2fcd..fc603eb5568 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -421,6 +421,7 @@ cp_stabilize_reference (tree ref)
     case PARM_DECL:
     case RESULT_DECL:
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
     case INDIRECT_REF:
@@ -2040,6 +2041,7 @@ strip_typedefs_expr (tree t, bool *remove_attributes, unsigned int flags)
   switch (code)
     {
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
     case IMPLICIT_CONV_EXPR:
     case DYNAMIC_CAST_EXPR:
     case STATIC_CAST_EXPR:
@@ -4179,6 +4181,7 @@ cp_tree_equal (tree t1, tree t2)
     case NEW_EXPR:
     case BIT_CAST_EXPR:
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
       if (!same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
 	return false;
       /* Now compare operands as usual.  */
@@ -6094,15 +6097,6 @@ cp_free_lang_data (tree t)
     DECL_CHAIN (t) = NULL_TREE;
 }
 
-/* Stub for c-common.  Please keep in sync with c-decl.cc.
-   FIXME: If address space support is target specific, then this
-   should be a C target hook.  But currently this is not possible,
-   because this function is called via REGISTER_TARGET_PRAGMAS.  */
-void
-c_register_addr_space (const char * /*word*/, addr_space_t /*as*/)
-{
-}
-
 /* Return the number of operands in T that we care about for things like
    mangling.  */
 
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 5f5fb2a212b..653b015f673 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -693,9 +693,28 @@ composite_pointer_type_r (const op_location_t &location,
 	return error_mark_node;
       result_type = void_type_node;
     }
+
+
+  /* If possible merge the address space into the superset of the address
+     spaces of t1 and t2, or raise an error. */
   const int q1 = cp_type_quals (pointee1);
   const int q2 = cp_type_quals (pointee2);
-  const int quals = q1 | q2;
+  addr_space_t as_t1 = DECODE_QUAL_ADDR_SPACE (q1);
+  addr_space_t as_t2 = DECODE_QUAL_ADDR_SPACE (q2);
+  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_t1, as_t2, &as_common))
+    {
+      as_common = as_t1;
+      error_at (location, "%qT and %qT are in disjoint named address spaces",
+		t1, t2);
+      return error_mark_node;
+    }
+
+  const int quals = CLEAR_QUAL_ADDR_SPACE (q1 | q2)
+    | ENCODE_QUAL_ADDR_SPACE (as_common);
   result_type = cp_build_qualified_type (result_type,
 					 (quals | (*add_const
 						   ? TYPE_QUAL_CONST
@@ -803,10 +822,27 @@ composite_pointer_type (const op_location_t &location,
 	  else
 	    return error_mark_node;
         }
+
+      addr_space_t as_t1 = TYPE_ADDR_SPACE (t1);
+      addr_space_t as_t2 = TYPE_ADDR_SPACE (t2);
+      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_t1, as_t2, &as_common))
+	{
+	  as_common = as_t1;
+	  error_at (location,
+	      "%qT and %qT are in disjoint named address spaces",
+	      t1, t2);
+	}
+      int quals_t1 = cp_type_quals (TREE_TYPE (t1));
+      int quals_t2 = cp_type_quals (TREE_TYPE (t2));
       result_type
 	= cp_build_qualified_type (void_type_node,
-				   (cp_type_quals (TREE_TYPE (t1))
-				    | cp_type_quals (TREE_TYPE (t2))));
+				   (CLEAR_QUAL_ADDR_SPACE (quals_t1)
+				    | CLEAR_QUAL_ADDR_SPACE (quals_t2)
+				    | ENCODE_QUAL_ADDR_SPACE (as_common)));
       result_type = build_pointer_type (result_type);
       /* Merge the attributes.  */
       attributes = (*targetm.merge_type_attributes) (t1, t2);
@@ -1731,7 +1767,9 @@ comptypes (tree t1, tree t2, int strict)
 }
 
 /* Returns nonzero iff TYPE1 and TYPE2 are the same type, ignoring
-   top-level qualifiers.  */
+   top-level qualifiers, except for named address spaces.  If the pointers point
+   to different named addresses spaces, then we must determine if one address
+   space is a subset of the other.  */
 
 bool
 same_type_ignoring_top_level_qualifiers_p (tree type1, tree type2)
@@ -6676,10 +6714,34 @@ static tree
 pointer_diff (location_t loc, tree op0, tree op1, tree ptrtype,
 	      tsubst_flags_t complain, tree *instrument_expr)
 {
-  tree result, inttype;
   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 (ptrtype);
 
+  /* 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;
+
+      if (!addr_space_superset (as0, as1, &as_common))
+	{
+	  error_at (loc, "pointers to disjoint address spaces "
+			 "%qT and %qT in substraction",
+			 TREE_TYPE (op0), TREE_TYPE (op1));
+	  return error_mark_node;
+	}
+
+      common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1));
+      op0 = convert (common_type, op0);
+      op1 = convert (common_type, op1);
+    }
+
   if (!complete_type_or_maybe_complain (target_type, NULL_TREE, complain))
     return error_mark_node;
 
@@ -7139,6 +7201,7 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
   switch (TREE_CODE (arg))
     {
     CASE_CONVERT:
+    case ADDR_SPACE_CONVERT_EXPR:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
       /* We should have handled this above in the lvalue_kind check.  */
@@ -8133,6 +8196,41 @@ maybe_warn_about_cast_ignoring_quals (location_t loc, tree type,
 		"type qualifiers ignored on cast result type");
 }
 
+/* Warns if the cast cross address-space boundaries.  */
+static void
+warn_about_cast_crossing_as_boundaries (location_t loc, tree type,
+					tree expr, tsubst_flags_t complain)
+{
+  if (TREE_CODE (type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+      && !NULLPTR_TYPE_P (expr)
+      && (complain & tf_warning))
+    {
+      addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type));
+      addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
+      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 %qs 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 %qs address space pointer",
+			c_addr_space_name (as_from));
+
+	  else
+	    warning_at (loc, 0, "cast to %qs address space pointer "
+			"from disjoint %qs address space pointer",
+			c_addr_space_name (as_to),
+			c_addr_space_name (as_from));
+	}
+    }
+}
+
 /* Convert EXPR (an expression with pointer-to-member type) to TYPE
    (another pointer-to-member type in the same hierarchy) and return
    the converted expression.  If ALLOW_INVERSE_P is permitted, a
@@ -8564,6 +8662,7 @@ build_static_cast (location_t loc, tree type, tree oexpr,
 	{
 	  maybe_warn_about_useless_cast (loc, type, expr, complain);
 	  maybe_warn_about_cast_ignoring_quals (loc, type, complain);
+	  warn_about_cast_crossing_as_boundaries (loc, type, expr, complain);
 	}
       if (processing_template_decl)
 	goto tmpl;
@@ -8886,6 +8985,7 @@ build_reinterpret_cast (location_t loc, tree type, tree expr,
     {
       maybe_warn_about_useless_cast (loc, type, expr, complain);
       maybe_warn_about_cast_ignoring_quals (loc, type, complain);
+      warn_about_cast_crossing_as_boundaries (loc, type, expr, complain);
     }
   protected_set_expr_location (r, loc);
   return r;
@@ -9072,6 +9172,7 @@ build_const_cast (location_t loc, tree type, tree expr,
     {
       maybe_warn_about_useless_cast (loc, type, expr, complain);
       maybe_warn_about_cast_ignoring_quals (loc, type, complain);
+      warn_about_cast_crossing_as_boundaries (loc, type, expr, complain);
     }
   protected_set_expr_location (r, loc);
   return r;
@@ -9181,6 +9282,7 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
 	{
 	  maybe_warn_about_useless_cast (loc, type, value, complain);
 	  maybe_warn_about_cast_ignoring_quals (loc, type, complain);
+	  warn_about_cast_crossing_as_boundaries (loc, type, expr, complain);
 	}
       return result;
     }
@@ -9203,6 +9305,7 @@ cp_build_c_cast (location_t loc, tree type, tree expr,
 
       maybe_warn_about_useless_cast (loc, type, value, complain);
       maybe_warn_about_cast_ignoring_quals (loc, type, complain);
+      warn_about_cast_crossing_as_boundaries (loc, type, expr, complain);
 
       /* Non-class rvalues always have cv-unqualified type.  */
       if (!CLASS_TYPE_P (type))
@@ -11308,6 +11411,30 @@ comp_ptr_ttypes_real (tree to, tree from, int constp)
 	      to_more_cv_qualified = true;
 	    }
 
+      /* Warn about conversions between pointers to disjoint
+	 address spaces.  */
+      if (TREE_CODE (from) == POINTER_TYPE
+	  && TREE_CODE (to) == POINTER_TYPE)
+	{
+	  addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (from));
+	  addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (to));
+	  addr_space_t as_common;
+
+	  if (!addr_space_superset (as_to, as_from, &as_common)
+	      || as_common != as_to)
+	    return false;
+	}
+      else
+	{
+	  addr_space_t as_from = TYPE_ADDR_SPACE ((from));
+	  addr_space_t as_to = TYPE_ADDR_SPACE ((to));
+	  addr_space_t as_common;
+
+	  if (!addr_space_superset (as_to, as_from, &as_common)
+	      || as_common != as_to)
+	    return false;
+	}
+
 	  if (constp > 0)
 	    constp &= TYPE_READONLY (to);
 	}
diff --git a/gcc/doc/gcc/extensions-to-the-c-language-family/named-address-spaces.rst b/gcc/doc/gcc/extensions-to-the-c-language-family/named-address-spaces.rst
index 44e4cccc3c8..93fca7cbe3c 100644
--- a/gcc/doc/gcc/extensions-to-the-c-language-family/named-address-spaces.rst
+++ b/gcc/doc/gcc/extensions-to-the-c-language-family/named-address-spaces.rst
@@ -10,7 +10,7 @@
 Named Address Spaces
 ********************
 
-As an extension, GNU C supports named address spaces as
+As an extension, GNU C and GNU C++ support named address spaces as
 defined in the N1275 draft of ISO/IEC DTR 18037.  Support for named
 address spaces in GCC will evolve as the draft technical report
 changes.  Calling conventions for any target might also change.  At
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 12a58456b39..7227739e3f8 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -1687,7 +1687,7 @@ default_addr_space_legitimize_address (rtx x, rtx oldx, machine_mode mode,
 bool
 default_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
 {
-  return (subset == superset);
+  return (subset == 2 && superset == 0) || (subset == superset);
 }
 
 /* The default hook for determining if 0 within a named address
diff --git a/gcc/testsuite/g++.dg/abi/mangle-addr-space1.C b/gcc/testsuite/g++.dg/abi/mangle-addr-space1.C
new file mode 100644
index 00000000000..35701c60637
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-addr-space1.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-final { scan-assembler "_Z1fPU8__seg_fsVi" } }
+
+int f (int volatile __seg_fs *a)
+{
+  return *a;
+}
+
+int main () {}
diff --git a/gcc/testsuite/g++.dg/abi/mangle-addr-space2.C b/gcc/testsuite/g++.dg/abi/mangle-addr-space2.C
new file mode 100644
index 00000000000..1daf15a73c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-addr-space2.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-options "-fabi-version=8 -Wabi -save-temps" }
+// { dg-final { scan-assembler "_Z1fIU8__seg_fsiEiPT_" } }
+
+template <class T>
+int f (T *p) { return *p; }
+int g (__seg_fs int *p) { return *p; }
+__seg_fs int *a;
+int main() { f(a); }
diff --git a/gcc/testsuite/g++.dg/ext/addr-space-decl.C b/gcc/testsuite/g++.dg/ext/addr-space-decl.C
new file mode 100644
index 00000000000..4199bf375b3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/addr-space-decl.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+__seg_fs char a, b, c;
+__seg_fs const int *p;
+static /* gives internal linkage to variable q */
+__seg_fs struct { int a; char b; } * __seg_gs q;
diff --git a/gcc/testsuite/g++.dg/ext/addr-space-ops.C b/gcc/testsuite/g++.dg/ext/addr-space-ops.C
new file mode 100644
index 00000000000..783e36aabab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/addr-space-ops.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+int __seg_fs * fs1;
+int __seg_fs * fs2;
+int __seg_gs * gs1;
+int __seg_gs * gs2;
+
+int
+main ()
+{
+  fs1 + fs2; // { dg-error "invalid operands of types .__seg_fs int.. and .__seg_fs int.. to binary .operator.." }
+  fs1 - fs2;
+  fs1 - gs2; // { dg-error "pointers to disjoint address spaces .__seg_fs int.. and .__seg_gs int.. in substraction" }
+	     // { dg-error ".__seg_fs int.. and .__seg_gs int.. are in disjoint named address spaces" "" { target *-*-* } .-1 }
+  fs1 == fs2;
+  fs1 != gs2; // { dg-error ".__seg_fs int.. and .__seg_gs int.. are in disjoint named address spaces" }
+  fs1 = fs2;
+  fs1 = gs2; // { dg-error "invalid conversion from .__seg_gs int.. to .__seg_fs int.." }
+  fs1 > fs2;
+  fs1 < gs2; // { dg-error ".__seg_fs int.. and .__seg_gs int.. are in disjoint named address spaces" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/ext/addr-space-ref.C b/gcc/testsuite/g++.dg/ext/addr-space-ref.C
new file mode 100644
index 00000000000..e87649abb5d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/addr-space-ref.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-prune-output "does not allow .register. storage class specifier" }
+int __seg_fs * outer_b;
+
+struct s {
+  __seg_fs int * ok;
+  __seg_gs int ko; // { dg-error ".__seg_gs. specified for structure field .ko." }
+};
+
+namespace ns_a
+{
+  int __seg_fs * inner_b;
+
+  template<typename T>
+  int f (T &a) { return a; }
+  int g (__seg_fs int a) { return a; } // { dg-error ".__seg_fs. specified for parameter .a." }
+  int h (__seg_fs int *a) { return *a; }
+}
+
+int
+main ()
+{
+  int register __seg_gs reg_gs; // { dg-error ".__seg_gs. specified for variable .reg_gs. with automatic storage" }
+  static __seg_gs int static_gs;
+  __seg_fs int auto_fs; // { dg-error ".__seg_fs. specified for variable .auto_fs. with automatic storage" }
+  __seg_fs int *pa = outer_b;
+  __seg_fs int& ra = *ns_a::inner_b;
+  return ns_a::f(ra) + ns_a::f(*pa);
+}
diff --git a/gcc/testsuite/g++.dg/parse/addr-space.C b/gcc/testsuite/g++.dg/parse/addr-space.C
new file mode 100644
index 00000000000..ebb6316054a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/addr-space.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+
+__seg_fs struct foo; // { dg-error "address space can only be specified for objects and functions" }
+
+int
+main ()
+{
+	return 0; 
+}
diff --git a/gcc/testsuite/g++.dg/parse/addr-space1.C b/gcc/testsuite/g++.dg/parse/addr-space1.C
new file mode 100644
index 00000000000..2e8ee32a885
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/addr-space1.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-options "-std=gnu++98" }
+
+int
+main ()
+{
+	struct foo {int a; char b[2];} structure;
+	structure = ((__seg_fs struct foo) {1 + 2, 'a', 0}); // { dg-error "compound literal qualified by address-space qualifier" }
+	return 0; 
+}
diff --git a/gcc/testsuite/g++.dg/parse/addr-space2.C b/gcc/testsuite/g++.dg/parse/addr-space2.C
new file mode 100644
index 00000000000..5f64d52885e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/addr-space2.C
@@ -0,0 +1,9 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+
+__seg_fs __seg_gs int *a; // { dg-error "incompatible address space qualifiers" }
+
+int
+main ()
+{
+	return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/addr-space-overload.C b/gcc/testsuite/g++.dg/template/addr-space-overload.C
new file mode 100644
index 00000000000..70dfcce53fa
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/addr-space-overload.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+
+int __seg_fs * fs1;
+int __seg_gs * gs1;
+
+template<typename T, typename U>
+__seg_fs T* f (T __seg_fs * a, U __seg_gs * b) { return a; }
+template<typename T, typename U>
+__seg_gs T* f (T __seg_gs * a, U __seg_fs * b) { return a; }
+
+int
+main ()
+{
+    f (fs1, gs1);
+    f (gs1, fs1);
+    return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/addr-space-strip1.C b/gcc/testsuite/g++.dg/template/addr-space-strip1.C
new file mode 100644
index 00000000000..36c402f5cd2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/addr-space-strip1.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+// { dg-require-effective-target c++11 }
+// decltype is only available since c++11
+
+int __seg_fs * fs1;
+int __seg_gs * gs1;
+
+template<typename T> struct strip;
+template<typename T> struct strip<__seg_fs T *> { typedef T type; };
+template<typename T> struct strip<__seg_gs T *> { typedef T type; };
+
+int
+main ()
+{
+    *(strip<decltype(fs1)>::type *) fs1 == *(strip<decltype(gs1)>::type *) gs1;
+    // { dg-warning "cast to generic address space pointer from disjoint" "" { target *-*-* } .-1 }
+    return 0;
+}
diff --git a/gcc/testsuite/g++.dg/template/addr-space-strip2.C b/gcc/testsuite/g++.dg/template/addr-space-strip2.C
new file mode 100644
index 00000000000..a2ffb532087
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/addr-space-strip2.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+
+int __seg_fs * fs1;
+int __seg_gs * gs1;
+
+template<typename T, typename U>
+bool f (T __seg_fs * a, U __seg_gs * b)
+{
+    return *(T *) a == *(U *) b;
+    // { dg-warning "cast to generic address space pointer from disjoint" "" { target *-*-* } .-1 }
+}
+
+int
+main ()
+{
+    return f (fs1, gs1);
+}
diff --git a/gcc/testsuite/g++.dg/template/spec-addr-space.C b/gcc/testsuite/g++.dg/template/spec-addr-space.C
new file mode 100644
index 00000000000..ae9f4de0e1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec-addr-space.C
@@ -0,0 +1,8 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+
+template <class T>
+int f (T __seg_gs *p) { return *p; } // { dg-note "candidate: 'template<class T> int f.__seg_gs T\*." }
+				     // { dg-note "template argument deduction/substitution failed:" "" { target *-*-* } .-1 }
+__seg_fs int *a;
+int main() { f(a); } // { dg-error "no matching" }
+// { dg-note "types .__seg_gs T. and .__seg_fs int. have incompatible cv-qualifiers" "" { target *-*-* } .-1 }
diff --git a/gcc/tree.h b/gcc/tree.h
index a863d2e50e5..b9992e3fca8 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2298,7 +2298,7 @@ extern tree vector_element_bits_tree (const_tree);
 
 /* Encode/decode the named memory support as part of the qualifier.  If more
    than 8 qualifiers are added, these macros need to be adjusted.  */
-#define ENCODE_QUAL_ADDR_SPACE(NUM) ((NUM & 0xFF) << 8)
+#define ENCODE_QUAL_ADDR_SPACE(NUM) (((NUM) & 0xFF) << 8)
 #define DECODE_QUAL_ADDR_SPACE(X) (((X) >> 8) & 0xFF)
 
 /* Return all qualifiers except for the address space qualifiers.  */







  reply	other threads:[~2022-11-10 15:42 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-06 14:34 [RFC] " Paul Iannetta
2022-10-06 17:34 ` Jason Merrill
2022-10-09 16:12   ` [PATCH] " Paul Iannetta
2022-10-10 19:20     ` Jason Merrill
2022-10-11 22:03       ` [PATCH v2] " Paul Iannetta
2022-10-12  1:49         ` Jason Merrill
2022-10-13  0:52           ` Paul Iannetta
2022-10-13  5:46             ` Jakub Jelinek
2022-10-13 15:14               ` Paul Iannetta
2022-10-13 15:02             ` Jason Merrill
2022-10-13 15:23               ` Paul Iannetta
2022-10-13 15:47                 ` Jason Merrill
2022-10-13 16:02                   ` Paul Iannetta
2022-10-13 19:41                     ` Jason Merrill
2022-10-13 21:57                       ` Paul Iannetta
2022-10-14 15:19                         ` Jason Merrill
2022-10-18  7:37                           ` [PATCH v3] " Paul Iannetta
2022-10-18 14:24                             ` Jason Merrill
2022-10-18 17:01                               ` Paul Iannetta
2022-10-19 18:55                                 ` Jason Merrill
2022-10-26  7:18                                   ` Paul Iannetta
2022-10-26 16:28                                     ` Jason Merrill
2022-11-10 15:42                                       ` Paul Iannetta [this message]
2022-11-03 13:38                                     ` Georg-Johann Lay
2022-11-10 14:08                                       ` Paul Iannetta
2022-11-10 16:40                                         ` Georg-Johann Lay
2022-11-14 17:55                                           ` Jason Merrill
2022-11-15 12:15                                             ` Georg-Johann Lay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221110154222.twnrydaj3zhig3tj@ws2202.lin.mbt.kalray.eu \
    --to=piannetta@kalrayinc.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).