diff mbox

C++ PATCH for c++/79960, partial ordering with alias template

Message ID CADzB+2n69Po5r0G5=Qdee06KkgoGzX2DamMQF9kz8NEp6GBopA@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill March 10, 2017, 5:35 p.m. UTC
The semantics of alias templates are still pretty unclear, but this
testcase looks like it ought to work.  I decided to make it work by
treating partial ordering specially; while normally a use of a
non-transparent alias template compares as distinct from its
expansion, as necessary for proper redeclaration handling, when
comparing the result of deduction and substitution to our goal we
can't be so strict.  In this testcase, we end up comparing

const __has_tuple_size<volatile __has_tuple_size <T>>

to

const volatile __has_tuple_size<T>

which are not the same for SFINAE, but let's treat them the same for ordering.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 2599ce3daf721917b52f4a7c6c6ee1098907a800
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 10 00:57:04 2017 -0500

            PR c++/79960 - alias templates and partial ordering
    
            * pt.c (comp_template_args): Add partial_order parm.
            (template_args_equal): Likewise.
            (comp_template_args_porder): New.
            (get_partial_spec_bindings): Use it.
diff mbox

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 68f2722..5be5dfe 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6208,8 +6208,8 @@  extern int is_specialization_of			(tree, tree);
 extern bool is_specialization_of_friend		(tree, tree);
 extern tree get_pattern_parm			(tree, tree);
 extern int comp_template_args			(tree, tree, tree * = NULL,
-						 tree * = NULL);
-extern int template_args_equal                  (tree, tree);
+						 tree * = NULL, bool = false);
+extern int template_args_equal                  (tree, tree, bool = false);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
 extern void print_candidates			(tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 416f132..b8ce9fe 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -8240,7 +8240,7 @@  coerce_innermost_template_parms (tree parms,
 /* Returns 1 if template args OT and NT are equivalent.  */
 
 int
-template_args_equal (tree ot, tree nt)
+template_args_equal (tree ot, tree nt, bool partial_order /* = false */)
 {
   if (nt == ot)
     return 1;
@@ -8288,8 +8288,13 @@  template_args_equal (tree ot, tree nt)
 	 template argument; we need them to be distinct so that we
 	 substitute into the specialization arguments at instantiation
 	 time.  And aliases can't be equivalent without being ==, so
-	 we don't need to look any deeper.  */
-      if (TYPE_ALIAS_P (nt) || TYPE_ALIAS_P (ot))
+	 we don't need to look any deeper.
+
+         During partial ordering, however, we need to treat them normally so
+         that we can order uses of the same alias with different
+         cv-qualification (79960).  */
+      if (!partial_order
+	  && (TYPE_ALIAS_P (nt) || TYPE_ALIAS_P (ot)))
 	return false;
       else
 	return same_type_p (ot, nt);
@@ -8321,7 +8326,8 @@  template_args_equal (tree ot, tree nt)
 
 int
 comp_template_args (tree oldargs, tree newargs,
-		    tree *oldarg_ptr, tree *newarg_ptr)
+		    tree *oldarg_ptr, tree *newarg_ptr,
+		    bool partial_order)
 {
   int i;
 
@@ -8339,7 +8345,7 @@  comp_template_args (tree oldargs, tree newargs,
       tree nt = TREE_VEC_ELT (newargs, i);
       tree ot = TREE_VEC_ELT (oldargs, i);
 
-      if (! template_args_equal (ot, nt))
+      if (! template_args_equal (ot, nt, partial_order))
 	{
 	  if (oldarg_ptr != NULL)
 	    *oldarg_ptr = ot;
@@ -8351,6 +8357,12 @@  comp_template_args (tree oldargs, tree newargs,
   return 1;
 }
 
+inline bool
+comp_template_args_porder (tree oargs, tree nargs)
+{
+  return comp_template_args (oargs, nargs, NULL, NULL, true);
+}
+
 static void
 add_pending_template (tree d)
 {
@@ -21584,8 +21596,8 @@  get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
   if (spec_args == error_mark_node
       /* We only need to check the innermost arguments; the other
 	 arguments will always agree.  */
-      || !comp_template_args (INNERMOST_TEMPLATE_ARGS (spec_args),
-			      INNERMOST_TEMPLATE_ARGS (args)))
+      || !comp_template_args_porder (INNERMOST_TEMPLATE_ARGS (spec_args),
+				     INNERMOST_TEMPLATE_ARGS (args)))
     return NULL_TREE;
 
   /* Now that we have bindings for all of the template arguments,
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-57.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-57.C
new file mode 100644
index 0000000..f257e62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-57.C
@@ -0,0 +1,30 @@ 
+// PR c++/79960
+// { dg-do compile { target c++11 } }
+
+using size_t = decltype(sizeof(0));
+
+template<typename T> struct tuple_size;
+
+template<typename T, size_t U = tuple_size<T>::value>
+  using __has_tuple_size = T;
+
+template<typename T> struct tuple_size<const __has_tuple_size<T>> {
+  static constexpr size_t value = tuple_size<T>::value;
+};
+
+template<typename T> struct tuple_size<volatile __has_tuple_size<T>> {
+  static constexpr size_t value = tuple_size<T>::value;
+};
+
+template<typename T> struct tuple_size<const __has_tuple_size<volatile T>> {
+  static constexpr size_t value = tuple_size<T>::value;
+};
+
+template<typename... T> struct tuple { };
+template<typename... T> struct tuple_size<tuple<T...>> {
+  static constexpr size_t value = sizeof...(T);
+};
+
+static_assert( tuple_size<const tuple<>>::value == 0, "" );  // OK
+static_assert( tuple_size<volatile tuple<>>::value == 0, "" ); // OK
+static_assert( tuple_size<const volatile tuple<>>::value == 0, "" ); // FAIL