diff --git a/gcc/config/aarch64/aarch64-linux.h b/gcc/config/aarch64/aarch64-linux.h
index e587e2e9ad6..b1d1f671fc5 100644
--- a/gcc/config/aarch64/aarch64-linux.h
+++ b/gcc/config/aarch64/aarch64-linux.h
@@ -64,8 +64,6 @@
     }						\
   while (0)
 
-#define GNU_USER_TARGET_D_CRITSEC_SIZE 48
-
 #define TARGET_ASM_FILE_END aarch64_file_end_indicate_exec_stack
 
 /* Uninitialized common symbols in non-PIE executables, even with
diff --git a/gcc/config/glibc-d.c b/gcc/config/glibc-d.c
index bdacdace0c3..7eb9e315f00 100644
--- a/gcc/config/glibc-d.c
+++ b/gcc/config/glibc-d.c
@@ -42,23 +42,7 @@ glibc_d_os_builtins (void)
 #endif
 }
 
-/* Implement TARGET_D_CRITSEC_SIZE for Glibc targets.  */
-
-static unsigned
-glibc_d_critsec_size (void)
-{
-  /* This is the sizeof pthread_mutex_t.  */
-#ifdef GNU_USER_TARGET_D_CRITSEC_SIZE
-  return GNU_USER_TARGET_D_CRITSEC_SIZE;
-#else
-  return (POINTER_SIZE == 64) ? 40 : 24;
-#endif
-}
-
 #undef TARGET_D_OS_VERSIONS
 #define TARGET_D_OS_VERSIONS glibc_d_os_builtins
 
-#undef TARGET_D_CRITSEC_SIZE
-#define TARGET_D_CRITSEC_SIZE glibc_d_critsec_size
-
 struct gcc_targetdm targetdm = TARGETDM_INITIALIZER;
diff --git a/gcc/config/i386/linux-common.h b/gcc/config/i386/linux-common.h
index 1ae6b3f3939..982390d7f3e 100644
--- a/gcc/config/i386/linux-common.h
+++ b/gcc/config/i386/linux-common.h
@@ -30,9 +30,6 @@ along with GCC; see the file COPYING3.  If not see
 #define EXTRA_TARGET_D_OS_VERSIONS()		\
   ANDROID_TARGET_D_OS_VERSIONS();
 
-#define GNU_USER_TARGET_D_CRITSEC_SIZE		\
-  (TARGET_64BIT ? (POINTER_SIZE == 64 ? 40 : 32) : 24)
-
 #undef CC1_SPEC
 #define CC1_SPEC \
   LINUX_OR_ANDROID_CC (GNU_USER_TARGET_CC1_SPEC, \
diff --git a/gcc/config/sol2-d.c b/gcc/config/sol2-d.c
index 73ca78698b2..27068f83082 100644
--- a/gcc/config/sol2-d.c
+++ b/gcc/config/sol2-d.c
@@ -33,19 +33,7 @@ solaris_d_os_builtins (void)
   d_add_builtin_version ("Solaris");			\
 }
 
-/* Implement TARGET_D_CRITSEC_SIZE for Solaris targets.  */
-
-static unsigned
-solaris_d_critsec_size (void)
-{
-  /* This is the sizeof pthread_mutex_t.  */
-  return 24;
-}
-
 #undef TARGET_D_OS_VERSIONS
 #define TARGET_D_OS_VERSIONS solaris_d_os_builtins
 
-#undef TARGET_D_CRITSEC_SIZE
-#define TARGET_D_CRITSEC_SIZE solaris_d_critsec_size
-
 struct gcc_targetdm targetdm = TARGETDM_INITIALIZER;
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index 78f14203b5c..692fce6a655 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -202,16 +202,6 @@ Target::fieldalign (Type *type)
   return align / BITS_PER_UNIT;
 }
 
-/* Return size of OS critical section.
-   Can't use the sizeof () calls directly since cross compiling is supported
-   and would end up using the host sizes rather than the target sizes.  */
-
-unsigned
-Target::critsecsize (void)
-{
-  return targetdm.d_critsec_size ();
-}
-
 /* Returns a Type for the va_list type of the target.  */
 
 Type *
diff --git a/gcc/d/d-target.def b/gcc/d/d-target.def
index d641c743429..41b31723188 100644
--- a/gcc/d/d-target.def
+++ b/gcc/d/d-target.def
@@ -46,15 +46,5 @@ relating to the target operating system.",
  void, (void),
  hook_void_void)
 
-/* The sizeof CRITICAL_SECTION or pthread_mutex_t.  */
-DEFHOOK
-(d_critsec_size,
- "Returns the size of the data structure used by the target operating system\n\
-for critical sections and monitors.  For example, on Microsoft Windows this\n\
-would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that\n\
-implement pthreads would return @code{sizeof(pthread_mutex_t)}.",
- unsigned, (void),
- hook_uint_void_0)
-
 /* Close the 'struct gcc_targetdm' definition.  */
 HOOK_VECTOR_END (C90_EMPTY_HACK)
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 7b561e4044e..39e424f2a98 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-0fcdaab32c7645820820f6e1474343ccfb7560e5
+bec5973b0203c95adbda2a049ccdf3cd3a4378f6
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
index 2944a79af2a..a6267c515de 100644
--- a/gcc/d/dmd/idgen.c
+++ b/gcc/d/dmd/idgen.c
@@ -262,7 +262,7 @@ Msgtable msgtable[] =
     { "aaRehash", "_aaRehash" },
     { "monitorenter", "_d_monitorenter" },
     { "monitorexit", "_d_monitorexit" },
-    { "criticalenter", "_d_criticalenter" },
+    { "criticalenter", "_d_criticalenter2" },
     { "criticalexit", "_d_criticalexit" },
     { "__ArrayEq", NULL },
     { "__ArrayPostblit", NULL },
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 42f885d4175..4ff07f6f2eb 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -3213,14 +3213,15 @@ public:
         else
         {
             /* Generate our own critical section, then rewrite as:
-             *  __gshared byte[CriticalSection.sizeof] critsec;
-             *  _d_criticalenter(critsec.ptr);
-             *  try { body } finally { _d_criticalexit(critsec.ptr); }
+             *  __gshared void* __critsec;
+             *  _d_criticalenter2(&__critsec);
+             *  try { body } finally { _d_criticalexit(__critsec); }
              */
             Identifier *id = Identifier::generateId("__critsec");
-            Type *t = Type::tint8->sarrayOf(target.ptrsize + target.critsecsize());
+            Type *t = Type::tvoidptr;
             VarDeclaration *tmp = new VarDeclaration(ss->loc, t, id, NULL);
             tmp->storage_class |= STCtemp | STCgshared | STCstatic;
+            Expression *tmpExp = new VarExp(ss->loc, tmp);
 
             Statements *cs = new Statements();
             cs->push(new ExpStatement(ss->loc, tmp));
@@ -3236,15 +3237,14 @@ public:
             args->push(new Parameter(0, t->pointerTo(), NULL, NULL));
 
             FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
-            Expression *e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
+            Expression *e = new AddrExp(ss->loc, tmpExp);
             e = semantic(e, sc);
             e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
             e->type = Type::tvoid;                  // do not run semantic on e
             cs->push(new ExpStatement(ss->loc, e));
 
             FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
-            e = new DotIdExp(ss->loc, new VarExp(ss->loc, tmp), Id::ptr);
-            e = semantic(e, sc);
+            e = semantic(tmpExp, sc);
             e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
             e->type = Type::tvoid;                  // do not run semantic on e
             Statement *s = new ExpStatement(ss->loc, e);
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index d76a9f89abd..c34826af304 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -28,7 +28,6 @@ struct TargetC
 {
     unsigned longsize;            // size of a C 'long' or 'unsigned long' type
     unsigned long_doublesize;     // size of a C 'long double'
-    unsigned criticalSectionSize; // size of os critical section
 };
 
 struct TargetCPP
@@ -98,7 +97,6 @@ public:
     // Type sizes and support.
     unsigned alignsize(Type *type);
     unsigned fieldalign(Type *type);
-    unsigned critsecsize();
     Type *va_listType(const Loc &loc, Scope *sc);  // get type of va_list
     int isVectorTypeSupported(int sz, Type *type);
     bool isVectorOpSupported(Type *type, TOK op, Type *t2 = NULL);
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 97437e8274f..24c37f655c8 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -10817,13 +10817,6 @@ Similarly to @code{TARGET_D_CPU_VERSIONS}, but is used for versions
 relating to the target operating system.
 @end deftypefn
 
-@deftypefn {D Target Hook} unsigned TARGET_D_CRITSEC_SIZE (void)
-Returns the size of the data structure used by the target operating system
-for critical sections and monitors.  For example, on Microsoft Windows this
-would return the @code{sizeof(CRITICAL_SECTION)}, while other platforms that
-implement pthreads would return @code{sizeof(pthread_mutex_t)}.
-@end deftypefn
-
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 412e22c89ab..2b8d29f235a 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -7351,8 +7351,6 @@ floating-point support; they are not included in this mechanism.
 
 @hook TARGET_D_OS_VERSIONS
 
-@hook TARGET_D_CRITSEC_SIZE
-
 @node Named Address Spaces
 @section Adding support for named address spaces
 @cindex named address spaces
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index bcde10514ec..485f8e999d6 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-d05ebaad15fbffce6d707c138c84d7b60fcf5ffd
+58560d5163381b0f1c893bd0d035b7a0a1631f92
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/rt/critical_.d b/libphobos/libdruntime/rt/critical_.d
index c2ef8220901..40030ad35b8 100644
--- a/libphobos/libdruntime/rt/critical_.d
+++ b/libphobos/libdruntime/rt/critical_.d
@@ -31,12 +31,30 @@ extern (C) void _d_critical_term()
 
 extern (C) void _d_criticalenter(D_CRITICAL_SECTION* cs)
 {
+    assert(cs !is null);
     ensureMutex(cast(shared(D_CRITICAL_SECTION*)) cs);
     lockMutex(&cs.mtx);
 }
 
+extern (C) void _d_criticalenter2(D_CRITICAL_SECTION** pcs)
+{
+    if (atomicLoad!(MemoryOrder.acq)(*cast(shared) pcs) is null)
+    {
+        lockMutex(cast(Mutex*)&gcs.mtx);
+        if (atomicLoad!(MemoryOrder.raw)(*cast(shared) pcs) is null)
+        {
+            auto cs = new shared D_CRITICAL_SECTION;
+            initMutex(cast(Mutex*)&cs.mtx);
+            atomicStore!(MemoryOrder.rel)(*cast(shared) pcs, cs);
+        }
+        unlockMutex(cast(Mutex*)&gcs.mtx);
+    }
+    lockMutex(&(*pcs).mtx);
+}
+
 extern (C) void _d_criticalexit(D_CRITICAL_SECTION* cs)
 {
+    assert(cs !is null);
     unlockMutex(&cs.mtx);
 }
 
