tmroeder created this revision.
Herald added a reviewer: shafik.
Herald added subscribers: cfe-commits, jdoerfert.
Herald added a project: clang.

This allows ASTs to be merged when they contain ChooseExpr (the GNU
__builtin_choose_expr construction). This is needed, for example, for
cross-CTU analysis of C code that makes use of __builtin_choose_expr.

The node is already supported in the AST, but it didn't have a matcher
in ASTMatchers. So, this change adds the matcher and adds support to
ASTImporter.


Repository:
  rC Clang

https://reviews.llvm.org/D58292

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  lib/AST/ASTImporter.cpp
  lib/ASTMatchers/ASTMatchersInternal.cpp
  test/ASTMerge/choose-expr/Inputs/choose1.c
  test/ASTMerge/choose-expr/Inputs/choose2.c
  test/ASTMerge/choose-expr/test.c
  unittests/AST/ASTImporterTest.cpp

Index: unittests/AST/ASTImporterTest.cpp
===================================================================
--- unittests/AST/ASTImporterTest.cpp
+++ unittests/AST/ASTImporterTest.cpp
@@ -563,6 +563,15 @@
           stringLiteral(hasType(asString("const char [7]"))))));
 }
 
+TEST_P(ImportExpr, ImportChooseExpr) {
+  MatchVerifier<Decl> Verifier;
+
+  testImport(
+    "void declToImport() { __builtin_choose_expr(1, 2, 3); }",
+    Lang_C, "", Lang_C, Verifier,
+    functionDecl(hasDescendant(chooseExpr())));
+}
+
 TEST_P(ImportExpr, ImportGNUNullExpr) {
   MatchVerifier<Decl> Verifier;
   testImport(
@@ -1082,6 +1091,38 @@
   EXPECT_EQ(To, nullptr);
 }
 
+TEST_P(ASTImporterOptionSpecificTestBase, ImportChooseExpr) {
+  MatchVerifier<Decl> Verifier;
+
+  // The macro in this TuDecl violates standard rules of macros (like not
+  // using a variable more than once), but it's only used to test a realistic
+  // __builtin_choose_expr construction.
+  Decl *FromTU = getTuDecl(
+      R"(
+      #define abs_int(x) __builtin_choose_expr(                    \
+         __builtin_types_compatible_p(__typeof(x), unsigned int),  \
+         x,                                                        \
+         __builtin_choose_expr(                                    \
+           __builtin_types_compatible_p(__typeof(x), int),         \
+           x < 0 ? -x : x,                                         \
+           (void)0))
+      void declToImport() {
+        int x = -10;
+        int abs_x = abs_int(x);
+        (void)abs_x;
+      }
+      )",
+      Lang_C, "input.c");
+  auto *From = FirstDeclMatcher<FunctionDecl>().match(
+      FromTU, functionDecl(hasName("declToImport")));
+  ASSERT_TRUE(From);
+  auto *To = Import(From, Lang_C);
+  ASSERT_TRUE(To);
+  EXPECT_TRUE(MatchVerifier<FunctionDecl>().match(
+      To, functionDecl(hasName("declToImport"),
+                       hasDescendant(chooseExpr(hasDescendant(chooseExpr()))))));
+}
+
 const internal::VariadicDynCastAllOfMatcher<Expr, CXXPseudoDestructorExpr>
     cxxPseudoDestructorExpr;
 
Index: test/ASTMerge/choose-expr/test.c
===================================================================
--- /dev/null
+++ test/ASTMerge/choose-expr/test.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/choose1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/choose2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1
Index: test/ASTMerge/choose-expr/Inputs/choose2.c
===================================================================
--- /dev/null
+++ test/ASTMerge/choose-expr/Inputs/choose2.c
@@ -0,0 +1,12 @@
+#define abs_int(x) __builtin_choose_expr(                     \
+    __builtin_types_compatible_p(__typeof(x), unsigned int),  \
+    x,                                                        \
+    __builtin_choose_expr(                                    \
+    __builtin_types_compatible_p(__typeof(x), int),           \
+    x < 0 ? -x : x,                                           \
+    (void)0))
+void declToImport() {
+  int x = -10;
+  int abs_x = abs_int(x);
+  (void)abs_x;
+}
Index: test/ASTMerge/choose-expr/Inputs/choose1.c
===================================================================
--- /dev/null
+++ test/ASTMerge/choose-expr/Inputs/choose1.c
@@ -0,0 +1,12 @@
+#define abs_int(x) __builtin_choose_expr(                     \
+    __builtin_types_compatible_p(__typeof(x), unsigned int),  \
+    x,                                                        \
+    __builtin_choose_expr(                                    \
+    __builtin_types_compatible_p(__typeof(x), int),           \
+    x < 0 ? -x : x,                                           \
+    (void)0))
+void declToImport() {
+  int x = -10;
+  int abs_x = abs_int(x);
+  (void)abs_x;
+}
Index: lib/ASTMatchers/ASTMatchersInternal.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchersInternal.cpp
+++ lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -727,6 +727,7 @@
     compoundLiteralExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
     cxxNullPtrLiteralExpr;
+const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr> chooseExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr> gnuNullExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, AtomicExpr> atomicExpr;
 const internal::VariadicDynCastAllOfMatcher<Stmt, StmtExpr> stmtExpr;
Index: lib/AST/ASTImporter.cpp
===================================================================
--- lib/AST/ASTImporter.cpp
+++ 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,35 @@
       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 = false;
+  if (!E->isConditionDependent())
+    CondIsTrue = 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: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -2158,6 +2158,10 @@
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
     cxxNullPtrLiteralExpr;
 
+/// Matches GNU __builtin_choose_expr.
+extern const internal::VariadicDynCastAllOfMatcher<Stmt, ChooseExpr>
+    chooseExpr;
+
 /// Matches GNU __null expression.
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, GNUNullExpr>
     gnuNullExpr;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to