aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-01-22 13:51:43 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-01-22 13:51:43 +0000
commit62e4a758537dd6c82a0a2ce1b0cd75842e41441c (patch)
tree8feaf4e16f95f3879323455ce542e7a5e0b35e7e /gcc
parent0bbcfbafc8aa36f62eb4d347301cf80498ac3464 (diff)
downloadgcc-62e4a758537dd6c82a0a2ce1b0cd75842e41441c.zip
gcc-62e4a758537dd6c82a0a2ce1b0cd75842e41441c.tar.gz
gcc-62e4a758537dd6c82a0a2ce1b0cd75842e41441c.tar.bz2
cp-tree.h (unification_kind_t): Add DEDUCE_ORDER.
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog24
-rw-r--r--gcc/cp/call.c1
-rw-r--r--gcc/cp/cp-tree.h7
-rw-r--r--gcc/cp/pt.c142
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C1
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/spec35.C31
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/spec36.C46
8 files changed, 212 insertions, 46 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7927428..3374dd2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e3613ee..fa5a508 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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));
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 1df938b..8122d56 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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));
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index cf3b52d..184edf8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -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;
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d43e891..09f2e13 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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.
diff --git a/gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C b/gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C
index c2dc941..382214c 100644
--- a/gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C
+++ b/gcc/testsuite/g++.old-deja/g++.martin/sts_partial.C
@@ -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
index 0000000..e768c91
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec35.C
@@ -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
index 0000000..7581f85
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec36.C
@@ -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);
+}