On Fri, Apr 05, 2019 at 12:12:11AM -0400, Jason Merrill wrote: > On 4/4/19 5:18 PM, Marek Polacek wrote: > > On Thu, Mar 28, 2019 at 03:54:30PM -0400, Jason Merrill wrote: > > > On 3/20/19 4:12 PM, Marek Polacek wrote: > > > > 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. > > > > > > Yeah, we shouldn't be preserving lower level codes like this ADDR_EXPR; we > > > should probably return an IMPLICIT_CONV_EXPR rather than make the call > > > explicit. > > > > I'm having trouble with this. Do we want > > build_converted_constant_expr_internal > > to build an IMPLICIT_CONV_EXPR in a template, much like > > perform_implicit_conversion? That seems to break a lot of stuff, and I'm > > nervous about that at this stage :/ We could probably handle this specially > > in convert_nontype_argument. Maybe build an IMPLICIT_CONV_EXPR for > > value-dependent CONSTRUCTORs? > > That sounds reasonable.
Great, thanks. Something like this, then? Bootstrapped/regtested on x86_64-linux, ok for trunk? 2019-04-05 Marek Polacek <pola...@redhat.com> PR c++/87145 - bogus error converting class type in template arg list. * pt.c (convert_nontype_argument): Don't call build_converted_constant_expr if it could involve calling a conversion function with a instantiation-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 40d954d1e8a..f8001317bda 100644 --- gcc/cp/pt.c +++ gcc/cp/pt.c @@ -6837,6 +6837,19 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain) else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type) || cxx_dialect >= cxx17) { + /* Calling build_converted_constant_expr might create a call to + a conversion function with a value-dependent argument, which + could invoke taking the address of a temporary representing + the result of the conversion. */ + if (COMPOUND_LITERAL_P (expr) + && CONSTRUCTOR_IS_DEPENDENT (expr) + && MAYBE_CLASS_TYPE_P (expr_type) + && TYPE_HAS_CONVERSION (expr_type)) + { + expr = build1 (IMPLICIT_CONV_EXPR, type, expr); + IMPLICIT_CONV_EXPR_NONTYPE_ARG (expr) = true; + return expr; + } /* C++17: A template-argument for a non-type template-parameter shall be a converted constant expression (8.20) of the type of the template-parameter. */ 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>(); +}