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

Reply via email to