[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:
parent
17aec7bd36
commit
9a72870122
|
@ -788,6 +788,11 @@ Example matches 'a', L'a'
|
|||
</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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue