[regex] Clearing failures in regex_regress on Tru64/CXX

Attached patch clears the current failures in regex_regress on Tru64/CXX. Basically it adds an explicit instantiation of a template class needed because otherwise CXX ends up with multiple instances of the static variable used in the class, which is because of the template compilation model chosen for the compiler. As it shouldn't hurt other compilers, I didn't wrap it in #if ... #endif. Secondly it avoids three tricky test cases which hang the test program otherwise. Ok to commit? Markus Index: regress/info.hpp =================================================================== RCS file: /cvsroot/boost/boost/libs/regex/test/regress/info.hpp,v retrieving revision 1.3 diff -u -w -r1.3 info.hpp --- regress/info.hpp 21 Jan 2005 17:26:27 -0000 1.3 +++ regress/info.hpp 28 Jun 2005 12:52:13 -0000 @@ -140,6 +140,11 @@ : public test_info_base<char> {}; +// Explicit instantiations to avoid trouble with multiple instances +// of static variables in the test_info_base class. +template struct test_info_base<wchar_t>; +template struct test_info_base<char>; + template <class charT> std::ostream& operator<<(std::ostream& os, const test_info<charT>&) { Index: regress/test_tricky_cases.cpp =================================================================== RCS file: /cvsroot/boost/boost/libs/regex/test/regress/test_tricky_cases.cpp,v retrieving revision 1.4 diff -u -w -r1.4 test_tricky_cases.cpp --- regress/test_tricky_cases.cpp 30 Mar 2005 11:38:51 -0000 1.4 +++ regress/test_tricky_cases.cpp 28 Jun 2005 12:52:13 -0000 @@ -256,10 +256,12 @@ TEST_REGEX_SEARCH_W(L"[[:unicode:]]+", perl, L"a\x0300\x0400z", match_default, make_array(1, 3, -2, -2)); TEST_REGEX_SEARCH_W(L"[\x10-\xff]", perl, L"\x0300\x0400", match_default, make_array(-2, -2)); TEST_REGEX_SEARCH_W(L"[\01-\05]{5}", perl, L"\x0300\x0400\x0300\x0400\x0300\x0400", match_default, make_array(-2, -2)); +#if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) TEST_REGEX_SEARCH_W(L"[\x300-\x400]+", perl, L"\x0300\x0400\x0300\x0400\x0300\x0400", match_default, make_array(0, 6, -2, -2)); TEST_REGEX_SEARCH_W(L"[\\x{300}-\\x{400}]+", perl, L"\x0300\x0400\x0300\x0400\x0300\x0400", match_default, make_array(0, 6, -2, -2)); TEST_REGEX_SEARCH_W(L"\\x{300}\\x{400}+", perl, L"\x0300\x0400\x0400\x0400\x0400\x0400", match_default, make_array(0, 6, -2, -2)); #endif +#endif // finally try some case insensitive matches: TEST_REGEX_SEARCH("0123456789@abcdefghijklmnopqrstuvwxyz\\[\\\\\\]\\^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ\\{\\|\\}", perl|icase, "0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}", match_default, make_array(0, 72, -2, -2)); TEST_REGEX_SEARCH("a", perl|icase, "A", match_default, make_array(0, 1, -2, -2));

Attached patch clears the current failures in regex_regress on Tru64/CXX.
Basically it adds an explicit instantiation of a template class needed because otherwise CXX ends up with multiple instances of the static variable used in the class, which is because of the template compilation model chosen for the compiler. As it shouldn't hurt other compilers, I didn't wrap it in #if ... #endif.
Secondly it avoids three tricky test cases which hang the test program otherwise.
Ok to commit?
Not quite: the explicit instantiation are not legal C++ if applied in more than one translation unit. If you wrap them in the appropriate #ifdef's then it's probably OK to commit. (I say probably, because I'm not sure what Tru64 cxx does in other template instantiation modes, I suspect the patch may actually mess some of them up). John.

John Maddock wrote:
Attached patch clears the current failures in regex_regress on Tru64/CXX.
Basically it adds an explicit instantiation of a template class needed because otherwise CXX ends up with multiple instances of the static variable used in the class, which is because of the template compilation model chosen for the compiler. As it shouldn't hurt other compilers, I didn't wrap it in #if ... #endif.
[snip]
Not quite: the explicit instantiation are not legal C++ if applied in more than one translation unit. If you wrap them in the appropriate #ifdef's then it's probably OK to commit. (I say probably, because I'm not sure what Tru64 cxx does in other template instantiation modes, I suspect the patch may actually mess some of them up).
Umm, now I'm confused. Why is explicit instantiation in more than one translation unit illegal? Markus

Umm, now I'm confused. Why is explicit instantiation in more than one translation unit illegal?
I think I must be loosing it.... I can't find any such prohibition anywhere.... I was so sure that I'd had problems with this in the past as well! I'd still prefer it if you surrounded the changes with #ifdef's just to be extra careful, but please do go ahead and make the change. Apologies for the misinformation, and thanks for looking into this! John.

On Wed, Jun 29, 2005 at 12:59:57PM +0100, John Maddock wrote:
Umm, now I'm confused. Why is explicit instantiation in more than one translation unit illegal?
I think I must be loosing it.... I can't find any such prohibition anywhere.... I was so sure that I'd had problems with this in the past as well!
You are referring to the explicit instantiation of the same template specialization in several TUs, aren't you? That is indeed prohibited. I am too lazy to look for chapter and verse in my copy of the standard but Vandevoorde and Josuttis write in "C++ Templates. The Complete Guide": Section 6.2.1: There should be, at most, one explicit instantiation of each distinct entity in a program. [...] Not following this rule usually results in linker errors that report duplicate definitions of the instantiated entities. Section 10.5: The standard also specifies that there can be at most one explicit instantiation of a certain template specialization in a program. Furthermore, if a template specialization is explicitly instantiated, it should not be explicitly specialized, and vice versa. Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

Christoph Ludwig wrote:
On Wed, Jun 29, 2005 at 12:59:57PM +0100, John Maddock wrote:
Umm, now I'm confused. Why is explicit instantiation in more than one translation unit illegal?
I think I must be loosing it.... I can't find any such prohibition anywhere.... I was so sure that I'd had problems with this in the past as well!
You are referring to the explicit instantiation of the same template specialization in several TUs, aren't you?
That is indeed prohibited. I am too lazy to look for chapter and verse in my copy of the standard but Vandevoorde and Josuttis write in "C++ Templates. The Complete Guide":
Section 6.2.1: There should be, at most, one explicit instantiation of each distinct entity in a program. [...] Not following this rule usually results in linker errors that report duplicate definitions of the instantiated entities.
The problem is that the compiler _needs_ the explicit instantiation in order not to end up with multiple defitions of a static variable used in the class. And where should that instantiation be written, if not in the header?
Section 10.5: The standard also specifies that there can be at most one explicit instantiation of a certain template specialization in a program. Furthermore, if a template specialization is explicitly instantiated, it should not be explicitly specialized, and vice versa.
I can't find anything in the standard (14.7) indicating this. Markus

On Wed, Jun 29, 2005 at 02:52:12PM +0200, Markus Schöpflin wrote:
Christoph Ludwig wrote:
On Wed, Jun 29, 2005 at 12:59:57PM +0100, John Maddock wrote:
Umm, now I'm confused. Why is explicit instantiation in more than one translation unit illegal?
I think I must be loosing it.... I can't find any such prohibition anywhere.... I was so sure that I'd had problems with this in the past as well!
You are referring to the explicit instantiation of the same template specialization in several TUs, aren't you?
That is indeed prohibited. I am too lazy to look for chapter and verse in my copy of the standard but Vandevoorde and Josuttis write in "C++ Templates. The Complete Guide":
Section 6.2.1: There should be, at most, one explicit instantiation of each distinct entity in a program. [...] Not following this rule usually results in linker errors that report duplicate definitions of the instantiated entities.
The problem is that the compiler _needs_ the explicit instantiation in order not to end up with multiple defitions of a static variable used in the class. And where should that instantiation be written, if not in the header?
I don't know the peculiarities of the Tru64/CXX compiler. If it does not care about multiple explicit instantiations (or even requires them for some reason), then it may make sense to ignore the standard *on this particular platform*. The explicit instantiation should be guarded by #ifdefs that filter out all other platforms, though.
Section 10.5: The standard also specifies that there can be at most one explicit instantiation of a certain template specialization in a program. Furthermore, if a template specialization is explicitly instantiated, it should not be explicitly specialized, and vice versa.
I can't find anything in the standard (14.7) indicating this.
OK, I overcame my laziness :-) It is 14.7p5: No program shall explicitly instantiate any template more than once, both explicitly instantiate and explicitly specialize a template, or specialize a template more than once for a given set of template arguments. An implementation is not required to diagnose a violation of this rule. I admit I find Vandvoorde's and Josuttis' phrasing much easier to grok. Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

Christoph Ludwig wrote:
On Wed, Jun 29, 2005 at 02:52:12PM +0200, Markus Schöpflin wrote:
Christoph Ludwig wrote:
Section 10.5: The standard also specifies that there can be at most one explicit instantiation of a certain template specialization in a program. Furthermore, if a template specialization is explicitly instantiated, it should not be explicitly specialized, and vice versa.
I can't find anything in the standard (14.7) indicating this.
OK, I overcame my laziness :-) It is 14.7p5:
No program shall explicitly instantiate any template more than once, both explicitly instantiate and explicitly specialize a template, or specialize a template more than once for a given set of template arguments. An implementation is not required to diagnose a violation of this rule.
I admit I find Vandvoorde's and Josuttis' phrasing much easier to grok.
Duh, I read 14.7.2 and 14.7.3 over and over and I completely missed that one. :-( Hmm, now I'm left wondering how in general to deal with this issue. Would this be legal? ---%<--- template <class T> struct foo { static T bar() { static T t; return t; } }; template<> foo<int>; template int foo<int>::bar(); --->%-- Time to ask the compiler vendor on how to avoid multiple copies of t here, I think. Thanks, Markus

On Wed, Jun 29, 2005 at 04:12:17PM +0200, Markus Schöpflin wrote:
Christoph Ludwig wrote:
OK, I overcame my laziness :-) It is 14.7p5:
No program shall explicitly instantiate any template more than once, both explicitly instantiate and explicitly specialize a template, or specialize a template more than once for a given set of template arguments. An implementation is not required to diagnose a violation of this rule.
I admit I find Vandvoorde's and Josuttis' phrasing much easier to grok.
Duh, I read 14.7.2 and 14.7.3 over and over and I completely missed that one.:-(
Hmm, now I'm left wondering how in general to deal with this issue. Would this be legal?
---%<--- template <class T> struct foo { static T bar() { static T t; return t; } };
template<> foo<int>; template int foo<int>::bar(); --->%--
That can't be correct: a) You mix an explicit specialization of foo with the explicit instantiation of its member bar. But explicit instantiation and specialization do not go together. b) You forward declare the explicit specialization of foo<int>. (Is 'forward declaration' the right technical term? Anyway, you understand what I mean, I hope.) Then you instantiate the member foo<int>::bar. But at this point the compiler cannot know whether foo<int> has a member bar at all! It cannot refer to the primary template's definition anymore since foo<int> is explicitly specialized. OTOH, it did not see the definition of foo<int> yet... Regards Christoph -- http://www.informatik.tu-darmstadt.de/TI/Mitarbeiter/cludwig.html LiDIA: http://www.informatik.tu-darmstadt.de/TI/LiDIA/Welcome.html

Markus Schöpflin <markus.schoepflin@comsoft.de> writes:
Christoph Ludwig wrote:
On Wed, Jun 29, 2005 at 02:52:12PM +0200, Markus Schöpflin wrote:
Christoph Ludwig wrote:
Section 10.5: The standard also specifies that there can be at most one explicit instantiation of a certain template specialization in a program. Furthermore, if a template specialization is explicitly instantiated, it should not be explicitly specialized, and vice versa.
I can't find anything in the standard (14.7) indicating this.
OK, I overcame my laziness :-) It is 14.7p5:
No program shall explicitly instantiate any template more than once, both explicitly instantiate and explicitly specialize a template, or specialize a template more than once for a given set of template arguments. An implementation is not required to diagnose a violation of this rule.
I admit I find Vandvoorde's and Josuttis' phrasing much easier to grok.
Duh, I read 14.7.2 and 14.7.3 over and over and I completely missed that one. :-(
Hmm, now I'm left wondering how in general to deal with this issue. Would this be legal?
---%<--- template <class T> struct foo { static T bar() { static T t; return t; } };
template<> foo<int>; template int foo<int>::bar(); --->%--
Time to ask the compiler vendor on how to avoid multiple copies of t here, I think.
What happens if you explicitly mark it "inline"? -- Dave Abrahams Boost Consulting www.boost-consulting.com

Christoph Ludwig wrote:
On Wed, Jun 29, 2005 at 02:52:12PM +0200, Markus Schöpflin wrote:
The problem is that the compiler _needs_ the explicit instantiation in order not to end up with multiple defitions of a static variable used in the class. And where should that instantiation be written, if not in the header?
I don't know the peculiarities of the Tru64/CXX compiler. If it does not care about multiple explicit instantiations (or even requires them for some reason), then it may make sense to ignore the standard *on this particular platform*. The explicit instantiation should be guarded by #ifdefs that filter out all other platforms, though.
No reply from the vendor on this yet, but I did some more testing. Basically, I tested with the following header file included into two different TUs and then linked together into a single application. This should mirror the situation in question close enough, I hope. ---%<--- #include <iostream> template <class T> struct foo_base { static void bar() { static T t = T(); std::cout << "t=" << t << '\n'; ++t; } }; template void foo_base<int>::bar(); struct foo : public foo_base<int> { }; --->%--- Each TU included a call to foo::bar() and only when the explicit instantiation of foo_base::bar() was present, the program worked as expected in all instantiation modes, when compiled with cxx (and g++) on Tru64. I had a look at the generated object files and indeed there are definitions for the static variable t in each object file, but they have so called common linkage, which means that only one symbol is finally chosen. So I think it will be ok to add the change when the instantiation is wrapped in appropriate #ifdefs. What do you think, John? Markus

Each TU included a call to foo::bar() and only when the explicit instantiation of foo_base::bar() was present, the program worked as expected in all instantiation modes, when compiled with cxx (and g++) on Tru64.
I had a look at the generated object files and indeed there are definitions for the static variable t in each object file, but they have so called common linkage, which means that only one symbol is finally chosen.
So I think it will be ok to add the change when the instantiation is wrapped in appropriate #ifdefs. What do you think, John?
OK go ahead and add the explicit instantiations wrapped in #ifdef's, make sure there is a comment explaining the problem as well, thanks for delving into this! John.

John Maddock wrote:
Each TU included a call to foo::bar() and only when the explicit instantiation of foo_base::bar() was present, the program worked as expected in all instantiation modes, when compiled with cxx (and g++) on Tru64.
I had a look at the generated object files and indeed there are definitions for the static variable t in each object file, but they have so called common linkage, which means that only one symbol is finally chosen.
So I think it will be ok to add the change when the instantiation is wrapped in appropriate #ifdefs. What do you think, John?
OK go ahead and add the explicit instantiations wrapped in #ifdef's, make sure there is a comment explaining the problem as well, thanks for delving into this!
Phew, I finally managed to do the commit. That should clear the last error for Tru64/cxx65. Markus
participants (4)
-
Christoph Ludwig
-
David Abrahams
-
John Maddock
-
Markus Schöpflin