The comment removed by this patch asserts that we can't see a VAR_DECL
in unify, because any use of a variable as a template argument will have
been adjusted to be either its constant value or its address. But that
isn't actually true when the type of the non-type template parameter
depends on a type template argument, so we need to adjust based on what
we end up getting.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit fb06c19fb2adc8d69e924db2072437904a4e9c58
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Jan 19 12:09:17 2016 -0500
PR c++/59759
* pt.c (convert_template_argument): Handle VAR_DECL properly.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 866b4b1..9305e1d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -19923,11 +19923,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
return unify_template_argument_mismatch (explain_p, parm, arg);
case VAR_DECL:
- /* A non-type template parameter that is a variable should be a
- an integral constant, in which case, it whould have been
- folded into its (constant) value. So we should not be getting
- a variable here. */
- gcc_unreachable ();
+ /* We might get a variable as a non-type template argument in parm if the
+ corresponding parameter is type-dependent. Make any necessary
+ adjustments based on whether arg is a reference. */
+ if (CONSTANT_CLASS_P (arg))
+ parm = fold_non_dependent_expr (parm);
+ else if (REFERENCE_REF_P (arg))
+ {
+ tree sub = TREE_OPERAND (arg, 0);
+ STRIP_NOPS (sub);
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ arg = TREE_OPERAND (sub, 0);
+ }
+ /* Now use the normal expression code to check whether they match. */
+ goto expr;
case TYPE_ARGUMENT_PACK:
case NONTYPE_ARGUMENT_PACK:
@@ -19960,7 +19969,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
if (is_overloaded_fn (parm) || type_unknown_p (parm))
return unify_success (explain_p);
gcc_assert (EXPR_P (parm));
-
+ expr:
/* We must be looking at an expression. This can happen with
something like:
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default6.C b/gcc/testsuite/g++.dg/cpp0x/temp_default6.C
new file mode 100644
index 0000000..10cde2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default6.C
@@ -0,0 +1,27 @@
+// PR c++/59759
+// { dg-do compile { target c++11 } }
+
+namespace std {
+template <typename _Tp>
+struct B {
+ static constexpr _Tp value = 0;
+};
+typedef B<int> false_type;
+struct C : false_type {};
+template <typename>
+struct is_integral : C {};
+template <int, typename _Tp>
+struct enable_if {
+ typedef _Tp type;
+};
+}
+enum class enabled;
+extern constexpr enabled dummy{};
+template <typename T, typename std::enable_if<std::is_integral<T>::value,
+ T>::type = dummy>
+class A;
+template <typename T>
+void f(A<const T&>*) {
+ A<const enabled&>* map;
+ f(map);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default7.C b/gcc/testsuite/g++.dg/cpp0x/temp_default7.C
new file mode 100644
index 0000000..c517aad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default7.C
@@ -0,0 +1,27 @@
+// PR c++/59759
+// { dg-do compile { target c++11 } }
+
+namespace std {
+template <typename _Tp>
+struct B {
+ static constexpr _Tp value = 0;
+};
+typedef B<int> false_type;
+struct C : false_type {};
+template <typename>
+struct is_integral : C {};
+template <int, typename _Tp>
+struct enable_if {
+ typedef _Tp type;
+};
+}
+enum class enabled;
+constexpr enabled dummy{};
+template <typename T, typename std::enable_if<std::is_integral<T>::value,
+ enabled>::type = dummy>
+class A;
+template <typename T>
+void f(A<T>*) {
+ A<int>* map;
+ f(map);
+}