aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-06-13 01:07:41 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-06-13 01:07:41 +0000
commitcd65f4903dc737d92655a0cf72755c16831ae668 (patch)
tree951c7e96d5fd0ee80e32486785814a90ae402d33
parente0deb035b3e2d07b41ea55db84b110abcb65b753 (diff)
Add missing narrowing check: converting from a signed integral type to a wider
unsigned type is narrowing if the source is non-constant or negative. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158377 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/SemaOverload.cpp16
-rw-r--r--test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp14
2 files changed, 25 insertions, 5 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 994471ab5c..d723d45587 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -389,11 +389,20 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
const unsigned ToWidth = Ctx.getIntWidth(ToType);
if (FromWidth > ToWidth ||
- (FromWidth == ToWidth && FromSigned != ToSigned)) {
+ (FromWidth == ToWidth && FromSigned != ToSigned) ||
+ (FromSigned && !ToSigned)) {
// Not all values of FromType can be represented in ToType.
llvm::APSInt InitializerValue;
const Expr *Initializer = IgnoreNarrowingConversion(Converted);
- if (Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ if (!Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) {
+ // Such conversions on variables are always narrowing.
+ return NK_Variable_Narrowing;
+ } else if (FromWidth < ToWidth) {
+ // Negative -> unsigned is narrowing. Otherwise, more bits is never
+ // narrowing.
+ if (InitializerValue.isSigned() && InitializerValue.isNegative())
+ return NK_Constant_Narrowing;
+ } else {
ConstantValue = APValue(InitializerValue);
// Add a bit to the InitializerValue so we don't have to worry about
@@ -411,9 +420,6 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
ConstantType = Initializer->getType();
return NK_Constant_Narrowing;
}
- } else {
- // Variables are always narrowings.
- return NK_Variable_Narrowing;
}
}
return NK_Not_Narrowing;
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
index db20ea6426..e3909cce13 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.list/p7-0x.cpp
@@ -167,6 +167,20 @@ void shrink_int() {
Agg<short> ce1 = { Convert<int>(100000) }; // expected-error {{constant expression evaluates to 100000 which cannot be narrowed to type 'short'}} expected-note {{override}} expected-warning {{changes value from 100000 to -31072}}
Agg<char> ce2 = { ConvertVar<short>() }; // expected-error {{non-constant-expression cannot be narrowed from type 'short' to 'char'}} expected-note {{override}}
+
+ // Negative -> larger unsigned type.
+ unsigned long long ll1 = { -1 }; // expected-error {{cannot be narrowed}} expected-note {{override}}
+ unsigned long long ll2 = { 1 }; // OK
+ unsigned long long ll3 = { s }; // expected-error {{cannot be narrowed}} expected-note {{override}}
+ unsigned long long ll4 = { us }; // OK
+ unsigned long long ll5 = { ll }; // expected-error {{cannot be narrowed}} expected-note {{override}}
+ Agg<unsigned long long> ll6 = { -1 }; // expected-error {{cannot be narrowed}} expected-note {{override}}
+ Agg<unsigned long long> ll7 = { 18446744073709551615ULL }; // OK
+ Agg<unsigned long long> ll8 = { __int128(18446744073709551615ULL) + 1 }; // expected-error {{cannot be narrowed}} expected-note {{override}} expected-warning {{changes value}}
+ signed char c = 'x';
+ unsigned short usc1 = { c }; // expected-error {{cannot be narrowed}} expected-note {{override}}
+ unsigned short usc2 = { (signed char)'x' }; // OK
+ unsigned short usc3 = { (signed char)-1 }; // expected-error {{cannot be narrowed}} expected-note {{override}}
}
// Be sure that type- and value-dependent expressions in templates get the error