diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -1704,6 +1704,11 @@
+
Matcher<Stmt> | genericSelectionExpr | Matcher<GenericSelectionExpr>... |
+Matches C11 _Generic expression.
+ |
+
+
Matcher<Stmt> | gnuNullExpr | Matcher<GNUNullExpr>... |
Matches GNU __null expression.
|
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2362,6 +2362,10 @@
extern const internal::VariadicDynCastAllOfMatcher
gnuNullExpr;
+/// Matches C11 _Generic expression.
+extern const internal::VariadicDynCastAllOfMatcher
+ genericSelectionExpr;
+
/// Matches atomic builtins.
/// Example matches __atomic_load_n(ptr, 1)
/// \code
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -577,6 +577,7 @@
ExpectedStmt VisitVAArgExpr(VAArgExpr *E);
ExpectedStmt VisitChooseExpr(ChooseExpr *E);
ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E);
+ ExpectedStmt VisitGenericSelectionExpr(GenericSelectionExpr *E);
ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E);
ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E);
ExpectedStmt VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
@@ -6526,6 +6527,40 @@
return new (Importer.getToContext()) GNUNullExpr(*TypeOrErr, *BeginLocOrErr);
}
+ExpectedStmt
+ASTNodeImporter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
+ Error Err = Error::success();
+ auto ToGenericLoc = importChecked(Err, E->getGenericLoc());
+ auto *ToControllingExpr = importChecked(Err, E->getControllingExpr());
+ auto ToDefaultLoc = importChecked(Err, E->getDefaultLoc());
+ auto ToRParenLoc = importChecked(Err, E->getRParenLoc());
+ if (Err)
+ return std::move(Err);
+
+ ArrayRef FromAssocTypes(E->getAssocTypeSourceInfos());
+ SmallVector ToAssocTypes(FromAssocTypes.size());
+ if (Error Err = ImportContainerChecked(FromAssocTypes, ToAssocTypes))
+ return std::move(Err);
+
+ ArrayRef FromAssocExprs(E->getAssocExprs());
+ SmallVector ToAssocExprs(FromAssocExprs.size());
+ if (Error Err = ImportContainerChecked(FromAssocExprs, ToAssocExprs))
+ return std::move(Err);
+
+ const ASTContext &ToCtx = Importer.getToContext();
+ if (E->isResultDependent()) {
+ return GenericSelectionExpr::Create(
+ ToCtx, ToGenericLoc, ToControllingExpr,
+ llvm::makeArrayRef(ToAssocTypes), llvm::makeArrayRef(ToAssocExprs),
+ ToDefaultLoc, ToRParenLoc, E->containsUnexpandedParameterPack());
+ }
+
+ return GenericSelectionExpr::Create(
+ ToCtx, ToGenericLoc, ToControllingExpr, llvm::makeArrayRef(ToAssocTypes),
+ llvm::makeArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
+ E->containsUnexpandedParameterPack(), E->getResultIndex());
+}
+
ExpectedStmt ASTNodeImporter::VisitPredefinedExpr(PredefinedExpr *E) {
Error Err = Error::success();
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -233,6 +233,24 @@
return E1->isExact() == E2->isExact() && E1->getValue() == E2->getValue();
}
+ bool IsStmtEquivalent(const GenericSelectionExpr *E1,
+ const GenericSelectionExpr *E2) {
+ for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),
+ E2->getAssocTypeSourceInfos())) {
+ Optional Child1 = std::get<0>(Pair);
+ Optional Child2 = std::get<1>(Pair);
+ // Skip this case if there are a different number of associated types.
+ if (!Child1 || !Child2)
+ return false;
+
+ if (!IsStructurallyEquivalent(Context, (*Child1)->getType(),
+ (*Child2)->getType()))
+ return false;
+ }
+
+ return true;
+ }
+
bool IsStmtEquivalent(const ImplicitCastExpr *CastE1,
const ImplicitCastExpr *CastE2) {
return IsStructurallyEquivalent(Context, CastE1->getType(),
diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
--- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -905,6 +905,8 @@
cxxNullPtrLiteralExpr;
const internal::VariadicDynCastAllOfMatcher chooseExpr;
const internal::VariadicDynCastAllOfMatcher gnuNullExpr;
+const internal::VariadicDynCastAllOfMatcher
+ genericSelectionExpr;
const internal::VariadicDynCastAllOfMatcher atomicExpr;
const internal::VariadicDynCastAllOfMatcher stmtExpr;
const internal::VariadicDynCastAllOfMatcher
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -239,6 +239,7 @@
REGISTER_MATCHER(functionProtoType);
REGISTER_MATCHER(functionTemplateDecl);
REGISTER_MATCHER(functionType);
+ REGISTER_MATCHER(genericSelectionExpr);
REGISTER_MATCHER(gnuNullExpr);
REGISTER_MATCHER(gotoStmt);
REGISTER_MATCHER(has);
diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
--- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp
+++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp
@@ -95,10 +95,6 @@
return Node.isPotentiallyEvaluated();
}
-const ast_matchers::internal::VariadicDynCastAllOfMatcher
- genericSelectionExpr;
-
AST_MATCHER_P(GenericSelectionExpr, hasControllingExpr,
ast_matchers::internal::Matcher, InnerMatcher) {
return InnerMatcher.matches(*Node.getControllingExpr(), Finder, Builder);
diff --git a/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.c b/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.c
new file mode 100644
--- /dev/null
+++ b/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.c
@@ -0,0 +1,6 @@
+void f() {
+ int x;
+ float y;
+ _Static_assert(_Generic(x, float : 0, int : 1), "Incorrect semantics of _Generic");
+ _Static_assert(_Generic(y, float : 1, int : 0), "Incorrect semantics of _Generic");
+}
diff --git a/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.cpp b/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/ASTMerge/generic-selection-expr/Inputs/generic.cpp
@@ -0,0 +1,5 @@
+template
+void f() {
+ T x;
+ _Static_assert(_Generic(x, float : 0, int : 1), "Incorrect semantics of _Generic");
+}
diff --git a/clang/test/ASTMerge/generic-selection-expr/test.c b/clang/test/ASTMerge/generic-selection-expr/test.c
new file mode 100644
--- /dev/null
+++ b/clang/test/ASTMerge/generic-selection-expr/test.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=c11 -emit-pch -o %t.ast %S/Inputs/generic.c
+// RUN: %clang_cc1 -std=c11 -ast-merge %t.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
diff --git a/clang/test/ASTMerge/generic-selection-expr/test.cpp b/clang/test/ASTMerge/generic-selection-expr/test.cpp
new file mode 100644
--- /dev/null
+++ b/clang/test/ASTMerge/generic-selection-expr/test.cpp
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -std=c++03 -emit-pch -o %t.ast %S/Inputs/generic.cpp
+// RUN: %clang_cc1 -std=c++03 -ast-merge %t.ast -fsyntax-only -verify %s
+// expected-no-diagnostics
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -279,6 +279,15 @@
functionDecl(hasDescendant(gnuNullExpr(hasType(isInteger())))));
}
+TEST_P(ImportExpr, ImportGenericSelectionExpr) {
+ MatchVerifier Verifier;
+
+ testImport(
+ "void declToImport() { int x; (void)_Generic(x, int: 0, float: 1); }",
+ Lang_C99, "", Lang_C99, Verifier,
+ functionDecl(hasDescendant(genericSelectionExpr())));
+}
+
TEST_P(ImportExpr, ImportCXXNullPtrLiteralExpr) {
MatchVerifier Verifier;
testImport(
@@ -1087,6 +1096,36 @@
ToChooseExpr->isConditionDependent());
}
+TEST_P(ASTImporterOptionSpecificTestBase, ImportGenericSelectionExpr) {
+ Decl *From, *To;
+ std::tie(From, To) = getImportedDecl(
+ R"(
+ int declToImport() {
+ int x;
+ return _Generic(x, int: 0, default: 1);
+ }
+ )",
+ Lang_C99, "", Lang_C99);
+
+ auto ToResults =
+ match(genericSelectionExpr().bind("expr"), To->getASTContext());
+ auto FromResults =
+ match(genericSelectionExpr().bind("expr"), From->getASTContext());
+
+ const GenericSelectionExpr *FromGenericSelectionExpr =
+ selectFirst("expr", FromResults);
+ ASSERT_TRUE(FromGenericSelectionExpr);
+
+ const GenericSelectionExpr *ToGenericSelectionExpr =
+ selectFirst("expr", ToResults);
+ ASSERT_TRUE(ToGenericSelectionExpr);
+
+ EXPECT_EQ(FromGenericSelectionExpr->isResultDependent(),
+ ToGenericSelectionExpr->isResultDependent());
+ EXPECT_EQ(FromGenericSelectionExpr->getResultIndex(),
+ ToGenericSelectionExpr->getResultIndex());
+}
+
TEST_P(ASTImporterOptionSpecificTestBase,
ImportFunctionWithBackReferringParameter) {
Decl *From, *To;
diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp
--- a/clang/unittests/AST/StructuralEquivalenceTest.cpp
+++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp
@@ -1598,6 +1598,72 @@
EXPECT_FALSE(testStructuralMatch(t));
}
+TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprSame) {
+ auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
+ "_Generic(0u, unsigned int: 0, float: 1)", Lang_C99,
+ genericSelectionExpr());
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprSignsDiffer) {
+ auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
+ "_Generic(0, int: 0, float: 1)", Lang_C99,
+ genericSelectionExpr());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprOrderDiffers) {
+ auto t = makeWrappedStmts("_Generic(0u, unsigned int: 0, float: 1)",
+ "_Generic(0u, float: 1, unsigned int: 0)", Lang_C99,
+ genericSelectionExpr());
+ EXPECT_FALSE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceStmtTest, GenericSelectionExprDependentResultSame) {
+ auto t = makeStmts(
+ R"(
+ template
+ void f() {
+ T x;
+ (void)_Generic(x, int: 0, float: 1);
+ }
+ void g() { f(); }
+ )",
+ R"(
+ template
+ void f() {
+ T x;
+ (void)_Generic(x, int: 0, float: 1);
+ }
+ void g() { f(); }
+ )",
+ Lang_CXX03, genericSelectionExpr());
+ EXPECT_TRUE(testStructuralMatch(t));
+}
+
+TEST_F(StructuralEquivalenceStmtTest,
+ GenericSelectionExprDependentResultOrderDiffers) {
+ auto t = makeStmts(
+ R"(
+ template
+ void f() {
+ T x;
+ (void)_Generic(x, float: 1, int: 0);
+ }
+ void g() { f(); }
+ )",
+ R"(
+ template
+ void f() {
+ T x;
+ (void)_Generic(x, int: 0, float: 1);
+ }
+ void g() { f(); }
+ )",
+ Lang_CXX03, genericSelectionExpr());
+
+ EXPECT_FALSE(testStructuralMatch(t));
+}
TEST_F(StructuralEquivalenceStmtTest, IntegerLiteral) {
auto t = makeWrappedStmts("1", "1", Lang_CXX03, integerLiteral());
EXPECT_TRUE(testStructuralMatch(t));
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -982,6 +982,11 @@
EXPECT_TRUE(matches("int* i = __null;", gnuNullExpr()));
}
+TEST_P(ASTMatchersTest, GenericSelectionExpr) {
+ EXPECT_TRUE(matches("void f() { (void)_Generic(1, int: 1, float: 2.0); }",
+ genericSelectionExpr()));
+}
+
TEST_P(ASTMatchersTest, AtomicExpr) {
EXPECT_TRUE(matches("void foo() { int *ptr; __atomic_load_n(ptr, 1); }",
atomicExpr()));