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)) + && 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>(); +} Marek