Merge remote-tracking branch 'origin/swift-4.0-branch' into stable
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index d6ebdb1..9efb1e3 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -433,6 +433,13 @@
   "declaration does not declare a parameter">;
 def err_no_matching_param : Error<"parameter named %0 is missing">;
 
+/// Objective-C++ parser diagnostics
+def err_expected_token_instead_of_objcxx_keyword : Error<
+  "expected %0; %1 is a keyword in Objective-C++">;
+def err_expected_member_name_or_semi_objcxx_keyword : Error<
+  "expected member name or ';' after declaration specifiers; "
+  "%0 is a keyword in Objective-C++">;
+
 /// C++ parser diagnostics
 def err_invalid_operator_on_type : Error<
   "cannot use %select{dot|arrow}0 operator on a type">;
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 52238f8..7d10f14 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -277,7 +277,11 @@
   bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; }
 
   /// \brief Return true if this token is a keyword in the specified language.
-  bool isKeyword(const LangOptions &LangOpts);
+  bool isKeyword(const LangOptions &LangOpts) const;
+
+  /// \brief Return true if this token is a C++ keyword in the specified
+  /// language.
+  bool isCPlusPlusKeyword(const LangOptions &LangOpts) const;
 
   /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to
   /// associate arbitrary metadata with this token.
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index a3c7b7b..0f5cd45 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -800,6 +800,14 @@
   /// \brief Consume any extra semi-colons until the end of the line.
   void ConsumeExtraSemi(ExtraSemiKind Kind, unsigned TST = TST_unspecified);
 
+  /// Return false if the next token is an identifier. An 'expected identifier'
+  /// error is emitted otherwise.
+  ///
+  /// The parser tries to recover from the error by checking if the next token
+  /// is a C++ keyword when parsing Objective-C++. Return false if the recovery
+  /// was successful.
+  bool expectIdentifier();
+
 public:
   //===--------------------------------------------------------------------===//
   // Scope manipulation
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index b8d90b0..e7a276d 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -501,7 +501,14 @@
 
   PrintingPolicy SubPolicy(Policy);
   SubPolicy.SuppressSpecifiers = false;
-  std::string Proto = D->getNameInfo().getAsString();
+  std::string Proto;
+  if (!Policy.SuppressScope) {
+    if (const NestedNameSpecifier *NS = D->getQualifier()) {
+      llvm::raw_string_ostream OS(Proto);
+      NS->print(OS, Policy);
+    }
+  }
+  Proto += D->getNameInfo().getAsString();
   if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) {
     llvm::raw_string_ostream POut(Proto);
     DeclPrinter TArgPrinter(POut, SubPolicy, Indentation);
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 52791e5..23bcd6d 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -574,7 +574,9 @@
       LangOptions LO;
       LO.CPlusPlus = true;
       LO.Bool = true;
-      OS << TInfo->getType().getAsString(PrintingPolicy(LO));
+      PrintingPolicy PP(LO);
+      PP.SuppressScope = true;
+      OS << TInfo->getType().getAsString(PP);
     } else
       OS << Name;
     return;
diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp
index 8a96744..60724ea 100644
--- a/lib/Analysis/ReachableCode.cpp
+++ b/lib/Analysis/ReachableCode.cpp
@@ -58,6 +58,14 @@
   return false;
 }
 
+static bool isBuiltinUnreachable(const Stmt *S) {
+  if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
+    if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
+      return 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
@@ -592,8 +600,7 @@
 
   if (isa<BreakStmt>(S)) {
     UK = reachable_code::UK_Break;
-  }
-  else if (isTrivialDoWhile(B, S)) {
+  } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S)) {
     return;
   }
   else if (isDeadReturn(B, S)) {
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 8c67f4e..6f67081 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -243,7 +243,7 @@
 
 /// \brief Returns true if the identifier represents a keyword in the
 /// specified language.
-bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) {
+bool IdentifierInfo::isKeyword(const LangOptions &LangOpts) const {
   switch (getTokenKwStatus(LangOpts, getTokenID())) {
   case KS_Enabled:
   case KS_Extension:
@@ -253,6 +253,19 @@
   }
 }
 
+/// \brief Returns true if the identifier represents a C++ keyword in the
+/// specified language.
+bool IdentifierInfo::isCPlusPlusKeyword(const LangOptions &LangOpts) const {
+  if (!LangOpts.CPlusPlus || !isKeyword(LangOpts))
+    return false;
+  // This is a C++ keyword if this identifier is not a keyword when checked
+  // using LangOptions without C++ support.
+  LangOptions LangOptsNoCPP = LangOpts;
+  LangOptsNoCPP.CPlusPlus = false;
+  LangOptsNoCPP.CPlusPlus11 = false;
+  return !isKeyword(LangOptsNoCPP);
+}
+
 tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const {
   // We use a perfect hash function here involving the length of the keyword,
   // the first and third character.  For preprocessor ID's there are no
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 423225f..b986026 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -5600,6 +5600,21 @@
     if (Tok.is(tok::l_square))
       return ParseMisplacedBracketDeclarator(D);
     if (D.getContext() == Declarator::MemberContext) {
+      // Objective-C++: Detect C++ keywords and try to prevent further errors by
+      // treating these keyword as valid member names.
+      if (getLangOpts().ObjC1 && getLangOpts().CPlusPlus &&
+          Tok.getIdentifierInfo() &&
+          Tok.getIdentifierInfo()->isCPlusPlusKeyword(getLangOpts())) {
+        Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
+             diag::err_expected_member_name_or_semi_objcxx_keyword)
+            << Tok.getIdentifierInfo()
+            << (D.getDeclSpec().isEmpty() ? SourceRange()
+                                          : D.getDeclSpec().getSourceRange());
+        D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+        D.SetRangeEnd(Tok.getLocation());
+        ConsumeToken();
+        goto PastIdentifier;
+      }
       Diag(getMissingDeclaratorIdLoc(D, Tok.getLocation()),
            diag::err_expected_member_name_or_semi)
           << (D.getDeclSpec().isEmpty() ? SourceRange()
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index fb4b945..99cc00f7 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -137,8 +137,7 @@
 
   while (1) {
     MaybeSkipAttributes(tok::objc_class);
-    if (Tok.isNot(tok::identifier)) {
-      Diag(Tok, diag::err_expected) << tok::identifier;
+    if (expectIdentifier()) {
       SkipUntil(tok::semi);
       return Actions.ConvertDeclToDeclGroup(nullptr);
     }
@@ -231,11 +230,8 @@
 
   MaybeSkipAttributes(tok::objc_interface);
 
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected)
-        << tok::identifier; // missing class or category name.
-    return nullptr;
-  }
+  if (expectIdentifier())
+    return nullptr; // missing class or category name.
 
   // We have a class or category name - consume it.
   IdentifierInfo *nameId = Tok.getIdentifierInfo();
@@ -321,11 +317,8 @@
       return nullptr;
     }
 
-    if (Tok.isNot(tok::identifier)) {
-      Diag(Tok, diag::err_expected)
-          << tok::identifier; // missing super class name.
-      return nullptr;
-    }
+    if (expectIdentifier())
+      return nullptr; // missing super class name.
     superClassId = Tok.getIdentifierInfo();
     superClassLoc = ConsumeToken();
 
@@ -1440,12 +1433,9 @@
       cutOffParsing();
       return nullptr;
     }
-    
-    if (Tok.isNot(tok::identifier)) {
-      Diag(Tok, diag::err_expected)
-          << tok::identifier; // missing argument name.
-      break;
-    }
+
+    if (expectIdentifier())
+      break; // missing argument name.
 
     ArgInfo.Name = Tok.getIdentifierInfo();
     ArgInfo.NameLoc = Tok.getLocation();
@@ -1554,8 +1544,7 @@
       return true;
     }
 
-    if (Tok.isNot(tok::identifier)) {
-      Diag(Tok, diag::err_expected) << tok::identifier;
+    if (expectIdentifier()) {
       SkipUntil(tok::greater, StopAtSemi);
       return true;
     }
@@ -2037,10 +2026,8 @@
 
   MaybeSkipAttributes(tok::objc_protocol);
 
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected) << tok::identifier; // missing protocol name.
-    return nullptr;
-  }
+  if (expectIdentifier())
+    return nullptr; // missing protocol name.
   // Save the protocol name, then consume it.
   IdentifierInfo *protocolName = Tok.getIdentifierInfo();
   SourceLocation nameLoc = ConsumeToken();
@@ -2060,8 +2047,7 @@
     // Parse the list of forward declarations.
     while (1) {
       ConsumeToken(); // the ','
-      if (Tok.isNot(tok::identifier)) {
-        Diag(Tok, diag::err_expected) << tok::identifier;
+      if (expectIdentifier()) {
         SkipUntil(tok::semi);
         return nullptr;
       }
@@ -2128,11 +2114,8 @@
 
   MaybeSkipAttributes(tok::objc_implementation);
 
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected)
-        << tok::identifier; // missing class or category name.
-    return nullptr;
-  }
+  if (expectIdentifier())
+    return nullptr; // missing class or category name.
   // We have a class or category name - consume it.
   IdentifierInfo *nameId = Tok.getIdentifierInfo();
   SourceLocation nameLoc = ConsumeToken(); // consume class or category name
@@ -2202,11 +2185,8 @@
     IdentifierInfo *superClassId = nullptr;
     if (TryConsumeToken(tok::colon)) {
       // We have a super class
-      if (Tok.isNot(tok::identifier)) {
-        Diag(Tok, diag::err_expected)
-            << tok::identifier; // missing super class name.
-        return nullptr;
-      }
+      if (expectIdentifier())
+        return nullptr; // missing super class name.
       superClassId = Tok.getIdentifierInfo();
       superClassLoc = ConsumeToken(); // Consume super class name
     }
@@ -2306,16 +2286,12 @@
   assert(Tok.isObjCAtKeyword(tok::objc_compatibility_alias) &&
          "ParseObjCAtAliasDeclaration(): Expected @compatibility_alias");
   ConsumeToken(); // consume compatibility_alias
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected) << tok::identifier;
+  if (expectIdentifier())
     return nullptr;
-  }
   IdentifierInfo *aliasId = Tok.getIdentifierInfo();
   SourceLocation aliasLoc = ConsumeToken(); // consume alias-name
-  if (Tok.isNot(tok::identifier)) {
-    Diag(Tok, diag::err_expected) << tok::identifier;
+  if (expectIdentifier())
     return nullptr;
-  }
   IdentifierInfo *classId = Tok.getIdentifierInfo();
   SourceLocation classLoc = ConsumeToken(); // consume class-name;
   ExpectAndConsume(tok::semi, diag::err_expected_after, "@compatibility_alias");
@@ -2363,11 +2339,9 @@
         cutOffParsing();
         return nullptr;
       }
-      
-      if (Tok.isNot(tok::identifier)) {
-        Diag(Tok, diag::err_expected) << tok::identifier;
+
+      if (expectIdentifier())
         break;
-      }
       propertyIvar = Tok.getIdentifierInfo();
       propertyIvarLoc = ConsumeToken(); // consume ivar-name
     }
@@ -2425,9 +2399,8 @@
       cutOffParsing();
       return nullptr;
     }
-    
-    if (Tok.isNot(tok::identifier)) {
-      Diag(Tok, diag::err_expected) << tok::identifier;
+
+    if (expectIdentifier()) {
       SkipUntil(tok::semi);
       return nullptr;
     }
@@ -3563,8 +3536,8 @@
   BalancedDelimiterTracker T(*this, tok::l_paren);
   T.consumeOpen();
 
-  if (Tok.isNot(tok::identifier))
-    return ExprError(Diag(Tok, diag::err_expected) << tok::identifier);
+  if (expectIdentifier())
+    return ExprError();
 
   IdentifierInfo *protocolId = Tok.getIdentifierInfo();
   SourceLocation ProtoIdLoc = ConsumeToken();
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index bb45366..573f879 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -236,6 +236,21 @@
       << FixItHint::CreateRemoval(SourceRange(StartLoc, EndLoc));
 }
 
+bool Parser::expectIdentifier() {
+  if (Tok.is(tok::identifier))
+    return false;
+  if (const auto *II = Tok.getIdentifierInfo()) {
+    if (II->isCPlusPlusKeyword(getLangOpts())) {
+      Diag(Tok, diag::err_expected_token_instead_of_objcxx_keyword)
+          << tok::identifier << Tok.getIdentifierInfo();
+      // Objective-C++: Recover by treating this keyword as a valid identifier.
+      return false;
+    }
+  }
+  Diag(Tok, diag::err_expected) << tok::identifier;
+  return true;
+}
+
 //===----------------------------------------------------------------------===//
 // Error recovery.
 //===----------------------------------------------------------------------===//
diff --git a/test/Index/comment-cplus-decls.cpp b/test/Index/comment-cplus-decls.cpp
index d4f968f..4c9ce88 100644
--- a/test/Index/comment-cplus-decls.cpp
+++ b/test/Index/comment-cplus-decls.cpp
@@ -96,7 +96,7 @@
     friend void ns::f(int a);
   };
 }
-// CHECK: <Declaration>friend void f(int a)</Declaration>
+// CHECK: <Declaration>friend void ns::f(int a)</Declaration>
 
 namespace test1 {
   template <class T> struct Outer {
@@ -109,7 +109,7 @@
     };
   };
 }
-// CHECK: <Declaration>friend void foo(T)</Declaration>
+// CHECK: <Declaration>friend void Outer&lt;T&gt;::foo(T)</Declaration>
 
 namespace test2 {
   namespace foo {
@@ -123,7 +123,7 @@
     friend void ::test2::foo::Func(int x);
   };
 }
-// CHECK: <Declaration>friend void Func(int x)</Declaration>
+// CHECK: <Declaration>friend void ::test2::foo::Func(int x)</Declaration>
 
 namespace test3 {
   template<class T> class vector {
@@ -143,7 +143,7 @@
   };
 }
 // CHECK: <Declaration>void f(const T &amp;t = T())</Declaration>
-// CHECK: <Declaration>friend void f(const test3::A &amp;)</Declaration>
+// CHECK: <Declaration>friend void vector&lt;A&gt;::f(const test3::A &amp;)</Declaration>
 
 class MyClass
 {
diff --git a/test/Index/overriding-method-comments.mm b/test/Index/overriding-method-comments.mm
index d995e0e..824d055 100644
--- a/test/Index/overriding-method-comments.mm
+++ b/test/Index/overriding-method-comments.mm
@@ -78,7 +78,7 @@
 
 void Base::foo_outofline(int RRR) {}
 
-// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
+// CHECK: FullCommentAsXML=[<Function isInstanceMethod="1" file="{{[^"]+}}overriding-method-comments.mm" line="[[@LINE-2]]" column="12"><Name>foo_outofline</Name><USR>c:@S@Base@F@foo_outofline#I#</USR><Declaration>void Base::foo_outofline(int RRR)</Declaration><Abstract><Para> Does something. </Para></Abstract><Parameters><Parameter><Name>RRR</Name><Index>0</Index><Direction isExplicit="0">in</Direction><Discussion><Para> argument to undefined virtual.</Para></Discussion></Parameter></Parameters></Function>]
 
 struct Derived : public Base {
   virtual void foo_pure(int PPP);
diff --git a/test/Misc/ast-print-out-of-line-func.cpp b/test/Misc/ast-print-out-of-line-func.cpp
new file mode 100644
index 0000000..7c4f7ae
--- /dev/null
+++ b/test/Misc/ast-print-out-of-line-func.cpp
@@ -0,0 +1,54 @@
+// RUN: %clang_cc1 -ast-print -std=c++14 %s | FileCheck %s
+
+namespace ns {
+
+struct Wrapper {
+class Inner {
+  Inner();
+  Inner(int);
+  ~Inner();
+
+  void operator += (int);
+
+  template<typename T>
+  void member();
+
+  static void staticMember();
+
+  operator int();
+
+  operator ns::Wrapper();
+  // CHECK: operator ns::Wrapper()
+};
+};
+
+Wrapper::Inner::Inner() { }
+// CHECK: Wrapper::Inner::Inner()
+
+void Wrapper::Inner::operator +=(int) { }
+// CHECK: void Wrapper::Inner::operator+=(int)
+
+}
+
+ns::Wrapper::Inner::Inner(int) { }
+// CHECK: ns::Wrapper::Inner::Inner(int)
+
+ns::Wrapper::Inner::~Inner() { }
+// CHECK: ns::Wrapper::Inner::~Inner()
+
+template<typename T>
+void ::ns::Wrapper::Inner::member() { }
+// CHECK: template <typename T> void ::ns::Wrapper::Inner::member()
+
+ns::Wrapper::Inner::operator int() { return 0; }
+// CHECK: ns::Wrapper::Inner::operator int()
+
+ns::Wrapper::Inner::operator ::ns::Wrapper() { return ns::Wrapper(); }
+// CHECK: ns::Wrapper::Inner::operator ::ns::Wrapper()
+
+namespace ns {
+
+void Wrapper::Inner::staticMember() { }
+// CHECK: void Wrapper::Inner::staticMember()
+
+}
diff --git a/test/Parser/objc-cxx-keyword-identifiers.mm b/test/Parser/objc-cxx-keyword-identifiers.mm
new file mode 100644
index 0000000..6791f0d
--- /dev/null
+++ b/test/Parser/objc-cxx-keyword-identifiers.mm
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wno-objc-root-class -Wno-incomplete-implementation -triple x86_64-apple-macosx10.10.0 -verify %s
+
+// rdar://20626062
+
+struct S {
+  int throw; // expected-error {{expected member name or ';' after declaration specifiers; 'throw' is a keyword in Objective-C++}}
+};
+
+@interface class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@interface Bar: class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@protocol P // ok
+@end
+
+@protocol new // expected-error {{expected identifier; 'new' is a keyword in Objective-C++}}
+@end
+
+@protocol P2, delete; // expected-error {{expected identifier; 'delete' is a keyword in Objective-C++}}
+
+@class Foo, try; // expected-error {{expected identifier; 'try' is a keyword in Objective-C++}}
+
+@interface Foo
+
+@property (readwrite, nonatomic) int a, b, throw; // expected-error {{expected member name or ';' after declaration specifiers; 'throw' is a keyword in Objective-C++}}
+
+-foo:(int)class; // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
++foo:(int)constexpr; // expected-error {{expected identifier; 'constexpr' is a keyword in Objective-C++}}
+
+@end
+
+@interface Foo () <P, new> // expected-error {{expected identifier; 'new' is a keyword in Objective-C++}}
+@end
+
+@implementation Foo
+
+@synthesize a = _a; // ok
+@synthesize b = virtual; // expected-error {{expected identifier; 'virtual' is a keyword in Objective-C++}}
+
+@dynamic throw; // expected-error {{expected identifier; 'throw' is a keyword in Objective-C++}}
+
+-foo:(int)class { // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+}
+
+@end
+
+@implementation class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@implementation Bar: class // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+@end
+
+@compatibility_alias C Foo; // ok
+@compatibility_alias const_cast Bar; // expected-error {{expected identifier; 'const_cast' is a keyword in Objective-C++}}
+@compatibility_alias C2 class; // expected-error {{expected identifier; 'class' is a keyword in Objective-C++}}
+
+void func() {
+  (void)@protocol(P); // ok
+  (void)@protocol(delete); // expected-error {{expected identifier; 'delete' is a keyword in Objective-C++}}
+}
diff --git a/test/Sema/warn-unreachable.c b/test/Sema/warn-unreachable.c
index 1f79216..440aa0a 100644
--- a/test/Sema/warn-unreachable.c
+++ b/test/Sema/warn-unreachable.c
@@ -461,3 +461,40 @@
   if (!true) // expected-note {{silence by adding parentheses to mark code as explicitly dead}}
     testTrueFalseMacros(); // expected-warning {{code will never be executed}}
 }
+
+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
+}