forked from OSchip/llvm-project
PR11778: Fix the rejects-valid half of this bug. We still produce the same
poorly-worded warning for a case value that is not a possible value of the switched-on expression. llvm-svn: 214678
This commit is contained in:
parent
454b85606e
commit
077d083b4d
|
@ -481,47 +481,6 @@ Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
|
||||||
thenStmt, ElseLoc, elseStmt);
|
thenStmt, ElseLoc, elseStmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have
|
|
||||||
/// the specified width and sign. If an overflow occurs, detect it and emit
|
|
||||||
/// the specified diagnostic.
|
|
||||||
void Sema::ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &Val,
|
|
||||||
unsigned NewWidth, bool NewSign,
|
|
||||||
SourceLocation Loc,
|
|
||||||
unsigned DiagID) {
|
|
||||||
// Perform a conversion to the promoted condition type if needed.
|
|
||||||
if (NewWidth > Val.getBitWidth()) {
|
|
||||||
// If this is an extension, just do it.
|
|
||||||
Val = Val.extend(NewWidth);
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
|
|
||||||
// If the input was signed and negative and the output is
|
|
||||||
// unsigned, don't bother to warn: this is implementation-defined
|
|
||||||
// behavior.
|
|
||||||
// FIXME: Introduce a second, default-ignored warning for this case?
|
|
||||||
} else if (NewWidth < Val.getBitWidth()) {
|
|
||||||
// If this is a truncation, check for overflow.
|
|
||||||
llvm::APSInt ConvVal(Val);
|
|
||||||
ConvVal = ConvVal.trunc(NewWidth);
|
|
||||||
ConvVal.setIsSigned(NewSign);
|
|
||||||
ConvVal = ConvVal.extend(Val.getBitWidth());
|
|
||||||
ConvVal.setIsSigned(Val.isSigned());
|
|
||||||
if (ConvVal != Val)
|
|
||||||
Diag(Loc, DiagID) << Val.toString(10) << ConvVal.toString(10);
|
|
||||||
|
|
||||||
// Regardless of whether a diagnostic was emitted, really do the
|
|
||||||
// truncation.
|
|
||||||
Val = Val.trunc(NewWidth);
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
} else if (NewSign != Val.isSigned()) {
|
|
||||||
// Convert the sign to match the sign of the condition. This can cause
|
|
||||||
// overflow as well: unsigned(INTMIN)
|
|
||||||
// We don't diagnose this overflow, because it is implementation-defined
|
|
||||||
// behavior.
|
|
||||||
// FIXME: Introduce a second, default-ignored warning for this case?
|
|
||||||
Val.setIsSigned(NewSign);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct CaseCompareFunctor {
|
struct CaseCompareFunctor {
|
||||||
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
bool operator()(const std::pair<llvm::APSInt, CaseStmt*> &LHS,
|
||||||
|
@ -671,13 +630,30 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
|
static void AdjustAPSInt(llvm::APSInt &Val, unsigned BitWidth, bool IsSigned) {
|
||||||
if (Val.getBitWidth() < BitWidth)
|
Val = Val.extOrTrunc(BitWidth);
|
||||||
Val = Val.extend(BitWidth);
|
|
||||||
else if (Val.getBitWidth() > BitWidth)
|
|
||||||
Val = Val.trunc(BitWidth);
|
|
||||||
Val.setIsSigned(IsSigned);
|
Val.setIsSigned(IsSigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the specified case value is in range for the given unpromoted switch
|
||||||
|
/// type.
|
||||||
|
static void checkCaseValue(Sema &S, SourceLocation Loc, const llvm::APSInt &Val,
|
||||||
|
unsigned UnpromotedWidth, bool UnpromotedSign) {
|
||||||
|
// If the case value was signed and negative and the switch expression is
|
||||||
|
// unsigned, don't bother to warn: this is implementation-defined behavior.
|
||||||
|
// FIXME: Introduce a second, default-ignored warning for this case?
|
||||||
|
if (UnpromotedWidth < Val.getBitWidth()) {
|
||||||
|
llvm::APSInt ConvVal(Val);
|
||||||
|
AdjustAPSInt(ConvVal, UnpromotedWidth, UnpromotedSign);
|
||||||
|
AdjustAPSInt(ConvVal, Val.getBitWidth(), Val.isSigned());
|
||||||
|
// FIXME: Use different diagnostics for overflow in conversion to promoted
|
||||||
|
// type versus "switch expression cannot have this value". Use proper
|
||||||
|
// IntRange checking rather than just looking at the unpromoted type here.
|
||||||
|
if (ConvVal != Val)
|
||||||
|
S.Diag(Loc, diag::warn_case_value_overflow) << Val.toString(10)
|
||||||
|
<< ConvVal.toString(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if we should emit a diagnostic about this case expression not
|
/// Returns true if we should emit a diagnostic about this case expression not
|
||||||
/// being a part of the enum used in the switch controlling expression.
|
/// being a part of the enum used in the switch controlling expression.
|
||||||
static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx,
|
static bool ShouldDiagnoseSwitchCaseNotInEnum(const ASTContext &Ctx,
|
||||||
|
@ -744,13 +720,20 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the bitwidth of the switched-on value before promotions. We must
|
// Get the bitwidth of the switched-on value after promotions. We must
|
||||||
// convert the integer case values to this width before comparison.
|
// convert the integer case values to this width before comparison.
|
||||||
bool HasDependentValue
|
bool HasDependentValue
|
||||||
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
|
= CondExpr->isTypeDependent() || CondExpr->isValueDependent();
|
||||||
unsigned CondWidth
|
unsigned CondWidth = HasDependentValue ? 0 : Context.getIntWidth(CondType);
|
||||||
|
bool CondIsSigned = CondType->isSignedIntegerOrEnumerationType();
|
||||||
|
|
||||||
|
// Get the width and signedness that the condition might actually have, for
|
||||||
|
// warning purposes.
|
||||||
|
// FIXME: Grab an IntRange for the condition rather than using the unpromoted
|
||||||
|
// type.
|
||||||
|
unsigned CondWidthBeforePromotion
|
||||||
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
|
= HasDependentValue ? 0 : Context.getIntWidth(CondTypeBeforePromotion);
|
||||||
bool CondIsSigned
|
bool CondIsSignedBeforePromotion
|
||||||
= CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
|
= CondTypeBeforePromotion->isSignedIntegerOrEnumerationType();
|
||||||
|
|
||||||
// Accumulate all of the case values in a vector so that we can sort them
|
// Accumulate all of the case values in a vector so that we can sort them
|
||||||
|
@ -816,15 +799,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get();
|
Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the value to the same width/sign as the condition had prior to
|
// Check the unconverted value is within the range of possible values of
|
||||||
// integral promotions.
|
// the switch expression.
|
||||||
//
|
checkCaseValue(*this, Lo->getLocStart(), LoVal,
|
||||||
// FIXME: This causes us to reject valid code:
|
CondWidthBeforePromotion, CondIsSignedBeforePromotion);
|
||||||
// switch ((char)c) { case 256: case 0: return 0; }
|
|
||||||
// Here we claim there is a duplicated condition value, but there is not.
|
// Convert the value to the same width/sign as the condition.
|
||||||
ConvertIntegerToTypeWarnOnOverflow(LoVal, CondWidth, CondIsSigned,
|
AdjustAPSInt(LoVal, CondWidth, CondIsSigned);
|
||||||
Lo->getLocStart(),
|
|
||||||
diag::warn_case_value_overflow);
|
|
||||||
|
|
||||||
CS->setLHS(Lo);
|
CS->setLHS(Lo);
|
||||||
|
|
||||||
|
@ -847,8 +828,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
llvm::APSInt ConstantCondValue;
|
llvm::APSInt ConstantCondValue;
|
||||||
bool HasConstantCond = false;
|
bool HasConstantCond = false;
|
||||||
if (!HasDependentValue && !TheDefaultStmt) {
|
if (!HasDependentValue && !TheDefaultStmt) {
|
||||||
HasConstantCond
|
HasConstantCond = CondExpr->EvaluateAsInt(ConstantCondValue, Context,
|
||||||
= CondExprBeforePromotion->EvaluateAsInt(ConstantCondValue, Context,
|
|
||||||
Expr::SE_AllowSideEffects);
|
Expr::SE_AllowSideEffects);
|
||||||
assert(!HasConstantCond ||
|
assert(!HasConstantCond ||
|
||||||
(ConstantCondValue.getBitWidth() == CondWidth &&
|
(ConstantCondValue.getBitWidth() == CondWidth &&
|
||||||
|
@ -935,10 +915,13 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
|
||||||
Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get();
|
Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check the unconverted value is within the range of possible values of
|
||||||
|
// the switch expression.
|
||||||
|
checkCaseValue(*this, Hi->getLocStart(), HiVal,
|
||||||
|
CondWidthBeforePromotion, CondIsSignedBeforePromotion);
|
||||||
|
|
||||||
// Convert the value to the same width/sign as the condition.
|
// Convert the value to the same width/sign as the condition.
|
||||||
ConvertIntegerToTypeWarnOnOverflow(HiVal, CondWidth, CondIsSigned,
|
AdjustAPSInt(HiVal, CondWidth, CondIsSigned);
|
||||||
Hi->getLocStart(),
|
|
||||||
diag::warn_case_value_overflow);
|
|
||||||
|
|
||||||
CR->setRHS(Hi);
|
CR->setRHS(Hi);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -Wswitch-enum -Wcovered-switch-default -triple x86_64-linux-gnu %s
|
||||||
void f (int z) {
|
void f (int z) {
|
||||||
while (z) {
|
while (z) {
|
||||||
default: z--; // expected-error {{statement not in switch}}
|
default: z--; // expected-error {{statement not in switch}}
|
||||||
|
@ -375,3 +375,13 @@ void switch_on_ExtendedEnum1(enum ExtendedEnum1 e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PR11778(char c, int n, long long ll) {
|
||||||
|
// Do not reject this; we don't have duplicate case values because we
|
||||||
|
// check for duplicates in the promoted type.
|
||||||
|
switch (c) case 1: case 257: ; // expected-warning {{overflow}}
|
||||||
|
|
||||||
|
switch (n) case 0x100000001LL: case 1: ; // expected-warning {{overflow}} expected-error {{duplicate}} expected-note {{previous}}
|
||||||
|
switch ((int)ll) case 0x100000001LL: case 1: ; // expected-warning {{overflow}} expected-error {{duplicate}} expected-note {{previous}}
|
||||||
|
switch ((long long)n) case 0x100000001LL: case 1: ;
|
||||||
|
switch (ll) case 0x100000001LL: case 1: ;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue