This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
[Patch] libstdc++/29217
- From: Paolo Carlini <pcarlini at suse dot de>
- To: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Cc: Benjamin Kosnik <bkoz at redhat dot com>
- Date: Tue, 26 Sep 2006 13:18:59 +0200
- Subject: [Patch] libstdc++/29217
Hi,
this issue is annoying: we have got an inconsistency between the
numerical encodings of the collate and time categories and the
corresponding names. Ideally, we would like to cleanly fix the former
(see alternate patch (only the first and third hunks do the real job)),
but we can't at this stage, because that means that old code linked vs
the updated library regresses, gets the wrong category replaced when
calling the various out of line locale constructors taking a category.
I'm afraid we need the below workaround, for now.
Compatibility issues also block a different elegant solution: change the
order of the names instead (thus locale::name()) and make locale(const
char*), input in general, smarter, able to deal with arbitrary orders: a
locale::name() produced by the new library would be read incorrectly by
an old binary elsewhere.
Tested x86-linux, if nobody disagree, for 4.2.0 I would go ahead with
the workaround.
Paolo.
////////////////
2006-09-26 Paolo Carlini <pcarlini@suse.de>
PR libstdc++/29217
* src/localename.cc (locale::_Impl::_M_replace_categories)):
Compensate for the inconsistent numerical encodings of the
collate and time categories vs the corresponding names.
* testsuite/22_locale/locale/cons/29217.cc: New.
* testsuite/22_locale/locale/cons/2.cc: Enable and split
out the few ENC_TRAITS bits to...
* testsuite/22_locale/locale/cons/unicode/1.cc... here.
Index: src/localename.cc
===================================================================
--- src/localename.cc (revision 117192)
+++ src/localename.cc (working copy)
@@ -288,13 +288,23 @@
std::memcpy(_M_names[__i], _M_names[0], __len);
}
}
- char* __src = __imp->_M_names[__ix] ? __imp->_M_names[__ix]
- : __imp->_M_names[0];
+
+ // FIXME: Hack for libstdc++/29217: the numerical encodings
+ // of the time and collate categories are swapped vs the
+ // order of the names in locale::_S_categories. We'd like to
+ // adjust the former (the latter is dictated by compatibility
+ // with glibc) but we can't for binary compatibility.
+ size_t __ix_name = __ix;
+ if (__ix == 2 || __ix == 3)
+ __ix_name = 5 - __ix;
+
+ char* __src = __imp->_M_names[__ix_name] ?
+ __imp->_M_names[__ix_name] : __imp->_M_names[0];
const size_t __len = std::strlen(__src) + 1;
char* __new = new char[__len];
std::memcpy(__new, __src, __len);
- delete [] _M_names[__ix];
- _M_names[__ix] = __new;
+ delete [] _M_names[__ix_name];
+ _M_names[__ix_name] = __new;
}
}
}
Index: testsuite/22_locale/locale/cons/2.cc
===================================================================
--- testsuite/22_locale/locale/cons/2.cc (revision 117213)
+++ testsuite/22_locale/locale/cons/2.cc (working copy)
@@ -2,7 +2,8 @@
// 2000-09-13 Benjamin Kosnik <bkoz@redhat.com>
-// Copyright (C) 2000, 2001, 2002, 2003, 2005 Free Software Foundation
+// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006
+// Free Software Foundation
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
@@ -27,11 +28,11 @@
#include <stdexcept>
#include <testsuite_hooks.h>
-#if _GLIBCXX_USE___ENC_TRAITS
typedef std::codecvt<char, char, std::mbstate_t> c_codecvt;
-typedef std::codecvt_byname<char, char, std::mbstate_t> c_codecvt_byname;
+
+#ifdef _GLIBCXX_USE_WCHAR_T
typedef std::codecvt<wchar_t, char, std::mbstate_t> w_codecvt;
-typedef std::codecvt_byname<wchar_t, char, std::mbstate_t> w_codecvt_byname;
+#endif
class gnu_codecvt: public c_codecvt { };
@@ -43,77 +44,10 @@
std::locale::id gnu_facet::id;
-// Need some char_traits specializations for this to work.
-typedef unsigned short unicode_t;
-
-namespace std
-{
- template<>
- struct char_traits<unicode_t>
- {
- typedef unicode_t char_type;
- // Unsigned as wint_t is unsigned.
- typedef unsigned long int_type;
- typedef streampos pos_type;
- typedef streamoff off_type;
- typedef mbstate_t state_type;
-
- static void
- assign(char_type& __c1, const char_type& __c2);
-
- static bool
- eq(const char_type& __c1, const char_type& __c2);
-
- static bool
- lt(const char_type& __c1, const char_type& __c2);
-
- static int
- compare(const char_type* __s1, const char_type* __s2, size_t __n)
- { return memcmp(__s1, __s2, __n); }
-
- static size_t
- length(const char_type* __s);
-
- static const char_type*
- find(const char_type* __s, size_t __n, const char_type& __a);
-
- static char_type*
- move(char_type* __s1, const char_type* __s2, size_t __n);
-
- static char_type*
- copy(char_type* __s1, const char_type* __s2, size_t __n)
- { return static_cast<char_type*>(memcpy(__s1, __s2, __n)); }
-
- static char_type*
- assign(char_type* __s, size_t __n, char_type __a);
-
- static char_type
- to_char_type(const int_type& __c);
-
- static int_type
- to_int_type(const char_type& __c);
-
- static bool
- eq_int_type(const int_type& __c1, const int_type& __c2);
-
- static int_type
- eof();
-
- static int_type
- not_eof(const int_type& __c);
- };
-}
-
void test01()
{
using namespace std;
- typedef unicode_t int_type;
- typedef char ext_type;
- typedef __enc_traits enc_type;
- typedef codecvt<int_type, ext_type, enc_type> unicode_codecvt;
-
bool test __attribute__((unused)) = true;
- string str1, str2;
// construct a locale object with the C facet
const locale loc01 = locale::classic();
@@ -122,13 +56,15 @@
// template <class Facet> locale(const locale& other, Facet* f)
// construct a locale object with the specialized facet.
locale loc02(locale::classic(), new gnu_codecvt);
- VERIFY (loc01 != loc02);
- VERIFY (loc02.name() == "*");
+ VERIFY( loc01 != loc02 );
+ VERIFY( loc02.name() == "*" );
try
{
- VERIFY (has_facet<gnu_codecvt>(loc02));
- VERIFY (has_facet<c_codecvt>(loc02));
- VERIFY (has_facet<w_codecvt>(loc02));
+ VERIFY( has_facet<gnu_codecvt>(loc02) );
+ VERIFY( has_facet<c_codecvt>(loc02) );
+#ifdef _GLIBCXX_USE_WCHAR_T
+ VERIFY( has_facet<w_codecvt>(loc02) );
+#endif
}
catch(...)
{ VERIFY( false ); }
@@ -140,105 +76,85 @@
catch(...)
{ VERIFY( false ); }
- // unicode_codecvt
- locale loc13(locale::classic(), new unicode_codecvt);
- VERIFY (loc01 != loc13);
- VERIFY (loc13.name() == "*");
- try
- {
- VERIFY (has_facet<c_codecvt>(loc13));
- VERIFY (has_facet<w_codecvt>(loc13));
- VERIFY (has_facet<unicode_codecvt>(loc13));
- }
- catch(...)
- { VERIFY( false ); }
-
- try
- { use_facet<gnu_facet>(loc13); }
- catch(bad_cast& obj)
- { VERIFY( true ); }
- catch(...)
- { VERIFY( false ); }
-
// 2
// locale() throw()
locale loc03;
- VERIFY (loc03 == loc01);
- VERIFY (loc03.name() == "C");
+ VERIFY( loc03 == loc01 );
+ VERIFY( loc03.name() == "C");
locale loc04 = locale::global(loc02);
locale loc05;
- VERIFY (loc05 != loc03);
- VERIFY (loc05 == loc02);
+ VERIFY( loc05 != loc03 );
+ VERIFY( loc05 == loc02 );
// 3
// explicit locale(const char* std_name)
locale loc06 = locale("fr_FR");
- VERIFY (loc06 != loc01);
- VERIFY (loc06 != loc02);
- VERIFY (loc06.name() == "fr_FR");
+ VERIFY( loc06 != loc01 );
+ VERIFY( loc06 != loc02 );
+ VERIFY( loc06.name() == "fr_FR");
locale loc07("");
- VERIFY (loc07 != loc02);
- VERIFY (loc07.name() != "");
+ VERIFY( loc07 != loc02 );
+ VERIFY( loc07.name() != "" );
try
{ locale loc08(static_cast<const char*>(NULL)); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
try
{ locale loc08("saturn_SUN*RA"); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
// 4
// locale(const locale& other, const char* std_name, category)
{
// This is the same as 5 only use "C" for loc("C")
locale loc09(loc06, "C", locale::ctype);
- VERIFY (loc09.name() != "fr_FR");
- VERIFY (loc09.name() != "C");
- VERIFY (loc09.name() != "*");
- VERIFY (loc09 != loc01);
- VERIFY (loc09 != loc06);
+ VERIFY( loc09.name() != "fr_FR" );
+ VERIFY( loc09.name() != "C" );
+ VERIFY( loc09.name() != "*" );
+ VERIFY( loc09 != loc01 );
+ VERIFY( loc09 != loc06 );
locale loc10(loc02, "C", locale::ctype);
- VERIFY (loc10.name() == "*");
- VERIFY (loc10 != loc01); // As not named, even tho facets same...
- VERIFY (loc10 != loc02);
+ VERIFY( loc10.name() == "*" );
+ VERIFY( loc10 != loc01 ); // As not named, even tho facets same...
+ VERIFY( loc10 != loc02 );
locale loc11(loc01, "C", locale::ctype);
- VERIFY (loc11.name() == "C");
- VERIFY (loc11 == loc01);
+ VERIFY( loc11.name() == "C" );
+ VERIFY( loc11 == loc01 );
try
{ locale loc12(loc01, static_cast<const char*>(NULL), locale::ctype); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
try
{ locale loc13(loc01, "localized by the wu-tang clan", locale::ctype); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
locale loc14(loc06, "C", locale::none);
- VERIFY (loc14.name() == "fr_FR");
- VERIFY (loc14 == loc06);
+ VERIFY( loc14.name() == "fr_FR" );
+ VERIFY( loc14 == loc06 );
- locale loc15(loc06, "C", locale::collate);
- VERIFY (loc15.name() != "fr_FR");
- VERIFY (loc15.name() != "C");
- VERIFY (loc15.name() != "*");
- VERIFY (loc15.name() != loc09.name());
- VERIFY (loc15 != loc01);
- VERIFY (loc15 != loc06);
- VERIFY (loc15 != loc09);
+ locale loc15(loc06, "C", locale::collate );
+ VERIFY( loc15.name() != "fr_FR" );
+ VERIFY( loc15.name() != "C" );
+ VERIFY( loc15.name() != "*" );
+ VERIFY( loc15.name() != loc09.name() );
+ VERIFY( loc15 != loc01 );
+ VERIFY( loc15 != loc06 );
+ VERIFY( loc15 != loc09 );
}
// 5
@@ -246,55 +162,52 @@
{
// This is the exact same as 4, with locale("C") for "C"
locale loc09(loc06, loc01, locale::ctype);
- VERIFY (loc09.name() != "fr_FR");
- VERIFY (loc09.name() != "C");
- VERIFY (loc09.name() != "*");
- VERIFY (loc09 != loc01);
- VERIFY (loc09 != loc06);
+ VERIFY( loc09.name() != "fr_FR" );
+ VERIFY( loc09.name() != "C" );
+ VERIFY( loc09.name() != "*" );
+ VERIFY( loc09 != loc01 );
+ VERIFY( loc09 != loc06 );
locale loc10(loc02, loc01, locale::ctype);
- VERIFY (loc10.name() == "*");
- VERIFY (loc10 != loc01); // As not named, even tho facets same...
- VERIFY (loc10 != loc02);
+ VERIFY( loc10.name() == "*");
+ VERIFY( loc10 != loc01 ); // As not named, even tho facets same...
+ VERIFY( loc10 != loc02 );
locale loc11(loc01, loc01, locale::ctype);
- VERIFY (loc11.name() == "C");
- VERIFY (loc11 == loc01);
+ VERIFY( loc11.name() == "C" );
+ VERIFY( loc11 == loc01 );
try
{ locale loc12(loc01, static_cast<const char*>(NULL), locale::ctype); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
try
{ locale loc13(loc01, locale("wu-tang clan"), locale::ctype); }
catch(runtime_error& obj)
- { VERIFY (true); }
+ { VERIFY( true ); }
catch(...)
- { VERIFY (false); }
+ { VERIFY( false ); }
locale loc14(loc06, loc01, locale::none);
- VERIFY (loc14.name() == "fr_FR");
- VERIFY (loc14 == loc06);
+ VERIFY( loc14.name() == "fr_FR" );
+ VERIFY( loc14 == loc06 );
locale loc15(loc06, loc01, locale::collate);
- VERIFY (loc15.name() != "fr_FR");
- VERIFY (loc15.name() != "C");
- VERIFY (loc15.name() != "*");
- VERIFY (loc15.name() != loc09.name());
- VERIFY (loc15 != loc01);
- VERIFY (loc15 != loc06);
- VERIFY (loc15 != loc09);
+ VERIFY( loc15.name() != "fr_FR" );
+ VERIFY( loc15.name() != "C" );
+ VERIFY( loc15.name() != "*" );
+ VERIFY( loc15.name() != loc09.name() );
+ VERIFY( loc15 != loc01 );
+ VERIFY( loc15 != loc06 );
+ VERIFY( loc15 != loc09 );
}
}
-#endif // _GLIBCXX_USE___ENC_TRAITS
int main()
{
-#if _GLIBCXX_USE___ENC_TRAITS
test01();
-#endif
return 0;
}
Index: testsuite/22_locale/locale/cons/unicode/1.cc
===================================================================
--- testsuite/22_locale/locale/cons/unicode/1.cc (revision 0)
+++ testsuite/22_locale/locale/cons/unicode/1.cc (revision 0)
@@ -0,0 +1,142 @@
+// Copyright (C) 2006 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 22.1.1.2 locale constructors and destructors [lib.locale.cons]
+
+#include <cwchar> // for mbstate_t
+#include <locale>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+
+#if _GLIBCXX_USE___ENC_TRAITS
+typedef std::codecvt<char, char, std::mbstate_t> c_codecvt;
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+typedef std::codecvt<wchar_t, char, std::mbstate_t> w_codecvt;
+#endif
+
+class gnu_facet: public std::locale::facet
+{
+public:
+ static std::locale::id id;
+};
+
+std::locale::id gnu_facet::id;
+
+// Need some char_traits specializations for this to work.
+typedef unsigned short unicode_t;
+
+namespace std
+{
+ template<>
+ struct char_traits<unicode_t>
+ {
+ typedef unicode_t char_type;
+ // Unsigned as wint_t is unsigned.
+ typedef unsigned long int_type;
+ typedef streampos pos_type;
+ typedef streamoff off_type;
+ typedef mbstate_t state_type;
+
+ static void
+ assign(char_type& __c1, const char_type& __c2);
+
+ static bool
+ eq(const char_type& __c1, const char_type& __c2);
+
+ static bool
+ lt(const char_type& __c1, const char_type& __c2);
+
+ static int
+ compare(const char_type* __s1, const char_type* __s2, size_t __n)
+ { return memcmp(__s1, __s2, __n); }
+
+ static size_t
+ length(const char_type* __s);
+
+ static const char_type*
+ find(const char_type* __s, size_t __n, const char_type& __a);
+
+ static char_type*
+ move(char_type* __s1, const char_type* __s2, size_t __n);
+
+ static char_type*
+ copy(char_type* __s1, const char_type* __s2, size_t __n)
+ { return static_cast<char_type*>(memcpy(__s1, __s2, __n)); }
+
+ static char_type*
+ assign(char_type* __s, size_t __n, char_type __a);
+
+ static char_type
+ to_char_type(const int_type& __c);
+
+ static int_type
+ to_int_type(const char_type& __c);
+
+ static bool
+ eq_int_type(const int_type& __c1, const int_type& __c2);
+
+ static int_type
+ eof();
+
+ static int_type
+ not_eof(const int_type& __c);
+ };
+}
+
+void test01()
+{
+ using namespace std;
+ typedef unicode_t int_type;
+ typedef char ext_type;
+ typedef __enc_traits enc_type;
+ typedef codecvt<int_type, ext_type, enc_type> unicode_codecvt;
+
+ bool test __attribute__((unused)) = true;
+
+ // unicode_codecvt
+ locale loc13(locale::classic(), new unicode_codecvt);
+ VERIFY( loc01 != loc13 );
+ VERIFY( loc13.name() == "*" );
+ try
+ {
+ VERIFY( has_facet<c_codecvt>(loc13) );
+#ifdef _GLIBCXX_USE_WCHAR_T
+ VERIFY( has_facet<w_codecvt>(loc13) );
+#endif
+ VERIFY( has_facet<unicode_codecvt>(loc13) );
+ }
+ catch(...)
+ { VERIFY( false ); }
+
+ try
+ { use_facet<gnu_facet>(loc13); }
+ catch(bad_cast& obj)
+ { VERIFY( true ); }
+ catch(...)
+ { VERIFY( false ); }
+}
+#endif // _GLIBCXX_USE___ENC_TRAITS
+
+int main()
+{
+#if _GLIBCXX_USE___ENC_TRAITS
+ test01();
+#endif
+ return 0;
+}
Index: testsuite/22_locale/locale/cons/29217.cc
===================================================================
--- testsuite/22_locale/locale/cons/29217.cc (revision 0)
+++ testsuite/22_locale/locale/cons/29217.cc (revision 0)
@@ -0,0 +1,54 @@
+// { dg-require-namedlocale "" }
+
+// Copyright (C) 2006 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+// USA.
+
+// 22.1.1.2 locale constructors and destructors [lib.locale.cons]
+
+#include <locale>
+#include <testsuite_hooks.h>
+
+// libstdc++/29217
+void test01()
+{
+ bool test __attribute__((unused)) = true;
+ using namespace std;
+
+ locale::global(locale(locale(), "en_US.UTF-8",
+ locale::collate | locale::ctype));
+
+ VERIFY( locale().name() == "LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;"
+ "LC_TIME=C;LC_COLLATE=en_US.UTF-8;LC_MONETARY=C;LC_MESSAGES=C;"
+ "LC_PAPER=C;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;"
+ "LC_MEASUREMENT=C;LC_IDENTIFICATION=C" );
+
+ VERIFY( locale().name() == setlocale(LC_ALL, NULL) );
+
+ locale loc1 = locale(locale::classic(), "en_US.UTF-8", locale::time);
+
+ VERIFY( loc1.name() == "LC_CTYPE=C;LC_NUMERIC=C;LC_TIME=en_US.UTF-8;"
+ "LC_COLLATE=C;LC_MONETARY=C;LC_MESSAGES=C;LC_PAPER=C;LC_NAME=C;"
+ "LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=C;"
+ "LC_IDENTIFICATION=C" );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
Index: include/bits/locale_classes.h
===================================================================
--- include/bits/locale_classes.h (revision 117206)
+++ include/bits/locale_classes.h (working copy)
@@ -104,12 +104,12 @@
static const category none = 0;
static const category ctype = 1L << 0;
static const category numeric = 1L << 1;
- static const category collate = 1L << 2;
- static const category time = 1L << 3;
+ static const category time = 1L << 2;
+ static const category collate = 1L << 3;
static const category monetary = 1L << 4;
static const category messages = 1L << 5;
- static const category all = (ctype | numeric | collate |
- time | monetary | messages);
+ static const category all = (ctype | numeric | time |
+ collate | monetary | messages);
//@}
// Construct/copy/destroy:
@@ -496,8 +496,8 @@
char** _M_names;
static const locale::id* const _S_id_ctype[];
static const locale::id* const _S_id_numeric[];
+ static const locale::id* const _S_id_time[];
static const locale::id* const _S_id_collate[];
- static const locale::id* const _S_id_time[];
static const locale::id* const _S_id_monetary[];
static const locale::id* const _S_id_messages[];
static const locale::id* const* const _S_facet_categories[];
Index: src/locale_init.cc
===================================================================
--- src/locale_init.cc (revision 117206)
+++ src/locale_init.cc (working copy)
@@ -346,8 +346,8 @@
// Order must match the decl order in class locale.
locale::_Impl::_S_id_ctype,
locale::_Impl::_S_id_numeric,
+ locale::_Impl::_S_id_time,
locale::_Impl::_S_id_collate,
- locale::_Impl::_S_id_time,
locale::_Impl::_S_id_monetary,
locale::_Impl::_S_id_messages,
0
Index: src/locale.cc
===================================================================
--- src/locale.cc (revision 117206)
+++ src/locale.cc (working copy)
@@ -60,8 +60,8 @@
const locale::category locale::none;
const locale::category locale::ctype;
const locale::category locale::numeric;
+ const locale::category locale::time;
const locale::category locale::collate;
- const locale::category locale::time;
const locale::category locale::monetary;
const locale::category locale::messages;
const locale::category locale::all;