This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C++ PATCH to fix an ICE on invalid with OVERLOADs (PR c++/84854)
- From: Jason Merrill <jason at redhat dot com>
- To: Marek Polacek <polacek at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 3 Apr 2018 13:32:46 -0400
- Subject: Re: C++ PATCH to fix an ICE on invalid with OVERLOADs (PR c++/84854)
- References: <20180314155956.GU3522@redhat.com> <CADzB+2m724Mw2HtbKjb22Hdqbbm0WPCC-urRLmNznW8kCS2M7w@mail.gmail.com> <20180315114922.GV3522@redhat.com> <CADzB+2=eAD_1W29J7hNFbD=VX-60wMSDtS8Ext2zPVEUoffqaQ@mail.gmail.com> <20180321183739.GG3522@redhat.com> <CADzB+2k0KvRKMy9XutWfdDRSm2yOmL303W2RUuTqDsJmCJfEEQ@mail.gmail.com> <20180321201430.GH3522@redhat.com>
On Wed, Mar 21, 2018 at 4:14 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Wed, Mar 21, 2018 at 02:55:36PM -0400, Jason Merrill wrote:
>> On Wed, Mar 21, 2018 at 2:37 PM, Marek Polacek <polacek@redhat.com> wrote:
>> > On Thu, Mar 15, 2018 at 08:55:59AM -0400, Jason Merrill wrote:
>> >> On Thu, Mar 15, 2018 at 7:49 AM, Marek Polacek <polacek@redhat.com> wrote:
>> >> > On Wed, Mar 14, 2018 at 02:06:36PM -0400, Jason Merrill wrote:
>> >> >> On Wed, Mar 14, 2018 at 11:59 AM, Marek Polacek <polacek@redhat.com> wrote:
>> >> >> > cxx_constant_value doesn't understand template codes, and neither it
>> >> >> > understands OVERLOADs, so if we pass an OVERLOAD to it, we crash. Here
>> >> >> > instantiate_non_dependent_expr got an OVERLOAD, but since it calls
>> >> >> > is_nondependent_constant_expression which checks type_unknown_p, it left the
>> >> >> > expression as it was. We can't use is_nondependent_constant_expression in
>> >> >> > finish_if_stmt_cond because i_n_c_e checks is_constant_expression and that is
>> >> >> > not suitable here; we'd miss diagnostics. So I did the following; I think we
>> >> >> > should reject the testcase with an error.
>> >> >> >
>> >> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
>> >> >> >
>> >> >> > 2018-03-14 Marek Polacek <polacek@redhat.com>
>> >> >> >
>> >> >> > PR c++/84854
>> >> >> > * semantics.c (finish_if_stmt_cond): Give error if the condition
>> >> >> > is an overloaded function with no contextual type information.
>> >> >> >
>> >> >> > * g++.dg/cpp1z/constexpr-if15.C: New test.
>> >> >> >
>> >> >> > diff --git gcc/cp/semantics.c gcc/cp/semantics.c
>> >> >> > index fdf37bea770..a056e9445e9 100644
>> >> >> > --- gcc/cp/semantics.c
>> >> >> > +++ gcc/cp/semantics.c
>> >> >> > @@ -735,8 +735,16 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
>> >> >> > && require_constant_expression (cond)
>> >> >> > && !value_dependent_expression_p (cond))
>> >> >> > {
>> >> >> > - cond = instantiate_non_dependent_expr (cond);
>> >> >> > - cond = cxx_constant_value (cond, NULL_TREE);
>> >> >> > + if (type_unknown_p (cond))
>> >> >> > + {
>> >> >> > + cxx_incomplete_type_error (cond, TREE_TYPE (cond));
>> >> >> > + cond = error_mark_node;
>> >> >>
>> >> >> I think I'd prefer to skip this block when type_unknown_p, and leave
>> >> >> error handling up to the code shared with regular if.
>> >> >
>> >> > Like this?
>> >>
>> >> Yes, thanks.
>> >>
>> >> > It was my first version, but I thought we wanted the error;
>> >>
>> >> Getting an error is an improvement, but it should apply to
>> >> non-constexpr if as well, so checking in maybe_convert_cond would be
>> >> better. Actually, if we deal with unknown type there, we shouldn't
>> >> need this patch at all.
>> >>
>> >> ...except I also notice that since maybe_convert_cond doesn't do any
>> >> conversion in a template, we're trying to extract the constant value
>> >> without first converting to bool, which breaks this testcase:
>> >>
>> >> struct A
>> >> {
>> >> constexpr operator bool () { return true; }
>> >> int i;
>> >> };
>> >>
>> >> A a;
>> >>
>> >> template <class T> void f()
>> >> {
>> >> constexpr bool b = a; // works
>> >> if constexpr (a) { } // breaks
>> >> }
>> >>
>> >> int main()
>> >> {
>> >> f<int>();
>> >> }
>> >>
>> >> A simple fix would be to replace your type_unknown_p check here with a
>> >> comparison to boolean_type_node, so we wait until instantiation time
>> >> to require a constant value.
>> >
>> > Ok, that works.
>> >
>> > We should also make g++ accept the testcase with "static_assert(a)" instead of
>> > "if constexpr (a) { }" probably.
>>
>> > I guess the cxx_constant_value call in
>> > finish_static_assert should happen earlier?
>>
>> fold_non_dependent_expr should already have gotten the constant value,
>> the call to cxx_constant_value is just for giving an error.
>
> Oop, right.
>
>> The bug seems to be that is_nondependent_constant_expression doesn't
>> realize that the conversion to bool is OK because it uses a constexpr
>> member function.
>
> OK, I can look into this separately.
>
>> >> Better would be to actually do the conversion. Perhaps this could
>> >> share code (for converting and getting a constant value) with
>> >> finish_static_assert.
>> >
>> > But this I didn't manage to make to work. If I call perform_implicit_conversion_flags
>> > in maybe_convert_cond, I get
>> > error: cannot resolve overloaded function ‘foo’ based on conversion to type ‘bool’
>> > so I'm not sure how the conversion would help.
>>
>> That looks like a good diagnostic to me, what's the problem?
>
> Ugh, I got this wrong. That diagnostic is fine, because we can reject
> constexpr-if15.C, but with perform_implicit_conversion_flags we then
> can't evaluate constexpr-if16.C:
> error: the value of ‘a’ is not usable in a constant expression
>
>> > Anyway, here's at least the boolean_type_node version.
>> >
>> > Bootstrapped/regtested on x86_64-linux.
>> >
>> > 2018-03-21 Marek Polacek <polacek@redhat.com>
>> >
>> > PR c++/84854
>> > * semantics.c (finish_if_stmt_cond): Check if the type of the condition
>> > is boolean.
>>
>> OK.
>
> Thanks, will commit this part along with the testcases. Incrementally we should
> then a) add constexpr-if15.C diagnostic, b) accept constexpr-if16.C with
> static_assert, too.
I think we want to use instantiation_dependent_expression_p here, too.
Applying.
commit 255d33f7e10bd13e99b270e7ac34946e3a03dba1
Author: Jason Merrill <jason@redhat.com>
Date: Mon Apr 2 17:58:41 2018 -0400
* semantics.c (finish_if_stmt_cond): Use instantiation_dependent_expression_p.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index eef9e2f645d..ef243f6bf0a 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -733,7 +733,7 @@ finish_if_stmt_cond (tree cond, tree if_stmt)
if (IF_STMT_CONSTEXPR_P (if_stmt)
&& !type_dependent_expression_p (cond)
&& require_constant_expression (cond)
- && !value_dependent_expression_p (cond)
+ && !instantiation_dependent_expression_p (cond)
/* Wait until instantiation time, since only then COND has been
converted to bool. */
&& TREE_TYPE (cond) == boolean_type_node)