Ping. On Wed, Mar 20, 2019 at 04:12:13PM -0400, 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. > > 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>(); > +}
Marek