From patchwork Mon Aug 28 23:24:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Polacek X-Patchwork-Id: 137089 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:a7d1:0:b0:3f2:4152:657d with SMTP id p17csp3622337vqm; Mon, 28 Aug 2023 16:25:48 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFUBX3J6RxwAljlQz3ae3LtU4L8LLOhwlpxyfUm9O0sMOVZv520z6iAgOREl1o3qj8Voks5 X-Received: by 2002:a17:906:95:b0:9a2:86a:f9b7 with SMTP id 21-20020a170906009500b009a2086af9b7mr10519583ejc.59.1693265148355; Mon, 28 Aug 2023 16:25:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1693265148; cv=none; d=google.com; s=arc-20160816; b=vKgtxYHD6e3K/vtWYAK2CQjdBkVugVnQ1D4raulWkB0DdmZAN6iM7WDFQlsIf/X2mN /i6HIHnH+UHjXt7LHDatcUOLwbxB6ttudOcRWFyCZ0F9f5ASRX0DHJnZ/Y7W4FLadraq +/YzfSCuv/f923NJzTkawy4IF2xeQOpEgbFvDfE4ZGkk8pCDYiZmhD2UHzHe5fC5VSj/ 4ZPLNZ06GSB1nud+JOjA2+F7g+r+Ub2K6SCt6gM6wtQJlZyfumbJS/hlSDeRXdb0F6f4 MrhY4L5L8vEqHgYtaE/4jICeA0ztattUTqbWGmBacjtC/g3k+j2JeGoxX9JbRMPTXxq8 AYFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:from:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence :content-disposition:user-agent:in-reply-to:mime-version:references :message-id:subject:cc:to:date:dmarc-filter:delivered-to :dkim-signature:dkim-filter; bh=w7EedrdPvxP5fhUamX3qUuflIpf83nwfyopPqLMdrdE=; fh=rsfJLMIL/7j+58qzkgIXBlfQSah3iXypQc76SN5PqTs=; b=x/pUg4GOuHPdmwfwpyLAxBSRvFR+qVncVPS2oNgXSASgjeuaIB9HACpC0pwyI/g4UE M5NJyLgfyA2pRiOxvd06OdGF4P4SLqzBaSl0oASjwaeAtg0DRmIwALrIDf/twiJCdU4K h80l/SQe7dP2h610yN298RbtwSzyXNhqMktcJfIcLWepsMAEl7Dp6vEI0eABYSkATHpE ljDCo45sC0zhxtRwMW9aVmuHSHjb3DSF6mHIPTHaZhhkV2nJpP6AjBoVyl32PunhFpU1 HKSQQys++xZQRnuNwgJ5GDEOVkx2xNYSzZG9d9JjMO6+B2Crqs1WWfCkGD5SnDuTczmi wvnA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=GbTBgLbC; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id x12-20020a170906148c00b00997c3561696si5000763ejc.577.2023.08.28.16.25.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 16:25:48 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=GbTBgLbC; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E74E5385840C for ; Mon, 28 Aug 2023 23:25:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E74E5385840C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1693265146; bh=w7EedrdPvxP5fhUamX3qUuflIpf83nwfyopPqLMdrdE=; h=Date:To:Cc:Subject:References:In-Reply-To:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=GbTBgLbC+vICDESnXDekC/UkodrowjrIjv0T4kJmXS3EG5Zb+5uM8o/gxdTlHKzjx TLVqAu6BqyhfiLLJHM5i49+WeaJydlv9/BSt7xq0X5huex8lAUszGwZBwEG6xHEzvz lBkhPGZKx4RFqPAw8ojy1cdrspuIOd/S8Jdaqy5U= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org 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 0D3803858D28 for ; Mon, 28 Aug 2023 23:25:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0D3803858D28 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-388-ptkn0g8_Pvq3KNMcwNoePg-1; Mon, 28 Aug 2023 19:24:59 -0400 X-MC-Unique: ptkn0g8_Pvq3KNMcwNoePg-1 Received: by mail-qt1-f200.google.com with SMTP id d75a77b69052e-4108d23b401so41948221cf.1 for ; Mon, 28 Aug 2023 16:24:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1693265098; x=1693869898; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w7EedrdPvxP5fhUamX3qUuflIpf83nwfyopPqLMdrdE=; b=O2VizrlpiEI1EwHBxd6whNUP4wDgyRPhxYfiXPYgfBkpR7Jm+2GDMDL7lHn3q/IAZQ HlebfjxolMqqJ4LGLTRODyRNGp7EagR5kjLCbcp6XQTp165aw2ntOn6G/ysFuJr7OYQY MD4rxEu45Vp+RmFHV5G1G7pgNa+syru2SNBksK4BApmYMl7mFRmAGwM9VU0jCyoOYQfQ 3c95DMC77J4Y91AAJ/IJnssqFW+UOSjkSLHaCdTuerL++SLI2iXxyM0Dmuvw5AFybijb V8Qm1VLRHgJr0KJime6JzFp6g8AVGtOF7R0F/Y+KQHLJTDRu/kBwmg5iD86uv78xGprG mrUw== X-Gm-Message-State: AOJu0Yx4zQhzDZNTM+rEo4HiXcKsHodb2Y3OMB3MiG2EOyKl4GqRMOVr MDX/Mr0uqpqJhQ7z4mIVpBMguCs3+jtlJy0aF7TmhJjnH+JAFgtFySLwPzEJDtJ6FvdugIilOA2 5clupVuN87QSKazUnSqp7h4XnrQ== X-Received: by 2002:ac8:7d41:0:b0:40d:4c6:bcf9 with SMTP id h1-20020ac87d41000000b0040d04c6bcf9mr33162929qtb.7.1693265098456; Mon, 28 Aug 2023 16:24:58 -0700 (PDT) X-Received: by 2002:ac8:7d41:0:b0:40d:4c6:bcf9 with SMTP id h1-20020ac87d41000000b0040d04c6bcf9mr33162916qtb.7.1693265098101; Mon, 28 Aug 2023 16:24:58 -0700 (PDT) Received: from redhat.com (2603-7000-9500-34a5-0000-0000-0000-1db4.res6.spectrum.com. [2603:7000:9500:34a5::1db4]) by smtp.gmail.com with ESMTPSA id b18-20020ac86bd2000000b0040f8ac751a5sm2610502qtt.96.2023.08.28.16.24.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Aug 2023 16:24:57 -0700 (PDT) Date: Mon, 28 Aug 2023 19:24:56 -0400 To: Jason Merrill Cc: GCC Patches Subject: [PATCH v2] c++: tweaks for explicit conversion fns diagnostic Message-ID: References: <20230825233746.904433-1-polacek@redhat.com> <16883fbb-a076-ff23-a23d-b92c4035ec87@redhat.com> MIME-Version: 1.0 In-Reply-To: <16883fbb-a076-ff23-a23d-b92c4035ec87@redhat.com> User-Agent: Mutt/2.2.9 (2022-11-12) X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, 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 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: , X-Patchwork-Original-From: Marek Polacek via Gcc-patches From: Marek Polacek Reply-To: Marek Polacek Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1775246214359807774 X-GMAIL-MSGID: 1775517195920030132 On Fri, Aug 25, 2023 at 08:34:37PM -0400, Jason Merrill wrote: > On 8/25/23 19:37, Marek Polacek wrote: > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? > > > > -- >8 -- > > > > 1) When saying that a conversion is erroneous because it would use > > an explicit constructor, it might be nice to show where exactly > > the explicit constructor is located. For example, with this patch: > > > > [...] > > explicit.C:4:12: note: 'S::S(int)' declared here > > 4 | explicit S(int) { } > > | ^ > > > > 2) When a conversion doesn't work out merely because the conversion > > function necessary to do the conversion couldn't be used because > > it was marked explicit, it would be useful to the user to say so, > > rather than just saying "cannot convert". For example, with this patch: > > > > explicit.C:13:12: error: cannot convert 'S' to 'bool' in initialization > > 13 | bool b = S{1}; > > | ^~~~ > > | | > > | S > > explicit.C:5:12: note: explicit conversion function was not considered > > 5 | explicit operator bool() const { return true; } > > | ^~~~~~~~ > > > > gcc/cp/ChangeLog: > > > > * call.cc (convert_like_internal): Show where the conversion function > > was declared. > > (maybe_show_nonconverting_candidate): New. > > * cp-tree.h (maybe_show_nonconverting_candidate): Declare. > > * typeck.cc (convert_for_assignment): Call it. > > > > gcc/testsuite/ChangeLog: > > > > * g++.dg/diagnostic/explicit.C: New test. > > --- > > gcc/cp/call.cc | 41 +++++++++++++++++++--- > > gcc/cp/cp-tree.h | 1 + > > gcc/cp/typeck.cc | 5 +++ > > gcc/testsuite/g++.dg/diagnostic/explicit.C | 16 +++++++++ > > 4 files changed, 59 insertions(+), 4 deletions(-) > > create mode 100644 gcc/testsuite/g++.dg/diagnostic/explicit.C > > > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc > > index 23e458d3252..09ebcf6a115 100644 > > --- a/gcc/cp/call.cc > > +++ b/gcc/cp/call.cc > > @@ -8459,12 +8459,21 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, > > if (pedwarn (loc, 0, "converting to %qT from initializer list " > > "would use explicit constructor %qD", > > totype, convfn)) > > - inform (loc, "in C++11 and above a default constructor " > > - "can be explicit"); > > + { > > + inform (loc, "in C++11 and above a default constructor " > > + "can be explicit"); > > + inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here", > > + convfn); > > I'd swap these two informs. Done. > > +++ b/gcc/testsuite/g++.dg/diagnostic/explicit.C > > @@ -0,0 +1,16 @@ > > +// { dg-do compile { target c++11 } } > > + > > +struct S { > > + explicit S(int) { } > > + explicit operator bool() const { return true; } // { dg-message "explicit conversion function was not considered" } > > + explicit operator int() const { return 42; } // { dg-message "explicit conversion function was not considered" } > > +}; > > + > > +void > > +g () > > +{ > > + S s = {1}; // { dg-error "would use explicit constructor" } > > + bool b = S{1}; // { dg-error "cannot convert .S. to .bool. in initialization" } > > + int i; > > + i = S{2}; // { dg-error "cannot convert .S. to .int. in assignment" } > > +} > > Let's also test other copy-initialization contexts: parameter passing, > return, throw, aggregate member initialization. Done except for throw. To handle arg passing I moved the call to maybe_show_nonconverting_candidate one line down. I guess a testcase for throw would be struct T { T() { } // #1 explicit T(const T&) { } // #2 }; void g () { T t{}; throw t; } but #2 isn't a viable candidate so this would take more effort to handle. We just say about #1 that "candidate expects 0 arguments, 1 provided". clang++ says e.C:3:12: note: explicit constructor is not a candidate 3 | explicit T(const T&) { } | ^ Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk? -- >8 -- 1) When saying that a conversion is erroneous because it would use an explicit constructor, it might be nice to show where exactly the explicit constructor is located. For example, with this patch: [...] explicit.C:4:12: note: 'S::S(int)' declared here 4 | explicit S(int) { } | ^ 2) When a conversion doesn't work out merely because the conversion function necessary to do the conversion couldn't be used because it was marked explicit, it would be useful to the user to say so, rather than just saying "cannot convert". For example, with this patch: explicit.C:13:12: error: cannot convert 'S' to 'bool' in initialization 13 | bool b = S{1}; | ^~~~ | | | S explicit.C:5:12: note: explicit conversion function was not considered 5 | explicit operator bool() const { return true; } | ^~~~~~~~ gcc/cp/ChangeLog: * call.cc (convert_like_internal): Show where the conversion function was declared. (maybe_show_nonconverting_candidate): New. * cp-tree.h (maybe_show_nonconverting_candidate): Declare. * typeck.cc (convert_for_assignment): Call it. gcc/testsuite/ChangeLog: * g++.dg/diagnostic/explicit.C: New test. --- gcc/cp/call.cc | 41 +++++++++++++++++++--- gcc/cp/cp-tree.h | 1 + gcc/cp/typeck.cc | 6 ++++ gcc/testsuite/g++.dg/diagnostic/explicit.C | 33 +++++++++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/diagnostic/explicit.C base-commit: cf64ab18e3f820376ff20c663c7c7bf1af290f02 diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 23e458d3252..52c9f4265a4 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -8459,12 +8459,21 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum, if (pedwarn (loc, 0, "converting to %qT from initializer list " "would use explicit constructor %qD", totype, convfn)) - inform (loc, "in C++11 and above a default constructor " - "can be explicit"); + { + inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here", + convfn); + inform (loc, "in C++11 and above a default constructor " + "can be explicit"); + } } else - error ("converting to %qT from initializer list would use " - "explicit constructor %qD", totype, convfn); + { + auto_diagnostic_group d; + error ("converting to %qT from initializer list would use " + "explicit constructor %qD", totype, convfn); + inform (DECL_SOURCE_LOCATION (convfn), "%qD declared here", + convfn); + } } /* If we're initializing from {}, it's value-initialization. */ @@ -14323,4 +14332,28 @@ is_list_ctor (tree decl) return true; } +/* We know that can_convert_arg_bad already said "no" when trying to convert + FROM to TO with ARG and FLAGS. Try to figure out if it was because + an explicit conversion function was skipped when looking for a way to + perform the conversion. At this point we've already printed an error. */ + +void +maybe_show_nonconverting_candidate (tree to, tree from, tree arg, int flags) +{ + if (!(flags & LOOKUP_ONLYCONVERTING)) + return; + + conversion_obstack_sentinel cos; + conversion *c = implicit_conversion (to, from, arg, /*c_cast_p=*/false, + flags & ~LOOKUP_ONLYCONVERTING, tf_none); + if (c && !c->bad_p && c->user_conv_p) + /* Ay, the conversion would have worked in copy-init context. */ + for (; c; c = next_conversion (c)) + if (c->kind == ck_user + && DECL_P (c->cand->fn) + && DECL_NONCONVERTING_P (c->cand->fn)) + inform (DECL_SOURCE_LOCATION (c->cand->fn), "explicit conversion " + "function was not considered"); +} + #include "gt-cp-call.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 608d6310e53..6b225ca182f 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6727,6 +6727,7 @@ extern bool cp_handle_deprecated_or_unavailable (tree, tsubst_flags_t = tf_warni extern void cp_warn_deprecated_use_scopes (tree); extern tree get_function_version_dispatcher (tree); extern bool any_template_arguments_need_structural_equality_p (tree); +extern void maybe_show_nonconverting_candidate (tree, tree, tree, int); /* in class.cc */ extern tree build_vfield_ref (tree, tree); diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index d5c0c85ed51..459739d5866 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -10262,6 +10262,8 @@ convert_for_assignment (tree type, tree rhs, { range_label_for_type_mismatch label (rhstype, type); gcc_rich_location richloc (rhs_loc, has_loc ? &label : NULL); + auto_diagnostic_group d; + switch (errtype) { case ICR_DEFAULT_ARGUMENT: @@ -10296,6 +10298,10 @@ convert_for_assignment (tree type, tree rhs, gcc_unreachable(); } } + + /* See if we can be more helpful. */ + maybe_show_nonconverting_candidate (type, rhstype, rhs, flags); + if (TYPE_PTR_P (rhstype) && TYPE_PTR_P (type) && CLASS_TYPE_P (TREE_TYPE (rhstype)) diff --git a/gcc/testsuite/g++.dg/diagnostic/explicit.C b/gcc/testsuite/g++.dg/diagnostic/explicit.C new file mode 100644 index 00000000000..122accb86c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/diagnostic/explicit.C @@ -0,0 +1,33 @@ +// { dg-do compile { target c++11 } } + +struct A { + long int l; +}; + +struct S { + explicit S(int) { } + explicit operator bool() const { return true; } // { dg-message "explicit conversion function was not considered" } + explicit operator int() const { return 42; } // { dg-message "explicit conversion function was not considered" } + explicit operator char() const { return 42; } // { dg-message "explicit conversion function was not considered" } + explicit operator double() const { return 42.; } // { dg-message "explicit conversion function was not considered" } + explicit operator float() const { return 42.; } // { dg-message "explicit conversion function was not considered" } + explicit operator long() const { return 42.; } // { dg-message "explicit conversion function was not considered" } +}; + +double +f (char) +{ + return S{2}; // { dg-error "cannot convert .S. to .double. in return" } +} + +void +g () +{ + S s = {1}; // { dg-error "would use explicit constructor" } + bool b = S{1}; // { dg-error "cannot convert .S. to .bool. in initialization" } + int i; + i = S{2}; // { dg-error "cannot convert .S. to .int. in assignment" } + f (S{3}); // { dg-error "cannot convert .S. to .char." } + A a{ S{4} }; // { dg-error "cannot convert .S. to .long int. in initialization" } + float arr[1] = { S{5} }; // { dg-error "cannot convert .S. to .float. in initialization" } +}