diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index ee5f5b70200..729f8ba7dee 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -699,6 +699,9 @@ class Expr : public Stmt { /// or CastExprs, returning their operand. Expr *IgnoreParenCasts() LLVM_READONLY; + /// Ignore casts. Strip off any CastExprs, returning their operand. + Expr *IgnoreCasts() LLVM_READONLY; + /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off /// any ParenExpr or ImplicitCastExprs, returning their operand. Expr *IgnoreParenImpCasts() LLVM_READONLY; @@ -760,6 +763,11 @@ class Expr : public Stmt { const Expr *IgnoreParenCasts() const LLVM_READONLY { return const_cast(this)->IgnoreParenCasts(); } + /// Strip off casts, but keep parentheses. + const Expr *IgnoreCasts() const LLVM_READONLY { + return const_cast(this)->IgnoreCasts(); + } + const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const LLVM_READONLY { return const_cast(this)->IgnoreParenNoopCasts(Ctx); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index f023fe804b6..4ddd0a239aa 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2400,6 +2400,27 @@ Expr *Expr::IgnoreParenCasts() { } } +Expr *Expr::IgnoreCasts() { + Expr *E = this; + while (true) { + if (CastExpr *P = dyn_cast(E)) { + E = P->getSubExpr(); + continue; + } + if (MaterializeTemporaryExpr *Materialize + = dyn_cast(E)) { + E = Materialize->GetTemporaryExpr(); + continue; + } + if (SubstNonTypeTemplateParmExpr *NTTP + = dyn_cast(E)) { + E = NTTP->getReplacement(); + continue; + } + return E; + } +} + /// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue /// casts. This is intended purely as a temporary workaround for code /// that hasn't yet been rewritten to do the right thing about those diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 3cc8ae4a081..8be1af7cef3 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -139,6 +139,9 @@ static bool isConfigurationValue(const Stmt *S, if (!S) return false; + if (const Expr *Ex = dyn_cast(S)) + S = Ex->IgnoreCasts(); + // Special case looking for the sigil '()' around an integer literal. if (const ParenExpr *PE = dyn_cast(S)) if (!PE->getLocStart().isMacroID()) @@ -146,7 +149,7 @@ static bool isConfigurationValue(const Stmt *S, IncludeIntegers, true); if (const Expr *Ex = dyn_cast(S)) - S = Ex->IgnoreParenCasts(); + S = Ex->IgnoreCasts(); bool IgnoreYES_NO = false; diff --git a/test/SemaCXX/warn-unreachable.cpp b/test/SemaCXX/warn-unreachable.cpp index 744825e226f..b08467ab51e 100644 --- a/test/SemaCXX/warn-unreachable.cpp +++ b/test/SemaCXX/warn-unreachable.cpp @@ -327,6 +327,36 @@ void test_with_paren_silencing(int x) { calledFun(); } +void test_with_paren_silencing_impcast(int x) { + if (0) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}} + if ((0)) calledFun(); // no-warning + + if (1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} + calledFun(); + else + calledFun(); // expected-warning {{will never be executed}} + + if ((1)) + calledFun(); + else + calledFun(); // no-warning + + if (!1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} + calledFun(); // expected-warning {{code will never be executed}} + else + calledFun(); + + if ((!1)) + calledFun(); // no-warning + else + calledFun(); + + if (!(1)) + calledFun(); // no-warning + else + calledFun(); +} + void tautological_compare(bool x, int y) { if (x > 10) // expected-note {{silence}} calledFun(); // expected-warning {{will never be executed}}