From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from fx303.security-mail.net (mxout.security-mail.net [85.31.212.46]) by sourceware.org (Postfix) with ESMTPS id A397038AA241 for ; Thu, 13 Oct 2022 00:53:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A397038AA241 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 (fx303.security-mail.net [127.0.0.1]) by fx303.security-mail.net (Postfix) with ESMTP id 1736B30EDD0 for ; Thu, 13 Oct 2022 02:53:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kalrayinc.com; s=sec-sig-email; t=1665622382; bh=0eQW/vW4keJ7DkyYaf2PKuKuLQcRAFh0Atpj2S/GsI0=; h=Date:From:To:Cc:Subject:References:In-Reply-To; b=OdVlCZyFMYYTy6fv3SfyDV292MTHn1jsh1L0UjO2HVORH/WVMbTWvp9x1Vn5YgBFr rYDqjQsc9hbc2Chz4BnjAAZ/tOQkI50hvWRHET6p6olm7CXO63ApaZqs51Od87zBb8 +Llmvva7cg9V3DXUajh7IAP3botZ3y/om+tGP484= Received: from fx303 (fx303.security-mail.net [127.0.0.1]) by fx303.security-mail.net (Postfix) with ESMTP id BC32D30EDCB; Thu, 13 Oct 2022 02:53:01 +0200 (CEST) Received: from zimbra2.kalray.eu (unknown [217.181.231.53]) by fx303.security-mail.net (Postfix) with ESMTPS id C659330EDB6; Thu, 13 Oct 2022 02:53:00 +0200 (CEST) Received: from zimbra2.kalray.eu (localhost [127.0.0.1]) by zimbra2.kalray.eu (Postfix) with ESMTPS id 91E8C27E0454; Thu, 13 Oct 2022 02:53:00 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by zimbra2.kalray.eu (Postfix) with ESMTP id 74BCA27E045F; Thu, 13 Oct 2022 02:53:00 +0200 (CEST) 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 zOUVTg4MtHms; Thu, 13 Oct 2022 02:53:00 +0200 (CEST) Received: from localhost (unknown [192.168.37.51]) by zimbra2.kalray.eu (Postfix) with ESMTPSA id 5347127E0454; Thu, 13 Oct 2022 02:53:00 +0200 (CEST) X-Virus-Scanned: E-securemail Secumail-id: <2097.6347616c.c0c12.0> DKIM-Filter: OpenDKIM Filter v2.10.3 zimbra2.kalray.eu 74BCA27E045F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kalrayinc.com; s=4F334102-7B72-11EB-A74E-42D0B9747555; t=1665622380; bh=OppD5fQVsg7dzpjK/f3gw2iRK7amKpUlyBN4WZb8iqQ=; h=Date:From:To:Message-ID:MIME-Version; b=H3tpVrYmYN+kT+99O/Pc4dVXyzuq8zlUdhGyv8TXZTr2CjmfJlIY5KLFd81qmGN2F VanfLfLKk/TWA/OaWSHhKqecZNiAFqrBvNRV569b3xuvc5HqxeyKtFtZdHSMKopifj 7fDgfN4Zc9SkYEXDYRxCrQRV40Wfza/TbCxdtUDiecWB+U+Fo72LmxwjY8jz+4jBOv 3EMIhX99xwg08sYuBA+A7A/s96NRrvWQPqHAPCMUBbUyn+WmeCvBvOPF+bJ2tTMDhH GHjf50Fcr4C3fD1onp7WTCjHAziLAtEc9wyaB+J8VLQ4+85w0z4/A+xWGqrCuofkiv G4DeccNqc1oSA== Date: Thu, 13 Oct 2022 02:52:59 +0200 From: Paul Iannetta To: Jason Merrill Cc: gcc-patches@gcc.gnu.org Subject: Re: [PATCH v2] c++: parser - Support for target address spaces in C++ Message-ID: <20221013005158.mfahyohzbywlyl7i@ws2202.lin.mbt.kalray.eu> References: <20221006143400.es3u6ebqt3xkw6jp@ws2202.lin.mbt.kalray.eu> <697f23be-7318-1c87-5625-2411b1ab18a3@redhat.com> <20221009161256.p63tnxsqzwcnvh5h@ws2202.lin.mbt.kalray.eu> <20221011220017.pvs5jawrzqoaqkkf@ws2202.lin.mbt.kalray.eu> <19526772-3afb-87d1-190a-5ab0ffb566a9@redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <19526772-3afb-87d1-190a-5ab0ffb566a9@redhat.com> User-Agent: NeoMutt/20171215 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-ALTERMIMEV2_out: done X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,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: On Tue, Oct 11, 2022 at 09:49:43PM -0400, Jason Merrill wrote: > > It surprises that this is the only place we complain about an object with an > address-space qualifier. Shouldn't we also complain about e.g. automatic > variables/parameters or non-static data members with address-space qualified > type? > Indeed, I was missing quite a few things here. Thanks. I used the draft as basis this time and imported from the C implementation the relevant parts. This time, the errors get properly emitted when an address space is unduly specified; and comparisons, assignments and comparisons are taken care of. There are quite a few things I would like to clarify concerning some implementation details. - A variable with automatic storage (which is neither a pointer nor a reference) cannot be qualified with an address space. I detect this by the combination of `sc_none' and `! toplevel_bindings_p ()', but I've also seen the use of `at_function_scope' at other places. And I'm unsure which one is appropriate here. This detection happens at the very end of grokdeclarator because I need to know that the type is a pointer, which is not know until very late in the function. - I'm having some trouble deciding whether I include those three stub programs as tests, they all compile fine and clang accepts them as well. Ex1: ``` 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; return 0; } ``` Ex2: ``` int __seg_fs * fs1; int __seg_fs * fs2; template auto f (T __seg_fs * a, U __seg_gs * b) { return a; } template 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 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 % qualifier for %qs", + c_addr_space_name (address_space), name); + break; + case sc_register: + error ("%qs combined with % 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 % 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 +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 + 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 +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 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. */