Ok, thanks. On Apr 10, 2018 4:37 PM, "Marek Polacek" <pola...@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 <pola...@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 <pola...@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 <pola...@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 <pola...@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