The fix for 77656 caused us to call convert_nontype_argument even for value-dependent arguments, to perform the conversion in order to avoid a bogus warning.
In this case, the argument is Pod{N}. The call to build_converted_constant_expr in convert_nontype_argument produces Pod::operator Enum(&{N}). It doesn't crash because we're in a template and build_address no longer crashes on CONSTRUCTORs in a template. Then when instantiating the function foo we substitute its argument: &{N}. So we're in tsubst_copy_and_build/ADDR_EXPR. The call to tsubst_non_call_postfix_expression turns {N} into TARGET_EXPR <D.2329, {.val=2}>. Then build_x_unary_op is supposed to put the ADDR_EXPR back. It calls cp_build_addr_expr_strict. But it's *strict*, so the prvalue of class type TARGET_EXPR <D.2329, {.val=2}> isn't allowed -> error. It's _strict since <https://gcc.gnu.org/ml/gcc-patches/2010-09/msg02144.html>, that seem like a desirable change, and we had a warning for taking the address of a TARGET_EXPR in build_x_unary_op even before that. So rather than messing with _strict, let's avoid this scenario altogether. I checked whether we have a case in the testsuite that results in convert_like getting a value-dependent CONSTRUCTOR, but found none. With this patch, we avoid it, and only call convert_nontype_argument after substitution, at which point maybe_constant_value will be able to evaluate the conversion to a constant. This problem doesn't occur when passing Pod{N} as an argument to a function, or using it as an array dimension; seems we avoid converting the argument if it's value-dependent. Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-03-20 Marek Polacek <pola...@redhat.com> PR c++/87145 - bogus error converting class type in template arg list. * pt.c (convert_template_argument): Don't call convert_nontype_argument if it could involve calling a conversion function with a value-dependent constructor as its argument. * g++.dg/cpp0x/constexpr-conv3.C: New test. * g++.dg/cpp0x/constexpr-conv4.C: New test. diff --git gcc/cp/pt.c gcc/cp/pt.c index 0acc16d1b92..6878583d99b 100644 --- gcc/cp/pt.c +++ gcc/cp/pt.c @@ -8056,7 +8056,16 @@ convert_template_argument (tree parm, t = canonicalize_type_argument (t, complain); if (!type_dependent_expression_p (orig_arg) - && !uses_template_parms (t)) + && !uses_template_parms (t) + /* This might trigger calling a conversion function with + a value-dependent argument, which could invoke taking + the address of a temporary representing the result of + the conversion. */ + && !(COMPOUND_LITERAL_P (orig_arg) + && MAYBE_CLASS_TYPE_P (TREE_TYPE (orig_arg)) + && TYPE_HAS_CONVERSION (TREE_TYPE (orig_arg)) + && INTEGRAL_OR_ENUMERATION_TYPE_P (t) + && value_dependent_expression_p (orig_arg))) /* We used to call digest_init here. However, digest_init will report errors, which we don't want when complain is zero. More importantly, digest_init will try too @@ -8092,7 +8101,7 @@ convert_template_argument (tree parm, && TREE_CODE (TREE_TYPE (innertype)) == FUNCTION_TYPE && TREE_OPERAND_LENGTH (inner) > 0 && reject_gcc_builtin (TREE_OPERAND (inner, 0))) - return error_mark_node; + return error_mark_node; } if (TREE_CODE (val) == SCOPE_REF) diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-conv3.C gcc/testsuite/g++.dg/cpp0x/constexpr-conv3.C new file mode 100644 index 00000000000..3f47c58cd2a --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/constexpr-conv3.C @@ -0,0 +1,25 @@ +// PR c++/87145 +// { dg-do compile { target c++11 } } + +template<typename T, T t> struct integral_constant { + static constexpr T value = t; +}; + +enum class Enum : unsigned {}; + +struct Pod { + unsigned val; + + constexpr operator Enum() const { + return static_cast<Enum>(val); + } +}; + +template<unsigned N> +constexpr void foo() { + using Foo = integral_constant<Enum, Pod{N}>; +} + +int main() { + foo<2>(); +} diff --git gcc/testsuite/g++.dg/cpp0x/constexpr-conv4.C gcc/testsuite/g++.dg/cpp0x/constexpr-conv4.C new file mode 100644 index 00000000000..f4e3f00a585 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/constexpr-conv4.C @@ -0,0 +1,25 @@ +// PR c++/87145 +// { dg-do compile { target c++11 } } + +struct S { + int val; + + constexpr operator int() const { + return static_cast<int>(val); + } +}; + +template<int N> +struct F { }; + +template<unsigned N> +constexpr void foo() { + F<int{N}> f; + F<S{N}> f2; +} + +int +main() +{ + foo<2>(); +}