From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 112DD385702E for ; Wed, 26 Oct 2022 16:28:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 112DD385702E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1666801724; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qZ3IQ56Ui22yCIszKf9hH/WEWy7mVv/DccMNcEYgihE=; b=UzkYajStUc3H1uuWbgTVV/iK6YscD7xidTxIeBr4qSFpd4EZv1g8SK/8oSRzUcb8laBNTB KdjILe0g/axldKZ5Q9NNxJFXaMG6+J124BvWICcgBdhOY4yqW59u0yj60u9RhUwAvih7Z+ SSwnyT9oVeDsK5lAGpBZJjb3+XB6BpE= Received: from mail-qk1-f199.google.com (mail-qk1-f199.google.com [209.85.222.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-124-JBmmneOcM4eFMDGlH5weCQ-1; Wed, 26 Oct 2022 12:28:43 -0400 X-MC-Unique: JBmmneOcM4eFMDGlH5weCQ-1 Received: by mail-qk1-f199.google.com with SMTP id bk21-20020a05620a1a1500b006be9f844c59so14383196qkb.9 for ; Wed, 26 Oct 2022 09:28:43 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=qZ3IQ56Ui22yCIszKf9hH/WEWy7mVv/DccMNcEYgihE=; b=B+pi7FMlIjm4QAJC84nNNSRU4wHNjOGsOp3vrONFd+0VM0NB69cfKZ3o0dwRyEQGOl VS5QKAPmBGf3ZFd1Bw0ZKI3YubR1VkyCbCOPPJrQouSLTLxpNwgqGptuUtv4YtFNPeXP QaR7AcZUdeylGhWG8XsUIbb8cBUMUxgc9HrHBNreABKK2hSzDN1HbdQl6NHCPfFTm+k0 3Rao0xaLzk4zgoEr+uxH14ad0hZ6cEQGJ581RdZCYfQK8TsdKmqRRkmdBAWHRAlmejcz sQNjMBRJkp5xtG61H/4iBIUj3CZSSMU0XGS1Zg89HQI0eP53NAyit6S4KavGO4sKUrlu IIow== X-Gm-Message-State: ACrzQf0L3PauWk3JrDE/LNCW6idZkbfXX4xw/fhb+2aBLYXwdhIIis8b jZ+WCL2BiUHRd/1Vr/SxP/jOgNogt4Tjvf4s+rPRxCO/8aFv53EOWvO1XbEDcJXoMKS4yYrYZFS 1XY6y6EwUkfD19HYiug== X-Received: by 2002:a05:620a:2409:b0:6ec:5325:340c with SMTP id d9-20020a05620a240900b006ec5325340cmr31306223qkn.300.1666801721807; Wed, 26 Oct 2022 09:28:41 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7S81Bex0tC3Al0kEJYciOxfXGHnZ/lJ2ghZUilvhDHcv+pqHwx3VXVV7Jh2tHdimmPrMg6QA== X-Received: by 2002:a05:620a:2409:b0:6ec:5325:340c with SMTP id d9-20020a05620a240900b006ec5325340cmr31306163qkn.300.1666801720774; Wed, 26 Oct 2022 09:28:40 -0700 (PDT) Received: from [192.168.1.101] (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id a1-20020a05620a438100b006cea2984c9bsm4128484qkp.100.2022.10.26.09.28.39 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 26 Oct 2022 09:28:40 -0700 (PDT) Message-ID: Date: Wed, 26 Oct 2022 12:28:33 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.0 Subject: Re: [PATCH v3] c++: parser - Support for target address spaces in C++ To: Paul Iannetta Cc: gcc-patches@gcc.gnu.org References: <20221013152341.bztoqunwtmhdzi3f@ws2202.lin.mbt.kalray.eu> <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> From: Jason Merrill In-Reply-To: <20221026071837.l3de5hkxujvqqztr@ws2202.lin.mbt.kalray.eu> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_ASCII_DIVIDERS,KAM_SHORT,NICE_REPLY_A,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,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 10/26/22 03:18, Paul Iannetta wrote: > On Wed, Oct 19, 2022 at 02:55:21PM -0400, Jason Merrill wrote: >> On 10/18/22 13:01, Paul Iannetta wrote: >>> Thank you very much for the detailed review. >>> >>> On Tue, Oct 18, 2022 at 10:24:23AM -0400, Jason Merrill wrote: >>>> On 10/18/22 03:37, Paul Iannetta wrote: >>>>> On Fri, Oct 14, 2022 at 11:19:50AM -0400, Jason Merrill wrote: >>>>>> On 10/13/22 17:57, Paul Iannetta wrote: >>>>>>> On Thu, Oct 13, 2022 at 03:41:16PM -0400, Jason Merrill wrote: >>>>>>>> On 10/13/22 12:02, Paul Iannetta wrote: >>>>>>>>> On Thu, Oct 13, 2022 at 11:47:42AM -0400, Jason Merrill wrote: >>>>>>>>>> On 10/13/22 11:23, Paul Iannetta wrote: >>>>>>>>>>> On Thu, Oct 13, 2022 at 11:02:24AM -0400, Jason Merrill wrote: >>>>>>>>>>>> On 10/12/22 20:52, Paul Iannetta wrote: >>>>>>>>>>>>> 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. >>>>>>>>>>>> >>>>>>>>>>>> At that point you have the decl, and you can ask directly what its storage >>>>>>>>>>>> duration is, perhaps using decl_storage_duration. >>>>>>>>>>>> >>>>>>>>>>>> But why do you need to know whether the type is a pointer? The attribute >>>>>>>>>>>> applies to the target type of the pointer, not the pointer type. I think >>>>>>>>>>>> the problem is that you're looking at declspecs when you ought to be looking >>>>>>>>>>>> at type_quals. >>>>>>>>>>> >>>>>>>>>>> I need to know that the base type is a pointer to reject invalid >>>>>>>>>>> declarations such as: >>>>>>>>>>> >>>>>>>>>>> int f (__seg_fs int a) { } or int f () { __seg_fs int a; } >>>>>>>>>>> >>>>>>>>>>> because parameters and auto variables can have an address space >>>>>>>>>>> qualifier only if they are pointer or reference type, which I can't >>>>>>>>>>> tell only from type_quals. >>>>>>>>>> >>>>>>>>>> But "int *__seg_fs a" is just as invalid as the above; the difference is not >>>>>>>>>> whether a is a pointer, but whether the address-space-qualified is the type >>>>>>>>>> of a itself or some sub-type. >>>>>>>>> >>>>>>>>> I agree that "int * __seg_fs a" is invalid but it is accepted by the C >>>>>>>>> front-end, and by clang (both C and C++), the behavior is that the >>>>>>>>> address-name is silently ignored. >>>>>>>> >>>>>>>> Hmm, that sounds like a bug; in that case, presumably the user meant to >>>>>>>> qualify the pointed-to type, and silently ignoring seems unlikely to give >>>>>>>> the effect they want. >>>>>>>> >>>>>>> >>>>>>> Well, actually, I'm re-reading the draft and "int * __seg_fs a" is >>>>>>> valid. It means "pointer in address space __seg_fs pointing to an >>>>>>> object in the generic address space", whereas "__seg_fs int * a" means >>>>>>> "pointer in the generic address space pointing to an object in the >>>>>>> __seg_fs address-space". >>>>>>> >>>>>>> Oddities such as, "__seg_fs int * __seg_gs a" are also perfectly >>>>>>> valid. >>>>>> >>>>>> If a has static storage duration, sure; I was still thinking about >>>>>> declarations with automatic storage duration such as in your example above. >>>>>> >>>>> >>>>> Thanks, I only use type_quals now. I also took into account the style >>>>> recommendations from Jakub, and included the other template tests. >>>>> I rebased over trunk, bootstrapped the compiler and run the "make >>>>> check-gcc" with no regressions on x86. >>>>> >>>>> Paul >>>>> >>>>> # ------------------------ >8 ------------------------ >>>>> 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. >>>>> * 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. >>>>> >>>>> # ------------------------ >8 ------------------------ >>>>> diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc >>>>> index 9ec9100cc90..3b79dc47515 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 >>>>> @@ -2785,6 +2812,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 62ab4ba437b..a3864d874aa 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 a7571cc7542..b1f69997ff7 100644 >>>>> --- a/gcc/c/c-decl.cc >>>>> +++ b/gcc/c/c-decl.cc >>>>> @@ -12531,25 +12531,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 fdb96c28c51..2a700bbaff3 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/cp-tree.h b/gcc/cp/cp-tree.h >>>>> index e2607f09c19..0248569a95b 100644 >>>>> --- a/gcc/cp/cp-tree.h >>>>> +++ b/gcc/cp/cp-tree.h >>>>> @@ -6235,6 +6235,7 @@ enum cp_decl_spec { >>>>> ds_const, >>>>> ds_volatile, >>>>> ds_restrict, >>>>> + ds_addr_space, >>>>> ds_inline, >>>>> ds_virtual, >>>>> ds_explicit, >>>>> @@ -6281,6 +6282,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 85b892cddf0..a87fed04529 100644 >>>>> --- a/gcc/cp/decl.cc >>>>> +++ b/gcc/cp/decl.cc >>>>> @@ -5290,6 +5290,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; >>>>> } >>>>> @@ -5412,6 +5414,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 " >>>>> @@ -14608,6 +14614,59 @@ 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 (decl_context == NORMAL) >>>>> + { >>>>> + switch (storage_class) >>>> >>>> I would still suggest checking decl_storage_duration at this point rather >>>> than the storage_class specifier. >>> >>> Unless I misunderstand something, I can't weed out register variables >>> if I rely on decl_storage_duration. >> >> Yes, but register variables are automatic, so they'll get that error; I >> don't think they need their own specific error. >> > Noted. >>>>> + { >>>>> + 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", >>>> >>>> And let's refer to automatic storage duration rather than shorten to 'auto'. >>>> >>> Right. >>>>> + 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 1215463089b..aafff98f05a 100644 >>>>> --- a/gcc/cp/mangle.cc >>>>> +++ b/gcc/cp/mangle.cc >>>>> @@ -2520,6 +2520,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 9ddfb027ff9..c82059d1efd 100644 >>>>> --- a/gcc/cp/parser.cc >>>>> +++ b/gcc/cp/parser.cc >>>>> @@ -7703,6 +7703,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, >>>>> @@ -19445,6 +19454,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; >>>>> + } >>>>> + >>>>> + >>>> >>>> I don't think we need two blank lines before and after this block, one each >>>> should be enough. >>>> >>> Indeed. >>>>> /* Handle simple keywords. */ >>>>> if (ds != ds_last) >>>>> { >>>>> @@ -23837,6 +23855,7 @@ cp_parser_ptr_operator (cp_parser* parser, >>>>> GNU Extension: >>>>> cv-qualifier: >>>>> + address-space-qualifier >>>>> __restrict__ >>>>> Returns a bitmask representing the cv-qualifiers. */ >>>>> @@ -23873,6 +23892,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; >>>>> @@ -32893,6 +32917,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 >>>>> { >>>>> @@ -32925,6 +32951,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 e4dca9d4f9d..7b73a57091e 100644 >>>>> --- a/gcc/cp/pt.cc >>>>> +++ b/gcc/cp/pt.cc >>>>> @@ -23778,8 +23778,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; >>>> >>>> I'd expect address space qualifiers to follow the 'strict' parameter like >>>> the other qualifiers; the above test seems to assume >>>> UNIFY_ALLOW_{OUTER_,}LESS_CV_QUAL. >>>> >>> The reason I ignored strict was to enforce that the deduced address >>> space is always at most "as_parm" unless "as_parm" is the generic address >>> space, and prevent unifying if the two address spaces are disjoint >>> unless "parm" does not have any address space constraints; and avoid the >>> addition/deletion of an address space to "arg" during the unifying >>> process. >>> >>> Since I don't really understand the whole picture behind strict, and when >>> check_cv_quals_for_unify gets called with which variant of restrict it >>> might be me who tried to be overcareful when unifying the address >>> spaces. >> >> How we need to handle differing qualifiers varies between different template >> argument deduction contexts. >> >> The code you wrote above is correct for the function call context, since >> https://eel.is/c++draft/temp.deduct.call#4.2 says the deduced type can be >> convertable by qualification conversion, i.e. parm more qualified than arg >> (and my "LESS" above was backwards). This is a bit different for address >> space qualifiers given that the qualification conversion would be removing >> the address space qualifier or changing it to a more general one, but the >> principle is the same. >> >> But the allowance for qualifier changes doesn't apply to all deduction >> contexts: for instance, >> >> template void f(T * const *); >> struct A { >> template operator T**(); >> }; >> int main() >> { >> f((void**)0); // void** -> void*const* is a valid qualification conv >> (void *const*)A(); // same conversion >> void (*p)(void **) = f; // error, type mismatch >> } >> >> so similarly, >> >> template void f(T **); >> struct A { >> template operator T*__seg_fs*(); >> }; >> int main() >> { >> f((void* __seg_fs *)0); // void*__seg_fs* -> void** should be OK >> void (*p)(void * __seg_fs *) = f; // error >> } >> >> > I do not completely agree here. Currently, my implementation rejects > all deductions which would change or remove an address space no matter > the context, which is very conservative. > > I tried using "strict" as the other qualifiers do, and as I expected, > it keeps rejecting > f((void* __seg_fs *)0); // void*__seg_fs* -> void** should be OK > which is to be expected, since a pointer can't jump from an address > space to another unless there is a common superset and here __seg_fs > is disjoint from the generic address space. Aha, I was thinking that the generic address space was a superset. > I don't really understand what is done in > (void **)A(); // same conversion > but it is similarly rejected (implicit conversion from A to (void**)) > > The third one is strangely accepted, and clang accept is as well (only > the address space variant, the one with const is duly rejected). > I will investigate what clang does here, as I think it would be better > if the behavior of clang and gcc concerning this feature matches as > much as possible from a user standpoint, since the C++ side of this > feature is, to my knowledge, completely undocumented. I assume this is a bug in clang as well. >>>>> if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM >>>>> && !(strict & UNIFY_ALLOW_OUTER_MORE_CV_QUAL)) >>>>> @@ -24415,10 +24426,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; >>>> >>>> Hmm, I'd think we also want as_common = as_arg when it's a subset of >>>> as_parm. >>> >>> Let's assume that "PARM" is "__as1 T", and since the call to >>> check_cv_quals_for_unify succeeded we know that "as_common" is >>> "__as1". That is ARG is of the form "__as2 U" with "__as2" a >>> subset of "__as1", hence we are trying to unify >>> __as1 T = __as1 U >>> which does not give any constraints over PARM since it alreay contains >>> the common address space, hence there is no more constraints on T and >>> as_common = 0. >> >> Agreed. >> >>> However, if PARM's address space is 0, we are trying to unify >>> T = __as1 U >>> and we need to add __addr_space1 to the constraints of T. >> >> Agreed. >> >>> If as_parm is not the generic address space (ie, as_parm != 0) >> >> Looks like this comment got cut off? This is the case I was talking about. >> When we are trying to unify >> >> __as1 T = __as2 U >> >> and __as2 is a subset of __as1, I think we want T to be deduced to __as2 U, >> and then substitution will need to handle substituting __as2 U for T into >> __as1 T to get __as2 U. >> > > I more or less agree, but I think that the substitution will need to > handle substituting __as2 U for T into __as1 T to get __as1 U. > (Leading to __as1 U and not __as2 U, since __as1 is the biggest > address space and the templated function expect __as1 T). After substitution, I would think we want to end up with the smaller address space; in general, we want the more specialized form. > Nevertheless, this means that when fully deduced __as1 T becomes __as1 > __as2 U and then the substitution mechanism would make it into __as1 > U. Could you please tell me where the substitution mechanism takes > place so that I can account for this case and that if we end up with > two compatible address spaces the biggest is selected? I think it would be best to handle it in cp_build_qualified_type. >>>>> /* 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 45348c58bb6..1f330ca93ed 100644 >>>>> --- a/gcc/cp/tree.cc >>>>> +++ b/gcc/cp/tree.cc >>>>> @@ -6072,15 +6072,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 da0e1427b97..93cfdc70e2d 100644 >>>>> --- a/gcc/cp/typeck.cc >>>>> +++ b/gcc/cp/typeck.cc >>>>> @@ -803,10 +803,28 @@ 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); >>>> >>>> Why not return error_mark_node here? >>>> >>> That's a mistake. Thanks. >>>>> + } >>>>> + 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 +1749,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) >>>>> @@ -1741,6 +1761,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; >>>> >>>> Why do you need this change? I'd expect this function to ignore top level >>>> address space qualifiers like the other qualifiers. >>> >>> I am mirroring the C front-end here, which does the same thing in >>> "comp_target_types" (gcc/c/c-typeck.cc), which ignores qualifiers but >>> not address spaces when checking if two pointer types are equivalent. >> >> This function serves a very different function from comp_target_types, which >> deals with the types that pointers point to; this function is ignoring >> top-level qualifiers that should not affect the type. >> >> ...except now I see that cp_build_binary_op is wierdly using this function >> for pointer subtraction. I'd think it should use composite_pointer_type >> instead, like EQ_EXPR does. > > I think this is because of https://eel.is/c++draft/expr.add#2.2 and I > am not sure that composite_pointer_type can replace it here since it > does try to merge the two list of qualifiers. Ah, good point. So I guess it does make sense for it to use same_type_ignoring_top_level_qualifiers_p there, but the other callers of that function don't want this address space check; it should be enough to do it only in pointer_diff. >>>>> type1 = cp_build_qualified_type (type1, TYPE_UNQUALIFIED); >>>>> type2 = cp_build_qualified_type (type2, TYPE_UNQUALIFIED); >>>>> return same_type_p (type1, type2); >>>>> @@ -6672,10 +6700,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); >>>>> + } >>>> >>>> I think you shouldn't need to change pointer_diff if composite_pointer_type >>>> returns error_mark_node above. >>> >>> I'll have a look, the idea here is to prevent "a - b" with "a" and "b" >>> from different address spaces. >> >> As above, I think this should have been handled in cp_build_binary_op. > > I don't really understand why you don't want the address space > conversion (which might be needed for subtraction) to happen at the same > time as the conversion to the "common_pointer_type". Agreed, except you'll want a diagnostic here now. >>>>> if (!complete_type_or_maybe_complain (target_type, NULL_TREE, complain)) >>>>> return error_mark_node; >>>>> @@ -11286,6 +11336,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; >>>> >>>> I think you also want to check that as_common == as_to here? >>>> >>> Yes. >>>>> + } >>>>> + >>>>> if (constp > 0) >>>>> constp &= TYPE_READONLY (to); >>>>> } >>>>> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi >>>>> index cfbe32afce9..ef75f6b83a2 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-*-* } } } >>>> >>>> This can be dg-do compile, I don't think you get anything from running an >>>> empty main. >>>> >>> Yes. >>>>> +// { dg-options "-fabi-version=8 -Wabi -save-temps" } >>>> >>>> And then you don't need -save-temps. What are the other options for? >>>> >>> I forgot to remove -Wabi and -fabi-version, this was from my first >>> attempt when I used AS to mangle which changed the ABI. I'll >>> remove them. >>>>> +// { 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" } >>>> >>>> Also not clear that running is important for this test. >>>> >>> Noted. >>>>> +// { 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 */ >>>> >>>> Hmm, this 'static' gives internal linkage to the variable q, not the type. >>>> What do you want it for? >>>> >>> Yes, the idea is to give internal linkage to q, otherwise g++ >>> complains in -std=c++98 mode because q is externally visible but it >>> can't be reffered from anywhere else since there is no tag for this >>> structure. >> >> Then let's change the comment to /* give internal linkage to q */ > Agreed. >> >>>>> +__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/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..5df115db939 >>>>> --- /dev/null >>>>> +++ b/gcc/testsuite/g++.dg/template/addr-space-strip1.C >>>>> @@ -0,0 +1,17 @@ >>>>> +// { dg-do compile { target { i?86-*-* x86_64-*-* } } } >>>>> +// { dg-skip-if "" { *-*-* } { "-std=c++98" "-std=c++03" "-std=gnu++98" "-std=gnu++03" } { "" } } >>>> >>>> This can be { dg-require-effective-target c++11 } >> >> Or put the x86 requirement in dg-require-effective-target, and put c++11 in >> the dg-do target spec, either way. > Agreed. >> >>>>> +// decltype is ony available since c++11 >>>> >>>> "only" >>>> >>>>> + >>>>> +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; >>>>> +} >>>>> 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..526bbaa56b7 >>>>> --- /dev/null >>>>> +++ b/gcc/testsuite/g++.dg/template/addr-space-strip2.C >>>>> @@ -0,0 +1,16 @@ >>>>> +// { 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; >>>>> +} >>>>> + >>>>> +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 9af971cf401..4aebfef854b 100644 >>>>> --- a/gcc/tree.h >>>>> +++ b/gcc/tree.h >>>>> @@ -2292,7 +2292,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. */ > > > >