tmroeder updated this revision to Diff 187989. tmroeder added a comment. Added more unit tests.
Sorry for the delay; I had to dig into the details to figure out where to put these tests and how to structure them. Please let me know if there are better ways to do this. I don't know any way to write a matcher that checks the condition of __builtin_choose_expr before and after import, so I added a unit test that matches the expr and compares the From and To ChooseExprs directly. I've confirmed that without the negation in the condition in VisitChooseExpr, the new tests cause failures and with the negation, everything is clean. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D58292/new/ https://reviews.llvm.org/D58292 Files: docs/LibASTMatchersReference.html include/clang/ASTMatchers/ASTMatchers.h lib/AST/ASTImporter.cpp lib/ASTMatchers/ASTMatchersInternal.cpp lib/ASTMatchers/Dynamic/Registry.cpp test/ASTMerge/choose-expr/Inputs/choose.c test/ASTMerge/choose-expr/test.c unittests/AST/ASTImporterTest.cpp unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Index: unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ 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())); } Index: unittests/AST/ASTImporterTest.cpp =================================================================== --- unittests/AST/ASTImporterTest.cpp +++ unittests/AST/ASTImporterTest.cpp @@ -563,6 +563,35 @@ stringLiteral(hasType(asString("const char [7]")))))); } +TEST_P(ImportExpr, ImportChooseExpr) { + MatchVerifier<Decl> 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<Decl> Matcher = + functionTemplateDecl(hasDescendant(chooseExpr())); + + // Don't try to match the template contents if template parsing is delayed. + if (std::find(std::begin(Args), std::end(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<int N> void declToImport() { " + "(void)__builtin_choose_expr(N, 1, 0); }", + Lang_CXX, "", Lang_CXX, Verifier, Matcher); +} + TEST_P(ImportExpr, ImportGNUNullExpr) { MatchVerifier<Decl> Verifier; testImport( @@ -1312,6 +1341,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<ChooseExpr>("choose", FromResults); + ASSERT_TRUE(FromChooseExpr); + + const ChooseExpr* ToChooseExpr = selectFirst<ChooseExpr>("choose", ToResults); + ASSERT_TRUE(ToChooseExpr); + + EXPECT_EQ(FromChooseExpr->isConditionTrue(), ToChooseExpr->isConditionTrue()); +} + TEST_P(ASTImporterOptionSpecificTestBase, ImportFunctionWithBackReferringParameter) { Decl *From, *To; Index: test/ASTMerge/choose-expr/test.c =================================================================== --- /dev/null +++ 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: test/ASTMerge/choose-expr/Inputs/choose.c =================================================================== --- /dev/null +++ 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: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ 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: 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,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: 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; Index: docs/LibASTMatchersReference.html =================================================================== --- docs/LibASTMatchersReference.html +++ docs/LibASTMatchersReference.html @@ -788,6 +788,11 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('chooseExpr0')"><a name="chooseExpr0Anchor">chooseExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ChooseExpr.html">ChooseExpr</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="chooseExpr0"><pre>Matches GNU __builtin_choose_expr. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('compoundLiteralExpr0')"><a name="compoundLiteralExpr0Anchor">compoundLiteralExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>>...</td></tr> <tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits