From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from fx308.security-mail.net (smtpout30.security-mail.net [85.31.212.38]) by sourceware.org (Postfix) with ESMTPS id 5DC3A3858D38 for ; Thu, 10 Nov 2022 15:42:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5DC3A3858D38 Authentication-Results: sourceware.org; dmarc=fail (p=quarantine dis=none) header.from=kalrayinc.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=kalray.eu Received: from localhost (localhost [127.0.0.1]) by fx308.security-mail.net (Postfix) with ESMTP id 37FD15CABB5 for ; Thu, 10 Nov 2022 16:42:37 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kalrayinc.com; s=sec-sig-email; t=1668094957; bh=/en25gwiuQ3ovyRDONar0XW4/Yznadrkl0mebr6CV3I=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=l6R3riu9UHkxvXEVbDmmg2/zlWk666lnSV1pJ9pjLk/4SXt0I3UniPvSYqP77U2CY ym1E7pp33tvYjtQmFcER7B3oImpT98iWaHs9L0qEOeZz7e+aOo6avtRQSZrce/loQ2 9YU5IJ16mm1UrUz8h1JaFFu/ZkaYrJc5vMLHk798= Received: from fx308 (localhost [127.0.0.1]) by fx308.security-mail.net (Postfix) with ESMTP id 22D1B5CB181; Thu, 10 Nov 2022 16:42:37 +0100 (CET) Received: from zimbra2.kalray.eu (unknown [217.181.231.53]) by fx308.security-mail.net (Postfix) with ESMTPS id A51715CA469; Thu, 10 Nov 2022 16:42:36 +0100 (CET) Received: from zimbra2.kalray.eu (localhost [127.0.0.1]) by zimbra2.kalray.eu (Postfix) with ESMTPS id 826E427E031D; Thu, 10 Nov 2022 16:42:36 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by zimbra2.kalray.eu (Postfix) with ESMTP id 6899927E031F; Thu, 10 Nov 2022 16:42:36 +0100 (CET) Received: from zimbra2.kalray.eu ([127.0.0.1]) by localhost (zimbra2.kalray.eu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id hwnM_AHHjxt7; Thu, 10 Nov 2022 16:42:36 +0100 (CET) Received: from localhost (unknown [192.168.37.51]) by zimbra2.kalray.eu (Postfix) with ESMTPSA id 4919C27E031D; Thu, 10 Nov 2022 16:42:36 +0100 (CET) X-Virus-Scanned: E-securemail Secumail-id: <13737.636d1bec.a450e.0> DKIM-Filter: OpenDKIM Filter v2.10.3 zimbra2.kalray.eu 6899927E031F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kalrayinc.com; s=4F334102-7B72-11EB-A74E-42D0B9747555; t=1668094956; bh=Ril1j7Rediy3A2G6dt/PqIZk2+FRUvd9JSbUUAuSTI8=; h=Date:From:To:Message-ID:MIME-Version; b=Nt3JoG2GSrWbQsVkZEn89kN+rkv1evy43TwXrgBfhsv0ixrLZ758fDmTB3Jnq9Gy/ GtO9h4vzPp7Mb03wLo1//qv/6LA8sIWXGSDYwRuwBNil0vMHk/RNUzKUjx+Th2zFEL UFx6K1FZMn8rm/N15a6jHugTouPD/8chbp06QbR9MG4AzCBBZcoCBl31Sv0MV5xSyv i1lIyB0o3PcpyyDoY2e8TNWqJZXs2wjAC72szzj3zJFVf6mwiHiU9PUTDsau8JBZPe 9xqIr1YPPUDeA0ETXXH8BMPpnDvxbbkoxI9UOthoBUaWYs0ySNs+AxuSN8dMp0Khev L1kJrF0m3QD1Q== Date: Thu, 10 Nov 2022 16:42:22 +0100 From: Paul Iannetta To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH v4] c++: parser - Support for target address spaces in C++ Message-ID: <20221110154222.twnrydaj3zhig3tj@ws2202.lin.mbt.kalray.eu> References: <20221013160227.sdlv6yaw5gr4zcvd@ws2202.lin.mbt.kalray.eu> <20221013215643.o2bymrmffwbtuppu@ws2202.lin.mbt.kalray.eu> <4026cae9-e371-a2ee-2b36-7abc9224afa1@redhat.com> <20221018073731.wj2expjfmk5uhmp3@ws2202.lin.mbt.kalray.eu> <07d4c9ba-594a-d3f8-3df3-5ef5d18a6e97@redhat.com> <20221018170135.zpkmyebmpcvqx7ky@ws2202.lin.mbt.kalray.eu> <20221026071837.l3de5hkxujvqqztr@ws2202.lin.mbt.kalray.eu> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: User-Agent: NeoMutt/20171215 Content-Transfer-Encoding: 8bit X-ALTERMIMEV2_out: done X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,KAM_ASCII_DIVIDERS,RCVD_IN_DNSWL_LOW,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: 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 void f(T **); struct A { template 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 * 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 * 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 * 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 * 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 * 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 +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 + 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 +__seg_fs T* f (T __seg_fs * a, U __seg_gs * b) { return a; } +template +__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 struct strip; +template struct strip<__seg_fs T *> { typedef T type; }; +template struct strip<__seg_gs T *> { typedef T type; }; + +int +main () +{ + *(strip::type *) fs1 == *(strip::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 +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 +int f (T __seg_gs *p) { return *p; } // { dg-note "candidate: 'template 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. */