Index: cfe/trunk/docs/LibASTMatchersReference.html =================================================================== --- cfe/trunk/docs/LibASTMatchersReference.html +++ cfe/trunk/docs/LibASTMatchersReference.html @@ -788,6 +788,11 @@ +Matcher<Stmt>chooseExprMatcher<ChooseExpr>... +
Matches GNU __builtin_choose_expr.
+
+ + Matcher<Stmt>compoundLiteralExprMatcher<CompoundLiteralExpr>...
Matches compound (i.e. non-scalar) literals
 
Index: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
@@ -2158,6 +2158,10 @@
 extern const internal::VariadicDynCastAllOfMatcher
     cxxNullPtrLiteralExpr;
 
+/// Matches GNU __builtin_choose_expr.
+extern const internal::VariadicDynCastAllOfMatcher
+    chooseExpr;
+
 /// Matches GNU __null expression.
 extern const internal::VariadicDynCastAllOfMatcher
     gnuNullExpr;
Index: cfe/trunk/lib/AST/ASTImporter.cpp
===================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp
+++ cfe/trunk/lib/AST/ASTImporter.cpp
@@ -552,6 +552,7 @@
     // Importing expressions
     ExpectedStmt VisitExpr(Expr *E);
     ExpectedStmt VisitVAArgExpr(VAArgExpr *E);
+    ExpectedStmt VisitChooseExpr(ChooseExpr *E);
     ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E);
     ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E);
     ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E);
@@ -6135,6 +6136,33 @@
       E->isMicrosoftABI());
 }
 
+ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) {
+  auto Imp = importSeq(E->getCond(), E->getLHS(), E->getRHS(),
+                       E->getBuiltinLoc(), E->getRParenLoc(), E->getType());
+  if (!Imp)
+    return Imp.takeError();
+
+  Expr *ToCond;
+  Expr *ToLHS;
+  Expr *ToRHS;
+  SourceLocation ToBuiltinLoc, ToRParenLoc;
+  QualType ToType;
+  std::tie(ToCond, ToLHS, ToRHS, ToBuiltinLoc, ToRParenLoc, ToType) = *Imp;
+
+  ExprValueKind VK = E->getValueKind();
+  ExprObjectKind OK = E->getObjectKind();
+
+  bool TypeDependent = ToCond->isTypeDependent();
+  bool ValueDependent = ToCond->isValueDependent();
+
+  // The value of CondIsTrue only matters if the value is not
+  // condition-dependent.
+  bool CondIsTrue = !E->isConditionDependent() && E->isConditionTrue();
+
+  return new (Importer.getToContext())
+      ChooseExpr(ToBuiltinLoc, ToCond, ToLHS, ToRHS, ToType, VK, OK,
+                 ToRParenLoc, CondIsTrue, TypeDependent, ValueDependent);
+}
 
 ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) {
   ExpectedType TypeOrErr = import(E->getType());
Index: cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -727,6 +727,7 @@
     compoundLiteralExpr;
 const internal::VariadicDynCastAllOfMatcher
     cxxNullPtrLiteralExpr;
+const internal::VariadicDynCastAllOfMatcher chooseExpr;
 const internal::VariadicDynCastAllOfMatcher gnuNullExpr;
 const internal::VariadicDynCastAllOfMatcher atomicExpr;
 const internal::VariadicDynCastAllOfMatcher stmtExpr;
Index: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -147,6 +147,7 @@
   REGISTER_MATCHER(caseStmt);
   REGISTER_MATCHER(castExpr);
   REGISTER_MATCHER(characterLiteral);
+  REGISTER_MATCHER(chooseExpr);
   REGISTER_MATCHER(classTemplateDecl);
   REGISTER_MATCHER(classTemplateSpecializationDecl);
   REGISTER_MATCHER(complexType);
Index: cfe/trunk/test/ASTMerge/choose-expr/Inputs/choose.c
===================================================================
--- cfe/trunk/test/ASTMerge/choose-expr/Inputs/choose.c
+++ cfe/trunk/test/ASTMerge/choose-expr/Inputs/choose.c
@@ -0,0 +1,2 @@
+_Static_assert(__builtin_choose_expr(1, 1, 0), "Incorrect semantics of __builtin_choose_expr");
+_Static_assert(__builtin_choose_expr(0, 0, 1), "Incorrect semantics of __builtin_choose_expr");
Index: cfe/trunk/test/ASTMerge/choose-expr/test.c
===================================================================
--- cfe/trunk/test/ASTMerge/choose-expr/test.c
+++ cfe/trunk/test/ASTMerge/choose-expr/test.c
@@ -0,0 +1,4 @@
+// RUN: %clang_cc1 -std=c11 -emit-pch -o %t.ast %S/Inputs/choose.c
+// RUN: %clang_cc1 -std=c11 -ast-merge %t.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
+
Index: cfe/trunk/unittests/AST/ASTImporterTest.cpp
===================================================================
--- cfe/trunk/unittests/AST/ASTImporterTest.cpp
+++ cfe/trunk/unittests/AST/ASTImporterTest.cpp
@@ -563,6 +563,34 @@
           stringLiteral(hasType(asString("const char [7]"))))));
 }
 
+TEST_P(ImportExpr, ImportChooseExpr) {
+  MatchVerifier Verifier;
+
+  // This case tests C code that is not condition-dependent and has a true
+  // condition.
+  testImport(
+    "void declToImport() { (void)__builtin_choose_expr(1, 2, 3); }",
+    Lang_C, "", Lang_C, Verifier,
+    functionDecl(hasDescendant(chooseExpr())));
+
+  ArgVector Args = getExtraArgs();
+  BindableMatcher Matcher =
+      functionTemplateDecl(hasDescendant(chooseExpr()));
+
+  // Don't try to match the template contents if template parsing is delayed.
+  if (llvm::find(Args, "-fdelayed-template-parsing") != Args.end()) {
+    Matcher = functionTemplateDecl();
+  }
+
+  // Make sure that uses of (void)__builtin_choose_expr with dependent types in
+  // the condition are handled properly. This test triggers an assertion if the
+  // ASTImporter incorrectly tries to access isConditionTrue() when
+  // isConditionDependent() is true.
+  testImport("template void declToImport() { "
+             "(void)__builtin_choose_expr(N, 1, 0); }",
+             Lang_CXX, "", Lang_CXX, Verifier, Matcher);
+}
+
 TEST_P(ImportExpr, ImportGNUNullExpr) {
   MatchVerifier Verifier;
   testImport(
@@ -1312,6 +1340,27 @@
   ASSERT_EQ(ToTemplated1, ToTemplated);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) {
+  // This tests the import of isConditionTrue directly to make sure the importer
+  // gets it right.
+  Decl *From, *To;
+  std::tie(From, To) = getImportedDecl(
+    "void declToImport() { (void)__builtin_choose_expr(1, 0, 1); }",
+    Lang_C, "", Lang_C);
+
+  auto ToResults = match(chooseExpr().bind("choose"), To->getASTContext());
+  auto FromResults = match(chooseExpr().bind("choose"), From->getASTContext());
+
+  const ChooseExpr *FromChooseExpr =
+      selectFirst("choose", FromResults);
+  ASSERT_TRUE(FromChooseExpr);
+
+  const ChooseExpr *ToChooseExpr = selectFirst("choose", ToResults);
+  ASSERT_TRUE(ToChooseExpr);
+
+  EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue());
+}
+
 TEST_P(ASTImporterOptionSpecificTestBase,
        ImportFunctionWithBackReferringParameter) {
   Decl *From, *To;
Index: cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
===================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -754,6 +754,11 @@
   EXPECT_TRUE(matches("int* i = nullptr;", cxxNullPtrLiteralExpr()));
 }
 
+TEST(Matcher, ChooseExpr) {
+  EXPECT_TRUE(matchesC("void f() { (void)__builtin_choose_expr(1, 2, 3); }",
+                       chooseExpr()));
+}
+
 TEST(Matcher, GNUNullExpr) {
   EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
 }