From 2823a6960fe486f3d311c18321a0363e199694e0 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 1 Aug 2017 09:48:53 -0700 Subject: [PATCH] Properly interpolate negative AP literals Integer and Floating literals are aware of their negation but do not store the sign in the text of the value. Retrieve the sign bit and properly interpolate the text of the literal value with it to distinguish negative and positive literals. --- include/swift/AST/Expr.h | 5 +++-- lib/AST/Expr.cpp | 9 +++++---- lib/IRGen/GenEnum.cpp | 6 ++---- lib/Sema/TypeCheckSwitchStmt.cpp | 4 ++-- test/Sema/exhaustive_switch.swift | 18 ++++++++++++++++-- 5 files changed, 28 insertions(+), 14 deletions(-) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index b6cce94d322ac..46607d1243208 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -893,7 +893,7 @@ class IntegerLiteralExpr : public NumberLiteralExpr { {} APInt getValue() const; - static APInt getValue(StringRef Text, unsigned BitWidth); + static APInt getValue(StringRef Text, unsigned BitWidth, bool Negative); static bool classof(const Expr *E) { return E->getKind() == ExprKind::IntegerLiteral; @@ -910,7 +910,8 @@ class FloatLiteralExpr : public NumberLiteralExpr { {} APFloat getValue() const; - static APFloat getValue(StringRef Text, const llvm::fltSemantics &Semantics); + static APFloat getValue(StringRef Text, const llvm::fltSemantics &Semantics, + bool Negative); static bool classof(const Expr *E) { return E->getKind() == ExprKind::FloatLiteral; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index d7797f17e5752..8567dc4f6f17d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1005,8 +1005,8 @@ static APInt getIntegerLiteralValue(bool IsNegative, StringRef Text, return Value; } -APInt IntegerLiteralExpr::getValue(StringRef Text, unsigned BitWidth) { - return getIntegerLiteralValue(/*IsNegative=*/false, Text, BitWidth); +APInt IntegerLiteralExpr::getValue(StringRef Text, unsigned BitWidth, bool Negative) { + return getIntegerLiteralValue(Negative, Text, BitWidth); } APInt IntegerLiteralExpr::getValue() const { @@ -1035,8 +1035,9 @@ static APFloat getFloatLiteralValue(bool IsNegative, StringRef Text, } APFloat FloatLiteralExpr::getValue(StringRef Text, - const llvm::fltSemantics &Semantics) { - return getFloatLiteralValue(/*IsNegative*/false, Text, Semantics); + const llvm::fltSemantics &Semantics, + bool Negative) { + return getFloatLiteralValue(Negative, Text, Semantics); } llvm::APFloat FloatLiteralExpr::getValue() const { diff --git a/lib/IRGen/GenEnum.cpp b/lib/IRGen/GenEnum.cpp index df9902a39ad87..8ec8d27ec388b 100644 --- a/lib/IRGen/GenEnum.cpp +++ b/lib/IRGen/GenEnum.cpp @@ -1027,10 +1027,8 @@ namespace { auto intType = getDiscriminatorType(); APInt intValue = IntegerLiteralExpr::getValue(intExpr->getDigitsText(), - intType->getBitWidth()); - - if (intExpr->isNegative()) - intValue = -intValue; + intType->getBitWidth(), + intExpr->isNegative()); return intValue.getZExtValue(); } diff --git a/lib/Sema/TypeCheckSwitchStmt.cpp b/lib/Sema/TypeCheckSwitchStmt.cpp index 1a7dff5de24a2..a95a942b40429 100644 --- a/lib/Sema/TypeCheckSwitchStmt.cpp +++ b/lib/Sema/TypeCheckSwitchStmt.cpp @@ -980,7 +980,7 @@ namespace { auto *ILE = cast(EL); auto cacheVal = IntLiteralCache.insert( - {ILE->getValue(ILE->getDigitsText(), 128), ILE}); + {ILE->getValue(ILE->getDigitsText(), 128, ILE->isNegative()), ILE}); PrevPattern = (cacheVal.first != IntLiteralCache.end()) ? cacheVal.first->getSecond() : nullptr; @@ -993,7 +993,7 @@ namespace { auto cacheVal = FloatLiteralCache.insert( {FLE->getValue(FLE->getDigitsText(), - APFloat::IEEEquad()), FLE}); + APFloat::IEEEquad(), FLE->isNegative()), FLE}); PrevPattern = (cacheVal.first != FloatLiteralCache.end()) ? cacheVal.first->getSecond() : nullptr; diff --git a/test/Sema/exhaustive_switch.swift b/test/Sema/exhaustive_switch.swift index 74eed8b77ee69..83bc8c8d90fff 100644 --- a/test/Sema/exhaustive_switch.swift +++ b/test/Sema/exhaustive_switch.swift @@ -559,8 +559,7 @@ func infinitelySized() -> Bool { } } -// Literal Duplicate checks -func checkLiterals() { +func diagnoseDuplicateLiterals() { let str = "def" let int = 2 let dbl = 2.5 @@ -614,6 +613,9 @@ func checkLiterals() { // No Diagnostics switch int { + case -2: break + case -1: break + case 0: break case 1: break case 2: break case 3: break @@ -621,6 +623,8 @@ func checkLiterals() { } switch int { + case -2: break // expected-note {{first occurrence of identical literal pattern is here}} + case -2: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} case 1: break case 2: break // expected-note {{first occurrence of identical literal pattern is here}} case 2: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} @@ -629,6 +633,7 @@ func checkLiterals() { } switch int { + case -2, -2: break // expected-note {{first occurrence of identical literal pattern is here}} expected-warning {{literal value is already handled by previous pattern; consider removing it}} case 1, 2: break // expected-note 3 {{first occurrence of identical literal pattern is here}} case 2, 3: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} case 1, 2: break // expected-warning 2 {{literal value is already handled by previous pattern; consider removing it}} @@ -655,10 +660,12 @@ func checkLiterals() { switch int { case 10: break case 0b10: break // expected-note {{first occurrence of identical literal pattern is here}} + case -0b10: break // expected-note {{first occurrence of identical literal pattern is here}} case 3000: break case 0x12: break // expected-note {{first occurrence of identical literal pattern is here}} case 400: break case 2: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} + case -2: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} case 18: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} default: break } @@ -681,6 +688,9 @@ func checkLiterals() { // No Diagnostics switch dbl { + case -3.5: break + case -2.5: break + case -1.5: break case 1.5: break case 2.5: break case 3.5: break @@ -688,6 +698,10 @@ func checkLiterals() { } switch dbl { + case -3.5: break + case -2.5: break // expected-note {{first occurrence of identical literal pattern is here}} + case -2.5: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}} + case -1.5: break case 1.5: break case 2.5: break // expected-note {{first occurrence of identical literal pattern is here}} case 2.5: break // expected-warning {{literal value is already handled by previous pattern; consider removing it}}