Index: cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp +++ cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -89,18 +89,19 @@ DynTypedMatcher DynTypedMatcher::constructVariadic( VariadicOperatorFunction Func, std::vector InnerMatchers) { assert(InnerMatchers.size() > 0 && "Array must not be empty."); - DynTypedMatcher Result = InnerMatchers[0]; - // Use the least derived type as the restriction for the wrapper. - // This allows mismatches to be resolved on the inner matchers. - for (const DynTypedMatcher &M : InnerMatchers) { - assert(Result.SupportedKind.isSame(M.SupportedKind) && - "SupportedKind must match!"); - Result.RestrictKind = - ast_type_traits::ASTNodeKind::getMostDerivedCommonAncestor( - Result.RestrictKind, M.RestrictKind); - } - Result.Implementation = new VariadicMatcher(Func, std::move(InnerMatchers)); - return Result; + assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(), + [&InnerMatchers](const DynTypedMatcher &M) { + return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind); + }) && + "SupportedKind must match!"); + + // We must relax the restrict kind here. + // The different operators might deal differently with a mismatch. + // Make it the same as SupportedKind, since that is the broadest type we are + // allowed to accept. + return DynTypedMatcher(InnerMatchers[0].SupportedKind, + InnerMatchers[0].SupportedKind, + new VariadicMatcher(Func, std::move(InnerMatchers))); } DynTypedMatcher DynTypedMatcher::trueMatcher( Index: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -591,6 +591,11 @@ EXPECT_TRUE(matches("class X { class Z {}; };", ClassXHasNotClassY)); EXPECT_TRUE(notMatches("class X { class Y {}; class Z {}; };", ClassXHasNotClassY)); + + DeclarationMatcher NamedNotRecord = + namedDecl(hasName("Foo"), unless(recordDecl())); + EXPECT_TRUE(matches("void Foo(){}", NamedNotRecord)); + EXPECT_TRUE(notMatches("struct Foo {};", NamedNotRecord)); } TEST(DeclarationMatcher, HasDescendant) { Index: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp =================================================================== --- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -380,6 +380,13 @@ EXPECT_FALSE(matches("class Bar{ int Foo; };", D)); EXPECT_TRUE(matches("class OtherBar{ int Foo; };", D)); + + D = constructMatcher( + "namedDecl", constructMatcher("hasName", std::string("Foo")), + constructMatcher("unless", constructMatcher("recordDecl"))) + .getTypedMatcher(); + EXPECT_TRUE(matches("void Foo(){}", D)); + EXPECT_TRUE(notMatches("struct Foo {};", D)); } TEST_F(RegistryTest, Errors) {