Consider the following test program: #include <stdio.h> template <class T> struct X { enum { val = 0 }; }; template <class T> struct X<const T> { enum { val = 1 }; }; int main() { printf("%d\n", X<int&>::val); } The value printed is "1". That is, the 3.x compiler (tested with 3.1, 3.3, and mainline) thinks that X<int&> refers to the X<const T> partial specialization rather than to the primary template. I believe that this is wrong. The partial specialization should only be used for a type that has a top-level const qualifier, and references are not cv-qualified. (8.3.2, paragraph 1). This is a regression from 2.95.
Here is something which is easy for regression testers to reject: template <class T> struct X { enum { val = 0 }; }; template <class T> struct X<const T> { enum { val = 1 }; }; int i[X<int&>::val == 0?1:-1]; Confirmed. From Phil's regression hunter: Search converges between 2002-02-17-trunk (#59) and 2002-02-24- trunk (#60).
Or, still simpler: ------------------ template <typename T> struct X {}; template <typename T> struct X<const T>; template struct X<int&>; ------------------ W.
Maybe related to bug 2645 and most likely broke by the patch which fixed that one.
Adjust milestone
Nathan Sidwell believes that the standard, as presently written, requires the current behavior. He is going to try to write up an explanation of why he believes this behavior is presently required and attach it to the PR.
Depending on what that explanation looks like, it might be a good idea to get in touch with the committee and request clarification.
Subject: Re: [3.3/3.4/3.5 Regression] Incorrect use of const partial specialization for reference template argument austern at apple dot com wrote: > ------- Additional Comments From austern at apple dot com 2004-03-17 18:23 ------- > Depending on what that explanation looks like, it might be a good idea to get in touch with the > committee and request clarification. yes, I know. I had a conversation a while back with John Spicer, but I was unable to properly describe the situation. I need to iterate. nathan
given template <typename T> struct X {}; // #1 template <typename T> struct X<const T>; //#2 template struct X<int&>; //#3 Does #3 instantiate #1 or #2? It seems obvious that #1 is what is desired, but that is not what the standard says. The relevent bits of the standard are the partial specialization rules [14.5.4.1] and the ignoring of cv qualifiers on a reference type introduced by a typedef or template parameter [8.3.2]/1 To determine which partial specializations match, we see if its arguments can be deduced from the actual template argument list. In this case, can we deduce a 'T const' from 'int &' ? [14.8.2] describes template argument deduction, but primarily focusses on deduction of a templated function. Presumable [14.8.2.4] is what applies here. In this case P is 'T const' and A is 'int &'. Para1 tells us to find a type such that when subtituted into P, will make that compatible with A. Here 'int &' is such a type for T, because when substituted into 'T const', we ignore the const as the reference is introduced via a template type. Hence partial specialization #2 deduces with T='int &'. However, if the rule in [8.3.2]/1 about ignoring cv qualifiers on references does not apply during deduction, then presumably the same applies to DR295, where CV qualifiers of function types introduced via a typedef or template parameter are similarly not ignored in deduction. If that is the case, does it apply during deduction only in deduced contexts, or in both deduced and non-deduced contexts? In either case, I can find nothing in the standard to indicate this. template <typename T> void Foo (T); // #1 template <typename T> void Foo (T const); // #2 static_cast <void (int &)> (Foo); // #1 or #2? template <typename T> void Foo (T *); // #1 template <typename T> void Foo (T const *); // #2 void Baz (); Foo (Baz); // which? template <typename T> T const *Foo (T *); // #1 void Baz (); Foo (Baz); // well formed? template <typename T> void Foo (T *, T const * = 0); void Baz (); Foo (Baz); // well formed?
Without commenting on the function-type issues, I'll note that Nathan's argument now makes sense to me. Here is another way to approach it. Given template <typename T> struct X {}; // #1 template <typename T> struct X<const T>; //#2 template struct X<int&>; //#3 the only issue is whether #2 matches #3. If so, then it is clearly the most specialized and is the one selected. Presumably, 14.8.2/2 -- which is written for function templates, but makes sense for explicitly specified class template arguments as well -- applies. It lists the cases in which deduction fails because an invalid type is created -- and creating a cv-qualified reference type is not among them. As Nathan notes, 8.3.2 explicitly allows cv-qualified reference types in this situation. (Clearly, this example: template <typename T> void f(const T) {} template void f<int&>(int &); is valid.) I'm therefore closing this as INVALID. Nathan, Matt -- if y'all thing this is the wrong behavior, would you please submit a DR?
Subject: Re: [3.3/3.4/3.5 Regression] Incorrect use of const partial specialization for reference template argument "mmitchel at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes: | I'm therefore closing this as INVALID. | | Nathan, Matt -- if y'all thing this is the wrong behavior, would you please | submit a DR? Wihle I can see the logic in Nathan's reasoning, I think the proper action is indeed to bring this before the committee. -- Gaby
Subject: Re: [3.3/3.4/3.5 Regression] Incorrect use of const partial specialization for reference template argument Gaby and I have raised this with the committee. c++std-core-10466.
Reopening to ...
Suspend it as this might not be the correct behaviour.
Subject: Bug 14007 CVSROOT: /cvs/gcc Module name: gcc Changes by: nathan@gcc.gnu.org 2004-04-02 11:48:56 Modified files: gcc/cp : ChangeLog tree.c pt.c gcc/testsuite : ChangeLog gcc/testsuite/g++.dg/template: qualttp20.C gcc/testsuite/g++.old-deja/g++.jason: report.C gcc/testsuite/g++.old-deja/g++.other: qual1.C Added files: gcc/testsuite/g++.dg/template: unify5.C unify6.C Log message: cp: PR c++/14007 * pt.c (check_cv_quals_for_unify): Correct logic for disallowed cv-qualifier unification. * tree.c (cp_build_qualified_type_real): Renable DR295 logic. testsuite: PR c++/14007 * g++.dg/template/unify5.C: New. * g++.dg/template/unify6.C: New. * g++.dg/template/qualttp20.C: Adjust. * g++.old-deja/g++.jason/report.C: Adjust. * g++.old-deja/g++.other/qual1.C: Adjust. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4026&r2=1.4027 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/tree.c.diff?cvsroot=gcc&r1=1.370&r2=1.371 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&r1=1.845&r2=1.846 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.3650&r2=1.3651 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/unify5.C.diff?cvsroot=gcc&r1=NONE&r2=1.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/unify6.C.diff?cvsroot=gcc&r1=NONE&r2=1.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/qualttp20.C.diff?cvsroot=gcc&r1=1.5&r2=1.6 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.jason/report.C.diff?cvsroot=gcc&r1=1.10&r2=1.11 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.other/qual1.C.diff?cvsroot=gcc&r1=1.6&r2=1.7
apply to 3.4.1 when appropriate
Mark, this is a wrong-code regression, and Nathan's patch silently changes the semantic of well-formed programs. Now that it's been made clear by the commettee that GCC behaviour is wrong, I think this bug is very critical. What about having the patch for 3.4.0? I'm not sure we want such a change to occur between point releases...
Subject: Re: [3.3/3.4/3.5 Regression] Incorrect use of const partial specialization for reference template argument "giovannibajo at libero dot it" <gcc-bugzilla@gcc.gnu.org> writes: | Mark, this is a wrong-code regression, and Nathan's patch silently changes the | semantic of well-formed programs. Now that it's been made clear by the | commettee that GCC behaviour is wrong, I think this bug is very critical. What | about having the patch for 3.4.0? I'm not sure we want such a change to occur | between point releases... I second Giovanni's assessement. I'm studying the applicability of this patch to 3.3.4. -- Gaby
This patch should not be applied to 3.4 or 3.3 without further discussion. It appears the rules are still inconsistent, refer to 3518 for details.
I don't think we should be making any drastic changes right now. The behavior in 3.4.0 is consistent with all releases from 3.0.x onwards. Changing the semantics from these releases should not be done until we are absolutely sure what the right behavior is. In my opinion, that logic should apply to 3.3.4 as well. Making changes in 3.3.4 that will make it behave differently from 3.3.3 and from 3.4.0 would be a mistake.
I agree with Mark. This patch should only be allowed to go into 3.3.4 if it also goes into 3.4, and maybe even then it shouldn't to not generate different code than 3.3.3. On the other hand, it would be better if it were applied to 3.4.0 rather than 3.4.1, to keep things consistent within dot releases. W.
Subject: Re: [3.3/3.4 Regression] Incorrect use of const partial specialization for reference template argument "mmitchel at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes: | I don't think we should be making any drastic changes right now. | | The behavior in 3.4.0 is consistent with all releases from 3.0.x onwards. | Changing the semantics from these releases should not be done until we are | absolutely sure what the right behavior is. Agreed. | In my opinion, that logic should apply to 3.3.4 as well. Making changes in | 3.3.4 that will make it behave differently from 3.3.3 and from 3.4.0 would be a | mistake. I'm considering the applicability of the patch for 3.3.4 only if it goes to 3.4.[01]. -- Gaby
Nathan, does it make sense to apply your patch to 3.4.1? Or does your Comment #18 about remaining issues still apply?
There is still someting wrong with this patch, which I tried to fix at the summit on mainline. Unfortunately the expected set of unexpected failures has changed, probably transiently due to the ssa merge, and I've not followed up on that. Volker Reichelt sent me this test case template <typename T> int ref (T&) { return 0; } template <typename T> int ref (const volatile T&) { return 1; } template <typename T> int ptr (T*) { return 0; } template <typename T> int ptr (const volatile T*) { return 2; } void foo (void) {} int main() { return ref(foo) + ptr(&foo); } it should return zero, but does not.
Postponed until GCC 3.4.2.
I have looked at the example in comment 23 and concluded that g++ DTRT. That example should indeed return 1. EDG 3.4 in strict mode does this too. I conclude that the fix on mainline for this bug is ok for the 3.4 branch too.
Subject: Re: [3.3/3.4 Regression] Incorrect use of const partial specialization for reference template argument nathan at gcc dot gnu dot org wrote: > ------- Additional Comments From nathan at gcc dot gnu dot org 2004-06-19 09:00 ------- > I have looked at the example in comment 23 and concluded that g++ DTRT. That > example should indeed return 1. EDG 3.4 in strict mode does this too. > > I conclude that the fix on mainline for this bug is ok for the 3.4 branch too. OK, please apply then. Thanks,
Applied to 3.4 branch 2004-06-21 Nathan Sidwell <nathan@codesourcery.com> PR c++/3518 * pt.c (check_cv_quals_for_unify): Ignore bogus CV quals at outer level. PR c++/14007 * pt.c (check_cv_quals_for_unify): Correct logic for disallowed cv-qualifier unification. * tree.c (cp_build_qualified_type_real): Renable DR295 logic.
Subject: Bug 14007 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_4-branch Changes by: nathan@gcc.gnu.org 2004-06-21 12:46:29 Modified files: gcc/cp : ChangeLog pt.c tree.c gcc/testsuite : ChangeLog gcc/testsuite/g++.dg/template: qualttp20.C gcc/testsuite/g++.old-deja/g++.jason: report.C gcc/testsuite/g++.old-deja/g++.other: qual1.C Added files: gcc/testsuite/g++.dg/template: unify5.C unify6.C unify7.C Log message: cp: PR c++/3518 * pt.c (check_cv_quals_for_unify): Ignore bogus CV quals at outer level. PR c++/14007 * pt.c (check_cv_quals_for_unify): Correct logic for disallowed cv-qualifier unification. * tree.c (cp_build_qualified_type_real): Renable DR295 logic. testsuite: PR c++/3518 * g++.dg/template/unify7.C: New. PR c++/14007 * g++.dg/template/unify5.C: New. * g++.dg/template/unify6.C: New. * g++.dg/template/qualttp20.C: Adjust. * g++.old-deja/g++.jason/report.C: Adjust. * g++.old-deja/g++.other/qual1.C: Adjust. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3892.2.125&r2=1.3892.2.126 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.816.2.31&r2=1.816.2.32 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/tree.c.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.360.4.6&r2=1.360.4.7 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3389.2.212&r2=1.3389.2.213 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/unify5.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.18.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/unify6.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.18.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/unify7.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.18.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/qualttp20.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.4&r2=1.4.32.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.jason/report.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.10&r2=1.10.16.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.other/qual1.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.5&r2=1.5.16.1
Please adjust the target milestone to 3.4.1