Ex1:
```
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;
return 0;
}
```
Ex2:
```
int __seg_fs * fs1;
int __seg_fs * fs2;
template<typename T, typename U> auto f (T __seg_fs * a, U __seg_gs * b) {
return a; }
template<typename T, typename U> auto f (T __seg_gs * a, U __seg_fs * b) {
return a; }
int
main ()
{
f (fs1, gs1);
f (gs1, fs1);
return 0;
}
```
Ex3:
```
int __seg_fs * fs1;
int __seg_gs * gs1;
template<typename T, typename U>
auto f (T __seg_fs * a, U __seg_gs * b)
{
return *(T *) a == *(U *) b;
}
int
main ()
{
return f (fs1, gs1);
}
```
Add support for custom address spaces in C++
gcc/
* tree.h (ENCODE_QUAL_ADDR_SPACE): Missing parentheses.
gcc/c/
* c-decl.cc: Remove c_register_addr_space.
gcc/c-family/
* c-common.cc (c_register_addr_space): Imported from c-decl.cc
(addr_space_superset): Imported from gcc/c/c-typecheck.cc
* c-common.h: Remove the FIXME.
(addr_space_superset): New declaration.
gcc/cp/
* cp-tree.h (enum cp_decl_spec): Add addr_space support.
(struct cp_decl_specifier_seq): Likewise.
* decl.cc (get_type_quals): Likewise.
(check_tag_decl): Likewise.
(grokdeclarator): Likewise.
* parser.cc (cp_parser_type_specifier): Likewise.
(cp_parser_cv_qualifier_seq_opt): Likewise.
(cp_parser_postfix_expression): Likewise.
(cp_parser_type_specifier): Likewise.
(set_and_check_decl_spec_loc): Likewise.
* typeck.cc (composite_pointer_type): Likewise
(comp_ptr_ttypes_real): Likewise.
(same_type_ignoring_top_level_qualifiers_p): Likewise.
* pt.cc (check_cv_quals_for_unify): Likewise.
(unify): Likewise.
* tree.cc: Remove c_register_addr_space stub.
* mangle.cc (write_CV_qualifiers_for_type): Mangle address spaces
using the extended qualifier notation.
gcc/doc
* extend.texi (Named Address Spaces): add a mention about C++
support.
gcc/testsuite/
* g++.dg/abi/mangle-addr-space1.C: New test.
* g++.dg/abi/mangle-addr-space2.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/parse/template/spec-addr-space.C: New test.
* g++.dg/ext/addr-space-decl.C: New test.
* g++.dg/ext/addr-space-ref.C: New test.
* g++.dg/ext/addr-space-ops.C: New test.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sun Oct 9 16:02:22 2022 +0200
#
# On branch releases/gcc-12
# Your branch is ahead of 'origin/releases/gcc-12' by 2 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: gcc/c-family/c-common.cc
# modified: gcc/c-family/c-common.h
# modified: gcc/c/c-decl.cc
# modified: gcc/c/c-typeck.cc
# modified: gcc/cp/cp-tree.h
# modified: gcc/cp/decl.cc
# modified: gcc/cp/mangle.cc
# modified: gcc/cp/parser.cc
# modified: gcc/cp/pt.cc
# modified: gcc/cp/tree.cc
# modified: gcc/cp/typeck.cc
# modified: gcc/doc/extend.texi
# new file: gcc/testsuite/g++.dg/abi/mangle-addr-space1.C
# new file: gcc/testsuite/g++.dg/abi/mangle-addr-space2.C
# new file: gcc/testsuite/g++.dg/ext/addr-space-decl.C
# new file: gcc/testsuite/g++.dg/ext/addr-space-ops.C
# new file: gcc/testsuite/g++.dg/ext/addr-space-ref.C
# new file: gcc/testsuite/g++.dg/parse/addr-space.C
# new file: gcc/testsuite/g++.dg/parse/addr-space1.C
# new file: gcc/testsuite/g++.dg/parse/addr-space2.C
# new file: gcc/testsuite/g++.dg/template/spec-addr-space.C
# modified: gcc/tree.h
#
# Untracked files:
# Makefile
# addr-space-decl.C
# addr-space-decl.s
# addr-space-ops.C
# addr-space-ref.C
# addr-space-template.C
# addr-space-template.s
# addr-space-template2.C
# addr-space-template2.C.006t.gimple
# addr-space-template2.s
# addr-space-traits.C
# addr-space4.C
# addr-space4.C.006t.gimple
# addr-space4.s
# build-x86_64-pc-linux-gnu/
# compare
# host-x86_64-pc-linux-gnu/
# mangle-addr-space1.s
# prev-x86_64-pc-linux-gnu/
# rename
# stage1-x86_64-pc-linux-gnu/
# stage_current
# stage_final
# stage_last
# x86_64-pc-linux-gnu/
#
# ------------------------ >8 ------------------------
# Do not modify or remove the line above.
# Everything below it will be ignored.
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index bb0544eeaea..ff1146ecc25 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -615,6 +615,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
@@ -2809,6 +2836,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 52a85bfb783..d36f9e4975b 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 *);
@@ -952,6 +951,7 @@ extern void c_common_finish (void);
extern void c_common_parse_file (void);
extern FILE *get_dump_info (int, dump_flags_t *);
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 c701f07befe..e1bb4f1cf37 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -12337,25 +12337,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 b271af9bedb..c4b01368534 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -296,32 +296,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/cp-tree.h b/gcc/cp/cp-tree.h
index 72f4398a8f9..82a6d72f5df 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6206,6 +6206,7 @@ enum cp_decl_spec {
ds_const,
ds_volatile,
ds_restrict,
+ ds_addr_space,
ds_inline,
ds_virtual,
ds_explicit,
@@ -6252,6 +6253,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 9f78c500a15..fa5a1ddb21d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -5280,6 +5280,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;
}
@@ -5402,6 +5404,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 "
@@ -14572,6 +14578,57 @@ grokdeclarator (const cp_declarator *declarator,
if (!processing_template_decl)
cp_apply_type_quals_to_decl (type_quals, decl);
+ addr_space_t address_space = declspecs->address_space;
+ if (!ADDR_SPACE_GENERIC_P (address_space) && !INDIRECT_TYPE_P (type))
+ {
+ if (decl_context == NORMAL)
+ {
+ switch (storage_class)
+ {
+ case sc_auto:
+ error ("%qs combined with C++98 %<auto%> qualifier for %qs",
+ c_addr_space_name (address_space), name);
+ break;
+ case sc_register:
+ error ("%qs combined with %<register%> qualifier for %qs",
+ c_addr_space_name (address_space), name);
+ break;
+ case sc_none:
+ if (! toplevel_bindings_p ())
+ error ("%qs specified for auto variable %qs",
+ c_addr_space_name (address_space), name);
+ break;
+ case sc_mutable:
+ error ("%qs combined with %<mutable%> qualifier for %qs",
+ c_addr_space_name (address_space), name);
+ break;
+ case sc_static:
+ case sc_extern:
+ 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/mangle.cc b/gcc/cp/mangle.cc
index eb53e0ebeb4..16cb2ff4332 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -2509,6 +2509,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 763df6f479b..f0169d83ab0 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -7640,6 +7640,14 @@ 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,
@@ -19408,6 +19416,15 @@ 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)
{
@@ -23776,6 +23793,7 @@ cp_parser_ptr_operator (cp_parser* parser,
GNU Extension:
cv-qualifier:
+ address-space-qualifier
__restrict__
Returns a bitmask representing the cv-qualifiers. */
@@ -23812,6 +23830,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;
@@ -32705,6 +32728,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
{
@@ -32737,6 +32762,25 @@ 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,
+ "conflicting named address spaces (%s vs %s)",
+ 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 %s",
+ 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 bef31416fb7..c9d1c01f4ce 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -23655,8 +23655,19 @@ 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 (!(as_parm == as_common || as_parm == 0))
+ return 0;
if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM
&& !(strict & UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
@@ -24292,10 +24303,26 @@ 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 space constraints it can
+ fully match the address space of ARG. However, if PARM contains an
+ address space constraint, 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_real
- (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_real (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 3b37567cbd7..5e14ac837fc 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -6048,15 +6048,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 ceb80d9744f..7d810c6a12c 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -656,10 +656,26 @@ composite_pointer_type (const op_location_t &location,
else
return error_mark_node;
}
+ /* If possible merge the address space into the superset of the address
+ spaces of t1 and t2, or raise an error. */
+ 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);
+ }
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 (cp_type_quals
(TREE_TYPE (t1)))
+ | CLEAR_QUAL_ADDR_SPACE (cp_type_quals
(TREE_TYPE (t2)))
+ | ENCODE_QUAL_ADDR_SPACE (as_common)));
result_type = build_pointer_type (result_type);
/* Merge the attributes. */
attributes = (*targetm.merge_type_attributes) (t1, t2);
@@ -1579,7 +1595,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)
@@ -1589,6 +1607,14 @@ same_type_ignoring_top_level_qualifiers_p (tree type1,
tree type2)
if (type1 == type2)
return true;
+ addr_space_t as_type1 = TYPE_ADDR_SPACE (type1);
+ addr_space_t as_type2 = TYPE_ADDR_SPACE (type2);
+ addr_space_t as_common;
+
+ /* Fail if pointers point to incompatible address spaces. */
+ if (!addr_space_superset (as_type1, as_type2, &as_common))
+ return false;
+
type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED);
type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED);
return same_type_p (type1, type2);
@@ -6374,10 +6400,32 @@ 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;
+
+ /* 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);
+ }
+
if (!complete_type_or_maybe_complain (target_type, NULL_TREE, complain))
return error_mark_node;
@@ -10805,6 +10853,19 @@ 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))
+ return false;
+ }
+
if (constp > 0)
constp &= TYPE_READONLY (to);
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index ac3db88566d..1e0d436c02c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -1448,7 +1448,7 @@ Fixed-point types are supported by the DWARF debug
information format.
@section Named Address Spaces
@cindex 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/testsuite/g++.dg/abi/mangle-addr-space1.C
b/gcc/testsuite/g++.dg/abi/mangle-addr-space1.C
new file mode 100644
index 00000000000..c01f8d6054a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-addr-space1.C
@@ -0,0 +1,10 @@
+// { dg-do run { target { i?86-*-* x86_64-*-* } } }
+// { dg-options "-fabi-version=8 -Wabi -save-temps" }
+// { 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..862bbbdcdf2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-addr-space2.C
@@ -0,0 +1,9 @@
+// { dg-do run { 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..c04d2f497da
--- /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 /* give internal linkage to the following anonymous struct */
+__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..86c02d1e7f5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/addr-space-ops.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target { i?86-*-* x86_64-*-* } } }
+int __seg_fs * fs1;
+int __seg_fs * fs2;
+float __seg_gs * gs1;
+float __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 "invalid operands of types .__seg_fs int.. and .__seg_gs
float.. to binary .operator.." }
+ fs1 == fs2;
+ fs1 != gs2; // { dg-error "comparison between distinct pointer types .__seg_fs
int.. and .__seg_gs float.. lacks a cast" }
+ fs1 = fs2;
+ fs1 = gs2; // { dg-error "cannot convert .__seg_gs float.. to .__seg_fs int.. in
assignment" }
+ fs1 > fs2;
+ fs1 < gs2; // { dg-error "comparison between distinct pointer types .__seg_fs
int.. and .__seg_gs float.. lacks a cast" }
+ 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..12d7975e560
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/addr-space-ref.C
@@ -0,0 +1,31 @@
+// { 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." }
+};
+
+int register __seg_fs reg_fs; // { dg-error ".__seg_fs. combined with .register.
qualifier for .reg_fs." }
+
+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. combined with .register.
qualifier for .reg_gs." }
+ static __seg_gs int static_gs;
+ __seg_fs int auto_fs; // { dg-error ".__seg_fs. specified for auto variable
.auto_fs." }
+ __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..5b2c0f28078
--- /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 "conflicting named address spaces .__seg_fs
vs __seg_gs." }
+
+int
+main ()
+{
+ return 0;
+}
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 8844471e9a5..b7da4c5141a 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2229,7 +2229,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. */