This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [Patch] PR c++/42824
Hello,
So I tried the idea you talked about on IRC, which is basically to
tsubst the arguments of the type of the most general template with all
but the innermost arguments of the current template specialization we
are looking up. The result of that tsubsting constitutes the arguments
of the partial instantiation of the member of class template, if
applicable.
Comparing the arguments of the specialization we are looking up with the
result of the tsubsting does the trick and lets me do away with the new
comparison code.
Tested on x86_64-unknown-linux-gnu against trunk.
Thanks.
Dodji
commit 4bf13553672be5c496042b762766167642a5fd11
Author: Dodji Seketeli <dodji@redhat.com>
Date: Thu Feb 4 20:20:49 2010 +0100
Fix PR c++/42824
gcc/cp/ChangeLog:
PR c++/42824
* pt.c (lookup_template_class): Better support of specialization
of member of class template implicit instantiation.
gcc/testsuite/ChangeLog:
PR c++/42824
* g++.dg/template/memclass4.C: New test.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b903f77..6b5a65d 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6325,7 +6325,8 @@ lookup_template_class (tree d1,
tree found = NULL_TREE;
int arg_depth;
int parm_depth;
- int is_partial_instantiation;
+ int is_dependent_type;
+ int use_partial_inst_tmpl = false;
gen_tmpl = most_general_template (templ);
parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);
@@ -6441,21 +6442,17 @@ lookup_template_class (tree d1,
if (entry)
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, entry->spec);
- /* This type is a "partial instantiation" if any of the template
- arguments still involve template parameters. Note that we set
- IS_PARTIAL_INSTANTIATION for partial specializations as
- well. */
- is_partial_instantiation = uses_template_parms (arglist);
+ is_dependent_type = uses_template_parms (arglist);
/* If the deduced arguments are invalid, then the binding
failed. */
- if (!is_partial_instantiation
+ if (!is_dependent_type
&& check_instantiated_args (gen_tmpl,
INNERMOST_TEMPLATE_ARGS (arglist),
complain))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
- if (!is_partial_instantiation
+ if (!is_dependent_type
&& !PRIMARY_TEMPLATE_P (gen_tmpl)
&& !LAMBDA_TYPE_P (TREE_TYPE (gen_tmpl))
&& TREE_CODE (CP_DECL_CONTEXT (gen_tmpl)) == NAMESPACE_DECL)
@@ -6474,7 +6471,7 @@ lookup_template_class (tree d1,
/* Create the type. */
if (TREE_CODE (template_type) == ENUMERAL_TYPE)
{
- if (!is_partial_instantiation)
+ if (!is_dependent_type)
{
set_current_access_from_decl (TYPE_NAME (template_type));
t = start_enum (TYPE_IDENTIFIER (template_type),
@@ -6540,11 +6537,69 @@ lookup_template_class (tree d1,
DECL_VISIBILITY (type_decl) = CLASSTYPE_VISIBILITY (template_type);
}
- /* Set up the template information. We have to figure out which
- template is the immediate parent if this is a full
- instantiation. */
- if (parm_depth == 1 || is_partial_instantiation
- || !PRIMARY_TEMPLATE_P (gen_tmpl))
+ /* Let's consider the explicit specialization of a member
+ of a class template specialization that is implicitely instantiated,
+ e.g.:
+ template<class T>
+ struct S
+ {
+ template<class U> struct M {}; //#0
+ };
+
+ template<>
+ template<>
+ struct S<int>::M<char> //#1
+ {
+ int i;
+ };
+ [temp.expl.spec]/4 says this is valid.
+
+ In this case, when we write:
+ S<int>::M<char> m;
+
+ M is instantiated from the CLASSTYPE_TI_TEMPLATE of #1, not from
+ the one of #0.
+
+ When we encounter #1, we want to store the partial instantiation
+ of M (template<class T> S<int>::M<T>) in it's CLASSTYPE_TI_TEMPLATE.
+
+ For all cases other than this "explicit specialization of member of a
+ class template", we just want to store the most general template into
+ the CLASSTYPE_TI_TEMPLATE of M.
+
+ This case of "explicit specialization of member of a class template"
+ only happens when:
+ 1/ the enclosing class is an instantiation of, and therefore not
+ the same as, the context of the most general template, and
+ 2/ we aren't looking at the partial instantiation itself, i.e.
+ the innermost arguments are not the same as the innermost parms of
+ the most general template.
+
+ So it's only when 1/ and 2/ happens that we want to use the partial
+ instantiation of the member template in lieu of its most general
+ template. */
+
+ if (PRIMARY_TEMPLATE_P (gen_tmpl)
+ && TREE_VEC_LENGTH (arglist) > 1
+ /* the enclosing class must be an instantiation... */
+ && CLASS_TYPE_P (context)
+ && !same_type_p (context, DECL_CONTEXT (gen_tmpl)))
+ {
+ tree partial_inst_args;
+ TREE_VEC_LENGTH (arglist)--;
+ ++processing_template_decl;
+ partial_inst_args = tsubst (CLASSTYPE_TI_ARGS (TREE_TYPE (gen_tmpl)),
+ arglist, complain, NULL_TREE);
+ --processing_template_decl;
+ TREE_VEC_LENGTH (arglist)++;
+ use_partial_inst_tmpl =
+ /*...and we must not be looking at the partial instantiation
+ itself. */
+ !comp_template_args (INNERMOST_TEMPLATE_ARGS (arglist),
+ INNERMOST_TEMPLATE_ARGS (partial_inst_args));
+ }
+
+ if (!use_partial_inst_tmpl)
/* This case is easy; there are no member templates involved. */
found = gen_tmpl;
else
@@ -6574,8 +6629,7 @@ lookup_template_class (tree d1,
= tree_cons (arglist, t,
DECL_TEMPLATE_INSTANTIATIONS (templ));
- if (TREE_CODE (t) == ENUMERAL_TYPE
- && !is_partial_instantiation)
+ if (TREE_CODE (t) == ENUMERAL_TYPE && !is_dependent_type)
/* Now that the type has been registered on the instantiations
list, we set up the enumerators. Because the enumeration
constants may involve the enumeration type itself, we make
@@ -6585,7 +6639,7 @@ lookup_template_class (tree d1,
the instantiation and exit above. */
tsubst_enum (template_type, t, arglist);
- if (is_partial_instantiation)
+ if (is_dependent_type)
/* If the type makes use of template parameters, the
code that generates debugging information will crash. */
DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
diff --git a/gcc/testsuite/g++.dg/template/memclass4.C b/gcc/testsuite/g++.dg/template/memclass4.C
new file mode 100644
index 0000000..65a42a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/memclass4.C
@@ -0,0 +1,70 @@
+// Origin: PR c++/42824
+// { dg-do compile }
+
+template<int T>
+class int_ {
+};
+
+template<int T, int T2>
+class Unit {
+public:
+ Unit(const Unit<T, T2>& other) {}
+};
+
+template<int T>
+class Quan {
+public:
+ Quan(void) {}
+
+ template<int T2>
+ Quan(double value, Unit<T, T2> unit) {}
+};
+typedef Quan<0> Scalar;
+
+template<int T>
+class hlp {
+public:
+ typedef Quan<T> type;
+};
+
+class Mtrl {
+public:
+ template<int T>
+ struct AssoType {
+ typedef typename hlp<T>::type type;
+ };
+};
+
+template<class T>
+class Eval {
+public:
+ Eval(const T& object){}
+
+ template<int V>
+ void eval() {
+ eval<V> (int_<0>());
+ }
+private:
+ template<typename U> struct Wrap {};
+
+ template<int V, int V2>
+ void value(Wrap<Quan<V2> >) {}
+
+ template<int V>
+ void value(Wrap<Scalar>) {}
+
+ template<int V>
+ void eval(int_<0>) {
+ typedef typename T::template AssoType<V>::type Type;
+ value<V>(Wrap<Type>());
+ }
+};
+
+class Foo {
+public:
+ static void eval(const Mtrl& mtrl) {
+ Eval<Mtrl> h(mtrl);
+ h.eval<0> ();
+ }
+};
+