diff options
author | Hubert Tong <hubert.reinterpretcast@gmail.com> | 2015-06-08 21:59:59 +0000 |
---|---|---|
committer | Hubert Tong <hubert.reinterpretcast@gmail.com> | 2015-06-08 21:59:59 +0000 |
commit | b15375b3f601242d233233ccf394b1af9834ce2d (patch) | |
tree | 165dadbe2429302305793d49e4a9ff0e06259689 | |
parent | e3d3ccf99349e3087f311f2b610bdadf6851272f (diff) |
Consider unsigned long for non-u/U decimal literals (C90/C++03)
Summary:
This modifies Clang to reflect that under pre-C99 ISO C, decimal
constants may have type `unsigned long` even if they do not contain `u`
or `U` in their suffix (C90 subclause 6.1.3.2 paragraph 5). The same is
done for C++ without C++11 which--because of undefined behaviour--allows
for behaviour compatible with ISO C90 in the case of an unsuffixed
decimal literal and is otherwise identical to C90 in its treatment of
integer literals (C++03 subclause 2.13.1 [lex.icon] paragraph 2).
Messages are added to the `c99-compat` and `c++11-compat` groups to warn
on such literals, since they behave differently under the newer
standards.
Fixes PR 16678.
Test Plan:
A new test file is added to exercise both pre-C99/C++11 and C99/C++11-up
on decimal literals with no suffix or suffixes `l`/`L` for both 32-bit
and 64-bit `long`.
In the file, 2^31 (being `INT_MAX+1`) is tested for the expected type
using `__typeof__` and multiple declarations of the same entity. 2^63
is similarly tested when it is within the range of `unsigned long`.
Preprocessor arithmetic tests are added to ensure consistency given
that Clang (like GCC) uses greater than 32 bits for preprocessor
arithmetic even when `long` and `unsigned long` is 32 bits and a
pre-C99/C++11 mode is in effect.
Tests added:
test/Sema/PR16678.c
Reviewers: fraggamuffin, rsmith
Reviewed By: rsmith
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D9794
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@239356 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticCommonKinds.td | 18 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 1 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 16 | ||||
-rw-r--r-- | test/Sema/PR16678.c | 153 |
4 files changed, 187 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index afdd9269d0..deb23f3149 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -115,7 +115,23 @@ def err_integer_literal_too_large : Error< def ext_integer_literal_too_large_for_signed : ExtWarn< "integer literal is too large to be represented in a signed integer type, " "interpreting as unsigned">, - InGroup<DiagGroup<"implicitly-unsigned-literal">>; + InGroup<ImplicitlyUnsignedLiteral>; +def warn_old_implicitly_unsigned_long : Warning< + "integer literal is too large to be represented in type 'long', " + "interpreting as 'unsigned long' per C89; this literal will " + "%select{have type 'long long'|be ill-formed}0 in C99 onwards">, + InGroup<C99Compat>; +def warn_old_implicitly_unsigned_long_cxx : Warning< + "integer literal is too large to be represented in type 'long', " + "interpreting as 'unsigned long' per C++98; this literal will " + "%select{have type 'long long'|be ill-formed}0 in C++11 onwards">, + InGroup<CXX11Compat>; +def ext_old_implicitly_unsigned_long_cxx : ExtWarn< + "integer literal is too large to be represented in type 'long' and is " + "subject to undefined behavior under C++98, interpreting as 'unsigned long'; " + "this literal will %select{have type 'long long'|be ill-formed}0 " + "in C++11 onwards">, + InGroup<CXX11Compat>; // SEH def err_seh_expected_handler : Error< diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index 61436eabe5..24ba839ebb 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -239,6 +239,7 @@ def MultiChar : DiagGroup<"multichar">; def : DiagGroup<"nested-externs">; def CXX11LongLong : DiagGroup<"c++11-long-long">; def LongLong : DiagGroup<"long-long", [CXX11LongLong]>; +def ImplicitlyUnsignedLiteral : DiagGroup<"implicitly-unsigned-literal">; def MethodSignatures : DiagGroup<"method-signatures">; def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index dfb17f4bbc..b0bc231e7e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -3425,6 +3425,22 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Ty = Context.LongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongTy; + // Check according to the rules of C90 6.1.3.2p5. C++03 [lex.icon]p2 + // is compatible. + else if (!getLangOpts().C99 && !getLangOpts().CPlusPlus11) { + const unsigned LongLongSize = + Context.getTargetInfo().getLongLongWidth(); + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus + ? Literal.isLong + ? diag::warn_old_implicitly_unsigned_long_cxx + : /*C++98 UB*/ diag:: + ext_old_implicitly_unsigned_long_cxx + : diag::warn_old_implicitly_unsigned_long) + << (LongLongSize > LongSize ? /*will have type 'long long'*/ 0 + : /*will be ill-formed*/ 1); + Ty = Context.UnsignedLongTy; + } Width = LongSize; } } diff --git a/test/Sema/PR16678.c b/test/Sema/PR16678.c new file mode 100644 index 0000000000..a06d0a98ba --- /dev/null +++ b/test/Sema/PR16678.c @@ -0,0 +1,153 @@ +// RUN: %clang_cc1 -DX32TYPE=ULONG -triple powerpc-unknown-linux-gnu -std=c89 -x c %s -verify +// RUN: %clang_cc1 -DX32TYPE=ULONG -triple powerpc-unknown-linux-gnu -std=iso9899:199409 -x c %s -verify +// RUN: %clang_cc1 -DX32TYPE=ULONG -triple powerpc-unknown-linux-gnu -std=c++98 -x c++ %s -verify +// RUN: %clang_cc1 -DX32TYPE=LLONG -triple powerpc-unknown-linux-gnu -std=c99 -x c %s -verify +// RUN: %clang_cc1 -DX32TYPE=LLONG -triple powerpc-unknown-linux-gnu -std=c11 -x c %s -verify +// RUN: %clang_cc1 -DX32TYPE=LLONG -triple powerpc-unknown-linux-gnu -std=c++11 -x c++ %s -verify +// RUN: %clang_cc1 -DX32TYPE=LLONG -triple powerpc-unknown-linux-gnu -std=c++1y -x c++ %s -verify +// RUN: %clang_cc1 -DX32TYPE=LLONG -triple powerpc-unknown-linux-gnu -std=c++1z -x c++ %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULONG -triple powerpc64-unknown-linux-gnu -std=c89 -x c %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULONG -triple powerpc64-unknown-linux-gnu -std=iso9899:199409 -x c %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULONG -triple powerpc64-unknown-linux-gnu -std=c++98 -x c++ %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULLONG -triple powerpc64-unknown-linux-gnu -std=c99 -x c %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULLONG -triple powerpc64-unknown-linux-gnu -std=c11 -x c %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULLONG -triple powerpc64-unknown-linux-gnu -std=c++11 -x c++ %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULLONG -triple powerpc64-unknown-linux-gnu -std=c++1y -x c++ %s -verify +// RUN: %clang_cc1 -DX64TYPE=ULLONG -triple powerpc64-unknown-linux-gnu -std=c++1z -x c++ %s -verify + +#ifdef X64TYPE +#define X32TYPE long +#endif + +#define IS_ULONG_ULONG 1 +#define IS_ULONG2(X) IS_ULONG_##X +#define IS_ULONG(X) IS_ULONG2(X) + +#if !defined(X64TYPE) && !IS_ULONG(X32TYPE) +// expected-no-diagnostics +#endif + +typedef unsigned long ULONG; +typedef long long LLONG; +typedef unsigned long long ULLONG; + + +/****************************************************************************** + * Test 2^31 as a decimal literal with no suffix and with the "l" and "L" cases. + ******************************************************************************/ +extern X32TYPE x32; +extern __typeof__(2147483648) x32; +extern __typeof__(2147483648l) x32; +extern __typeof__(2147483648L) x32; + +#if IS_ULONG(X32TYPE) +#if !__cplusplus + +/****************************************************************************** + * Under pre-C99 ISO C, unsigned long is attempted for decimal integer literals + * that do not have a suffix containing "u" or "U" if the literal does not fit + * within the range of int or long. See 6.1.3.2 paragraph 5. + ******************************************************************************/ +// expected-warning@39 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will have type 'long long' in C99 onwards}} +// expected-warning@40 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will have type 'long long' in C99 onwards}} +// expected-warning@41 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will have type 'long long' in C99 onwards}} +#else + +/****************************************************************************** + * Under pre-C++11 ISO C++, the same holds if the literal contains an "l" or "L" + * in its suffix; otherwise, the behavior is undefined. See 2.13.1 [lex.icon] + * paragraph 2. + ******************************************************************************/ +// expected-warning@39 {{integer literal is too large to be represented in type 'long' and is subject to undefined behavior under C++98, interpreting as 'unsigned long'; this literal will have type 'long long' in C++11 onwards}} +// expected-warning@40 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C++98; this literal will have type 'long long' in C++11 onwards}} +// expected-warning@41 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C++98; this literal will have type 'long long' in C++11 onwards}} +#endif +#endif + + +#ifdef X64TYPE + +/****************************************************************************** + * Test 2^63 as a decimal literal with no suffix and with the "l" and "L" cases. + ******************************************************************************/ +extern X64TYPE x64; +extern __typeof__(9223372036854775808) x64; +extern __typeof__(9223372036854775808l) x64; +extern __typeof__(9223372036854775808L) x64; + +#if IS_ULONG(X64TYPE) + +#if !__cplusplus + +/****************************************************************************** + * Under pre-C99 ISO C, unsigned long is attempted for decimal integer literals + * that do not have a suffix containing "u" or "U" if the literal does not fit + * within the range of int or long. See 6.1.3.2 paragraph 5. + ******************************************************************************/ +// expected-warning@74 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will be ill-formed in C99 onwards}} +// expected-warning@75 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will be ill-formed in C99 onwards}} +// expected-warning@76 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C89; this literal will be ill-formed in C99 onwards}} +#else + +/****************************************************************************** + * Under pre-C++11 ISO C++, the same holds if the literal contains an "l" or "L" + * in its suffix; otherwise, the behavior is undefined. See 2.13.1 [lex.icon] + * paragraph 2. + ******************************************************************************/ +// expected-warning@74 {{integer literal is too large to be represented in type 'long' and is subject to undefined behavior under C++98, interpreting as 'unsigned long'; this literal will be ill-formed in C++11 onwards}} +// expected-warning@75 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C++98; this literal will be ill-formed in C++11 onwards}} +// expected-warning@76 {{integer literal is too large to be represented in type 'long', interpreting as 'unsigned long' per C++98; this literal will be ill-formed in C++11 onwards}} +#endif +#else + +/****************************************************************************** + * The status quo in C99/C++11-and-later modes for the literals in question is + * to interpret them as unsigned as an extension. + ******************************************************************************/ +// expected-warning@74 {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}} +// expected-warning@75 {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}} +// expected-warning@76 {{integer literal is too large to be represented in a signed integer type, interpreting as unsigned}} +#endif +#endif + + +/****************************************************************************** + * Test preprocessor arithmetic with 2^31 as a decimal literal with no suffix + * and with the "l" and "L" cases. + ******************************************************************************/ +#if !IS_ULONG(X32TYPE) + +/****************************************************************************** + * If the literal is signed without need for the modified range of the signed + * integer types within the controlling constant expression for conditional + * inclusion, then it will also be signed with said modified range. + ******************************************************************************/ +#define EXPR(X) ((X - X) - 1 < 0) +#else + +/****************************************************************************** + * Strictly speaking, in pre-C99/C++11 ISO C/C++, the preprocessor arithmetic is + * evaluated with the range of long/unsigned long; however, both Clang and GCC + * evaluate using 64-bits even when long/unsigned long are 32-bits outside of + * preprocessing. + * + * If the range used becomes 32-bits, then this test will enforce the treatment + * as unsigned of the literals in question. + * + * Note: + * Under pre-C99/C++11 ISO C/C++, whether the interpretation of the literal is + * affected by the modified range of the signed and unsigned integer types + * within the controlling constant expression for conditional inclusion is + * unclear. + ******************************************************************************/ +#define PP_LONG_MAX ((0ul - 1ul) >> 1) +#define EXPR(X) \ + (PP_LONG_MAX >= 0x80000000 || (X - X) - 1 > 0) // either 2^31 fits into a + // preprocessor "long" or the + // literals in question are + // unsigned +#endif + +#if !(EXPR(2147483648) && EXPR(2147483648l) && EXPR(2147483648L)) +#error Unexpected signedness or conversion behavior +#endif |