[ASTImporter] Add support for importing ChooseExpr AST nodes.

Summary:
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.

Reviewers: shafik, a_sidorin, martong, aaron.ballman

Subscribers: aaron.ballman, rnkovacs, jdoerfert, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D58292

llvm-svn: 354832
This commit is contained in:
Tom Roeder 2019-02-25 23:24:58 +00:00
parent 17aec7bd36
commit 9a72870122
9 changed files with 99 additions and 0 deletions

View File

@ -788,6 +788,11 @@ Example matches 'a', L'a'
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('chooseExpr0')"><a name="chooseExpr0Anchor">chooseExpr</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ChooseExpr.html">ChooseExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="chooseExpr0"><pre>Matches GNU __builtin_choose_expr.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('compoundLiteralExpr0')"><a name="compoundLiteralExpr0Anchor">compoundLiteralExpr</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CompoundLiteralExpr.html">CompoundLiteralExpr</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="compoundLiteralExpr0"><pre>Matches compound (i.e. non-scalar) literals

View File

@ -2158,6 +2158,10 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
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;

View File

@ -552,6 +552,7 @@ namespace clang {
// 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 @@ ExpectedStmt ASTNodeImporter::VisitVAArgExpr(VAArgExpr *E) {
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());

View File

@ -727,6 +727,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CompoundLiteralExpr>
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;

View File

@ -147,6 +147,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(caseStmt);
REGISTER_MATCHER(castExpr);
REGISTER_MATCHER(characterLiteral);
REGISTER_MATCHER(chooseExpr);
REGISTER_MATCHER(classTemplateDecl);
REGISTER_MATCHER(classTemplateSpecializationDecl);
REGISTER_MATCHER(complexType);

View File

@ -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");

View File

@ -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

View File

@ -563,6 +563,34 @@ TEST_P(ImportExpr, ImportStringLiteral) {
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 (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<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 +1340,27 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportCorrectTemplatedDecl) {
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;

View File

@ -754,6 +754,11 @@ TEST(Matcher, NullPtrLiteral) {
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()));
}