C++ PATCH for c++/85032, rejects-valid with if constexpr in template

Message ID 20180324105904.GA8748@redhat.com
State New
Headers show
Series
  • C++ PATCH for c++/85032, rejects-valid with if constexpr in template
Related show

Commit Message

Marek Polacek March 24, 2018, 10:59 a.m.
Recently the code in finish_static_assert was changed to use
perform_implicit_conversion_flags followed by fold_non_dependent_expr.  That
broke this test becase when in a template, p_i_c_f merely wraps the expr in
an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to fold it to
a constant but it gave up because is_nondependent_constant_expression returned
false.  Jason suggested to fix this roughly like the following, i.e. consider
conversions from classes to literal types potentially constant.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-03-24  Marek Polacek  <polacek@redhat.com>

	PR c++/85032
	* constexpr.c (potential_constant_expression_1): Consider conversions
	from classes to literal types potentially constant.

	* g++.dg/cpp0x/pr51225.C: Adjust error message.
	* g++.dg/cpp1z/constexpr-if17.C: New test.


	Marek

Comments

Jason Merrill March 26, 2018, 5:17 p.m. | #1
On Sat, Mar 24, 2018 at 6:59 AM, Marek Polacek <polacek@redhat.com> wrote:
> Recently the code in finish_static_assert was changed to use

> perform_implicit_conversion_flags followed by fold_non_dependent_expr.  That

> broke this test becase when in a template, p_i_c_f merely wraps the expr in

> an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to fold it to

> a constant but it gave up because is_nondependent_constant_expression returned

> false.  Jason suggested to fix this roughly like the following, i.e. consider

> conversions from classes to literal types potentially constant.

>

> Bootstrapped/regtested on x86_64-linux, ok for trunk?

>

> 2018-03-24  Marek Polacek  <polacek@redhat.com>

>

>         PR c++/85032

>         * constexpr.c (potential_constant_expression_1): Consider conversions

>         from classes to literal types potentially constant.

>

>         * g++.dg/cpp0x/pr51225.C: Adjust error message.

>         * g++.dg/cpp1z/constexpr-if17.C: New test.

>

> diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c

> index bebd9f5b5d0..c4b5afe90a2 100644

> --- gcc/cp/constexpr.c

> +++ gcc/cp/constexpr.c

> @@ -5768,6 +5768,23 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,

>                       TREE_TYPE (t));

>           return false;

>         }

> +      /* This might be a conversion from a class to a literal type.  Let's

> +        consider it potentially constant since the conversion might be

> +        a constexpr user-defined conversion.  */

> +      else if (cxx_dialect >= cxx11

> +              && COMPLETE_TYPE_P (TREE_TYPE (t))

> +              && literal_type_p (TREE_TYPE (t))


We probably need to allow dependent types here, too.  And incomplete
classes, which might turn out to be literal later.

Jason
Marek Polacek April 6, 2018, 6:17 p.m. | #2
On Mon, Mar 26, 2018 at 01:17:22PM -0400, Jason Merrill wrote:
> On Sat, Mar 24, 2018 at 6:59 AM, Marek Polacek <polacek@redhat.com> wrote:

> > Recently the code in finish_static_assert was changed to use

> > perform_implicit_conversion_flags followed by fold_non_dependent_expr.  That

> > broke this test becase when in a template, p_i_c_f merely wraps the expr in

> > an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to fold it to

> > a constant but it gave up because is_nondependent_constant_expression returned

> > false.  Jason suggested to fix this roughly like the following, i.e. consider

> > conversions from classes to literal types potentially constant.

> >

> > Bootstrapped/regtested on x86_64-linux, ok for trunk?

> >

> > 2018-03-24  Marek Polacek  <polacek@redhat.com>

> >

> >         PR c++/85032

> >         * constexpr.c (potential_constant_expression_1): Consider conversions

> >         from classes to literal types potentially constant.

> >

> >         * g++.dg/cpp0x/pr51225.C: Adjust error message.

> >         * g++.dg/cpp1z/constexpr-if17.C: New test.

> >

> > diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c

> > index bebd9f5b5d0..c4b5afe90a2 100644

> > --- gcc/cp/constexpr.c

> > +++ gcc/cp/constexpr.c

> > @@ -5768,6 +5768,23 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,

> >                       TREE_TYPE (t));

> >           return false;

> >         }

> > +      /* This might be a conversion from a class to a literal type.  Let's

> > +        consider it potentially constant since the conversion might be

> > +        a constexpr user-defined conversion.  */

> > +      else if (cxx_dialect >= cxx11

> > +              && COMPLETE_TYPE_P (TREE_TYPE (t))

> > +              && literal_type_p (TREE_TYPE (t))

> 

> We probably need to allow dependent types here, too.  And incomplete

> classes, which might turn out to be literal later.


Ok, I've allowed incomplete types, too.  And I think the patch also allows
dependent types.  Or did you mean using
   && (TREE_TYPE (t) == NULL_TREE
       || !COMPLETE_TYPE_P (TREE_TYPE (t))
       || literal_type_p (TREE_TYPE (t)))
?  That doesn't seem to be needed.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-04-06  Marek Polacek  <polacek@redhat.com>

	PR c++/85032
	* constexpr.c (potential_constant_expression_1): Consider conversions
	from classes to literal types potentially constant.

	* g++.dg/cpp0x/pr51225.C: Adjust error message.
	* g++.dg/cpp1z/constexpr-if20.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 3cc196b4d17..916060312f0 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5777,6 +5777,23 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 		      TREE_TYPE (t));
 	  return false;
 	}
+      /* This might be a conversion from a class to a (potentially) literal
+	 type.  Let's consider it potentially constant since the conversion
+	 might be a constexpr user-defined conversion.  */
+      else if (cxx_dialect >= cxx11
+	       && (!COMPLETE_TYPE_P (TREE_TYPE (t))
+		   || literal_type_p (TREE_TYPE (t)))
+	       && TREE_OPERAND (t, 0))
+	{
+	  tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+	  /* If this is a dependent type, it could end up being a class
+	     with conversions.  */
+	  if (type == NULL_TREE || WILDCARD_TYPE_P (type))
+	    return true;
+	  /* Or a non-dependent class which has conversions.  */
+	  else if (CLASS_TYPE_P (type) && TYPE_HAS_CONVERSION (type))
+	    return true;
+	}
 
       return (RECUR (TREE_OPERAND (t, 0),
 		     TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
diff --git gcc/testsuite/g++.dg/cpp0x/pr51225.C gcc/testsuite/g++.dg/cpp0x/pr51225.C
index f80bd0e778e..5b4e432f7ed 100644
--- gcc/testsuite/g++.dg/cpp0x/pr51225.C
+++ gcc/testsuite/g++.dg/cpp0x/pr51225.C
@@ -5,7 +5,7 @@ template<int> struct A {};
 
 template<typename> void foo()
 {
-  A<int(x)> a; // { dg-error "not declared|invalid type" }
+  A<int(x)> a; // { dg-error "not declared|could not convert" }
 }
 
 template<typename> struct bar
diff --git gcc/testsuite/g++.dg/cpp1z/constexpr-if20.C gcc/testsuite/g++.dg/cpp1z/constexpr-if20.C
index e69de29bb2d..56e108be4ad 100644
--- gcc/testsuite/g++.dg/cpp1z/constexpr-if20.C
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-if20.C
@@ -0,0 +1,22 @@
+// PR c++/85032
+// { dg-options -std=c++17 }
+
+struct A
+{
+  constexpr operator bool () { return true; }
+  int i;
+};
+
+A a;
+
+template <class T>
+void f()
+{
+  constexpr bool b = a;
+  static_assert (a);
+}
+
+int main()
+{
+  f<int>();
+}

	Marek
Jason Merrill April 9, 2018, 6:18 p.m. | #3
On Fri, Apr 6, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:
> On Mon, Mar 26, 2018 at 01:17:22PM -0400, Jason Merrill wrote:

>> On Sat, Mar 24, 2018 at 6:59 AM, Marek Polacek <polacek@redhat.com> wrote:

>> > Recently the code in finish_static_assert was changed to use

>> > perform_implicit_conversion_flags followed by fold_non_dependent_expr.  That

>> > broke this test becase when in a template, p_i_c_f merely wraps the expr in

>> > an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to fold it to

>> > a constant but it gave up because is_nondependent_constant_expression returned

>> > false.  Jason suggested to fix this roughly like the following, i.e. consider

>> > conversions from classes to literal types potentially constant.

>> >

>> > Bootstrapped/regtested on x86_64-linux, ok for trunk?

>> >

>> > 2018-03-24  Marek Polacek  <polacek@redhat.com>

>> >

>> >         PR c++/85032

>> >         * constexpr.c (potential_constant_expression_1): Consider conversions

>> >         from classes to literal types potentially constant.

>> >

>> >         * g++.dg/cpp0x/pr51225.C: Adjust error message.

>> >         * g++.dg/cpp1z/constexpr-if17.C: New test.

>> >

>> > diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c

>> > index bebd9f5b5d0..c4b5afe90a2 100644

>> > --- gcc/cp/constexpr.c

>> > +++ gcc/cp/constexpr.c

>> > @@ -5768,6 +5768,23 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,

>> >                       TREE_TYPE (t));

>> >           return false;

>> >         }

>> > +      /* This might be a conversion from a class to a literal type.  Let's

>> > +        consider it potentially constant since the conversion might be

>> > +        a constexpr user-defined conversion.  */

>> > +      else if (cxx_dialect >= cxx11

>> > +              && COMPLETE_TYPE_P (TREE_TYPE (t))

>> > +              && literal_type_p (TREE_TYPE (t))

>>

>> We probably need to allow dependent types here, too.  And incomplete

>> classes, which might turn out to be literal later.

>

> Ok, I've allowed incomplete types, too.  And I think the patch also allows

> dependent types.  Or did you mean using

>    && (TREE_TYPE (t) == NULL_TREE

>        || !COMPLETE_TYPE_P (TREE_TYPE (t))

>        || literal_type_p (TREE_TYPE (t)))

> ?  That doesn't seem to be needed.


I meant dependent_type_p (TREE_TYPE (t)).  I suppose checking
COMPLETE_TYPE_P will cover that by accident, but I'd prefer to make it
explicit.

> +         /* If this is a dependent type, it could end up being a class

> +            with conversions.  */

> +         if (type == NULL_TREE || WILDCARD_TYPE_P (type))

> +           return true;

> +         /* Or a non-dependent class which has conversions.  */

> +         else if (CLASS_TYPE_P (type) && TYPE_HAS_CONVERSION (type))

> +           return true;


And here, a dependent class type like A<T*> could fail both of these
tests and still end up with conversions when instantiated.  We should
check dependent_scope_p as well as TYPE_HAS_CONVERSION.

Jason
Marek Polacek April 10, 2018, 8:37 p.m. | #4
On Mon, Apr 09, 2018 at 02:18:16PM -0400, Jason Merrill wrote:
> On Fri, Apr 6, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:

> > On Mon, Mar 26, 2018 at 01:17:22PM -0400, Jason Merrill wrote:

> >> On Sat, Mar 24, 2018 at 6:59 AM, Marek Polacek <polacek@redhat.com> wrote:

> >> > Recently the code in finish_static_assert was changed to use

> >> > perform_implicit_conversion_flags followed by fold_non_dependent_expr.  That

> >> > broke this test becase when in a template, p_i_c_f merely wraps the expr in

> >> > an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to fold it to

> >> > a constant but it gave up because is_nondependent_constant_expression returned

> >> > false.  Jason suggested to fix this roughly like the following, i.e. consider

> >> > conversions from classes to literal types potentially constant.

> >> >

> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?

> >> >

> >> > 2018-03-24  Marek Polacek  <polacek@redhat.com>

> >> >

> >> >         PR c++/85032

> >> >         * constexpr.c (potential_constant_expression_1): Consider conversions

> >> >         from classes to literal types potentially constant.

> >> >

> >> >         * g++.dg/cpp0x/pr51225.C: Adjust error message.

> >> >         * g++.dg/cpp1z/constexpr-if17.C: New test.

> >> >

> >> > diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c

> >> > index bebd9f5b5d0..c4b5afe90a2 100644

> >> > --- gcc/cp/constexpr.c

> >> > +++ gcc/cp/constexpr.c

> >> > @@ -5768,6 +5768,23 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,

> >> >                       TREE_TYPE (t));

> >> >           return false;

> >> >         }

> >> > +      /* This might be a conversion from a class to a literal type.  Let's

> >> > +        consider it potentially constant since the conversion might be

> >> > +        a constexpr user-defined conversion.  */

> >> > +      else if (cxx_dialect >= cxx11

> >> > +              && COMPLETE_TYPE_P (TREE_TYPE (t))

> >> > +              && literal_type_p (TREE_TYPE (t))

> >>

> >> We probably need to allow dependent types here, too.  And incomplete

> >> classes, which might turn out to be literal later.

> >

> > Ok, I've allowed incomplete types, too.  And I think the patch also allows

> > dependent types.  Or did you mean using

> >    && (TREE_TYPE (t) == NULL_TREE

> >        || !COMPLETE_TYPE_P (TREE_TYPE (t))

> >        || literal_type_p (TREE_TYPE (t)))

> > ?  That doesn't seem to be needed.

> 

> I meant dependent_type_p (TREE_TYPE (t)).  I suppose checking

> COMPLETE_TYPE_P will cover that by accident, but I'd prefer to make it

> explicit.


Ah, ok.  I've added it, but seems like I need to keep the COMPLETE_TYPE_P
check, too, otherwise e.g. default13.C fails in literal_type_p: we have
a type that is still incomplete even after the call to complete_type.

> > +         /* If this is a dependent type, it could end up being a class

> > +            with conversions.  */

> > +         if (type == NULL_TREE || WILDCARD_TYPE_P (type))

> > +           return true;

> > +         /* Or a non-dependent class which has conversions.  */

> > +         else if (CLASS_TYPE_P (type) && TYPE_HAS_CONVERSION (type))

> > +           return true;

> 

> And here, a dependent class type like A<T*> could fail both of these

> tests and still end up with conversions when instantiated.  We should

> check dependent_scope_p as well as TYPE_HAS_CONVERSION.


Hopefully done, too.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-04-10  Marek Polacek  <polacek@redhat.com>

	PR c++/85032
	* constexpr.c (potential_constant_expression_1): Consider conversions
	from classes to literal types potentially constant.

	* g++.dg/cpp0x/pr51225.C: Adjust error message.
	* g++.dg/cpp1z/constexpr-if21.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 3cc196b4d17..75f56df4465 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5777,6 +5777,25 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 		      TREE_TYPE (t));
 	  return false;
 	}
+      /* This might be a conversion from a class to a (potentially) literal
+	 type.  Let's consider it potentially constant since the conversion
+	 might be a constexpr user-defined conversion.  */
+      else if (cxx_dialect >= cxx11
+	       && (dependent_type_p (TREE_TYPE (t))
+		   || !COMPLETE_TYPE_P (TREE_TYPE (t))
+		   || literal_type_p (TREE_TYPE (t)))
+	       && TREE_OPERAND (t, 0))
+	{
+	  tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+	  /* If this is a dependent type, it could end up being a class
+	     with conversions.  */
+	  if (type == NULL_TREE || WILDCARD_TYPE_P (type))
+	    return true;
+	  /* Or a non-dependent class which has conversions.  */
+	  else if (CLASS_TYPE_P (type)
+		   && (TYPE_HAS_CONVERSION (type) || dependent_scope_p (type)))
+	    return true;
+	}
 
       return (RECUR (TREE_OPERAND (t, 0),
 		     TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
diff --git gcc/testsuite/g++.dg/cpp0x/pr51225.C gcc/testsuite/g++.dg/cpp0x/pr51225.C
index f80bd0e778e..5b4e432f7ed 100644
--- gcc/testsuite/g++.dg/cpp0x/pr51225.C
+++ gcc/testsuite/g++.dg/cpp0x/pr51225.C
@@ -5,7 +5,7 @@ template<int> struct A {};
 
 template<typename> void foo()
 {
-  A<int(x)> a; // { dg-error "not declared|invalid type" }
+  A<int(x)> a; // { dg-error "not declared|could not convert" }
 }
 
 template<typename> struct bar
diff --git gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
index e69de29bb2d..56e108be4ad 100644
--- gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
@@ -0,0 +1,22 @@
+// PR c++/85032
+// { dg-options -std=c++17 }
+
+struct A
+{
+  constexpr operator bool () { return true; }
+  int i;
+};
+
+A a;
+
+template <class T>
+void f()
+{
+  constexpr bool b = a;
+  static_assert (a);
+}
+
+int main()
+{
+  f<int>();
+}

	Marek
Jason Merrill April 10, 2018, 11:59 p.m. | #5
Ok, thanks.

On Apr 10, 2018 4:37 PM, "Marek Polacek" <polacek@redhat.com> wrote:

On Mon, Apr 09, 2018 at 02:18:16PM -0400, Jason Merrill wrote:
> On Fri, Apr 6, 2018 at 2:17 PM, Marek Polacek <polacek@redhat.com> wrote:

> > On Mon, Mar 26, 2018 at 01:17:22PM -0400, Jason Merrill wrote:

> >> On Sat, Mar 24, 2018 at 6:59 AM, Marek Polacek <polacek@redhat.com>

wrote:
> >> > Recently the code in finish_static_assert was changed to use

> >> > perform_implicit_conversion_flags followed by

fold_non_dependent_expr.  That
> >> > broke this test becase when in a template, p_i_c_f merely wraps the

expr in
> >> > an IMPLICIT_CONV_EXPR.  fold_non_dependent_expr should be able to

fold it to
> >> > a constant but it gave up because

is_nondependent_constant_expression returned
> >> > false.  Jason suggested to fix this roughly like the following, i.e.

consider
> >> > conversions from classes to literal types potentially constant.

> >> >

> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk?

> >> >

> >> > 2018-03-24  Marek Polacek  <polacek@redhat.com>

> >> >

> >> >         PR c++/85032

> >> >         * constexpr.c (potential_constant_expression_1): Consider

conversions
> >> >         from classes to literal types potentially constant.

> >> >

> >> >         * g++.dg/cpp0x/pr51225.C: Adjust error message.

> >> >         * g++.dg/cpp1z/constexpr-if17.C: New test.

> >> >

> >> > diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c

> >> > index bebd9f5b5d0..c4b5afe90a2 100644

> >> > --- gcc/cp/constexpr.c

> >> > +++ gcc/cp/constexpr.c

> >> > @@ -5768,6 +5768,23 @@ potential_constant_expression_1 (tree t, bool

want_rval, bool strict, bool now,
> >> >                       TREE_TYPE (t));

> >> >           return false;

> >> >         }

> >> > +      /* This might be a conversion from a class to a literal

type.  Let's
> >> > +        consider it potentially constant since the conversion might

be
> >> > +        a constexpr user-defined conversion.  */

> >> > +      else if (cxx_dialect >= cxx11

> >> > +              && COMPLETE_TYPE_P (TREE_TYPE (t))

> >> > +              && literal_type_p (TREE_TYPE (t))

> >>

> >> We probably need to allow dependent types here, too.  And incomplete

> >> classes, which might turn out to be literal later.

> >

> > Ok, I've allowed incomplete types, too.  And I think the patch also

allows
> > dependent types.  Or did you mean using

> >    && (TREE_TYPE (t) == NULL_TREE

> >        || !COMPLETE_TYPE_P (TREE_TYPE (t))

> >        || literal_type_p (TREE_TYPE (t)))

> > ?  That doesn't seem to be needed.

>

> I meant dependent_type_p (TREE_TYPE (t)).  I suppose checking

> COMPLETE_TYPE_P will cover that by accident, but I'd prefer to make it

> explicit.


Ah, ok.  I've added it, but seems like I need to keep the COMPLETE_TYPE_P
check, too, otherwise e.g. default13.C fails in literal_type_p: we have
a type that is still incomplete even after the call to complete_type.


> > +         /* If this is a dependent type, it could end up being a class

> > +            with conversions.  */

> > +         if (type == NULL_TREE || WILDCARD_TYPE_P (type))

> > +           return true;

> > +         /* Or a non-dependent class which has conversions.  */

> > +         else if (CLASS_TYPE_P (type) && TYPE_HAS_CONVERSION (type))

> > +           return true;

>

> And here, a dependent class type like A<T*> could fail both of these

> tests and still end up with conversions when instantiated.  We should

> check dependent_scope_p as well as TYPE_HAS_CONVERSION.


Hopefully done, too.


Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-04-10  Marek Polacek  <polacek@redhat.com>


        PR c++/85032
        * constexpr.c (potential_constant_expression_1): Consider
conversions
        from classes to literal types potentially constant.

        * g++.dg/cpp0x/pr51225.C: Adjust error message.
        * g++.dg/cpp1z/constexpr-if21.C: New test.

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index 3cc196b4d17..75f56df4465 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5777,6 +5777,25 @@ potential_constant_expression_1 (tree t, bool
want_rval, bool strict, bool now,
                      TREE_TYPE (t));
          return false;
        }

+      /* This might be a conversion from a class to a (potentially) literal
+        type.  Let's consider it potentially constant since the conversion
+        might be a constexpr user-defined conversion.  */

+      else if (cxx_dialect >= cxx11
+              && (dependent_type_p (TREE_TYPE (t))
+                  || !COMPLETE_TYPE_P (TREE_TYPE (t))

+                  || literal_type_p (TREE_TYPE (t)))
+              && TREE_OPERAND (t, 0))
+       {
+         tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+         /* If this is a dependent type, it could end up being a class
+            with conversions.  */
+         if (type == NULL_TREE || WILDCARD_TYPE_P (type))
+           return true;
+         /* Or a non-dependent class which has conversions.  */
+         else if (CLASS_TYPE_P (type)
+                  && (TYPE_HAS_CONVERSION (type) || dependent_scope_p
(type)))

+           return true;
+       }

       return (RECUR (TREE_OPERAND (t, 0),
                     TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
diff --git gcc/testsuite/g++.dg/cpp0x/pr51225.C
gcc/testsuite/g++.dg/cpp0x/pr51225.C
index f80bd0e778e..5b4e432f7ed 100644
--- gcc/testsuite/g++.dg/cpp0x/pr51225.C
+++ gcc/testsuite/g++.dg/cpp0x/pr51225.C
@@ -5,7 +5,7 @@ template<int> struct A {};

 template<typename> void foo()
 {
-  A<int(x)> a; // { dg-error "not declared|invalid type" }
+  A<int(x)> a; // { dg-error "not declared|could not convert" }
 }

 template<typename> struct bar
diff --git gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
index e69de29bb2d..56e108be4ad 100644
--- gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-if21.C

@@ -0,0 +1,22 @@
+// PR c++/85032
+// { dg-options -std=c++17 }
+
+struct A
+{
+  constexpr operator bool () { return true; }
+  int i;
+};
+
+A a;
+
+template <class T>
+void f()
+{
+  constexpr bool b = a;
+  static_assert (a);
+}
+
+int main()
+{
+  f<int>();
+}

        Marek

Patch

diff --git gcc/cp/constexpr.c gcc/cp/constexpr.c
index bebd9f5b5d0..c4b5afe90a2 100644
--- gcc/cp/constexpr.c
+++ gcc/cp/constexpr.c
@@ -5768,6 +5768,23 @@  potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
 		      TREE_TYPE (t));
 	  return false;
 	}
+      /* This might be a conversion from a class to a literal type.  Let's
+	 consider it potentially constant since the conversion might be
+	 a constexpr user-defined conversion.  */
+      else if (cxx_dialect >= cxx11
+	       && COMPLETE_TYPE_P (TREE_TYPE (t))
+	       && literal_type_p (TREE_TYPE (t))
+	       && TREE_OPERAND (t, 0))
+	{
+	  tree type = TREE_TYPE (TREE_OPERAND (t, 0));
+	  /* If this is a dependent type, it could end up being a class
+	     with conversions.  */
+	  if (type == NULL_TREE || WILDCARD_TYPE_P (type))
+	    return true;
+	  /* Or a non-dependent class which has conversions.  */
+	  else if (CLASS_TYPE_P (type) && TYPE_HAS_CONVERSION (type))
+	    return true;
+	}
 
       return (RECUR (TREE_OPERAND (t, 0),
 		     TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE));
diff --git gcc/testsuite/g++.dg/cpp0x/pr51225.C gcc/testsuite/g++.dg/cpp0x/pr51225.C
index f80bd0e778e..5b4e432f7ed 100644
--- gcc/testsuite/g++.dg/cpp0x/pr51225.C
+++ gcc/testsuite/g++.dg/cpp0x/pr51225.C
@@ -5,7 +5,7 @@  template<int> struct A {};
 
 template<typename> void foo()
 {
-  A<int(x)> a; // { dg-error "not declared|invalid type" }
+  A<int(x)> a; // { dg-error "not declared|could not convert" }
 }
 
 template<typename> struct bar
diff --git gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
index e69de29bb2d..56e108be4ad 100644
--- gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
+++ gcc/testsuite/g++.dg/cpp1z/constexpr-if17.C
@@ -0,0 +1,22 @@ 
+// PR c++/85032
+// { dg-options -std=c++17 }
+
+struct A
+{
+  constexpr operator bool () { return true; }
+  int i;
+};
+
+A a;
+
+template <class T>
+void f()
+{
+  constexpr bool b = a;
+  static_assert (a);
+}
+
+int main()
+{
+  f<int>();
+}