diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -40,6 +40,10 @@ C/C++ Language Potentially Breaking Changes ------------------------------------------- +- The definition of ``USHRT_MAX`` in the freestanding ``<limits.h>`` no longer + overflows on AVR (where ``sizeof(unsigned int) == sizeof(unsigned short)``). + The type of ``USHRT_MAX`` on AVR is now ``unsigned int`` instead of ``int``, + as required by the C standard. C++ Specific Potentially Breaking Changes ----------------------------------------- diff --git a/clang/lib/Headers/limits.h b/clang/lib/Headers/limits.h --- a/clang/lib/Headers/limits.h +++ b/clang/lib/Headers/limits.h @@ -52,7 +52,10 @@ #define LONG_MIN (-__LONG_MAX__ -1L) #define UCHAR_MAX (__SCHAR_MAX__*2 +1) -#define USHRT_MAX (__SHRT_MAX__ *2 +1) +/* This isn't safe to compute in type int on 16-bit int platforms, so compute it + * in unsigned int, cast to unsigned short, and perform the regular integer + * promotion via unary plus. */ +#define USHRT_MAX (+(unsigned short)(__SHRT_MAX__ * 2U + 1U)) #define UINT_MAX (__INT_MAX__ *2U +1U) #define ULONG_MAX (__LONG_MAX__ *2UL+1UL) diff --git a/clang/test/Headers/limits.cpp b/clang/test/Headers/limits.cpp --- a/clang/test/Headers/limits.cpp +++ b/clang/test/Headers/limits.cpp @@ -3,6 +3,10 @@ // RUN: %clang_cc1 -std=c++11 -ffreestanding -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c17 -ffreestanding -fsyntax-only -verify -x c %s // RUN: %clang_cc1 -std=c2x -ffreestanding -fsyntax-only -verify -x c %s + +// Specifically test 16-bit int platforms. +// RUN: %clang_cc1 -triple=avr -ffreestanding -fsyntax-only -verify -x c %s + // expected-no-diagnostics #include <limits.h> @@ -24,6 +28,16 @@ _Static_assert(UCHAR_MAX == (unsigned char)~0ULL, ""); _Static_assert(USHRT_MAX == (unsigned short)~0ULL, ""); + +#if __cplusplus +#define EXPR_TYPE_IS(EXPR, TYP) __is_same(__typeof(EXPR), TYP) +#else +#define EXPR_TYPE_IS(EXPR, TYP) _Generic(EXPR, TYP: 1, default: 0) +#endif +_Static_assert(USHRT_MAX <= INT_MAX ? + EXPR_TYPE_IS(USHRT_MAX, int) : + EXPR_TYPE_IS(USHRT_MAX, unsigned int), ""); + _Static_assert(UINT_MAX == (unsigned int)~0ULL, ""); _Static_assert(ULONG_MAX == (unsigned long)~0ULL, "");