diff -urN a/ChangeLog b/ChangeLog
--- a/ChangeLog	2017-08-02 07:57:16.000000000 -0500
+++ b/ChangeLog	2017-11-14 10:44:33.367788400 -0500
@@ -1,3 +1,13 @@
+2017-11-14  Paul Carroll  <pcarroll@codesourcery.com>
+
+	[BZ #21513]
+	* sysdeps/nptl/pthread.h (pthread_cleanup_push): Added 'volatile'
+	to __cancel_routine and __cancel_arg definitions.
+	* sysdeps/unix/sysv/linux/hppa/pthread.h (pthread_cleanup_push): Added
+	'volatile' to __cancel_routine and __cancel_arg definitions.
+	* nptl/Makefile (tests): Add tst-clobbered.c.
+	* nptl/tst-clobbered.c: New file.
+
 2017-08-02  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
 	* version.h (RELEASE): Set to "stable"
diff -urN a/nptl/Makefile b/nptl/Makefile
--- a/nptl/Makefile	2017-08-02 07:57:16.000000000 -0500
+++ b/nptl/Makefile	2017-11-14 10:44:12.211757900 -0500
@@ -302,7 +302,8 @@
 			    c89 gnu89 c99 gnu99 c11 gnu11) \
 	tst-bad-schedattr \
 	tst-thread_local1 tst-mutex-errorcheck tst-robust10 \
-	tst-robust-fork tst-create-detached tst-memstream
+	tst-robust-fork tst-create-detached tst-memstream \
+	tst-clobbered
 
 tests-internal := tst-typesizes \
 		  tst-rwlock19 tst-rwlock20 \
diff -urN a/nptl/tst-clobbered.c b/nptl/tst-clobbered.c
--- a/nptl/tst-clobbered.c	1969-12-31 19:00:00.000000000 -0500
+++ b/nptl/tst-clobbered.c	2017-11-14 10:45:50.376896700 -0500
@@ -0,0 +1,39 @@
+#include <pthread.h>
+#pragma GCC diagnostic error "-Wclobbered"
+
+#include <stdlib.h>
+
+void cleanup_fn(void *mutex)
+{
+}
+
+typedef struct {
+  size_t progress;
+  size_t total;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  double min_wait;
+} dmnsn_future;
+
+void
+dmnsn_future_wait(dmnsn_future *future, double progress)
+{
+  pthread_mutex_lock(&future->mutex);
+  while ((double)future->progress/future->total < progress) {
+    /* Warning goes away without this block */
+    if (progress < future->min_wait) {
+      future->min_wait = progress;
+    }
+
+    pthread_cleanup_push(cleanup_fn, &future->mutex);
+    pthread_cond_wait(&future->cond, &future->mutex);
+    pthread_cleanup_pop(0);
+  }
+  pthread_mutex_unlock(&future->mutex);
+}
+
+int
+main(int argc, char *argv[])
+{
+  exit(0);
+}
diff -urN a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
--- a/sysdeps/nptl/pthread.h	2017-08-02 07:57:16.000000000 -0500
+++ b/sysdeps/nptl/pthread.h	2017-11-14 10:48:12.943097200 -0500
@@ -665,8 +665,8 @@
 # define pthread_cleanup_push(routine, arg) \
   do {									      \
     __pthread_unwind_buf_t __cancel_buf;				      \
-    void (*__cancel_routine) (void *) = (routine);			      \
-    void *__cancel_arg = (arg);						      \
+    void (* volatile __cancel_routine) (void *) = (routine);		      \
+    void * volatile __cancel_arg = (arg);				      \
     int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
 					__cancel_buf.__cancel_jmp_buf, 0);    \
     if (__glibc_unlikely (__not_first_call))				      \
@@ -700,8 +700,8 @@
 #  define pthread_cleanup_push_defer_np(routine, arg) \
   do {									      \
     __pthread_unwind_buf_t __cancel_buf;				      \
-    void (*__cancel_routine) (void *) = (routine);			      \
-    void *__cancel_arg = (arg);						      \
+    void (* volatile __cancel_routine) (void *) = (routine);		      \
+    void * volatile __cancel_arg = (arg);				      \
     int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
 					__cancel_buf.__cancel_jmp_buf, 0);    \
     if (__glibc_unlikely (__not_first_call))				      \
diff -urN a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
--- a/sysdeps/unix/sysv/linux/hppa/pthread.h	2017-08-02 07:57:16.000000000 -0500
+++ b/sysdeps/unix/sysv/linux/hppa/pthread.h	2017-11-14 10:50:03.305252400 -0500
@@ -641,8 +641,8 @@
 # define pthread_cleanup_push(routine, arg) \
   do {									      \
     __pthread_unwind_buf_t __cancel_buf;				      \
-    void (*__cancel_routine) (void *) = (routine);			      \
-    void *__cancel_arg = (arg);						      \
+    void (* volatile __cancel_routine) (void *) = (routine);		      \
+    void * volatile __cancel_arg = (arg);				      \
     int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
 					__cancel_buf.__cancel_jmp_buf, 0);    \
     if (__glibc_unlikely (__not_first_call))				      \
@@ -676,8 +676,8 @@
 #  define pthread_cleanup_push_defer_np(routine, arg) \
   do {									      \
     __pthread_unwind_buf_t __cancel_buf;				      \
-    void (*__cancel_routine) (void *) = (routine);			      \
-    void *__cancel_arg = (arg);						      \
+    void (* volatile __cancel_routine) (void *) = (routine);		      \
+    void * volatile __cancel_arg = (arg);				      \
     int __not_first_call = __sigsetjmp ((struct __jmp_buf_tag *) (void *)     \
 					__cancel_buf.__cancel_jmp_buf, 0);    \
     if (__glibc_unlikely (__not_first_call))				      \
