diff options
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 38 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.const/p2-0x.cpp | 4 | ||||
-rw-r--r-- | clang/test/Sema/constant-conversion.c | 31 |
3 files changed, 70 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 60a2e505d88..295ff71eff7 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7578,7 +7578,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. llvm::APSInt Value(32); - if (E->isIntegerConstantExpr(Value, S.Context)) { + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -7603,6 +7603,42 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); } + if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative && + SourceRange.NonNegative && Source->isSignedIntegerType()) { + // Warn when doing a signed to signed conversion, warn if the positive + // source value is exactly the width of the target type, which will + // cause a negative value to be stored. + + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) { + if (!S.SourceMgr.isInSystemMacro(CC)) { + + IntegerLiteral *IntLit = + dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts()); + + // If initializing from a constant, and the constant starts with '0', + // then it is a binary, octal, or hexadecimal. Allow these constants + // to fill all the bits, even if there is a sign change. + if (!IntLit || + *(S.getSourceManager().getCharacterData(IntLit->getLocStart())) != + '0') { + + std::string PrettySourceValue = Value.toString(10); + std::string PrettyTargetValue = + PrettyPrintInRange(Value, TargetRange); + + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + return; + } + } + } + // Fall through for non-constants to give a sign conversion warning. + } + if ((TargetRange.NonNegative && !SourceRange.NonNegative) || (!TargetRange.NonNegative && SourceRange.NonNegative && SourceRange.Width == TargetRange.Width)) { diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index c519ecbda22..fd15960647c 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp @@ -242,8 +242,8 @@ namespace UndefinedBehavior { constexpr int n13 = n5 + n5; // expected-error {{constant expression}} expected-note {{value -4294967296 is outside the range of }} constexpr int n14 = n3 - n5; // expected-error {{constant expression}} expected-note {{value 4294967295 is outside the range of }} constexpr int n15 = n5 * n5; // expected-error {{constant expression}} expected-note {{value 4611686018427387904 is outside the range of }} - constexpr signed char c1 = 100 * 2; // ok - constexpr signed char c2 = '\x64' * '\2'; // also ok + constexpr signed char c1 = 100 * 2; // ok expected-warning{{changes value}} + constexpr signed char c2 = '\x64' * '\2'; // also ok expected-warning{{changes value}} constexpr long long ll1 = 0x7fffffffffffffff; // ok constexpr long long ll2 = ll1 + 1; // expected-error {{constant}} expected-note {{ 9223372036854775808 }} constexpr long long ll3 = -ll1 - 1; // ok diff --git a/clang/test/Sema/constant-conversion.c b/clang/test/Sema/constant-conversion.c index 13763339671..74a469d08a9 100644 --- a/clang/test/Sema/constant-conversion.c +++ b/clang/test/Sema/constant-conversion.c @@ -80,3 +80,34 @@ void test8() { struct { enum E x : 1; } f; f.x = C; // expected-warning {{implicit truncation from 'int' to bitfield changes value from 2 to 0}} } + +void test9() { + const char max_char = 0x7F; + const short max_short = 0x7FFF; + const int max_int = 0x7FFFFFFF; + + const short max_char_plus_one = (short)max_char + 1; + const int max_short_plus_one = (int)max_short + 1; + const long max_int_plus_one = (long)max_int + 1; + + char new_char = max_char_plus_one; // expected-warning {{implicit conversion from 'const short' to 'char' changes value from 128 to -128}} + short new_short = max_short_plus_one; // expected-warning {{implicit conversion from 'const int' to 'short' changes value from 32768 to -32768}} + int new_int = max_int_plus_one; // expected-warning {{implicit conversion from 'const long' to 'int' changes value from 2147483648 to -2147483648}} + + char hex_char = 0x80; + short hex_short = 0x8000; + int hex_int = 0x80000000; + + char oct_char = 0200; + short oct_short = 0100000; + int oct_int = 020000000000; + + char bin_char = 0b10000000; + short bin_short = 0b1000000000000000; + int bin_int = 0b10000000000000000000000000000000; + +#define CHAR_MACRO_HEX 0xff + char macro_char_hex = CHAR_MACRO_HEX; +#define CHAR_MACRO_DEC 255 + char macro_char_dec = CHAR_MACRO_DEC; // expected-warning {{implicit conversion from 'int' to 'char' changes value from 255 to -1}} +} |