diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index ee5f5b70200f..729f8ba7dee6 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -699,6 +699,9 @@ public: /// 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 @@ public: 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/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index f023fe804b6b..4ddd0a239aa9 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/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/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 3cc8ae4a0810..8be1af7cef3d 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/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/clang/test/SemaCXX/warn-unreachable.cpp b/clang/test/SemaCXX/warn-unreachable.cpp index 744825e226f2..b08467ab51e6 100644 --- a/clang/test/SemaCXX/warn-unreachable.cpp +++ b/clang/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}}