cp-tree.h (unification_kind_t): Add DEDUCE_ORDER.
authorNathan Sidwell <nathan@codesourcery.com>
Mon, 22 Jan 2001 13:51:43 +0000 (13:51 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Mon, 22 Jan 2001 13:51:43 +0000 (13:51 +0000)
cp:
* cp-tree.h (unification_kind_t): Add DEDUCE_ORDER.
(more_specialized): Add deduction parameter.
* call.c (joust): Adjust more_specialized call.
* pt.c (UNIFY_ALLOW_OUTER_MORE_CV_QUAL,
UNIFY_ALLOW_OUTER_LESS_CV_QUAL): New unify flags.
(get_bindings_order): Remove.
(get_bindings_real): Add DEDUCE parameter.
(maybe_adjust_types_for_deduction): Return extra unify flags. Do
REFERENCE_TYPE jig for DEDUCE_ORDER.
(type_unification_real): Deal with DEDUCE_ORDER. Use result of
maybe_adjust_types_for_deduction.
(more_specialized): Add DEDUCE parameter. Call get_bindings_real
directly.
(try_one_overload): Use result of maybe_adjust_types_for_deduction.
(check_cv_quals_for_unify): Use new unify qualifier flags.
(unify): Clear new unify qualifier flags.
(get_bindings_real): Add DEDUCE parameter.
(get_bindings): Adjust call to get_bindings_real.
(get_bindings_overload): Likewise.
(most_specialized_instantiation): Adjust call to
more_specialized.
testsuite:
* g++.old-deja/g++.martin/sts_partial.C: Remove XFAIL.
* g++.old-deja/g++.pt/spec35.C: New test.
* g++.old-deja/g++.pt/spec36.C: New test.

From-SVN: r39182

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C
gcc/testsuite/g++.old-deja/g++.pt/spec35.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.pt/spec36.C [new file with mode: 0644]

index 79274281bed0530619d7d532c458cb6e34cc406d..3374dd2e268f0b2ba7b1a4c027ff53a2c35deea6 100644 (file)
@@ -1,3 +1,27 @@
+2001-01-22  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * cp-tree.h (unification_kind_t): Add DEDUCE_ORDER.
+       (more_specialized): Add deduction parameter.
+       * call.c (joust): Adjust more_specialized call.
+       * pt.c (UNIFY_ALLOW_OUTER_MORE_CV_QUAL,
+       UNIFY_ALLOW_OUTER_LESS_CV_QUAL): New unify flags.
+       (get_bindings_order): Remove.
+       (get_bindings_real): Add DEDUCE parameter.
+       (maybe_adjust_types_for_deduction): Return extra unify flags. Do
+       REFERENCE_TYPE jig for DEDUCE_ORDER.
+       (type_unification_real): Deal with DEDUCE_ORDER. Use result of
+       maybe_adjust_types_for_deduction.
+       (more_specialized): Add DEDUCE parameter. Call get_bindings_real
+       directly.
+       (try_one_overload): Use result of maybe_adjust_types_for_deduction.
+       (check_cv_quals_for_unify): Use new unify qualifier flags.
+       (unify): Clear new unify qualifier flags.
+       (get_bindings_real): Add DEDUCE parameter.
+       (get_bindings): Adjust call to get_bindings_real.
+       (get_bindings_overload): Likewise.
+       (most_specialized_instantiation): Adjust call to
+       more_specialized.
+
 2001-01-19  Jason Merrill  <jason@redhat.com>
 
        * decl2.c (flag_vtable_thunks): Also depend on ENABLE_NEW_GXX_ABI.
index e3613ee72653d57bdf1da813d4a608584d66d470..fa5a50803bf0a31215bf9802e21e44d8dfb70492 100644 (file)
@@ -5196,6 +5196,7 @@ joust (cand1, cand2, warn)
   else if (cand1->template && cand2->template)
     winner = more_specialized
       (TI_TEMPLATE (cand1->template), TI_TEMPLATE (cand2->template),
+       DEDUCE_ORDER,
        /* Never do unification on the 'this' parameter.  */
        TREE_VEC_LENGTH (cand1->convs)
        - DECL_NONSTATIC_MEMBER_FUNCTION_P (cand1->fn));
index 1df938b814dd5af7f3f265f5aaffa23a80773c79..8122d566697b02e262288faed356a23582a6b1b8 100644 (file)
@@ -3209,14 +3209,15 @@ extern int function_depth;
 
 /* in pt.c  */
 
-/* These values are used for the `STRICT' parameter to type_unfication and
+/* These values are used for the `STRICT' parameter to type_unification and
    fn_type_unification.  Their meanings are described with the
    documentation for fn_type_unification.  */
 
 typedef enum unification_kind_t {
   DEDUCE_CALL,
   DEDUCE_CONV,
-  DEDUCE_EXACT
+  DEDUCE_EXACT,
+  DEDUCE_ORDER
 } unification_kind_t;
 
 /* Macros for operating on a template instantation level node, represented
@@ -4143,7 +4144,7 @@ extern tree instantiate_template          PARAMS ((tree, tree));
 extern int fn_type_unification                  PARAMS ((tree, tree, tree, tree, tree, unification_kind_t, int));
 extern tree tinst_for_decl                     PARAMS ((void));
 extern void mark_decl_instantiated             PARAMS ((tree, int));
-extern int more_specialized                    PARAMS ((tree, tree, int));
+extern int more_specialized                    PARAMS ((tree, tree, int, int));
 extern void mark_class_instantiated            PARAMS ((tree, int));
 extern void do_decl_instantiation              PARAMS ((tree, tree, tree));
 extern void do_type_instantiation              PARAMS ((tree, tree, int));
index cf3b52d33e2304ddcaf588b21bf88ccfaa40268d..184edf846f9d255e87a13893e6c44962c97feb0f 100644 (file)
@@ -87,6 +87,8 @@ static htab_t local_specializations;
 #define UNIFY_ALLOW_DERIVED 4
 #define UNIFY_ALLOW_INTEGER 8
 #define UNIFY_ALLOW_OUTER_LEVEL 16
+#define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32
+#define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64
 
 #define GTB_VIA_VIRTUAL 1 /* The base class we are examining is
                             virtual, or a base class of a virtual
@@ -111,7 +113,7 @@ static tree coerce_template_parms PARAMS ((tree, tree, tree, int, int));
 static void tsubst_enum        PARAMS ((tree, tree, tree));
 static tree add_to_template_args PARAMS ((tree, tree));
 static tree add_outermost_template_args PARAMS ((tree, tree));
-static void maybe_adjust_types_for_deduction PARAMS ((unification_kind_t, tree*,
+static int maybe_adjust_types_for_deduction PARAMS ((unification_kind_t, tree*,
                                                    tree*)); 
 static int  type_unification_real PARAMS ((tree, tree, tree, tree,
                                         int, unification_kind_t, int, int));
@@ -121,7 +123,6 @@ static tree convert_nontype_argument PARAMS ((tree, tree));
 static tree convert_template_argument PARAMS ((tree, tree, tree, int,
                                              int , tree));
 static tree get_bindings_overload PARAMS ((tree, tree, tree));
-static tree get_bindings_order PARAMS ((tree, tree, int));
 static int for_each_template_parm PARAMS ((tree, tree_fn_t, void*));
 static tree build_template_parm_index PARAMS ((int, int, int, tree, tree));
 static int inline_needs_template_parms PARAMS ((tree));
@@ -136,7 +137,7 @@ static tree build_template_decl PARAMS ((tree, tree));
 static int mark_template_parm PARAMS ((tree, void *));
 static tree tsubst_friend_function PARAMS ((tree, tree));
 static tree tsubst_friend_class PARAMS ((tree, tree));
-static tree get_bindings_real PARAMS ((tree, tree, tree, int, int));
+static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int));
 static int template_decl_level PARAMS ((tree));
 static tree maybe_get_template_decl_from_type_decl PARAMS ((tree));
 static int check_cv_quals_for_unify PARAMS ((int, tree, tree));
@@ -7681,13 +7682,15 @@ instantiate_template (tmpl, targ_ptr)
      [temp.deduct.conv].
 
    DEDUCE_EXACT:
+     We are deducing arguments when doing an explicit instantiation
+     as in [temp.explicit], when determining an explicit specialization
+     as in [temp.expl.spec], or when taking the address of a function
+     template, as in [temp.deduct.funcaddr]. 
+
+   DEDUCE_ORDER:
      We are deducing arguments when calculating the partial
      ordering between specializations of function or class
-     templates, as in [temp.func.order] and [temp.class.order],
-     when doing an explicit instantiation as in [temp.explicit],
-     when determining an explicit specialization as in
-     [temp.expl.spec], or when taking the address of a function
-     template, as in [temp.deduct.funcaddr]. 
+     templates, as in [temp.func.order] and [temp.class.order].
 
    LEN is the number of parms to consider before returning success, or -1
    for all.  This is used in partial ordering to avoid comparing parms for
@@ -7793,12 +7796,14 @@ fn_type_unification (fn, explicit_targs, targs, args, return_type,
    the argument passed to the call, or the type of the value
    initialized with the result of the conversion function.  */
 
-static void
+static int
 maybe_adjust_types_for_deduction (strict, parm, arg)
      unification_kind_t strict;
      tree* parm;
      tree* arg;
 {
+  int result = 0;
+  
   switch (strict)
     {
     case DEDUCE_CALL:
@@ -7817,8 +7822,43 @@ maybe_adjust_types_for_deduction (strict, parm, arg)
 
     case DEDUCE_EXACT:
       /* There is nothing to do in this case.  */
-      return;
+      return 0;
 
+    case DEDUCE_ORDER:
+      /* DR 214. [temp.func.order] is underspecified, and leads to no
+         ordering between things like `T *' and `T const &' for `U *'.
+         The former has T=U and the latter T=U*. The former looks more
+         specialized and John Spicer considers it well-formed (the EDG
+         compiler accepts it).
+
+         John also confirms that deduction should proceed as in a function
+         call. Which implies the usual ARG and PARM bashing as DEDUCE_CALL.
+         However, in ordering, ARG can have REFERENCE_TYPE, but no argument
+         to an actual call can have such a type.
+         
+         When deducing against a REFERENCE_TYPE, we can either not change
+         PARM's type, or we can change ARG's type too. The latter, though
+         seemingly more safe, turns out to give the following quirk. Consider
+         deducing a call to a `const int *' with the following template 
+         function parameters 
+           #1; T const *const &   ; T = int
+           #2; T *const &         ; T = const int
+           #3; T *                ; T = const int
+         It looks like #1 is the more specialized.  Taken pairwise, #1 is
+         more specialized than #2 and #2 is more specialized than #3, yet
+         there is no ordering between #1 and #3.
+         
+         So, if ARG is a reference, we look though it when PARM is
+         not a refence. When both are references we don't change either.  */
+      if (TREE_CODE (*arg) == REFERENCE_TYPE)
+        {
+          if (TREE_CODE (*parm) == REFERENCE_TYPE)
+            return 0;
+          *arg = TREE_TYPE (*arg);
+          result |= UNIFY_ALLOW_OUTER_LESS_CV_QUAL;
+          goto skip_arg;
+        }
+      break;
     default:
       my_friendly_abort (0);
     }
@@ -7849,6 +7889,7 @@ maybe_adjust_types_for_deduction (strict, parm, arg)
        *arg = TYPE_MAIN_VARIANT (*arg);
     }
   
+  skip_arg:;
   /* [temp.deduct.call]
      
      If P is a cv-qualified type, the top level cv-qualifiers
@@ -7857,7 +7898,11 @@ maybe_adjust_types_for_deduction (strict, parm, arg)
      type deduction.  */
   *parm = TYPE_MAIN_VARIANT (*parm);
   if (TREE_CODE (*parm) == REFERENCE_TYPE)
-    *parm = TREE_TYPE (*parm);
+    {
+      *parm = TREE_TYPE (*parm);
+      result |= UNIFY_ALLOW_OUTER_MORE_CV_QUAL;
+    }
+  return result;
 }
 
 /* Most parms like fn_type_unification.
@@ -7902,6 +7947,10 @@ type_unification_real (tparms, targs, parms, args, subr,
     case DEDUCE_EXACT:
       sub_strict = UNIFY_ALLOW_NONE;
       break;
+    
+    case DEDUCE_ORDER:
+      sub_strict = UNIFY_ALLOW_NONE;
+      break;
       
     default:
       my_friendly_abort (0);
@@ -7943,7 +7992,7 @@ type_unification_real (tparms, targs, parms, args, subr,
              arg = NULL_TREE;
            }
 
-         if (strict == DEDUCE_EXACT)
+         if (strict == DEDUCE_EXACT || strict == DEDUCE_ORDER)
            {
              if (same_type_p (parm, type))
                continue;
@@ -7976,12 +8025,16 @@ type_unification_real (tparms, targs, parms, args, subr,
            }
          arg = TREE_TYPE (arg);
        }
+      
+      {
+        int arg_strict = sub_strict;
+        
+        if (!subr)
+         arg_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
 
-      if (!subr)
-       maybe_adjust_types_for_deduction (strict, &parm, &arg);
-
-      if (unify (tparms, targs, parm, arg, sub_strict))
-        return 1;
+        if (unify (tparms, targs, parm, arg, arg_strict))
+          return 1;
+      }
 
       /* Are we done with the interesting parms?  */
       if (--len == 0)
@@ -8129,7 +8182,7 @@ try_one_overload (tparms, orig_targs, targs, parm, arg, strict,
   if (uses_template_parms (arg))
     return 1;
 
-  maybe_adjust_types_for_deduction (strict, &parm, &arg);
+  sub_strict |= maybe_adjust_types_for_deduction (strict, &parm, &arg);
 
   /* We don't copy orig_targs for this because if we have already deduced
      some template args from previous args, unify would complain when we
@@ -8413,11 +8466,11 @@ check_cv_quals_for_unify (strict, arg, parm)
      tree arg;
      tree parm;
 {
-  if (!(strict & UNIFY_ALLOW_MORE_CV_QUAL)
+  if (!(strict & (UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_OUTER_MORE_CV_QUAL))
       && !at_least_as_qualified_p (arg, parm))
     return 0;
 
-  if (!(strict & UNIFY_ALLOW_LESS_CV_QUAL)
+  if (!(strict & (UNIFY_ALLOW_LESS_CV_QUAL | UNIFY_ALLOW_OUTER_LESS_CV_QUAL))
       && !at_least_as_qualified_p (parm, arg))
     return 0;
 
@@ -8448,7 +8501,13 @@ check_cv_quals_for_unify (strict, arg, parm)
        have const qualified pointers leading up to the inner type which
        requires additional CV quals, except at the outer level, where const
        is not required [conv.qual]. It would be normal to set this flag in
-       addition to setting UNIFY_ALLOW_MORE_CV_QUAL.  */
+       addition to setting UNIFY_ALLOW_MORE_CV_QUAL.
+     UNIFY_ALLOW_OUTER_MORE_CV_QUAL:
+       This is the outermost level of a deduction, and PARM can be more CV
+       qualified at this point.
+     UNIFY_ALLOW_OUTER_LESS_CV_QUAL:
+       This is the outermost level of a deduction, and PARM can be less CV
+       qualified at this point.  */
 
 static int
 unify (tparms, targs, parm, arg, strict)
@@ -8498,6 +8557,8 @@ unify (tparms, targs, parm, arg, strict)
     strict &= ~UNIFY_ALLOW_MORE_CV_QUAL;
   strict &= ~UNIFY_ALLOW_OUTER_LEVEL;
   strict &= ~UNIFY_ALLOW_DERIVED;
+  strict &= ~UNIFY_ALLOW_OUTER_MORE_CV_QUAL;
+  strict &= ~UNIFY_ALLOW_OUTER_LESS_CV_QUAL;
   
   switch (TREE_CODE (parm))
     {
@@ -8963,6 +9024,8 @@ mark_decl_instantiated (result, extern_p)
 
 /* Given two function templates PAT1 and PAT2, return:
 
+   DEDUCE should be DEDUCE_EXACT or DEDUCE_ORDER.
+   
    1 if PAT1 is more specialized than PAT2 as described in [temp.func.order].
    -1 if PAT2 is more specialized than PAT1.
    0 if neither is more specialized.
@@ -8970,18 +9033,21 @@ mark_decl_instantiated (result, extern_p)
    LEN is passed through to fn_type_unification.  */
    
 int
-more_specialized (pat1, pat2, len)
+more_specialized (pat1, pat2, deduce, len)
      tree pat1, pat2;
+     int deduce;
      int len;
 {
   tree targs;
   int winner = 0;
 
-  targs = get_bindings_order (pat1, DECL_TEMPLATE_RESULT (pat2), len);
+  targs = get_bindings_real (pat1, DECL_TEMPLATE_RESULT (pat2),
+                             NULL_TREE, 0, deduce, len);
   if (targs)
     --winner;
 
-  targs = get_bindings_order (pat2, DECL_TEMPLATE_RESULT (pat1), len);
+  targs = get_bindings_real (pat2, DECL_TEMPLATE_RESULT (pat1),
+                             NULL_TREE, 0, deduce, len);
   if (targs)
     ++winner;
 
@@ -9018,12 +9084,12 @@ more_specialized_class (pat1, pat2)
    DECL from the function template FN, with the explicit template
    arguments EXPLICIT_ARGS.  If CHECK_RETTYPE is 1, the return type must
    also match.  Return NULL_TREE if no satisfactory arguments could be
-   found.  LEN is passed through to fn_type_unification.  */
+   found.  DEDUCE and LEN are passed through to fn_type_unification.  */
    
 static tree
-get_bindings_real (fn, decl, explicit_args, check_rettype, len)
+get_bindings_real (fn, decl, explicit_args, check_rettype, deduce, len)
      tree fn, decl, explicit_args;
-     int check_rettype, len;
+     int check_rettype, deduce, len;
 {
   int ntparms = DECL_NTPARMS (fn);
   tree targs = make_tree_vec (ntparms);
@@ -9069,7 +9135,7 @@ get_bindings_real (fn, decl, explicit_args, check_rettype, len)
                           decl_arg_types,
                           (check_rettype || DECL_CONV_FN_P (fn)
                            ? TREE_TYPE (decl_type) : NULL_TREE),
-                          DEDUCE_EXACT, len);
+                          deduce, len);
 
   if (i != 0)
     return NULL_TREE;
@@ -9083,7 +9149,7 @@ tree
 get_bindings (fn, decl, explicit_args)
      tree fn, decl, explicit_args;
 {
-  return get_bindings_real (fn, decl, explicit_args, 1, -1);
+  return get_bindings_real (fn, decl, explicit_args, 1, DEDUCE_EXACT, -1);
 }
 
 /* But for resolve_overloaded_unification, we only care about the parameter
@@ -9093,17 +9159,7 @@ static tree
 get_bindings_overload (fn, decl, explicit_args)
      tree fn, decl, explicit_args;
 {
-  return get_bindings_real (fn, decl, explicit_args, 0, -1);
-}
-
-/* And for more_specialized, we want to be able to stop partway.  */
-
-static tree
-get_bindings_order (fn, decl, len)
-     tree fn, decl;
-     int len;
-{
-  return get_bindings_real (fn, decl, NULL_TREE, 0, len);
+  return get_bindings_real (fn, decl, explicit_args, 0, DEDUCE_EXACT, -1);
 }
 
 /* Return the innermost template arguments that, when applied to a
@@ -9162,7 +9218,8 @@ most_specialized_instantiation (instantiations)
   champ = instantiations;
   for (fn = TREE_CHAIN (instantiations); fn; fn = TREE_CHAIN (fn))
     {
-      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), -1);
+      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn),
+                               DEDUCE_EXACT, -1);
       if (fate == 1)
        ;
       else
@@ -9179,7 +9236,8 @@ most_specialized_instantiation (instantiations)
 
   for (fn = instantiations; fn && fn != champ; fn = TREE_CHAIN (fn))
     {
-      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn), -1);
+      fate = more_specialized (TREE_VALUE (champ), TREE_VALUE (fn),
+                               DEDUCE_EXACT, -1);
       if (fate != 1)
        return error_mark_node;
     }
index d43e8915b09bf6d49d51f49a88fe771ec259a025..09f2e134866badb82cd3717736c271fdfd5b3af4 100644 (file)
@@ -1,3 +1,9 @@
+2001-01-22  Nathan Sidwell  <nathan@codesourcery.com>
+
+       * g++.old-deja/g++.martin/sts_partial.C: Remove XFAIL.
+       * g++.old-deja/g++.pt/spec35.C: New test.
+       * g++.old-deja/g++.pt/spec36.C: New test.
+
 2001-01-20  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.c-torture/compile/20010118-1.c: New test.
index c2dc9411b548ad18d0a4f98bc3ab91470017a9e8..382214c3c76de7d870ea25bd7fe80ab2312b0931 100644 (file)
@@ -1,4 +1,3 @@
-// excess errors test - XFAIL 
 // ecgs-bugs 1999-02-22 14:26 Stefan Schwarzer
 // sts@ica1.uni-stuttgart.de
 // partial ordering problem in egcs <= 1.1.1
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec35.C b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C
new file mode 100644 (file)
index 0000000..e768c91
--- /dev/null
@@ -0,0 +1,31 @@
+// Build don't link:
+// 
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 18 Jan 2001 <nathan@codesourcery.com>
+
+// Bug 1617. We didn't resolve partial ordering properly. The std is rather
+// vague about it anyway, DR 214 talks about this.
+
+extern "C" int puts (char const *);
+
+template <typename T> int Foo (T);    // ERROR - candidate
+template <typename T> int Foo (T &);  // ERROR - candidate
+
+template <typename T> int Qux (T);    // ERROR - candidate
+template <typename T> int Qux (T const &);  // ERROR - candidate
+
+template <typename T> int Bar (T const *const &); // ERROR - candidate
+template <typename T> int Bar (T *const &);       // ERROR - candidate
+template <typename T> int Bar (T *);              // ERROR - candidate
+
+template <typename T> int Baz (T *const &);       // ERROR - candidate
+template <typename T> int Baz (T *);              // ERROR - candidate
+
+int Baz (int const *ptr, int *ptr2)
+{
+  Baz (ptr2);   // ERROR - ambiguous
+  Bar (ptr2);   // ERROR - ambiguous
+  Foo (ptr2);   // ERROR - ambiguous
+  Qux (ptr2);   // ERROR - ambiguous
+  return 0;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec36.C b/gcc/testsuite/g++.old-deja/g++.pt/spec36.C
new file mode 100644 (file)
index 0000000..7581f85
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 18 Jan 2001 <nathan@codesourcery.com>
+
+// Bug 1617. We didn't resolve partial ordering properly. The std is rather
+// vague about it anyway, DR 214 talks about this.
+
+extern "C" int puts (char const *);
+
+template <typename T> int Foo (T *) {puts (__PRETTY_FUNCTION__); return 1;}
+template <typename T> int Foo (T &) {puts (__PRETTY_FUNCTION__); return 2;}
+template <typename T> int Foo (T const &) {puts (__PRETTY_FUNCTION__); return 3;}
+
+template <typename T> int Bar (T const *const &) {puts (__PRETTY_FUNCTION__); return 4;}
+template <typename T> int Bar (T *const &) {puts (__PRETTY_FUNCTION__); return 5;}
+template <typename T> int Bar (T *) {puts (__PRETTY_FUNCTION__); return 6;}
+
+template <typename T> int Quux (T *const &) {puts (__PRETTY_FUNCTION__); return 7;}
+template <typename T> int Quux (T const &) {puts (__PRETTY_FUNCTION__); return 8;}
+
+
+int Baz (int const *ptr, int *ptr2)
+{
+  if (Foo (ptr) != 1)
+    return 1;
+  if (Foo (ptr2) != 1)
+    return 2;
+  if (Foo (*ptr) != 3)
+    return 3;
+  if (Foo (*ptr2) != 2)
+    return 4;
+  
+  if (Bar (ptr) != 4)
+    return 5;
+  
+  if (Quux (ptr) != 7)
+    return 5;
+  if (Quux (ptr2) != 7)
+    return 6;
+  
+  return 0;
+}
+
+int main ()
+{
+  return Baz (0, 0);
+}