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>genericSelectionExprMatcher<GenericSelectionExpr>... +
Matches C11 _Generic expression.
+
+ + Matcher<Stmt>gnuNullExprMatcher<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 @@ -585,6 +585,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); @@ -6501,6 +6502,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/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -901,6 +901,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 @@ -241,6 +241,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,7 @@ +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/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,4 @@ +// 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/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( @@ -1088,6 +1097,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/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -985,6 +985,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()));