linux-user: Suppress address-of-packed-member warnings in __get/put_user_e
diff mbox series

Message ID 20180928142533.8451-1-peter.maydell@linaro.org
State New
Headers show
Series
  • linux-user: Suppress address-of-packed-member warnings in __get/put_user_e
Related show

Commit Message

Peter Maydell Sept. 28, 2018, 2:25 p.m. UTC
Our __get_user_e() and __put_user_e() macros cause newer versions
of clang to generate false-positive -Waddress-of-packed-member
warnings if they are passed the address of a member of a packed
struct (see https://bugs.llvm.org/show_bug.cgi?id=39113).
Suppress these using the _Pragma() operator.

To put in the pragmas we need to convert the macros from
expressions to statements, but all the callsites effectively
treat them as statements already so this is OK.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/qemu.h | 57 +++++++++++++++++++++++++++++++----------------
 1 file changed, 38 insertions(+), 19 deletions(-)

Comments

Laurent Vivier Sept. 28, 2018, 2:51 p.m. UTC | #1
Le 28/09/2018 à 16:25, Peter Maydell a écrit :
> Our __get_user_e() and __put_user_e() macros cause newer versions
> of clang to generate false-positive -Waddress-of-packed-member
> warnings if they are passed the address of a member of a packed
> struct (see https://bugs.llvm.org/show_bug.cgi?id=39113).
> Suppress these using the _Pragma() operator.
> 
> To put in the pragmas we need to convert the macros from
> expressions to statements, but all the callsites effectively
> treat them as statements already so this is OK.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/qemu.h | 57 +++++++++++++++++++++++++++++++----------------
>  1 file changed, 38 insertions(+), 19 deletions(-)
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Liam Merwick Sept. 28, 2018, 3:16 p.m. UTC | #2
On 28/09/18 15:25, Peter Maydell wrote:
> Our __get_user_e() and __put_user_e() macros cause newer versions
> of clang to generate false-positive -Waddress-of-packed-member
> warnings if they are passed the address of a member of a packed
> struct (see https://bugs.llvm.org/show_bug.cgi?id=39113).
> Suppress these using the _Pragma() operator.
>
> To put in the pragmas we need to convert the macros from
> expressions to statements, but all the callsites effectively
> treat them as statements already so this is OK.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Liam Merwick <liam.merwick@oracle.com>

> ---
>   linux-user/qemu.h | 57 +++++++++++++++++++++++++++++++----------------
>   1 file changed, 38 insertions(+), 19 deletions(-)
>
> diff --git a/linux-user/qemu.h b/linux-user/qemu.h
> index b4959e41c6e..56c4f2d5374 100644
> --- a/linux-user/qemu.h
> +++ b/linux-user/qemu.h
> @@ -461,27 +461,46 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
>      These are usually used to access struct data members once the struct has
>      been locked - usually with lock_user_struct.  */
>   
> -/* Tricky points:
> -   - Use __builtin_choose_expr to avoid type promotion from ?:,
> -   - Invalid sizes result in a compile time error stemming from
> -     the fact that abort has no parameters.
> -   - It's easier to use the endian-specific unaligned load/store
> -     functions than host-endian unaligned load/store plus tswapN.  */
> +/*
> + * Tricky points:
> + * - Use __builtin_choose_expr to avoid type promotion from ?:,
> + * - Invalid sizes result in a compile time error stemming from
> + *   the fact that abort has no parameters.
> + * - It's easier to use the endian-specific unaligned load/store
> + *   functions than host-endian unaligned load/store plus tswapN.
> + * - The pragmas are necessary only to silence a clang false-positive
> + *   warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 .
> + * - We have to disable -Wpragmas warnings to avoid a complaint about
> + *   an unknown warning type from older compilers that don't know about
> + *   -Waddress-of-packed-member.
> + */
> +#define __put_user_e(x, hptr, e)                                            \
> +    do {                                                                    \
> +        _Pragma("GCC diagnostic push");                                     \
> +        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
> +        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
> +        (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                 \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,            \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p,            \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort))))  \
> +            ((hptr), (x)), (void)0);                                        \
> +        _Pragma("GCC diagnostic pop");                                      \
> +    } while (0)
>   
> -#define __put_user_e(x, hptr, e)                                        \
> -  (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                   \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,             \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p,             \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort))))   \
> -     ((hptr), (x)), (void)0)
> +#define __get_user_e(x, hptr, e)                                            \
> +    do {                                                                    \
> +        _Pragma("GCC diagnostic push");                                     \
> +        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
> +        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
> +        ((x) = (typeof(*hptr))(                                             \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                 \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p,           \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p,            \
> +        __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort))))  \
> +            (hptr)), (void)0);                                              \
> +        _Pragma("GCC diagnostic pop");                                      \
> +    } while (0)
>   
> -#define __get_user_e(x, hptr, e)                                        \
> -  ((x) = (typeof(*hptr))(                                               \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                  \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p,            \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p,             \
> -   __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort))))   \
> -     (hptr)), (void)0)
>   
>   #ifdef TARGET_WORDS_BIGENDIAN
>   # define __put_user(x, hptr)  __put_user_e(x, hptr, be)
Laurent Vivier Oct. 4, 2018, 4:55 p.m. UTC | #3
Le 28/09/2018 à 16:25, Peter Maydell a écrit :
> Our __get_user_e() and __put_user_e() macros cause newer versions
> of clang to generate false-positive -Waddress-of-packed-member
> warnings if they are passed the address of a member of a packed
> struct (see https://bugs.llvm.org/show_bug.cgi?id=39113).
> Suppress these using the _Pragma() operator.
> 
> To put in the pragmas we need to convert the macros from
> expressions to statements, but all the callsites effectively
> treat them as statements already so this is OK.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/qemu.h | 57 +++++++++++++++++++++++++++++++----------------
>  1 file changed, 38 insertions(+), 19 deletions(-)
> 

Applied to my linux-user branch.

Thanks,
Laurent
Laurent Vivier Oct. 5, 2018, 12:28 a.m. UTC | #4
On 04/10/2018 18:55, Laurent Vivier wrote:
> Le 28/09/2018 à 16:25, Peter Maydell a écrit :
>> Our __get_user_e() and __put_user_e() macros cause newer versions
>> of clang to generate false-positive -Waddress-of-packed-member
>> warnings if they are passed the address of a member of a packed
>> struct (see https://bugs.llvm.org/show_bug.cgi?id=39113).
>> Suppress these using the _Pragma() operator.
>>
>> To put in the pragmas we need to convert the macros from
>> expressions to statements, but all the callsites effectively
>> treat them as statements already so this is OK.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  linux-user/qemu.h | 57 +++++++++++++++++++++++++++++++----------------
>>  1 file changed, 38 insertions(+), 19 deletions(-)
>>
> 
> Applied to my linux-user branch.

I have the following error when building on Fedora 28 and gcc (GCC)
8.1.1 20180712 (Red Hat 8.1.1-5)

  CC      aarch64_be-linux-user/target/arm/arm-semi.o
.../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
.../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
GCC diagnostic’ kind [-Werror=pragmas]

Perhaps you should use a "#if defined(__clang__)" to apply your fix only
to clang?

Thanks,
Laurent
Peter Maydell Oct. 5, 2018, 9:10 a.m. UTC | #5
On 5 October 2018 at 01:28, Laurent Vivier <laurent@vivier.eu> wrote:
> I have the following error when building on Fedora 28 and gcc (GCC)
> 8.1.1 20180712 (Red Hat 8.1.1-5)
>
>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
> .../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
> .../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
> GCC diagnostic’ kind [-Werror=pragmas]
>
> Perhaps you should use a "#if defined(__clang__)" to apply your fix only
> to clang?

I did test on gcc, but not that version. The point of the
   _Pragma("GCC diagnostic ignored \"-Wpragmas\"");
line is to suppress that error (which it does on my gcc 5)
so I don't know why your gcc is complaining :-(

If you add an extra diagnostic push, so:

+        _Pragma("GCC diagnostic push");                                     \
+        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
+        _Pragma("GCC diagnostic push");                                     \
+        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \

and then a balancing extra

+        _Pragma("GCC diagnostic pop");                                      \

at the end, I don't suppose that helps?

(I generally prefer to avoid marking things as clang- or gcc-
specific where I can.)

thanks
-- PMM
Laurent Vivier Oct. 5, 2018, 9:43 a.m. UTC | #6
On 05/10/2018 11:10, Peter Maydell wrote:
> On 5 October 2018 at 01:28, Laurent Vivier <laurent@vivier.eu> wrote:
>> I have the following error when building on Fedora 28 and gcc (GCC)
>> 8.1.1 20180712 (Red Hat 8.1.1-5)
>>
>>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
>> .../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
>> .../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
>> GCC diagnostic’ kind [-Werror=pragmas]
>>
>> Perhaps you should use a "#if defined(__clang__)" to apply your fix only
>> to clang?
> 
> I did test on gcc, but not that version. The point of the
>    _Pragma("GCC diagnostic ignored \"-Wpragmas\"");
> line is to suppress that error (which it does on my gcc 5)
> so I don't know why your gcc is complaining :-(

You should add Fedora 28 to you collection of virtual machines :)

> 
> If you add an extra diagnostic push, so:
> 
> +        _Pragma("GCC diagnostic push");                                     \
> +        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
> +        _Pragma("GCC diagnostic push");                                     \
> +        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
> 
> and then a balancing extra
> 
> +        _Pragma("GCC diagnostic pop");                                      \
> 
> at the end, I don't suppose that helps?

No, it doesn't help

> (I generally prefer to avoid marking things as clang- or gcc-
> specific where I can.)

I understand.
But it's a clang bug, it seems reasonable to have specific code to
workaround it.

Thanks,
Laurent
Richard Henderson Oct. 5, 2018, 3:25 p.m. UTC | #7
On 10/5/18 4:10 AM, Peter Maydell wrote:
> On 5 October 2018 at 01:28, Laurent Vivier <laurent@vivier.eu> wrote:
>> I have the following error when building on Fedora 28 and gcc (GCC)
>> 8.1.1 20180712 (Red Hat 8.1.1-5)
>>
>>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
>> .../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
>> .../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
>> GCC diagnostic’ kind [-Werror=pragmas]
>>
>> Perhaps you should use a "#if defined(__clang__)" to apply your fix only
>> to clang?
> 
> I did test on gcc, but not that version. The point of the
>    _Pragma("GCC diagnostic ignored \"-Wpragmas\"");
> line is to suppress that error (which it does on my gcc 5)
> so I don't know why your gcc is complaining :-(

I suppose you could try -Wunknown-pragmas.
But from reading the manual it shouldn't make a difference.
OTOH, what you wrote should have worked...


r~
Laurent Vivier Oct. 5, 2018, 4:09 p.m. UTC | #8
On 05/10/2018 17:25, Richard Henderson wrote:
> On 10/5/18 4:10 AM, Peter Maydell wrote:
>> On 5 October 2018 at 01:28, Laurent Vivier <laurent@vivier.eu> wrote:
>>> I have the following error when building on Fedora 28 and gcc (GCC)
>>> 8.1.1 20180712 (Red Hat 8.1.1-5)
>>>
>>>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
>>> .../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
>>> .../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
>>> GCC diagnostic’ kind [-Werror=pragmas]
>>>
>>> Perhaps you should use a "#if defined(__clang__)" to apply your fix only
>>> to clang?
>>
>> I did test on gcc, but not that version. The point of the
>>    _Pragma("GCC diagnostic ignored \"-Wpragmas\"");
>> line is to suppress that error (which it does on my gcc 5)
>> so I don't know why your gcc is complaining :-(
> 
> I suppose you could try -Wunknown-pragmas.
> But from reading the manual it shouldn't make a difference.
> OTOH, what you wrote should have worked...

Could it be a bug in _Pragma()?

If I use "#pragma" for the file, it works:

--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -474,10 +474,10 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
  *   an unknown warning type from older compilers that don't know about
  *   -Waddress-of-packed-member.
  */
+#pragma GCC diagnostic ignored "-Wpragmas"
 #define __put_user_e(x, hptr, e)                                            \
     do {                                                                    \
         _Pragma("GCC diagnostic push");                                     \
-        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
         _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
         (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                 \
         __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,            \
@@ -490,7 +490,6 @@ static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
 #define __get_user_e(x, hptr, e)                                            \
     do {                                                                    \
         _Pragma("GCC diagnostic push");                                     \
-        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
         _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
         ((x) = (typeof(*hptr))(                                             \
         __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                 \
Peter Maydell Oct. 9, 2018, 11:59 a.m. UTC | #9
On 5 October 2018 at 17:09, Laurent Vivier <laurent@vivier.eu> wrote:
> On 05/10/2018 17:25, Richard Henderson wrote:
>> On 10/5/18 4:10 AM, Peter Maydell wrote:
>>> On 5 October 2018 at 01:28, Laurent Vivier <laurent@vivier.eu> wrote:
>>>> I have the following error when building on Fedora 28 and gcc (GCC)
>>>> 8.1.1 20180712 (Red Hat 8.1.1-5)
>>>>
>>>>   CC      aarch64_be-linux-user/target/arm/arm-semi.o
>>>> .../target/arm/arm-semi.c: In function ‘do_arm_semihosting’:
>>>> .../target/arm/arm-semi.c:270:1: error: unknown option after ‘#pragma
>>>> GCC diagnostic’ kind [-Werror=pragmas]
>>>>
>>>> Perhaps you should use a "#if defined(__clang__)" to apply your fix only
>>>> to clang?
>>>
>>> I did test on gcc, but not that version. The point of the
>>>    _Pragma("GCC diagnostic ignored \"-Wpragmas\"");
>>> line is to suppress that error (which it does on my gcc 5)
>>> so I don't know why your gcc is complaining :-(
>>
>> I suppose you could try -Wunknown-pragmas.
>> But from reading the manual it shouldn't make a difference.
>> OTOH, what you wrote should have worked...
>
> Could it be a bug in _Pragma()?

I got an f28 VM and can repro this. It looks like the problem
only happens when the get_user/put_user stuff is used via some
other macro, for some reason -- so the GET_ARG and SET_ARG
macros in arm-semi.c and the NEW_AUX_ENT macro in elfload.c
cause problems, but less indirect use does not. I'll try to
trim this down to a smaller test case somehow...

thanks
-- PMM
Peter Maydell Oct. 9, 2018, 2:52 p.m. UTC | #10
On 9 October 2018 at 12:59, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 5 October 2018 at 17:09, Laurent Vivier <laurent@vivier.eu> wrote:
>> Could it be a bug in _Pragma()?
>
> I got an f28 VM and can repro this. It looks like the problem
> only happens when the get_user/put_user stuff is used via some
> other macro, for some reason -- so the GET_ARG and SET_ARG
> macros in arm-semi.c and the NEW_AUX_ENT macro in elfload.c
> cause problems, but less indirect use does not. I'll try to
> trim this down to a smaller test case somehow...

I think it is a bug in _Pragma(). I boiled it down to a
small test case, and tested using the compilers on godbolt.org.
The test fails with gcc 5, 6, 7 and 8 but works on 4 and on
gcc trunk.

Trying to use _Pragma() inside a macro to disable warnings
seems to be pretty broken. The GCC bugzilla has:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85153
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69558
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82335
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543

which are various bug reports in this area, with test cases
which variously are fixed in gcc 8, or fixed not in 8 but
in trunk, or still broken in trunk. So there isn't a single
bug here but a cluster of similar ones.

I think the underlying difficulty is that the compiler decides
whether to suppress the warning by looking at the source location
for the warning, and at the source locations of the various
pragmas, and especially when macro expansion is involved the
"source location" can be harder to correctly identify.

I'm not sure if there is some "safe" subset of _Pragma()-in-macro
use here that will work regardless of compiler version, or if
we should just give up on it as non-feasible and try to silence
the warnings some other way.

Looks like clang is not flawless in this area either:
https://bugs.llvm.org/show_bug.cgi?id=31999
https://bugs.llvm.org/show_bug.cgi?id=15129
https://bugs.llvm.org/show_bug.cgi?id=35154

thanks
-- PMM
Laurent Vivier Oct. 9, 2018, 2:57 p.m. UTC | #11
Le 09/10/2018 à 16:52, Peter Maydell a écrit :
> On 9 October 2018 at 12:59, Peter Maydell <peter.maydell@linaro.org> wrote:
>> On 5 October 2018 at 17:09, Laurent Vivier <laurent@vivier.eu> wrote:
>>> Could it be a bug in _Pragma()?
>>
>> I got an f28 VM and can repro this. It looks like the problem
>> only happens when the get_user/put_user stuff is used via some
>> other macro, for some reason -- so the GET_ARG and SET_ARG
>> macros in arm-semi.c and the NEW_AUX_ENT macro in elfload.c
>> cause problems, but less indirect use does not. I'll try to
>> trim this down to a smaller test case somehow...
> 
> I think it is a bug in _Pragma(). I boiled it down to a
> small test case, and tested using the compilers on godbolt.org.
> The test fails with gcc 5, 6, 7 and 8 but works on 4 and on
> gcc trunk.
> 
> Trying to use _Pragma() inside a macro to disable warnings
> seems to be pretty broken. The GCC bugzilla has:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85153
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69558
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82335
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66099
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543
> 
> which are various bug reports in this area, with test cases
> which variously are fixed in gcc 8, or fixed not in 8 but
> in trunk, or still broken in trunk. So there isn't a single
> bug here but a cluster of similar ones.
> 
> I think the underlying difficulty is that the compiler decides
> whether to suppress the warning by looking at the source location
> for the warning, and at the source locations of the various
> pragmas, and especially when macro expansion is involved the
> "source location" can be harder to correctly identify.
> 
> I'm not sure if there is some "safe" subset of _Pragma()-in-macro
> use here that will work regardless of compiler version, or if
> we should just give up on it as non-feasible and try to silence
> the warnings some other way.

To keep it simple, and as I have suggested before, perhaps you can use
only the _Pragma() we need to workaround clang bug with clang (#ifde
__clang__)?

Thanks,
Laurent

Patch
diff mbox series

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index b4959e41c6e..56c4f2d5374 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -461,27 +461,46 @@  static inline int access_ok(int type, abi_ulong addr, abi_ulong size)
    These are usually used to access struct data members once the struct has
    been locked - usually with lock_user_struct.  */
 
-/* Tricky points:
-   - Use __builtin_choose_expr to avoid type promotion from ?:,
-   - Invalid sizes result in a compile time error stemming from
-     the fact that abort has no parameters.
-   - It's easier to use the endian-specific unaligned load/store
-     functions than host-endian unaligned load/store plus tswapN.  */
+/*
+ * Tricky points:
+ * - Use __builtin_choose_expr to avoid type promotion from ?:,
+ * - Invalid sizes result in a compile time error stemming from
+ *   the fact that abort has no parameters.
+ * - It's easier to use the endian-specific unaligned load/store
+ *   functions than host-endian unaligned load/store plus tswapN.
+ * - The pragmas are necessary only to silence a clang false-positive
+ *   warning: see https://bugs.llvm.org/show_bug.cgi?id=39113 .
+ * - We have to disable -Wpragmas warnings to avoid a complaint about
+ *   an unknown warning type from older compilers that don't know about
+ *   -Waddress-of-packed-member.
+ */
+#define __put_user_e(x, hptr, e)                                            \
+    do {                                                                    \
+        _Pragma("GCC diagnostic push");                                     \
+        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
+        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
+        (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                 \
+        __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,            \
+        __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p,            \
+        __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort))))  \
+            ((hptr), (x)), (void)0);                                        \
+        _Pragma("GCC diagnostic pop");                                      \
+    } while (0)
 
-#define __put_user_e(x, hptr, e)                                        \
-  (__builtin_choose_expr(sizeof(*(hptr)) == 1, stb_p,                   \
-   __builtin_choose_expr(sizeof(*(hptr)) == 2, stw_##e##_p,             \
-   __builtin_choose_expr(sizeof(*(hptr)) == 4, stl_##e##_p,             \
-   __builtin_choose_expr(sizeof(*(hptr)) == 8, stq_##e##_p, abort))))   \
-     ((hptr), (x)), (void)0)
+#define __get_user_e(x, hptr, e)                                            \
+    do {                                                                    \
+        _Pragma("GCC diagnostic push");                                     \
+        _Pragma("GCC diagnostic ignored \"-Wpragmas\"");                    \
+        _Pragma("GCC diagnostic ignored \"-Waddress-of-packed-member\"");   \
+        ((x) = (typeof(*hptr))(                                             \
+        __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                 \
+        __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p,           \
+        __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p,            \
+        __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort))))  \
+            (hptr)), (void)0);                                              \
+        _Pragma("GCC diagnostic pop");                                      \
+    } while (0)
 
-#define __get_user_e(x, hptr, e)                                        \
-  ((x) = (typeof(*hptr))(                                               \
-   __builtin_choose_expr(sizeof(*(hptr)) == 1, ldub_p,                  \
-   __builtin_choose_expr(sizeof(*(hptr)) == 2, lduw_##e##_p,            \
-   __builtin_choose_expr(sizeof(*(hptr)) == 4, ldl_##e##_p,             \
-   __builtin_choose_expr(sizeof(*(hptr)) == 8, ldq_##e##_p, abort))))   \
-     (hptr)), (void)0)
 
 #ifdef TARGET_WORDS_BIGENDIAN
 # define __put_user(x, hptr)  __put_user_e(x, hptr, be)