Index: lib/Analysis/ReachableCode.cpp =================================================================== --- lib/Analysis/ReachableCode.cpp +++ lib/Analysis/ReachableCode.cpp @@ -58,6 +58,15 @@ return false; } +static bool isBuiltinUnreachable(const Stmt *S) { + if (const DeclRefExpr *DRE = dyn_cast(S)) { + const FunctionDecl *FDecl = dyn_cast(DRE->getDecl()); + return FDecl && FDecl->getIdentifier() && + FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable; + } + return false; +} + static bool isDeadReturn(const CFGBlock *B, const Stmt *S) { // Look to see if the current control flow ends with a 'return', and see if // 'S' is a substatement. The 'return' may not be the last element in the @@ -574,8 +583,7 @@ if (isa(S)) { UK = reachable_code::UK_Break; - } - else if (isTrivialDoWhile(B, S)) { + } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S)) { return; } else if (isDeadReturn(B, S)) { Index: test/Sema/warn-unreachable.c =================================================================== --- test/Sema/warn-unreachable.c +++ test/Sema/warn-unreachable.c @@ -396,3 +396,40 @@ else calledFun(); } + +int pr13910_foo(int x) { + if (x == 1) + return 0; + else + return x; + __builtin_unreachable(); // expected no warning +} + +int pr13910_bar(int x) { + switch (x) { + default: + return x + 1; + } + pr13910_foo(x); // expected-warning {{code will never be executed}} +} + +int pr13910_bar2(int x) { + if (x == 1) + return 0; + else + return x; + pr13910_foo(x); // expected-warning {{code will never be executed}} + __builtin_unreachable(); // expected no warning + pr13910_foo(x); // expected-warning {{code will never be executed}} +} + +void pr13910_noreturn() { + raze(); + __builtin_unreachable(); // expected no warning +} + +void pr13910_assert() { + myassert(0 && "unreachable"); + return; + __builtin_unreachable(); // expected no warning +}