Skip to content

Commit 81ce77d

Browse files
authored
Merge pull request swiftlang#16644 from ravikandhadai/LargeIntOverflowPR
2 parents d0ef976 + f1ff8a6 commit 81ce77d

File tree

10 files changed

+190
-31
lines changed

10 files changed

+190
-31
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2449,6 +2449,9 @@ ERROR(no_MaxBuiltinIntegerType_found,none,
24492449
"standard library error: _MaxBuiltinIntegerType is not properly defined", ())
24502450
ERROR(no_MaxBuiltinFloatType_found,none,
24512451
"standard library error: _MaxBuiltinFloatType is not properly defined", ())
2452+
ERROR(integer_literal_overflows_maxwidth, none,
2453+
"integer literal needs %1 bits, exceeding limit of %0 bits",
2454+
(unsigned, unsigned))
24522455

24532456
ERROR(no_member_of_module,none,
24542457
"module %0 has no member named %1", (Identifier, DeclName))

include/swift/AST/Expr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,8 @@ class IntegerLiteralExpr : public NumberLiteralExpr {
835835
APInt getValue() const;
836836
static APInt getValue(StringRef Text, unsigned BitWidth, bool Negative);
837837

838+
APInt getRawMagnitude() const;
839+
838840
static bool classof(const Expr *E) {
839841
return E->getKind() == ExprKind::IntegerLiteral;
840842
}

lib/AST/Expr.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -996,15 +996,19 @@ LiteralExpr *LiteralExpr::shallowClone(
996996
return Result;
997997
}
998998

999-
1000-
999+
/// A wrapper around LLVM::getAsInteger that can be used on Swift interger
1000+
/// literals. It avoids misinterpreting decimal numbers prefixed with 0 as
1001+
/// octal numbers.
1002+
static bool getAsInteger(StringRef Text, llvm::APInt &Value) {
1003+
// swift encodes octal differently from C
1004+
bool IsCOctal = Text.size() > 1 && Text[0] == '0' && isdigit(Text[1]);
1005+
return Text.getAsInteger(IsCOctal ? 10 : 0, Value);
1006+
}
10011007

10021008
static APInt getIntegerLiteralValue(bool IsNegative, StringRef Text,
10031009
unsigned BitWidth) {
10041010
llvm::APInt Value(BitWidth, 0);
1005-
// swift encodes octal differently from C
1006-
bool IsCOctal = Text.size() > 1 && Text[0] == '0' && isdigit(Text[1]);
1007-
bool Error = Text.getAsInteger(IsCOctal ? 10 : 0, Value);
1011+
bool Error = getAsInteger(Text, Value);
10081012
assert(!Error && "Invalid IntegerLiteral formed"); (void)Error;
10091013
if (IsNegative)
10101014
Value = -Value;
@@ -1017,6 +1021,15 @@ APInt IntegerLiteralExpr::getValue(StringRef Text, unsigned BitWidth, bool Negat
10171021
return getIntegerLiteralValue(Negative, Text, BitWidth);
10181022
}
10191023

1024+
/// Returns the raw magnitude of the literal text without any truncation.
1025+
APInt IntegerLiteralExpr::getRawMagnitude() const {
1026+
llvm::APInt Value(64, 0);
1027+
bool Error = getAsInteger(getDigitsText(), Value);
1028+
assert(!Error && "Invalid IntegerLiteral formed");
1029+
(void)Error;
1030+
return Value;
1031+
}
1032+
10201033
APInt IntegerLiteralExpr::getValue() const {
10211034
assert(!getType().isNull() && "Semantic analysis has not completed");
10221035
assert(!getType()->hasError() && "Should have a valid type");

lib/Sema/CSApply.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,7 +1858,6 @@ namespace {
18581858
return bridgeFromObjectiveC(object, valueType, false);
18591859
}
18601860

1861-
TypeAliasDecl *MaxIntegerTypeDecl = nullptr;
18621861
TypeAliasDecl *MaxFloatTypeDecl = nullptr;
18631862

18641863
public:
@@ -1921,28 +1920,6 @@ namespace {
19211920
}
19221921
}
19231922

1924-
// Find the maximum-sized builtin integer type.
1925-
1926-
if (!MaxIntegerTypeDecl) {
1927-
SmallVector<ValueDecl *, 1> lookupResults;
1928-
tc.getStdlibModule(dc)->lookupValue(/*AccessPath=*/{},
1929-
tc.Context.Id_MaxBuiltinIntegerType,
1930-
NLKind::QualifiedLookup,
1931-
lookupResults);
1932-
if (lookupResults.size() == 1) {
1933-
MaxIntegerTypeDecl = dyn_cast<TypeAliasDecl>(lookupResults.front());
1934-
tc.validateDecl(MaxIntegerTypeDecl);
1935-
}
1936-
}
1937-
if (!MaxIntegerTypeDecl ||
1938-
!MaxIntegerTypeDecl->hasInterfaceType() ||
1939-
!MaxIntegerTypeDecl->getDeclaredInterfaceType()->is<BuiltinIntegerType>()) {
1940-
tc.diagnose(expr->getLoc(), diag::no_MaxBuiltinIntegerType_found);
1941-
return nullptr;
1942-
}
1943-
tc.validateDecl(MaxIntegerTypeDecl);
1944-
auto maxType = MaxIntegerTypeDecl->getUnderlyingTypeLoc().getType();
1945-
19461923
DeclName initName(tc.Context, DeclBaseName::createConstructor(),
19471924
{ tc.Context.Id_integerLiteral });
19481925
DeclName builtinInitName(tc.Context, DeclBaseName::createConstructor(),
@@ -1956,7 +1933,9 @@ namespace {
19561933
tc.Context.Id_IntegerLiteralType,
19571934
initName,
19581935
builtinProtocol,
1959-
maxType,
1936+
// Note that 'MaxIntegerType' is guaranteed to be available.
1937+
// Otherwise it would be caught by CSGen::visitLiteralExpr
1938+
tc.getMaxIntegerType(dc),
19601939
builtinInitName,
19611940
nullptr,
19621941
diag::integer_literal_broken_proto,

lib/Sema/CSGen.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,44 @@ namespace {
11791179
auto protocol = CS.getTypeChecker().getLiteralProtocol(expr);
11801180
if (!protocol)
11811181
return nullptr;
1182-
1182+
1183+
// Make sure that MaxIntegerType is defined if it would used later
1184+
// during constraint solving (CSApply).
1185+
if (isa<IntegerLiteralExpr>(expr) ||
1186+
(isa<MagicIdentifierLiteralExpr>(expr) &&
1187+
dyn_cast<MagicIdentifierLiteralExpr>(expr)->isColumn())) {
1188+
1189+
auto maxIntType = CS.TC.getMaxIntegerType(CS.DC);
1190+
if (maxIntType.isNull()) {
1191+
CS.TC.diagnose(expr->getLoc(), diag::no_MaxBuiltinIntegerType_found);
1192+
return nullptr;
1193+
}
1194+
1195+
// In the case of integer literal, make sure that the literal value
1196+
// will fit within the bit width of the maximum integer type.
1197+
if (IntegerLiteralExpr *intLit = dyn_cast<IntegerLiteralExpr>(expr)) {
1198+
unsigned maxWidth =
1199+
maxIntType->castTo<BuiltinIntegerType>()->getGreatestWidth();
1200+
APInt magnitude = intLit->getRawMagnitude();
1201+
unsigned magWidth = magnitude.getActiveBits();
1202+
bool isNegative = intLit->isNegative();
1203+
1204+
// Compute the literal bit width in the signed two's complement form.
1205+
// This is generally one more than the magnitude width, but is the
1206+
// same when the literal is of the form -2^i (for some Nat `i`).
1207+
unsigned signedLitWidth =
1208+
(isNegative && (magnitude.countTrailingZeros() == magWidth - 1))
1209+
? magWidth
1210+
: (magWidth + 1);
1211+
1212+
if (signedLitWidth > maxWidth) { // overflow?
1213+
CS.TC.diagnose(expr->getLoc(),
1214+
diag::integer_literal_overflows_maxwidth, maxWidth,
1215+
signedLitWidth);
1216+
return nullptr;
1217+
}
1218+
}
1219+
}
11831220

11841221
auto tv = CS.createTypeVariable(CS.getConstraintLocator(expr),
11851222
TVO_PrefersSubtypeBinding);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3000,7 +3000,11 @@ static LiteralExpr *getAutomaticRawValueExpr(TypeChecker &TC,
30003000
return new (TC.Context) IntegerLiteralExpr("0", SourceLoc(),
30013001
/*Implicit=*/true);
30023002
}
3003-
3003+
// If the prevValue is not a well-typed integer, then break.
3004+
// This could happen if the literal value overflows _MaxBuiltinIntegerType.
3005+
if (!prevValue->getType())
3006+
return nullptr;
3007+
30043008
if (auto intLit = dyn_cast<IntegerLiteralExpr>(prevValue)) {
30053009
APInt nextVal = intLit->getValue() + 1;
30063010
bool negative = nextVal.slt(0);

lib/Sema/TypeCheckType.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,31 @@ Type TypeChecker::getUInt8Type(DeclContext *dc) {
144144
return ::getStdlibType(*this, UInt8Type, dc, "UInt8");
145145
}
146146

147+
/// Returns the maximum-sized builtin integer type.
148+
Type TypeChecker::getMaxIntegerType(DeclContext *dc) {
149+
if (!MaxIntegerType.isNull())
150+
return MaxIntegerType;
151+
152+
SmallVector<ValueDecl *, 1> lookupResults;
153+
getStdlibModule(dc)->lookupValue(/*AccessPath=*/{},
154+
Context.Id_MaxBuiltinIntegerType,
155+
NLKind::QualifiedLookup, lookupResults);
156+
if (lookupResults.size() != 1)
157+
return MaxIntegerType;
158+
159+
auto *maxIntegerTypeDecl = dyn_cast<TypeAliasDecl>(lookupResults.front());
160+
if (!maxIntegerTypeDecl)
161+
return MaxIntegerType;
162+
163+
validateDecl(maxIntegerTypeDecl);
164+
if (!maxIntegerTypeDecl->hasInterfaceType() ||
165+
!maxIntegerTypeDecl->getDeclaredInterfaceType()->is<BuiltinIntegerType>())
166+
return MaxIntegerType;
167+
168+
MaxIntegerType = maxIntegerTypeDecl->getUnderlyingTypeLoc().getType();
169+
return MaxIntegerType;
170+
}
171+
147172
/// Find the standard type of exceptions.
148173
///
149174
/// We call this the "exception type" to try to avoid confusion with

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,7 @@ class TypeChecker final : public LazyResolver {
870870

871871
private:
872872
Type IntLiteralType;
873+
Type MaxIntegerType;
873874
Type FloatLiteralType;
874875
Type BooleanLiteralType;
875876
Type UnicodeScalarType;
@@ -1048,6 +1049,7 @@ class TypeChecker final : public LazyResolver {
10481049
Type getIntType(DeclContext *dc);
10491050
Type getInt8Type(DeclContext *dc);
10501051
Type getUInt8Type(DeclContext *dc);
1052+
Type getMaxIntegerType(DeclContext *dc);
10511053
Type getNSObjectType(DeclContext *dc);
10521054
Type getNSErrorType(DeclContext *dc);
10531055
Type getObjCSelectorType(DeclContext *dc);

test/SILOptimizer/diagnostic_constant_propagation.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// References: <rdar://problem/29937936>, <rdar://problem/29939484>,
99
// <https://bugs.swift.org/browse/SR-5964>, <rdar://problem/39120081>
1010

11+
import StdlibUnittest
12+
1113
func testArithmeticOverflow() {
1214
let xu8 : UInt8 = 250
1315
let yu8 : UInt8 = 250
@@ -39,6 +41,18 @@ func testArithmeticOverflow() {
3941
// Note: asserts in the shift operators confuse constant propagation
4042
var _: Int8 = (-1 & ~(1<<7))+1 // FIXME: false negative: should expect an error
4143
// like {{arithmetic operation '127 + 1' (on type 'Int8') results in an overflow}}
44+
45+
// The following cases check that overflows in arithmetic over large literals
46+
// without explicit types are caught. Note that if a literal overflows even
47+
// Int20148 it will be caught by the Sema phases. Also note that the
48+
// overflow is detected during implicit conversion to 'Int'.
49+
_blackHole(
50+
-00016158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328 - 1)
51+
// expected-error@-1 {{integer literal '-16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115328' overflows when stored into 'Int'}}
52+
53+
_blackHole(
54+
00016158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115327 + 1)
55+
// expected-error@-1 {{integer literal '16158503035655503650357438344334975980222051334857742016065172713762327569433945446598600705761456731844358980460949009747059779575245460547544076193224141560315438683650498045875098875194826053398028819192033784138396109321309878080919047169238085235290822926018152521443787945770532904303776199561965192760957166694834171210342487393282284747428088017663161029038902829665513096354230157075129296432088558362971801859230928678799175576150822952201848806616643615613562842355410104862578550863465661734839271290328348967522998634176499319107762583194718667771801067716614802322659239302476074096777926805529798115327' overflows when stored into 'Int'}}
4256
}
4357

4458
@_transparent

0 commit comments

Comments
 (0)