From patchwork Mon Feb 10 11:09:41 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Simon Martin X-Patchwork-Id: 106246 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0254E385842C for ; Mon, 10 Feb 2025 11:11:16 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0254E385842C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=nasilyan.com header.i=@nasilyan.com header.a=rsa-sha256 header.s=tey23rxsjton5kop5bydp3vc5ylkyjkg header.b=eho6zKFp; dkim=pass (1024-bit key, unprotected) header.d=amazonses.com header.i=@amazonses.com header.a=rsa-sha256 header.s=uku4taia5b5tsbglxyj6zym32efj7xqv header.b=BRyTuS+x X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from a3-40.smtp-out.eu-west-1.amazonses.com (a3-40.smtp-out.eu-west-1.amazonses.com [54.240.3.40]) by sourceware.org (Postfix) with ESMTPS id E10983858CDA for ; Mon, 10 Feb 2025 11:09:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E10983858CDA Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=nasilyan.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=eu-west-1.amazonses.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E10983858CDA Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=54.240.3.40 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1739185784; cv=none; b=rEDkqJNnl3hfJR+V83M1EWlgn3akobL9hqxx1zXRfFHuvUexLFdZ8h30n9lhLUjF2Su96v+jkslDgTpXs48WNBfVKK0jH1ncYbzZoiedBCzq773PWMDWN/28jj/iy9+290u+LpatQUBMtGdf2HK8sRYZxzz9KaTTzsjVcK3CgPE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1739185784; c=relaxed/simple; bh=rHdyURNsf2uSLx/PTLk3TS1Iry9slMGvXeQIHJQ7Lys=; h=DKIM-Signature:DKIM-Signature:Subject:From:To:Date:Mime-Version: Message-ID; b=Bz4hCH4RxW62KbuEr0T09Zj80aUPdQ+VzR6CZqaxU2KeQdq/FH5Al6CNjmkQQFk0x6LP+RY72c+W4i9/Ib/mWHfVv1nhbxZ0Hoe2JSm7Kz84jfrE7q2UFP/0+2FOwjFAeBIx2xmkgre4ovVnN0Gg05pHqiiNV7x7pacQLxEwNKA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E10983858CDA DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=tey23rxsjton5kop5bydp3vc5ylkyjkg; d=nasilyan.com; t=1739185781; h=Subject:From:To:Cc:Date:Mime-Version:Content-Type:In-Reply-To:References:Message-Id; bh=rHdyURNsf2uSLx/PTLk3TS1Iry9slMGvXeQIHJQ7Lys=; b=eho6zKFpzyLUQuJHObYOOH3IWclXixS+L6r44wpFOxSfvjSW6VKvLdrHN7JQLKLZ 3K3YwAnnuHQUeD9GtvKVvwT73bxZKBYiV75F5fU2M2Uhe+wgVQ6xTTSoj6IQKjOXzly tSXDksItjIrtVceqgS7MtimL8HRRGM9HsSkGE1r0= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/simple; s=uku4taia5b5tsbglxyj6zym32efj7xqv; d=amazonses.com; t=1739185781; h=Subject:From:To:Cc:Date:Mime-Version:Content-Type:In-Reply-To:References:Message-Id:Feedback-ID; bh=rHdyURNsf2uSLx/PTLk3TS1Iry9slMGvXeQIHJQ7Lys=; b=BRyTuS+xrS7HpyJidWsi5KXkcevcpQam8LPlo85e6EQ2zVWgVuZW/cY1+/f40ZuG l+IvOwiJTPH2QHaAOjAkArnR1rrODhGXXWvqkmjIG1toeNECBInSHohRW2HiLNhi6Ly objICXvniR6mxjWGopKWFwk6XhIwKbOZb6+o5BYU= Subject: [PATCH v4] c++: Reject cdtors and conversion operators with a single * as return type [PR118306] From: =?utf-8?q?Simon_Martin?= To: =?utf-8?q?Jason_Merrill?= Cc: =?utf-8?q?Andrew_Pinski?= , =?utf-8?q?gcc-patches=40g?= =?utf-8?q?cc=2Egnu=2Eorg?= , =?utf-8?q?Marek_Polac?= =?utf-8?q?ek?= Date: Mon, 10 Feb 2025 11:09:41 +0000 Mime-Version: 1.0 In-Reply-To: References: <010201944fef89d8-714d6c52-eadb-47d8-a77f-90d2015fa0ae-000000@eu-west-1.amazonses.com> <01020194d1ad0bb7-4ecc05b9-f984-45a5-b470-94a31cd54abc-000000@eu-west-1.amazonses.com> <8964ec49-7cb9-4776-abe1-57f8b84a2a1f@redhat.com> <0453B624-CF8F-482F-BD64-C55AD2CF5154@nasilyan.com> <01020194d1da4bd7-5861d4e7-c174-4c9e-b009-046a9fb1909e-000000@eu-west-1.amazonses.com> <38254aad-7764-4bfb-9569-f5b33ca6d207@redhat.com> <088e227f-2359-4ca9-83c0-34c598684ad4@redhat.com> <97F98777-27A0-45AB-8E0D-8599B64D5EC7@nasilyan.com> <01020194d78f7b36-12fbef55-72a4-4c73-a9df-f0c6bac22962-000000@eu-west-1.amazonses.com> <193404db-d15f-46d7-a0f0-90eaac5a0e22@redhat.com> <01020194dcddff96-418d4f93-eaa0-4d58-9059-f447d0500bd4-000000@eu-west-1.amazonses.com> <64B933F6-DC44-4566-8B0C-12E201A3A3A0@nasilyan.com> <01020194e23a3621-bc4efd33-2ab4-44d8-a96e-c73b366be90d-000000@eu-west-1.amazonses.com> <9049B627-9822-487C-90DB-C55C6DA8BB31@nasilyan.com> X-Mailer: Amazon WorkMail Thread-Index: AQHbY1FoOzjyBue5TRyScaRcRp4PlgAOctmhANm9ogIA4LNzdgD9vheDAQMhUOcE8nLRWwTy+Pb6BPPJibME9LLITwT7rNRxBPxbUloFLHBIJwVXXh0VBWBDD8AFhHunsgWUm4/FBZb1elUGFrfgqw== Thread-Topic: [PATCH v4] c++: Reject cdtors and conversion operators with a single * as return type [PR118306] X-Original-Mailer: MailMate (1.13.2r5673) X-Wm-Sent-Timestamp: 1739185780 Message-ID: <01020194ef8cfb84-d20985f4-d745-4710-b03d-c602be794ecc-000000@eu-west-1.amazonses.com> Feedback-ID: ::1.eu-west-1.b24dn6frgCi6dh20skzbuMRr7UL8M6Soir/3ogtEjHQ=:AmazonSES X-SES-Outgoing: 2025.02.10-54.240.3.40 X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, BODY_8BITS, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, PDS_BAD_THREAD_QP_64, RCVD_IN_DNSWL_NONE, 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 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Hi Jason, On 7 Feb 2025, at 23:10, Jason Merrill wrote: > On 2/7/25 4:04 PM, Simon Martin wrote: >> Hi Jason, >> >> On 7 Feb 2025, at 14:21, Jason Merrill wrote: >> >>> On 2/6/25 3:05 PM, Simon Martin wrote: >>>> Hi Jason, >>>> >>>> On 6 Feb 2025, at 16:48, Jason Merrill wrote: >>>> >>>>> On 2/5/25 2:21 PM, Simon Martin wrote: >>>>>> Hi Jason, >>>>>> >>>>>> On 4 Feb 2025, at 21:23, Jason Merrill wrote: >>>>>> >>>>>>> On 2/4/25 3:03 PM, Jason Merrill wrote: >>>>>>>> On 2/4/25 11:45 AM, Simon Martin wrote: >>>>>>>>> On 4 Feb 2025, at 17:17, Jason Merrill wrote: >>>>>>>>> >>>>>>>>>> On 2/4/25 10:56 AM, Simon Martin wrote: >>>>>>>>>>> Hi Jason, >>>>>>>>>>> >>>>>>>>>>> On 4 Feb 2025, at 16:39, Jason Merrill wrote: >>>>>>>>>>> >>>>>>>>>>>> On 1/15/25 9:56 AM, Jason Merrill wrote: >>>>>>>>>>>>> On 1/15/25 7:24 AM, Simon Martin wrote: >>>>>>>>>>>>>> Hi, >>>>>>>>>>>>>> >>>>>>>>>>>>>> On 14 Jan 2025, at 23:31, Jason Merrill wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>>> On 1/14/25 2:13 PM, Simon Martin wrote: >>>>>>>>>>>>>>>> On 10 Jan 2025, at 19:10, Andrew Pinski wrote: >>>>>>>>>>>>>>>>> On Fri, Jan 10, 2025 at 3:18 AM Simon Martin >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>> We currently accept the following invalid code (EDG >>>>>>>>>>>>>>>>>> and >> >>>>>>>>>>>>>>>>>> MSVC >>>>>>>>>>>>>>>>>> do >>>>>>>>>>>>>>>>>> as >>>>>>>>>>>>>>>>>> well) >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> clang does too: >>>>>>>>>>>>>>>>> https://github.com/llvm/llvm-project/issues/121706 . >>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> Note it might be useful if a testcase with multiply >>>>>>>>>>>>>>>>> `*` >>>>>>>>>>>>>>>>> is >>>>>>>>>>>>>>>>> included >>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>> too: >>>>>>>>>>>>>>>>> ``` >>>>>>>>>>>>>>>>> struct A { >>>>>>>>>>>>>>>>>       ****A (); >>>>>>>>>>>>>>>>> }; >>>>>>>>>>>>>>>>> ``` >>>>>>>>>>>>>>>> Thanks, makes sense to add those. Done in the attached >>>>>>>>>>>>>>>> updated >>>>>>>>>>>>>>>> revision, >>>>>>>>>>>>>>>> successfully tested on x86_64-pc-linux-gnu. >>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> +/* Check that it's OK to declare a function at ID_LOC >> >>>>>>>>>>>>>>>> with >>>>>>>>>>>>>>>> the >>>>>>>>>>>>>>>> indicated TYPE, >>>>>>>>>>>>>>>> +   TYPE_QUALS and DECLARATOR.  SFK indicates the >>>>>>>>>>>>>>>> kind >>>>>>>>>>>>>>>> of >>>>>>>>>>>>>>>> special >>>>>>>>>>>>>>>> function (if >>>>>>>>>>>>>>>> +   any) that this function is.  OPTYPE is the type >>>>>>>>>>>>>>>> given >>>>>>>>>>>>>>>> in >>>>>>>>>>>>>>>> a >>>>>>>>>>>>>>>> conversion >>>>>>>>>>>>>>>>        operator declaration, or the class type >>>>>>>>>>>>>>>> for >>>>>>>>>>>>>>>> a >>>>>>>>>>>>>>>> constructor/destructor. >>>>>>>>>>>>>>>>        Returns the actual return type of the >>>>>>>>>>>>>>>> function; >>>>>>>>>>>>>>>> that >>>>>>>>>>>>>>>> may >>>>>>>>>>>>>>>> be >>>>>>>>>>>>>>>> different >>>>>>>>>>>>>>>>        than TYPE if an error occurs, or for >>>>>>>>>>>>>>>> certain >>>>>>>>>>>>>>>> special >>>>>>>>>>>>>>>> functions. >>>>>>>>>>>>>>>> */ >>>>>>>>>>>>>>>> @@ -12361,8 +12362,19 @@ >>>>>>>>>>>>>>>> check_special_function_return_type >>>>>>>>>>>>>>>> (special_function_kind sfk, >>>>>>>>>>>>>>>>                         tree >>>>>>>>>>>>>>>> type, >>>>>>>>>>>>>>>>                         tree >>>>>>>>>>>>>>>> optype, >>>>>>>>>>>>>>>>                         int >>>>>>>>>>>>>>>> type_quals, >>>>>>>>>>>>>>>> +                    const >>>>>>>>>>>>>>>> cp_declarator >>>>>>>>>>>>>>>> *declarator, >>>>>>>>>>>>>>>> +                    location_t >>>>>>>>>>>>>>>> id_loc, >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> id_loc should be the same as declarator->id_loc? >>>>>>>>>>>>>> You’re right. >>>>>>>>>>>>>> >>>>>>>>>>>>>>>>                         const >>>>>>>>>>>>>>>> location_t* >>>>>>>>>>>>>>>> locations) >>>>>>>>>>>>>>>>     { >>>>>>>>>>>>>>>> +  /* If TYPE is unspecified, DECLARATOR, if set, >>>>>>>>>>>>>>>> should >>>>>>>>>>>>>>>> not >>>>>>>>>>>>>>>> represent a pointer >>>>>>>>>>>>>>>> +     or a reference type.  */ >>>>>>>>>>>>>>>> +  if (type == NULL_TREE >>>>>>>>>>>>>>>> +      && declarator >>>>>>>>>>>>>>>> +      && (declarator->kind == cdk_pointer >>>>>>>>>>>>>>>> +      || declarator->kind == cdk_reference)) >>>>>>>>>>>>>>>> +    error_at (id_loc, "expected unqualified-id >>>>>>>>>>>>>>>> before >>>>>>>>>>>>>>>> %qs >>>>>>>>>>>>>>>> token", >>>>>>>>>>>>>>>> +          declarator->kind == cdk_pointer ? >>>>>>>>>>>>>>>> "*" >>>>>>>>>>>>>>>> : >>>>>>>>>>>>>>>> "&"); >>>>>>>>>>>>>>> >>>>>>>>>>>>>>> ...and id_loc isn't the location of the ptr-operator, >>>>>>>>>>>>>>> it's >> >>>>>>>>>>>>>>> the >>>>>> >>>>>>>>>>>>>>> location of the identifier, so this indicates the wrong >>>>>>>>>>>>>>> column. >>>>>>>>>>>>>>> I >>>>>>>>>>>>>>> think using declarator->id_loc makes sense, just not >>>>>>>>>>>>>>> pretending >>>>>>>>>>>>>>> it's >>>>>>>>>>>>>>> the location of the *. >>>>>>>>>>>>>> Good catch, thanks. >>>>>>>>>>>>>> >>>>>>>>>>>>>>> Let's give diagnostics more like the others later in the >>>>>>>>>>>>>>> function >>>>>>>>>>>>>>> instead of trying to emulate cp_parser_error. >>>>>>>>>>>>>> Makes sense. This is what the updated patch does, >>>>>>>>>>>>>> successfully >>>>>>>>>>>>>> tested on >>>>>>>>>>>>>> x86_64-pc-linux-gnu. OK for GCC 16? >>>>>>>>>>>>> >>>>>>>>>>>>> OK. >>>>>>>>>>>> >>>>>>>>>>>> Does this also fix 118304?  If so, let's go ahead and >>>>>>>>>>>> apply >>>>>>>>>>>> it >>>>>>>>>>>> to >>>>>>>>>>>> GCC >>>>>>>>>>>> 15. >>>>>>>>>>> I have checked just now, and we still ICE for 118304’s >> >>>>>>>>>>> testcase >>>>>>>>>>> with >>>>>>>>>>> that fix. >>>>>>>>>> >>>>>>>>>> Why doesn't the preeexisting >>>>>>>>>> >>>>>>>>>> type = void_type_node; >>>>>>>>>> >>>>>>>>>> in check_special_function_return_type fix the return type and >>>>>>>>>> avoid >>>>>> >>>>>>>>>> the ICE? >>>>>>>> >>>>>>>>> We hit the gcc_assert at method.cc:3593, that Marek’s fix >>>>>> >>>>>>>>> bypasses. >>>>>>>> >>>>>>>> Yes, but why doesn't check_special_function_return_type prevent >>>>>>>> that? >>>>>>> >>>>>>> Ah, because we call it before walking the declarator. We need >>>>>>> to >>>>>>> check again later, perhaps in grokfndecl, that the type is >>>>>>> correct. >>>>>>> Perhaps instead of your patch. >>>>>> One “issue” with adding another check in or close to >>>>>> grokfndecl >>>>>> is >>>>>> that DECLARATOR will have “been moved to the ID”, and the >>>>>> fact >>>>>> that >>>>>> we had a CDK_POINTER kind is “lost”. We could obviously >>>>>> somehow >>>>>> propagate this information, but there might be something easier. >>>>> >>>>> The information isn't lost: it's now reflected in the (wrong) >>>>> return >> >>>>> type. One place it would make sense to check would be >>>>> >>>>>> if (ctype && (sfk == sfk_constructor >>>>>> || sfk == sfk_destructor)) >>>>>> { >>>>>> /* We are within a class's scope. If our >>>>>> declarator >>>>>> name >>>>>> is the same as the class name, and we are >>>>>> defining >>>>>> a >>>>>> function, then it is a constructor/destructor, and >>>>>> therefore >>>>>> returns a void type. */ >>>>> >>>>> Here 'type' is still the return type, we haven't gotten to >>>>> build_function_type yet. >>>> That’s true. However, doesn’t it make sense to cram all the >>>> checks >>>> about the return type of special functions in >>>> check_special_function_return_type, and return an error if that >>>> return >>>> type is invalid? >>> >>> This error seems easily recoverable since we know what the type >>> needs >>> to be, there's no need for error return from grokdeclarator. >> ACK. >> >>> However, an alternative to my suggestion above would be to build on >>> your patch by making check_special_function_return_type actually >>> strip >>> the invalid declarators, not just complain about them. > >> Thanks for the suggestion, I like that it keeps everything within >> check_special_function_return_type. Hence the updated attached patch, >> >> successfully tested on 86_64-pc-linux-gnu. OK for trunk? > >> case sfk_constructor: >> if (type) >> error_at (smallest_type_location (type_quals, locations), >> "return type specification for constructor invalid"); >> + else if (maybe_strip_indirect_ref (declarator)) >> + error_at ((*declarator)->id_loc, >> + "return type specification for constructor invalid"); >> else if (type_quals != TYPE_UNQUALIFIED) >> error_at (smallest_type_quals_location (type_quals, locations), >> "qualifiers are not allowed on constructor declaration"); > > This looks like if someone writes e.g. > > int *A(); > > then we'll complain about the 'int' but leave the * alone. Argh you’re right, the return type is not fully groked at this point, so check_special_function_return_type should check first for indirect refs and then for type if needed. This is what the updated attached patch does Successfully tested on x86_64-pc-linux-gnu. OK for trunk? Thanks, Simon From 140bd5fa4f98fcb2ac32b99e4403dd4875afe9c5 Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Sun, 9 Feb 2025 20:38:43 +0100 Subject: [PATCH] c++: Reject cdtors and conversion operators with a single * as return type [PR118304, PR118306] We currently accept the following constructor declaration (clang, EDG and MSVC do as well), and ICE on the destructor declaration === cut here === struct A { *A (); ~A () = default; }; === cut here === The problem is that we end up in grokdeclarator with a cp_declarator of kind cdk_pointer but no type, and we happily go through (if we have a reference instead we eventually error out trying to form a reference to void). This patch makes sure that grokdeclarator errors out and strips the invalid declarator when processing a cdtor (or a conversion operator with no return type specified) with a declarator representing a pointer or a reference type. Successfully tested on x86_64-pc-linux-gnu. PR c++/118306 PR c++/118304 gcc/cp/ChangeLog: * decl.cc (maybe_strip_indirect_ref): New. (check_special_function_return_type): Take declarator as input. Call maybe_strip_indirect_ref and error out if it returns true. (grokdeclarator): Update call to check_special_function_return_type. gcc/testsuite/ChangeLog: * g++.old-deja/g++.jason/operator.C: Adjust bogus test expectation (char** vs char*). * g++.dg/parse/constructor4.C: New test. * g++.dg/parse/constructor5.C: New test. * g++.dg/parse/conv_op2.C: New test. * g++.dg/parse/default_to_int.C: New test. --- gcc/cp/decl.cc | 50 ++++++++++++----- gcc/testsuite/g++.dg/parse/constructor4.C | 54 +++++++++++++++++++ gcc/testsuite/g++.dg/parse/constructor5.C | 48 +++++++++++++++++ gcc/testsuite/g++.dg/parse/conv_op2.C | 10 ++++ gcc/testsuite/g++.dg/parse/default_to_int.C | 37 +++++++++++++ .../g++.old-deja/g++.jason/operator.C | 2 +- 6 files changed, 187 insertions(+), 14 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/constructor4.C create mode 100644 gcc/testsuite/g++.dg/parse/constructor5.C create mode 100644 gcc/testsuite/g++.dg/parse/conv_op2.C create mode 100644 gcc/testsuite/g++.dg/parse/default_to_int.C -- 2.44.0 diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc index 84abc17ade0..552a7a2ec54 100644 --- a/gcc/cp/decl.cc +++ b/gcc/cp/decl.cc @@ -101,7 +101,8 @@ static void end_cleanup_fn (void); static tree cp_make_fname_decl (location_t, tree, int); static void initialize_predefined_identifiers (void); static tree check_special_function_return_type - (special_function_kind, tree, tree, int, const location_t*); + (special_function_kind, tree, tree, int, const cp_declarator**, + const location_t*); static tree push_cp_library_fn (enum tree_code, tree, int); static tree build_cp_library_fn (tree, enum tree_code, tree, int); static void store_parm_decls (tree); @@ -12441,10 +12442,27 @@ smallest_type_location (const cp_decl_specifier_seq *declspecs) return smallest_type_location (type_quals, declspecs->locations); } -/* Check that it's OK to declare a function with the indicated TYPE - and TYPE_QUALS. SFK indicates the kind of special function (if any) - that this function is. OPTYPE is the type given in a conversion - operator declaration, or the class type for a constructor/destructor. +/* Returns whether DECLARATOR represented a pointer or a reference and if so, + strip out the pointer/reference declarator(s). */ + +static bool +maybe_strip_indirect_ref (const cp_declarator** declarator) +{ + bool indirect_ref_p = false; + while (declarator && *declarator + && ((*declarator)->kind == cdk_pointer + || (*declarator)->kind == cdk_reference)) + { + indirect_ref_p = true; + *declarator = (*declarator)->declarator; + } + return indirect_ref_p; +} + +/* Check that it's OK to declare a function with the indicated TYPE, TYPE_QUALS + and DECLARATOR. SFK indicates the kind of special function (if any) that + this function is. OPTYPE is the type given in a conversion operator + declaration, or the class type for a constructor/destructor. Returns the actual return type of the function; that may be different than TYPE if an error occurs, or for certain special functions. */ @@ -12453,13 +12471,18 @@ check_special_function_return_type (special_function_kind sfk, tree type, tree optype, int type_quals, + const cp_declarator** declarator, const location_t* locations) { + gcc_assert (declarator); + location_t rettype_loc = (type + ? smallest_type_location (type_quals, locations) + : (*declarator)->id_loc); switch (sfk) { case sfk_constructor: - if (type) - error_at (smallest_type_location (type_quals, locations), + if (maybe_strip_indirect_ref (declarator) || type) + error_at (rettype_loc, "return type specification for constructor invalid"); else if (type_quals != TYPE_UNQUALIFIED) error_at (smallest_type_quals_location (type_quals, locations), @@ -12472,8 +12495,8 @@ check_special_function_return_type (special_function_kind sfk, break; case sfk_destructor: - if (type) - error_at (smallest_type_location (type_quals, locations), + if (maybe_strip_indirect_ref (declarator) || type) + error_at (rettype_loc, "return type specification for destructor invalid"); else if (type_quals != TYPE_UNQUALIFIED) error_at (smallest_type_quals_location (type_quals, locations), @@ -12488,8 +12511,8 @@ check_special_function_return_type (special_function_kind sfk, break; case sfk_conversion: - if (type) - error_at (smallest_type_location (type_quals, locations), + if (maybe_strip_indirect_ref (declarator) || type) + error_at (rettype_loc, "return type specified for %", optype); else if (type_quals != TYPE_UNQUALIFIED) error_at (smallest_type_quals_location (type_quals, locations), @@ -12500,8 +12523,8 @@ check_special_function_return_type (special_function_kind sfk, break; case sfk_deduction_guide: - if (type) - error_at (smallest_type_location (type_quals, locations), + if (maybe_strip_indirect_ref (declarator) || type) + error_at (rettype_loc, "return type specified for deduction guide"); else if (type_quals != TYPE_UNQUALIFIED) error_at (smallest_type_quals_location (type_quals, locations), @@ -13181,6 +13204,7 @@ grokdeclarator (const cp_declarator *declarator, type = check_special_function_return_type (sfk, type, ctor_return_type, type_quals, + &declarator, declspecs->locations); type_quals = TYPE_UNQUALIFIED; } diff --git a/gcc/testsuite/g++.dg/parse/constructor4.C b/gcc/testsuite/g++.dg/parse/constructor4.C new file mode 100644 index 00000000000..f7e4cace451 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/constructor4.C @@ -0,0 +1,54 @@ +// PR c++/118306 +// { dg-do "compile" } + +// Constructors. +struct A { + *A (); // { dg-error "return type specification" } +}; +struct B { + **B (); // { dg-error "return type specification" } +}; +struct C { + ***C (); // { dg-error "return type specification" } +}; +struct D { + &D (); // { dg-error "return type specification|reference to" } +}; +struct E { + *&E (); // { dg-error "return type specification|reference to" } +}; +struct F { + **&F (); // { dg-error "return type specification|reference to" } +}; +struct G { + *G (const G&); // { dg-error "return type specification" } +}; +struct H { + **H (const H&); // { dg-error "return type specification" } +}; +struct I { + &I (const I&); // { dg-error "return type specification|reference to" } +}; +struct J { + const J(); // { dg-error "expected unqualified-id" } +}; + +// Destructors. +struct K { + * ~K (); // { dg-error "return type specification" } +}; +struct L { + ** ~L (); // { dg-error "return type specification" } +}; +struct M { + & ~M (); // { dg-error "return type specification|reference to" } +}; +struct N { + virtual * ~N (); // { dg-error "return type specification" } +}; +struct O { + virtual & ~O (); // { dg-error "return type specification|reference to" } +}; +struct P { + volatile ~P(); // { dg-error "qualifiers are not allowed" } +}; diff --git a/gcc/testsuite/g++.dg/parse/constructor5.C b/gcc/testsuite/g++.dg/parse/constructor5.C new file mode 100644 index 00000000000..5c86fe721a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/constructor5.C @@ -0,0 +1,48 @@ +// PR c++/118304 +// { dg-do "compile" { target c++11 } } + +// Constructors. +struct A { + *A () = default; // { dg-error "return type specification" } +}; +struct B { + int* B () = default; // { dg-error "return type specification" } +}; +struct C { + const int& C () = default; // { dg-error "return type specification" } +}; +struct D { + **D () = default; // { dg-error "return type specification" } +}; +struct E { + &E () = default; // { dg-error "return type specification|reference to" } +}; +struct F { + *&F () = default; // { dg-error "return type specification|reference to" } +}; +struct G { + **&G () = default; // { dg-error "return type specification|reference to" } +}; +struct H { + *H (const H&) = default; // { dg-error "return type specification" } +}; +struct I { + **I (const I&) = default; // { dg-error "return type specification" } +}; +struct J { + &J (const J&) = default; // { dg-error "return type specification|reference to" } +}; +struct K { + const K() = default; // { dg-error "expected unqualified-id" } +}; + +// Destructors. +struct L { + * ~L () = default; // { dg-error "return type specification" } +}; +struct M { + ** ~M () = default; // { dg-error "return type specification" } +}; +struct N { + & ~N () = default; // { dg-error "return type specification|reference to" } +}; diff --git a/gcc/testsuite/g++.dg/parse/conv_op2.C b/gcc/testsuite/g++.dg/parse/conv_op2.C new file mode 100644 index 00000000000..f2719135e00 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/conv_op2.C @@ -0,0 +1,10 @@ +// PR c++/118306 +// { dg-do "compile" } + +struct K { + char operator int(); // { dg-error "return type specified for" } + * operator short(); // { dg-error "return type specified for" } + ** operator float(); // { dg-error "return type specified for" } + &* operator double(); // { dg-error "return type specified for|pointer to 'double&'" } + & operator long(); // { dg-error "return type specified for" } +}; diff --git a/gcc/testsuite/g++.dg/parse/default_to_int.C b/gcc/testsuite/g++.dg/parse/default_to_int.C new file mode 100644 index 00000000000..681298ce634 --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/default_to_int.C @@ -0,0 +1,37 @@ +// PR c++/118306 - "Document" various behaviours wrt. defaulting types to int. +// { dg-do "compile" } +// { dg-additional-options "-fpermissive" } + +// Members. +struct K { + * mem1; // { dg-warning "forbids declaration" } + * mem2; // { dg-warning "forbids declaration" } + const * mem3; // { dg-warning "forbids declaration" } + const ** mem4; // { dg-warning "forbids declaration" } + & mem5; // { dg-warning "forbids declaration" } + volatile & mem6; // { dg-warning "forbids declaration" } + + void foo (const& permissive_fine, // { dg-warning "forbids declaration" } + volatile* permissive_fine_as_well); // { dg-warning "forbids declaration" } + + * bar () { return 0; } // { dg-warning "forbids declaration" } + const& baz (); // { dg-warning "forbids declaration" } + + void bazz () { + try {} + catch (const *i) {} // { dg-warning "forbids" } + catch (const &i) {} // { dg-warning "forbids" } + } +}; + +// Template parameters. +template // { dg-warning "forbids" } +void baz() {} + +// Functions. +foo(int) { return 42; } // { dg-warning "forbids declaration" } +*bar(int) { return 0; } // { dg-warning "forbids declaration" } +**bazz(int) { return 0; } // { dg-warning "forbids declaration" } +*&bazzz(int) { return 0; } // { dg-warning "forbids declaration|bind non-const" } +const bazzzz (int) { return 0; } // { dg-warning "forbids declaration" } +const* bazzzzz (int) { return 0; } // { dg-warning "forbids declaration" } diff --git a/gcc/testsuite/g++.old-deja/g++.jason/operator.C b/gcc/testsuite/g++.old-deja/g++.jason/operator.C index c18790190b5..542f305942c 100644 --- a/gcc/testsuite/g++.old-deja/g++.jason/operator.C +++ b/gcc/testsuite/g++.old-deja/g++.jason/operator.C @@ -29,4 +29,4 @@ void * operator new (A a); // { dg-error ".operator new. takes type .size_t." } void operator delete (A a); // { dg-error ".operator delete. takes type .void\\*. as first parameter" } char * operator char * (int); // { dg-error "return type" "ret" } -// { dg-error "8:.operator char\\*\\*\\(int\\). must be a non-static member function" "mem" { target *-*-* } .-1 } +// { dg-error "8:.operator char\\*\\(int\\). must be a non-static member function" "mem" { target *-*-* } .-1 }