This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Add thread-safe locale handling
[perl5.git] / perl.h
diff --git a/perl.h b/perl.h
index 7c698cf..ff6c882 100644 (file)
--- a/perl.h
+++ b/perl.h
 #  endif
 #endif
 
-#ifdef PERL_GLOBAL_STRUCT
-#  ifndef PERL_GET_VARS
+#if defined(PERL_GLOBAL_STRUCT) && !defined(PERL_GET_VARS)
 #    ifdef PERL_GLOBAL_STRUCT_PRIVATE
        EXTERN_C struct perl_vars* Perl_GetVarsPrivate();
 #      define PERL_GET_VARS() Perl_GetVarsPrivate() /* see miniperlmain.c */
 #    else
 #      define PERL_GET_VARS() PL_VarsPtr
 #    endif
-#  endif
 #endif
 
 /* this used to be off by default, now its on, see perlio.h */
 #  undef PERL_TRACK_MEMPOOL
 #endif
 
+#ifdef DEBUGGING
+#  define dTHX_DEBUGGING dTHX
+#else
+#  define dTHX_DEBUGGING dNOOP
+#endif
+
 #define STATIC static
 
 #ifndef PERL_CORE
 #endif
 
 #ifndef PERL_UNUSED_DECL
-#  if defined(HASATTRIBUTE_UNUSED) && (!defined(__cplusplus) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
+#  if defined(HASATTRIBUTE_UNUSED) && (!defined(__cplusplus) || __GNUC__ >= 4)
 #    define PERL_UNUSED_DECL __attribute__unused__
 #  else
 #    define PERL_UNUSED_DECL
 /* on gcc (and clang), specify that a warning should be temporarily
  * ignored; e.g.
  *
- *    GCC_DIAG_IGNORE(-Wmultichar);
+ *    GCC_DIAG_IGNORE_DECL(-Wmultichar);
  *    char b = 'ab';
- *    GCC_DIAG_RESTORE;
+ *    GCC_DIAG_RESTORE_DECL;
  *
  * based on http://dbp-consulting.com/tutorials/SuppressingGCCWarnings.html
  *
  * Note that "pragma GCC diagnostic push/pop" was added in GCC 4.6, Mar 2011;
  * clang only pretends to be GCC 4.2, but still supports push/pop.
  *
- * Note on usage: on non-gcc (or lookalike, like clang) compilers
- * one cannot use these with a semicolon at file (global) level without
- * warnings since they are defined as empty, which leads into the terminating
- * semicolon being left alone on a line:
- * ;
- * which makes compilers mildly cranky.  Therefore at file level one
- * should use the GCC_DIAG_IGNORE and GCC_DIAG_RESTORE macros *without*
- * the semicolons.
+ * Note on usage: all macros must be used at a place where a declaration
+ * or statement can occur, i.e., not in the middle of an expression.
+ * *_DIAG_IGNORE() and *_DIAG_RESTORE can be used in any such place, but
+ * must be used without a following semicolon.  *_DIAG_IGNORE_DECL() and
+ * *_DIAG_RESTORE_DECL must be used with a following semicolon, and behave
+ * syntactically as declarations (like dNOOP).  *_DIAG_IGNORE_STMT()
+ * and *_DIAG_RESTORE_STMT must be used with a following semicolon,
+ * and behave syntactically as statements (like NOOP).
  *
- * (A dead-on-arrival solution would be to try to define the macros as
- * NOOP or dNOOP, those don't work both inside functions and outside.)
  */
 
 #if defined(__clang__) || defined(__clang) || \
 #  define GCC_DIAG_IGNORE(w)
 #  define GCC_DIAG_RESTORE
 #endif
+#define GCC_DIAG_IGNORE_DECL(x) GCC_DIAG_IGNORE(x) dNOOP
+#define GCC_DIAG_RESTORE_DECL GCC_DIAG_RESTORE dNOOP
+#define GCC_DIAG_IGNORE_STMT(x) GCC_DIAG_IGNORE(x) NOOP
+#define GCC_DIAG_RESTORE_STMT GCC_DIAG_RESTORE NOOP
 /* for clang specific pragmas */
 #if defined(__clang__) || defined(__clang)
 #  define CLANG_DIAG_PRAGMA(x) _Pragma (#x)
 #  define CLANG_DIAG_IGNORE(w)
 #  define CLANG_DIAG_RESTORE
 #endif
+#define CLANG_DIAG_IGNORE_DECL(x) CLANG_DIAG_IGNORE(x) dNOOP
+#define CLANG_DIAG_RESTORE_DECL CLANG_DIAG_RESTORE dNOOP
+#define CLANG_DIAG_IGNORE_STMT(x) CLANG_DIAG_IGNORE(x) NOOP
+#define CLANG_DIAG_RESTORE_STMT CLANG_DIAG_RESTORE NOOP
 
 #define NOOP /*EMPTY*/(void)0
-/* cea2e8a9dd23747f accidentally lost the comment originally from the first
-   check in of thread.h, explaining why we need dNOOP at all:  */
-/* Rats: if dTHR is just blank then the subsequent ";" throws an error */
-/* Declaring a *function*, instead of a variable, ensures that we don't rely
-   on being able to suppress "unused" warnings.  */
-#ifdef __cplusplus
-#define dNOOP (void)0
-#else
-#define dNOOP extern int Perl___notused(void)
-#endif
+#define dNOOP struct Perl___notused_struct
 
 #ifndef pTHX
 /* Don't bother defining tTHX ; using it outside
 #define DOSISH 1
 #endif
 
-#if defined(__STDC__) || defined(_AIX) || defined(__stdc__) || defined(__cplusplus) || defined(NETWARE) || defined(__SYMBIAN32__)
-# define STANDARD_C 1
-#endif
-
-#if defined(__cplusplus) || defined(WIN32) || defined(__sgi) || defined(__EMX__) || defined(__QNX__) || defined(NETWARE) || defined(PERL_MICRO)
-# define DONT_DECLARE_STD 1
-#endif
-
-#if defined(HASVOLATILE) || defined(STANDARD_C)
-#      define VOL volatile
-#else
-#   define VOL
+/* These exist only for back-compat with XS modules. */
+#ifndef PERL_CORE
+#define VOL volatile
+#define CAN_PROTOTYPE
+#define _(args) args
+#define I_LIMITS
+#define I_STDARG
+#define STANDARD_C
 #endif
 
 /* By compiling a perl with -DNO_TAINT_SUPPORT or -DSILENT_NO_TAINT_SUPPORT,
 */
 #ifdef HAS_SETPGID
 #  define BSD_SETPGRP(pid, pgrp)       setpgid((pid), (pgrp))
-#else
-#  if defined(HAS_SETPGRP) && defined(USE_BSD_SETPGRP)
-#    define BSD_SETPGRP(pid, pgrp)     setpgrp((pid), (pgrp))
-#  else
-#    ifdef HAS_SETPGRP2  /* DG/UX */
-#      define BSD_SETPGRP(pid, pgrp)   setpgrp2((pid), (pgrp))
-#    endif
-#  endif
+#elif defined(HAS_SETPGRP) && defined(USE_BSD_SETPGRP)
+#  define BSD_SETPGRP(pid, pgrp)       setpgrp((pid), (pgrp))
+#elif defined(HAS_SETPGRP2)
+#  define BSD_SETPGRP(pid, pgrp)       setpgrp2((pid), (pgrp))
 #endif
 #if defined(BSD_SETPGRP) && !defined(HAS_SETPGRP)
 #  define HAS_SETPGRP  /* Well, effectively it does . . . */
 */
 #ifdef HAS_GETPGID
 #  define BSD_GETPGRP(pid)             getpgid((pid))
-#else
-#  if defined(HAS_GETPGRP) && defined(USE_BSD_GETPGRP)
-#    define BSD_GETPGRP(pid)           getpgrp((pid))
-#  else
-#    ifdef HAS_GETPGRP2  /* DG/UX */
-#      define BSD_GETPGRP(pid)         getpgrp2((pid))
-#    endif
-#  endif
+#elif defined(HAS_GETPGRP) && defined(USE_BSD_GETPGRP)
+#  define BSD_GETPGRP(pid)             getpgrp((pid))
+#elif defined(HAS_GETPGRP2)
+#  define BSD_GETPGRP(pid)             getpgrp2((pid))
 #endif
 #if defined(BSD_GETPGRP) && !defined(HAS_GETPGRP)
 #  define HAS_GETPGRP  /* Well, effectively it does . . . */
 
 #include <sys/types.h>
 
-#ifdef __cplusplus
-#  ifndef I_STDARG
-#    define I_STDARG 1
-#  endif
-#endif
-
 /* EVC 4 SDK headers includes a bad definition of MB_CUR_MAX in stdlib.h
   which is included from stdarg.h. Bad definition not present in SD 2008
   SDK headers. wince.h is not yet included, so we cant fix this from there
   cewchar.h includes a correct definition of MB_CUR_MAX and it is copied here
   since cewchar.h can't be included this early */
 #if defined(UNDER_CE) && (_MSC_VER < 1300)
-#  define MB_CUR_MAX 1
-#endif
-#ifdef I_STDARG
-#  include <stdarg.h>
-#else
-#  ifdef I_VARARGS
-#    include <varargs.h>
-#  endif
+#  define MB_CUR_MAX 1uL
 #endif
 
+# include <stdarg.h>
+
 #ifdef I_STDINT
 # include <stdint.h>
 #endif
 
 #include <ctype.h>
+#include <float.h>
+#include <limits.h>
 
 #ifdef METHOD  /* Defined by OSF/1 v3.0 by ctype.h */
 #undef METHOD
 #   if !defined(NO_LOCALE_TIME) && defined(LC_TIME)
 #      define USE_LOCALE_TIME
 #   endif
+#   if !defined(NO_LOCALE_ADDRESS) && defined(LC_ADDRESS)
+#      define USE_LOCALE_ADDRESS
+#   endif
+#   if !defined(NO_LOCALE_IDENTIFICATION) && defined(LC_IDENTIFICATION)
+#      define USE_LOCALE_IDENTIFICATION
+#   endif
+#   if !defined(NO_LOCALE_MEASUREMENT) && defined(LC_MEASUREMENT)
+#      define USE_LOCALE_MEASUREMENT
+#   endif
+#   if !defined(NO_LOCALE_PAPER) && defined(LC_PAPER)
+#      define USE_LOCALE_PAPER
+#   endif
+#   if !defined(NO_LOCALE_TELEPHONE) && defined(LC_TELEPHONE)
+#      define USE_LOCALE_TELEPHONE
+#   endif
 #endif /* !NO_LOCALE && HAS_SETLOCALE */
 
+#ifdef USE_LOCALE /* These locale things are all subject to change */
+#  if      defined(HAS_NEWLOCALE)               \
+      &&   defined(LC_ALL_MASK)                 \
+      &&   defined(HAS_FREELOCALE)              \
+      &&   defined(HAS_USELOCALE)               \
+      && ! defined(NO_POSIX_2008_LOCALE)
+
+    /* For simplicity, the code is written to assume that any platform advanced
+     * enough to have the Posix 2008 locale functions has LC_ALL.  The test
+     * above makes sure that assumption is valid */
+
+#    define HAS_POSIX_2008_LOCALE
+#  endif
+#  if     defined(USE_ITHREADS)                                             \
+      && (    defined(HAS_POSIX_2008_LOCALE)                                \
+          || (defined(WIN32) && defined(_MSC_VER) && _MSC_VER >= 1400))     \
+      && ! defined(NO_THREAD_SAFE_LOCALE)
+#    define USE_THREAD_SAFE_LOCALE
+#    ifdef HAS_POSIX_2008_LOCALE
+#      define USE_POSIX_2008_LOCALE
+#    endif
+#  endif
+#endif
+
 #include <setjmp.h>
 
 #ifdef I_SYS_PARAM
 #   endif
 #endif
 
-/* Use all the "standard" definitions? */
-#if defined(STANDARD_C) && defined(I_STDLIB)
-#   include <stdlib.h>
-#endif
+/* Use all the "standard" definitions */
+#include <stdlib.h>
 
 /* If this causes problems, set i_unistd=undef in the hint file.  */
 #ifdef I_UNISTD
@@ -823,56 +840,124 @@ EXTERN_C int syscall(int, ...);
 EXTERN_C int usleep(unsigned int);
 #endif
 
-#ifdef PERL_CORE
+/* macros for correct constant construction.  These are in C99 <stdint.h>
+ * (so they will not be available in strict C89 mode), but they are nice, so
+ * let's define them if necessary. */
+#ifndef UINT16_C
+#  if INTSIZE >= 2
+#    define UINT16_C(x) ((U16_TYPE)x##U)
+#  else
+#    define UINT16_C(x) ((U16_TYPE)x##UL)
+#  endif
+#endif
 
-/* macros for correct constant construction */
-# if INTSIZE >= 2
-#  define U16_CONST(x) ((U16)x##U)
-# else
-#  define U16_CONST(x) ((U16)x##UL)
-# endif
+#ifndef UINT32_C
+#  if INTSIZE >= 4
+#    define UINT32_C(x) ((U32_TYPE)x##U)
+#  else
+#    define UINT32_C(x) ((U32_TYPE)x##UL)
+#  endif
+#endif
 
-# if INTSIZE >= 4
-#  define U32_CONST(x) ((U32)x##U)
-# else
-#  define U32_CONST(x) ((U32)x##UL)
-# endif
+#ifdef I_STDINT
+    typedef intmax_t  PERL_INTMAX_T;
+    typedef uintmax_t PERL_UINTMAX_T;
+#endif
 
-# ifdef HAS_QUAD
-#  if INTSIZE >= 8
-#   define U64_CONST(x) ((U64)x##U)
-#  elif LONGSIZE >= 8
-#   define U64_CONST(x) ((U64)x##UL)
-#  elif QUADKIND == QUAD_IS_LONG_LONG
-#   define U64_CONST(x) ((U64)x##ULL)
-#  elif QUADKIND == QUAD_IS___INT64
-#   define U64_CONST(x) ((U64)x##UI64)
-#  else /* best guess we can make */
-#   define U64_CONST(x) ((U64)x##UL)
+/* N.B.  We use QUADKIND here instead of HAS_QUAD here, because that doesn't
+ * actually mean what it has always been documented to mean (see RT #119753)
+ * and is explicitly turned off outside of core with dire warnings about
+ * removing the undef. */
+
+#if defined(QUADKIND)
+#  undef PeRl_INT64_C
+#  undef PeRl_UINT64_C
+/* Prefer the native integer types (int and long) over long long
+ * (which is not C89) and Win32-specific __int64. */
+#  if QUADKIND == QUAD_IS_INT && INTSIZE == 8
+#    define PeRl_INT64_C(c)    (c)
+#    define PeRl_UINT64_C(c)   CAT2(c,U)
+#  endif
+#  if QUADKIND == QUAD_IS_LONG && LONGSIZE == 8
+#    define PeRl_INT64_C(c)    CAT2(c,L)
+#    define PeRl_UINT64_C(c)   CAT2(c,UL)
+#  endif
+#  if QUADKIND == QUAD_IS_LONG_LONG && defined(HAS_LONG_LONG)
+#    define PeRl_INT64_C(c)    CAT2(c,LL)
+#    define PeRl_UINT64_C(c)   CAT2(c,ULL)
+#  endif
+#  if QUADKIND == QUAD_IS___INT64
+#    define PeRl_INT64_C(c)    CAT2(c,I64)
+#    define PeRl_UINT64_C(c)   CAT2(c,UI64)
+#  endif
+#  ifndef PeRl_INT64_C
+#    define PeRl_INT64_C(c)    ((I64)(c)) /* last resort */
+#    define PeRl_UINT64_C(c)   ((U64TYPE)(c))
+#  endif
+/* In OS X the INT64_C/UINT64_C are defined with LL/ULL, which will
+ * not fly with C89-pedantic gcc, so let's undefine them first so that
+ * we can redefine them with our native integer preferring versions. */
+#  if defined(PERL_DARWIN) && defined(PERL_GCC_PEDANTIC)
+#    undef INT64_C
+#    undef UINT64_C
+#  endif
+#  ifndef INT64_C
+#    define INT64_C(c) PeRl_INT64_C(c)
+#  endif
+#  ifndef UINT64_C
+#    define UINT64_C(c) PeRl_UINT64_C(c)
+#  endif
+
+#  ifndef I_STDINT
+    typedef I64TYPE PERL_INTMAX_T;
+    typedef U64TYPE PERL_UINTMAX_T;
+#  endif
+#  ifndef INTMAX_C
+#    define INTMAX_C(c) INT64_C(c)
+#  endif
+#  ifndef UINTMAX_C
+#    define UINTMAX_C(c) UINT64_C(c)
+#  endif
+
+#else  /* below QUADKIND is undefined */
+
+/* Perl doesn't work on 16 bit systems, so must be 32 bit */
+#  ifndef I_STDINT
+    typedef I32TYPE PERL_INTMAX_T;
+    typedef U32TYPE PERL_UINTMAX_T;
+#  endif
+#  ifndef INTMAX_C
+#    define INTMAX_C(c) INT32_C(c)
+#  endif
+#  ifndef UINTMAX_C
+#    define UINTMAX_C(c) UINT32_C(c)
 #  endif
-# endif
+
+#endif  /* no QUADKIND */
+
+#ifdef PERL_CORE
 
 /* byte-swapping functions for big-/little-endian conversion */
 # define _swab_16_(x) ((U16)( \
-         (((U16)(x) & U16_CONST(0x00ff)) << 8) | \
-         (((U16)(x) & U16_CONST(0xff00)) >> 8) ))
+         (((U16)(x) & UINT16_C(0x00ff)) << 8) | \
+         (((U16)(x) & UINT16_C(0xff00)) >> 8) ))
 
 # define _swab_32_(x) ((U32)( \
-         (((U32)(x) & U32_CONST(0x000000ff)) << 24) | \
-         (((U32)(x) & U32_CONST(0x0000ff00)) <<  8) | \
-         (((U32)(x) & U32_CONST(0x00ff0000)) >>  8) | \
-         (((U32)(x) & U32_CONST(0xff000000)) >> 24) ))
+         (((U32)(x) & UINT32_C(0x000000ff)) << 24) | \
+         (((U32)(x) & UINT32_C(0x0000ff00)) <<  8) | \
+         (((U32)(x) & UINT32_C(0x00ff0000)) >>  8) | \
+         (((U32)(x) & UINT32_C(0xff000000)) >> 24) ))
 
 # ifdef HAS_QUAD
 #  define _swab_64_(x) ((U64)( \
-          (((U64)(x) & U64_CONST(0x00000000000000ff)) << 56) | \
-          (((U64)(x) & U64_CONST(0x000000000000ff00)) << 40) | \
-          (((U64)(x) & U64_CONST(0x0000000000ff0000)) << 24) | \
-          (((U64)(x) & U64_CONST(0x00000000ff000000)) <<  8) | \
-          (((U64)(x) & U64_CONST(0x000000ff00000000)) >>  8) | \
-          (((U64)(x) & U64_CONST(0x0000ff0000000000)) >> 24) | \
-          (((U64)(x) & U64_CONST(0x00ff000000000000)) >> 40) | \
-          (((U64)(x) & U64_CONST(0xff00000000000000)) >> 56) ))
+          (((U64)(x) & UINT64_C(0x00000000000000ff)) << 56) | \
+          (((U64)(x) & UINT64_C(0x000000000000ff00)) << 40) | \
+          (((U64)(x) & UINT64_C(0x0000000000ff0000)) << 24) | \
+          (((U64)(x) & UINT64_C(0x00000000ff000000)) <<  8) | \
+          (((U64)(x) & UINT64_C(0x000000ff00000000)) >>  8) | \
+          (((U64)(x) & UINT64_C(0x0000ff0000000000)) >> 24) | \
+          (((U64)(x) & UINT64_C(0x00ff000000000000)) >> 40) | \
+          (((U64)(x) & UINT64_C(0xff00000000000000)) >> 56) ))
 # endif
 
 /* The old value was hard coded at 1008. (4096-16) seems to be a bit faster,
@@ -888,6 +973,26 @@ EXTERN_C int usleep(unsigned int);
 
 #endif /* PERL_CORE */
 
+/* Maximum number of args that may be passed to an OP_MULTICONCAT op.
+ * It determines the size of local arrays in S_maybe_multiconcat() and
+ * pp_multiconcat().
+ */
+#define PERL_MULTICONCAT_MAXARG 64
+
+/* The indexes of fields of a multiconcat aux struct.
+ * The fixed fields are followed by nargs+1 const segment lengths,
+ * and if utf8 and non-utf8 differ, a second nargs+1 set for utf8.
+ */
+
+#define PERL_MULTICONCAT_IX_NARGS     0 /* number of arguments */
+#define PERL_MULTICONCAT_IX_PLAIN_PV  1 /* non-utf8 constant string */
+#define PERL_MULTICONCAT_IX_PLAIN_LEN 2 /* non-utf8 constant string length */
+#define PERL_MULTICONCAT_IX_UTF8_PV   3 /* utf8 constant string */
+#define PERL_MULTICONCAT_IX_UTF8_LEN  4 /* utf8 constant string length */
+#define PERL_MULTICONCAT_IX_LENGTHS   5 /* first of nargs+1 const segment lens */
+#define PERL_MULTICONCAT_HEADER_SIZE 5 /* The number of fields of a
+                                           multiconcat header */
+
 /* We no longer default to creating a new SV for GvSV.
    Do this before embed.  */
 #ifndef PERL_CREATE_GVSV
@@ -921,12 +1026,8 @@ EXTERN_C int usleep(unsigned int);
 #  define PERL_STRLEN_EXPAND_SHIFT 2
 #endif
 
-#if defined(STANDARD_C) && defined(I_STDDEF) && !defined(PERL_GCC_PEDANTIC)
-#   include <stddef.h>
-#   define STRUCT_OFFSET(s,m)  offsetof(s,m)
-#else
-#   define STRUCT_OFFSET(s,m)  (Size_t)(&(((s *)0)->m))
-#endif
+#include <stddef.h>
+#define STRUCT_OFFSET(s,m)  offsetof(s,m)
 
 /* ptrdiff_t is C11, so undef it under pedantic builds */
 #ifdef PERL_GCC_PEDANTIC
@@ -934,11 +1035,7 @@ EXTERN_C int usleep(unsigned int);
 #endif
 
 #ifndef __SYMBIAN32__
-#  if defined(I_STRING) || defined(__cplusplus)
-#     include <string.h>
-#  else
-#     include <strings.h>
-#  endif
+#  include <string.h>
 #endif
 
 /* This comes after <stdlib.h> so we don't try to change the standard
@@ -992,15 +1089,6 @@ EXTERN_C int usleep(unsigned int);
 #define MALLOC_TOO_LATE_FOR(ch)        TOO_LATE_FOR_(ch, " with $ENV{PERL_MALLOC_OPT}")
 #define MALLOC_CHECK_TAINT2(argc,argv) MALLOC_CHECK_TAINT(argc,argv,NULL)
 
-#if !defined(HAS_STRCHR) && defined(HAS_INDEX) && !defined(strchr)
-#define strchr index
-#define strrchr rindex
-#endif
-
-#ifdef I_MEMORY
-#  include <memory.h>
-#endif
-
 #ifndef memzero
 #   define memzero(d,l) memset(d,0,l)
 #endif
@@ -1042,9 +1130,7 @@ EXTERN_C int usleep(unsigned int);
 #   undef S_ISLNK
 #endif
 
-#ifdef I_TIME
-#   include <time.h>
-#endif
+#include <time.h>
 
 #ifdef I_SYS_TIME
 #   ifdef I_SYS_TIME_KERNEL
@@ -1060,10 +1146,6 @@ EXTERN_C int usleep(unsigned int);
 #    include <sys/times.h>
 #endif
 
-#if defined(HAS_STRERROR) && (!defined(HAS_MKDIR) || !defined(HAS_RMDIR))
-#   undef HAS_STRERROR
-#endif
-
 #include <errno.h>
 
 #if defined(WIN32) && defined(PERL_IMPLICIT_SYS)
@@ -1116,16 +1198,11 @@ EXTERN_C off_t ftello(FILE *);
 
 #if defined(__SUNPRO_CC) /* SUNWspro CC (C++) */
 EXTERN_C char *crypt(const char *, const char *);
-EXTERN_C char **environ;
 #endif
 
-#if defined(__cplusplus)
-#  if defined(BSDish)
-EXTERN_C char **environ;
-#  elif defined(__CYGWIN__)
+#if defined(__cplusplus) && defined(__CYGWIN__)
 EXTERN_C char *crypt(const char *, const char *);
 #endif
-#endif
 
 #ifdef SETERRNO
 # undef SETERRNO  /* SOCKS might have defined this */
@@ -1246,26 +1323,10 @@ EXTERN_C char *crypt(const char *, const char *);
 
 #define UNKNOWN_ERRNO_MSG "(unknown)"
 
-#ifdef HAS_STRERROR
-#   ifndef DONT_DECLARE_STD
-#       ifdef VMS
-       char *strerror (int,...);
-#       else
-       char *strerror (int);
-#       endif
-#    endif
-#    ifndef Strerror
-#       define Strerror strerror
-#    endif
+#if VMS
+#define Strerror(e) strerror((e), vaxc$errno)
 #else
-#    ifdef HAS_SYS_ERRLIST
-       extern int sys_nerr;
-       extern char *sys_errlist[];
-#       ifndef Strerror
-#           define Strerror(e) \
-               ((e) < 0 || (e) >= sys_nerr ? UNKNOWN_ERRNO_MSG : sys_errlist[e])
-#       endif
-#   endif
+#define Strerror(e) strerror(e)
 #endif
 
 #ifdef I_SYS_IOCTL
@@ -1299,19 +1360,11 @@ EXTERN_C char *crypt(const char *, const char *);
 
 /* Configure already sets Direntry_t */
 #if defined(I_DIRENT)
-#   include <dirent.h>
-#else
-#   ifdef I_SYS_NDIR
-#      include <sys/ndir.h>
-#   else
-#      ifdef I_SYS_DIR
-#          ifdef hp9000s500
-#              include <ndir.h>        /* may be wrong in the future */
-#          else
-#              include <sys/dir.h>
-#          endif
-#      endif
-#   endif
+#  include <dirent.h>
+#elif defined(I_SYS_NDIR)
+#  include <sys/ndir.h>
+#elif defined(I_SYS_DIR)
+#  include <sys/dir.h>
 #endif
 
 /*
@@ -1361,35 +1414,27 @@ EXTERN_C char *crypt(const char *, const char *);
 #endif
 
 #ifndef S_ISLNK
-#   ifdef _S_ISLNK
-#      define S_ISLNK(m) _S_ISLNK(m)
-#   else
-#      ifdef _S_IFLNK
-#          define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
-#      else
-#          ifdef S_IFLNK
-#              define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
-#          else
-#              define S_ISLNK(m) (0)
-#          endif
-#      endif
-#   endif
+#  ifdef _S_ISLNK
+#    define S_ISLNK(m) _S_ISLNK(m)
+#  elif defined(_S_IFLNK)
+#    define S_ISLNK(m) ((m & S_IFMT) == _S_IFLNK)
+#  elif defined(S_IFLNK)
+#    define S_ISLNK(m) ((m & S_IFMT) == S_IFLNK)
+#  else
+#    define S_ISLNK(m) (0)
+#  endif
 #endif
 
 #ifndef S_ISSOCK
-#   ifdef _S_ISSOCK
-#      define S_ISSOCK(m) _S_ISSOCK(m)
-#   else
-#      ifdef _S_IFSOCK
-#          define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
-#      else
-#          ifdef S_IFSOCK
-#              define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
-#          else
-#              define S_ISSOCK(m) (0)
-#          endif
-#      endif
-#   endif
+#  ifdef _S_ISSOCK
+#    define S_ISSOCK(m) _S_ISSOCK(m)
+#  elif defined(_S_IFSOCK)
+#    define S_ISSOCK(m) ((m & S_IFMT) == _S_IFSOCK)
+#  elif defined(S_IFSOCK)
+#    define S_ISSOCK(m) ((m & S_IFMT) == S_IFSOCK)
+#  else
+#    define S_ISSOCK(m) (0)
+#  endif
 #endif
 
 #ifndef S_IRUSR
@@ -1472,15 +1517,13 @@ EXTERN_C char *crypt(const char *, const char *);
 #undef UV
 #endif
 
-/* For the times when you want the return value of sprintf, and you want it
-   to be the length. Can't have a thread variable passed in, because C89 has
-   no varargs macros.
-*/
-#ifdef SPRINTF_RETURNS_STRLEN
-#  define my_sprintf sprintf
-#else
-#  define my_sprintf Perl_my_sprintf
-#endif
+/* This used to be conditionally defined based on whether we had a sprintf()
+ * that correctly returns the string length (as required by C89), but we no
+ * longer need that. XS modules can (and do) use this name, so it must remain
+ * a part of the API that's visible to modules. But we no longer document it
+ * either (because using sprintf() rather than snprintf() is almost always
+ * a bad idea). */
+#define my_sprintf sprintf
 
 /*
  * If we have v?snprintf() and the C99 variadic macros, we can just
@@ -1503,8 +1546,7 @@ EXTERN_C char *crypt(const char *, const char *);
 #ifdef USE_QUADMATH
 #  define my_snprintf Perl_my_snprintf
 #  define PERL_MY_SNPRINTF_GUARDED
-#else
-#if defined(HAS_SNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
+#elif defined(HAS_SNPRINTF) && defined(HAS_C99_VARIADIC_MACROS) && !(defined(DEBUGGING) && !defined(PERL_USE_GCC_BRACE_GROUPS)) && !defined(PERL_GCC_PEDANTIC)
 #  ifdef PERL_USE_GCC_BRACE_GROUPS
 #      define my_snprintf(buffer, max, ...) ({ int len = snprintf(buffer, max, __VA_ARGS__); PERL_SNPRINTF_CHECK(len, max, snprintf); len; })
 #      define PERL_MY_SNPRINTF_GUARDED
@@ -1515,7 +1557,6 @@ EXTERN_C char *crypt(const char *, const char *);
 #  define my_snprintf  Perl_my_snprintf
 #  define PERL_MY_SNPRINTF_GUARDED
 #endif
-#endif
 
 /* There is no quadmath_vsnprintf, and therefore my_vsnprintf()
  * dies if called under USE_QUADMATH. */
@@ -1568,12 +1609,26 @@ EXTERN_C char *crypt(const char *, const char *);
 #  define my_strlcat    Perl_my_strlcat
 #endif
 
+#if defined(PERL_CORE) || defined(PERL_EXT)
+#  ifdef HAS_MEMRCHR
+#    define my_memrchr memrchr
+#  else
+#    define my_memrchr S_my_memrchr
+#  endif
+#endif
+
 #ifdef HAS_STRLCPY
 #  define my_strlcpy   strlcpy
 #else
 #  define my_strlcpy   Perl_my_strlcpy
 #endif
 
+#ifdef HAS_STRNLEN
+#  define my_strnlen   strnlen
+#else
+#  define my_strnlen   Perl_my_strnlen
+#endif
+
 /*
     The IV type is supposed to be long enough to hold any integral
     value or a pointer.
@@ -1661,13 +1716,11 @@ typedef UVTYPE UV;
 #if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE)
 #  define PTRV                 UV
 #  define INT2PTR(any,d)       (any)(d)
+#elif PTRSIZE == LONGSIZE
+#  define PTRV                 unsigned long
+#  define PTR2ul(p)            (unsigned long)(p)
 #else
-#  if PTRSIZE == LONGSIZE
-#    define PTRV               unsigned long
-#    define PTR2ul(p)          (unsigned long)(p)
-#  else
-#    define PTRV               unsigned
-#  endif
+#  define PTRV                 unsigned
 #endif
 
 #ifndef INT2PTR
@@ -1704,89 +1757,22 @@ typedef UVTYPE UV;
 #  endif
 #endif
 
-#ifdef OVR_DBL_DIG
-/* Use an overridden DBL_DIG */
-# ifdef DBL_DIG
-#  undef DBL_DIG
-# endif
-# define DBL_DIG OVR_DBL_DIG
-#else
-/* The following is all to get DBL_DIG, in order to pick a nice
-   default value for printing floating point numbers in Gconvert
-   (see config.h). (It also has other uses, such as figuring out if
-   a given precision of printing can be done with a double instead of
-   a long double - Allen).
-*/
-#ifdef I_LIMITS
-#include <limits.h>
-#endif
-#ifdef I_FLOAT
-#include <float.h>
-#endif
-#ifndef HAS_DBL_DIG
-#define DBL_DIG        15   /* A guess that works lots of places */
-#endif
-#endif
-
-#ifdef OVR_LDBL_DIG
-/* Use an overridden LDBL_DIG */
-# ifdef LDBL_DIG
-#  undef LDBL_DIG
-# endif
-# define LDBL_DIG OVR_LDBL_DIG
-#else
 /* The following is all to get LDBL_DIG, in order to pick a nice
    default value for printing floating point numbers in Gconvert.
    (see config.h)
 */
-# ifdef I_LIMITS
-#   include <limits.h>
-# endif
-# ifdef I_FLOAT
-#  include <float.h>
-# endif
-# ifndef HAS_LDBL_DIG
+#ifndef HAS_LDBL_DIG
 #  if LONG_DOUBLESIZE == 10
-#   define LDBL_DIG 18 /* assume IEEE */
-#  else
-#   if LONG_DOUBLESIZE == 12
+#    define LDBL_DIG 18 /* assume IEEE */
+#  elif LONG_DOUBLESIZE == 12
 #    define LDBL_DIG 18 /* gcc? */
-#   else
-#    if LONG_DOUBLESIZE == 16
-#     define LDBL_DIG 33 /* assume IEEE */
-#    else
-#     if LONG_DOUBLESIZE == DOUBLESIZE
-#      define LDBL_DIG DBL_DIG /* bummer */
-#     endif
-#    endif
-#   endif
+#  elif LONG_DOUBLESIZE == 16
+#    define LDBL_DIG 33 /* assume IEEE */
+#  elif LONG_DOUBLESIZE == DOUBLESIZE
+#    define LDBL_DIG DBL_DIG /* bummer */
 #  endif
-# endif
-#endif
-
-/*
- * This is for making sure we have a good DBL_MAX value, if possible,
- * either for usage as NV_MAX or for usage in figuring out if we can
- * fit a given long double into a double, if bug-fixing makes it
- * necessary to do so. - Allen <allens@cpan.org>
- */
-
-#ifdef I_LIMITS
-#  include <limits.h>
 #endif
 
-#ifdef I_VALUES
-#  if !(defined(DBL_MIN) && defined(DBL_MAX) && defined(I_LIMITS))
-#    include <values.h>
-#    if defined(MAXDOUBLE) && !defined(DBL_MAX)
-#      define DBL_MAX MAXDOUBLE
-#    endif
-#    if defined(MINDOUBLE) && !defined(DBL_MIN)
-#      define DBL_MIN MINDOUBLE
-#    endif
-#  endif
-#endif /* defined(I_VALUES) */
-
 typedef NVTYPE NV;
 
 #ifdef I_IEEEFP
@@ -1839,10 +1825,8 @@ typedef NVTYPE NV;
 #       ifdef LDBL_MAX
 #           define NV_MAX LDBL_MAX
 /* Having LDBL_MAX doesn't necessarily mean that we have LDBL_MIN... -Allen */
-#       else
-#           ifdef HUGE_VALL
-#               define NV_MAX HUGE_VALL
-#           endif
+#       elif defined(HUGE_VALL)
+#           define NV_MAX HUGE_VALL
 #       endif
 #   endif
 #   if defined(HAS_SQRTL)
@@ -1883,20 +1867,16 @@ EXTERN_C long double modfl(long double, long double *);
 #   ifndef Perl_frexp
 #       ifdef HAS_FREXPL
 #           define Perl_frexp(x,y) frexpl(x,y)
-#       else
-#           if defined(HAS_ILOGBL) && defined(HAS_SCALBNL)
+#       elif defined(HAS_ILOGBL) && defined(HAS_SCALBNL)
 extern long double Perl_my_frexpl(long double x, int *e);
-#               define Perl_frexp(x,y) Perl_my_frexpl(x,y)
-#           endif
+#           define Perl_frexp(x,y) Perl_my_frexpl(x,y)
 #       endif
 #   endif
 #   ifndef Perl_ldexp
 #       ifdef HAS_LDEXPL
 #           define Perl_ldexp(x, y) ldexpl(x,y)
-#       else
-#           if defined(HAS_SCALBNL) && FLT_RADIX == 2
-#               define Perl_ldexp(x,y) scalbnl(x,y)
-#           endif
+#       elif defined(HAS_SCALBNL) && FLT_RADIX == 2
+#           define Perl_ldexp(x,y) scalbnl(x,y)
 #       endif
 #   endif
 #   ifndef Perl_isnan
@@ -1962,38 +1942,16 @@ extern long double Perl_my_frexpl(long double x, int *e);
 #   define Perl_fp_class_zero(x)   (Perl_fp_class(x) == 0)
 #else
 #   define NV_DIG DBL_DIG
-#   ifdef DBL_MANT_DIG
-#       define NV_MANT_DIG DBL_MANT_DIG
-#   endif
-#   ifdef DBL_MIN
-#       define NV_MIN DBL_MIN
-#   endif
-#   ifdef DBL_MAX
-#       define NV_MAX DBL_MAX
-#   endif
-#   ifdef DBL_MIN_EXP
-#       define NV_MIN_EXP DBL_MIN_EXP
-#   endif
-#   ifdef DBL_MAX_EXP
-#       define NV_MAX_EXP DBL_MAX_EXP
-#   endif
-#   ifdef DBL_MIN_10_EXP
-#       define NV_MIN_10_EXP DBL_MIN_10_EXP
-#   endif
-#   ifdef DBL_MAX_10_EXP
-#       define NV_MAX_10_EXP DBL_MAX_10_EXP
-#   endif
-#   ifdef DBL_EPSILON
-#       define NV_EPSILON DBL_EPSILON
-#   endif
-#   ifdef DBL_MAX               /* XXX Does DBL_MAX imply having DBL_MIN? */
-#       define NV_MAX DBL_MAX
-#       define NV_MIN DBL_MIN
-#   else
-#       ifdef HUGE_VAL
-#           define NV_MAX HUGE_VAL
-#       endif
-#   endif
+#   define NV_MANT_DIG DBL_MANT_DIG
+#   define NV_MIN DBL_MIN
+#   define NV_MAX DBL_MAX
+#   define NV_MIN_EXP DBL_MIN_EXP
+#   define NV_MAX_EXP DBL_MAX_EXP
+#   define NV_MIN_10_EXP DBL_MIN_10_EXP
+#   define NV_MAX_10_EXP DBL_MAX_10_EXP
+#   define NV_EPSILON DBL_EPSILON
+#   define NV_MAX DBL_MAX
+#   define NV_MIN DBL_MIN
 
 /* These math interfaces are C89. */
 #   define Perl_acos acos
@@ -2276,12 +2234,10 @@ int isnan(double d);
 #ifndef Perl_isnan
 #   ifdef Perl_fp_class_nan
 #       define Perl_isnan(x) Perl_fp_class_nan(x)
+#   elif defined(HAS_UNORDERED)
+#       define Perl_isnan(x) unordered((x), 0.0)
 #   else
-#       ifdef HAS_UNORDERED
-#           define Perl_isnan(x) unordered((x), 0.0)
-#       else
-#           define Perl_isnan(x) ((x)!=(x))
-#       endif
+#       define Perl_isnan(x) ((x)!=(x))
 #   endif
 #endif
 
@@ -2357,56 +2313,6 @@ int isnan(double d);
 #   define Perl_atof2(s, n) ((n) = atof(s))
 #endif
 
-/* Previously these definitions used hardcoded figures.
- * It is hoped these formula are more portable, although
- * no data one way or another is presently known to me.
- * The "PERL_" names are used because these calculated constants
- * do not meet the ANSI requirements for LONG_MAX, etc., which
- * need to be constants acceptable to #if - kja
- *    define PERL_LONG_MAX        2147483647L
- *    define PERL_LONG_MIN        (-LONG_MAX - 1)
- *    define PERL ULONG_MAX       4294967295L
- */
-
-#ifdef I_LIMITS  /* Needed for cast_xxx() functions below. */
-#  include <limits.h>
-#endif
-/* Included values.h above if necessary; still including limits.h down here,
- * despite doing above, because math.h might have overridden... XXX - Allen */
-
-/*
- * Try to figure out max and min values for the integral types.  THE CORRECT
- * SOLUTION TO THIS MESS: ADAPT enquire.c FROM GCC INTO CONFIGURE.  The
- * following hacks are used if neither limits.h or values.h provide them:
- * U<TYPE>_MAX: for types >= int: ~(unsigned TYPE)0
- *              for types <  int:  (unsigned TYPE)~(unsigned)0
- *     The argument to ~ must be unsigned so that later signed->unsigned
- *     conversion can't modify the value's bit pattern (e.g. -0 -> +0),
- *     and it must not be smaller than int because ~ does integral promotion.
- * <type>_MAX: (<type>) (U<type>_MAX >> 1)
- * <type>_MIN: -<type>_MAX - <is_twos_complement_architecture: (3 & -1) == 3>.
- *     The latter is a hack which happens to work on some machines but
- *     does *not* catch any random system, or things like integer types
- *     with NaN if that is possible.
- *
- * All of the types are explicitly cast to prevent accidental loss of
- * numeric range, and in the hope that they will be less likely to confuse
- * over-eager optimizers.
- *
- */
-
-#define PERL_UCHAR_MIN ((unsigned char)0)
-
-#ifdef UCHAR_MAX
-#  define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX)
-#else
-#  ifdef MAXUCHAR
-#    define PERL_UCHAR_MAX ((unsigned char)MAXUCHAR)
-#  else
-#    define PERL_UCHAR_MAX       ((unsigned char)~(unsigned)0)
-#  endif
-#endif
-
 /*
  * CHAR_MIN and CHAR_MAX are not included here, as the (char) type may be
  * ambiguous. It may be equivalent to (signed char) or (unsigned char)
@@ -2416,121 +2322,32 @@ int isnan(double d);
  *                                                           - kja
  */
 
-#define PERL_USHORT_MIN ((unsigned short)0)
-
-#ifdef USHORT_MAX
-#  define PERL_USHORT_MAX ((unsigned short)USHORT_MAX)
-#else
-#  ifdef MAXUSHORT
-#    define PERL_USHORT_MAX ((unsigned short)MAXUSHORT)
-#  else
-#    ifdef USHRT_MAX
-#      define PERL_USHORT_MAX ((unsigned short)USHRT_MAX)
-#    else
-#      define PERL_USHORT_MAX       ((unsigned short)~(unsigned)0)
-#    endif
-#  endif
-#endif
-
-#ifdef SHORT_MAX
-#  define PERL_SHORT_MAX ((short)SHORT_MAX)
-#else
-#  ifdef MAXSHORT    /* Often used in <values.h> */
-#    define PERL_SHORT_MAX ((short)MAXSHORT)
-#  else
-#    ifdef SHRT_MAX
-#      define PERL_SHORT_MAX ((short)SHRT_MAX)
-#    else
-#      define PERL_SHORT_MAX      ((short) (PERL_USHORT_MAX >> 1))
-#    endif
-#  endif
-#endif
+#define PERL_UCHAR_MIN ((unsigned char)0)
+#define PERL_UCHAR_MAX ((unsigned char)UCHAR_MAX)
 
-#ifdef SHORT_MIN
-#  define PERL_SHORT_MIN ((short)SHORT_MIN)
-#else
-#  ifdef MINSHORT
-#    define PERL_SHORT_MIN ((short)MINSHORT)
-#  else
-#    ifdef SHRT_MIN
-#      define PERL_SHORT_MIN ((short)SHRT_MIN)
-#    else
-#      define PERL_SHORT_MIN        (-PERL_SHORT_MAX - ((3 & -1) == 3))
-#    endif
-#  endif
-#endif
+#define PERL_USHORT_MIN ((unsigned short)0)
+#define PERL_USHORT_MAX ((unsigned short)USHRT_MAX)
 
-#ifdef UINT_MAX
-#  define PERL_UINT_MAX ((unsigned int)UINT_MAX)
-#else
-#  ifdef MAXUINT
-#    define PERL_UINT_MAX ((unsigned int)MAXUINT)
-#  else
-#    define PERL_UINT_MAX       (~(unsigned int)0)
-#  endif
-#endif
+#define PERL_SHORT_MAX ((short)SHRT_MAX)
+#define PERL_SHORT_MIN ((short)SHRT_MIN)
 
+#define PERL_UINT_MAX ((unsigned int)UINT_MAX)
 #define PERL_UINT_MIN ((unsigned int)0)
 
-#ifdef INT_MAX
-#  define PERL_INT_MAX ((int)INT_MAX)
-#else
-#  ifdef MAXINT    /* Often used in <values.h> */
-#    define PERL_INT_MAX ((int)MAXINT)
-#  else
-#    define PERL_INT_MAX        ((int)(PERL_UINT_MAX >> 1))
-#  endif
-#endif
-
-#ifdef INT_MIN
-#  define PERL_INT_MIN ((int)INT_MIN)
-#else
-#  ifdef MININT
-#    define PERL_INT_MIN ((int)MININT)
-#  else
-#    define PERL_INT_MIN        (-PERL_INT_MAX - ((3 & -1) == 3))
-#  endif
-#endif
-
-#ifdef ULONG_MAX
-#  define PERL_ULONG_MAX ((unsigned long)ULONG_MAX)
-#else
-#  ifdef MAXULONG
-#    define PERL_ULONG_MAX ((unsigned long)MAXULONG)
-#  else
-#    define PERL_ULONG_MAX       (~(unsigned long)0)
-#  endif
-#endif
+#define PERL_INT_MAX ((int)INT_MAX)
+#define PERL_INT_MIN ((int)INT_MIN)
 
+#define PERL_ULONG_MAX ((unsigned long)ULONG_MAX)
 #define PERL_ULONG_MIN ((unsigned long)0L)
 
-#ifdef LONG_MAX
-#  define PERL_LONG_MAX ((long)LONG_MAX)
-#else
-#  ifdef MAXLONG    /* Often used in <values.h> */
-#    define PERL_LONG_MAX ((long)MAXLONG)
-#  else
-#    define PERL_LONG_MAX        ((long) (PERL_ULONG_MAX >> 1))
-#  endif
-#endif
-
-#ifdef LONG_MIN
-#  define PERL_LONG_MIN ((long)LONG_MIN)
-#else
-#  ifdef MINLONG
-#    define PERL_LONG_MIN ((long)MINLONG)
-#  else
-#    define PERL_LONG_MIN        (-PERL_LONG_MAX - ((3 & -1) == 3))
-#  endif
-#endif
+#define PERL_LONG_MAX ((long)LONG_MAX)
+#define PERL_LONG_MIN ((long)LONG_MIN)
 
 #ifdef UV_IS_QUAD
-
 #    define PERL_UQUAD_MAX     (~(UV)0)
 #    define PERL_UQUAD_MIN     ((UV)0)
 #    define PERL_QUAD_MAX      ((IV) (PERL_UQUAD_MAX >> 1))
 #    define PERL_QUAD_MIN      (-PERL_QUAD_MAX - ((3 & -1) == 3))
-
 #endif
 
 typedef MEM_SIZE STRLEN;
@@ -2604,8 +2421,8 @@ typedef AV PAD;
 typedef struct padnamelist PADNAMELIST;
 typedef struct padname PADNAME;
 
-/* enable PERL_OP_PARENT by default */
-#if !defined(PERL_OP_PARENT) && !defined(PERL_NO_OP_PARENT)
+/* always enable PERL_OP_PARENT  */
+#if !defined(PERL_OP_PARENT)
 #  define PERL_OP_PARENT
 #endif
 
@@ -2761,60 +2578,28 @@ typedef struct padname PADNAME;
 #endif
 
 /* NSIG logic from Configure --> */
-/* Strange style to avoid deeply-nested #if/#else/#endif */
 #ifndef NSIG
 #  ifdef _NSIG
 #    define NSIG (_NSIG)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef SIGMAX
+#  elif defined(SIGMAX)
 #    define NSIG (SIGMAX+1)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef SIG_MAX
+#  elif defined(SIG_MAX)
 #    define NSIG (SIG_MAX+1)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef _SIG_MAX
+#  elif defined(_SIG_MAX)
 #    define NSIG (_SIG_MAX+1)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef MAXSIG
+#  elif defined(MAXSIG)
 #    define NSIG (MAXSIG+1)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef MAX_SIG
+#  elif defined(MAX_SIG)
 #    define NSIG (MAX_SIG+1)
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef SIGARRAYSIZE
+#  elif defined(SIGARRAYSIZE)
 #    define NSIG SIGARRAYSIZE /* Assume ary[SIGARRAYSIZE] */
-#  endif
-#endif
-
-#ifndef NSIG
-#  ifdef _sys_nsig
+#  elif defined(_sys_nsig)
 #    define NSIG (_sys_nsig) /* Solaris 2.5 */
-#  endif
-#endif
-
-/* Default to some arbitrary number that's big enough to get most
-   of the common signals.
-*/
-#ifndef NSIG
+#  else
+     /* Default to some arbitrary number that's big enough to get most
+      * of the common signals.  */
 #    define NSIG 50
+#  endif
 #endif
 /* <-- NSIG logic from Configure */
 
@@ -2835,15 +2620,12 @@ typedef struct padname PADNAME;
    and then they have the gall to warn that a value computed is not used. Hence
    cast to void.  */
 #    define PERL_FPU_INIT (void)fpsetmask(0)
+#  elif defined(SIGFPE) && defined(SIG_IGN) && !defined(PERL_MICRO)
+#    define PERL_FPU_INIT       PL_sigfpe_saved = (Sighandler_t) signal(SIGFPE, SIG_IGN)
+#    define PERL_FPU_PRE_EXEC   { Sigsave_t xfpe; rsignal_save(SIGFPE, PL_sigfpe_saved, &xfpe);
+#    define PERL_FPU_POST_EXEC    rsignal_restore(SIGFPE, &xfpe); }
 #  else
-#    if defined(SIGFPE) && defined(SIG_IGN) && !defined(PERL_MICRO)
-#      define PERL_FPU_INIT       PL_sigfpe_saved = (Sighandler_t) signal(SIGFPE, SIG_IGN)
-#      define PERL_FPU_PRE_EXEC   { Sigsave_t xfpe; rsignal_save(SIGFPE, PL_sigfpe_saved, &xfpe);
-#      define PERL_FPU_POST_EXEC    rsignal_restore(SIGFPE, &xfpe); }
-#    else
-#      define PERL_FPU_INIT
-
-#    endif
+#    define PERL_FPU_INIT
 #  endif
 #endif
 #ifndef PERL_FPU_PRE_EXEC
@@ -3098,32 +2880,24 @@ freeing any remaining Perl interpreters.
 
 #if defined(USE_ITHREADS)
 #  ifdef NETWARE
-#   include <nw5thread.h>
-#  else
-#    ifdef WIN32
-#      include <win32thread.h>
-#    else
-#      ifdef OS2
-#        include "os2thread.h"
-#      else
-#        ifdef I_MACH_CTHREADS
-#          include <mach/cthreads.h>
+#    include <nw5thread.h>
+#  elif defined(WIN32)
+#    include <win32thread.h>
+#  elif defined(OS2)
+#    include "os2thread.h"
+#  elif defined(I_MACH_CTHREADS)
+#    include <mach/cthreads.h>
 typedef cthread_t      perl_os_thread;
 typedef mutex_t                perl_mutex;
 typedef condition_t    perl_cond;
 typedef void *         perl_key;
-#        else /* Posix threads */
-#          ifdef I_PTHREAD
-#            include <pthread.h>
-#          endif
+#  elif defined(I_PTHREAD) /* Posix threads */
+#    include <pthread.h>
 typedef pthread_t      perl_os_thread;
 typedef pthread_mutex_t PERL_TSA_CAPABILITY("mutex") perl_mutex;
 typedef pthread_cond_t perl_cond;
 typedef pthread_key_t  perl_key;
-#        endif /* I_MACH_CTHREADS */
-#      endif /* OS2 */
-#    endif /* WIN32 */
-#  endif /* NETWARE */
+#  endif
 #endif /* USE_ITHREADS */
 
 #ifdef PERL_TSA_ACTIVE
@@ -3446,12 +3220,10 @@ EXTERN_C int perl_tsa_mutex_unlock(perl_mutex* mutex)
 #ifndef PERL_FLUSHALL_FOR_CHILD
 # if defined(USE_PERLIO) || defined(FFLUSH_NULL)
 #  define PERL_FLUSHALL_FOR_CHILD      PerlIO_flush((PerlIO*)NULL)
+# elif defined(FFLUSH_ALL)
+#  define PERL_FLUSHALL_FOR_CHILD      my_fflush_all()
 # else
-#  ifdef FFLUSH_ALL
-#   define PERL_FLUSHALL_FOR_CHILD     my_fflush_all()
-#  else
-#   define PERL_FLUSHALL_FOR_CHILD     NOOP
-#  endif
+#  define PERL_FLUSHALL_FOR_CHILD      NOOP
 # endif
 #endif
 
@@ -3529,10 +3301,8 @@ EXTERN_C int perl_tsa_mutex_unlock(perl_mutex* mutex)
 #ifdef PERL_CORE
 /* not used; but needed for backward compatibility with XS code? - RMB */
 #  undef UVf
-#else
-#  ifndef UVf
-#    define UVf UVuf
-#  endif
+#elif !defined(UVf)
+#  define UVf UVuf
 #endif
 
 #ifdef HASATTRIBUTE_DEPRECATED
@@ -3586,12 +3356,10 @@ EXTERN_C int perl_tsa_mutex_unlock(perl_mutex* mutex)
 #  define __attribute__warn_unused_result__
 #endif
 
-#ifdef I_ASSERT
-#  if !defined(DEBUGGING) && !defined(NDEBUG)
-#    define NDEBUG 1
-#  endif
-#  include <assert.h>
+#if !defined(DEBUGGING) && !defined(NDEBUG)
+#  define NDEBUG 1
 #endif
+#include <assert.h>
 
 /* For functions that are marked as __attribute__noreturn__, it's not
    appropriate to call return.  In either case, include the lint directive.
@@ -3708,14 +3476,12 @@ EXTERN_C int perl_tsa_mutex_unlock(perl_mutex* mutex)
 #   ifdef IOCPARM_MASK
        /* on BSDish systems we're safe */
 #      define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
-#   else
-#      if defined(_IOC_SIZE) && defined(__GLIBC__)
+#   elif defined(_IOC_SIZE) && defined(__GLIBC__)
        /* on Linux systems we're safe; except when we're not [perl #38223] */
-#          define IOCPARM_LEN(x) (_IOC_SIZE(x) < 256 ? 256 : _IOC_SIZE(x))
-#      else
+#      define IOCPARM_LEN(x) (_IOC_SIZE(x) < 256 ? 256 : _IOC_SIZE(x))
+#   else
        /* otherwise guess at what's safe */
-#          define IOCPARM_LEN(x)       256
-#      endif
+#      define IOCPARM_LEN(x)   256
 #   endif
 #endif
 
@@ -4334,7 +4100,7 @@ Gid_t getegid (void);
                        "\", line %d", STRINGIFY(what), __LINE__),      \
              (void) 0)), ((void)0))
 
-/* assert() gets defined if DEBUGGING (and I_ASSERT).
+/* assert() gets defined if DEBUGGING.
  * If no DEBUGGING, the <assert.h> has not been included. */
 #ifndef assert
 #  define assert(what) Perl_assert(what)
@@ -4373,48 +4139,10 @@ static PERL_MG_UFUNC(foo_get, index, val)
 #define PERL_MG_UFUNC(name,ix,sv) I32 name(pTHX_ IV ix, SV *sv)
 #endif
 
-/* Fix these up for __STDC__ */
-#ifndef DONT_DECLARE_STD
-char *mktemp (char*);
-#ifndef atof
-double atof (const char*);
-#endif
-#endif
-
-#ifndef STANDARD_C
-/* All of these are in stdlib.h or time.h for ANSI C */
-Time_t time();
-struct tm *gmtime(), *localtime();
-#if defined(OEMVS)
-char *(strchr)(), *(strrchr)();
-char *(strcpy)(), *(strcat)();
-#else
-char *strchr(), *strrchr();
-char *strcpy(), *strcat();
-#endif
-#endif /* ! STANDARD_C */
-
-
-#ifdef I_MATH
-#    include <math.h>
-#    ifdef __VMS
+#include <math.h>
+#ifdef __VMS
      /* isfinite and others are here rather than in math.h as C99 stipulates */
-#        include <fp.h>
-#    endif
-#else
-START_EXTERN_C
-           double exp (double);
-           double log (double);
-           double log10 (double);
-           double sqrt (double);
-           double frexp (double,int*);
-           double ldexp (double,int);
-           double modf (double,double*);
-           double sin (double);
-           double cos (double);
-           double atan2 (double,double);
-           double pow (double,double);
-END_EXTERN_C
+#    include <fp.h>
 #endif
 
 #ifndef __cplusplus
@@ -4423,18 +4151,6 @@ END_EXTERN_C
 char *crypt (const char*, const char*);
 #endif
 #  endif /* !WIN32 */
-#  ifndef DONT_DECLARE_STD
-#    ifndef getenv
-char *getenv (const char*);
-#    endif /* !getenv */
-#    if !defined(HAS_LSEEK_PROTO) && !defined(__hpux)
-#      ifdef _FILE_OFFSET_BITS
-#        if _FILE_OFFSET_BITS == 64
-Off_t lseek (int,Off_t,int);
-#        endif
-#      endif
-#    endif
-#  endif /* !DONT_DECLARE_STD */
 #  ifndef WIN32
 #    ifndef getlogin
 char *getlogin (void);
@@ -4627,15 +4343,9 @@ typedef void (*despatch_signals_proc_t) (pTHX);
 #if defined(__DYNAMIC__) && defined(PERL_DARWIN) && defined(PERL_CORE)
 #  include <crt_externs.h>     /* for the env array */
 #  define environ (*_NSGetEnviron())
-#else
+#elif defined(USE_ENVIRON_ARRAY) && !defined(environ)
    /* VMS and some other platforms don't use the environ array */
-#  ifdef USE_ENVIRON_ARRAY
-#    if !defined(DONT_DECLARE_STD) || \
-        (defined(__svr4__) && defined(__GNUC__) && defined(__sun)) || \
-        defined(__sgi)
-extern char ** environ;        /* environment variables supplied via exec */
-#    endif
-#  endif
+EXTERN_C char **environ;  /* environment variables supplied via exec */
 #endif
 
 #define PERL_PATCHLEVEL_H_IMPLICIT
@@ -5340,9 +5050,6 @@ typedef enum {
                                 */
 
 /* The following are stored in $^H{sort}, not in PL_hints */
-#define HINT_SORT_SORT_BITS    0x000000FF /* allow 256 different ones */
-#define HINT_SORT_QUICKSORT    0x00000001
-#define HINT_SORT_MERGESORT    0x00000002
 #define HINT_SORT_STABLE       0x00000100 /* sort styles */
 #define HINT_SORT_UNSTABLE     0x00000200
 
@@ -5822,25 +5529,22 @@ typedef struct am_table_short AMTS;
 
 #define PERLDB_LINE_OR_SAVESRC (PL_perldb & (PERLDBf_LINE | PERLDBf_SAVESRC))
 
-#ifdef USE_LOCALE
-/* These locale things are all subject to change */
-
-
-#  if      defined(HAS_NEWLOCALE)               \
-      &&   defined(LC_ALL_MASK)                 \
-      &&   defined(HAS_FREELOCALE)              \
-      &&   defined(HAS_USELOCALE)               \
-      && ! defined(NO_POSIX_2008_LOCALE)
-
-    /* The code is written for simplicity to assume that any platform advanced
-     * enough to have the Posix 2008 locale functions has LC_ALL.  The test
-     * above makes sure that assumption is valid */
+#ifdef USE_ITHREADS
+#  define KEYWORD_PLUGIN_MUTEX_INIT    MUTEX_INIT(&PL_keyword_plugin_mutex)
+#  define KEYWORD_PLUGIN_MUTEX_LOCK    MUTEX_LOCK(&PL_keyword_plugin_mutex)
+#  define KEYWORD_PLUGIN_MUTEX_UNLOCK  MUTEX_UNLOCK(&PL_keyword_plugin_mutex)
+#  define KEYWORD_PLUGIN_MUTEX_TERM    MUTEX_DESTROY(&PL_keyword_plugin_mutex)
+#else
+#  define KEYWORD_PLUGIN_MUTEX_INIT    NOOP
+#  define KEYWORD_PLUGIN_MUTEX_LOCK    NOOP
+#  define KEYWORD_PLUGIN_MUTEX_UNLOCK  NOOP
+#  define KEYWORD_PLUGIN_MUTEX_TERM    NOOP
+#endif
 
-#    define HAS_POSIX_2008_LOCALE
-#  endif
+#ifdef USE_LOCALE /* These locale things are all subject to change */
 
-/* We create a C locale object unconditionally if we have the functions to do
* so; hence must destroy it unconditionally at the end */
+    /* We create a C locale object unconditionally if we have the functions to
    * do so; hence must destroy it unconditionally at the end */
 #  ifndef HAS_POSIX_2008_LOCALE
 #    define _LOCALE_TERM_POSIX_2008  NOOP
 #  else
@@ -5856,24 +5560,105 @@ typedef struct am_table_short AMTS;
                     } STMT_END
 #  endif
 
-#  ifndef USE_ITHREADS
+#  if ! defined(USE_ITHREADS) || defined(USE_THREAD_SAFE_LOCALE)
 #    define LOCALE_INIT
 #    define LOCALE_LOCK
 #    define LOCALE_UNLOCK
+#    define LC_NUMERIC_LOCK(cond)
+#    define LC_NUMERIC_UNLOCK
 #    define LOCALE_TERM  STMT_START { _LOCALE_TERM_POSIX_2008; } STMT_END
-#  else /* Below is do use threads */
-#    define LOCALE_INIT         MUTEX_INIT(&PL_locale_mutex)
-#    define LOCALE_LOCK         MUTEX_LOCK(&PL_locale_mutex)
-#    define LOCALE_UNLOCK       MUTEX_UNLOCK(&PL_locale_mutex)
+#  else
+#    define LOCALE_INIT         STMT_START {                                \
+                                    MUTEX_INIT(&PL_locale_mutex);           \
+                                    MUTEX_INIT(&PL_lc_numeric_mutex);       \
+                                } STMT_END
+
+/* This mutex is used to create critical sections where we want the LC_NUMERIC
+ * locale to be locked into either the C (standard) locale, or the underlying
+ * locale, so that other threads interrupting this one don't change it to the
+ * wrong state before we've had a chance to complete our operation.  It can
+ * stay locked over an entire printf operation, for example.  And so is made
+ * distinct from the LOCALE_LOCK mutex.
+ *
+ * This simulates kind of a general semaphore.  The current thread will lock
+ * the mutex if the per-thread variable is zero, and then increments that
+ * variable.  Each corresponding UNLOCK decrements the variable until it is 0,
+ * at which point it actually unlocks the mutex.  Since the variable is
+ * per-thread, there is no race with other threads.
+ *
+ * The single argument is a condition to test for, and if true, to panic, as
+ * this would be an attempt to complement the LC_NUMERIC state, and we're not
+ * supposed to because it's locked */
+#    define LC_NUMERIC_LOCK(cond_to_panic_if_already_locked)                \
+        STMT_START {                                                        \
+            if (PL_lc_numeric_mutex_depth <= 0) {                           \
+                MUTEX_LOCK(&PL_lc_numeric_mutex);                           \
+                PL_lc_numeric_mutex_depth = 1;                              \
+                DEBUG_Lv(PerlIO_printf(Perl_debug_log,                      \
+                         "%s: %d: locking lc_numeric; depth=1\n",           \
+                         __FILE__, __LINE__));                              \
+            }                                                               \
+            else {                                                          \
+                PL_lc_numeric_mutex_depth++;                                \
+                DEBUG_Lv(PerlIO_printf(Perl_debug_log,                      \
+                        "%s: %d: avoided lc_numeric_lock; depth=%d\n",      \
+                        __FILE__, __LINE__, PL_lc_numeric_mutex_depth));    \
+                if (cond_to_panic_if_already_locked) {                      \
+                    Perl_croak_nocontext("panic: %s: %d: Trying to change"  \
+                                         " LC_NUMERIC incompatibly",        \
+                                         __FILE__, __LINE__);               \
+                }                                                           \
+            }                                                               \
+        } STMT_END
+
+#    define LC_NUMERIC_UNLOCK                                               \
+        STMT_START {                                                        \
+            if (PL_lc_numeric_mutex_depth <= 1) {                           \
+                MUTEX_UNLOCK(&PL_lc_numeric_mutex);                         \
+                PL_lc_numeric_mutex_depth = 0;                              \
+                DEBUG_Lv(PerlIO_printf(Perl_debug_log,                      \
+                         "%s: %d: unlocking lc_numeric; depth=0\n",           \
+                         __FILE__, __LINE__));                              \
+            }                                                               \
+            else {                                                          \
+                PL_lc_numeric_mutex_depth--;                                \
+                DEBUG_Lv(PerlIO_printf(Perl_debug_log,                      \
+                        "%s: %d: avoided lc_numeric_unlock; depth=%d\n",    \
+                        __FILE__, __LINE__, PL_lc_numeric_mutex_depth));    \
+            }                                                               \
+        } STMT_END
+
+/* This is used as a generic lock for locale operations.  For example this is
+ * used when calling nl_langinfo() so that another thread won't zap the
+ * contents of its buffer before it gets saved; and it's called when changing
+ * the locale of LC_MESSAGES.  On some systems the latter can cause the
+ * nl_langinfo buffer to be zapped under a race condition.
+ *
+ * If combined with LC_NUMERIC_LOCK, calls to this and its corresponding unlock
+ * should be contained entirely within the locked portion of LC_NUMERIC.  This
+ * mutex should be used only in very short sections of code, while
+ * LC_NUMERIC_LOCK may span more operations.  By always following this
+ * convention, deadlock should be impossible.  But if necessary, the two
+ * mutexes could be combined */
+#    define LOCALE_LOCK                                                     \
+        STMT_START {                                                        \
+            DEBUG_Lv(PerlIO_printf(Perl_debug_log,                          \
+                    "%s: %d: locking locale\n", __FILE__, __LINE__));       \
+            MUTEX_LOCK(&PL_locale_mutex);                                   \
+        } STMT_END
+#    define LOCALE_UNLOCK                                                   \
+        STMT_START {                                                        \
+            DEBUG_Lv(PerlIO_printf(Perl_debug_log,                          \
+                   "%s: %d: unlocking locale\n", __FILE__, __LINE__));      \
+            MUTEX_UNLOCK(&PL_locale_mutex);                                 \
+        } STMT_END
+
 #    define LOCALE_TERM                                                     \
                     STMT_START {                                            \
                         MUTEX_DESTROY(&PL_locale_mutex);                    \
+                        MUTEX_DESTROY(&PL_lc_numeric_mutex);                \
                         _LOCALE_TERM_POSIX_2008;                            \
                     } STMT_END
-#    ifdef HAS_POSIX_2008_LOCALE
-#      define USE_POSIX_2008_LOCALE
-#      define USE_THREAD_SAFE_LOCALE
-#    endif
 #  endif
 
 /* Returns TRUE if the plain locale pragma without a parameter is in effect
@@ -5904,10 +5689,10 @@ typedef struct am_table_short AMTS;
 
 #   define IN_LC_COMPILETIME(category)                                       \
        (IN_LC_ALL_COMPILETIME || (IN_LC_PARTIAL_COMPILETIME                  \
-                                  && _is_in_locale_category(TRUE, (category))))
+                  && Perl__is_in_locale_category(aTHX_ TRUE, (category))))
 #   define IN_LC_RUNTIME(category)                                           \
        (IN_LC_ALL_RUNTIME || (IN_LC_PARTIAL_RUNTIME                          \
-                              && _is_in_locale_category(FALSE, (category))))
+                  && Perl__is_in_locale_category(aTHX_ FALSE, (category))))
 #   define IN_LC(category)  \
                     (IN_LC_COMPILETIME(category) || IN_LC_RUNTIME(category))
 
@@ -5958,7 +5743,6 @@ typedef struct am_table_short AMTS;
         }  STMT_END
 
 #   endif   /* PERL_CORE or PERL_IN_XSUB_RE */
-
 #else   /* No locale usage */
 #   define LOCALE_INIT
 #   define LOCALE_TERM
@@ -6024,6 +5808,10 @@ argument list, like this:
 The private variable is used to save the current locale state, so
 that the requisite matching call to L</RESTORE_LC_NUMERIC> can restore it.
 
+On threaded perls not operating with thread-safe functionality, this macro uses
+a mutex to force a critical section.  Therefore the matching RESTORE should be
+close by, and guaranteed to be called.
+
 =for apidoc Am|void|STORE_LC_NUMERIC_SET_TO_NEEDED
 
 This is used to help wrap XS or C code that that is C<LC_NUMERIC> locale-aware.
@@ -6054,14 +5842,16 @@ argument list, like this:
      ...
  }
 
+On threaded perls not operating with thread-safe functionality, this macro uses
+a mutex to force a critical section.  Therefore the matching RESTORE should be
+close by, and guaranteed to be called.
+
 =for apidoc Am|void|RESTORE_LC_NUMERIC
 
 This is used in conjunction with one of the macros
 L</STORE_LC_NUMERIC_SET_TO_NEEDED>
-and
-L</STORE_LC_NUMERIC_FORCE_TO_UNDERLYING>
-
-to properly restore the C<LC_NUMERIC> state.
+and L</STORE_LC_NUMERIC_FORCE_TO_UNDERLYING> to properly restore the
+C<LC_NUMERIC> state.
 
 A call to L</DECLARATION_FOR_LC_NUMERIC_MANIPULATION> must have been made to
 declare at compile time a private variable used by this macro and the two
@@ -6079,74 +5869,111 @@ expression, but with an empty argument list, like this:
 
 */
 
-#define _NOT_IN_NUMERIC_STANDARD (! PL_numeric_standard)
+/* The numeric locale is generally kept in the C locale instead of the
+ * underlying locale.  The current status is known by looking at two words.
+ * One is non-zero if the current numeric locale is the standard C/POSIX one.
+ * The other is non-zero if the current locale is the underlying locale.  Both
+ * can be non-zero if, as often happens, the underlying locale is C.
+ *
+ * Its slightly more complicated than this, as the PL_numeric_standard variable
+ * is set if the current numeric locale is indistinguishable from the C locale.
+ * This happens when the radix character is a dot, and the thousands separator
+ * is the empty string.
+ *
+ * khw believes the reason for the variables instead of the bits in a single
+ * word is to avoid having to have masking instructions. */
+
+#  define _NOT_IN_NUMERIC_STANDARD (! PL_numeric_standard)
 
 /* We can lock the category to stay in the C locale, making requests to the
  * contrary be noops, in the dynamic scope by setting PL_numeric_standard to 2.
  * */
-#define _NOT_IN_NUMERIC_UNDERLYING                                          \
-                        (! PL_numeric_local && PL_numeric_standard < 2)
+#  define _NOT_IN_NUMERIC_UNDERLYING                                        \
+                    (! PL_numeric_underlying && PL_numeric_standard < 2)
 
-#define DECLARATION_FOR_LC_NUMERIC_MANIPULATION                             \
+#  define DECLARATION_FOR_LC_NUMERIC_MANIPULATION                           \
     void (*_restore_LC_NUMERIC_function)(pTHX) = NULL
 
-#define STORE_LC_NUMERIC_SET_TO_NEEDED()                                    \
-    if (IN_LC(LC_NUMERIC)) {                                                \
-        if (_NOT_IN_NUMERIC_UNDERLYING) {                                   \
-            Perl_set_numeric_local(aTHX);                                   \
-            _restore_LC_NUMERIC_function = &Perl_set_numeric_standard;      \
-        }                                                                   \
-    }                                                                       \
-    else {                                                                  \
-        if (_NOT_IN_NUMERIC_STANDARD) {                                     \
-            SET_NUMERIC_STANDARD();                                         \
-            _restore_LC_NUMERIC_function = &Perl_set_numeric_local;         \
-        }                                                                   \
-    }
-
-#define RESTORE_LC_NUMERIC()                                                \
-    if (_restore_LC_NUMERIC_function) {                                     \
-        _restore_LC_NUMERIC_function(aTHX);                                 \
-    }
+#  define STORE_LC_NUMERIC_SET_TO_NEEDED()                                  \
+        STMT_START {                                                        \
+            LC_NUMERIC_LOCK(                                                \
+                          (IN_LC(LC_NUMERIC) && _NOT_IN_NUMERIC_UNDERLYING) \
+                      || _NOT_IN_NUMERIC_STANDARD);                         \
+            if (IN_LC(LC_NUMERIC)) {                                        \
+                if (_NOT_IN_NUMERIC_UNDERLYING) {                           \
+                    Perl_set_numeric_underlying(aTHX);                      \
+                    _restore_LC_NUMERIC_function                            \
+                                            = &Perl_set_numeric_standard;   \
+                }                                                           \
+            }                                                               \
+            else {                                                          \
+                if (_NOT_IN_NUMERIC_STANDARD) {                             \
+                    Perl_set_numeric_standard(aTHX);                        \
+                    _restore_LC_NUMERIC_function                            \
+                                            = &Perl_set_numeric_underlying; \
+                }                                                           \
+            }                                                               \
+        } STMT_END
+
+#  define RESTORE_LC_NUMERIC()                                              \
+        STMT_START {                                                        \
+            if (_restore_LC_NUMERIC_function) {                             \
+                _restore_LC_NUMERIC_function(aTHX);                         \
+            }                                                               \
+            LC_NUMERIC_UNLOCK;                                              \
+        } STMT_END
 
 /* The next two macros set unconditionally.  These should be rarely used, and
  * only after being sure that this is what is needed */
-#define SET_NUMERIC_STANDARD()                                              \
-       STMT_START { if (_NOT_IN_NUMERIC_STANDARD)                          \
-                                          Perl_set_numeric_standard(aTHX);  \
-                   } STMT_END
+#  define SET_NUMERIC_STANDARD()                                            \
+       STMT_START {                                                        \
+            DEBUG_Lv(PerlIO_printf(Perl_debug_log,"%s: %d: standard=%d\n",  \
+                                __FILE__, __LINE__, PL_numeric_standard));  \
+            Perl_set_numeric_standard(aTHX);                            \
+            DEBUG_Lv(PerlIO_printf(Perl_debug_log, "%s: %d: standard=%d\n", \
+                                 __FILE__, __LINE__, PL_numeric_standard)); \
+        } STMT_END
 
-#define SET_NUMERIC_UNDERLYING()                                            \
-       STMT_START { if (_NOT_IN_NUMERIC_UNDERLYING)                        \
-                                Perl_set_numeric_local(aTHX); } STMT_END
+#  define SET_NUMERIC_UNDERLYING()                                          \
+       STMT_START {                                                        \
+            if (_NOT_IN_NUMERIC_UNDERLYING) {                               \
+                Perl_set_numeric_underlying(aTHX);                          \
+            }                                                               \
+        } STMT_END
 
 /* The rest of these LC_NUMERIC macros toggle to one or the other state, with
  * the RESTORE_foo ones called to switch back, but only if need be */
-#define STORE_LC_NUMERIC_UNDERLYING_SET_STANDARD()                          \
-       bool _was_local = _NOT_IN_NUMERIC_STANDARD;                         \
-       if (_was_local) Perl_set_numeric_standard(aTHX);
-
-/* Doesn't change to underlying locale unless within the scope of some form of
- * 'use locale'.  This is the usual desired behavior. */
-#define STORE_LC_NUMERIC_STANDARD_SET_UNDERLYING()                          \
-       bool _was_standard = _NOT_IN_NUMERIC_UNDERLYING                     \
-                            && IN_LC(LC_NUMERIC);                           \
-       if (_was_standard) Perl_set_numeric_local(aTHX);
+#  define STORE_LC_NUMERIC_SET_STANDARD()                                   \
+        STMT_START {                                                        \
+            LC_NUMERIC_LOCK(_NOT_IN_NUMERIC_STANDARD);                      \
+            if (_NOT_IN_NUMERIC_STANDARD) {                                 \
+                _restore_LC_NUMERIC_function = &Perl_set_numeric_underlying;\
+                Perl_set_numeric_standard(aTHX);                            \
+            }                                                               \
+        } STMT_END
 
 /* Rarely, we want to change to the underlying locale even outside of 'use
  * locale'.  This is principally in the POSIX:: functions */
-#define STORE_LC_NUMERIC_FORCE_TO_UNDERLYING()                              \
-    if (_NOT_IN_NUMERIC_UNDERLYING) {                                       \
-        Perl_set_numeric_local(aTHX);                                       \
-        _restore_LC_NUMERIC_function = &Perl_set_numeric_standard;          \
-    }
+#  define STORE_LC_NUMERIC_FORCE_TO_UNDERLYING()                            \
+       STMT_START {                                                        \
+            LC_NUMERIC_LOCK(_NOT_IN_NUMERIC_UNDERLYING);                    \
+            if (_NOT_IN_NUMERIC_UNDERLYING) {                               \
+                Perl_set_numeric_underlying(aTHX);                          \
+                _restore_LC_NUMERIC_function = &Perl_set_numeric_standard;  \
+            }                                                               \
+        } STMT_END
 
 /* Lock/unlock to the C locale until unlock is called.  This needs to be
  * recursively callable.  [perl #128207] */
-#define LOCK_LC_NUMERIC_STANDARD()                          \
-        (__ASSERT_(PL_numeric_standard)                     \
-        PL_numeric_standard++)
-#define UNLOCK_LC_NUMERIC_STANDARD()                        \
+#  define LOCK_LC_NUMERIC_STANDARD()                                        \
+        STMT_START {                                                        \
+            DEBUG_Lv(PerlIO_printf(Perl_debug_log, "%s: %d: standard=%d\n", \
+                                 __FILE__, __LINE__, PL_numeric_standard)); \
+            __ASSERT_(PL_numeric_standard)                                  \
+            PL_numeric_standard++;                                          \
+        } STMT_END
+
+#  define UNLOCK_LC_NUMERIC_STANDARD()                      \
             STMT_START {                                    \
                 if (PL_numeric_standard > 1) {              \
                     PL_numeric_standard--;                  \
@@ -6156,54 +5983,23 @@ expression, but with an empty argument list, like this:
                 }                                           \
             } STMT_END
 
-#define RESTORE_LC_NUMERIC_UNDERLYING()                     \
-       if (_was_local) Perl_set_numeric_local(aTHX);
-
-#define RESTORE_LC_NUMERIC_STANDARD()                       \
-    if (_restore_LC_NUMERIC_function) {                     \
-        _restore_LC_NUMERIC_function(aTHX);                 \
-    }
-
 #else /* !USE_LOCALE_NUMERIC */
 
-#define SET_NUMERIC_STANDARD()
-#define SET_NUMERIC_UNDERLYING()
-#define IS_NUMERIC_RADIX(a, b)         (0)
-#define STORE_LC_NUMERIC_UNDERLYING_SET_STANDARD()
-#define STORE_LC_NUMERIC_STANDARD_SET_UNDERLYING()
-#define STORE_LC_NUMERIC_FORCE_TO_UNDERLYING()
-#define RESTORE_LC_NUMERIC_UNDERLYING()
-#define RESTORE_LC_NUMERIC_STANDARD()
-#define DECLARATION_FOR_LC_NUMERIC_MANIPULATION
-#define STORE_LC_NUMERIC_SET_TO_NEEDED()
-#define RESTORE_LC_NUMERIC()
-#define LOCK_LC_NUMERIC_STANDARD()
-#define UNLOCK_LC_NUMERIC_STANDARD()
+#  define SET_NUMERIC_STANDARD()
+#  define SET_NUMERIC_UNDERLYING()
+#  define IS_NUMERIC_RADIX(a, b)               (0)
+#  define DECLARATION_FOR_LC_NUMERIC_MANIPULATION
+#  define STORE_LC_NUMERIC_SET_STANDARD()
+#  define STORE_LC_NUMERIC_FORCE_TO_UNDERLYING()
+#  define STORE_LC_NUMERIC_SET_TO_NEEDED()
+#  define RESTORE_LC_NUMERIC()
+#  define LOCK_LC_NUMERIC_STANDARD()
+#  define UNLOCK_LC_NUMERIC_STANDARD()
 
 #endif /* !USE_LOCALE_NUMERIC */
 
 #define Atof                           my_atof
 
-/* Back-compat names */
-#define DECLARATION_FOR_STORE_LC_NUMERIC_SET_TO_NEEDED              \
-                        DECLARATION_FOR_LC_NUMERIC_MANIPULATION
-#define DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED()                    \
-                DECLARATION_FOR_STORE_LC_NUMERIC_SET_TO_NEEDED;     \
-                STORE_LC_NUMERIC_SET_TO_NEEDED();
-#define LOCK_NUMERIC_STANDARD() LOCK_LC_NUMERIC_STANDARD()
-#define RESTORE_NUMERIC_LOCAL() RESTORE_LC_NUMERIC_UNDERLYING()
-#define RESTORE_NUMERIC_STANDARD() RESTORE_LC_NUMERIC_STANDARD()
-#define SET_NUMERIC_LOCAL() SET_NUMERIC_UNDERLYING()
-#define STORE_NUMERIC_LOCAL_SET_STANDARD()                          \
-                    STORE_LC_NUMERIC_UNDERLYING_SET_STANDARD()
-#define STORE_NUMERIC_STANDARD_SET_LOCAL()                          \
-                    STORE_LC_NUMERIC_STANDARD_SET_UNDERLYING()
-#define STORE_NUMERIC_STANDARD_FORCE_LOCAL()                        \
-                        STORE_LC_NUMERIC_FORCE_TO_UNDERLYING()
-#define UNLOCK_NUMERIC_STANDARD() UNLOCK_LC_NUMERIC_STANDARD()
-
-
-
 #ifdef USE_QUADMATH
 #  define Perl_strtod(s, e) strtoflt128(s, e)
 #elif defined(HAS_LONG_DOUBLE) && defined(USE_LONG_DOUBLE)
@@ -6331,14 +6127,12 @@ expression, but with an empty argument list, like this:
 #           define semun gccbug_semun
 #      endif
 #       define Semctl(id, num, cmd, semun) semctl(id, num, cmd, semun)
-#   else
-#       ifdef USE_SEMCTL_SEMID_DS
+#   elif defined(USE_SEMCTL_SEMID_DS)
 #           ifdef EXTRA_F_IN_SEMUN_BUF
 #               define Semctl(id, num, cmd, semun) semctl(id, num, cmd, semun.buff)
 #           else
 #               define Semctl(id, num, cmd, semun) semctl(id, num, cmd, semun.buf)
 #           endif
-#       endif
 #   endif
 #endif
 
@@ -6879,7 +6673,7 @@ extern void moncontrol(int);
  */
 
 /* The quadmath literals are anon structs which -Wc++-compat doesn't like. */
-GCC_DIAG_IGNORE(-Wc++-compat)
+GCC_DIAG_IGNORE_DECL(-Wc++-compat);
 
 #  ifdef USE_QUADMATH
 /* Cannot use HUGE_VALQ for PL_inf because not a compile-time
@@ -6949,7 +6743,7 @@ INFNAN_NV_U8_DECL PL_nan = { 0.0/0.0 }; /* keep last */
 #    endif
 #  endif
 
-GCC_DIAG_RESTORE
+GCC_DIAG_RESTORE_DECL;
 
 #else