You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stdcxx.apache.org by el...@apache.org on 2008/05/07 22:28:20 UTC

svn commit: r654264 - /stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp

Author: elemings
Date: Wed May  7 13:28:19 2008
New Revision: 654264

URL: http://svn.apache.org/viewvc?rev=654264&view=rev
Log:
2008-05-07  Eric Lemings <er...@roguewave.com>

	STDCXX-869
	* branches/4.2.x/tests/localization/22.locale.synopsis.cpp: Test
	missing from 4.2.x branch.  Merged from trunk.


Added:
    stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp

Added: stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp
URL: http://svn.apache.org/viewvc/stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp?rev=654264&view=auto
==============================================================================
--- stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp (added)
+++ stdcxx/branches/4.2.x/tests/localization/22.locale.synopsis.cpp Wed May  7 13:28:19 2008
@@ -0,0 +1,1992 @@
+/***************************************************************************
+ *
+ * 22.locale.synopsis.cpp - test exercising synopsis of header <locale>
+ *
+ * $Id$
+ *
+ ***************************************************************************
+ *
+ * Licensed to the Apache Software  Foundation (ASF) under one or more
+ * contributor  license agreements.  See  the NOTICE  file distributed
+ * with  this  work  for  additional information  regarding  copyright
+ * ownership.   The ASF  licenses this  file to  you under  the Apache
+ * License, Version  2.0 (the  "License"); you may  not use  this file
+ * except in  compliance with the License.   You may obtain  a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the  License is distributed on an  "AS IS" BASIS,
+ * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY  KIND, either  express or
+ * implied.   See  the License  for  the  specific language  governing
+ * permissions and limitations under the License.
+ *
+ * Copyright 1994-2008 Rogue Wave Software.
+ *
+ **************************************************************************/
+
+#include <rw/_defs.h>
+
+// disable implicit inclusion to work around a limitation in
+// IBM VAC++ 5.0.2.0 (PR #26959)
+#if defined __IBMCPP__ && !defined _RWSTD_NO_IMPLICIT_INCLUSION
+#  define _RWSTD_NO_IMPLICIT_INCLUSION
+#endif
+
+// make protected members accessible if possible
+#if defined _RWSTD_NO_EXPORT && !defined _MSC_VER
+#  define protected public
+#endif
+
+#include <iterator>
+#include <locale>
+
+#include <driver.h>
+
+static void
+test_lc_defs ()
+{
+    rw_info (0, __FILE__, __LINE__, "checking LC_XXX constants");
+
+    // check that <locale> doesn't introduce any LC_XXX constants
+    // (not required, but it's good practice to keep headers clean)
+    static const char* const lc_defs[] =
+    {
+#ifdef LC_ALL
+        "LC_ALL",
+#endif   // LC_ALL
+#ifdef LC_COLLATE
+        "LC_COLLATE",
+#endif   // LC_COLLATE
+#ifdef LC_CTYPE
+        "LC_CTYPE",
+#endif   // LC_CTYPE
+#ifdef LC_MONETARY
+        "LC_MONETARY",
+#endif   // LC_MONETARY
+#ifdef LC_NUMERIC
+        "LC_NUMERIC",
+#endif   // LC_NUMERIC
+#ifdef LC_TIME
+        "LC_TIME",
+#endif   // LC_TIME
+#ifdef LC_MESSAGES
+        "LC_MESSAGES",
+#endif   // LC_MESSAGES
+
+        0
+    };
+
+    for (unsigned i = 0; i != sizeof lc_defs / sizeof *lc_defs; ++i) {
+        rw_assert (!lc_defs [i], __FILE__, __LINE__,
+                   "<locale> unexpectedly #defines %s", lc_defs [i]);
+    }
+}
+
+static void
+test_isxxx ()
+{
+    rw_info (0, __FILE__, __LINE__, "checking isxxx() macros");
+
+    // check that <locale> doesn't introduce any isxxx() macros
+    static const char* const isxxx[] =
+    {
+#ifdef isspace
+        "isspace",
+#endif   // isspace
+#ifdef isprint
+        "isprint",
+#endif   // isprint
+#ifdef iscntrl
+        "iscntrl",
+#endif   // iscntrl
+#ifdef isupper
+        "isupper",
+#endif   // isupper
+#ifdef islower
+        "islower",
+#endif   // islower
+#ifdef isalpha
+        "isalpha",
+#endif   // isalpha
+#ifdef isdigit
+        "isdigit",
+#endif   // isdigit
+#ifdef ispunct
+        "ispunct",
+#endif   // ispunct
+#ifdef isxdigit
+        "isxdigit",
+#endif   // isxdigit
+#ifdef isalnum
+        "isalnum",
+#endif   // isalnum
+#ifdef isgraph
+        "isgraph",
+#endif   // isgraph
+#ifdef toupper
+        "toupper",
+#endif   // toupper
+#ifdef tolower
+        "tolower",
+#endif   // tolower
+
+        0
+    };
+
+    for (unsigned i = 0; i != sizeof isxxx / sizeof *isxxx; ++i) {
+        rw_assert (!isxxx [i], __FILE__, __LINE__,
+                   "<locale> unexpectedly #defines %s", isxxx [i]);
+    }
+}
+
+/***************************************************************************/
+
+#include <clocale>   // for LC_XXX macros
+#include <cwchar>    // for mbstate_t
+
+#if !defined LC_MESSAGES && defined _RWSTD_LC_MESSAGES
+#  define LC_MESSAGES _RWSTD_LC_MESSAGES
+#endif   // !LC_MESSAGES && _RWSTD_LC_MESSAGES
+
+// exercise the signature of a nonmember (or static member) function
+#define FUN(result, name, arg_list) do {                              \
+        /* make name unique to prevent bogus gcc -Wshadow warnings */ \
+        result (*_RWSTD_PASTE (pf, __LINE__)) arg_list = &name;       \
+        _RWSTD_UNUSED (_RWSTD_PASTE (pf, __LINE__));                  \
+    } while (0)
+
+/***************************************************************************/
+
+// exercise the signatures of std::{has,use}_facet<>()
+template <class charT>
+static void
+test_have_use_facet ()
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::has_facet<Facet>(std::locale&) synopsis");
+    rw_info (0, __FILE__, __LINE__,
+             "std::use_facet<Facet>(std::locale&) synopsis");
+
+#if !defined __HP_aCC || __HP_aCC > 33100
+
+// working around an HP aCC bug (see PR #23312)
+
+#  if    !(defined __GNUG__ || __GNUG__ > 2 || __GNUC_MINOR__ > 96) \
+      && !(defined _MSC_VER || _MSC_VER >= 0x1300)
+
+    // working around a gcc 2.9{5,6} ICE
+    // working around an MSVC 6.0 bug (PR #26307)
+    FUN (const std::ctype<charT>&,
+         std::use_facet<std::ctype<charT> >, (const std::locale&));
+    FUN (bool, std::has_facet<std::ctype<charT> >, (const std::locale&));
+
+#  endif   // gcc > 2.96 && MSVC > 6.0
+
+#endif   // __HP_aCC > 33000
+}
+
+/***************************************************************************/
+
+// exercise the signatures of the convenience locale interfaces
+template <class charT>
+static void
+test_convenience_funs ()
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::isxxx(std::locale&) convenience functions synopsis");
+
+    FUN (bool, std::isspace, (charT, const std::locale&));
+    FUN (bool, std::isprint, (charT, const std::locale&));
+    FUN (bool, std::iscntrl, (charT, const std::locale&));
+    FUN (bool, std::isupper, (charT, const std::locale&));
+    FUN (bool, std::islower, (charT, const std::locale&));
+    FUN (bool, std::isalpha, (charT, const std::locale&));
+    FUN (bool, std::isdigit, (charT, const std::locale&));
+    FUN (bool, std::ispunct, (charT, const std::locale&));
+    FUN (bool, std::isxdigit, (charT, const std::locale&));
+    FUN (bool, std::isalnum, (charT, const std::locale&));
+    FUN (bool, std::isgraph, (charT, const std::locale&));
+    FUN (charT, std::toupper, (charT, const std::locale&));
+    FUN (charT, std::tolower, (charT, const std::locale&));
+}
+
+_RWSTD_NAMESPACE (std) {
+
+#if !defined _MSC_VER
+
+// verify that specializations are present in the lib
+_RWSTD_SPECIALIZED_CLASS class ctype<char>;
+_RWSTD_SPECIALIZED_CLASS class ctype_byname<char>;
+
+#  ifndef _RWSTD_NO_WCHAR_T
+
+_RWSTD_SPECIALIZED_CLASS class ctype<wchar_t>;
+_RWSTD_SPECIALIZED_CLASS class ctype_byname<wchar_t>;
+
+#  endif   // _RWSTD_NO_WCHAR_T
+
+#endif   // _MSC_VER
+
+}   // namespace std
+
+/***************************************************************************/
+
+// test for the presence of the required facet templates
+// and their specializations (as required by Table 52)
+template <class charT>
+static void
+test_facets ()
+{
+    // introduce a typedef to work around a SunPro 5.3 bug (see PR #25967)
+    typedef charT char_type;
+
+    const std::locale::facet *pfac;
+    _RWSTD_UNUSED (pfac);
+
+    {
+        // collate category
+        const std::collate<char_type>        *col        = 0;
+        const std::collate_byname<char_type> *col_byname = 0;
+
+        // verify that facet publicly derives from locale::facet
+        pfac = col;
+        col  = col_byname;
+    }
+
+    {
+        // ctype category
+
+        // force a link failure if required specializations aren't
+        // provided (e.g., if only the primary template is defined)
+        const std::ctype<char_type>        *ctp = 0;
+        const std::ctype_byname<char_type> *ctp_byname = 0;
+
+        // verify that facet publicly derives from locale::facet
+        const std::ctype_base *ctpbase = ctp;
+        pfac = ctp;
+        ctp  = ctp_byname;
+
+        _RWSTD_UNUSED (ctpbase);
+    }
+
+    {
+        const std::codecvt<char_type, char, std::mbstate_t> *cvt = 0;
+        const std::codecvt_byname<char_type, char, std::mbstate_t>
+            *cvt_byname = 0;
+
+        // verify that facet publicly derives from locale::facet
+        pfac = cvt;
+
+        const std::codecvt_base *pcvtbase = cvt;
+        _RWSTD_UNUSED (pcvtbase);
+
+        cvt = cvt_byname;
+    }
+
+    typedef std::char_traits<char_type>               CTr;
+    typedef std::istreambuf_iterator<char_type, CTr > IIt;
+    typedef std::ostreambuf_iterator<char_type, CTr > OIt;
+
+    {
+        // monetary category
+
+        const std::moneypunct<char_type, false>        *mpun             = 0;
+        const std::moneypunct<char_type, true>         *mpun_intl        = 0;
+        const std::moneypunct_byname<char_type, false> *mpun_byname      = 0;
+        const std::moneypunct_byname<char_type, true>  *mpun_intl_byname = 0;
+        const std::money_get<char_type, IIt>           *mget             = 0;
+        const std::money_put<char_type, OIt>           *mput             = 0;
+
+        // verify that facets publicly derive from locale::facet
+        pfac = mpun;
+        pfac = mpun_intl;
+        pfac = mget;
+        pfac = mput;
+
+        mpun      = mpun_byname;
+        mpun_intl = mpun_intl_byname;
+
+        // verify that punct facets publicly derive from money_base
+        const std::money_base *pmbase = mpun;
+        pmbase = mpun_intl;
+        _RWSTD_UNUSED (pmbase);
+
+#ifndef _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+        const std::moneypunct<char_type> *pmpun_noarg = mpun;
+        _RWSTD_UNUSED (pmpun_noarg);
+
+        // verify default template arguments
+        const std::money_get<char_type> *pmget = mget;
+        const std::money_put<char_type> *pmput = mput;
+        _RWSTD_UNUSED (pmget);
+        _RWSTD_UNUSED (pmput);
+
+#endif   // _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+    }
+
+    {
+        // numeric category
+
+        const std::num_get<char_type, IIt> *nget = 0;
+        const std::num_put<char_type, OIt> *nput = 0;
+
+        // verify that facets publicly derive from locale::facet
+        pfac = nget;
+        pfac = nput;
+
+#ifndef _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+        // verify default template arguments
+        const std::num_get<char_type> *pnget = nget;
+        const std::num_put<char_type> *pnput = nput;
+        _RWSTD_UNUSED (pnget);
+        _RWSTD_UNUSED (pnput);
+
+#endif   // _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+    }
+
+    {
+        // time category
+
+        const std::time_get<char_type, IIt> *tget = 0;
+        const std::time_put<char_type, OIt> *tput = 0;
+
+        // verify that facets publicly derive from locale::facet
+        pfac = tget;
+        pfac = tput;
+
+#ifndef _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+        // verify default template arguments
+        const std::time_get<char_type> *ptget = tget;
+        const std::time_put<char_type> *ptput = tput;
+        _RWSTD_UNUSED (ptget);
+        _RWSTD_UNUSED (ptput);
+
+#endif   // _RWSTD_NO_DEFAULT_TEMPLATE_ARGS
+
+    }
+
+    {
+        // messages category
+
+        const std::messages<char_type>        *msgs = 0;
+        const std::messages_byname<char_type> *msgs_byname = 0;
+
+        // verify that facets publicly derive from locale::facet
+        pfac = msgs;
+
+        const std::messages_base       *pmsgbase = msgs;
+        const std::messages<char_type> *pmsgs    = msgs_byname;
+
+        _RWSTD_UNUSED (pmsgbase);
+        _RWSTD_UNUSED (pmsgs);
+    }
+}
+
+/***************************************************************************/
+
+#ifndef _RWSTD_NO_EXPLICIT
+
+// helper to verify that locale and facet ctors are explicit
+// not defined since they must not be referenced if test is successful
+void is_explicit (const std::locale&);
+void is_explicit (const std::locale::facet&);
+
+void is_explicit (const std::collate<char>&);
+void is_explicit (const std::ctype<char>&);
+
+#  ifndef _RWSTD_NO_WCHAR_T
+
+void is_explicit (const std::collate<wchar_t>&);
+void is_explicit (const std::ctype<wchar_t>&);
+
+#  endif   // _RWSTD_NO_WCHAR_T
+
+struct has_implicit_ctor
+{
+    // NOT explicit
+
+    // for locale::facet::facet (size_t = 0) and derived facet ctors
+    has_implicit_ctor (std::size_t) { /* empty */ }
+
+    // for ctype<char>::ctype (const mask*, bool = false, size_t = 0)
+    has_implicit_ctor (const std::ctype_base::mask*) { /* empty */ }
+
+    // for locale::locale (const char*, size_t = 0)
+    has_implicit_ctor (const char*) { /* empty */ }
+};
+
+// calls to the overloaded is_explicit() resolve to the function below
+void is_explicit (const has_implicit_ctor&) { /* empty */ }
+
+#endif   // _RWSTD_NO_EXPLICIT
+
+/***************************************************************************/
+
+// local to test_locale
+static bool dtor_called = false;
+
+struct Facet: std::locale::facet
+{
+    typedef std::locale::facet Base;
+
+    // default argument provided to work around a library limitation
+    // that requires all facets to have default ctors
+    Facet (std::size_t refs = 0): Base (refs) { /* empty */ }
+
+    ~Facet () {
+        dtor_called = true;
+    }
+
+    static std::locale::id id;
+
+#ifdef _RWSTD_NO_MEMBER_TEMPLATES
+
+    virtual std::locale::id& _C_get_id () const {
+        return id;
+    }
+
+#endif   // _RWSTD_NO_MEMBER_TEMPLATES
+};
+
+
+std::locale::id Facet::id;
+
+// using a global in favor of a static local
+// to work around an MSVC 6.0 bug (see PR #26305)
+static bool is_dtor_virtual;
+
+
+template <class charT>
+struct StringTypes
+{
+    typedef std::char_traits<charT>                          traits_type;
+    typedef std::allocator<charT>                            Allocator;
+    typedef std::basic_string<charT, traits_type, Allocator> string_type;
+};
+
+
+// test class locale definition
+static void
+test_locale ()
+{
+    rw_info (0, __FILE__, __LINE__, "class std::locale synopsis");
+
+    // 21.1.1.1.1
+    const std::locale::category *pcat = (int*)0;
+
+#ifndef _RWSTD_NO_STATIC_CONST_MEMBER_INIT
+
+    // verify that category constants are defined
+    pcat = &std::locale::none;
+    pcat = &std::locale::collate;
+    pcat = &std::locale::ctype;
+    pcat = &std::locale::monetary;
+    pcat = &std::locale::numeric;
+    pcat = &std::locale::time;
+    pcat = &std::locale::messages;
+    pcat = &std::locale::all;
+
+#endif   // _RWSTD_NO_STATIC_CONST_MEMBER_INIT
+
+    // verify that category constants are constant integral expressions
+    switch (*pcat) {
+    case std::locale::none:
+    case std::locale::collate:
+    case std::locale::ctype:
+    case std::locale::monetary:
+    case std::locale::numeric:
+    case std::locale::time:
+    case std::locale::messages:
+    case std::locale::all:
+        break;
+    }
+
+    static const int c_cats [] = {
+        LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
+
+#ifdef LC_MESSAGES
+        , LC_MESSAGES
+#endif   // LC_MESSAGES
+
+    };
+
+    static const std::locale::category cats[] = {
+        std::locale::none, std::locale::collate, std::locale::ctype,
+        std::locale::monetary, std::locale::numeric, std::locale::time,
+        std::locale::messages, std::locale::all
+    };
+
+    for (pcat = cats; pcat != cats + sizeof cats / sizeof *cats - 1; ++pcat) {
+
+        bool success = true;
+
+        for (unsigned i = pcat - cats + 1; i < sizeof cats / sizeof *cats; ++i)
+            if (   *pcat != std::locale::all
+                && cats [i] != std::locale::all
+                && (*pcat & cats [i]))
+                rw_assert (success = false, __FILE__, __LINE__,
+                           "(%{Lc} & %{Lc}) != 0", *pcat, cats [i]);
+
+        for (unsigned j = 0; j != sizeof c_cats / sizeof *c_cats; ++j) {
+            // locale::category values must not conflict with LC_XXX constants
+            if (*pcat & c_cats [j])
+                rw_assert (success = false, __FILE__, __LINE__,
+                           "(%{Lc} & %{Lc}) != 0", *pcat, c_cats [j]);
+
+            if (*pcat == c_cats [j])
+                rw_assert (success = false, __FILE__, __LINE__,
+                           "%{Lc} != %{Lc}", *pcat, c_cats [j]);
+        }
+
+        rw_assert (success, __FILE__, __LINE__, "%{Lc}", *pcat);
+    }
+
+    // 21.1.1.1.1, p1
+    const int all =   std::locale::collate
+                    | std::locale::ctype
+                    | std::locale::monetary
+                    | std::locale::numeric
+                    | std::locale::time
+                    | std::locale::messages;
+
+    rw_assert (std::locale::all == all, __FILE__, __LINE__,
+               "std::locale::all == %#x, got %#x", all, std::locale::all);
+
+    // 22.1.1.1.2
+
+    // verify that locale::facet::facet (size_t) is explicit
+    is_explicit (std::size_t ());
+
+    {
+        // verify that ctor takes a default argument
+        struct Facet: std::locale::facet {
+
+            typedef std::locale::facet Base;
+
+            Facet (): Base () { /* empty */ }
+            Facet (std::size_t ref): Base (ref) {/* empty */  }
+            ~Facet () {
+                is_dtor_virtual = true;
+            }
+#ifdef _RWSTD_NO_MEMBER_TEMPLATES
+
+            virtual std::locale::id& _C_get_id () const {
+                static std::locale::id id;
+                return id;
+            }
+
+#endif   // _RWSTD_NO_MEMBER_TEMPLATES
+        };
+
+        // delete a derived object using a pointer to the base
+        delete (std::locale::facet*)new Facet ();
+        rw_assert (is_dtor_virtual, __FILE__, __LINE__,
+                   "locale::facet::~facet() not virtual");
+    }
+
+    // 22.1.1.1.3 - dfeault ctor and dtor are public
+    std::locale::id id;
+    _RWSTD_UNUSED (id);
+
+    // 22.1.1.2, p1
+    const std::locale l;
+
+    // 22.1.1.2, p3
+    std::locale l2 (l);
+
+    // 22.1.1.2, p6
+    (void)std::locale ("");
+
+    // verify that locale::locale (const char*) is explicit
+    is_explicit ((const char*)"");
+
+    // 22.1.1.2, p9
+    (void)std::locale (l, "", std::locale::all);
+
+#ifndef _RWSTD_NO_MEMBER_TEMPLATES
+
+    Facet *pf = new Facet (1 /* ref count */);
+
+    {
+        // 22.1.1.2, p12
+        // enclose unnamed temporary in its own scope to work around
+        // a SunPro 5.4 bug which amkes it calls the dtor too late
+        // see PR #27543
+        (void)std::locale (l, pf);
+    }
+
+    // exercise 22.1.1.1.2, p2, refs == 1
+    rw_assert (!dtor_called, __FILE__, __LINE__,
+               "facet dtor called for ref count of 1");
+
+    if (!dtor_called)
+        delete pf;
+
+    dtor_called = false;
+
+    // exercise 22.1.1.1.2, p2, refs == 0
+    pf = new Facet (0 /* ref count */);
+
+    {
+        // create an unnamed temporary object and force it to go out of
+        // scope (in case the compiler, such as SunPro 5.4, fails to
+        // detsroy it at the end of the expression) so that it is forced
+        // to destroy the user-defined facet
+        (void)std::locale (l, pf);
+    }
+
+    rw_assert (dtor_called, __FILE__, __LINE__,
+               "UD facet dtor not called for ref count of 0");
+
+    if (!dtor_called)
+        delete pf;
+
+    pf = 0;
+
+#endif   // _RWSTD_NO_MEMBER_TEMPLATES
+
+    // 22.1.1.2, p14
+    (void)std::locale (l, l, std::locale::all);
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#define MEMFUN(result, name, arg_list)                                   \
+        do {                                                             \
+           /* jumping thru hoops to avoid bogus gcc -Wshadow warnings */ \
+           result (std::locale::* _RWSTD_PASTE (pf, __LINE__))           \
+               arg_list = &std::locale::name;                            \
+           _RWSTD_UNUSED (_RWSTD_PASTE (pf, __LINE__));                  \
+         }  while (0)
+
+#if !defined __HP_aCC || __HP_aCC > 33100
+
+    // working around an HP aCC bug (see PR #23312)
+
+    // 22.1.1.2, p4
+    MEMFUN (const std::locale&, operator=,(const std::locale&) _PTR_THROWS(()));
+
+#endif   // __HP_aCC > 33000
+
+#ifndef _RWSTD_NO_MEMBER_TEMPLATES
+
+#  if !defined __HP_aCC || __HP_aCC > 33100
+
+    // working around an HP aCC bug (see PR #23312)
+
+    // 22.1.1.3, p1
+    MEMFUN (std::locale, combine<Facet>, (const std::locale&) const);
+
+#  endif   // __HP_aCC > 33000
+
+#endif   // _RWSTD_NO_MEMBER_TEMPLATES
+
+    // 22.1.1.3, p5
+    MEMFUN (std::string, name, () const);
+
+    // 22.1.1.4, p1
+    MEMFUN (bool, operator==, (const std::locale&) const);
+
+    // 22.1.1.4, p2
+    MEMFUN (bool, operator!=, (const std::locale&) const);
+
+    // 22.1.1.4, p3
+    MEMFUN (bool, operator(), (const std::string&, const std::string&) const);
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+    MEMFUN (bool, operator(), (const std::wstring&, const std::wstring&)const);
+
+#endif   // _RWSTD_NO_WCHAR_T
+
+#ifndef _RWSTD_NO_MEMBER_TEMPLATES
+
+    // exercise a specialization other than on the default char types
+    typedef StringTypes<int>::string_type IntString;
+
+    MEMFUN (bool, operator(), (const IntString&, const IntString&) const);
+
+#endif   // _RWSTD_NO_MEMBER_TEMPLATES
+
+    // 22.1.1.5
+    FUN (std::locale, std::locale::global, (const std::locale&));
+    FUN (const std::locale&, std::locale::classic, ());
+}
+
+/***************************************************************************/
+
+// test class template ctype definition
+
+template <class charT>
+struct CtypeDerived: std::ctype<charT>
+{
+    typedef std::ctype<charT>     CtypeT;
+    typedef std::ctype_base::mask M;
+    typedef const charT*          PtrT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                       \
+        do {                                                 \
+            result (CtypeT::* pf) arg_list = &CtypeT::name;  \
+            _RWSTD_UNUSED (pf);                              \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected members (see `#define protected public' above)
+        MEMFUN (bool, do_is, (M, charT) const);
+        MEMFUN (PtrT, do_is, (PtrT, PtrT, M*) const);
+
+        // lwg issue 124
+        MEMFUN (PtrT, do_scan_is, (M, PtrT, PtrT) const);
+        MEMFUN (PtrT, do_scan_not, (M, PtrT, PtrT) const);
+        MEMFUN (charT, do_toupper, (charT) const);
+        MEMFUN (PtrT, do_toupper, (charT*, PtrT) const);
+        MEMFUN (charT, do_tolower, (charT) const);
+        MEMFUN (PtrT, do_tolower, (charT*, PtrT) const);
+        MEMFUN (charT, do_widen, (char) const);
+        MEMFUN (const char*,
+                do_widen, (const char*, const char*, charT*) const);
+        MEMFUN (char, do_narrow, (charT, char) const);
+        MEMFUN (PtrT, do_narrow,
+                (PtrT, PtrT, char, char*) const);
+    }
+};
+
+
+// exercise the primary template
+template <class charT>
+/*static*/ void
+test_ctype_specialization ()
+{
+    CtypeDerived<charT>::test_protected_members ();
+}
+
+
+struct CtypeCharDerived: std::ctype<char>
+{
+    typedef std::ctype<char>      CtypeT;
+    typedef std::ctype_base::mask Mask;
+
+    // verify that all required ctors (or one with default args) exist
+    CtypeCharDerived (): CtypeT () { /* empty */ }
+    CtypeCharDerived (const Mask *tbl): CtypeT (tbl) { /* empty */ }
+    CtypeCharDerived (const Mask *tbl, bool del): CtypeT (tbl, del) { /* empty */ }
+    CtypeCharDerived (const Mask *tbl, bool del, std::size_t ref)
+        : CtypeT (tbl, del, ref) { /* empty */ }
+
+    static void test_protected_members () {
+
+#ifndef _RWSTD_NO_STATIC_CONST_MEMBER_INIT
+
+        // verify that table_size is properly defined
+        const std::size_t *psz = &std::ctype<char>::table_size;
+
+#else
+
+        const std::size_t dummy = std::ctype<char>::table_size;
+        const std::size_t *psz  = &dummy;
+
+#endif   // _RWSTD_NO_STATIC_CONST_MEMBER_INIT
+
+        // verify that table_size is an integral constant expression
+        switch (*psz) {
+        case std::ctype<char>::table_size: break;
+        }
+
+        MEMFUN (char, do_toupper, (char) const);
+        MEMFUN (const char*, do_toupper, (char*, const char*) const);
+        MEMFUN (char, do_tolower, (char) const);
+        MEMFUN (const char*, do_tolower, (char*, const char*) const);
+        MEMFUN (char, do_widen, (char) const);
+        MEMFUN (const char*, do_widen,
+                (const char*, const char*, char*) const);
+        MEMFUN (char, do_narrow, (char, char) const);
+        MEMFUN (const char*, do_narrow,
+                (const char*, const char*, char, char*) const);
+
+        // 22.2.1.3.2, p12
+        MEMFUN (const std::ctype_base::mask*,
+                table, () const _PTR_THROWS (()));
+
+        // 22.2.1.3.3
+        FUN (const std::ctype_base::mask*,
+             CtypeT::classic_table, () _PTR_THROWS (()));
+    }
+};
+
+
+// exercise the char specialization
+_RWSTD_SPECIALIZED_FUNCTION
+/*static*/ void
+test_ctype_specialization<char> ()
+{
+    // prevent multiple assertions
+    static int called /* = false */;
+    if (called++)
+        return;
+
+    // 22.2.1.3.2, p3 - verify that ctor is explicit
+    is_explicit ((const std::ctype_base::mask*)0);
+
+    CtypeCharDerived::test_protected_members ();
+}
+
+
+// skip POSIX-dependent behavior
+static int opt_enable_posix      = 0;   // --enable-posix
+
+
+template <class charT>
+static void
+test_ctype (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::ctype<%s> synopsis", cname);
+
+    std::ctype_base::mask m = std::ctype_base::space;
+    _RWSTD_UNUSED (m);
+
+    const std::ctype_base::mask *pm = 0;
+    _RWSTD_UNUSED (pm);
+
+    // verify that mask constants are constant integral expressions
+    // whose address can be taken
+    switch (m) {
+
+#ifndef _RWSTD_NO_STATIC_CONST_MEMBER_INIT
+   // see lwg issue 339
+#  define ADDR(name)     pm = &std::ctype_base::name
+#else
+#  define ADDR(ignore)   (void)0
+#endif
+
+#if !defined __IBMCPP__ || __IBMCPP__ > 800
+    // working around an IBM VAC++ bug #559
+    case std::ctype_base::mask (): break;
+#endif   // !VAC+ || VAC++ > 7.0
+
+    case std::ctype_base::space:  ADDR (space); break;
+    case std::ctype_base::print:  ADDR (print); break;
+    case std::ctype_base::cntrl:  ADDR (cntrl); break;
+    case std::ctype_base::upper:  ADDR (upper); break;
+    case std::ctype_base::lower:  ADDR (lower); break;
+    case std::ctype_base::alpha:  ADDR (alpha); break;
+    case std::ctype_base::digit:  ADDR (digit); break;
+    case std::ctype_base::punct:  ADDR (punct); break;
+    case std::ctype_base::xdigit: ADDR (xdigit); break;
+    case std::ctype_base::alnum:  ADDR (alnum); break;
+    case std::ctype_base::graph:  ADDR (graph); break;
+
+    default: break;
+    }
+
+    // prevent unnecessary assertions
+    if (sizeof (charT) == sizeof (char)) {
+        rw_assert (std::ctype_base::alnum ==
+                   (std::ctype_base::alpha | std::ctype_base::digit),
+                   __FILE__, __LINE__,
+                   "std::ctype_base::alnum = %#x, expected %#x",
+                   std::ctype_base::alnum,
+                   std::ctype_base::alpha | std::ctype_base::digit);
+
+        if (opt_enable_posix) {
+            // POSIX allows graph characters that aren't alnum or punct
+            // 22.2.1 says the numeric values are for exposition only
+            // which presumably applies to all the constants
+            rw_assert (std::ctype_base::graph
+                       == (std::ctype_base::alnum | std::ctype_base::punct),
+                       __FILE__, __LINE__,
+                       "std::ctype_base::graph = %#x, expected %#x",
+                       std::ctype_base::graph,
+                       std::ctype_base::alnum | std::ctype_base::punct);
+        }
+    }
+
+    typedef std::ctype<charT>     CtypeT;
+    typedef typename CtypeT::mask Mask;
+
+    charT *pc = (typename CtypeT::char_type*)0;
+    _RWSTD_UNUSED (pc);
+
+    typedef const charT* PtrT;
+
+    MEMFUN (bool, is, (Mask, charT) const);
+    MEMFUN (PtrT, is, (PtrT, PtrT, Mask*) const);
+    MEMFUN (PtrT, scan_is, (Mask, PtrT, PtrT) const);
+    MEMFUN (PtrT, scan_not, (Mask, PtrT, PtrT) const);
+    MEMFUN (charT, toupper, (charT) const);
+    MEMFUN (PtrT, toupper, (charT*, PtrT) const);
+    MEMFUN (charT, tolower, (charT) const);
+    MEMFUN (PtrT, tolower, (charT*, PtrT) const);
+    MEMFUN (charT, widen, (char) const);
+    MEMFUN (const char*, widen, (const char*, const char*, charT*) const);
+    MEMFUN (char, narrow, (charT, char) const);
+    MEMFUN (PtrT, narrow,
+            (PtrT, PtrT, char, char*) const);
+
+    std::locale::id *pid = &CtypeT::id;
+    _RWSTD_UNUSED (pid);
+
+    // exercise virtuals and other parts that differ between
+    // the primary template and the char specialization
+    test_ctype_specialization<charT> ();
+}
+
+/***************************************************************************/
+
+template <class charT>
+struct CodecvtDerived: std::codecvt<charT, char, std::mbstate_t>
+{
+    typedef std::codecvt<charT, char, std::mbstate_t> Codecvt;
+    typedef std::codecvt_base::result                 Result;
+    typedef typename Codecvt::intern_type             InternT;
+    typedef typename Codecvt::extern_type             ExternT;
+    typedef typename Codecvt::state_type              StateT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                        \
+        do {                                                  \
+           result (Codecvt::*pf) arg_list = &Codecvt::name;   \
+           _RWSTD_UNUSED (pf);                                \
+         }  while (0)
+
+    void test_protected_members () {
+            // protected virtuals
+            MEMFUN (Result, do_out,
+                    (StateT&, const InternT*, const InternT*, const InternT*&,
+                     ExternT*, ExternT*, ExternT*&) const);
+
+            MEMFUN (Result, do_unshift,
+                    (StateT&, ExternT*, ExternT*, ExternT*&) const);
+
+            MEMFUN (Result, do_in,
+                    (StateT&, const ExternT*, const ExternT*, const ExternT*&,
+                     InternT*, InternT*, InternT*&) const);
+
+            MEMFUN (int, do_encoding, () const _PTR_THROWS (()));
+            MEMFUN (bool, do_always_noconv, () const _PTR_THROWS (()));
+
+            // lwg issue 75 changes first argument from const StateT& to State&
+            MEMFUN (int, do_length,
+                    (StateT&, const ExternT*, const ExternT*,
+                     std::size_t) const);
+
+            MEMFUN (int, do_max_length, () const _PTR_THROWS (()));
+        }
+    };
+
+
+template <class charT>
+static void
+test_codecvt (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::codecvt<%s, char, std::mbstate_t> synopsis", cname);
+
+    // verify base class
+    std::codecvt_base b;
+    std::codecvt_base::result r = b.ok;
+
+    // prevent a bogus MSVC warning 4101 (see PR #24178)
+    _RWSTD_UNUSED (b);
+
+    // verify that result is a constant integral expression
+    switch (r) {
+    case std::codecvt_base::ok:
+    case std::codecvt_base::partial:
+    case std::codecvt_base::error:
+    case std::codecvt_base::noconv:
+        break;
+    }
+
+    typedef std::codecvt<charT, char, std::mbstate_t> Codecvt;
+
+    // verify that nested types exist
+    typedef typename Codecvt::intern_type  InternT;
+    typedef typename Codecvt::extern_type  ExternT;
+    typedef typename Codecvt::state_type   StateT;
+
+    // verify nested types
+    const InternT *pint = (const charT*)0;
+    const ExternT *pext = (const char*)0;
+    const StateT  *pst  = (const std::mbstate_t*)0;
+
+    _RWSTD_UNUSED (pint);
+    _RWSTD_UNUSED (pext);
+    _RWSTD_UNUSED (pst);
+
+    typedef std::codecvt_base::result Result;
+
+    // public non-virtuals
+    MEMFUN (Result, out,
+            (StateT&, const InternT*, const InternT*, const InternT*&,
+             ExternT*, ExternT*, ExternT*&) const);
+
+    MEMFUN (Result, unshift, (StateT&, ExternT*, ExternT*, ExternT*&) const);
+
+    MEMFUN (Result, in,
+            (StateT&, const ExternT*, const ExternT*, const ExternT*&,
+             InternT*, InternT*, InternT*&) const);
+
+    MEMFUN (int, encoding, () const _PTR_THROWS (()));
+    MEMFUN (bool, always_noconv, () const _PTR_THROWS (()));
+
+    // lwg issue 75 changes the first argument from const StateT& to State&
+    MEMFUN (int, length,
+            (StateT&, const ExternT*, const ExternT*, std::size_t) const);
+
+    MEMFUN (int, max_length, () const _PTR_THROWS (()));
+
+    std::locale::id *pid = &Codecvt::id;
+    _RWSTD_UNUSED (pid);
+
+    CodecvtDerived<charT>().test_protected_members ();
+}
+
+/***************************************************************************/
+
+// user-defined character type; used to exercise requirements in Table 52
+// i.e., specializations of facets on types other than char and wchar_t
+#define UDC int
+
+// numeric category
+
+namespace std {
+
+// provide an explicit specialization of numpunct on UDC necessary
+// in order to exercise num_get<UDC> and num_put<UDC>
+
+_RWSTD_SPECIALIZED_CLASS
+struct numpunct<UDC>: locale::facet
+{
+    typedef UDC                                 char_type;
+    typedef StringTypes<char_type>::string_type string_type;
+
+    // working around an MSVC 6.0 bug
+    typedef locale::facet           Base;
+
+    _EXPLICIT numpunct (size_t refs = 0)
+        : Base (refs) { /* empty */ }
+
+    static locale::id id;
+
+    char_type decimal_point () const { return char_type (); }
+    char_type thousands_sep () const { return char_type (); }
+    string grouping () const { return ""; }
+    string_type falsename () const { return string_type (); }
+    string_type truename () const { return string_type (); }
+};
+
+locale::id numpunct<UDC>::id;
+
+}   // namespace std
+
+
+template <class charT>
+struct NumPunctDerived: std::numpunct<charT>
+{
+    typedef std::numpunct<charT>                     NumPunct;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                          \
+        do {                                                    \
+           result (NumPunct::*pf) arg_list = &NumPunct::name;   \
+           _RWSTD_UNUSED (pf);                                  \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (charT, do_decimal_point, () const);
+        MEMFUN (charT, do_thousands_sep, () const);
+        MEMFUN (std::string, do_grouping, () const);
+        MEMFUN (StringT, do_truename, () const);
+        MEMFUN (StringT, do_falsename, () const);
+    }
+};
+
+
+template <class charT>
+static void
+test_numpunct (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::numpunct<%s> synopsis", cname);
+
+    typedef std::numpunct<charT>                     NumPunct;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+    // verify nested types
+    typename NumPunct::char_type   *pc   = (charT*)0;
+    typename NumPunct::string_type *pstr = (StringT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pstr);
+
+    // public interface
+    MEMFUN (charT, decimal_point, () const);
+    MEMFUN (charT, thousands_sep, () const);
+    MEMFUN (std::string, grouping, () const);
+    MEMFUN (StringT, truename, () const);
+    MEMFUN (StringT, falsename, () const);
+
+    // verify that id is defined and non-const
+    std::locale::id *pid = &NumPunct::id;
+    _RWSTD_UNUSED (pid);
+
+    NumPunctDerived<charT>::test_protected_members ();
+}
+
+
+typedef std::ios_base          IosBase;
+typedef std::ios_base::iostate IoState;
+
+
+template <class charT, class IterT>
+struct NumGetDerived: std::num_get<charT, IterT>
+{
+    typedef std::num_get<charT, IterT> NumGet;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                      \
+        do {                                                \
+           result (NumGet::*pf) arg_list = &NumGet::name;   \
+           _RWSTD_UNUSED (pf);                              \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, bool&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase& ,IoState&, long&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, unsigned short&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, unsigned&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, unsigned long&) const);
+
+#ifdef _RWSTD_LONG_LONG
+
+        // extensions disabled in strict ANSI mode
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, _RWSTD_LONG_LONG&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&,
+                 unsigned _RWSTD_LONG_LONG&) const);
+
+#endif   // _RWSTD_LONG_LONG
+
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, float&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, double&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, long double&) const);
+        MEMFUN (IterT, do_get,
+                (IterT, IterT, IosBase&, IoState&, void*&) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_num_get (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::num_get<%s, %s > synopsis", cname, iname);
+
+    typedef std::num_get<charT, IterT> NumGet;
+
+    // verify nested types
+    typename NumGet::char_type *pc = (charT*)0;
+    typename NumGet::iter_type *pi = (IterT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+
+    // public interface
+    MEMFUN (IterT, get, (IterT, IterT, IosBase&, IoState&, bool&) const);
+    MEMFUN (IterT, get, (IterT, IterT, IosBase&, IoState&, long&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, unsigned short&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, unsigned&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, unsigned long&) const);
+
+#ifdef _RWSTD_LONG_LONG
+
+    // extensions disabled in strict ANSI mode
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, _RWSTD_LONG_LONG&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&,
+             unsigned _RWSTD_LONG_LONG&) const);
+
+#endif   // _RWSTD_LONG_LONG
+
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, float&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, double&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, long double&) const);
+    MEMFUN (IterT, get,
+            (IterT, IterT, IosBase&, IoState&, void*&) const);
+
+    std::locale::id *pid = &NumGet::id;
+    _RWSTD_UNUSED (pid);
+
+    NumGetDerived<charT, IterT>::test_protected_members ();
+}
+
+
+template <class charT, class IterT>
+struct NumPutDerived: std::num_put<charT, IterT>
+{
+    typedef std::num_put<charT, IterT> NumPut;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                      \
+        do {                                                \
+           result (NumPut::*pf) arg_list = &NumPut::name;   \
+           _RWSTD_UNUSED (pf);                              \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, bool) const);
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, long) const);
+
+        // no overloads for unsigned short or unsigned int
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, unsigned long) const);
+
+#ifdef _RWSTD_LONG_LONG
+
+        // extensions disabled when _RWSTD_NO_LONG_LONG is #defined
+        MEMFUN (IterT, do_put,
+                (IterT, IosBase&, charT, _RWSTD_LONG_LONG) const);
+        MEMFUN (IterT, do_put,
+                (IterT, IosBase&, charT, unsigned _RWSTD_LONG_LONG) const);
+
+#endif   // _RWSTD_LONG_LONG
+
+        // no float overload
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, double) const);
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, long double) const);
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, const void*) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_num_put (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::num_put<%s, %s > synopsis", cname, iname);
+
+    typedef std::num_put<charT, IterT> NumPut;
+
+    // verify nested types
+    typename NumPut::char_type *pc = (charT*)0;
+    typename NumPut::iter_type *pi = (IterT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+
+    // public interface
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, bool) const);
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, long) const);
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, unsigned long) const);
+
+#ifdef _RWSTD_LONG_LONG
+
+    // extensions disabled in strict ANSI mode
+    MEMFUN (IterT, put,
+            (IterT, IosBase&, charT, _RWSTD_LONG_LONG) const);
+    MEMFUN (IterT, put,
+            (IterT, IosBase&, charT, unsigned _RWSTD_LONG_LONG) const);
+
+#endif   // _RWSTD_LONG_LONG
+
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, double) const);
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, long double) const);
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, const void*) const);
+
+    std::locale::id *pid = &NumPut::id;
+    _RWSTD_UNUSED (pid);
+
+    NumPutDerived<charT, IterT>::test_protected_members ();
+}
+
+/***************************************************************************/
+
+// collate category
+
+template <class charT>
+struct CollateDerived: std::collate<charT>
+{
+    typedef const charT*                             PtrT;
+    typedef std::collate<charT>                      Collate;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                         \
+        do {                                                   \
+           result (Collate::* pf) arg_list = &Collate::name;   \
+           _RWSTD_UNUSED (pf);                                 \
+         }  while (0)
+
+    static void test_protected_members () {
+
+        MEMFUN (int, compare, (PtrT, PtrT, PtrT, PtrT) const);
+
+        MEMFUN (StringT, transform, (PtrT, PtrT) const);
+        MEMFUN (long, hash, (PtrT, PtrT) const);
+
+        std::locale::id *pid = &Collate::id;
+        _RWSTD_UNUSED (pid);
+
+        // protected virtuals (see `#define protected public' above)
+        MEMFUN (int, do_compare, (PtrT, PtrT, PtrT, PtrT) const);
+
+        MEMFUN (StringT, do_transform, (PtrT, PtrT) const);
+        MEMFUN (long, do_hash, (PtrT, PtrT) const);
+    }
+};
+
+
+template <class charT>
+static void
+test_collate (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::collate<%s> synopsis", cname);
+
+    typedef std::collate<charT> Collate;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+    // verify nested types
+    typename Collate::char_type   *pc   = (charT*)0;
+    typename Collate::string_type *pstr = (StringT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pstr);
+
+    CollateDerived<charT>::test_protected_members ();
+}
+
+/***************************************************************************/
+
+// time category
+
+template <class charT, class IterT>
+struct TimeGetDerived: std::time_get<charT, IterT>
+{
+    typedef std::time_get<charT, IterT> TimeGet;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                         \
+        do {                                                   \
+           result (TimeGet::* pf) arg_list = &TimeGet::name;   \
+           _RWSTD_UNUSED (pf);                                 \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (std::time_base::dateorder, do_date_order, () const);
+        MEMFUN (IterT, do_get_time,
+                (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+        MEMFUN (IterT, do_get_date,
+                (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+        MEMFUN (IterT, do_get_weekday,
+                (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+        MEMFUN (IterT, do_get_monthname,
+                (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+        MEMFUN (IterT, do_get_year,
+                (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_time_get (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::time_get<%s, %s > synopsis", cname, iname);
+
+    typedef std::time_get<charT, IterT> TimeGet;
+
+    // verify that dateorder constants are constant integral expressions
+    std::time_base::dateorder ord = std::time_base::no_order;
+    switch (ord) {
+    case std::time_base::no_order:
+    case std::time_base::dmy: case std::time_base::mdy:
+    case std::time_base::ymd: case std::time_base::ydm:
+        break;
+    }
+
+    // verify values
+    rw_assert (0 == std::time_base::no_order, __FILE__, __LINE__,
+               "std::time_base::no_order");
+    rw_assert (1 == std::time_base::dmy, __FILE__, __LINE__,
+               "std::time_base::dmy");
+    rw_assert (2 == std::time_base::mdy, __FILE__, __LINE__,
+               "std::time_base::mdy");
+    rw_assert (3 == std::time_base::ymd, __FILE__, __LINE__,
+               "std::time_base::ymd");
+    rw_assert (4 == std::time_base::ydm, __FILE__, __LINE__,
+               "std::time_base::ydm");
+
+    // verify nested types
+    typename TimeGet::char_type *pc = (charT*)0;
+    typename TimeGet::iter_type *pi = (IterT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+
+    // public non-virtuals
+    MEMFUN (std::time_base::dateorder, date_order, () const);
+    MEMFUN (IterT, get_time,
+            (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+    MEMFUN (IterT, get_date,
+            (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+    MEMFUN (IterT, get_weekday,
+            (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+    MEMFUN (IterT, get_monthname,
+            (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+    MEMFUN (IterT, get_year,
+            (IterT, IterT, IosBase&, IoState&, std::tm*) const);
+
+    std::locale::id *pid = &TimeGet::id;
+    _RWSTD_UNUSED (pid);
+
+    TimeGetDerived<charT, IterT>::test_protected_members ();
+}
+
+
+template <class charT, class IterT>
+struct TimePutDerived: std::time_put<charT, IterT>
+{
+    typedef std::time_put<charT, IterT> TimePut;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                        \
+        do {                                                  \
+           result (TimePut::*pf) arg_list = &TimePut::name;   \
+           _RWSTD_UNUSED (pf);                                \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (IterT, do_put, (IterT, IosBase&, charT, const std::tm*,
+                                char, char) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_time_put (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::time_put<%s, %s > synopsis", cname, iname);
+
+    typedef std::time_put<charT, IterT> TimePut;
+
+    // verify nested types
+    typename TimePut::char_type *pc = (charT*)0;
+    typename TimePut::iter_type *pi = (IterT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+
+    // public non-virtuals
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, const std::tm*,
+                          const charT*, const charT*) const);
+    MEMFUN (IterT, put, (IterT, IosBase&, charT, const std::tm*,
+                         char, char) const);
+
+    std::locale::id *pid = &TimePut::id;
+    _RWSTD_UNUSED (pid);
+
+    TimePutDerived<charT, IterT>::test_protected_members ();
+}
+
+/***************************************************************************/
+
+// monetary category
+
+namespace std {
+
+// (in the absence of support for partial specialization) provide explicit
+// specializations of moneypunct on UDC necessary in order to exercise
+// money_get<UDC> and money_put<UDC>
+
+_RWSTD_SPECIALIZED_CLASS
+struct moneypunct<UDC, false>: locale::facet, money_base
+{
+    typedef UDC                                 char_type;
+    typedef StringTypes<char_type>::string_type string_type;
+
+    // working around an MSVC 6.0 bug
+    typedef locale::facet           Base;
+
+    _EXPLICIT moneypunct (size_t refs = 0)
+        : Base (refs), money_base () { /* empty */ }
+
+    static locale::id id;
+
+    enum { intl = false };
+
+    char_type decimal_point () const { return char_type (); }
+    char_type thousands_sep () const { return char_type (); }
+    string grouping () const { return ""; }
+    string_type curr_symbol () const { return string_type (); }
+    string_type positive_sign () const { return string_type (); }
+    string_type negative_sign () const { return string_type (); }
+    int frac_digits () const { return 0; }
+    pattern pos_format () const { return pattern (); }
+    pattern neg_format () const { return pattern (); }
+};
+
+locale::id moneypunct<UDC, false>::id;
+
+
+_RWSTD_SPECIALIZED_CLASS
+struct moneypunct<UDC, true>: locale::facet, money_base
+{
+    typedef UDC                                 char_type;
+    typedef StringTypes<char_type>::string_type string_type;
+
+    // working around an MSVC 6.0 bug
+    typedef locale::facet           Base;
+
+    _EXPLICIT moneypunct (size_t refs = 0)
+        : Base (refs), money_base () { /* empty */ }
+
+    static locale::id id;
+
+    enum { intl = true };
+
+    char_type decimal_point () const { return char_type (); }
+    char_type thousands_sep () const { return char_type (); }
+    string grouping () const { return ""; }
+    string_type curr_symbol () const { return string_type (); }
+    string_type positive_sign () const { return string_type (); }
+    string_type negative_sign () const { return string_type (); }
+    int frac_digits () const { return 0; }
+    pattern pos_format () const { return pattern (); }
+    pattern neg_format () const { return pattern (); }
+};
+
+locale::id moneypunct<UDC, true>::id;
+
+}   // namespace std
+
+
+template <class charT, bool Intl>
+struct MoneyPunctDerived: std::moneypunct<charT, Intl>
+{
+    typedef std::moneypunct<charT, Intl>             MoneyPunct;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                               \
+        do {                                                         \
+           result (MoneyPunct::* pf) arg_list = &MoneyPunct::name;   \
+           _RWSTD_UNUSED (pf);                                       \
+         }  while (0)
+
+    static void test_protected_members () {
+
+        // protected virtuals
+        MEMFUN (charT, do_decimal_point, () const);
+        MEMFUN (charT, do_thousands_sep, () const );
+        MEMFUN (std::string, do_grouping, () const );
+        MEMFUN (StringT, do_curr_symbol, () const);
+        MEMFUN (StringT, do_positive_sign, () const);
+        MEMFUN (StringT, do_negative_sign, () const);
+        MEMFUN (int, do_frac_digits, () const);
+        MEMFUN (std::money_base::pattern, do_pos_format, () const);
+        MEMFUN (std::money_base::pattern, do_neg_format, () const);
+    }
+};
+
+
+template <class charT>
+static void
+test_moneypunct (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::moneypunct<%s, bool> synopsis", cname);
+
+    typedef std::moneypunct<charT, false>            MoneyPunct;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+    typename MoneyPunct::char_type *pc = (charT*)0;
+    typename MoneyPunct::string_type *ps = (StringT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (ps);
+
+    MEMFUN (charT, decimal_point, () const );
+    MEMFUN (charT, thousands_sep, () const );
+    MEMFUN (std::string, grouping, () const );
+    MEMFUN (StringT, curr_symbol, () const);
+    MEMFUN (StringT, positive_sign, () const);
+    MEMFUN (StringT, negative_sign, () const);
+    MEMFUN (int, frac_digits, () const);
+    MEMFUN (std::money_base::pattern, pos_format, () const);
+    MEMFUN (std::money_base::pattern, neg_format, () const);
+
+    std::locale::id *pid = &MoneyPunct::id;
+    _RWSTD_UNUSED (pid);
+
+    MoneyPunctDerived<charT, false>::test_protected_members ();
+}
+
+
+template <class charT, class IterT>
+struct MoneyGetDerived: std::money_get<charT, IterT>
+{
+    typedef std::money_get<charT, IterT>             MoneyGet;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                          \
+        do {                                                    \
+           result (MoneyGet::*pf) arg_list = &MoneyGet::name;   \
+           _RWSTD_UNUSED (pf);                                  \
+         }  while (0)
+
+    static void test_protected_members () {
+        // protected virtuals
+
+#ifndef _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_get, (IterT, IterT, bool, IosBase&,
+                                IoState&, long double&) const);
+
+#else   // if defined _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_get, (IterT, IterT, bool, IosBase&,
+                                IoState&, double&) const);
+
+#endif   // _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_get, (IterT, IterT, bool, IosBase&,
+                                IoState&, StringT&) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_money_get (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::money_get<%s, %s > synopsis", cname, iname);
+
+    typedef std::money_get<charT, IterT>             MoneyGet;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+    // verify nested types
+    typename MoneyGet::char_type *pc = (charT*)0;
+    typename MoneyGet::iter_type *pi = (IterT*)0;
+    typename MoneyGet::string_type *ps = (StringT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+    _RWSTD_UNUSED (ps);
+
+    // public interface
+    MEMFUN (IterT, get, (IterT, IterT, bool, IosBase&,
+                        IoState&, long double&) const);
+    MEMFUN (IterT, get, (IterT, IterT, bool, IosBase&,
+                        IoState&, StringT&) const);
+
+    std::locale::id *pid = &MoneyGet::id;
+    _RWSTD_UNUSED (pid);
+
+    MoneyGetDerived<charT, IterT>::test_protected_members ();
+}
+
+
+template <class charT, class IterT>
+struct MoneyPutDerived: std::money_put<charT, IterT>
+{
+    typedef std::money_put<charT, IterT>             MoneyPut;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                          \
+        do {                                                    \
+           result (MoneyPut::*pf) arg_list = &MoneyPut::name;   \
+           _RWSTD_UNUSED (pf);                                  \
+         }  while (0)
+
+    static void test_protected_members () {
+            // protected virtuals
+
+#ifndef _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_put, (IterT, bool, IosBase&, charT,
+                                long double) const);
+
+#else   // if defined _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_put, (IterT, bool, IosBase&, charT, double) const);
+
+#endif   // _RWSTD_NO_LONG_DOUBLE
+
+        MEMFUN (IterT, do_put, (IterT, bool, IosBase&, charT,
+                                const StringT&) const);
+    }
+};
+
+
+template <class charT, class IterT>
+static void
+test_money_put (const char* cname, const char* iname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::money_put<%s, %s > synopsis", cname, iname);
+
+    typedef std::money_put<charT, IterT>             MoneyPut;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+     //verify nested types
+    typename MoneyPut::char_type *pc = (charT*)0;
+    typename MoneyPut::iter_type *pi = (IterT*)0;
+    typename MoneyPut::string_type *ps = (StringT*)0;
+
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pi);
+    _RWSTD_UNUSED (ps);
+
+    // public interface
+    MEMFUN (IterT, put, (IterT, bool, IosBase&, charT,
+                        long double) const);
+    MEMFUN (IterT, put, (IterT, bool, IosBase&, charT,
+                        const StringT&) const);
+
+    std::locale::id *pid = &MoneyPut::id;
+    _RWSTD_UNUSED (pid);
+
+    MoneyPutDerived<charT, IterT>::test_protected_members ();
+}
+
+/***************************************************************************/
+
+// messges category
+
+template <class charT>
+struct MessagesDerived: std::messages<charT>
+{
+    typedef std::messages<charT>                     Messages;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+// verify that a member function is accessible and has the appropriate
+// signature, including return type and exception specification
+#undef MEMFUN
+#define MEMFUN(result, name, arg_list)                           \
+        do {                                                     \
+           result (Messages::* pf) arg_list = &Messages::name;   \
+           _RWSTD_UNUSED (pf);                                   \
+         }  while (0)
+
+
+    static void test_protected_members () {
+        // protected virtuals
+        MEMFUN (int,  do_open,
+                (const std::string&, const std::locale&) const);
+        MEMFUN (StringT, do_get, (int, int, int, const StringT&) const);
+        MEMFUN (void, do_close, (int) const);
+    }
+};
+
+
+template <class charT>
+static void
+test_messages (const char* cname)
+{
+    rw_info (0, __FILE__, __LINE__,
+             "std::messages<%s> synopsis", cname);
+
+    typedef std::messages<charT>                     Messages;
+    typedef typename StringTypes<charT>::string_type StringT;
+
+    // verify nested types
+    std::messages_base::catalog    *pcat = (int*)0;
+    typename Messages::char_type   *pc   = (charT*)0;
+    typename Messages::string_type *pstr = (StringT*)0;
+
+    _RWSTD_UNUSED (pcat);
+    _RWSTD_UNUSED (pc);
+    _RWSTD_UNUSED (pstr);
+
+    // public interface
+    MEMFUN (int,  open, (const std::string&, const std::locale&) const);
+    MEMFUN (StringT, get, (int, int, int, const StringT&) const);
+    MEMFUN (void, close, (int) const);
+
+    std::locale::id *pid = &Messages::id;
+    _RWSTD_UNUSED (pid);
+
+    MessagesDerived<charT>::test_protected_members ();
+}
+
+/***************************************************************************/
+
+static int
+run_test (int /*unused*/, char* /*unused*/ [])
+{
+    test_lc_defs ();
+    test_isxxx ();
+
+    // exercise the signatures of std::{has,use}_facet<>()
+    test_have_use_facet<char> ();
+
+    // exercise the signatures of the convenience locale interfaces
+    test_convenience_funs<char> ();
+
+    // test for the presence of the required facet templates
+    test_facets<char> ();
+
+    test_locale ();
+
+// don't use _RWSTD_STRSTR so type macros (e.g. UDC) are not expanded
+#undef FUN1
+#define FUN1(fun, charT) \
+        fun< charT > (#charT)
+
+    // std::locale::collate category
+    FUN1 (test_collate, char);
+
+    // std::locale::ctype category
+    FUN1 (test_codecvt, char);
+    FUN1 (test_ctype, char);
+
+#undef FUN2
+#define FUN2(fun, charT, IterT) \
+        fun< charT, IterT > (#charT, #IterT)
+
+    // std::locale::monetary category
+    FUN1 (test_moneypunct, char);
+    FUN2 (test_money_get, char, std::istreambuf_iterator<char>);
+    FUN2 (test_money_get, char, const char*);
+    FUN2 (test_money_put, char, std::ostreambuf_iterator<char>);
+    FUN2 (test_money_put, char, char*);
+
+    // std::locale::numeric category
+    FUN1 (test_numpunct, char);
+    FUN2 (test_num_get, char, std::istreambuf_iterator<char>);
+    FUN2 (test_num_get, char, const char*);
+    FUN2 (test_num_put, char, std::ostreambuf_iterator<char>);
+    FUN2 (test_num_put, char, char*);
+
+    // std::locale::time category
+    FUN2 (test_time_get, char, std::istreambuf_iterator<char>);
+    FUN2 (test_time_get, char, const char*);
+    FUN2 (test_time_put, char, std::ostreambuf_iterator<char>);
+    FUN2 (test_time_put, char, char*);
+
+    // std::locale::messages category
+    FUN1 (test_messages, char);
+
+#ifndef _RWSTD_NO_WCHAR_T
+
+    // same as above but for wchar_t
+    test_have_use_facet<wchar_t> ();
+    test_convenience_funs<wchar_t> ();
+    test_facets<wchar_t> ();
+
+    FUN1 (test_collate, wchar_t);
+
+    FUN1 (test_ctype, wchar_t);
+    FUN1 (test_codecvt, wchar_t);
+
+    FUN1 (test_moneypunct, wchar_t);
+    FUN2 (test_money_get, wchar_t, std::istreambuf_iterator<wchar_t>);
+    FUN2 (test_money_get, wchar_t, const wchar_t*);
+    FUN2 (test_money_put, wchar_t, std::ostreambuf_iterator<wchar_t>);
+    FUN2 (test_money_put, wchar_t, wchar_t*);
+
+    FUN1 (test_numpunct, wchar_t);
+    FUN2 (test_num_get, wchar_t, std::istreambuf_iterator<wchar_t>);
+    FUN2 (test_num_get, wchar_t, const wchar_t*);
+    FUN2 (test_num_put, wchar_t, std::ostreambuf_iterator<wchar_t>);
+    FUN2 (test_num_put, wchar_t, wchar_t*);
+
+    FUN2 (test_time_get, wchar_t, std::istreambuf_iterator<wchar_t>);
+    FUN2 (test_time_get, wchar_t, const wchar_t*);
+    FUN2 (test_time_put, wchar_t, std::ostreambuf_iterator<wchar_t>);
+    FUN2 (test_time_put, wchar_t, wchar_t*);
+
+    FUN1 (test_messages, wchar_t);
+
+#endif   // _RWSTD_NO_WCHAR_T
+
+    // test facet specializations on character types other than char and wchar_t
+    // and iterator types other than istreambuf_iterator and ostreambuf_iterator
+    // as per requirements in Table 52
+
+    FUN2 (test_money_get, UDC, std::istreambuf_iterator<UDC>);
+    FUN2 (test_money_get, UDC, const UDC*);
+
+    FUN2 (test_money_put, UDC, std::ostreambuf_iterator<UDC>);
+    FUN2 (test_money_put, UDC, UDC*);
+
+    FUN2 (test_num_get, UDC, std::istreambuf_iterator<UDC>);
+    FUN2 (test_num_get, UDC, const UDC*);
+
+    FUN2 (test_num_put, UDC, std::ostreambuf_iterator<UDC>);
+    FUN2 (test_num_put, UDC, UDC*);
+
+    FUN2 (test_time_get, char, const char*);
+    FUN2 (test_time_put, char, char*);
+
+    return 0;
+}
+
+/* extern */ int
+main (int argc, char* argv [])
+{
+    return rw_test (argc, argv, __FILE__,
+                    "lib.locales", "header <locale> synopsis",
+                    run_test, "|-enable-posix# ", &opt_enable_posix);
+}
+