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 <[email protected]>
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>();
+}